Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

brushbsp.c (46529B)


      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 #include "qbsp.h"
     24 #include "l_mem.h"
     25 #include "../botlib/aasfile.h"
     26 #include "aas_store.h"
     27 #include "aas_cfg.h"
     28 
     29 #include <assert.h>
     30 
     31 /*
     32 each side has a count of the other sides it splits
     33 
     34 the best split will be the one that minimizes the total split counts
     35 of all remaining sides
     36 
     37 precalc side on plane table
     38 
     39 evaluate split side
     40 {
     41 cost = 0
     42 for all sides
     43 	for all sides
     44 		get 
     45 		if side splits side and splitside is on same child
     46 			cost++;
     47 }
     48 */
     49 
     50 int c_nodes;
     51 int c_nonvis;
     52 int c_active_brushes;
     53 int c_solidleafnodes;
     54 int c_totalsides;
     55 int c_brushmemory;
     56 int c_peak_brushmemory;
     57 int c_nodememory;
     58 int c_peak_totalbspmemory;
     59 
     60 // if a brush just barely pokes onto the other side,
     61 // let it slide by without chopping
     62 #define	PLANESIDE_EPSILON	0.001
     63 //0.1
     64 
     65 //#ifdef DEBUG
     66 typedef struct cname_s
     67 {
     68 	int value;
     69 	char *name;
     70 } cname_t;
     71 
     72 cname_t contentnames[] =
     73 {
     74 	{CONTENTS_SOLID,"CONTENTS_SOLID"},
     75 	{CONTENTS_WINDOW,"CONTENTS_WINDOW"},
     76 	{CONTENTS_AUX,"CONTENTS_AUX"},
     77 	{CONTENTS_LAVA,"CONTENTS_LAVA"},
     78 	{CONTENTS_SLIME,"CONTENTS_SLIME"},
     79 	{CONTENTS_WATER,"CONTENTS_WATER"},
     80 	{CONTENTS_MIST,"CONTENTS_MIST"},
     81 	{LAST_VISIBLE_CONTENTS,"LAST_VISIBLE_CONTENTS"},
     82 
     83 	{CONTENTS_AREAPORTAL,"CONTENTS_AREAPORTAL"},
     84 	{CONTENTS_PLAYERCLIP,"CONTENTS_PLAYERCLIP"},
     85 	{CONTENTS_MONSTERCLIP,"CONTENTS_MONSTERCLIP"},
     86 	{CONTENTS_CURRENT_0,"CONTENTS_CURRENT_0"},
     87 	{CONTENTS_CURRENT_90,"CONTENTS_CURRENT_90"},
     88 	{CONTENTS_CURRENT_180,"CONTENTS_CURRENT_180"},
     89 	{CONTENTS_CURRENT_270,"CONTENTS_CURRENT_270"},
     90 	{CONTENTS_CURRENT_UP,"CONTENTS_CURRENT_UP"},
     91 	{CONTENTS_CURRENT_DOWN,"CONTENTS_CURRENT_DOWN"},
     92 	{CONTENTS_ORIGIN,"CONTENTS_ORIGIN"},
     93 	{CONTENTS_MONSTER,"CONTENTS_MONSTER"},
     94 	{CONTENTS_DEADMONSTER,"CONTENTS_DEADMONSTER"},
     95 	{CONTENTS_DETAIL,"CONTENTS_DETAIL"},
     96 	{CONTENTS_Q2TRANSLUCENT,"CONTENTS_TRANSLUCENT"},
     97 	{CONTENTS_LADDER,"CONTENTS_LADDER"},
     98 	{0, 0}
     99 };
    100 
    101 void PrintContents(int contents)
    102 {
    103 	int i;
    104 
    105 	for (i = 0; contentnames[i].value; i++)
    106 	{
    107 		if (contents & contentnames[i].value)
    108 		{
    109 			Log_Write("%s,", contentnames[i].name);
    110 		} //end if
    111 	} //end for
    112 } //end of the function PrintContents
    113 
    114 //#endif DEBUG
    115 
    116 //===========================================================================
    117 //
    118 // Parameter:			-
    119 // Returns:				-
    120 // Changes Globals:		-
    121 //===========================================================================
    122 void ResetBrushBSP(void)
    123 {
    124 	c_nodes = 0;
    125 	c_nonvis = 0;
    126 	c_active_brushes = 0;
    127 	c_solidleafnodes = 0;
    128 	c_totalsides = 0;
    129 	c_brushmemory = 0;
    130 	c_peak_brushmemory = 0;
    131 	c_nodememory = 0;
    132 	c_peak_totalbspmemory = 0;
    133 } //end of the function ResetBrushBSP
    134 //===========================================================================
    135 //
    136 // Parameter:			-
    137 // Returns:				-
    138 // Changes Globals:		-
    139 //===========================================================================
    140 void FindBrushInTree (node_t *node, int brushnum)
    141 {
    142 	bspbrush_t	*b;
    143 
    144 	if (node->planenum == PLANENUM_LEAF)
    145 	{
    146 		for (b=node->brushlist ; b ; b=b->next)
    147 			if (b->original->brushnum == brushnum)
    148 				Log_Print ("here\n");
    149 		return;
    150 	}
    151 	FindBrushInTree(node->children[0], brushnum);
    152 	FindBrushInTree(node->children[1], brushnum);
    153 } //end of the function FindBrushInTree
    154 //===========================================================================
    155 //
    156 // Parameter:			-
    157 // Returns:				-
    158 // Changes Globals:		-
    159 //===========================================================================
    160 void DrawBrushList (bspbrush_t *brush, node_t *node)
    161 {
    162 	int		i;
    163 	side_t	*s;
    164 
    165 	GLS_BeginScene ();
    166 	for ( ; brush ; brush=brush->next)
    167 	{
    168 		for (i=0 ; i<brush->numsides ; i++)
    169 		{
    170 			s = &brush->sides[i];
    171 			if (!s->winding)
    172 				continue;
    173 			if (s->texinfo == TEXINFO_NODE)
    174 				GLS_Winding (s->winding, 1);
    175 			else if (!(s->flags & SFL_VISIBLE))
    176 				GLS_Winding (s->winding, 2);
    177 			else
    178 				GLS_Winding (s->winding, 0);
    179 		}
    180 	}
    181 	GLS_EndScene ();
    182 } //end of the function DrawBrushList
    183 //===========================================================================
    184 //
    185 // Parameter:			-
    186 // Returns:				-
    187 // Changes Globals:		-
    188 //===========================================================================
    189 void WriteBrushList (char *name, bspbrush_t *brush, qboolean onlyvis)
    190 {
    191 	int		i;
    192 	side_t	*s;
    193 	FILE	*f;
    194 
    195 	qprintf ("writing %s\n", name);
    196 	f = SafeOpenWrite (name);
    197 
    198 	for ( ; brush ; brush=brush->next)
    199 	{
    200 		for (i=0 ; i<brush->numsides ; i++)
    201 		{
    202 			s = &brush->sides[i];
    203 			if (!s->winding)
    204 				continue;
    205 			if (onlyvis && !(s->flags & SFL_VISIBLE))
    206 				continue;
    207 			OutputWinding (brush->sides[i].winding, f);
    208 		}
    209 	}
    210 
    211 	fclose (f);
    212 } //end of the function WriteBrushList
    213 //===========================================================================
    214 //
    215 // Parameter:			-
    216 // Returns:				-
    217 // Changes Globals:		-
    218 //===========================================================================
    219 void PrintBrush (bspbrush_t *brush)
    220 {
    221 	int		i;
    222 
    223 	printf ("brush: %p\n", brush);
    224 	for (i=0;i<brush->numsides ; i++)
    225 	{
    226 		pw(brush->sides[i].winding);
    227 		printf ("\n");
    228 	} //end for
    229 } //end of the function PrintBrush
    230 //===========================================================================
    231 // Sets the mins/maxs based on the windings
    232 //
    233 // Parameter:			-
    234 // Returns:				-
    235 // Changes Globals:		-
    236 //===========================================================================
    237 void BoundBrush (bspbrush_t *brush)
    238 {
    239 	int			i, j;
    240 	winding_t	*w;
    241 
    242 	ClearBounds (brush->mins, brush->maxs);
    243 	for (i=0 ; i<brush->numsides ; i++)
    244 	{
    245 		w = brush->sides[i].winding;
    246 		if (!w)
    247 			continue;
    248 		for (j=0 ; j<w->numpoints ; j++)
    249 			AddPointToBounds (w->p[j], brush->mins, brush->maxs);
    250 	}
    251 } //end of the function BoundBrush
    252 //===========================================================================
    253 //
    254 // Parameter:			-
    255 // Returns:				-
    256 // Changes Globals:		-
    257 //===========================================================================
    258 void CreateBrushWindings (bspbrush_t *brush)
    259 {
    260 	int			i, j;
    261 	winding_t	*w;
    262 	side_t		*side;
    263 	plane_t		*plane;
    264 
    265 	for (i=0 ; i<brush->numsides ; i++)
    266 	{
    267 		side = &brush->sides[i];
    268 		plane = &mapplanes[side->planenum];
    269 		w = BaseWindingForPlane (plane->normal, plane->dist);
    270 		for (j=0 ; j<brush->numsides && w; j++)
    271 		{
    272 			if (i == j)
    273 				continue;
    274 			if (brush->sides[j].flags & SFL_BEVEL)
    275 				continue;
    276 			plane = &mapplanes[brush->sides[j].planenum^1];
    277 			ChopWindingInPlace (&w, plane->normal, plane->dist, 0); //CLIP_EPSILON);
    278 		}
    279 
    280 		side->winding = w;
    281 	}
    282 
    283 	BoundBrush (brush);
    284 } //end of the function CreateBrushWindings
    285 //===========================================================================
    286 // Creates a new axial brush
    287 //
    288 // Parameter:			-
    289 // Returns:				-
    290 // Changes Globals:		-
    291 //===========================================================================
    292 bspbrush_t	*BrushFromBounds (vec3_t mins, vec3_t maxs)
    293 {
    294 	bspbrush_t *b;
    295 	int i;
    296 	vec3_t normal;
    297 	vec_t dist;
    298 
    299 	b = AllocBrush (6);
    300 	b->numsides = 6;
    301 	for (i=0 ; i<3 ; i++)
    302 	{
    303 		VectorClear (normal);
    304 		normal[i] = 1;
    305 		dist = maxs[i];
    306 		b->sides[i].planenum = FindFloatPlane (normal, dist);
    307 
    308 		normal[i] = -1;
    309 		dist = -mins[i];
    310 		b->sides[3+i].planenum = FindFloatPlane (normal, dist);
    311 	}
    312 
    313 	CreateBrushWindings (b);
    314 
    315 	return b;
    316 } //end of the function BrushFromBounds
    317 //===========================================================================
    318 //
    319 // Parameter:			-
    320 // Returns:				-
    321 // Changes Globals:		-
    322 //===========================================================================
    323 int BrushOutOfBounds(bspbrush_t *brush, vec3_t mins, vec3_t maxs, float epsilon)
    324 {
    325 	int i, j, n;
    326 	winding_t *w;
    327 	side_t *side;
    328 
    329 	for (i = 0; i < brush->numsides; i++)
    330 	{
    331 		side = &brush->sides[i];
    332 		w = side->winding;
    333 		for (j = 0; j < w->numpoints; j++)
    334 		{
    335 			for (n = 0; n < 3; n++)
    336 			{
    337 				if (w->p[j][n] < (mins[n] + epsilon) || w->p[j][n] > (maxs[n] - epsilon)) return true;
    338 			} //end for
    339 		} //end for
    340 	} //end for
    341 	return false;
    342 } //end of the function BrushOutOfBounds
    343 //===========================================================================
    344 //
    345 // Parameter:			-
    346 // Returns:				-
    347 // Changes Globals:		-
    348 //===========================================================================
    349 vec_t BrushVolume (bspbrush_t *brush)
    350 {
    351 	int i;
    352 	winding_t *w;
    353 	vec3_t corner;
    354 	vec_t d, area, volume;
    355 	plane_t *plane;
    356 
    357 	if (!brush) return 0;
    358 
    359 	// grab the first valid point as the corner
    360 	w = NULL;
    361 	for (i = 0; i < brush->numsides; i++)
    362 	{
    363 		w = brush->sides[i].winding;
    364 		if (w) break;
    365 	} //end for
    366 	if (!w) return 0;
    367 	VectorCopy (w->p[0], corner);
    368 
    369 	// make tetrahedrons to all other faces
    370 	volume = 0;
    371 	for ( ; i < brush->numsides; i++)
    372 	{
    373 		w = brush->sides[i].winding;
    374 		if (!w) continue;
    375 		plane = &mapplanes[brush->sides[i].planenum];
    376 		d = -(DotProduct (corner, plane->normal) - plane->dist);
    377 		area = WindingArea(w);
    378 		volume += d * area;
    379 	} //end for
    380 
    381 	volume /= 3;
    382 	return volume;
    383 } //end of the function BrushVolume
    384 //===========================================================================
    385 //
    386 // Parameter:			-
    387 // Returns:				-
    388 // Changes Globals:		-
    389 //===========================================================================
    390 int CountBrushList (bspbrush_t *brushes)
    391 {
    392 	int c;
    393 
    394 	c = 0;
    395 	for ( ; brushes; brushes = brushes->next) c++;
    396 	return c;
    397 } //end of the function CountBrushList
    398 //===========================================================================
    399 //
    400 // Parameter:			-
    401 // Returns:				-
    402 // Changes Globals:		-
    403 //===========================================================================
    404 node_t *AllocNode (void)
    405 {
    406 	node_t	*node;
    407 
    408 	node = GetMemory(sizeof(*node));
    409 	memset (node, 0, sizeof(*node));
    410 	if (numthreads == 1)
    411 	{
    412 		c_nodememory += MemorySize(node);
    413 	} //end if
    414 	return node;
    415 } //end of the function AllocNode
    416 //===========================================================================
    417 //
    418 // Parameter:			-
    419 // Returns:				-
    420 // Changes Globals:		-
    421 //===========================================================================
    422 bspbrush_t *AllocBrush (int numsides)
    423 {
    424 	bspbrush_t	*bb;
    425 	int			c;
    426 
    427 	c = (int)&(((bspbrush_t *)0)->sides[numsides]);
    428 	bb = GetMemory(c);
    429 	memset (bb, 0, c);
    430 	if (numthreads == 1)
    431 	{
    432 		c_active_brushes++;
    433 		c_brushmemory += MemorySize(bb);
    434 		if (c_brushmemory > c_peak_brushmemory)
    435 				c_peak_brushmemory = c_brushmemory;
    436 	} //end if
    437 	return bb;
    438 } //end of the function AllocBrush
    439 //===========================================================================
    440 //
    441 // Parameter:			-
    442 // Returns:				-
    443 // Changes Globals:		-
    444 //===========================================================================
    445 void FreeBrush (bspbrush_t *brushes)
    446 {
    447 	int			i;
    448 
    449 	for (i=0 ; i<brushes->numsides ; i++)
    450 		if (brushes->sides[i].winding)
    451 			FreeWinding(brushes->sides[i].winding);
    452 	if (numthreads == 1)
    453 	{
    454 		c_active_brushes--;
    455 		c_brushmemory -= MemorySize(brushes);
    456 		if (c_brushmemory < 0) c_brushmemory = 0;
    457 	} //end if
    458 	FreeMemory(brushes);
    459 } //end of the function FreeBrush
    460 //===========================================================================
    461 //
    462 // Parameter:			-
    463 // Returns:				-
    464 // Changes Globals:		-
    465 //===========================================================================
    466 void FreeBrushList (bspbrush_t *brushes)
    467 {
    468 	bspbrush_t	*next;
    469 
    470 	for ( ; brushes; brushes = next)
    471 	{
    472 		next = brushes->next;
    473 
    474 		FreeBrush(brushes);
    475 	} //end for
    476 } //end of the function FreeBrushList
    477 //===========================================================================
    478 // Duplicates the brush, the sides, and the windings
    479 //
    480 // Parameter:			-
    481 // Returns:				-
    482 // Changes Globals:		-
    483 //===========================================================================
    484 bspbrush_t *CopyBrush (bspbrush_t *brush)
    485 {
    486 	bspbrush_t *newbrush;
    487 	int			size;
    488 	int			i;
    489 	
    490 	size = (int)&(((bspbrush_t *)0)->sides[brush->numsides]);
    491 
    492 	newbrush = AllocBrush (brush->numsides);
    493 	memcpy (newbrush, brush, size);
    494 
    495 	for (i=0 ; i<brush->numsides ; i++)
    496 	{
    497 		if (brush->sides[i].winding)
    498 			newbrush->sides[i].winding = CopyWinding (brush->sides[i].winding);
    499 	}
    500 
    501 	return newbrush;
    502 } //end of the function CopyBrush
    503 //===========================================================================
    504 //
    505 // Parameter:			-
    506 // Returns:				-
    507 // Changes Globals:		-
    508 //===========================================================================
    509 node_t *PointInLeaf (node_t *node, vec3_t point)
    510 {
    511 	vec_t		d;
    512 	plane_t		*plane;
    513 
    514 	while (node->planenum != PLANENUM_LEAF)
    515 	{
    516 		plane = &mapplanes[node->planenum];
    517 		d = DotProduct (point, plane->normal) - plane->dist;
    518 		if (d > 0)
    519 			node = node->children[0];
    520 		else
    521 			node = node->children[1];
    522 	}
    523 
    524 	return node;
    525 } //end of the function PointInLeaf
    526 //===========================================================================
    527 // Returns PSIDE_FRONT, PSIDE_BACK, or PSIDE_BOTH
    528 //
    529 // Parameter:			-
    530 // Returns:				-
    531 // Changes Globals:		-
    532 //===========================================================================
    533 #if 0
    534 int BoxOnPlaneSide (vec3_t mins, vec3_t maxs, plane_t *plane)
    535 {
    536 	int		side;
    537 	int		i;
    538 	vec3_t	corners[2];
    539 	vec_t	dist1, dist2;
    540 
    541 	// axial planes are easy
    542 	if (plane->type < 3)
    543 	{
    544 		side = 0;
    545 		if (maxs[plane->type] > plane->dist+PLANESIDE_EPSILON)
    546 			side |= PSIDE_FRONT;
    547 		if (mins[plane->type] < plane->dist-PLANESIDE_EPSILON)
    548 			side |= PSIDE_BACK;
    549 		return side;
    550 	}
    551 
    552 	// create the proper leading and trailing verts for the box
    553 
    554 	for (i=0 ; i<3 ; i++)
    555 	{
    556 		if (plane->normal[i] < 0)
    557 		{
    558 			corners[0][i] = mins[i];
    559 			corners[1][i] = maxs[i];
    560 		}
    561 		else
    562 		{
    563 			corners[1][i] = mins[i];
    564 			corners[0][i] = maxs[i];
    565 		}
    566 	}
    567 
    568 	dist1 = DotProduct (plane->normal, corners[0]) - plane->dist;
    569 	dist2 = DotProduct (plane->normal, corners[1]) - plane->dist;
    570 	side = 0;
    571 	if (dist1 >= PLANESIDE_EPSILON)
    572 		side = PSIDE_FRONT;
    573 	if (dist2 < PLANESIDE_EPSILON)
    574 		side |= PSIDE_BACK;
    575 
    576 	return side;
    577 }
    578 #else
    579 int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, plane_t *p)
    580 {
    581 	float	dist1, dist2;
    582 	int sides;
    583 
    584 	// axial planes are easy
    585 	if (p->type < 3)
    586 	{
    587 		sides = 0;
    588 		if (emaxs[p->type] > p->dist+PLANESIDE_EPSILON) sides |= PSIDE_FRONT;
    589 		if (emins[p->type] < p->dist-PLANESIDE_EPSILON) sides |= PSIDE_BACK;
    590 		return sides;
    591 	} //end if
    592 	
    593 // general case
    594 	switch (p->signbits)
    595 	{
    596 	case 0:
    597 		dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
    598 		dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
    599 		break;
    600 	case 1:
    601 		dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
    602 		dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
    603 		break;
    604 	case 2:
    605 		dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
    606 		dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
    607 		break;
    608 	case 3:
    609 		dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
    610 		dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
    611 		break;
    612 	case 4:
    613 		dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
    614 		dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
    615 		break;
    616 	case 5:
    617 		dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
    618 		dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
    619 		break;
    620 	case 6:
    621 		dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
    622 		dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
    623 		break;
    624 	case 7:
    625 		dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
    626 		dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
    627 		break;
    628 	default:
    629 		dist1 = dist2 = 0;		// shut up compiler
    630 //		assert( 0 );
    631 		break;
    632 	}
    633 
    634 	sides = 0;
    635 	if (dist1 - p->dist >= PLANESIDE_EPSILON) sides = PSIDE_FRONT;
    636 	if (dist2 - p->dist < PLANESIDE_EPSILON) sides |= PSIDE_BACK;
    637 
    638 //	assert(sides != 0);
    639 
    640 	return sides;
    641 }
    642 #endif
    643 //===========================================================================
    644 //
    645 // Parameter:			-
    646 // Returns:				-
    647 // Changes Globals:		-
    648 //===========================================================================
    649 int QuickTestBrushToPlanenum (bspbrush_t *brush, int planenum, int *numsplits)
    650 {
    651 	int i, num;
    652 	plane_t *plane;
    653 	int s;
    654 
    655 	*numsplits = 0;
    656 
    657 	plane = &mapplanes[planenum];
    658 
    659 #ifdef ME
    660 	//fast axial cases
    661 	if (plane->type < 3)
    662 	{
    663 		if (plane->dist + PLANESIDE_EPSILON < brush->mins[plane->type])
    664 			return PSIDE_FRONT;
    665 		if (plane->dist - PLANESIDE_EPSILON > brush->maxs[plane->type])
    666 			return PSIDE_BACK;
    667 	} //end if
    668 #endif //ME*/
    669 
    670 	// if the brush actually uses the planenum,
    671 	// we can tell the side for sure
    672 	for (i = 0; i < brush->numsides; i++)
    673 	{
    674 		num = brush->sides[i].planenum;
    675 		if (num >= MAX_MAPFILE_PLANES)
    676 			Error ("bad planenum");
    677 		if (num == planenum)
    678 			return PSIDE_BACK|PSIDE_FACING;
    679 		if (num == (planenum ^ 1) )
    680 			return PSIDE_FRONT|PSIDE_FACING;
    681 
    682 	}
    683 
    684 	// box on plane side
    685 	s = BoxOnPlaneSide (brush->mins, brush->maxs, plane);
    686 
    687 	// if both sides, count the visible faces split
    688 	if (s == PSIDE_BOTH)
    689 	{
    690 		*numsplits += 3;
    691 	}
    692 
    693 	return s;
    694 } //end of the function QuickTestBrushToPlanenum
    695 //===========================================================================
    696 //
    697 // Parameter:			-
    698 // Returns:				-
    699 // Changes Globals:		-
    700 //===========================================================================
    701 int TestBrushToPlanenum (bspbrush_t *brush, int planenum,
    702 						 int *numsplits, qboolean *hintsplit, int *epsilonbrush)
    703 {
    704 	int i, j, num;
    705 	plane_t *plane;
    706 	int s = 0;
    707 	winding_t *w;
    708 	vec_t d, d_front, d_back;
    709 	int front, back;
    710 	int type;
    711 	float dist;
    712 
    713 	*numsplits = 0;
    714 	*hintsplit = false;
    715 
    716 	plane = &mapplanes[planenum];
    717 
    718 #ifdef ME
    719 	//fast axial cases
    720 	type = plane->type;
    721 	if (type < 3)
    722 	{
    723 		dist = plane->dist;
    724 		if (dist + PLANESIDE_EPSILON < brush->mins[type]) return PSIDE_FRONT;
    725 		if (dist - PLANESIDE_EPSILON > brush->maxs[type]) return PSIDE_BACK;
    726 		if (brush->mins[type] < dist - PLANESIDE_EPSILON &&
    727 					brush->maxs[type] > dist + PLANESIDE_EPSILON) s = PSIDE_BOTH;
    728 	} //end if
    729 
    730 	if (s != PSIDE_BOTH)
    731 #endif //ME
    732 	{
    733 		// if the brush actually uses the planenum,
    734 		// we can tell the side for sure
    735 		for (i = 0; i < brush->numsides; i++)
    736 		{
    737 			num = brush->sides[i].planenum;
    738 			if (num >= MAX_MAPFILE_PLANES) Error ("bad planenum");
    739 			if (num == planenum)
    740 			{
    741 				//we don't need to test this side plane again
    742 				brush->sides[i].flags |= SFL_TESTED;
    743 				return PSIDE_BACK|PSIDE_FACING;
    744 			} //end if
    745 			if (num == (planenum ^ 1) )
    746 			{
    747 				//we don't need to test this side plane again
    748 				brush->sides[i].flags |= SFL_TESTED;
    749 				return PSIDE_FRONT|PSIDE_FACING;
    750 			} //end if
    751 		} //end for
    752 
    753 		// box on plane side
    754 		s = BoxOnPlaneSide (brush->mins, brush->maxs, plane);
    755 
    756 		if (s != PSIDE_BOTH) return s;
    757 	} //end if
    758 
    759 	// if both sides, count the visible faces split
    760 	d_front = d_back = 0;
    761 
    762 	for (i = 0; i < brush->numsides; i++)
    763 	{
    764 		if (brush->sides[i].texinfo == TEXINFO_NODE)
    765 			continue;		// on node, don't worry about splits
    766 		if (!(brush->sides[i].flags & SFL_VISIBLE))
    767 			continue;		// we don't care about non-visible
    768 		w = brush->sides[i].winding;
    769 		if (!w) continue;
    770 		front = back = 0;
    771 		for (j = 0; j < w->numpoints; j++)
    772 		{
    773 			d = DotProduct(w->p[j], plane->normal) - plane->dist;
    774 			if (d > d_front) d_front = d;
    775 			if (d < d_back) d_back = d;
    776 			if (d > 0.1) // PLANESIDE_EPSILON)
    777 				front = 1;
    778 			if (d < -0.1) // PLANESIDE_EPSILON)
    779 				back = 1;
    780 		} //end for
    781 		if (front && back)
    782 		{
    783 			if ( !(brush->sides[i].surf & SURF_SKIP) )
    784 			{
    785 				(*numsplits)++;
    786 				if (brush->sides[i].surf & SURF_HINT)
    787 				{
    788 					*hintsplit = true;
    789 				} //end if
    790 			} //end if
    791 		} //end if
    792 	} //end for
    793 
    794 	if ( (d_front > 0.0 && d_front < 1.0)
    795 		|| (d_back < 0.0 && d_back > -1.0) )
    796 		(*epsilonbrush)++;
    797 
    798 #if 0
    799 	if (*numsplits == 0)
    800 	{	//	didn't really need to be split
    801 		if (front) s = PSIDE_FRONT;
    802 		else if (back) s = PSIDE_BACK;
    803 		else s = 0;
    804 	}
    805 #endif
    806 
    807 	return s;
    808 } //end of the function TestBrushToPlanenum
    809 //===========================================================================
    810 // Returns true if the winding would be crunched out of
    811 // existance by the vertex snapping.
    812 //
    813 // Parameter:			-
    814 // Returns:				-
    815 // Changes Globals:		-
    816 //===========================================================================
    817 #define	EDGE_LENGTH	0.2
    818 qboolean WindingIsTiny (winding_t *w)
    819 {
    820 #if 0
    821 	if (WindingArea (w) < 1)
    822 		return true;
    823 	return false;
    824 #else
    825 	int		i, j;
    826 	vec_t	len;
    827 	vec3_t	delta;
    828 	int		edges;
    829 
    830 	edges = 0;
    831 	for (i=0 ; i<w->numpoints ; i++)
    832 	{
    833 		j = i == w->numpoints - 1 ? 0 : i+1;
    834 		VectorSubtract (w->p[j], w->p[i], delta);
    835 		len = VectorLength (delta);
    836 		if (len > EDGE_LENGTH)
    837 		{
    838 			if (++edges == 3)
    839 				return false;
    840 		}
    841 	}
    842 	return true;
    843 #endif
    844 } //end of the function WindingIsTiny
    845 //===========================================================================
    846 // Returns true if the winding still has one of the points
    847 // from basewinding for plane
    848 //
    849 // Parameter:			-
    850 // Returns:				-
    851 // Changes Globals:		-
    852 //===========================================================================
    853 qboolean WindingIsHuge (winding_t *w)
    854 {
    855 	int		i, j;
    856 
    857 	for (i=0 ; i<w->numpoints ; i++)
    858 	{
    859 		for (j=0 ; j<3 ; j++)
    860 			if (w->p[i][j] < -BOGUS_RANGE+1 || w->p[i][j] > BOGUS_RANGE-1)
    861 				return true;
    862 	}
    863 	return false;
    864 } //end of the function WindingIsHuge
    865 //===========================================================================
    866 // creates a leaf out of the given nodes with the given brushes
    867 //
    868 // Parameter:			-
    869 // Returns:				-
    870 // Changes Globals:		-
    871 //===========================================================================
    872 void LeafNode(node_t *node, bspbrush_t *brushes)
    873 {
    874 	bspbrush_t *b;
    875 	int i;
    876 
    877 	node->side = NULL;
    878 	node->planenum = PLANENUM_LEAF;
    879 	node->contents = 0;
    880 
    881 	for (b = brushes; b; b = b->next)
    882 	{
    883 		// if the brush is solid and all of its sides are on nodes,
    884 		// it eats everything
    885 		if (b->original->contents & CONTENTS_SOLID)
    886 		{
    887 			for (i=0 ; i<b->numsides ; i++)
    888 				if (b->sides[i].texinfo != TEXINFO_NODE)
    889 					break;
    890 			if (i == b->numsides)
    891 			{
    892 				node->contents = CONTENTS_SOLID;
    893 				break;
    894 			} //end if
    895 		} //end if
    896 		node->contents |= b->original->contents;
    897 	} //end for
    898 
    899 	if (create_aas)
    900 	{
    901 		node->expansionbboxes = 0;
    902 		node->contents = 0;
    903 		for (b = brushes; b; b = b->next)
    904 		{
    905 			node->expansionbboxes |= b->original->expansionbbox;
    906 			node->contents |= b->original->contents;
    907 			if (b->original->modelnum)
    908 				node->modelnum = b->original->modelnum;
    909 		} //end for
    910 		if (node->contents & CONTENTS_SOLID)
    911 		{
    912 			if (node->expansionbboxes != cfg.allpresencetypes)
    913 			{
    914 				node->contents &= ~CONTENTS_SOLID;
    915 			} //end if
    916 		} //end if
    917 	} //end if
    918 
    919 	node->brushlist = brushes;
    920 } //end of the function LeafNode
    921 //===========================================================================
    922 //
    923 // Parameter:			-
    924 // Returns:				-
    925 // Changes Globals:		-
    926 //===========================================================================
    927 void CheckPlaneAgainstParents (int pnum, node_t *node)
    928 {
    929 	node_t	*p;
    930 
    931 	for (p = node->parent; p; p = p->parent)
    932 	{
    933 		if (p->planenum == pnum) Error("Tried parent");
    934 	} //end for
    935 } //end of the function CheckPlaneAgainstParants
    936 //===========================================================================
    937 //
    938 // Parameter:			-
    939 // Returns:				-
    940 // Changes Globals:		-
    941 //===========================================================================
    942 qboolean CheckPlaneAgainstVolume (int pnum, node_t *node)
    943 {
    944 	bspbrush_t	*front, *back;
    945 	qboolean	good;
    946 
    947 	SplitBrush (node->volume, pnum, &front, &back);
    948 
    949 	good = (front && back);
    950 
    951 	if (front) FreeBrush (front);
    952 	if (back) FreeBrush (back);
    953 
    954 	return good;
    955 } //end of the function CheckPlaneAgaintsVolume
    956 //===========================================================================
    957 // Using a hueristic, choses one of the sides out of the brushlist
    958 // to partition the brushes with.
    959 // Returns NULL if there are no valid planes to split with..
    960 //
    961 // Parameter:			-
    962 // Returns:				-
    963 // Changes Globals:		-
    964 //===========================================================================
    965 side_t *SelectSplitSide (bspbrush_t *brushes, node_t *node)
    966 {
    967 	int			value, bestvalue;
    968 	bspbrush_t	*brush, *test;
    969 	side_t		*side, *bestside;
    970 	int			i, pass, numpasses;
    971 	int			pnum;
    972 	int			s;
    973 	int			front, back, both, facing, splits;
    974 	int			bsplits;
    975 	int			bestsplits;
    976 	int			epsilonbrush;
    977 	qboolean	hintsplit = false;
    978 
    979 	bestside = NULL;
    980 	bestvalue = -99999;
    981 	bestsplits = 0;
    982 
    983 	// the search order goes: visible-structural, visible-detail,
    984 	// nonvisible-structural, nonvisible-detail.
    985 	// If any valid plane is available in a pass, no further
    986 	// passes will be tried.
    987 	numpasses = 2;
    988 	for (pass = 0; pass < numpasses; pass++)
    989 	{
    990 		for (brush = brushes; brush; brush = brush->next)
    991 		{
    992 			// only check detail the second pass
    993 //			if ( (pass & 1) && !(brush->original->contents & CONTENTS_DETAIL) )
    994 //				continue;
    995 //			if ( !(pass & 1) && (brush->original->contents & CONTENTS_DETAIL) )
    996 //				continue;
    997 			for (i = 0; i < brush->numsides; i++)
    998 			{
    999 				side = brush->sides + i;
   1000 //				if (side->flags & SFL_BEVEL)
   1001 //					continue;	// never use a bevel as a spliter
   1002 				if (!side->winding)
   1003 					continue;	// nothing visible, so it can't split
   1004 				if (side->texinfo == TEXINFO_NODE)
   1005 					continue;	// allready a node splitter
   1006 				if (side->flags & SFL_TESTED)
   1007 					continue;	// we allready have metrics for this plane
   1008 //				if (side->surf & SURF_SKIP)
   1009 //					continue;	// skip surfaces are never chosen
   1010 
   1011 //				if (!(side->flags & SFL_VISIBLE) && (pass < 2))
   1012 //					continue;	// only check visible faces on first pass
   1013 
   1014 				if ((side->flags & SFL_CURVE) && (pass < 1))
   1015 					continue;	// only check curves the second pass
   1016 
   1017 				pnum = side->planenum;
   1018 				pnum &= ~1;	// allways use positive facing plane
   1019 
   1020 				CheckPlaneAgainstParents (pnum, node);
   1021 
   1022 				if (!CheckPlaneAgainstVolume (pnum, node))
   1023 					continue;	// would produce a tiny volume
   1024 
   1025 				front = 0;
   1026 				back = 0;
   1027 				both = 0;
   1028 				facing = 0;
   1029 				splits = 0;
   1030 				epsilonbrush = 0;
   1031 
   1032 				 //inner loop: optimize
   1033 				for (test = brushes; test; test = test->next)
   1034 				{
   1035 					s = TestBrushToPlanenum (test, pnum, &bsplits, &hintsplit, &epsilonbrush);
   1036 
   1037 					splits += bsplits;
   1038 //					if (bsplits && (s&PSIDE_FACING) )
   1039 //						Error ("PSIDE_FACING with splits");
   1040 
   1041 					test->testside = s;
   1042 					//
   1043 					if (s & PSIDE_FACING) facing++;
   1044 					if (s & PSIDE_FRONT) front++;
   1045 					if (s & PSIDE_BACK) back++;
   1046 					if (s == PSIDE_BOTH) both++;
   1047 				} //end for
   1048 
   1049 				// give a value estimate for using this plane
   1050 				value =  5*facing - 5*splits - abs(front-back);
   1051 //					value =  -5*splits;
   1052 //					value =  5*facing - 5*splits;
   1053 				if (mapplanes[pnum].type < 3)
   1054 					value+=5;		// axial is better
   1055 
   1056 				value -= epsilonbrush * 1000;	// avoid!
   1057 
   1058 				// never split a hint side except with another hint
   1059 				if (hintsplit && !(side->surf & SURF_HINT) )
   1060 					value = -9999999;
   1061 
   1062 				// save off the side test so we don't need
   1063 				// to recalculate it when we actually seperate
   1064 				// the brushes
   1065 				if (value > bestvalue)
   1066 				{
   1067 					bestvalue = value;
   1068 					bestside = side;
   1069 					bestsplits = splits;
   1070 					for (test = brushes; test ; test = test->next)
   1071 						test->side = test->testside;
   1072 				} //end if
   1073 			} //end for
   1074 		} //end for (brush = brushes;
   1075 
   1076 		// if we found a good plane, don't bother trying any
   1077 		// other passes
   1078 		if (bestside)
   1079 		{
   1080 			if (pass > 1)
   1081 			{
   1082 				if (numthreads == 1) c_nonvis++;
   1083 			}
   1084 			if (pass > 0) node->detail_seperator = true;	// not needed for vis
   1085 			break;
   1086 		} //end if
   1087 	} //end for (pass = 0;
   1088 
   1089 	//
   1090 	// clear all the tested flags we set
   1091 	//
   1092 	for (brush = brushes ; brush ; brush=brush->next)
   1093 	{
   1094 		for (i = 0; i < brush->numsides; i++)
   1095 		{
   1096 			brush->sides[i].flags &= ~SFL_TESTED;
   1097 		} //end for
   1098 	} //end for
   1099 
   1100 	return bestside;
   1101 } //end of the function SelectSplitSide
   1102 //===========================================================================
   1103 //
   1104 // Parameter:			-
   1105 // Returns:				-
   1106 // Changes Globals:		-
   1107 //===========================================================================
   1108 int BrushMostlyOnSide (bspbrush_t *brush, plane_t *plane)
   1109 {
   1110 	int			i, j;
   1111 	winding_t	*w;
   1112 	vec_t		d, max;
   1113 	int			side;
   1114 
   1115 	max = 0;
   1116 	side = PSIDE_FRONT;
   1117 	for (i=0 ; i<brush->numsides ; i++)
   1118 	{
   1119 		w = brush->sides[i].winding;
   1120 		if (!w)
   1121 			continue;
   1122 		for (j=0 ; j<w->numpoints ; j++)
   1123 		{
   1124 			d = DotProduct (w->p[j], plane->normal) - plane->dist;
   1125 			if (d > max)
   1126 			{
   1127 				max = d;
   1128 				side = PSIDE_FRONT;
   1129 			}
   1130 			if (-d > max)
   1131 			{
   1132 				max = -d;
   1133 				side = PSIDE_BACK;
   1134 			}
   1135 		}
   1136 	}
   1137 	return side;
   1138 } //end of the function BrushMostlyOnSide
   1139 //===========================================================================
   1140 // Generates two new brushes, leaving the original
   1141 // unchanged
   1142 //
   1143 // Parameter:			-
   1144 // Returns:				-
   1145 // Changes Globals:		-
   1146 //===========================================================================
   1147 void SplitBrush (bspbrush_t *brush, int planenum,
   1148 	bspbrush_t **front, bspbrush_t **back)
   1149 {
   1150 	bspbrush_t	*b[2];
   1151 	int			i, j;
   1152 	winding_t	*w, *cw[2], *midwinding;
   1153 	plane_t		*plane, *plane2;
   1154 	side_t		*s, *cs;
   1155 	float d, d_front, d_back;
   1156 
   1157 	*front = *back = NULL;
   1158 	plane = &mapplanes[planenum];
   1159 
   1160 	// check all points
   1161 	d_front = d_back = 0;
   1162 	for (i=0 ; i<brush->numsides ; i++)
   1163 	{
   1164 		w = brush->sides[i].winding;
   1165 		if (!w)
   1166 			continue;
   1167 		for (j=0 ; j<w->numpoints ; j++)
   1168 		{
   1169 			d = DotProduct (w->p[j], plane->normal) - plane->dist;
   1170 			if (d > 0 && d > d_front)
   1171 				d_front = d;
   1172 			if (d < 0 && d < d_back)
   1173 				d_back = d;
   1174 		}
   1175 	}
   1176 
   1177 	if (d_front < 0.2) // PLANESIDE_EPSILON)
   1178 	{	// only on back
   1179 		*back = CopyBrush (brush);
   1180 		return;
   1181 	}
   1182 	if (d_back > -0.2) // PLANESIDE_EPSILON)
   1183 	{	// only on front
   1184 		*front = CopyBrush (brush);
   1185 		return;
   1186 	}
   1187 
   1188 	// create a new winding from the split plane
   1189 
   1190 	w = BaseWindingForPlane (plane->normal, plane->dist);
   1191 	for (i=0 ; i<brush->numsides && w ; i++)
   1192 	{
   1193 		plane2 = &mapplanes[brush->sides[i].planenum ^ 1];
   1194 		ChopWindingInPlace (&w, plane2->normal, plane2->dist, 0); // PLANESIDE_EPSILON);
   1195 	}
   1196 
   1197 	if (!w || WindingIsTiny(w))
   1198 	{	// the brush isn't really split
   1199 		int		side;
   1200 
   1201 		side = BrushMostlyOnSide (brush, plane);
   1202 		if (side == PSIDE_FRONT)
   1203 			*front = CopyBrush (brush);
   1204 		if (side == PSIDE_BACK)
   1205 			*back = CopyBrush (brush);
   1206 		//free a possible winding
   1207 		if (w) FreeWinding(w);
   1208 		return;
   1209 	}
   1210 
   1211 	if (WindingIsHuge (w))
   1212 	{
   1213 		Log_Write("WARNING: huge winding\n");
   1214 	}
   1215 
   1216 	midwinding = w;
   1217 
   1218 	// split it for real
   1219 
   1220 	for (i=0 ; i<2 ; i++)
   1221 	{
   1222 		b[i] = AllocBrush (brush->numsides+1);
   1223 		b[i]->original = brush->original;
   1224 	}
   1225 
   1226 	// split all the current windings
   1227 
   1228 	for (i=0 ; i<brush->numsides ; i++)
   1229 	{
   1230 		s = &brush->sides[i];
   1231 		w = s->winding;
   1232 		if (!w)
   1233 			continue;
   1234 		ClipWindingEpsilon (w, plane->normal, plane->dist,
   1235 			0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]);
   1236 		for (j=0 ; j<2 ; j++)
   1237 		{
   1238 			if (!cw[j])
   1239 				continue;
   1240 #if 0
   1241 			if (WindingIsTiny (cw[j]))
   1242 			{
   1243 				FreeWinding (cw[j]);
   1244 				continue;
   1245 			}
   1246 #endif
   1247 			cs = &b[j]->sides[b[j]->numsides];
   1248 			b[j]->numsides++;
   1249 			*cs = *s;
   1250 //			cs->planenum = s->planenum;
   1251 //			cs->texinfo = s->texinfo;
   1252 //			cs->original = s->original;
   1253 			cs->winding = cw[j];
   1254 			cs->flags &= ~SFL_TESTED;
   1255 		}
   1256 	}
   1257 
   1258 
   1259 	// see if we have valid polygons on both sides
   1260 
   1261 	for (i=0 ; i<2 ; i++)
   1262 	{
   1263 		BoundBrush (b[i]);
   1264 		for (j=0 ; j<3 ; j++)
   1265 		{
   1266 			if (b[i]->mins[j] < -MAX_MAP_BOUNDS || b[i]->maxs[j] > MAX_MAP_BOUNDS)
   1267 			{
   1268 				Log_Write("bogus brush after clip");
   1269 				break;
   1270 			}
   1271 		}
   1272 
   1273 		if (b[i]->numsides < 3 || j < 3)
   1274 		{
   1275 			FreeBrush (b[i]);
   1276 			b[i] = NULL;
   1277 		}
   1278 	}
   1279 
   1280 	if ( !(b[0] && b[1]) )
   1281 	{
   1282 		if (!b[0] && !b[1])
   1283 			Log_Write("split removed brush\r\n");
   1284 		else
   1285 			Log_Write("split not on both sides\r\n");
   1286 		if (b[0])
   1287 		{
   1288 			FreeBrush (b[0]);
   1289 			*front = CopyBrush (brush);
   1290 		}
   1291 		if (b[1])
   1292 		{
   1293 			FreeBrush (b[1]);
   1294 			*back = CopyBrush (brush);
   1295 		}
   1296 		return;
   1297 	}
   1298 
   1299 	// add the midwinding to both sides
   1300 	for (i=0 ; i<2 ; i++)
   1301 	{
   1302 		cs = &b[i]->sides[b[i]->numsides];
   1303 		b[i]->numsides++;
   1304 
   1305 		cs->planenum = planenum^i^1;
   1306 		cs->texinfo = TEXINFO_NODE; //never use these sides as splitters
   1307 		cs->flags &= ~SFL_VISIBLE;
   1308 		cs->flags &= ~SFL_TESTED;
   1309 		if (i==0)
   1310 			cs->winding = CopyWinding (midwinding);
   1311 		else
   1312 			cs->winding = midwinding;
   1313 	}
   1314 
   1315 {
   1316 	vec_t	v1;
   1317 	int i;
   1318 
   1319 	for (i = 0; i < 2; i++)
   1320 	{
   1321 		v1 = BrushVolume (b[i]);
   1322 		if (v1 < 1.0)
   1323 		{
   1324 			FreeBrush(b[i]);
   1325 			b[i] = NULL;
   1326 			//Log_Write("tiny volume after clip");
   1327 		}
   1328 	}
   1329 	if (!b[0] && !b[1])
   1330 	{
   1331 		Log_Write("two tiny brushes\r\n");
   1332 	} //end if
   1333 }
   1334 
   1335 	*front = b[0];
   1336 	*back = b[1];
   1337 } //end of the function SplitBrush
   1338 //===========================================================================
   1339 //
   1340 // Parameter:			-
   1341 // Returns:				-
   1342 // Changes Globals:		-
   1343 //===========================================================================
   1344 void SplitBrushList (bspbrush_t *brushes, 
   1345 	node_t *node, bspbrush_t **front, bspbrush_t **back)
   1346 {
   1347 	bspbrush_t	*brush, *newbrush, *newbrush2;
   1348 	side_t		*side;
   1349 	int			sides;
   1350 	int			i;
   1351 
   1352 	*front = *back = NULL;
   1353 
   1354 	for (brush = brushes; brush; brush = brush->next)
   1355 	{
   1356 		sides = brush->side;
   1357 
   1358 		if (sides == PSIDE_BOTH)
   1359 		{	// split into two brushes
   1360 			SplitBrush (brush, node->planenum, &newbrush, &newbrush2);
   1361 			if (newbrush)
   1362 			{
   1363 				newbrush->next = *front;
   1364 				*front = newbrush;
   1365 			} //end if
   1366 			if (newbrush2)
   1367 			{
   1368 				newbrush2->next = *back;
   1369 				*back = newbrush2;
   1370 			} //end if
   1371 			continue;
   1372 		} //end if
   1373 
   1374 		newbrush = CopyBrush (brush);
   1375 
   1376 		// if the planenum is actualy a part of the brush
   1377 		// find the plane and flag it as used so it won't be tried
   1378 		// as a splitter again
   1379 		if (sides & PSIDE_FACING)
   1380 		{
   1381 			for (i=0 ; i<newbrush->numsides ; i++)
   1382 			{
   1383 				side = newbrush->sides + i;
   1384 				if ( (side->planenum& ~1) == node->planenum)
   1385 					side->texinfo = TEXINFO_NODE;
   1386 			} //end for
   1387 		} //end if
   1388 		if (sides & PSIDE_FRONT)
   1389 		{
   1390 			newbrush->next = *front;
   1391 			*front = newbrush;
   1392 			continue;
   1393 		} //end if
   1394 		if (sides & PSIDE_BACK)
   1395 		{
   1396 			newbrush->next = *back;
   1397 			*back = newbrush;
   1398 			continue;
   1399 		} //end if
   1400 	} //end for
   1401 } //end of the function SplitBrushList
   1402 //===========================================================================
   1403 //
   1404 // Parameter:			-
   1405 // Returns:				-
   1406 // Changes Globals:		-
   1407 //===========================================================================
   1408 void CheckBrushLists(bspbrush_t *brushlist1, bspbrush_t *brushlist2)
   1409 {
   1410 	bspbrush_t *brush1, *brush2;
   1411 
   1412 	for (brush1 = brushlist1; brush1; brush1 = brush1->next)
   1413 	{
   1414 		for (brush2 = brushlist2; brush2; brush2 = brush2->next)
   1415 		{
   1416 			assert(brush1 != brush2);
   1417 		} //end for
   1418 	} //end for
   1419 } //end of the function CheckBrushLists
   1420 //===========================================================================
   1421 //
   1422 // Parameter:			-
   1423 // Returns:				-
   1424 // Changes Globals:		-
   1425 //===========================================================================
   1426 int numrecurse = 0;
   1427 
   1428 node_t *BuildTree_r (node_t *node, bspbrush_t *brushes)
   1429 {
   1430 	node_t		*newnode;
   1431 	side_t		*bestside;
   1432 	int			i, totalmem;
   1433 	bspbrush_t	*children[2];
   1434 
   1435 	qprintf("\r%6d", numrecurse);
   1436 	numrecurse++;
   1437 
   1438 	if (numthreads == 1)
   1439 	{
   1440 		totalmem = WindingMemory() + c_nodememory + c_brushmemory;
   1441 		if (totalmem > c_peak_totalbspmemory)
   1442 			c_peak_totalbspmemory = totalmem;
   1443 		c_nodes++;
   1444 	} //endif
   1445 
   1446 	if (drawflag)
   1447 		DrawBrushList(brushes, node);
   1448 
   1449 	// find the best plane to use as a splitter
   1450 	bestside = SelectSplitSide (brushes, node);
   1451 	if (!bestside)
   1452 	{
   1453 		// leaf node
   1454 		node->side = NULL;
   1455 		node->planenum = -1;
   1456 		LeafNode(node, brushes);
   1457 		if (node->contents & CONTENTS_SOLID) c_solidleafnodes++;
   1458 		if (create_aas)
   1459 		{
   1460 			//free up memory!!!
   1461 			FreeBrushList(node->brushlist);
   1462 			node->brushlist = NULL;
   1463 			//free the node volume brush
   1464 			if (node->volume)
   1465 			{
   1466 				FreeBrush(node->volume);
   1467 				node->volume = NULL;
   1468 			} //end if
   1469 		} //end if
   1470 		return node;
   1471 	} //end if
   1472 
   1473 	// this is a splitplane node
   1474 	node->side = bestside;
   1475 	node->planenum = bestside->planenum & ~1;	// always use front facing
   1476 
   1477 	//split the brush list in two for both children
   1478 	SplitBrushList (brushes, node, &children[0], &children[1]);
   1479 	//free the old brush list
   1480 	FreeBrushList (brushes);
   1481 
   1482 	// allocate children before recursing
   1483 	for (i = 0; i < 2; i++)
   1484 	{
   1485 		newnode = AllocNode ();
   1486 		newnode->parent = node;
   1487 		node->children[i] = newnode;
   1488 	} //end for
   1489 
   1490 	//split the volume brush of the node for the children
   1491 	SplitBrush (node->volume, node->planenum, &node->children[0]->volume,
   1492 		&node->children[1]->volume);
   1493 
   1494 	if (create_aas)
   1495 	{
   1496 		//free the volume brush
   1497 		if (node->volume)
   1498 		{
   1499 			FreeBrush(node->volume);
   1500 			node->volume = NULL;
   1501 		} //end if
   1502 	} //end if
   1503 	// recursively process children
   1504 	for (i = 0; i < 2; i++)
   1505 	{
   1506 		node->children[i] = BuildTree_r(node->children[i], children[i]);
   1507 	} //end for
   1508 
   1509 	return node;
   1510 } //end of the function BuildTree_r
   1511 //===========================================================================
   1512 //
   1513 // Parameter:			-
   1514 // Returns:				-
   1515 // Changes Globals:		-
   1516 //===========================================================================
   1517 node_t *firstnode;		//first node in the list
   1518 node_t *lastnode;			//last node in the list
   1519 int nodelistsize;			//number of nodes in the list
   1520 int use_nodequeue = 0;	//use nodequeue, otherwise a node stack is used
   1521 int numwaiting = 0;
   1522 
   1523 void (*AddNodeToList)(node_t *node);
   1524 
   1525 //add the node to the front of the node list
   1526 //(effectively using a node stack)
   1527 void AddNodeToStack(node_t *node)
   1528 {
   1529 	ThreadLock();
   1530 
   1531 	node->next = firstnode;
   1532 	firstnode = node;
   1533 	if (!lastnode) lastnode = node;
   1534 	nodelistsize++;
   1535 
   1536 	ThreadUnlock();
   1537 	//
   1538 	ThreadSemaphoreIncrease(1);
   1539 } //end of the function AddNodeToStack
   1540 //add the node to the end of the node list
   1541 //(effectively using a node queue)
   1542 void AddNodeToQueue(node_t *node)
   1543 {
   1544 	ThreadLock();
   1545 
   1546 	node->next = NULL;
   1547 	if (lastnode) lastnode->next = node;
   1548 	else firstnode = node;
   1549 	lastnode = node;
   1550 	nodelistsize++;
   1551 
   1552 	ThreadUnlock();
   1553 	//
   1554 	ThreadSemaphoreIncrease(1);
   1555 } //end of the function AddNodeToQueue
   1556 //get the first node from the front of the node list
   1557 node_t *NextNodeFromList(void)
   1558 {
   1559 	node_t *node;
   1560 
   1561 	ThreadLock();
   1562 	numwaiting++;
   1563 	if (!firstnode)
   1564 	{
   1565 		if (numwaiting >= GetNumThreads()) ThreadSemaphoreIncrease(GetNumThreads());
   1566 	} //end if
   1567 	ThreadUnlock();
   1568 
   1569 	ThreadSemaphoreWait();
   1570 
   1571 	ThreadLock();
   1572 
   1573 	numwaiting--;
   1574 
   1575 	node = firstnode;
   1576 	if (firstnode)
   1577 	{
   1578 		firstnode = firstnode->next;
   1579 		nodelistsize--;
   1580 	} //end if
   1581 	if (!firstnode) lastnode = NULL;
   1582 
   1583 	ThreadUnlock();
   1584 
   1585 	return node;
   1586 } //end of the function NextNodeFromList
   1587 //returns the size of the node list
   1588 int NodeListSize(void)
   1589 {
   1590 	int size;
   1591 
   1592 	ThreadLock();
   1593 	size = nodelistsize;
   1594 	ThreadUnlock();
   1595 
   1596 	return size;
   1597 } //end of the function NodeListSize
   1598 //
   1599 void IncreaseNodeCounter(void)
   1600 {
   1601 	ThreadLock();
   1602 	//if (verbose) printf("\r%6d", numrecurse++);
   1603 	qprintf("\r%6d", numrecurse++);
   1604 	//qprintf("\r%6d %d, %5d ", numrecurse++, GetNumThreads(), nodelistsize);
   1605 	ThreadUnlock();
   1606 } //end of the function IncreaseNodeCounter
   1607 //thread function, gets nodes from the nodelist and processes them
   1608 void BuildTreeThread(int threadid)
   1609 {
   1610 	node_t *newnode, *node;
   1611 	side_t *bestside;
   1612 	int i, totalmem;
   1613 	bspbrush_t *brushes;
   1614 
   1615 	for (node = NextNodeFromList(); node; )
   1616 	{
   1617 		//if the nodelist isn't empty try to add another thread
   1618 		//if (NodeListSize() > 10) AddThread(BuildTreeThread);
   1619 		//display the number of nodes processed so far
   1620 		if (numthreads == 1)
   1621 			IncreaseNodeCounter();
   1622 
   1623 		brushes = node->brushlist;
   1624 
   1625 		if (numthreads == 1)
   1626 		{
   1627 			totalmem = WindingMemory() + c_nodememory + c_brushmemory;
   1628 			if (totalmem > c_peak_totalbspmemory)
   1629 			{
   1630 				c_peak_totalbspmemory = totalmem;
   1631 			} //end if
   1632 			c_nodes++;
   1633 		} //endif
   1634 
   1635 		if (drawflag)
   1636 		{
   1637 			DrawBrushList(brushes, node);
   1638 		} //end if
   1639 
   1640 		if (cancelconversion)
   1641 		{
   1642 			bestside = NULL;
   1643 		} //end if
   1644 		else
   1645 		{
   1646 			// find the best plane to use as a splitter
   1647 			bestside = SelectSplitSide(brushes, node);
   1648 		} //end else
   1649 		//if there's no split side left
   1650 		if (!bestside)
   1651 		{
   1652 			//create a leaf out of the node
   1653 			LeafNode(node, brushes);
   1654 			if (node->contents & CONTENTS_SOLID) c_solidleafnodes++;
   1655 			if (create_aas)
   1656 			{
   1657 				//free up memory!!!
   1658 				FreeBrushList(node->brushlist);
   1659 				node->brushlist = NULL;
   1660 			} //end if
   1661 			//free the node volume brush (it is not used anymore)
   1662 			if (node->volume)
   1663 			{
   1664 				FreeBrush(node->volume);
   1665 				node->volume = NULL;
   1666 			} //end if
   1667 			node = NextNodeFromList();
   1668 			continue;
   1669 		} //end if
   1670 
   1671 		// this is a splitplane node
   1672 		node->side = bestside;
   1673 		node->planenum = bestside->planenum & ~1;	//always use front facing
   1674 
   1675 		//allocate children
   1676 		for (i = 0; i < 2; i++)
   1677 		{
   1678 			newnode = AllocNode();
   1679 			newnode->parent = node;
   1680 			node->children[i] = newnode;
   1681 		} //end for
   1682 
   1683 		//split the brush list in two for both children
   1684 		SplitBrushList(brushes, node, &node->children[0]->brushlist, &node->children[1]->brushlist);
   1685 
   1686 		CheckBrushLists(node->children[0]->brushlist, node->children[1]->brushlist);
   1687 		//free the old brush list
   1688 		FreeBrushList(brushes);
   1689 		node->brushlist = NULL;
   1690 
   1691 		//split the volume brush of the node for the children
   1692 		SplitBrush(node->volume, node->planenum, &node->children[0]->volume,
   1693 								&node->children[1]->volume);
   1694 
   1695 		if (!node->children[0]->volume || !node->children[1]->volume)
   1696 		{
   1697 			Error("child without volume brush");
   1698 		} //end if
   1699 
   1700 		//free the volume brush
   1701 		if (node->volume)
   1702 		{
   1703 			FreeBrush(node->volume);
   1704 			node->volume = NULL;
   1705 		} //end if
   1706 		//add both children to the node list
   1707 		//AddNodeToList(node->children[0]);
   1708 		AddNodeToList(node->children[1]);
   1709 		node = node->children[0];
   1710 	} //end while
   1711 	RemoveThread(threadid);
   1712 } //end of the function BuildTreeThread
   1713 //===========================================================================
   1714 // build the bsp tree using a node list
   1715 //
   1716 // Parameter:			-
   1717 // Returns:				-
   1718 // Changes Globals:		-
   1719 //===========================================================================
   1720 void BuildTree(tree_t *tree)
   1721 {
   1722 	int i;
   1723 
   1724 	firstnode = NULL;
   1725 	lastnode = NULL;
   1726 	//use a node queue or node stack
   1727 	if (use_nodequeue) AddNodeToList = AddNodeToQueue;
   1728 	else AddNodeToList = AddNodeToStack;
   1729 	//setup thread locking
   1730 	ThreadSetupLock();
   1731 	ThreadSetupSemaphore();
   1732 	numwaiting = 0;
   1733 	//
   1734 	Log_Print("%6d threads max\n", numthreads);
   1735 	if (use_nodequeue) Log_Print("breadth first bsp building\n");
   1736 	else Log_Print("depth first bsp building\n");
   1737 	qprintf("%6d splits", 0);
   1738 	//add the first node to the list
   1739 	AddNodeToList(tree->headnode);
   1740 	//start the threads
   1741 	for (i = 0; i < numthreads; i++)
   1742 		AddThread(BuildTreeThread);
   1743 	//wait for all added threads to be finished
   1744 	WaitForAllThreadsFinished();
   1745 	//shutdown the thread locking
   1746 	ThreadShutdownLock();
   1747 	ThreadShutdownSemaphore();
   1748 } //end of the function BuildTree
   1749 //===========================================================================
   1750 // The incoming brush list will be freed before exiting
   1751 //
   1752 // Parameter:			-
   1753 // Returns:				-
   1754 // Changes Globals:		-
   1755 //===========================================================================
   1756 tree_t *BrushBSP(bspbrush_t *brushlist, vec3_t mins, vec3_t maxs)
   1757 {
   1758 	int i, c_faces, c_nonvisfaces, c_brushes;
   1759 	bspbrush_t *b;
   1760 	node_t *node;
   1761 	tree_t *tree;
   1762 	vec_t volume;
   1763 //	vec3_t point;
   1764 
   1765 	Log_Print("-------- Brush BSP ---------\n");
   1766 
   1767 	tree = Tree_Alloc();
   1768 
   1769 	c_faces = 0;
   1770 	c_nonvisfaces = 0;
   1771 	c_brushes = 0;
   1772 	c_totalsides = 0;
   1773 	for (b = brushlist; b; b = b->next)
   1774 	{
   1775 		c_brushes++;
   1776 
   1777 		volume = BrushVolume(b);
   1778 		if (volume < microvolume)
   1779 		{
   1780 			Log_Print("WARNING: entity %i, brush %i: microbrush\n",
   1781 				b->original->entitynum, b->original->brushnum);
   1782 		} //end if
   1783 
   1784 		for (i=0 ; i<b->numsides ; i++)
   1785 		{
   1786 			if (b->sides[i].flags & SFL_BEVEL)
   1787 				continue;
   1788 			if (!b->sides[i].winding)
   1789 				continue;
   1790 			if (b->sides[i].texinfo == TEXINFO_NODE)
   1791 				continue;
   1792 			if (b->sides[i].flags & SFL_VISIBLE)
   1793 			{
   1794 				c_faces++;
   1795 			} //end if
   1796 			else
   1797 			{
   1798 				c_nonvisfaces++;
   1799 				//if (create_aas) b->sides[i].texinfo = TEXINFO_NODE;
   1800 			} //end if
   1801 		} //end for
   1802 		c_totalsides += b->numsides;
   1803 
   1804 		AddPointToBounds (b->mins, tree->mins, tree->maxs);
   1805 		AddPointToBounds (b->maxs, tree->mins, tree->maxs);
   1806 	} //end for
   1807 
   1808 	Log_Print("%6i brushes\n", c_brushes);
   1809 	Log_Print("%6i visible faces\n", c_faces);
   1810 	Log_Print("%6i nonvisible faces\n", c_nonvisfaces);
   1811 	Log_Print("%6i total sides\n", c_totalsides);
   1812 
   1813 	c_active_brushes = c_brushes;
   1814 	c_nodememory = 0;
   1815 	c_brushmemory = 0;
   1816 	c_peak_brushmemory = 0;
   1817 
   1818 	c_nodes = 0;
   1819 	c_nonvis = 0;
   1820 	node = AllocNode ();
   1821 
   1822 	//volume of first node (head node)
   1823 	node->volume = BrushFromBounds (mins, maxs);
   1824 	//
   1825 	tree->headnode = node;
   1826 	//just get some statistics and the mins/maxs of the node
   1827 	numrecurse = 0;
   1828 //	qprintf("%6d splits", numrecurse);
   1829 
   1830 	tree->headnode->brushlist = brushlist;
   1831 	BuildTree(tree);
   1832 
   1833 	//build the bsp tree with the start node from the brushlist
   1834 //	node = BuildTree_r(node, brushlist);
   1835 
   1836 	//if the conversion is cancelled
   1837 	if (cancelconversion) return tree;
   1838 
   1839 	qprintf("\n");
   1840 	Log_Write("%6d splits\r\n", numrecurse);
   1841 //	Log_Print("%6i visible nodes\n", c_nodes/2 - c_nonvis);
   1842 //	Log_Print("%6i nonvis nodes\n", c_nonvis);
   1843 //	Log_Print("%6i leaves\n", (c_nodes+1)/2);
   1844 //	Log_Print("%6i solid leaf nodes\n", c_solidleafnodes);
   1845 //	Log_Print("%6i active brushes\n", c_active_brushes);
   1846 	if (numthreads == 1)
   1847 	{
   1848 //		Log_Print("%6i KB of node memory\n", c_nodememory >> 10);
   1849 //		Log_Print("%6i KB of brush memory\n", c_brushmemory >> 10);
   1850 //		Log_Print("%6i KB of peak brush memory\n", c_peak_brushmemory >> 10);
   1851 //		Log_Print("%6i KB of winding memory\n", WindingMemory() >> 10);
   1852 //		Log_Print("%6i KB of peak winding memory\n", WindingPeakMemory() >> 10);
   1853 		Log_Print("%6i KB of peak total bsp memory\n", c_peak_totalbspmemory >> 10);
   1854 	} //end if
   1855 
   1856 	/*
   1857 	point[0] = 1485;
   1858 	point[1] = 956.125;
   1859 	point[2] = 352.125;
   1860 	node = PointInLeaf(tree->headnode, point);
   1861 	if (node->planenum != PLANENUM_LEAF)
   1862 	{
   1863 		Log_Print("node not a leaf\n");
   1864 	} //end if
   1865 	Log_Print("at %f %f %f:\n", point[0], point[1], point[2]);
   1866 	PrintContents(node->contents);
   1867 	Log_Print("node->expansionbboxes = %d\n", node->expansionbboxes);
   1868 	//*/
   1869 	return tree;
   1870 } //end of the function BrushBSP
   1871