Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

map_sin.c (32168B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 //-----------------------------------------------------------------------------
     23 //
     24 //  $Logfile:: /MissionPack/code/bspc/map_sin.c                               $
     25 
     26 #include "qbsp.h"
     27 #include "l_bsp_sin.h"
     28 #include "aas_map.h"			//AAS_CreateMapBrushes
     29 
     30 
     31 //====================================================================
     32 
     33 
     34 /*
     35 ===========
     36 Sin_BrushContents
     37 ===========
     38 */
     39 
     40 int Sin_BrushContents(mapbrush_t *b)
     41 {
     42 	int			contents;
     43 	side_t		*s;
     44 	int			i;
     45 #ifdef SIN
     46 	float			trans = 0;
     47 #else
     48 	int			trans;
     49 #endif
     50 
     51 	s = &b->original_sides[0];
     52 	contents = s->contents;
     53 
     54 #ifdef SIN
     55 	trans = sin_texinfo[s->texinfo].translucence;
     56 #else
     57 	trans = texinfo[s->texinfo].flags;
     58 #endif
     59 	for (i=1 ; i<b->numsides ; i++, s++)
     60 	{
     61 		s = &b->original_sides[i];
     62 #ifdef SIN
     63 		trans += sin_texinfo[s->texinfo].translucence;
     64 #else
     65 		trans |= texinfo[s->texinfo].flags;
     66 #endif
     67 		if (s->contents != contents)
     68 		{
     69 #ifdef SIN
     70       if ( 
     71             ( s->contents & CONTENTS_DETAIL && !(contents & CONTENTS_DETAIL) ) ||
     72             ( !(s->contents & CONTENTS_DETAIL) && contents & CONTENTS_DETAIL ) 
     73          )
     74          {
     75          s->contents |= CONTENTS_DETAIL;
     76          contents |= CONTENTS_DETAIL;
     77          continue;
     78          }
     79 #endif
     80 			printf ("Entity %i, Brush %i: mixed face contents\n"
     81 				, b->entitynum, b->brushnum);
     82 			break;
     83 		}
     84 	}
     85 
     86 
     87 #ifdef SIN
     88 	if (contents & CONTENTS_FENCE)
     89 	{
     90 //		contents |= CONTENTS_TRANSLUCENT;
     91 		contents |= CONTENTS_DETAIL;
     92 		contents |= CONTENTS_DUMMYFENCE;
     93 		contents &= ~CONTENTS_SOLID;
     94 		contents &= ~CONTENTS_FENCE;
     95 		contents |= CONTENTS_WINDOW;
     96 	}
     97 #endif
     98 
     99 	// if any side is translucent, mark the contents
    100 	// and change solid to window
    101 #ifdef SIN
    102 	if ( trans > 0 )
    103 #else
    104 	if ( trans & (SURF_TRANS33|SURF_TRANS66) )
    105 #endif
    106 	{
    107 		contents |= CONTENTS_Q2TRANSLUCENT;
    108 		if (contents & CONTENTS_SOLID)
    109 		{
    110 			contents &= ~CONTENTS_SOLID;
    111 			contents |= CONTENTS_WINDOW;
    112 		}
    113 	}
    114 
    115 	return contents;
    116 } //*/
    117 
    118 
    119 //============================================================================
    120 
    121 
    122 
    123 /*
    124 =================
    125 ParseBrush
    126 =================
    127 * /
    128 void ParseBrush (entity_t *mapent)
    129 {
    130 	mapbrush_t		*b;
    131 	int			i,j, k;
    132 	int			mt;
    133 	side_t		*side, *s2;
    134 	int			planenum;
    135 	brush_texture_t	td;
    136 #ifdef SIN
    137    textureref_t newref;
    138 #endif
    139 	int			planepts[3][3];
    140 
    141 	if (nummapbrushes == MAX_MAP_BRUSHES)
    142 		Error ("nummapbrushes == MAX_MAP_BRUSHES");
    143 
    144 	b = &mapbrushes[nummapbrushes];
    145 	b->original_sides = &brushsides[nummapbrushsides];
    146 	b->entitynum = num_entities-1;
    147 	b->brushnum = nummapbrushes - mapent->firstbrush;
    148 
    149 	do
    150 	{
    151 		if (!GetToken (true))
    152 			break;
    153 		if (!strcmp (token, "}") )
    154 			break;
    155 
    156 		if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
    157 			Error ("MAX_MAP_BRUSHSIDES");
    158 		side = &brushsides[nummapbrushsides];
    159 
    160 		// read the three point plane definition
    161 		for (i=0 ; i<3 ; i++)
    162 		{
    163 			if (i != 0)
    164 				GetToken (true);
    165 			if (strcmp (token, "(") )
    166 				Error ("parsing brush");
    167 			
    168 			for (j=0 ; j<3 ; j++)
    169 			{
    170 				GetToken (false);
    171 				planepts[i][j] = atoi(token);
    172 			}
    173 			
    174 			GetToken (false);
    175 			if (strcmp (token, ")") )
    176 				Error ("parsing brush");
    177 				
    178 		}
    179 
    180 
    181 		//
    182 		// read the texturedef
    183 		//
    184 		GetToken (false);
    185 		strcpy (td.name, token);
    186 
    187 		GetToken (false);
    188 		td.shift[0] = atoi(token);
    189 		GetToken (false);
    190 		td.shift[1] = atoi(token);
    191 		GetToken (false);
    192 #ifdef SIN
    193 		td.rotate = atof(token);	
    194 #else
    195 		td.rotate = atoi(token);	
    196 #endif
    197 		GetToken (false);
    198 		td.scale[0] = atof(token);
    199 		GetToken (false);
    200 		td.scale[1] = atof(token);
    201 
    202 		// find default flags and values
    203 		mt = FindMiptex (td.name);
    204 #ifdef SIN
    205       // clear out the masks on newref
    206       memset(&newref,0,sizeof(newref));
    207       // copy over the name
    208       strcpy( newref.name, td.name );
    209 
    210       ParseSurfaceInfo( &newref );
    211       MergeRefs( &bsp_textureref[mt], &newref, &td.tref );
    212       side->contents = td.tref.contents;
    213       side->surf = td.tref.flags;
    214 #else
    215 		td.flags = textureref[mt].flags;
    216 		td.value = textureref[mt].value;
    217 		side->contents = textureref[mt].contents;
    218 		side->surf = td.flags = textureref[mt].flags;
    219 
    220 		if (TokenAvailable())
    221 		{
    222 			GetToken (false);
    223 			side->contents = atoi(token);
    224 			GetToken (false);
    225 			side->surf = td.flags = atoi(token);
    226 			GetToken (false);
    227 			td.value = atoi(token);
    228 		}
    229 #endif
    230 
    231 		// translucent objects are automatically classified as detail
    232 #ifdef SIN
    233 		if ( td.tref.translucence > 0 )
    234 #else
    235 		if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
    236 #endif
    237 			side->contents |= CONTENTS_DETAIL;
    238 		if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
    239 			side->contents |= CONTENTS_DETAIL;
    240 		if (fulldetail)
    241 			side->contents &= ~CONTENTS_DETAIL;
    242 		if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1) 
    243 			| CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST)  ) )
    244 			side->contents |= CONTENTS_SOLID;
    245 
    246 		// hints and skips are never detail, and have no content
    247 		if (side->surf & (SURF_HINT|SURF_SKIP) )
    248 		{
    249 			side->contents = 0;
    250 #ifndef SIN // I think this is a bug of some kind
    251 			side->surf &= ~CONTENTS_DETAIL;
    252 #endif
    253 		}
    254 
    255 		//
    256 		// find the plane number
    257 		//
    258 		planenum = PlaneFromPoints (planepts[0], planepts[1], planepts[2]);
    259 		if (planenum == -1)
    260 		{
    261 			printf ("Entity %i, Brush %i: plane with no normal\n"
    262 				, b->entitynum, b->brushnum);
    263 			continue;
    264 		}
    265 
    266 		//
    267 		// see if the plane has been used already
    268 		//
    269 		for (k=0 ; k<b->numsides ; k++)
    270 		{
    271 			s2 = b->original_sides + k;
    272 			if (s2->planenum == planenum)
    273 			{
    274 				printf ("Entity %i, Brush %i: duplicate plane\n"
    275 					, b->entitynum, b->brushnum);
    276 				break;
    277 			}
    278 			if ( s2->planenum == (planenum^1) )
    279 			{
    280 				printf ("Entity %i, Brush %i: mirrored plane\n"
    281 					, b->entitynum, b->brushnum);
    282 				break;
    283 			}
    284 		}
    285 		if (k != b->numsides)
    286 			continue;		// duplicated
    287 
    288 		//
    289 		// keep this side
    290 		//
    291 
    292 		side = b->original_sides + b->numsides;
    293 		side->planenum = planenum;
    294 #ifdef SIN
    295 		side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum],
    296 			&td, vec3_origin, &newref);
    297       // 
    298       // save off lightinfo
    299       //
    300 		side->lightinfo = LightinfoForBrushTexture ( &td );
    301 #else
    302 		side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum],
    303 			&td, vec3_origin);
    304 
    305 #endif
    306 
    307 		// save the td off in case there is an origin brush and we
    308 		// have to recalculate the texinfo
    309 		side_brushtextures[nummapbrushsides] = td;
    310 #ifdef SIN
    311       // save off the merged tref for animating textures
    312 		side_newrefs[nummapbrushsides] = newref;
    313 #endif
    314 
    315 		nummapbrushsides++;
    316 		b->numsides++;
    317 	} while (1);
    318 
    319 	// get the content for the entire brush
    320 	b->contents = Sin_BrushContents (b);
    321 
    322 	// allow detail brushes to be removed 
    323 	if (nodetail && (b->contents & CONTENTS_DETAIL) )
    324 	{
    325 		b->numsides = 0;
    326 		return;
    327 	}
    328 
    329 	// allow water brushes to be removed
    330 	if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) )
    331 	{
    332 		b->numsides = 0;
    333 		return;
    334 	}
    335 
    336 	// create windings for sides and bounds for brush
    337 	MakeBrushWindings (b);
    338 
    339 	// brushes that will not be visible at all will never be
    340 	// used as bsp splitters
    341 	if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
    342 	{
    343 		c_clipbrushes++;
    344 		for (i=0 ; i<b->numsides ; i++)
    345 			b->original_sides[i].texinfo = TEXINFO_NODE;
    346 	}
    347 
    348 	//
    349 	// origin brushes are removed, but they set
    350 	// the rotation origin for the rest of the brushes
    351 	// in the entity.  After the entire entity is parsed,
    352 	// the planenums and texinfos will be adjusted for
    353 	// the origin brush
    354 	//
    355 	if (b->contents & CONTENTS_ORIGIN)
    356 	{
    357 		char	string[32];
    358 		vec3_t	origin;
    359 
    360 		if (num_entities == 1)
    361 		{
    362 			Error ("Entity %i, Brush %i: origin brushes not allowed in world"
    363 				, b->entitynum, b->brushnum);
    364 			return;
    365 		}
    366 
    367 		VectorAdd (b->mins, b->maxs, origin);
    368 		VectorScale (origin, 0.5, origin);
    369 
    370 		sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
    371 		SetKeyValue (&entities[b->entitynum], "origin", string);
    372 
    373 		VectorCopy (origin, entities[b->entitynum].origin);
    374 
    375 		// don't keep this brush
    376 		b->numsides = 0;
    377 
    378 		return;
    379 	}
    380 
    381 	AddBrushBevels (b);
    382 
    383 	nummapbrushes++;
    384 	mapent->numbrushes++;		
    385 } //*/
    386 
    387 /*
    388 ================
    389 MoveBrushesToWorld
    390 
    391 Takes all of the brushes from the current entity and
    392 adds them to the world's brush list.
    393 
    394 Used by func_group and func_areaportal
    395 ================
    396 * /
    397 void MoveBrushesToWorld (entity_t *mapent)
    398 {
    399 	int			newbrushes;
    400 	int			worldbrushes;
    401 	mapbrush_t	*temp;
    402 	int			i;
    403 
    404 	// this is pretty gross, because the brushes are expected to be
    405 	// in linear order for each entity
    406 
    407 	newbrushes = mapent->numbrushes;
    408 	worldbrushes = entities[0].numbrushes;
    409 
    410 	temp = malloc(newbrushes*sizeof(mapbrush_t));
    411 	memcpy (temp, mapbrushes + mapent->firstbrush, newbrushes*sizeof(mapbrush_t));
    412 
    413 #if	0		// let them keep their original brush numbers
    414 	for (i=0 ; i<newbrushes ; i++)
    415 		temp[i].entitynum = 0;
    416 #endif
    417 
    418 	// make space to move the brushes (overlapped copy)
    419 	memmove (mapbrushes + worldbrushes + newbrushes,
    420 		mapbrushes + worldbrushes,
    421 		sizeof(mapbrush_t) * (nummapbrushes - worldbrushes - newbrushes) );
    422 
    423 	// copy the new brushes down
    424 	memcpy (mapbrushes + worldbrushes, temp, sizeof(mapbrush_t) * newbrushes);
    425 
    426 	// fix up indexes
    427 	entities[0].numbrushes += newbrushes;
    428 	for (i=1 ; i<num_entities ; i++)
    429 		entities[i].firstbrush += newbrushes;
    430 	free (temp);
    431 
    432 	mapent->numbrushes = 0;
    433 } //*/
    434 
    435 /*
    436 ================
    437 ParseMapEntity
    438 ================
    439 * /
    440 qboolean	Sin_ParseMapEntity (void)
    441 {
    442 	entity_t	*mapent;
    443 	epair_t		*e;
    444 	side_t		*s;
    445 	int			i, j;
    446 	int			startbrush, startsides;
    447 	vec_t		newdist;
    448 	mapbrush_t	*b;
    449 
    450 	if (!GetToken (true))
    451 		return false;
    452 
    453 	if (strcmp (token, "{") )
    454 		Error ("ParseEntity: { not found");
    455 	
    456 	if (num_entities == MAX_MAP_ENTITIES)
    457 		Error ("num_entities == MAX_MAP_ENTITIES");
    458 
    459 	startbrush = nummapbrushes;
    460 	startsides = nummapbrushsides;
    461 
    462 	mapent = &entities[num_entities];
    463 	num_entities++;
    464 	memset (mapent, 0, sizeof(*mapent));
    465 	mapent->firstbrush = nummapbrushes;
    466 	mapent->numbrushes = 0;
    467 //	mapent->portalareas[0] = -1;
    468 //	mapent->portalareas[1] = -1;
    469 
    470 	do
    471 	{
    472 		if (!GetToken (true))
    473 			Error ("ParseEntity: EOF without closing brace");
    474 		if (!strcmp (token, "}") )
    475 			break;
    476 		if (!strcmp (token, "{") )
    477 			ParseBrush (mapent);
    478 		else
    479 		{
    480 			e = ParseEpair ();
    481 #ifdef SIN
    482          //HACK HACK HACK
    483          // MED Gotta do this here
    484          if ( !stricmp(e->key, "surfacefile") )
    485             {
    486             if (!surfacefile[0])
    487                {
    488                strcpy( surfacefile, e->value );
    489                }
    490 		      printf ("--- ParseSurfaceFile ---\n");
    491 		      printf ("Surface script: %s\n", surfacefile);
    492 		      if (!ParseSurfaceFile(surfacefile))
    493                {
    494 		         Error ("Script file not found: %s\n", surfacefile);
    495                }
    496             }
    497 #endif
    498 			e->next = mapent->epairs;
    499 			mapent->epairs = e;
    500 		}
    501 	} while (1);
    502 
    503 #ifdef SIN
    504     if (!(strlen(ValueForKey(mapent, "origin")))  && ((num_entities-1) != 0))
    505         {
    506         mapbrush_t     *brush;
    507         vec3_t		    origin;
    508   	    char		    string[32];
    509         vec3_t          mins, maxs;
    510         int			    start, end;
    511         // Calculate bounds
    512 
    513         start = mapent->firstbrush;
    514 	    end = start + mapent->numbrushes;
    515 	    ClearBounds (mins, maxs);
    516 
    517 	    for (j=start ; j<end ; j++)
    518             {
    519 	        brush = &mapbrushes[j];
    520 		    if (!brush->numsides)
    521 			    continue;	// not a real brush (origin brush) - shouldn't happen
    522 		    AddPointToBounds (brush->mins, mins, maxs);
    523 		    AddPointToBounds (brush->maxs, mins, maxs);
    524             }
    525 
    526         // Set the origin to be the centroid of the entity.
    527         VectorAdd ( mins, maxs, origin);
    528 		VectorScale( origin, 0.5f, origin );
    529 
    530 		sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
    531 		SetKeyValue ( mapent, "origin", string);
    532 //        qprintf("Setting origin to %s\n",string);
    533         }
    534 #endif
    535 
    536 	GetVectorForKey (mapent, "origin", mapent->origin);
    537 
    538 #ifdef SIN
    539 	if (
    540          (!strcmp ("func_areaportal", ValueForKey (mapent, "classname"))) ||
    541          (!strcmp ("func_group", ValueForKey (mapent, "classname"))) ||
    542       	(!strcmp ("detail", ValueForKey (mapent, "classname")) && !entitydetails)
    543       )
    544       {
    545       VectorClear( mapent->origin );
    546       }
    547 #endif
    548 
    549 	//
    550 	// if there was an origin brush, offset all of the planes and texinfo
    551 	//
    552 	if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2])
    553 	{
    554 		for (i=0 ; i<mapent->numbrushes ; i++)
    555 		{
    556 			b = &mapbrushes[mapent->firstbrush + i];
    557 			for (j=0 ; j<b->numsides ; j++)
    558 			{
    559 				s = &b->original_sides[j];
    560 				newdist = mapplanes[s->planenum].dist -
    561 					DotProduct (mapplanes[s->planenum].normal, mapent->origin);
    562 				s->planenum = FindFloatPlane (mapplanes[s->planenum].normal, newdist);
    563 #ifdef SIN
    564 				s->texinfo = TexinfoForBrushTexture (&mapplanes[s->planenum],
    565 					&side_brushtextures[s-brushsides], mapent->origin, &side_newrefs[s-brushsides]);
    566             // 
    567             // save off lightinfo
    568             //
    569             s->lightinfo = LightinfoForBrushTexture (	&side_brushtextures[s-brushsides] );
    570 #else
    571 				s->texinfo = TexinfoForBrushTexture (&mapplanes[s->planenum],
    572 					&side_brushtextures[s-brushsides], mapent->origin);
    573 #endif
    574 			}
    575 			MakeBrushWindings (b);
    576 		}
    577 	}
    578 
    579 	// group entities are just for editor convenience
    580 	// toss all brushes into the world entity
    581 	if (!strcmp ("func_group", ValueForKey (mapent, "classname")))
    582 	{
    583 		MoveBrushesToWorld (mapent);
    584 		mapent->numbrushes = 0;
    585 		mapent->wasdetail = true;
    586       FreeValueKeys( mapent );
    587 		return true;
    588 	}
    589 #ifdef SIN
    590 	// detail entities are just for editor convenience
    591 	// toss all brushes into the world entity as detail brushes
    592 	if (!strcmp ("detail", ValueForKey (mapent, "classname")) && !entitydetails)
    593 	{
    594 		for (i=0 ; i<mapent->numbrushes ; i++)
    595 		{
    596          int j;
    597          side_t * s;
    598 			b = &mapbrushes[mapent->firstbrush + i];
    599    	   if (nodetail)
    600             {
    601             b->numsides = 0;
    602             continue;
    603             }
    604          if (!fulldetail)
    605             {
    606    	      // set the contents for the entire brush
    607 	         b->contents |= CONTENTS_DETAIL;
    608 			   // set the contents in the sides as well
    609 			   for (j=0, s=b->original_sides ; j<b->numsides ; j++,s++)
    610 		   	   {
    611                s->contents |= CONTENTS_DETAIL;
    612 	   	   	}
    613             }
    614          else
    615             {
    616    	      // set the contents for the entire brush
    617 	         b->contents |= CONTENTS_SOLID;
    618 			   // set the contents in the sides as well
    619 			   for (j=0, s=b->original_sides ; j<b->numsides ; j++,s++)
    620 		   	   {
    621                s->contents |= CONTENTS_SOLID;
    622 	   	   	}
    623             }
    624 		}
    625 		MoveBrushesToWorld (mapent);
    626 		mapent->wasdetail = true;
    627       FreeValueKeys( mapent );
    628       // kill off the entity
    629    	// num_entities--;
    630 		return true;
    631 	}
    632 #endif
    633 
    634 	// areaportal entities move their brushes, but don't eliminate
    635 	// the entity
    636 	if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname")))
    637 	{
    638 		char	str[128];
    639 
    640 		if (mapent->numbrushes != 1)
    641 			Error ("Entity %i: func_areaportal can only be a single brush", num_entities-1);
    642 
    643 		b = &mapbrushes[nummapbrushes-1];
    644 		b->contents = CONTENTS_AREAPORTAL;
    645 		c_areaportals++;
    646 		mapent->areaportalnum = c_areaportals;
    647 		// set the portal number as "style"
    648 		sprintf (str, "%i", c_areaportals);
    649 		SetKeyValue (mapent, "style", str);
    650 		MoveBrushesToWorld (mapent);
    651 		return true;
    652 	}
    653 
    654 	return true;
    655 } //end of the function Sin_ParseMapEntity */
    656 
    657 //===================================================================
    658 
    659 /*
    660 ================
    661 LoadMapFile
    662 ================
    663 * /
    664 void Sin_LoadMapFile (char *filename)
    665 {		
    666 	int		i;
    667 #ifdef SIN
    668    int num_detailsides=0;
    669    int num_detailbrushes=0;
    670    int num_worldsides=0;
    671    int num_worldbrushes=0;
    672    int      j,k;
    673 #endif
    674 
    675 	qprintf ("--- LoadMapFile ---\n");
    676 
    677 	LoadScriptFile (filename);
    678 
    679 	nummapbrushsides = 0;
    680 	num_entities = 0;
    681 	
    682 	while (ParseMapEntity ())
    683 	{
    684 	}
    685 
    686 	ClearBounds (map_mins, map_maxs);
    687 	for (i=0 ; i<entities[0].numbrushes ; i++)
    688 	{
    689 		if (mapbrushes[i].mins[0] > 4096)
    690 			continue;	// no valid points
    691 		AddPointToBounds (mapbrushes[i].mins, map_mins, map_maxs);
    692 		AddPointToBounds (mapbrushes[i].maxs, map_mins, map_maxs);
    693 	}
    694 #ifdef SIN
    695    for (j=0;  j<num_entities; j++)
    696       {
    697 	   for (i=0 ; i<entities[j].numbrushes ; i++)
    698 	      {
    699          side_t * s;
    700          mapbrush_t *b;
    701 			b = &mapbrushes[entities[j].firstbrush + i];
    702          if (b->numsides && b->contents & CONTENTS_DETAIL)
    703             num_detailbrushes++;
    704          else if (b->numsides)
    705             num_worldbrushes++;
    706 			for (k=0, s=b->original_sides ; k<b->numsides ; k++,s++)
    707 			   {
    708             if (s->contents & CONTENTS_DETAIL)
    709                num_detailsides++;
    710             else
    711                num_worldsides++;
    712 			   }
    713    	   }
    714       }
    715 #endif
    716 
    717 	qprintf ("%5i brushes\n", nummapbrushes);
    718 	qprintf ("%5i clipbrushes\n", c_clipbrushes);
    719 	qprintf ("%5i total sides\n", nummapbrushsides);
    720 	qprintf ("%5i boxbevels\n", c_boxbevels);
    721 	qprintf ("%5i edgebevels\n", c_edgebevels);
    722 	qprintf ("%5i entities\n", num_entities);
    723 	qprintf ("%5i planes\n", nummapplanes);
    724 	qprintf ("%5i areaportals\n", c_areaportals);
    725 	qprintf ("size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n", map_mins[0],map_mins[1],map_mins[2],
    726 		map_maxs[0],map_maxs[1],map_maxs[2]);
    727 #ifdef SIN
    728 	qprintf ("%5i detailbrushes\n", num_detailbrushes);
    729 	qprintf ("%5i worldbrushes\n", num_worldbrushes);
    730 	qprintf ("%5i detailsides\n", num_detailsides);
    731 	qprintf ("%5i worldsides\n", num_worldsides);
    732 #endif
    733 
    734 } //end of the function Sin_LoadMap */
    735 
    736 
    737 #ifdef ME		//Begin MAP loading from BSP file
    738 //===========================================================================
    739 //
    740 // Parameter:				-
    741 // Returns:					-
    742 // Changes Globals:		-
    743 //===========================================================================
    744 void Sin_CreateMapTexinfo(void)
    745 {
    746 	int i;
    747 	vec_t defaultvec[4] = {1, 0, 0, 0};
    748 
    749 	memcpy(map_texinfo[0].vecs[0], defaultvec, sizeof(defaultvec));
    750 	memcpy(map_texinfo[0].vecs[1], defaultvec, sizeof(defaultvec));
    751 	map_texinfo[0].flags = 0;
    752 	map_texinfo[0].value = 0;
    753 	strcpy(map_texinfo[0].texture, "generic/misc/red");	//no texture
    754 	map_texinfo[0].nexttexinfo = -1;
    755 	for (i = 1; i < sin_numtexinfo; i++)
    756 	{
    757 		memcpy(map_texinfo[i].vecs, sin_texinfo[i].vecs, sizeof(float) * 2 * 4);
    758 		map_texinfo[i].flags = sin_texinfo[i].flags;
    759 		map_texinfo[i].value = 0;
    760 		strcpy(map_texinfo[i].texture, sin_texinfo[i].texture);
    761 		map_texinfo[i].nexttexinfo = -1;
    762 	} //end for
    763 } //end of the function Sin_CreateMapTexinfo
    764 //===========================================================================
    765 //
    766 // Parameter:				-
    767 // Returns:					-
    768 // Changes Globals:		-
    769 //===========================================================================
    770 void Sin_SetLeafBrushesModelNumbers(int leafnum, int modelnum)
    771 {
    772 	int i, brushnum;
    773 	sin_dleaf_t *leaf;
    774 
    775 	leaf = &sin_dleafs[leafnum];
    776 	for (i = 0; i < leaf->numleafbrushes; i++)
    777 	{
    778 		brushnum = sin_dleafbrushes[leaf->firstleafbrush + i];
    779 		brushmodelnumbers[brushnum] = modelnum;
    780 		dbrushleafnums[brushnum] = leafnum;
    781 	} //end for
    782 } //end of the function Sin_SetLeafBrushesModelNumbers
    783 //===========================================================================
    784 //
    785 // Parameter:				-
    786 // Returns:					-
    787 // Changes Globals:		-
    788 //===========================================================================
    789 void Sin_InitNodeStack(void)
    790 {
    791 	nodestackptr = nodestack;
    792 	nodestacksize = 0;
    793 } //end of the function Sin_InitNodeStack
    794 //===========================================================================
    795 //
    796 // Parameter:				-
    797 // Returns:					-
    798 // Changes Globals:		-
    799 //===========================================================================
    800 void Sin_PushNodeStack(int num)
    801 {
    802 	*nodestackptr = num;
    803 	nodestackptr++;
    804 	nodestacksize++;
    805 	//
    806 	if (nodestackptr >= &nodestack[NODESTACKSIZE])
    807 	{
    808 		Error("Sin_PushNodeStack: stack overflow\n");
    809 	} //end if
    810 } //end of the function Sin_PushNodeStack
    811 //===========================================================================
    812 //
    813 // Parameter:				-
    814 // Returns:					-
    815 // Changes Globals:		-
    816 //===========================================================================
    817 int Sin_PopNodeStack(void)
    818 {
    819 	//if the stack is empty
    820 	if (nodestackptr <= nodestack) return -1;
    821 	//decrease stack pointer
    822 	nodestackptr--;
    823 	nodestacksize--;
    824 	//return the top value from the stack
    825 	return *nodestackptr;
    826 } //end of the function Sin_PopNodeStack
    827 //===========================================================================
    828 //
    829 // Parameter:				-
    830 // Returns:					-
    831 // Changes Globals:		-
    832 //===========================================================================
    833 void Sin_SetBrushModelNumbers(entity_t *mapent)
    834 {
    835 	int n, pn;
    836 	int leafnum;
    837 
    838 	//
    839 	Sin_InitNodeStack();
    840 	//head node (root) of the bsp tree
    841 	n = sin_dmodels[mapent->modelnum].headnode;
    842 	pn = 0;
    843 	
    844 	do
    845 	{
    846 		//if we are in a leaf (negative node number)
    847 		if (n < 0)
    848 		{
    849 			//number of the leaf
    850 			leafnum = (-n) - 1;
    851 			//set the brush numbers
    852 			Sin_SetLeafBrushesModelNumbers(leafnum, mapent->modelnum);
    853 			//walk back into the tree to find a second child to continue with
    854 			for (pn = Sin_PopNodeStack(); pn >= 0; n = pn, pn = Sin_PopNodeStack())
    855 			{
    856 				//if we took the first child at the parent node
    857 				if (sin_dnodes[pn].children[0] == n) break;
    858 			} //end for
    859 			//if the stack wasn't empty (if not processed whole tree)
    860 			if (pn >= 0)
    861 			{
    862 				//push the parent node again
    863 				Sin_PushNodeStack(pn);
    864 				//we proceed with the second child of the parent node
    865 				n = sin_dnodes[pn].children[1];
    866 			} //end if
    867 		} //end if
    868 		else
    869 		{
    870 			//push the current node onto the stack
    871 			Sin_PushNodeStack(n);
    872 			//walk forward into the tree to the first child
    873 			n = sin_dnodes[n].children[0];
    874 		} //end else
    875 	} while(pn >= 0);
    876 } //end of the function Sin_SetBrushModelNumbers
    877 //===========================================================================
    878 //
    879 // Parameter:				-
    880 // Returns:					-
    881 // Changes Globals:		-
    882 //===========================================================================
    883 void Sin_BSPBrushToMapBrush(sin_dbrush_t *bspbrush, entity_t *mapent)
    884 {
    885 	mapbrush_t *b;
    886 	int i, k, n;
    887 	side_t *side, *s2;
    888 	int planenum;
    889 	sin_dbrushside_t *bspbrushside;
    890 	sin_dplane_t *bspplane;
    891 
    892 	if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
    893 		Error ("nummapbrushes >= MAX_MAPFILE_BRUSHES");
    894 
    895 	b = &mapbrushes[nummapbrushes];
    896 	b->original_sides = &brushsides[nummapbrushsides];
    897 	b->entitynum = mapent-entities;
    898 	b->brushnum = nummapbrushes - mapent->firstbrush;
    899 	b->leafnum = dbrushleafnums[bspbrush - sin_dbrushes];
    900 
    901 	for (n = 0; n < bspbrush->numsides; n++)
    902 	{
    903 		//pointer to the bsp brush side
    904 		bspbrushside = &sin_dbrushsides[bspbrush->firstside + n];
    905 
    906 		if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
    907 		{
    908 			Error ("MAX_MAPFILE_BRUSHSIDES");
    909 		} //end if
    910 		//pointer to the map brush side
    911 		side = &brushsides[nummapbrushsides];
    912 		//if the BSP brush side is textured
    913 		if (sin_dbrushsidetextured[bspbrush->firstside + n]) side->flags |= SFL_TEXTURED;
    914 		else side->flags &= ~SFL_TEXTURED;
    915 		//ME: can get side contents and surf directly from BSP file
    916 		side->contents = bspbrush->contents;
    917 		//if the texinfo is TEXINFO_NODE
    918 		if (bspbrushside->texinfo < 0) side->surf = 0;
    919 		else side->surf = sin_texinfo[bspbrushside->texinfo].flags;
    920 
    921 		// translucent objects are automatically classified as detail
    922 		if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
    923 			side->contents |= CONTENTS_DETAIL;
    924 		if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
    925 			side->contents |= CONTENTS_DETAIL;
    926 		if (fulldetail)
    927 			side->contents &= ~CONTENTS_DETAIL;
    928 		if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1) 
    929 			| CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST)  ) )
    930 			side->contents |= CONTENTS_SOLID;
    931 
    932 		// hints and skips are never detail, and have no content
    933 		if (side->surf & (SURF_HINT|SURF_SKIP) )
    934 		{
    935 			side->contents = 0;
    936 			side->surf &= ~CONTENTS_DETAIL;
    937 		}
    938 
    939 		//ME: get a plane for this side
    940 		bspplane = &sin_dplanes[bspbrushside->planenum];
    941 		planenum = FindFloatPlane(bspplane->normal, bspplane->dist);
    942 		//
    943 		// see if the plane has been used already
    944 		//
    945 		//ME: this really shouldn't happen!!!
    946 		//ME: otherwise the bsp file is corrupted??
    947 		//ME: still it seems to happen, maybe Johny Boy's
    948 		//ME: brush bevel adding is crappy ?
    949 		for (k = 0; k < b->numsides; k++)
    950 		{
    951 			s2 = b->original_sides + k;
    952 			if (s2->planenum == planenum)
    953 			{
    954 				Log_Print("Entity %i, Brush %i: duplicate plane\n"
    955 					, b->entitynum, b->brushnum);
    956 				break;
    957 			}
    958 			if ( s2->planenum == (planenum^1) )
    959 			{
    960 				Log_Print("Entity %i, Brush %i: mirrored plane\n"
    961 					, b->entitynum, b->brushnum);
    962 				break;
    963 			}
    964 		}
    965 		if (k != b->numsides)
    966 			continue;		// duplicated
    967 
    968 		//
    969 		// keep this side
    970 		//
    971 		//ME: reset pointer to side, why? hell I dunno (pointer is set above already)
    972 		side = b->original_sides + b->numsides;
    973 		//ME: store the plane number
    974 		side->planenum = planenum;
    975 		//ME: texinfo is already stored when bsp is loaded
    976 		//NOTE: check for TEXINFO_NODE, otherwise crash in Sin_BrushContents
    977 		if (bspbrushside->texinfo < 0) side->texinfo = 0;
    978 		else side->texinfo = bspbrushside->texinfo;
    979 
    980 		// save the td off in case there is an origin brush and we
    981 		// have to recalculate the texinfo
    982 		// ME: don't need to recalculate because it's already done
    983 		//     (for non-world entities) in the BSP file
    984 //		side_brushtextures[nummapbrushsides] = td;
    985 
    986 		nummapbrushsides++;
    987 		b->numsides++;
    988 	} //end for
    989 
    990 	// get the content for the entire brush
    991 	b->contents = bspbrush->contents;
    992 	Sin_BrushContents(b);
    993 
    994 	if (BrushExists(b))
    995 	{
    996 		c_squattbrushes++;
    997 		b->numsides = 0;
    998 		return;
    999 	} //end if
   1000 
   1001 	//if we're creating AAS
   1002 	if (create_aas)
   1003 	{
   1004 		//create the AAS brushes from this brush, don't add brush bevels
   1005 		AAS_CreateMapBrushes(b, mapent, false);
   1006 		return;
   1007 	} //end if
   1008 
   1009 	// allow detail brushes to be removed 
   1010 	if (nodetail && (b->contents & CONTENTS_DETAIL) )
   1011 	{
   1012 		b->numsides = 0;
   1013 		return;
   1014 	} //end if
   1015 
   1016 	// allow water brushes to be removed
   1017 	if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) )
   1018 	{
   1019 		b->numsides = 0;
   1020 		return;
   1021 	} //end if
   1022 
   1023 	// create windings for sides and bounds for brush
   1024 	MakeBrushWindings(b);
   1025 
   1026 	//mark brushes without winding or with a tiny window as bevels
   1027 	MarkBrushBevels(b);
   1028 
   1029 	// brushes that will not be visible at all will never be
   1030 	// used as bsp splitters
   1031 	if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
   1032 	{
   1033 			c_clipbrushes++;
   1034 		for (i = 0; i < b->numsides; i++)
   1035 			b->original_sides[i].texinfo = TEXINFO_NODE;
   1036 	} //end for
   1037 
   1038 	//
   1039 	// origin brushes are removed, but they set
   1040 	// the rotation origin for the rest of the brushes
   1041 	// in the entity.  After the entire entity is parsed,
   1042 	// the planenums and texinfos will be adjusted for
   1043 	// the origin brush
   1044 	//
   1045 	//ME: not needed because the entities in the BSP file already
   1046 	//    have an origin set
   1047 //	if (b->contents & CONTENTS_ORIGIN)
   1048 //	{
   1049 //		char	string[32];
   1050 //		vec3_t	origin;
   1051 //
   1052 //		if (num_entities == 1)
   1053 //		{
   1054 //			Error ("Entity %i, Brush %i: origin brushes not allowed in world"
   1055 //				, b->entitynum, b->brushnum);
   1056 //			return;
   1057 //		}
   1058 //
   1059 //		VectorAdd (b->mins, b->maxs, origin);
   1060 //		VectorScale (origin, 0.5, origin);
   1061 //
   1062 //		sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
   1063 //		SetKeyValue (&entities[b->entitynum], "origin", string);
   1064 //
   1065 //		VectorCopy (origin, entities[b->entitynum].origin);
   1066 //
   1067 //		// don't keep this brush
   1068 //		b->numsides = 0;
   1069 //
   1070 //		return;
   1071 //	}
   1072 
   1073 	//ME: the bsp brushes already have bevels, so we won't try to
   1074 	//    add them again (especially since Johny Boy's bevel adding might
   1075 	//    be crappy)
   1076 //	AddBrushBevels(b);
   1077 
   1078 	nummapbrushes++;
   1079 	mapent->numbrushes++;
   1080 } //end of the function Sin_BSPBrushToMapBrush
   1081 //===========================================================================
   1082 //===========================================================================
   1083 void Sin_ParseBSPBrushes(entity_t *mapent)
   1084 {
   1085 	int i, testnum = 0;
   1086 
   1087 	//give all the brushes that belong to this entity the number of the
   1088 	//BSP model used by this entity
   1089 	Sin_SetBrushModelNumbers(mapent);
   1090 	//now parse all the brushes with the correct mapent->modelnum
   1091 	for (i = 0; i < sin_numbrushes; i++)
   1092 	{
   1093 		if (brushmodelnumbers[i] == mapent->modelnum)
   1094 		{
   1095 			testnum++;
   1096 			Sin_BSPBrushToMapBrush(&sin_dbrushes[i], mapent);
   1097 		} //end if
   1098 	} //end for
   1099 } //end of the function Sin_ParseBSPBrushes
   1100 //===========================================================================
   1101 //===========================================================================
   1102 qboolean Sin_ParseBSPEntity(int entnum)
   1103 {
   1104 	entity_t	*mapent;
   1105 	char *model;
   1106 	int startbrush, startsides;
   1107 
   1108 	startbrush = nummapbrushes;
   1109 	startsides = nummapbrushsides;
   1110 
   1111 	mapent = &entities[entnum];//num_entities];
   1112 	mapent->firstbrush = nummapbrushes;
   1113 	mapent->numbrushes = 0;
   1114 	mapent->modelnum = -1;	//-1 = no model
   1115 
   1116 	model = ValueForKey(mapent, "model");
   1117 	if (model && *model == '*')
   1118 	{
   1119 		mapent->modelnum = atoi(&model[1]);
   1120 		//Log_Print("model = %s\n", model);
   1121 		//Log_Print("mapent->modelnum = %d\n", mapent->modelnum);
   1122 	} //end if
   1123 
   1124 	GetVectorForKey(mapent, "origin", mapent->origin);
   1125 
   1126 	//if this is the world entity it has model number zero
   1127 	//the world entity has no model key
   1128 	if (!strcmp("worldspawn", ValueForKey(mapent, "classname")))
   1129 	{
   1130 		mapent->modelnum = 0;
   1131 	} //end if
   1132 	//if the map entity has a BSP model (a modelnum of -1 is used for
   1133 	//entities that aren't using a BSP model)
   1134 	if (mapent->modelnum >= 0)
   1135 	{
   1136 		//parse the bsp brushes
   1137 		Sin_ParseBSPBrushes(mapent);
   1138 	} //end if
   1139 	//
   1140 	//the origin of the entity is already taken into account
   1141 	//
   1142 	//func_group entities can't be in the bsp file
   1143 	//
   1144 	//check out the func_areaportal entities
   1145 	if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname")))
   1146 	{
   1147 		c_areaportals++;
   1148 		mapent->areaportalnum = c_areaportals;
   1149 		return true;
   1150 	} //end if
   1151 	return true;
   1152 } //end of the function Sin_ParseBSPEntity
   1153 //===========================================================================
   1154 //
   1155 // Parameter:				-
   1156 // Returns:					-
   1157 // Changes Globals:		-
   1158 //===========================================================================
   1159 void Sin_LoadMapFromBSP(char *filename, int offset, int length)
   1160 {
   1161 	int i;
   1162 
   1163 	Log_Print("-- Sin_LoadMapFromBSP --\n");
   1164 	//loaded map type
   1165 	loadedmaptype = MAPTYPE_SIN;
   1166 
   1167 	Log_Print("Loading map from %s...\n", filename);
   1168 	//load the bsp file
   1169 	Sin_LoadBSPFile(filename, offset, length);
   1170 
   1171 	//create an index from bsp planes to map planes
   1172 	//DPlanes2MapPlanes();
   1173 	//clear brush model numbers
   1174 	for (i = 0; i < MAX_MAPFILE_BRUSHES; i++)
   1175 		brushmodelnumbers[i] = -1;
   1176 
   1177 	nummapbrushsides = 0;
   1178 	num_entities = 0;
   1179 
   1180 	Sin_ParseEntities();
   1181 	//
   1182 	for (i = 0; i < num_entities; i++)
   1183 	{
   1184 		Sin_ParseBSPEntity(i);
   1185 	} //end for
   1186 
   1187 	//get the map mins and maxs from the world model
   1188 	ClearBounds(map_mins, map_maxs);
   1189 	for (i = 0; i < entities[0].numbrushes; i++)
   1190 	{
   1191 		if (mapbrushes[i].mins[0] > 4096)
   1192 			continue;	//no valid points
   1193 		AddPointToBounds (mapbrushes[i].mins, map_mins, map_maxs);
   1194 		AddPointToBounds (mapbrushes[i].maxs, map_mins, map_maxs);
   1195 	} //end for
   1196 	//
   1197 	Sin_CreateMapTexinfo();
   1198 } //end of the function Sin_LoadMapFromBSP
   1199 
   1200 void Sin_ResetMapLoading(void)
   1201 {
   1202 	//reset for map loading from bsp
   1203 	memset(nodestack, 0, NODESTACKSIZE * sizeof(int));
   1204 	nodestackptr = NULL;
   1205 	nodestacksize = 0;
   1206 	memset(brushmodelnumbers, 0, MAX_MAPFILE_BRUSHES * sizeof(int));
   1207 } //end of the function Sin_ResetMapLoading
   1208 
   1209 //End MAP loading from BSP file
   1210 
   1211 #endif //ME