Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

csg.c (25901B)


      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 
     25 /*
     26 
     27 tag all brushes with original contents
     28 brushes may contain multiple contents
     29 there will be no brush overlap after csg phase
     30 
     31 */
     32 
     33 int minplanenums[3];
     34 int maxplanenums[3];
     35 
     36 //===========================================================================
     37 //
     38 // Parameter:				-
     39 // Returns:					-
     40 // Changes Globals:		-
     41 //===========================================================================
     42 void CheckBSPBrush(bspbrush_t *brush)
     43 {
     44 	int i, j;
     45 	plane_t *plane1, *plane2;
     46 
     47 	//check if the brush is convex... flipped planes make a brush non-convex
     48 	for (i = 0; i < brush->numsides; i++)
     49 	{
     50 		for (j = 0; j < brush->numsides; j++)
     51 		{
     52 			if (i == j) continue;
     53 			plane1 = &mapplanes[brush->sides[i].planenum];
     54 			plane2 = &mapplanes[brush->sides[j].planenum];
     55 			//
     56 			if (WindingsNonConvex(brush->sides[i].winding,
     57 									brush->sides[j].winding,
     58 									plane1->normal, plane2->normal,
     59 									plane1->dist, plane2->dist))
     60 			{
     61 				Log_Print("non convex brush");
     62 				break;
     63 			} //end if
     64 		} //end for
     65 	} //end for
     66 	BoundBrush(brush);
     67 	//check for out of bound brushes
     68 	for (i = 0; i < 3; i++)
     69 	{
     70 		if (brush->mins[i] < -MAX_MAP_BOUNDS || brush->maxs[i] > MAX_MAP_BOUNDS)
     71 		{
     72 			Log_Print("brush: bounds out of range\n");
     73 			Log_Print("ob->mins[%d] = %f, ob->maxs[%d] = %f\n", i, brush->mins[i], i, brush->maxs[i]);
     74 			break;
     75 		} //end if
     76 		if (brush->mins[i] > MAX_MAP_BOUNDS || brush->maxs[i] < -MAX_MAP_BOUNDS)
     77 		{
     78 			Log_Print("brush: no visible sides on brush\n");
     79 			Log_Print("ob->mins[%d] = %f, ob->maxs[%d] = %f\n", i, brush->mins[i], i, brush->maxs[i]);
     80 			break;
     81 		} //end if
     82 	} //end for
     83 } //end of the function CheckBSPBrush
     84 //===========================================================================
     85 //
     86 // Parameter:				-
     87 // Returns:					-
     88 // Changes Globals:		-
     89 //===========================================================================
     90 void BSPBrushWindings(bspbrush_t *brush)
     91 {
     92 	int i, j;
     93 	winding_t *w;
     94 	plane_t *plane;
     95 
     96 	for (i = 0; i < brush->numsides; i++)
     97 	{
     98 		plane = &mapplanes[brush->sides[i].planenum];
     99 		w = BaseWindingForPlane(plane->normal, plane->dist);
    100 		for (j = 0; j < brush->numsides && w; j++)
    101 		{
    102 			if (i == j) continue;
    103 			plane = &mapplanes[brush->sides[j].planenum^1];
    104 			ChopWindingInPlace(&w, plane->normal, plane->dist, 0); //CLIP_EPSILON);
    105 		} //end for
    106 		brush->sides[i].winding = w;
    107 	} //end for
    108 } //end of the function BSPBrushWindings
    109 //===========================================================================
    110 // NOTE: can't keep brush->original intact
    111 //
    112 // Parameter:				-
    113 // Returns:					-
    114 // Changes Globals:		-
    115 //===========================================================================
    116 bspbrush_t *TryMergeBrushes(bspbrush_t *brush1, bspbrush_t *brush2)
    117 {
    118 	int i, j, k, n, shared;
    119 	side_t *side1, *side2, *cs;
    120 	plane_t *plane1, *plane2;
    121 	bspbrush_t *newbrush;
    122 
    123 	//check for bounding box overlapp
    124 	for (i = 0; i < 3; i++)
    125 	{
    126 		if (brush1->mins[i] > brush2->maxs[i] + 2
    127 				|| brush1->maxs[i] < brush2->mins[i] - 2)
    128 		{
    129 			return NULL;
    130 		} //end if
    131 	} //end for
    132 	//
    133 	shared = 0;
    134 	//check if the brush is convex... flipped planes make a brush non-convex
    135 	for (i = 0; i < brush1->numsides; i++)
    136 	{
    137 		side1 = &brush1->sides[i];
    138 		//don't check the "shared" sides
    139 		for (k = 0; k < brush2->numsides; k++)
    140 		{
    141 			side2 = &brush2->sides[k];
    142 			if (side1->planenum == (side2->planenum^1))
    143 			{
    144 				shared++;
    145 				//there may only be ONE shared side
    146 				if (shared > 1) return NULL;
    147 				break;
    148 			} //end if
    149 		} //end for
    150 		if (k < brush2->numsides) continue;
    151 		//
    152 		for (j = 0; j < brush2->numsides; j++)
    153 		{
    154 			side2 = &brush2->sides[j];
    155 			//don't check the "shared" sides
    156 			for (n = 0; n < brush1->numsides; n++)
    157 			{
    158 				side1 = &brush1->sides[n];
    159 				if (side1->planenum == (side2->planenum^1)) break;
    160 			} //end for
    161 			if (n < brush1->numsides) continue;
    162 			//
    163 			side1 = &brush1->sides[i];
    164 			//if the side is in the same plane
    165 			//*
    166 			if (side1->planenum == side2->planenum)
    167 			{
    168 				if (side1->texinfo != TEXINFO_NODE &&
    169 					side2->texinfo != TEXINFO_NODE &&
    170 					side1->texinfo != side2->texinfo) return NULL;
    171 				continue;
    172 			} //end if
    173 			//
    174 			plane1 = &mapplanes[side1->planenum];
    175 			plane2 = &mapplanes[side2->planenum];
    176 			//
    177 			if (WindingsNonConvex(side1->winding, side2->winding,
    178 									plane1->normal, plane2->normal,
    179 									plane1->dist, plane2->dist))
    180 			{
    181 				return NULL;
    182 			} //end if
    183 		} //end for
    184 	} //end for
    185 	newbrush = AllocBrush(brush1->numsides + brush2->numsides);
    186 	newbrush->original = brush1->original;
    187 	newbrush->numsides = 0;
    188 	//newbrush->side = brush1->side;	//brush contents
    189 	//fix texinfos for sides lying in the same plane
    190 	for (i = 0; i < brush1->numsides; i++)
    191 	{
    192 		side1 = &brush1->sides[i];
    193 		//
    194 		for (n = 0; n < brush2->numsides; n++)
    195 		{
    196 			side2 = &brush2->sides[n];
    197 			//if both sides are in the same plane get the texinfo right
    198 			if (side1->planenum == side2->planenum)
    199 			{
    200 				if (side1->texinfo == TEXINFO_NODE) side1->texinfo = side2->texinfo;
    201 				if (side2->texinfo == TEXINFO_NODE) side2->texinfo = side1->texinfo;
    202 			} //end if
    203 		} //end for
    204 	} //end for
    205 	//
    206 	for (i = 0; i < brush1->numsides; i++)
    207 	{
    208 		side1 = &brush1->sides[i];
    209 		//don't add the "shared" sides
    210 		for (n = 0; n < brush2->numsides; n++)
    211 		{
    212 			side2 = &brush2->sides[n];
    213 			if (side1->planenum == (side2->planenum ^ 1)) break;
    214 		} //end for
    215 		if (n < brush2->numsides) continue;
    216 		//
    217 		for (n = 0; n < newbrush->numsides; n++)
    218 		{
    219 			cs = &newbrush->sides[n];
    220 			if (cs->planenum == side1->planenum)
    221 			{
    222 				Log_Print("brush duplicate plane\n");
    223 				break;
    224 			} //end if
    225 		} //end if
    226 		if (n < newbrush->numsides) continue;
    227 		//add this side
    228 		cs = &newbrush->sides[newbrush->numsides];
    229 		newbrush->numsides++;
    230 		*cs = *side1;
    231 	} //end for
    232 	for (j = 0; j < brush2->numsides; j++)
    233 	{
    234 		side2 = &brush2->sides[j];
    235 		for (n = 0; n < brush1->numsides; n++)
    236 		{
    237 			side1 = &brush1->sides[n];
    238 			//if the side is in the same plane
    239 			if (side2->planenum == side1->planenum) break;
    240 			//don't add the "shared" sides
    241 			if (side2->planenum == (side1->planenum ^ 1)) break;
    242 		} //end for
    243 		if (n < brush1->numsides) continue;
    244 		//
    245 		for (n = 0; n < newbrush->numsides; n++)
    246 		{
    247 			cs = &newbrush->sides[n];
    248 			if (cs->planenum == side2->planenum)
    249 			{
    250 				Log_Print("brush duplicate plane\n");
    251 				break;
    252 			} //end if
    253 		} //end if
    254 		if (n < newbrush->numsides) continue;
    255 		//add this side
    256 		cs = &newbrush->sides[newbrush->numsides];
    257 		newbrush->numsides++;
    258 		*cs = *side2;
    259 	} //end for
    260 	BSPBrushWindings(newbrush);
    261 	BoundBrush(newbrush);
    262 	CheckBSPBrush(newbrush);
    263 	return newbrush;
    264 } //end of the function TryMergeBrushes
    265 //===========================================================================
    266 //
    267 // Parameter:				-
    268 // Returns:					-
    269 // Changes Globals:		-
    270 //===========================================================================
    271 bspbrush_t *MergeBrushes(bspbrush_t *brushlist)
    272 {
    273 	int nummerges, merged;
    274 	bspbrush_t *b1, *b2, *tail, *newbrush, *newbrushlist;
    275 	bspbrush_t *lastb2;
    276 
    277 	if (!brushlist) return NULL;
    278 
    279 	qprintf("%5d brushes merged", nummerges = 0);
    280 	do
    281 	{
    282 		for (tail = brushlist; tail; tail = tail->next)
    283 		{
    284 			if (!tail->next) break;
    285 		} //end for
    286 		merged = 0;
    287 		newbrushlist = NULL;
    288 		for (b1 = brushlist; b1; b1 = brushlist)
    289 		{
    290 			lastb2 = b1;
    291 			for (b2 = b1->next; b2; b2 = b2->next)
    292 			{
    293 				//if the brushes don't have the same contents
    294 				if (b1->original->contents != b2->original->contents ||
    295 					b1->original->expansionbbox != b2->original->expansionbbox) newbrush = NULL;
    296 				else newbrush = TryMergeBrushes(b1, b2);
    297 				if (newbrush)
    298 				{
    299 					tail->next = newbrush;
    300 					lastb2->next = b2->next;
    301 					brushlist = brushlist->next;
    302 					FreeBrush(b1);
    303 					FreeBrush(b2);
    304 					for (tail = brushlist; tail; tail = tail->next)
    305 					{
    306 						if (!tail->next) break;
    307 					} //end for
    308 					merged++;
    309 					qprintf("\r%5d", nummerges++);
    310 					break;
    311 				} //end if
    312 				lastb2 = b2;
    313 			} //end for
    314 			//if b1 can't be merged with any of the other brushes
    315 			if (!b2)
    316 			{
    317 				brushlist = brushlist->next;
    318 				//keep b1
    319 				b1->next = newbrushlist;
    320 				newbrushlist = b1;
    321 			} //end else
    322 		} //end for
    323 		brushlist = newbrushlist;
    324 	} while(merged);
    325 	qprintf("\n");
    326 	return newbrushlist;
    327 } //end of the function MergeBrushes
    328 //===========================================================================
    329 //
    330 // Parameter:				-
    331 // Returns:					-
    332 // Changes Globals:		-
    333 //===========================================================================
    334 void SplitBrush2 (bspbrush_t *brush, int planenum,
    335 	bspbrush_t **front, bspbrush_t **back)
    336 {
    337 	SplitBrush (brush, planenum, front, back);
    338 #if 0
    339 	if (*front && (*front)->sides[(*front)->numsides-1].texinfo == -1)
    340 		(*front)->sides[(*front)->numsides-1].texinfo = (*front)->sides[0].texinfo;	// not -1
    341 	if (*back && (*back)->sides[(*back)->numsides-1].texinfo == -1)
    342 		(*back)->sides[(*back)->numsides-1].texinfo = (*back)->sides[0].texinfo;	// not -1
    343 #endif
    344 } //end of the function SplitBrush2
    345 //===========================================================================
    346 // Returns a list of brushes that remain after B is subtracted from A.
    347 // May by empty if A is contained inside B.
    348 // The originals are undisturbed.
    349 //
    350 // Parameter:				-
    351 // Returns:					-
    352 // Changes Globals:		-
    353 //===========================================================================
    354 bspbrush_t *SubtractBrush (bspbrush_t *a, bspbrush_t *b)
    355 {	// a - b = out (list)
    356 	int		i;
    357 	bspbrush_t	*front, *back;
    358 	bspbrush_t	*out, *in;
    359 
    360 	in = a;
    361 	out = NULL;
    362 	for (i = 0; i < b->numsides && in; i++)
    363 	{
    364 		SplitBrush2(in, b->sides[i].planenum, &front, &back);
    365 		if (in != a) FreeBrush(in);
    366 		if (front)
    367 		{	// add to list
    368 			front->next = out;
    369 			out = front;
    370 		} //end if
    371 		in = back;
    372 	} //end for
    373 	if (in)
    374 	{
    375 		FreeBrush (in);
    376 	} //end if
    377 	else
    378 	{	// didn't really intersect
    379 		FreeBrushList (out);
    380 		return a;
    381 	} //end else
    382 	return out;
    383 } //end of the function SubtractBrush
    384 //===========================================================================
    385 // Returns a single brush made up by the intersection of the
    386 // two provided brushes, or NULL if they are disjoint.
    387 //
    388 // The originals are undisturbed.
    389 //
    390 // Parameter:				-
    391 // Returns:					-
    392 // Changes Globals:		-
    393 //===========================================================================
    394 bspbrush_t *IntersectBrush (bspbrush_t *a, bspbrush_t *b)
    395 {
    396 	int		i;
    397 	bspbrush_t	*front, *back;
    398 	bspbrush_t	*in;
    399 
    400 	in = a;
    401 	for (i=0 ; i<b->numsides && in ; i++)
    402 	{
    403 		SplitBrush2(in, b->sides[i].planenum, &front, &back);
    404 		if (in != a) FreeBrush(in);
    405 		if (front) FreeBrush(front);
    406 		in = back;
    407 	} //end for
    408 
    409 	if (in == a) return NULL;
    410 
    411 	in->next = NULL;
    412 	return in;
    413 } //end of the function IntersectBrush
    414 //===========================================================================
    415 // Returns true if the two brushes definately do not intersect.
    416 // There will be false negatives for some non-axial combinations.
    417 //
    418 // Parameter:				-
    419 // Returns:					-
    420 // Changes Globals:		-
    421 //===========================================================================
    422 qboolean BrushesDisjoint (bspbrush_t *a, bspbrush_t *b)
    423 {
    424 	int		i, j;
    425 
    426 	// check bounding boxes
    427 	for (i=0 ; i<3 ; i++)
    428 		if (a->mins[i] >= b->maxs[i]
    429 		|| a->maxs[i] <= b->mins[i])
    430 			return true;	// bounding boxes don't overlap
    431 
    432 	// check for opposing planes
    433 	for (i=0 ; i<a->numsides ; i++)
    434 	{
    435 		for (j=0 ; j<b->numsides ; j++)
    436 		{
    437 			if (a->sides[i].planenum ==
    438 			(b->sides[j].planenum^1) )
    439 				return true;	// opposite planes, so not touching
    440 		}
    441 	}
    442 
    443 	return false;	// might intersect
    444 } //end of the function BrushesDisjoint
    445 //===========================================================================
    446 // Returns a content word for the intersection of two brushes.
    447 // Some combinations will generate a combination (water + clip),
    448 // but most will be the stronger of the two contents.
    449 //
    450 // Parameter:				-
    451 // Returns:					-
    452 // Changes Globals:		-
    453 //===========================================================================
    454 int IntersectionContents (int c1, int c2)
    455 {
    456 	int out;
    457 
    458 	out = c1 | c2;
    459 
    460 	if (out & CONTENTS_SOLID) out = CONTENTS_SOLID;
    461 
    462 	return out;
    463 } //end of the function IntersectionContents
    464 //===========================================================================
    465 // Any planes shared with the box edge will be set to no texinfo
    466 //
    467 // Parameter:				-
    468 // Returns:					-
    469 // Changes Globals:		-
    470 //===========================================================================
    471 bspbrush_t *ClipBrushToBox(bspbrush_t *brush, vec3_t clipmins, vec3_t clipmaxs)
    472 {
    473 	int		i, j;
    474 	bspbrush_t	*front,	*back;
    475 	int		p;
    476 
    477 	for (j=0 ; j<2 ; j++)
    478 	{
    479 		if (brush->maxs[j] > clipmaxs[j])
    480 		{
    481 			SplitBrush (brush, maxplanenums[j], &front, &back);
    482 			if (front)
    483 				FreeBrush (front);
    484 			brush = back;
    485 			if (!brush)
    486 				return NULL;
    487 		}
    488 		if (brush->mins[j] < clipmins[j])
    489 		{
    490 			SplitBrush (brush, minplanenums[j], &front, &back);
    491 			if (back)
    492 				FreeBrush (back);
    493 			brush = front;
    494 			if (!brush)
    495 				return NULL;
    496 		}
    497 	}
    498 
    499 	// remove any colinear faces
    500 
    501 	for (i=0 ; i<brush->numsides ; i++)
    502 	{
    503 		p = brush->sides[i].planenum & ~1;
    504 		if (p == maxplanenums[0] || p == maxplanenums[1] 
    505 			|| p == minplanenums[0] || p == minplanenums[1])
    506 		{
    507 			brush->sides[i].texinfo = TEXINFO_NODE;
    508 			brush->sides[i].flags &= ~SFL_VISIBLE;
    509 		}
    510 	}
    511 	return brush;
    512 } //end of the function ClipBrushToBox
    513 //===========================================================================
    514 //
    515 // Parameter:				-
    516 // Returns:					-
    517 // Changes Globals:		-
    518 //===========================================================================
    519 bspbrush_t *MakeBspBrushList(int startbrush, int endbrush,
    520 											vec3_t clipmins, vec3_t clipmaxs)
    521 {
    522 	mapbrush_t	*mb;
    523 	bspbrush_t	*brushlist, *newbrush;
    524 	int			i, j;
    525 	int			c_faces;
    526 	int			c_brushes;
    527 	int			numsides;
    528 	int			vis;
    529 	vec3_t		normal;
    530 	float		dist;
    531 
    532 	for (i=0 ; i<2 ; i++)
    533 	{
    534 		VectorClear (normal);
    535 		normal[i] = 1;
    536 		dist = clipmaxs[i];
    537 		maxplanenums[i] = FindFloatPlane(normal, dist);
    538 		dist = clipmins[i];
    539 		minplanenums[i] = FindFloatPlane(normal, dist);
    540 	}
    541 
    542 	brushlist = NULL;
    543 	c_faces = 0;
    544 	c_brushes = 0;
    545 
    546 	for (i=startbrush ; i<endbrush ; i++)
    547 	{
    548 		mb = &mapbrushes[i];
    549 
    550 		numsides = mb->numsides;
    551 		if (!numsides)
    552 			continue;
    553 
    554 		// make sure the brush has at least one face showing
    555 		vis = 0;
    556 		for (j=0 ; j<numsides ; j++)
    557 			if ((mb->original_sides[j].flags & SFL_VISIBLE) && mb->original_sides[j].winding)
    558 				vis++;
    559 #if 0
    560 		if (!vis)
    561 			continue;	// no faces at all
    562 #endif
    563 		// if the brush is outside the clip area, skip it
    564 		for (j=0 ; j<3 ; j++)
    565 			if (mb->mins[j] >= clipmaxs[j]
    566 			|| mb->maxs[j] <= clipmins[j])
    567 			break;
    568 		if (j != 3)
    569 			continue;
    570 
    571 		//
    572 		// make a copy of the brush
    573 		//
    574 		newbrush = AllocBrush (mb->numsides);
    575 		newbrush->original = mb;
    576 		newbrush->numsides = mb->numsides;
    577 		memcpy (newbrush->sides, mb->original_sides, numsides*sizeof(side_t));
    578 		for (j=0 ; j<numsides ; j++)
    579 		{
    580 			if (newbrush->sides[j].winding)
    581 				newbrush->sides[j].winding = CopyWinding (newbrush->sides[j].winding);
    582 			if (newbrush->sides[j].surf & SURF_HINT)
    583 				newbrush->sides[j].flags |= SFL_VISIBLE;	// hints are always visible
    584 		}
    585 		VectorCopy (mb->mins, newbrush->mins);
    586 		VectorCopy (mb->maxs, newbrush->maxs);
    587 
    588 		//
    589 		// carve off anything outside the clip box
    590 		//
    591 		newbrush = ClipBrushToBox (newbrush, clipmins, clipmaxs);
    592 		if (!newbrush)
    593 			continue;
    594 
    595 		c_faces += vis;
    596 		c_brushes++;
    597 
    598 		newbrush->next = brushlist;
    599 		brushlist = newbrush;
    600 	}
    601 
    602 	return brushlist;
    603 } //end of the function MakeBspBrushList
    604 //===========================================================================
    605 //
    606 // Parameter:				-
    607 // Returns:					-
    608 // Changes Globals:		-
    609 //===========================================================================
    610 bspbrush_t *AddBrushListToTail (bspbrush_t *list, bspbrush_t *tail)
    611 {
    612 	bspbrush_t	*walk, *next;
    613 
    614 	for (walk=list ; walk ; walk=next)
    615 	{	// add to end of list
    616 		next = walk->next;
    617 		walk->next = NULL;
    618 		tail->next = walk;
    619 		tail = walk;
    620 	} //end for
    621 	return tail;
    622 } //end of the function AddBrushListToTail
    623 //===========================================================================
    624 // Builds a new list that doesn't hold the given brush
    625 //
    626 // Parameter:				-
    627 // Returns:					-
    628 // Changes Globals:		-
    629 //===========================================================================
    630 bspbrush_t *CullList(bspbrush_t *list, bspbrush_t *skip1)
    631 {
    632 	bspbrush_t	*newlist;
    633 	bspbrush_t	*next;
    634 
    635 	newlist = NULL;
    636 
    637 	for ( ; list ; list = next)
    638 	{
    639 		next = list->next;
    640 		if (list == skip1)
    641 		{
    642 			FreeBrush (list);
    643 			continue;
    644 		}
    645 		list->next = newlist;
    646 		newlist = list;
    647 	}
    648 	return newlist;
    649 } //end of the function CullList
    650 //===========================================================================
    651 //
    652 // Parameter:				-
    653 // Returns:					-
    654 // Changes Globals:		-
    655 //===========================================================================
    656 /*
    657 void WriteBrushMap(char *name, bspbrush_t *list)
    658 {
    659 	FILE	*f;
    660 	side_t	*s;
    661 	int		i;
    662 	winding_t	*w;
    663 
    664 	Log_Print("writing %s\n", name);
    665 	f = fopen (name, "wb");
    666 	if (!f)
    667 		Error ("Can't write %s\b", name);
    668 
    669 	fprintf (f, "{\n\"classname\" \"worldspawn\"\n");
    670 
    671 	for ( ; list ; list=list->next )
    672 	{
    673 		fprintf (f, "{\n");
    674 		for (i=0,s=list->sides ; i<list->numsides ; i++,s++)
    675 		{
    676 			w = BaseWindingForPlane (mapplanes[s->planenum].normal, mapplanes[s->planenum].dist);
    677 
    678 			fprintf (f,"( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]);
    679 			fprintf (f,"( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]);
    680 			fprintf (f,"( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]);
    681 
    682 			fprintf (f, "%s 0 0 0 1 1\n", texinfo[s->texinfo].texture);
    683 			FreeWinding (w);
    684 		}
    685 		fprintf (f, "}\n");
    686 	}
    687 	fprintf (f, "}\n");
    688 
    689 	fclose (f);
    690 } //end of the function WriteBrushMap
    691 */
    692 //===========================================================================
    693 // Returns true if b1 is allowed to bite b2
    694 //
    695 // Parameter:				-
    696 // Returns:					-
    697 // Changes Globals:		-
    698 //===========================================================================
    699 qboolean BrushGE (bspbrush_t *b1, bspbrush_t *b2)
    700 {
    701 #ifdef ME
    702 	if (create_aas)
    703 	{
    704 		if (b1->original->expansionbbox != b2->original->expansionbbox)
    705 		{
    706 			return false;
    707 		} //end if
    708 		//never have something else bite a ladder brush
    709 		//never have a ladder brush bite something else
    710 		if ( (b1->original->contents & CONTENTS_LADDER)
    711 			&& !(b2->original->contents & CONTENTS_LADDER))
    712 		{ 
    713 			return false;
    714 		} //end if
    715 	} //end if
    716 #endif //ME
    717 	// detail brushes never bite structural brushes
    718 	if ( (b1->original->contents & CONTENTS_DETAIL) 
    719 		&& !(b2->original->contents & CONTENTS_DETAIL) )
    720 	{
    721 		return false;
    722 	} //end if
    723 	if (b1->original->contents & CONTENTS_SOLID)
    724 	{
    725 		return true;
    726 	} //end if
    727 	return false;
    728 } //end of the function BrushGE
    729 //===========================================================================
    730 // Carves any intersecting solid brushes into the minimum number
    731 // of non-intersecting brushes.
    732 //
    733 // Parameter:				-
    734 // Returns:					-
    735 // Changes Globals:		-
    736 //===========================================================================
    737 bspbrush_t *ChopBrushes (bspbrush_t *head)
    738 {
    739 	bspbrush_t	*b1, *b2, *next;
    740 	bspbrush_t	*tail;
    741 	bspbrush_t	*keep;
    742 	bspbrush_t	*sub, *sub2;
    743 	int			c1, c2;
    744 	int num_csg_iterations;
    745 
    746 	Log_Print("-------- Brush CSG ---------\n");
    747 	Log_Print("%6d original brushes\n", CountBrushList (head));
    748 
    749 	num_csg_iterations = 0;
    750 	qprintf("%6d output brushes", num_csg_iterations);
    751 
    752 #if 0
    753 	if (startbrush == 0)
    754 		WriteBrushList ("before.gl", head, false);
    755 #endif
    756 	keep = NULL;
    757 
    758 newlist:
    759 	// find tail
    760 	if (!head) return NULL;
    761 
    762 	for (tail = head; tail->next; tail = tail->next)
    763 		;
    764 
    765 	for (b1=head ; b1 ; b1=next)
    766 	{
    767 		next = b1->next;
    768 
    769 		//if the conversion is cancelled
    770 		if (cancelconversion)
    771 		{
    772 			b1->next = keep;
    773 			keep = b1;
    774 			continue;
    775 		} //end if
    776 		
    777 		for (b2 = b1->next; b2; b2 = b2->next)
    778 		{
    779 			if (BrushesDisjoint (b1, b2))
    780 				continue;
    781 
    782 			sub = NULL;
    783 			sub2 = NULL;
    784 			c1 = 999999;
    785 			c2 = 999999;
    786 
    787 			if (BrushGE (b2, b1))
    788 			{
    789 				sub = SubtractBrush (b1, b2);
    790 				if (sub == b1)
    791 				{
    792 					continue;		// didn't really intersect
    793 				} //end if
    794 				if (!sub)
    795 				{	// b1 is swallowed by b2
    796 					head = CullList (b1, b1);
    797 					goto newlist;
    798 				}
    799 				c1 = CountBrushList (sub);
    800 			}
    801 
    802 			if ( BrushGE (b1, b2) )
    803 			{
    804 				sub2 = SubtractBrush (b2, b1);
    805 				if (sub2 == b2)
    806 					continue;		// didn't really intersect
    807 				if (!sub2)
    808 				{	// b2 is swallowed by b1
    809 					FreeBrushList (sub);
    810 					head = CullList (b1, b2);
    811 					goto newlist;
    812 				}
    813 				c2 = CountBrushList (sub2);
    814 			}
    815 
    816 			if (!sub && !sub2)
    817 				continue;		// neither one can bite
    818 
    819 			// only accept if it didn't fragment
    820 			// (commenting this out allows full fragmentation)
    821 			if (c1 > 1 && c2 > 1)
    822 			{
    823 				if (sub2)
    824 					FreeBrushList (sub2);
    825 				if (sub)
    826 					FreeBrushList (sub);
    827 				continue;
    828 			}
    829 
    830 			if (c1 < c2)
    831 			{
    832 				if (sub2) FreeBrushList (sub2);
    833 				tail = AddBrushListToTail (sub, tail);
    834 				head = CullList (b1, b1);
    835 				goto newlist;
    836 			} //end if
    837 			else
    838 			{
    839 				if (sub) FreeBrushList (sub);
    840 				tail = AddBrushListToTail (sub2, tail);
    841 				head = CullList (b1, b2);
    842 				goto newlist;
    843 			} //end else
    844 		} //end for
    845 
    846 		if (!b2)
    847 		{	// b1 is no longer intersecting anything, so keep it
    848 			b1->next = keep;
    849 			keep = b1;
    850 		} //end if
    851 		num_csg_iterations++;
    852 		qprintf("\r%6d", num_csg_iterations);
    853 	} //end for
    854 
    855 	if (cancelconversion) return keep;
    856 	//
    857 	qprintf("\n");
    858 	Log_Write("%6d output brushes\r\n", num_csg_iterations);
    859 
    860 #if 0
    861 	{
    862 		WriteBrushList ("after.gl", keep, false);
    863 		WriteBrushMap ("after.map", keep);
    864 	}
    865 #endif
    866 
    867 	return keep;
    868 } //end of the function ChopBrushes
    869 //===========================================================================
    870 //
    871 // Parameter:				-
    872 // Returns:					-
    873 // Changes Globals:		-
    874 //===========================================================================
    875 bspbrush_t *InitialBrushList (bspbrush_t *list)
    876 {
    877 	bspbrush_t *b;
    878 	bspbrush_t	*out, *newb;
    879 	int			i;
    880 
    881 	// only return brushes that have visible faces
    882 	out = NULL;
    883 	for (b=list ; b ; b=b->next)
    884 	{
    885 #if 0
    886 		for (i=0 ; i<b->numsides ; i++)
    887 			if (b->sides[i].flags & SFL_VISIBLE)
    888 				break;
    889 		if (i == b->numsides)
    890 			continue;
    891 #endif
    892 		newb = CopyBrush (b);
    893 		newb->next = out;
    894 		out = newb;
    895 
    896 		// clear visible, so it must be set by MarkVisibleFaces_r
    897 		// to be used in the optimized list
    898 		for (i=0 ; i<b->numsides ; i++)
    899 		{
    900 			newb->sides[i].original = &b->sides[i];
    901 //			newb->sides[i].visible = true;
    902 			b->sides[i].flags &= ~SFL_VISIBLE;
    903 		}
    904 	}
    905 
    906 	return out;
    907 } //end of the function InitialBrushList
    908 //===========================================================================
    909 //
    910 // Parameter:				-
    911 // Returns:					-
    912 // Changes Globals:		-
    913 //===========================================================================
    914 bspbrush_t *OptimizedBrushList (bspbrush_t *list)
    915 {
    916 	bspbrush_t *b;
    917 	bspbrush_t	*out, *newb;
    918 	int			i;
    919 
    920 	// only return brushes that have visible faces
    921 	out = NULL;
    922 	for (b=list ; b ; b=b->next)
    923 	{
    924 		for (i=0 ; i<b->numsides ; i++)
    925 			if (b->sides[i].flags & SFL_VISIBLE)
    926 				break;
    927 		if (i == b->numsides)
    928 			continue;
    929 		newb = CopyBrush (b);
    930 		newb->next = out;
    931 		out = newb;
    932 	} //end for
    933 
    934 //	WriteBrushList ("vis.gl", out, true);
    935 	return out;
    936 } //end of the function OptimizeBrushList
    937 //===========================================================================
    938 //
    939 // Parameter:				-
    940 // Returns:					-
    941 // Changes Globals:		-
    942 //===========================================================================
    943 tree_t *ProcessWorldBrushes(int brush_start, int brush_end)
    944 {
    945 	bspbrush_t *brushes;
    946 	tree_t *tree;
    947 	node_t *node;
    948 	vec3_t mins, maxs;
    949 
    950 	//take the whole world
    951 	mins[0] = map_mins[0] - 8;
    952 	mins[1] = map_mins[1] - 8;
    953 	mins[2] = map_mins[2] - 8;
    954 
    955 	maxs[0] = map_maxs[0] + 8;
    956 	maxs[1] = map_maxs[1] + 8;
    957 	maxs[2] = map_maxs[2] + 8;
    958 
    959 	//reset the brush bsp
    960 	ResetBrushBSP();
    961 
    962 	// the makelist and chopbrushes could be cached between the passes...
    963 
    964 	//create a list with brushes that are within the given mins/maxs
    965 	//some brushes will be cut and only the part that falls within the
    966 	//mins/maxs will be in the bush list
    967 	brushes = MakeBspBrushList(brush_start, brush_end, mins, maxs);
    968 	//
    969 
    970 	if (!brushes)
    971 	{
    972 		node = AllocNode ();
    973 		node->planenum = PLANENUM_LEAF;
    974 		node->contents = CONTENTS_SOLID;
    975 
    976 		tree = Tree_Alloc();
    977 		tree->headnode = node;
    978 		VectorCopy(mins, tree->mins);
    979 		VectorCopy(maxs, tree->maxs);
    980 	} //end if
    981 	else
    982 	{
    983 		//Carves any intersecting solid brushes into the minimum number
    984 		//of non-intersecting brushes. 
    985 		if (!nocsg)
    986 		{
    987 			brushes = ChopBrushes(brushes);
    988 			/*
    989 			if (create_aas)
    990 			{
    991 				brushes = MergeBrushes(brushes);
    992 			} //end if*/
    993 		} //end if
    994 		//if the conversion is cancelled
    995 		if (cancelconversion)
    996 		{
    997 			FreeBrushList(brushes);
    998 			return NULL;
    999 		} //end if
   1000 		//create the actual bsp tree
   1001 		tree = BrushBSP(brushes, mins, maxs);
   1002 	} //end else
   1003 	//return the tree
   1004 	return tree;
   1005 } //end of the function ProcessWorldBrushes