Exemplo n.º 1
0
/**
 * @brief If there was an origin brush, offset all of the planes and texinfo
 * @note Used for e.g. func_door or func_rotating
 */
static void AdjustBrushesForOrigin (const entity_t* ent)
{
	for (int i = 0; i < ent->numbrushes; i++) {
		mapbrush_t* b = &mapbrushes[ent->firstbrush + i];
		for (int j = 0; j < b->numsides; j++) {
			side_t* s = &b->original_sides[j];
			const ptrdiff_t index = s - brushsides;
			const vec_t newdist = mapplanes[s->planenum].dist -
				DotProduct(mapplanes[s->planenum].normal, ent->origin);
			s->surfaceFlags |= SURF_ORIGIN;
			side_brushtextures[index].surfaceFlags |= SURF_ORIGIN;
			s->planenum = FindOrCreateFloatPlane(mapplanes[s->planenum].normal, newdist);
			s->texinfo = TexinfoForBrushTexture(&mapplanes[s->planenum],
				&side_brushtextures[index], ent->origin, s->contentFlags & CONTENTS_TERRAIN);
			s->brush = b;
		}
		/* create windings for sides and bounds for brush */
		MakeBrushWindings(b);
	}
}
Exemplo n.º 2
0
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
void Q1_BSPBrushToMapBrush(bspbrush_t *bspbrush, entity_t *mapent)
{
    mapbrush_t *mapbrush;
    side_t *side;
    int i, besttexinfo;

    CheckBSPBrush(bspbrush);

    if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
        Error ("nummapbrushes == MAX_MAPFILE_BRUSHES");

    mapbrush = &mapbrushes[nummapbrushes];
    mapbrush->original_sides = &brushsides[nummapbrushsides];
    mapbrush->entitynum = mapent - entities;
    mapbrush->brushnum = nummapbrushes - mapent->firstbrush;
    mapbrush->leafnum = -1;
    mapbrush->numsides = 0;

    besttexinfo = TEXINFO_NODE;
    for (i = 0; i < bspbrush->numsides; i++)
    {
        if (!bspbrush->sides[i].winding) continue;
        //
        if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
            Error ("MAX_MAPFILE_BRUSHSIDES");
        side = &brushsides[nummapbrushsides];
        //the contents of the bsp brush is stored in the side variable
        side->contents = bspbrush->side;
        side->surf = 0;
        side->planenum = bspbrush->sides[i].planenum;
        side->texinfo = bspbrush->sides[i].texinfo;
        if (side->texinfo != TEXINFO_NODE)
        {
            //this brush side is textured
            side->flags |= SFL_TEXTURED;
            besttexinfo = side->texinfo;
        } //end if
        //
        nummapbrushsides++;
        mapbrush->numsides++;
    } //end for
    //
    if (besttexinfo == TEXINFO_NODE)
    {
        mapbrush->numsides = 0;
        q1_numclipbrushes++;
        return;
    } //end if
    //set the texinfo for all the brush sides without texture
    for (i = 0; i < mapbrush->numsides; i++)
    {
        if (mapbrush->original_sides[i].texinfo == TEXINFO_NODE)
        {
            mapbrush->original_sides[i].texinfo = besttexinfo;
        } //end if
    } //end for
    //contents of the brush
    mapbrush->contents = bspbrush->side;
    //
    if (create_aas)
    {
        //create the AAS brushes from this brush, add brush bevels
        AAS_CreateMapBrushes(mapbrush, mapent, true);
        return;
    } //end if
    //create windings for sides and bounds for brush
    MakeBrushWindings(mapbrush);
    //add brush bevels
    AddBrushBevels(mapbrush);
    //a new brush has been created
    nummapbrushes++;
    mapent->numbrushes++;
} //end of the function Q1_BSPBrushToMapBrush
Exemplo n.º 3
0
//===========================================================================
//
// Parameter:				-
// Returns:					-
// Changes Globals:		-
//===========================================================================
void Sin_BSPBrushToMapBrush(sin_dbrush_t *bspbrush, entity_t *mapent)
{
	mapbrush_t       *b;
	int              i, k, n;
	side_t           *side, *s2;
	int              planenum;
	sin_dbrushside_t *bspbrushside;
	sin_dplane_t     *bspplane;

	if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
	{
		Error("nummapbrushes >= MAX_MAPFILE_BRUSHES");
	}

	b                 = &mapbrushes[nummapbrushes];
	b->original_sides = &brushsides[nummapbrushsides];
	b->entitynum      = mapent - entities;
	b->brushnum       = nummapbrushes - mapent->firstbrush;
	b->leafnum        = dbrushleafnums[bspbrush - sin_dbrushes];

	for (n = 0; n < bspbrush->numsides; n++)
	{
		//pointer to the bsp brush side
		bspbrushside = &sin_dbrushsides[bspbrush->firstside + n];

		if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
		{
			Error("MAX_MAPFILE_BRUSHSIDES");
		} //end if
		  //pointer to the map brush side
		side = &brushsides[nummapbrushsides];
		//if the BSP brush side is textured
		if (sin_dbrushsidetextured[bspbrush->firstside + n])
		{
			side->flags |= SFL_TEXTURED;
		}
		else
		{
			side->flags &= ~SFL_TEXTURED;
		}
		//ME: can get side contents and surf directly from BSP file
		side->contents = bspbrush->contents;
		//if the texinfo is TEXINFO_NODE
		if (bspbrushside->texinfo < 0)
		{
			side->surf = 0;
		}
		else
		{
			side->surf = sin_texinfo[bspbrushside->texinfo].flags;
		}

		// translucent objects are automatically classified as detail
//		if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
//			side->contents |= CONTENTS_DETAIL;
		if (side->contents & (CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP))
		{
			side->contents |= CONTENTS_DETAIL;
		}
		if (fulldetail)
		{
			side->contents &= ~CONTENTS_DETAIL;
		}
		if (!(side->contents & ((LAST_VISIBLE_CONTENTS - 1)
		                        | CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP | CONTENTS_MIST)))
		{
			side->contents |= CONTENTS_SOLID;
		}

		// hints and skips are never detail, and have no content
		if (side->surf & (SURF_HINT | SURF_SKIP))
		{
			side->contents = 0;
			side->surf    &= ~CONTENTS_DETAIL;
		}

		//ME: get a plane for this side
		bspplane = &sin_dplanes[bspbrushside->planenum];
		planenum = FindFloatPlane(bspplane->normal, bspplane->dist, 0, NULL);
		//
		// see if the plane has been used already
		//
		//ME: this really shouldn't happen!!!
		//ME: otherwise the bsp file is corrupted??
		//ME: still it seems to happen, maybe Johny Boy's
		//ME: brush bevel adding is crappy ?
		for (k = 0; k < b->numsides; k++)
		{
			s2 = b->original_sides + k;
			if (s2->planenum == planenum)
			{
				Log_Print("Entity %i, Brush %i: duplicate plane\n"
				          , b->entitynum, b->brushnum);
				break;
			}
			if (s2->planenum == (planenum ^ 1))
			{
				Log_Print("Entity %i, Brush %i: mirrored plane\n"
				          , b->entitynum, b->brushnum);
				break;
			}
		}
		if (k != b->numsides)
		{
			continue;       // duplicated

		}
		//
		// keep this side
		//
		//ME: reset pointer to side, why? hell I dunno (pointer is set above already)
		side = b->original_sides + b->numsides;
		//ME: store the plane number
		side->planenum = planenum;
		//ME: texinfo is already stored when bsp is loaded
		//NOTE: check for TEXINFO_NODE, otherwise crash in Sin_BrushContents
		if (bspbrushside->texinfo < 0)
		{
			side->texinfo = 0;
		}
		else
		{
			side->texinfo = bspbrushside->texinfo;
		}

		// save the td off in case there is an origin brush and we
		// have to recalculate the texinfo
		// ME: don't need to recalculate because it's already done
		//     (for non-world entities) in the BSP file
//		side_brushtextures[nummapbrushsides] = td;

		nummapbrushsides++;
		b->numsides++;
	} //end for

	// get the content for the entire brush
	b->contents = bspbrush->contents;
	Sin_BrushContents(b);

	if (BrushExists(b))
	{
		c_squattbrushes++;
		b->numsides = 0;
		return;
	} //end if

	//if we're creating AAS
	if (create_aas)
	{
		//create the AAS brushes from this brush, don't add brush bevels
		AAS_CreateMapBrushes(b, mapent, false);
		return;
	} //end if

	// allow detail brushes to be removed
	if (nodetail && (b->contents & CONTENTS_DETAIL))
	{
		b->numsides = 0;
		return;
	} //end if

	// allow water brushes to be removed
	if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)))
	{
		b->numsides = 0;
		return;
	} //end if

	// create windings for sides and bounds for brush
	MakeBrushWindings(b);

	//mark brushes without winding or with a tiny window as bevels
	MarkBrushBevels(b);

	// brushes that will not be visible at all will never be
	// used as bsp splitters
	if (b->contents & (CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP))
	{
		c_clipbrushes++;
		for (i = 0; i < b->numsides; i++)
			b->original_sides[i].texinfo = TEXINFO_NODE;
	} //end for

	//
	// origin brushes are removed, but they set
	// the rotation origin for the rest of the brushes
	// in the entity.  After the entire entity is parsed,
	// the planenums and texinfos will be adjusted for
	// the origin brush
	//
	//ME: not needed because the entities in the BSP file already
	//    have an origin set
//	if (b->contents & CONTENTS_ORIGIN)
//	{
//		char	string[32];
//		vec3_t	origin;
//
//		if (num_entities == 1)
//		{
//			Error ("Entity %i, Brush %i: origin brushes not allowed in world"
//				, b->entitynum, b->brushnum);
//			return;
//		}
//
//		VectorAdd (b->mins, b->maxs, origin);
//		VectorScale (origin, 0.5, origin);
//
//		sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
//		SetKeyValue (&entities[b->entitynum], "origin", string);
//
//		VectorCopy (origin, entities[b->entitynum].origin);
//
//		// don't keep this brush
//		b->numsides = 0;
//
//		return;
//	}

	//ME: the bsp brushes already have bevels, so we won't try to
	//    add them again (especially since Johny Boy's bevel adding might
	//    be crappy)
//	AddBrushBevels(b);

	nummapbrushes++;
	mapent->numbrushes++;
} //end of the function Sin_BSPBrushToMapBrush
Exemplo n.º 4
0
/*
================
ParseMapEntity
================
*/
qboolean	ParseMapEntity (void)
{
	entity_t	*mapent;
	epair_t		*e;
	side_t		*s;
	int			i, j;
	int			startbrush, startsides;
	vec_t		newdist;
	mapbrush_t	*b;

	if (!GetToken (true))
		return false;

	if (strcmp (token, "{") )
		Error ("ParseEntity: { not found");
	
	if (num_entities == MAX_MAP_ENTITIES)
		Error ("num_entities == MAX_MAP_ENTITIES");

	startbrush = nummapbrushes;
	startsides = nummapbrushsides;

	mapent = &entities[num_entities];
	num_entities++;
	memset (mapent, 0, sizeof(*mapent));
	mapent->firstbrush = nummapbrushes;
	mapent->numbrushes = 0;
//	mapent->portalareas[0] = -1;
//	mapent->portalareas[1] = -1;

	do
	{
		if (!GetToken (true))
			Error ("ParseEntity: EOF without closing brace");
		if (!strcmp (token, "}") )
			break;
		if (!strcmp (token, "{") )
			ParseBrush (mapent);
		else
		{
			e = ParseEpair ();
			e->next = mapent->epairs;
			mapent->epairs = e;
		}
	} while (1);

	GetVectorForKey (mapent, "origin", mapent->origin);

	//
	// if there was an origin brush, offset all of the planes and texinfo
	//
	if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2])
	{
		for (i=0 ; i<mapent->numbrushes ; i++)
		{
			b = &mapbrushes[mapent->firstbrush + i];
			for (j=0 ; j<b->numsides ; j++)
			{
				s = &b->original_sides[j];
				newdist = mapplanes[s->planenum].dist -
					DotProduct (mapplanes[s->planenum].normal, mapent->origin);
				s->planenum = FindFloatPlane (mapplanes[s->planenum].normal, newdist);
				s->texinfo = TexinfoForBrushTexture (&mapplanes[s->planenum],
					&side_brushtextures[s-brushsides], mapent->origin);
			}
			MakeBrushWindings (b);
		}
	}

	// group entities are just for editor convenience
	// toss all brushes into the world entity
	if (!strcmp ("func_group", ValueForKey (mapent, "classname")))
	{
		MoveBrushesToWorld (mapent);
		mapent->numbrushes = 0;
		return true;
	}

	// areaportal entities move their brushes, but don't eliminate
	// the entity
	if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname")))
	{
		char	str[128];

		if (mapent->numbrushes != 1)
			Error ("Entity %i: func_areaportal can only be a single brush", num_entities-1);

		b = &mapbrushes[nummapbrushes-1];
		b->contents = CONTENTS_AREAPORTAL;
		c_areaportals++;
		mapent->areaportalnum = c_areaportals;
		// set the portal number as "style"
		sprintf (str, "%i", c_areaportals);
		SetKeyValue (mapent, "style", str);
		MoveBrushesToWorld (mapent);
		return true;
	}

	return true;
}
Exemplo n.º 5
0
/*
=================
ParseBrush
=================
*/
void ParseBrush (entity_t *mapent)
{
	mapbrush_t		*b;
	int			i,j, k;
	int			mt;
	side_t		*side, *s2;
	int			planenum;
	brush_texture_t	td;
	int			planepts[3][3];

	if (nummapbrushes == MAX_MAP_BRUSHES)
		Error ("nummapbrushes == MAX_MAP_BRUSHES");

	b = &mapbrushes[nummapbrushes];
	b->original_sides = &brushsides[nummapbrushsides];
	b->entitynum = num_entities-1;
	b->brushnum = nummapbrushes - mapent->firstbrush;

	do
	{
		if (!GetToken (true))
			break;
		if (!strcmp (token, "}") )
			break;

		if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
			Error ("MAX_MAP_BRUSHSIDES");
		side = &brushsides[nummapbrushsides];

		// read the three point plane definition
		for (i=0 ; i<3 ; i++)
		{
			if (i != 0)
				GetToken (true);
			if (strcmp (token, "(") )
				Error ("parsing brush");
			
			for (j=0 ; j<3 ; j++)
			{
				GetToken (false);
				planepts[i][j] = atoi(token);
			}
			
			GetToken (false);
			if (strcmp (token, ")") )
				Error ("parsing brush");
				
		}


		//
		// read the texturedef
		//
		GetToken (false);
		strcpy (td.name, token);

		GetToken (false);
		td.shift[0] = atoi(token);
		GetToken (false);
		td.shift[1] = atoi(token);
		GetToken (false);
		td.rotate = atoi(token);	
		GetToken (false);
		td.scale[0] = atof(token);
		GetToken (false);
		td.scale[1] = atof(token);

		// find default flags and values
		mt = FindMiptex (td.name);
		td.flags = textureref[mt].flags;
		td.value = textureref[mt].value;
		side->contents = textureref[mt].contents;
		side->surf = td.flags = textureref[mt].flags;

		if (TokenAvailable())
		{
			GetToken (false);
			side->contents = atoi(token);
			GetToken (false);
			side->surf = td.flags = atoi(token);
			GetToken (false);
			td.value = atoi(token);
		}

		// translucent objects are automatically classified as detail
		if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
			side->contents |= CONTENTS_DETAIL;
		if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
			side->contents |= CONTENTS_DETAIL;
		if (fulldetail)
			side->contents &= ~CONTENTS_DETAIL;
		if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1) 
			| CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST)  ) )
			side->contents |= CONTENTS_SOLID;

		// hints and skips are never detail, and have no content
		if (side->surf & (SURF_HINT|SURF_SKIP) )
		{
			side->contents = 0;
			side->surf &= ~CONTENTS_DETAIL;
		}


		//
		// find the plane number
		//
		planenum = PlaneFromPoints (planepts[0], planepts[1], planepts[2]);
		if (planenum == -1)
		{
			printf ("Entity %i, Brush %i: plane with no normal\n"
				, b->entitynum, b->brushnum);
			continue;
		}

		//
		// see if the plane has been used already
		//
		for (k=0 ; k<b->numsides ; k++)
		{
			s2 = b->original_sides + k;
			if (s2->planenum == planenum)
			{
				printf ("Entity %i, Brush %i: duplicate plane\n"
					, b->entitynum, b->brushnum);
				break;
			}
			if ( s2->planenum == (planenum^1) )
			{
				printf ("Entity %i, Brush %i: mirrored plane\n"
					, b->entitynum, b->brushnum);
				break;
			}
		}
		if (k != b->numsides)
			continue;		// duplicated

		//
		// keep this side
		//

		side = b->original_sides + b->numsides;
		side->planenum = planenum;
		side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum],
			&td, vec3_origin);

		// save the td off in case there is an origin brush and we
		// have to recalculate the texinfo
		side_brushtextures[nummapbrushsides] = td;

		nummapbrushsides++;
		b->numsides++;
	} while (1);

	// get the content for the entire brush
	b->contents = BrushContents (b);

	// allow detail brushes to be removed 
	if (nodetail && (b->contents & CONTENTS_DETAIL) )
	{
		b->numsides = 0;
		return;
	}

	// allow water brushes to be removed
	if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) )
	{
		b->numsides = 0;
		return;
	}

	// create windings for sides and bounds for brush
	MakeBrushWindings (b);

	// brushes that will not be visible at all will never be
	// used as bsp splitters
	if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
	{
		c_clipbrushes++;
		for (i=0 ; i<b->numsides ; i++)
			b->original_sides[i].texinfo = TEXINFO_NODE;
	}

	//
	// origin brushes are removed, but they set
	// the rotation origin for the rest of the brushes
	// in the entity.  After the entire entity is parsed,
	// the planenums and texinfos will be adjusted for
	// the origin brush
	//
	if (b->contents & CONTENTS_ORIGIN)
	{
		char	string[32];
		vec3_t	origin;

		if (num_entities == 1)
		{
			Error ("Entity %i, Brush %i: origin brushes not allowed in world"
				, b->entitynum, b->brushnum);
			return;
		}

		VectorAdd (b->mins, b->maxs, origin);
		VectorScale (origin, 0.5, origin);

		sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
		SetKeyValue (&entities[b->entitynum], "origin", string);

		VectorCopy (origin, entities[b->entitynum].origin);

		// don't keep this brush
		b->numsides = 0;

		return;
	}

	AddBrushBevels (b);

	nummapbrushes++;
	mapent->numbrushes++;		
}
Exemplo n.º 6
0
void AAS_CreateCurveBrushes(void)
{
	int i, j, n, planenum, numcurvebrushes = 0;
	q3_dsurface_t *surface;
	q3_drawVert_t *dv_p;
	vec3_t points[MAX_PATCH_VERTS];
	int width, height, c;
	patchCollide_t *pc;
	facet_t *facet;
	mapbrush_t *brush;
	side_t *side;
	entity_t *mapent;
	winding_t *winding;

	qprintf("nummapbrushsides = %d\n", nummapbrushsides);
	mapent = &entities[0];

	for(i = 0; i < q3_numDrawSurfaces; i++)
	{
		surface = &q3_drawSurfaces[i];

		if(!surface->patchWidth)
		{
			continue;
		}

		//if the curve is not solid
		if(!(q3_dshaders[surface->shaderNum].contentFlags & (CONTENTS_SOLID | CONTENTS_PLAYERCLIP)))
		{
			//Log_Print("skipped non-solid curve\n");
			continue;
		} //end if

		//
		width = surface->patchWidth;
		height = surface->patchHeight;
		c = width * height;

		if(c > MAX_PATCH_VERTS)
		{
			Error("ParseMesh: MAX_PATCH_VERTS");
		} //end if

		dv_p = q3_drawVerts + surface->firstVert;

		for(j = 0 ; j < c ; j++, dv_p++)
		{
			points[j][0] = dv_p->xyz[0];
			points[j][1] = dv_p->xyz[1];
			points[j][2] = dv_p->xyz[2];
		} //end for

		// create the internal facet structure
		pc = CM_GeneratePatchCollide(width, height, points);

		//
		for(j = 0; j < pc->numFacets; j++)
		{
			facet = &pc->facets[j];
			//
			brush = &mapbrushes[nummapbrushes];
			brush->original_sides = &brushsides[nummapbrushsides];
			brush->entitynum = 0;
			brush->brushnum = nummapbrushes - mapent->firstbrush;
			//
			brush->numsides = facet->numBorders + 2;
			nummapbrushsides += brush->numsides;
			brush->contents = CONTENTS_SOLID;
			//
			//qprintf("\r%6d curve brushes", nummapbrushsides);//++numcurvebrushes);
			qprintf("\r%6d curve brushes", ++numcurvebrushes);
			//
			planenum = FindFloatPlane(pc->planes[facet->surfacePlane].plane, pc->planes[facet->surfacePlane].plane[3]);
			//
			side = &brush->original_sides[0];
			side->planenum = planenum;
			side->contents = CONTENTS_SOLID;
			side->flags |= SFL_TEXTURED | SFL_VISIBLE | SFL_CURVE;
			side->surf = 0;
			//
			side = &brush->original_sides[1];

			if(create_aas)
			{
				//the plane is expanded later so it's not a problem that
				//these first two opposite sides are coplanar
				side->planenum = planenum ^ 1;
			} //end if
			else
			{
				side->planenum = FindFloatPlane(mapplanes[planenum ^ 1].normal, mapplanes[planenum ^ 1].dist + 1);
				side->flags |= SFL_TEXTURED | SFL_VISIBLE;
			} //end else

			side->contents = CONTENTS_SOLID;
			side->flags |= SFL_CURVE;
			side->surf = 0;
			//
			winding = BaseWindingForPlane(mapplanes[side->planenum].normal, mapplanes[side->planenum].dist);

			for(n = 0; n < facet->numBorders; n++)
			{
				//never use the surface plane as a border
				if(facet->borderPlanes[n] == facet->surfacePlane)
				{
					continue;
				}

				//
				side = &brush->original_sides[2 + n];
				side->planenum = FindFloatPlane(pc->planes[facet->borderPlanes[n]].plane, pc->planes[facet->borderPlanes[n]].plane[3]);

				if(facet->borderInward[n])
				{
					side->planenum ^= 1;
				}

				side->contents = CONTENTS_SOLID;
				side->flags |= SFL_TEXTURED | SFL_CURVE;
				side->surf = 0;

				//chop the winding in place
				if(winding)
				{
					ChopWindingInPlace(&winding, mapplanes[side->planenum ^ 1].normal, mapplanes[side->planenum ^ 1].dist, 0.1);      //CLIP_EPSILON);
				}
			} //end for

			//VectorCopy(pc->bounds[0], brush->mins);
			//VectorCopy(pc->bounds[1], brush->maxs);
			if(!winding)
			{
				Log_Print("WARNING: AAS_CreateCurveBrushes: no winding\n");
				brush->numsides = 0;
				continue;
			} //end if

			brush->original_sides[0].winding = winding;
			WindingBounds(winding, brush->mins, brush->maxs);

			for(n = 0; n < 3; n++)
			{
				//IDBUG: all the indexes into the mins and maxs were zero (not using i)
				if(brush->mins[n] < -MAX_MAP_BOUNDS || brush->maxs[n] > MAX_MAP_BOUNDS)
				{
					Log_Print("entity %i, brush %i: bounds out of range\n", brush->entitynum, brush->brushnum);
					Log_Print("brush->mins[%d] = %f, brush->maxs[%d] = %f\n", n, brush->mins[n], n, brush->maxs[n]);
					brush->numsides = 0; //remove the brush
					break;
				} //end if

				if(brush->mins[n] > MAX_MAP_BOUNDS || brush->maxs[n] < -MAX_MAP_BOUNDS)
				{
					Log_Print("entity %i, brush %i: no visible sides on brush\n", brush->entitynum, brush->brushnum);
					Log_Print("brush->mins[%d] = %f, brush->maxs[%d] = %f\n", n, brush->mins[n], n, brush->maxs[n]);
					brush->numsides = 0; //remove the brush
					break;
				} //end if
			} //end for

			if(create_aas)
			{
				//NOTE: brush bevels now already added
				//AddBrushBevels(brush);
				AAS_CreateMapBrushes(brush, mapent, false);
			} //end if
			else
			{
				// create windings for sides and bounds for brush
				MakeBrushWindings(brush);
				AddBrushBevels(brush);
				nummapbrushes++;
				mapent->numbrushes++;
			} //end else
		} //end for
	} //end for

	//qprintf("\r%6d curve brushes", nummapbrushsides);//++numcurvebrushes);
	qprintf("\r%6d curve brushes\n", numcurvebrushes);
} //end of the function AAS_CreateCurveBrushes
Exemplo n.º 7
0
//===========================================================================
//
// Parameter:               -
// Returns:                 -
// Changes Globals:     -
//===========================================================================
void Q3_BSPBrushToMapBrush(q3_dbrush_t *bspbrush, entity_t *mapent)
{
	mapbrush_t *b;
	int i, k, n;
	side_t *side, *s2;
	int planenum;
	q3_dbrushside_t *bspbrushside;
	q3_dplane_t *bspplane;
	int contentFlags = 0;

	if(nummapbrushes >= MAX_MAPFILE_BRUSHES)
	{
		Error("nummapbrushes >= MAX_MAPFILE_BRUSHES");
	}

	b = &mapbrushes[nummapbrushes];
	b->original_sides = &brushsides[nummapbrushsides];
	b->entitynum = mapent - entities;
	b->brushnum = nummapbrushes - mapent->firstbrush;
	b->leafnum = dbrushleafnums[bspbrush - q3_dbrushes];

	for(n = 0; n < bspbrush->numSides; n++)
	{
		//pointer to the bsp brush side
		bspbrushside = &q3_dbrushsides[bspbrush->firstSide + n];

		if(nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
		{
			Error("MAX_MAPFILE_BRUSHSIDES");
		} //end if

		//pointer to the map brush side
		side = &brushsides[nummapbrushsides];

		//if the BSP brush side is textured
		if(q3_dbrushsidetextured[bspbrush->firstSide + n])
		{
			side->flags |= SFL_TEXTURED | SFL_VISIBLE;
		}
		else
		{
			side->flags &= ~SFL_TEXTURED;
		}

		//NOTE: all Quake3 sides are assumed textured
		//side->flags |= SFL_TEXTURED|SFL_VISIBLE;
		//
		if(bspbrushside->shaderNum < 0)
		{
			side->contents = 0;
			side->surf = 0;
		} //end if
		else
		{
			side->contents = q3_dshaders[bspbrushside->shaderNum].contentFlags;
			side->surf = q3_dshaders[bspbrushside->shaderNum].surfaceFlags;

			if(strstr(q3_dshaders[bspbrushside->shaderNum].shader, "common/hint"))
			{
				//Log_Print("found hint side\n");
				side->surf |= SURF_HINT;
			} //end if

			// Ridah, mark ladder brushes
			if(cfg.rs_allowladders && strstr(q3_dshaders[bspbrushside->shaderNum].shader, "common/ladder"))
			{
				//Log_Print("found ladder side\n");
				side->contents |= CONTENTS_LADDER;
				contentFlags |= CONTENTS_LADDER;
			} //end if

			// done.

		} //end else

		//

		if(!(strstr(q3_dshaders[bspbrushside->shaderNum].shader, "common/slip")))
		{
			side->flags |= SFL_VISIBLE;
		}
		else if(side->surf & SURF_NODRAW)
		{
			side->flags |= SFL_TEXTURED | SFL_VISIBLE;
		} //end if

		/*
		if (side->contents & (CONTENTS_TRANSLUCENT|CONTENTS_STRUCTURAL))
		{
		  side->flags |= SFL_TEXTURED|SFL_VISIBLE;
		} //end if*/

		// hints and skips are never detail, and have no content
		if(side->surf & (SURF_HINT | SURF_SKIP))
		{
			side->contents = 0;
			//Log_Print("found hint brush side\n");
		}

		/*
		if ((side->surf & SURF_NODRAW) && (side->surf & SURF_NOIMPACT))
		{
		    side->contents = 0;
		    side->surf &= ~CONTENTS_DETAIL;
		    Log_Print("probably found hint brush in a BSP without hints being used\n");
		} //end if*/

		/*
		        // RF, ignore slick brushes (causes ladder issues)
		        if (strstr(q3_dshaders[bspbrushside->shaderNum].shader, "common/slick"))
		        {
		            //Log_Print("found hint side\n");
		            b->numsides = 0;
		            b->contents = 0;
		            return; // get out of here
		        } //end if
		*/

		//ME: get a plane for this side
		bspplane = &q3_dplanes[bspbrushside->planeNum];
		planenum = FindFloatPlane(bspplane->normal, bspplane->dist);

		//
		// see if the plane has been used already
		//
		//ME: this really shouldn't happen!!!
		//ME: otherwise the bsp file is corrupted??
		//ME: still it seems to happen, maybe Johny Boy's
		//ME: brush bevel adding is crappy ?
		for(k = 0; k < b->numsides; k++)
		{
			s2 = b->original_sides + k;
//			if (DotProduct (mapplanes[s2->planenum].normal, mapplanes[planenum].normal) > 0.999
//							&& fabs(mapplanes[s2->planenum].dist - mapplanes[planenum].dist) < 0.01 )

			if(s2->planenum == planenum)
			{
				Log_Print("Entity %i, Brush %i: duplicate plane\n"
				          , b->entitynum, b->brushnum);
				break;
			}

			if(s2->planenum == (planenum ^ 1))
			{
				Log_Print("Entity %i, Brush %i: mirrored plane\n"
				          , b->entitynum, b->brushnum);
				break;
			}
		}

		if(k != b->numsides)
		{
			continue;       // duplicated

		}

		//
		// keep this side
		//
		//ME: reset pointer to side, why? hell I dunno (pointer is set above already)
		side = b->original_sides + b->numsides;
		//ME: store the plane number
		side->planenum = planenum;
		//ME: texinfo is already stored when bsp is loaded
		//NOTE: check for TEXINFO_NODE, otherwise crash in Q3_BrushContents
		//if (bspbrushside->texinfo < 0) side->texinfo = 0;
		//else side->texinfo = bspbrushside->texinfo;

		// save the td off in case there is an origin brush and we
		// have to recalculate the texinfo
		// ME: don't need to recalculate because it's already done
		//     (for non-world entities) in the BSP file
//		side_brushtextures[nummapbrushsides] = td;

		nummapbrushsides++;
		b->numsides++;
	} //end for

	// get the content for the entire brush
	//Quake3 bsp brushes don't have a contents
	b->contents = q3_dshaders[bspbrush->shaderNum].contentFlags | contentFlags;
	// Ridah, Wolf has ladders (if we call Q3_BrushContents(), we'll get the solid area bug
	b->contents &= ~(/*CONTENTS_LADDER|*/ CONTENTS_FOG | CONTENTS_STRUCTURAL);

	//b->contents = Q3_BrushContents(b);
	//
	// Ridah, CONTENTS_MOSTERCLIP should prevent AAS from being created, but not clip players/AI in the game
	if(b->contents & CONTENTS_MONSTERCLIP)
	{
		b->contents |= CONTENTS_PLAYERCLIP;
	}

	// func_explosive's not solid
	if(!strcmp("func_explosive", ValueForKey(&entities[b->entitynum], "classname")) ||
	        !strcmp("func_invisible_user", ValueForKey(&entities[b->entitynum], "classname")) ||
	        !strcmp("script_mover", ValueForKey(&entities[b->entitynum], "classname")) ||
	        !strcmp("func_static", ValueForKey(&entities[b->entitynum], "classname")))
	{
		Log_Print("Ignoring %s brush..\n", ValueForKey(&entities[b->entitynum], "classname"));
		b->numsides = 0;
		b->contents = 0;
		return;
	}

	if(BrushExists(b))
	{
		c_squattbrushes++;
		b->numsides = 0;
		return;
	} //end if

	//if we're creating AAS
	if(create_aas)
	{
		//create the AAS brushes from this brush, don't add brush bevels
		AAS_CreateMapBrushes(b, mapent, false);
		return;
	} //end if

	// allow detail brushes to be removed
	if(nodetail && (b->contents & CONTENTS_DETAIL))
	{
		b->numsides = 0;
		return;
	} //end if

	// allow water brushes to be removed
	if(nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)))
	{
		b->numsides = 0;
		return;
	} //end if


	// create windings for sides and bounds for brush
	MakeBrushWindings(b);

	//mark brushes without winding or with a tiny window as bevels
	MarkBrushBevels(b);

	// brushes that will not be visible at all will never be
	// used as bsp splitters
	if(b->contents & (CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP))
	{
		c_clipbrushes++;

		for(i = 0; i < b->numsides; i++)
			b->original_sides[i].texinfo = TEXINFO_NODE;
	} //end for

	//
	// origin brushes are removed, but they set
	// the rotation origin for the rest of the brushes
	// in the entity.  After the entire entity is parsed,
	// the planenums and texinfos will be adjusted for
	// the origin brush
	//
	//ME: not needed because the entities in the BSP file already
	//    have an origin set
//	if (b->contents & CONTENTS_ORIGIN)
//	{
//		char    string[32];
//		vec3_t  origin;
//
//		if (num_entities == 1)
//		{
//			Error ("Entity %i, Brush %i: origin brushes not allowed in world"
//				, b->entitynum, b->brushnum);
//			return;
//		}
//
//		VectorAdd (b->mins, b->maxs, origin);
//		VectorScale (origin, 0.5, origin);
//
//		sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
//		SetKeyValue (&entities[b->entitynum], "origin", string);
//
//		VectorCopy (origin, entities[b->entitynum].origin);
//
//		// don't keep this brush
//		b->numsides = 0;
//
//		return;
//	}

	//ME: the bsp brushes already have bevels, so we won't try to
	//    add them again (especially since Johny Boy's bevel adding might
	//    be crappy)
//	AddBrushBevels(b);

	nummapbrushes++;
	mapent->numbrushes++;
} //end of the function Q3_BSPBrushToMapBrush
Exemplo n.º 8
0
/*
 * @brief
 */
static _Bool ParseMapEntity(void) {
	entity_t *mapent;
	epair_t *e;
	side_t *s;
	int32_t i, j;
	vec_t newdist;
	map_brush_t *b;

	if (!GetToken(true))
		return false;

	if (g_strcmp0(token, "{"))
		Com_Error(ERR_FATAL, "\"{\" not found\n");

	if (num_entities == MAX_BSP_ENTITIES)
		Com_Error(ERR_FATAL, "MAX_BSP_ENTITIES\n");

	mapent = &entities[num_entities];
	num_entities++;
	memset(mapent, 0, sizeof(*mapent));
	mapent->first_brush = num_map_brushes;
	mapent->num_brushes = 0;

	do {
		if (!GetToken(true))
			Com_Error(ERR_FATAL, "EOF without closing brace\n");
		if (!g_strcmp0(token, "}"))
			break;
		if (!g_strcmp0(token, "{"))
			ParseBrush(mapent);
		else {
			e = ParseEpair();
			e->next = mapent->epairs;
			mapent->epairs = e;
		}
	} while (true);

	VectorForKey(mapent, "origin", mapent->origin);

	// if there was an origin brush, offset all of the planes and texinfo
	if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2]) {
		for (i = 0; i < mapent->num_brushes; i++) {
			b = &map_brushes[mapent->first_brush + i];
			for (j = 0; j < b->num_sides; j++) {

				s = &b->original_sides[j];

				newdist = map_planes[s->plane_num].dist
						- DotProduct(map_planes[s->plane_num].normal, mapent->origin);

				s->plane_num = FindPlane(map_planes[s->plane_num].normal, newdist);

				s->texinfo = TexinfoForBrushTexture(&map_planes[s->plane_num],
						&map_brush_textures[s - map_brush_sides], mapent->origin);
			}
			MakeBrushWindings(b);
		}
	}

	// group entities are just for editor convenience
	// toss all brushes into the world entity
	if (!g_strcmp0("func_group", ValueForKey(mapent, "classname"))) {
		MoveBrushesToWorld(mapent);
		mapent->num_brushes = 0;
		return true;
	}

	// areaportal entities move their brushes, but don't eliminate the entity
	if (!g_strcmp0("func_areaportal", ValueForKey(mapent, "classname"))) {
		char str[128];

		if (mapent->num_brushes != 1)
			Com_Error(
					ERR_FATAL,
					"ParseMapEntity: %i func_areaportal can only be a single brush\n",
					num_entities - 1);

		b = &map_brushes[num_map_brushes - 1];
		b->contents = CONTENTS_AREA_PORTAL;
		c_area_portals++;
		mapent->area_portal_num = c_area_portals;
		// set the portal number as "style"
		sprintf(str, "%i", c_area_portals);
		SetKeyValue(mapent, "areaportal", str);
		MoveBrushesToWorld(mapent);
		return true;
	}

	return true;
}
Exemplo n.º 9
0
/*
 * @brief
 */
static void ParseBrush(entity_t *mapent) {
	map_brush_t *b;
	int32_t i, j, k;
	side_t *side, *s2;
	int32_t plane_num;
	map_brush_texture_t td;
	vec3_t planepts[3];

	if (num_map_brushes == MAX_BSP_BRUSHES)
		Com_Error(ERR_FATAL, "MAX_BSP_BRUSHES\n");

	b = &map_brushes[num_map_brushes];
	b->original_sides = &map_brush_sides[num_map_brush_sides];
	b->entity_num = num_entities - 1;
	b->brush_num = num_map_brushes - mapent->first_brush;

	do {
		if (!GetToken(true))
			break;
		if (!g_strcmp0(token, "}"))
			break;

		if (num_map_brush_sides == MAX_BSP_BRUSH_SIDES)
			Com_Error(ERR_FATAL, "MAX_BSP_BRUSH_SIDES\n");
		side = &map_brush_sides[num_map_brush_sides];

		// read the three point plane definition
		for (i = 0; i < 3; i++) {
			if (i != 0)
				GetToken(true);
			if (g_strcmp0(token, "("))
				Com_Error(ERR_FATAL, "Parsing brush\n");

			for (j = 0; j < 3; j++) {
				GetToken(false);
				planepts[i][j] = atof(token);
			}

			GetToken(false);
			if (g_strcmp0(token, ")"))
				Com_Error(ERR_FATAL, "Parsing brush\n");
		}

		memset(&td, 0, sizeof(td));

		// read the texturedef
		GetToken(false);

		if (strlen(token) > sizeof(td.name) - 1)
			Com_Error(ERR_FATAL, "Texture name \"%s\" is too long.\n", token);

		g_strlcpy(td.name, token, sizeof(td.name));

		GetToken(false);
		td.shift[0] = atoi(token);
		GetToken(false);
		td.shift[1] = atoi(token);
		GetToken(false);
		td.rotate = atoi(token);
		GetToken(false);
		td.scale[0] = atof(token);
		GetToken(false);
		td.scale[1] = atof(token);

		if (TokenAvailable()) {
			GetToken(false);
			side->contents = atoi(token);
			GetToken(false);
			side->surf = td.flags = atoi(token);
			GetToken(false);
			td.value = atoi(token);
		} else {
			side->contents = CONTENTS_SOLID;
			side->surf = td.flags = 0;
			td.value = 0;
		}

		// resolve implicit surface and contents flags
		SetImpliedFlags(side, td.name);

		// translucent objects are automatically classified as detail
		if (side->surf & (SURF_ALPHA_TEST | SURF_BLEND_33 | SURF_BLEND_66))
			side->contents |= CONTENTS_DETAIL;
		if (side->contents & (CONTENTS_PLAYER_CLIP | CONTENTS_MONSTER_CLIP))
			side->contents |= CONTENTS_DETAIL;
		if (fulldetail)
			side->contents &= ~CONTENTS_DETAIL;
		if (!(side->contents & ((LAST_VISIBLE_CONTENTS - 1) | CONTENTS_PLAYER_CLIP
				| CONTENTS_MONSTER_CLIP | CONTENTS_MIST)))
			side->contents |= CONTENTS_SOLID;

		// hints and skips are never detail, and have no content
		if (side->surf & (SURF_HINT | SURF_SKIP)) {
			side->contents = 0;
			side->surf &= ~CONTENTS_DETAIL;
		}

		// find the plane number
		plane_num = PlaneFromPoints(planepts[0], planepts[1], planepts[2]);
		if (plane_num == -1) {
			Com_Verbose("Entity %i, Brush %i: plane with no normal\n", b->entity_num, b->brush_num);
			continue;
		}

		// see if the plane has been used already
		for (k = 0; k < b->num_sides; k++) {
			s2 = b->original_sides + k;
			if (s2->plane_num == plane_num) {
				Com_Verbose("Entity %i, Brush %i: duplicate plane\n", b->entity_num, b->brush_num);
				break;
			}
			if (s2->plane_num == (plane_num ^ 1)) {
				Com_Verbose("Entity %i, Brush %i: mirrored plane\n", b->entity_num, b->brush_num);
				break;
			}
		}
		if (k != b->num_sides)
			continue; // duplicated

		// keep this side
		side = b->original_sides + b->num_sides;
		side->plane_num = plane_num;
		side->texinfo = TexinfoForBrushTexture(&map_planes[plane_num], &td, vec3_origin);

		// save the td off in case there is an origin brush and we
		// have to recalculate the texinfo
		map_brush_textures[num_map_brush_sides] = td;

		num_map_brush_sides++;
		b->num_sides++;
	} while (true);

	// get the content for the entire brush
	b->contents = BrushContents(b);

	// allow detail brushes to be removed
	if (nodetail && (b->contents & CONTENTS_DETAIL)) {
		b->num_sides = 0;
		return;
	}

	// allow water brushes to be removed
	if (nowater && (b->contents & MASK_LIQUID)) {
		b->num_sides = 0;
		return;
	}

	// create windings for sides and bounds for brush
	MakeBrushWindings(b);

	// brushes that will not be visible at all will never be
	// used as bsp splitters
	if (b->contents & (CONTENTS_PLAYER_CLIP | CONTENTS_MONSTER_CLIP)) {
		c_clip_brushes++;
		for (i = 0; i < b->num_sides; i++)
			b->original_sides[i].texinfo = TEXINFO_NODE;
	}

	// origin brushes are removed, but they set
	// the rotation origin for the rest of the brushes
	// in the entity. After the entire entity is parsed,
	// the plane_nums and texinfos will be adjusted for
	// the origin brush
	if (b->contents & CONTENTS_ORIGIN) {
		char string[32];
		vec3_t origin;

		if (num_entities == 1) {
			Com_Error(ERR_FATAL,
					"Entity %i, Brush %i: origin brushes not allowed in world\n",
					b->entity_num, b->brush_num);
			return;
		}

		VectorAdd(b->mins, b->maxs, origin);
		VectorScale(origin, 0.5, origin);

		sprintf(string, "%i %i %i", (int32_t)origin[0], (int32_t)origin[1],
				(int32_t)origin[2]);
		SetKeyValue(&entities[b->entity_num], "origin", string);

		VectorCopy(origin, entities[b->entity_num].origin);

		// don't keep this brush
		b->num_sides = 0;

		return;
	}

	AddBrushBevels(b);

	num_map_brushes++;
	mapent->num_brushes++;
}
Exemplo n.º 10
0
/*
=================
Q2_ParseBrush
=================
*/
void Q2_ParseBrush(script_t *script, entity_t *mapent)
{
	mapbrush_t      *b;
	int             i, j, k;
	int             mt;
	side_t          *side, *s2;
	int             planenum;
	brush_texture_t td;
	int             planepts[3][3];
	token_t         token;

	if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
	{
		Error("nummapbrushes == MAX_MAPFILE_BRUSHES");
	}

	b                 = &mapbrushes[nummapbrushes];
	b->original_sides = &brushsides[nummapbrushsides];
	b->entitynum      = num_entities - 1;
	b->brushnum       = nummapbrushes - mapent->firstbrush;
	b->leafnum        = -1;

	do
	{
		if (!PS_ReadToken(script, &token))
		{
			break;
		}
		if (!strcmp(token.string, "}"))
		{
			break;
		}

		//IDBUG: mixed use of MAX_MAPFILE_? and MAX_MAP_? this could
		//			lead to out of bound indexing of the arrays
		if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
		{
			Error("MAX_MAPFILE_BRUSHSIDES");
		}
		side = &brushsides[nummapbrushsides];

		//read the three point plane definition
		for (i = 0; i < 3; i++)
		{
			if (i != 0)
			{
				PS_ExpectTokenString(script, "(");
			}
			for (j = 0; j < 3; j++)
			{
				PS_ExpectAnyToken(script, &token);
				planepts[i][j] = atof(token.string);
			} //end for
			PS_ExpectTokenString(script, ")");
		} //end for

		//
		//read the texturedef
		//
		PS_ExpectAnyToken(script, &token);
		strcpy(td.name, token.string);

		PS_ExpectAnyToken(script, &token);
		td.shift[0] = atol(token.string);
		PS_ExpectAnyToken(script, &token);
		td.shift[1] = atol(token.string);
		PS_ExpectAnyToken(script, &token);
		td.rotate = atol(token.string);
		PS_ExpectAnyToken(script, &token);
		td.scale[0] = atof(token.string);
		PS_ExpectAnyToken(script, &token);
		td.scale[1] = atof(token.string);

		//find default flags and values
		mt             = FindMiptex(td.name);
		td.flags       = textureref[mt].flags;
		td.value       = textureref[mt].value;
		side->contents = textureref[mt].contents;
		side->surf     = td.flags = textureref[mt].flags;

		//check if there's a number available
		if (PS_CheckTokenType(script, TT_NUMBER, 0, &token))
		{
			side->contents = token.intvalue;
			PS_ExpectTokenType(script, TT_NUMBER, 0, &token);
			side->surf = td.flags = token.intvalue;
			PS_ExpectTokenType(script, TT_NUMBER, 0, &token);
			td.value = token.intvalue;
		}

		// translucent objects are automatically classified as detail
//		if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
//			side->contents |= CONTENTS_DETAIL;
		if (side->contents & (CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP))
		{
			side->contents |= CONTENTS_DETAIL;
		}
		if (fulldetail)
		{
			side->contents &= ~CONTENTS_DETAIL;
		}
		if (!(side->contents & ((LAST_VISIBLE_CONTENTS - 1)
		                        | CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP | CONTENTS_MIST)))
		{
			side->contents |= CONTENTS_SOLID;
		}

		// hints and skips are never detail, and have no content
//		if (side->surf & (SURF_HINT|SURF_SKIP) )
//		{
//			side->contents = 0;
//			side->surf &= ~CONTENTS_DETAIL;
//		}

#ifdef ME
		//for creating AAS... this side is textured
		side->flags |= SFL_TEXTURED;
#endif //ME
		//
		// find the plane number
		//
		planenum = PlaneFromPoints(planepts[0], planepts[1], planepts[2]);
		if (planenum == -1)
		{
			Log_Print("Entity %i, Brush %i: plane with no normal\n"
			          , b->entitynum, b->brushnum);
			continue;
		}

		//
		// see if the plane has been used already
		//
		for (k = 0 ; k < b->numsides ; k++)
		{
			s2 = b->original_sides + k;
			if (s2->planenum == planenum)
			{
				Log_Print("Entity %i, Brush %i: duplicate plane\n"
				          , b->entitynum, b->brushnum);
				break;
			}
			if (s2->planenum == (planenum ^ 1))
			{
				Log_Print("Entity %i, Brush %i: mirrored plane\n"
				          , b->entitynum, b->brushnum);
				break;
			}
		}
		if (k != b->numsides)
		{
			continue;       // duplicated

		}
		//
		// keep this side
		//

		side           = b->original_sides + b->numsides;
		side->planenum = planenum;
		side->texinfo  = TexinfoForBrushTexture(&mapplanes[planenum],
		                                        &td, vec3_origin);

		// save the td off in case there is an origin brush and we
		// have to recalculate the texinfo
		side_brushtextures[nummapbrushsides] = td;

		nummapbrushsides++;
		b->numsides++;
	}
	while (1);

	// get the content for the entire brush
	b->contents = Q2_BrushContents(b);

#ifdef ME
	if (BrushExists(b))
	{
		c_squattbrushes++;
		b->numsides = 0;
		return;
	} //end if

	if (create_aas)
	{
		//create AAS brushes, and add brush bevels
		AAS_CreateMapBrushes(b, mapent, true);
		//NOTE: if we return here then duplicate plane errors occur for the non world entities
		return;
	} //end if
#endif //ME

	// allow detail brushes to be removed
	if (nodetail && (b->contents & CONTENTS_DETAIL))
	{
		b->numsides = 0;
		return;
	}

	// allow water brushes to be removed
	if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)))
	{
		b->numsides = 0;
		return;
	}

	// create windings for sides and bounds for brush
	MakeBrushWindings(b);

	// brushes that will not be visible at all will never be
	// used as bsp splitters
	if (b->contents & (CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP))
	{
		c_clipbrushes++;
		for (i = 0 ; i < b->numsides ; i++)
			b->original_sides[i].texinfo = TEXINFO_NODE;
	}

	//
	// origin brushes are removed, but they set
	// the rotation origin for the rest of the brushes
	// in the entity.  After the entire entity is parsed,
	// the planenums and texinfos will be adjusted for
	// the origin brush
	//
	if (b->contents & CONTENTS_ORIGIN)
	{
		char   string[32];
		vec3_t origin;

		if (num_entities == 1)
		{
			Error("Entity %i, Brush %i: origin brushes not allowed in world"
			      , b->entitynum, b->brushnum);
			return;
		}

		VectorAdd(b->mins, b->maxs, origin);
		VectorScale(origin, 0.5, origin);

		sprintf(string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
		SetKeyValue(&entities[b->entitynum], "origin", string);

		VectorCopy(origin, entities[b->entitynum].origin);

		// don't keep this brush
		b->numsides = 0;

		return;
	}

	AddBrushBevels(b);

	nummapbrushes++;
	mapent->numbrushes++;
}
Exemplo n.º 11
0
/*
=================
ParseBrush
=================
*/
void ParseBrush (entity_t *mapent)
{
	char *tl;
	mapbrush_t		*b;
	int			i,j, k;
	int			mt;
	side_t		*side, *s2;
	int			planenum;
	brush_texture_t	td;
	float			planepts[3][3];
	qboolean		phongShading;

	MarkBrushBegin();

	if (nummapbrushes == MAX_MAP_BRUSHES)
		Error ("nummapbrushes == MAX_MAP_BRUSHES");

	b = &mapbrushes[nummapbrushes];
	b->original_sides = &brushsides[nummapbrushsides];
	b->entitynum = num_entities-1;
	b->brushnum = nummapbrushes - mapent->firstbrush;

	// Knightmare added
	b->optimizedDetail = false;
	b->isTerrain = (!strcmp("func_group", ValueForKey (&entities[b->entitynum], "classname"))
				&& strlen(ValueForKey (&entities[b->entitynum], "terrain")) > 0);
	b->isGenSurf = (!strcmp("func_group", ValueForKey (&entities[b->entitynum], "classname"))
				&& strlen(ValueForKey (&entities[b->entitynum], "gensurf")) > 0);
	phongShading = (!strcmp("func_group", ValueForKey (&entities[b->entitynum], "classname"))
				&& strlen(ValueForKey (&entities[b->entitynum], "phongshading")) > 0);
	//if (b->isTerrain) 
	//	printf ("Brush number %i in enitity number %i has terrain flag set.\n", b->brushnum, b->entitynum);
	//if (b->phongShading) 
	//	printf ("Brush number %i in enitity number %i has phong shading flag set.\n", b->brushnum, b->entitynum);
	if (verbosebrushes)
		printf ("enitity %i, brush  %i\n", b->entitynum, b->brushnum);
	// end Knightmare

	do
	{
		if (!GetToken (true))
			break;
		if (!strcmp (token, "}") )
			break;

		if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
			Error ("MAX_MAP_BRUSHSIDES");
		side = &brushsides[nummapbrushsides];

		// read the three point plane definition
		for (i=0 ; i<3 ; i++)
		{
			if (i != 0)
				GetToken (true);
			if (strcmp (token, "(") )
				Error ("parsing brush\n  Brush: %s", i+1, brush_info);
			
			for (j=0 ; j<3 ; j++)
			{
				GetToken (false);
				planepts[i][j] = atof(token);
			}
			
			GetToken (false);
			if (strcmp (token, ")") )
				Error ("parsing brush\n  Brush: %s", i+1, brush_info);
				
		}

		//
		// read the texturedef
		//
		GetToken (false);
        strcpy (td.name, token);

		tl = td.name;

		for(tl = td.name; *tl != 0; tl++)
			*tl = tolower(*tl);

		GetToken (false);
		td.shift[0] = atoi(token);
		GetToken (false);
		td.shift[1] = atoi(token);
		GetToken (false);
		td.rotate = atoi(token);	
		GetToken (false);
		td.scale[0] = atof(token);
		GetToken (false);
		td.scale[1] = atof(token);

		// find default flags and values
		mt = FindMiptex (td.name);
		td.flags = textureref[mt].flags;
		td.value = textureref[mt].value;
		side->contents = textureref[mt].contents;
		side->surf = td.flags = textureref[mt].flags;

		if (TokenAvailable())
		{
			GetToken (false);
			side->contents = atoi(token);
			GetToken (false);
			side->surf = td.flags = atoi(token);
			GetToken (false);
			td.value = atoi(token);
		}

		// translucent objects are automatically classified as detail
		if (side->surf & (SURF_TRANS33|SURF_TRANS66|SURF_ALPHATEST) ) // Knightmare- added alphatest
			side->contents |= CONTENTS_DETAIL;
		if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
			side->contents |= CONTENTS_DETAIL;
		if (fulldetail)
			side->contents &= ~CONTENTS_DETAIL;
		if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1) 
			| CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST)  ) )
			side->contents |= CONTENTS_SOLID;

		// hints and skips are never detail, and have no content
		if (side->surf & (SURF_HINT|SURF_SKIP) )
		{
			//side->contents = 0;
			//side->surf &= ~CONTENTS_DETAIL;
			side->contents &= CONTENTS_DETAIL; // allow only detail content- Geoffery DeWan?
		}

		//
		// find the plane number
		//
		planenum = PlaneFromPoints (planepts[0], planepts[1], planepts[2]);
		if (planenum == -1)
		{
			printf ("Entity %i, Brush %i: plane with no normal\n  Brush: %s\n"
				, b->entitynum, b->brushnum, brush_info);
			continue;
		}

		//
		// see if the plane has been used already
		//
		for (k=0 ; k<b->numsides ; k++)
		{
			s2 = b->original_sides + k;
			if (s2->planenum == planenum)
			{
				printf ("Entity %i, Brush %i: duplicate plane\n  Brush: %s\n"
					, b->entitynum, b->brushnum, brush_info);
				break;
			}
			if ( s2->planenum == (planenum^1) )
			{
				printf ("Entity %i, Brush %i: mirrored plane\n  Brush: %s\n"
					, b->entitynum, b->brushnum, brush_info);
				break;
			}
		}
		if (k != b->numsides)
			continue;		// duplicated

		//
		// keep this side
		//

		side = b->original_sides + b->numsides;
		side->planenum = planenum;
		side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum],
			&td, vec3_origin, b->isTerrain); // Knightmare added

		// save the td off in case there is an origin brush and we
		// have to recalculate the texinfo
		side_brushtextures[nummapbrushsides] = td;

		nummapbrushsides++;
		b->numsides++;
	} while (1);

	// get the content for the entire brush
	b->contents = BrushContents (b);

	// allow detail brushes to be removed 
	if (nodetail && (b->contents & CONTENTS_DETAIL) )
	{
		b->numsides = 0;
		return;
	}

	// allow water brushes to be removed
	if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) )
	{
		b->numsides = 0;
		return;
	}

	// Knightmare- check if this is an optimized detail brush (has caulk faces)
	// also exclude trans brushes and terrain
	if ((b->contents & CONTENTS_DETAIL) && (b->contents & CONTENTS_SOLID) && !b->isTerrain && !b->isGenSurf)
		for (i=0; i<b->numsides; i++)
		{
			if ( !strcmp(texinfo[b->original_sides[i].texinfo].texture, "system/caulk")
				|| !strcmp(texinfo[b->original_sides[i].texinfo].texture, "common/caulk") )
			{
				b->optimizedDetail = true;
				//printf ("Entity %i, Brush %i: optimized detail\n", b->entitynum, b->brushnum);
				break;
			}
		}

	// Knightmare- special handling for terrain brushes
	if (b->isTerrain || b->isGenSurf || phongShading)
		for (i=0; i<b->numsides; i++)
		{
			s2 = &b->original_sides[i];
			// set ArghRad phong shading value (because EasyGen/GTKGenSurf doesn't allow this)
			if (strcmp(texinfo[b->original_sides[i].texinfo].texture, "system/caulk")
				&& strcmp(texinfo[b->original_sides[i].texinfo].texture, "common/caulk"))
			{
				texinfo[s2->texinfo].value = 777 + b->entitynum;	// lucky 7's
				texinfo[s2->texinfo].flags &= ~SURF_LIGHT;			// must not be light-emitting
			}
		}

	// create windings for sides and bounds for brush

	// MEM_LEAK
	MakeBrushWindings (b);
	t_w = b->original_sides[0].winding;

	// brushes that will not be visible at all will never be
	// used as bsp splitters
	if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
	{
		c_clipbrushes++;
		for (i=0 ; i<b->numsides ; i++)
			b->original_sides[i].texinfo = TEXINFO_NODE;
	}

	//
	// origin brushes are removed, but they set
	// the rotation origin for the rest of the brushes
	// in the entity.  After the entire entity is parsed,
	// the planenums and texinfos will be adjusted for
	// the origin brush
	//
	if (b->contents & CONTENTS_ORIGIN)
	{
		char	string[32];
		vec3_t	origin;

		if (num_entities == 1)
		{
			Error ("Entity %i, Brush %i: origin brushes not allowed in world\n  BrushL %s",
				b->entitynum, b->brushnum, brush_info);
			return;
		}

		VectorAdd (b->mins, b->maxs, origin);
		VectorScale (origin, 0.5, origin);

		sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
		SetKeyValue (&entities[b->entitynum], "origin", string);

		VectorCopy (origin, entities[b->entitynum].origin);

		// don't keep this brush
		b->numsides = 0;

		return;
	}

	AddBrushBevels (b);

	nummapbrushes++;
	mapent->numbrushes++;		
}
Exemplo n.º 12
0
/**
 * @brief Parses a brush from the map file
 * @sa FindMiptex
 * @param[in] mapent The entity the brush to parse belongs to
 * @param[in] filename The map filename, used to derive the name for the footsteps file
 */
static void ParseBrush (entity_t* mapent, const char* filename)
{
	int j, k;
	brush_texture_t td;
	vec3_t planepts[3];
	const int checkOrFix = config.performMapCheck || config.fixMap ;

	if (nummapbrushes == MAX_MAP_BRUSHES)
		Sys_Error("nummapbrushes == MAX_MAP_BRUSHES (%i)", nummapbrushes);

	mapbrush_t* b = &mapbrushes[nummapbrushes];
	OBJZERO(*b);
	b->original_sides = &brushsides[nummapbrushsides];
	b->entitynum = num_entities - 1;
	b->brushnum = nummapbrushes - mapent->firstbrush;

	do {
		if (Q_strnull(GetToken()))
			break;
		if (*parsedToken == '}')
			break;

		if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
			Sys_Error("nummapbrushsides == MAX_MAP_BRUSHSIDES (%i)", nummapbrushsides);
		side_t* side = &brushsides[nummapbrushsides];

		/* read the three point plane definition */
		for (int i = 0; i < 3; i++) {
			if (i != 0)
				GetToken();
			if (*parsedToken != '(')
				Sys_Error("parsing brush");

			for (j = 0; j < 3; j++) {
				GetToken();
				planepts[i][j] = atof(parsedToken);
			}

			GetToken();
			if (*parsedToken != ')')
				Sys_Error("parsing brush");
		}

		/* read the texturedef */
		GetToken();
		if (strlen(parsedToken) >= MAX_TEXPATH) {
			if (config.performMapCheck || config.fixMap)
				Com_Printf("  ");/* hack to make this look like output from Check_Printf() */
			Com_Printf("ParseBrush: texture name too long (limit %i): %s\n", MAX_TEXPATH, parsedToken);
			if (config.fixMap)
				Sys_Error("Aborting, as -fix is active and saving might corrupt *.map by truncating texture name");
		}
		Q_strncpyz(td.name, parsedToken, sizeof(td.name));

		td.shift[0] = atof(GetToken());
		td.shift[1] = atof(GetToken());
		td.rotate = atof(GetToken());
		td.scale[0] = atof(GetToken());
		td.scale[1] = atof(GetToken());

		/* find default flags and values */
		const int mt = FindMiptex(td.name);
		side->surfaceFlags = td.surfaceFlags = side->contentFlags = td.value = 0;

		if (TokenAvailable()) {
			side->contentFlags = atoi(GetToken());
			side->surfaceFlags = td.surfaceFlags = atoi(GetToken());
			td.value = atoi(GetToken());
		}

		/* if in check or fix mode, let them choose to do this (with command line options),
		 * and then call is made elsewhere */
		if (!checkOrFix) {
			SetImpliedFlags(side, &td, b);
			/* if no other content flags are set - make this solid */
			if (!checkOrFix && side->contentFlags == 0)
				side->contentFlags = CONTENTS_SOLID;
		}

		/* translucent objects are automatically classified as detail and window */
		if (side->surfaceFlags & (SURF_BLEND33 | SURF_BLEND66 | SURF_ALPHATEST)) {
			side->contentFlags |= CONTENTS_DETAIL;
			side->contentFlags |= CONTENTS_TRANSLUCENT;
			side->contentFlags |= CONTENTS_WINDOW;
			side->contentFlags &= ~CONTENTS_SOLID;
		}
		if (config.fulldetail)
			side->contentFlags &= ~CONTENTS_DETAIL;
		if (!checkOrFix) {
			if (!(side->contentFlags & ((LAST_VISIBLE_CONTENTS - 1)
				| CONTENTS_ACTORCLIP | CONTENTS_WEAPONCLIP | CONTENTS_LIGHTCLIP)))
				side->contentFlags |= CONTENTS_SOLID;

			/* hints and skips are never detail, and have no content */
			if (side->surfaceFlags & (SURF_HINT | SURF_SKIP)) {
				side->contentFlags = 0;
				side->surfaceFlags &= ~CONTENTS_DETAIL;
			}
		}

		/* check whether the flags are ok */
		CheckFlags(side, b);

		/* generate a list of textures that should have footsteps when walking on them */
		if (mt > 0 && (side->surfaceFlags & SURF_FOOTSTEP))
			GenerateFootstepList(filename, mt);
		GenerateMaterialFile(filename, mt, side);

		/* find the plane number */
		int planenum = PlaneFromPoints(b, planepts[0], planepts[1], planepts[2]);
		if (planenum == PLANENUM_LEAF) {
			Com_Printf("Entity %i, Brush %i: plane with no normal\n", b->entitynum, b->brushnum);
			continue;
		}

		for (j = 0; j < 3; j++)
			VectorCopy(planepts[j], mapplanes[planenum].planeVector[j]);

		/* see if the plane has been used already */
		for (k = 0; k < b->numsides; k++) {
			const side_t* s2 = b->original_sides + k;
			if (s2->planenum == planenum) {
				Com_Printf("Entity %i, Brush %i: duplicate plane\n", b->entitynum, b->brushnum);
				break;
			}
			if (s2->planenum == (planenum ^ 1)) {
				Com_Printf("Entity %i, Brush %i: mirrored plane\n", b->entitynum, b->brushnum);
				break;
			}
		}
		if (k != b->numsides)
			continue;		/* duplicated */

		/* keep this side */
		side = b->original_sides + b->numsides;
		side->planenum = planenum;
		side->texinfo = TexinfoForBrushTexture(&mapplanes[planenum],
			&td, vec3_origin, side->contentFlags & CONTENTS_TERRAIN);
		side->brush = b;

		/* save the td off in case there is an origin brush and we
		 * have to recalculate the texinfo */
		side_brushtextures[nummapbrushsides] = td;

		Verb_Printf(VERB_DUMP, "Brush %i Side %i (%f %f %f) (%f %f %f) (%f %f %f) texinfo:%i[%s] plane:%i\n", nummapbrushes, nummapbrushsides,
			planepts[0][0], planepts[0][1], planepts[0][2],
			planepts[1][0], planepts[1][1], planepts[1][2],
			planepts[2][0], planepts[2][1], planepts[2][2],
			side->texinfo, td.name, planenum);

		nummapbrushsides++;
		b->numsides++;
	} while (1);

	/* get the content for the entire brush */
	b->contentFlags = BrushContents(b);

	/* copy all set face contentflags to the brush contentflags */
	for (int m = 0; m < b->numsides; m++)
		b->contentFlags |= b->original_sides[m].contentFlags;

	/* set DETAIL, TRANSLUCENT contentflags on all faces, if they have been set on any.
	 * called separately, if in check/fix mode */
	if (!checkOrFix)
		CheckPropagateParserContentFlags(b);

	/* allow detail brushes to be removed */
	if (config.nodetail && (b->contentFlags & CONTENTS_DETAIL)) {
		b->numsides = 0;
		return;
	}

	/* allow water brushes to be removed */
	if (config.nowater && (b->contentFlags & CONTENTS_WATER)) {
		b->numsides = 0;
		return;
	}

	/* create windings for sides and bounds for brush */
	MakeBrushWindings(b);

	Verb_Printf(VERB_DUMP, "Brush %i mins (%f %f %f) maxs (%f %f %f)\n", nummapbrushes,
		b->mbBox.mins[0], b->mbBox.mins[1], b->mbBox.mins[2],
		b->mbBox.maxs[0], b->mbBox.maxs[1], b->mbBox.maxs[2]);

	/* origin brushes are removed, but they set
	 * the rotation origin for the rest of the brushes (like func_door)
	 * in the entity. After the entire entity is parsed, the planenums
	 * and texinfos will be adjusted for the origin brush */
	if (!checkOrFix && (b->contentFlags & CONTENTS_ORIGIN)) {
		char string[32];
		vec3_t origin;

		if (num_entities == 1) {
			Sys_Error("Entity %i, Brush %i: origin brushes not allowed in world"
				, b->entitynum, b->brushnum);
			return;
		}

		b->mbBox.getCenter(origin);

		Com_sprintf(string, sizeof(string), "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
		SetKeyValue(&entities[b->entitynum], "origin", string);
		Verb_Printf(VERB_EXTRA, "Entity %i, Brush %i: set origin to %s\n", b->entitynum, b->brushnum, string);

		VectorCopy(origin, entities[b->entitynum].origin);

		/* don't keep this brush */
		b->numsides = 0;

		return;
	}

	if (!checkOrFix)
		AddBrushBevels(b);

	nummapbrushes++;
	mapent->numbrushes++;
}