Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

map_hl.c (31500B)


      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_bsp_hl.h"
     25 #include "aas_map.h"			//AAS_CreateMapBrushes
     26 
     27 int hl_numbrushes;
     28 int hl_numclipbrushes;
     29 
     30 //#define HL_PRINT
     31 #define HLCONTENTS
     32 
     33 //===========================================================================
     34 //
     35 // Parameter:				-
     36 // Returns:					-
     37 // Changes Globals:		-
     38 //===========================================================================
     39 int HL_TextureContents(char *name)
     40 {
     41 	if (!Q_strncasecmp (name, "sky",3))
     42 		return CONTENTS_SOLID;
     43 
     44 	if (!Q_strncasecmp(name+1,"!lava",5))
     45 		return CONTENTS_LAVA;
     46 
     47 	if (!Q_strncasecmp(name+1,"!slime",6))
     48 		return CONTENTS_SLIME;
     49 
     50 	/*
     51 	if (!Q_strncasecmp (name, "!cur_90",7))
     52 		return CONTENTS_CURRENT_90;
     53 	if (!Q_strncasecmp (name, "!cur_0",6))
     54 		return CONTENTS_CURRENT_0;
     55 	if (!Q_strncasecmp (name, "!cur_270",8))
     56 		return CONTENTS_CURRENT_270;
     57 	if (!Q_strncasecmp (name, "!cur_180",8))
     58 		return CONTENTS_CURRENT_180;
     59 	if (!Q_strncasecmp (name, "!cur_up",7))
     60 		return CONTENTS_CURRENT_UP;
     61 	if (!Q_strncasecmp (name, "!cur_dwn",8))
     62 		return CONTENTS_CURRENT_DOWN;
     63 	//*/
     64 	if (name[0] == '!')
     65 		return CONTENTS_WATER;
     66 	/*
     67 	if (!Q_strncasecmp (name, "origin",6))
     68 		return CONTENTS_ORIGIN;
     69 	if (!Q_strncasecmp (name, "clip",4))
     70 		return CONTENTS_CLIP;
     71 	if( !Q_strncasecmp( name, "translucent", 11 ) )
     72 		return CONTENTS_TRANSLUCENT;
     73 	if( name[0] == '@' )
     74 		return CONTENTS_TRANSLUCENT;
     75 	//*/
     76 
     77 	return CONTENTS_SOLID;
     78 } //end of the function HL_TextureContents
     79 //===========================================================================
     80 // Generates two new brushes, leaving the original
     81 // unchanged
     82 //
     83 // modified for Half-Life because there are quite a lot of tiny node leaves
     84 // in the Half-Life bsps
     85 //
     86 // Parameter:				-
     87 // Returns:					-
     88 // Changes Globals:		-
     89 //===========================================================================
     90 void HL_SplitBrush(bspbrush_t *brush, int planenum, int nodenum,
     91 						 bspbrush_t **front, bspbrush_t **back)
     92 {
     93 	bspbrush_t *b[2];
     94 	int i, j;
     95 	winding_t *w, *cw[2], *midwinding;
     96 	plane_t *plane, *plane2;
     97 	side_t *s, *cs;
     98 	float d, d_front, d_back;
     99 
    100 	*front = *back = NULL;
    101 	plane = &mapplanes[planenum];
    102 
    103 	// check all points
    104 	d_front = d_back = 0;
    105 	for (i=0 ; i<brush->numsides ; i++)
    106 	{
    107 		w = brush->sides[i].winding;
    108 		if (!w)
    109 			continue;
    110 		for (j=0 ; j<w->numpoints ; j++)
    111 		{
    112 			d = DotProduct (w->p[j], plane->normal) - plane->dist;
    113 			if (d > 0 && d > d_front)
    114 				d_front = d;
    115 			if (d < 0 && d < d_back)
    116 				d_back = d;
    117 		} //end for
    118 	} //end for
    119 
    120 	if (d_front < 0.1) // PLANESIDE_EPSILON)
    121 	{	// only on back
    122 		*back = CopyBrush (brush);
    123 		Log_Print("HL_SplitBrush: only on back\n");
    124 		return;
    125 	} //end if
    126 	if (d_back > -0.1) // PLANESIDE_EPSILON)
    127 	{	// only on front
    128 		*front = CopyBrush (brush);
    129 		Log_Print("HL_SplitBrush: only on front\n");
    130 		return;
    131 	} //end if
    132 
    133 	// create a new winding from the split plane
    134 
    135 	w = BaseWindingForPlane (plane->normal, plane->dist);
    136 	for (i = 0; i < brush->numsides && w; i++)
    137 	{
    138 		plane2 = &mapplanes[brush->sides[i].planenum ^ 1];
    139 		ChopWindingInPlace(&w, plane2->normal, plane2->dist, 0); // PLANESIDE_EPSILON);
    140 	} //end for
    141 
    142 	if (!w || WindingIsTiny(w))
    143 	{	// the brush isn't really split
    144 		int		side;
    145 
    146 		Log_Print("HL_SplitBrush: no split winding\n");
    147 		side = BrushMostlyOnSide (brush, plane);
    148 		if (side == PSIDE_FRONT)
    149 			*front = CopyBrush (brush);
    150 		if (side == PSIDE_BACK)
    151 			*back = CopyBrush (brush);
    152 		return;
    153 	}
    154 
    155 	if (WindingIsHuge(w))
    156 	{
    157 		Log_Print("HL_SplitBrush: WARNING huge split winding\n");
    158 	} //end of
    159 
    160 	midwinding = w;
    161 
    162 	// split it for real
    163 
    164 	for (i = 0; i < 2; i++)
    165 	{
    166 		b[i] = AllocBrush (brush->numsides+1);
    167 		b[i]->original = brush->original;
    168 	} //end for
    169 
    170 	// split all the current windings
    171 
    172 	for (i=0 ; i<brush->numsides ; i++)
    173 	{
    174 		s = &brush->sides[i];
    175 		w = s->winding;
    176 		if (!w)
    177 			continue;
    178 		ClipWindingEpsilon (w, plane->normal, plane->dist,
    179 			0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]);
    180 		for (j=0 ; j<2 ; j++)
    181 		{
    182 			if (!cw[j])
    183 				continue;
    184 #if 0
    185 			if (WindingIsTiny (cw[j]))
    186 			{
    187 				FreeWinding (cw[j]);
    188 				continue;
    189 			}
    190 #endif
    191 			cs = &b[j]->sides[b[j]->numsides];
    192 			b[j]->numsides++;
    193 			*cs = *s;
    194 //			cs->planenum = s->planenum;
    195 //			cs->texinfo = s->texinfo;
    196 //			cs->visible = s->visible;
    197 //			cs->original = s->original;
    198 			cs->winding = cw[j];
    199 			cs->flags &= ~SFL_TESTED;
    200 		} //end for
    201 	} //end for
    202 
    203 
    204 	// see if we have valid polygons on both sides
    205 
    206 	for (i=0 ; i<2 ; i++)
    207 	{
    208 		BoundBrush (b[i]);
    209 		for (j=0 ; j<3 ; j++)
    210 		{
    211 			if (b[i]->mins[j] < -4096 || b[i]->maxs[j] > 4096)
    212 			{
    213 				Log_Print("HL_SplitBrush: bogus brush after clip\n");
    214 				break;
    215 			} //end if
    216 		} //end for
    217 
    218 		if (b[i]->numsides < 3 || j < 3)
    219 		{
    220 			FreeBrush (b[i]);
    221 			b[i] = NULL;
    222 			Log_Print("HL_SplitBrush: numsides < 3\n");
    223 		} //end if
    224 	} //end for
    225 
    226 	if ( !(b[0] && b[1]) )
    227 	{
    228 		if (!b[0] && !b[1])
    229 			Log_Print("HL_SplitBrush: split removed brush\n");
    230 		else
    231 			Log_Print("HL_SplitBrush: split not on both sides\n");
    232 		if (b[0])
    233 		{
    234 			FreeBrush (b[0]);
    235 			*front = CopyBrush (brush);
    236 		} //end if
    237 		if (b[1])
    238 		{
    239 			FreeBrush (b[1]);
    240 			*back = CopyBrush (brush);
    241 		} //end if
    242 		return;
    243 	} //end if
    244 
    245 	// add the midwinding to both sides
    246 	for (i = 0; i < 2; i++)
    247 	{
    248 		cs = &b[i]->sides[b[i]->numsides];
    249 		b[i]->numsides++;
    250 
    251 		cs->planenum = planenum^i^1;
    252 		cs->texinfo = 0;
    253 		//store the node number in the surf to find the texinfo later on
    254 		cs->surf = nodenum;
    255 		//
    256 		cs->flags &= ~SFL_VISIBLE;
    257 		cs->flags &= ~SFL_TESTED;
    258 		if (i==0)
    259 			cs->winding = CopyWinding (midwinding);
    260 		else
    261 			cs->winding = midwinding;
    262 	} //end for
    263 
    264 
    265 {
    266 	vec_t v1;
    267 	int i;
    268 
    269 	for (i=0 ; i<2 ; i++)
    270 	{
    271 		v1 = BrushVolume (b[i]);
    272 		if (v1 < 1)
    273 		{
    274 			FreeBrush (b[i]);
    275 			b[i] = NULL;
    276 			Log_Print("HL_SplitBrush: tiny volume after clip\n");
    277 		} //end if
    278 	} //end for
    279 } //*/
    280 
    281 	*front = b[0];
    282 	*back = b[1];
    283 } //end of the function HL_SplitBrush
    284 //===========================================================================
    285 // returns true if the tree starting at nodenum has only solid leaves
    286 //
    287 // Parameter:				-
    288 // Returns:					-
    289 // Changes Globals:		-
    290 //===========================================================================
    291 int HL_SolidTree_r(int nodenum)
    292 {
    293 	if (nodenum < 0)
    294 	{
    295 		switch(hl_dleafs[(-nodenum) - 1].contents)
    296 		{
    297 			case HL_CONTENTS_EMPTY:
    298 			{
    299 				return false;
    300 			} //end case
    301 			case HL_CONTENTS_SOLID:
    302 #ifdef HLCONTENTS
    303 			case HL_CONTENTS_CLIP:
    304 #endif //HLCONTENTS
    305 			case HL_CONTENTS_SKY:
    306 #ifdef HLCONTENTS
    307 			case HL_CONTENTS_TRANSLUCENT:
    308 #endif //HLCONTENTS
    309 			{
    310 				return true;
    311 			} //end case
    312 			case HL_CONTENTS_WATER:
    313 			case HL_CONTENTS_SLIME:
    314 			case HL_CONTENTS_LAVA:
    315 #ifdef HLCONTENTS
    316 			//these contents should not be found in the BSP
    317 			case HL_CONTENTS_ORIGIN:
    318 			case HL_CONTENTS_CURRENT_0:
    319 			case HL_CONTENTS_CURRENT_90:
    320 			case HL_CONTENTS_CURRENT_180:
    321 			case HL_CONTENTS_CURRENT_270:
    322 			case HL_CONTENTS_CURRENT_UP:
    323 			case HL_CONTENTS_CURRENT_DOWN:
    324 #endif //HLCONTENTS
    325 			default:
    326 			{
    327 				return false;
    328 			} //end default
    329 		} //end switch
    330 		return false;
    331 	} //end if
    332 	if (!HL_SolidTree_r(hl_dnodes[nodenum].children[0])) return false;
    333 	if (!HL_SolidTree_r(hl_dnodes[nodenum].children[1])) return false;
    334 	return true;
    335 } //end of the function HL_SolidTree_r
    336 //===========================================================================
    337 //
    338 // Parameter:				-
    339 // Returns:					-
    340 // Changes Globals:		-
    341 //===========================================================================
    342 bspbrush_t *HL_CreateBrushes_r(bspbrush_t *brush, int nodenum)
    343 {
    344 	int planenum;
    345 	bspbrush_t *front, *back;
    346 	hl_dleaf_t *leaf;
    347 
    348 	//if it is a leaf
    349 	if (nodenum < 0)
    350 	{
    351 		leaf = &hl_dleafs[(-nodenum) - 1];
    352 		if (leaf->contents != HL_CONTENTS_EMPTY)
    353 		{
    354 #ifdef HL_PRINT
    355 			qprintf("\r%5i", ++hl_numbrushes);
    356 #endif //HL_PRINT
    357 		} //end if
    358 		switch(leaf->contents)
    359 		{
    360 			case HL_CONTENTS_EMPTY:
    361 			{
    362 				FreeBrush(brush);
    363 				return NULL;
    364 			} //end case
    365 			case HL_CONTENTS_SOLID:
    366 #ifdef HLCONTENTS
    367 			case HL_CONTENTS_CLIP:
    368 #endif //HLCONTENTS
    369 			case HL_CONTENTS_SKY:
    370 #ifdef HLCONTENTS
    371 			case HL_CONTENTS_TRANSLUCENT:
    372 #endif //HLCONTENTS
    373 			{
    374 				brush->side = CONTENTS_SOLID;
    375 				return brush;
    376 			} //end case
    377 			case HL_CONTENTS_WATER:
    378 			{
    379 				brush->side = CONTENTS_WATER;
    380 				return brush;
    381 			} //end case
    382 			case HL_CONTENTS_SLIME:
    383 			{
    384 				brush->side = CONTENTS_SLIME;
    385 				return brush;
    386 			} //end case
    387 			case HL_CONTENTS_LAVA:
    388 			{
    389 				brush->side = CONTENTS_LAVA;
    390 				return brush;
    391 			} //end case
    392 #ifdef HLCONTENTS
    393 			//these contents should not be found in the BSP
    394 			case HL_CONTENTS_ORIGIN:
    395 			case HL_CONTENTS_CURRENT_0:
    396 			case HL_CONTENTS_CURRENT_90:
    397 			case HL_CONTENTS_CURRENT_180:
    398 			case HL_CONTENTS_CURRENT_270:
    399 			case HL_CONTENTS_CURRENT_UP:
    400 			case HL_CONTENTS_CURRENT_DOWN:
    401 			{
    402 				Error("HL_CreateBrushes_r: found contents %d in Half-Life BSP", leaf->contents);
    403 				return NULL;
    404 			} //end case
    405 #endif //HLCONTENTS
    406 			default:
    407 			{
    408 				Error("HL_CreateBrushes_r: unknown contents %d in Half-Life BSP", leaf->contents);
    409 				return NULL;
    410 			} //end default
    411 		} //end switch
    412 		return NULL;
    413 	} //end if
    414 	//if the rest of the tree is solid
    415 	/*if (HL_SolidTree_r(nodenum))
    416 	{
    417 		brush->side = CONTENTS_SOLID;
    418 		return brush;
    419 	} //end if*/
    420 	//
    421 	planenum = hl_dnodes[nodenum].planenum;
    422 	planenum = FindFloatPlane(hl_dplanes[planenum].normal, hl_dplanes[planenum].dist);
    423 	//split the brush with the node plane
    424 	HL_SplitBrush(brush, planenum, nodenum, &front, &back);
    425 	//free the original brush
    426 	FreeBrush(brush);
    427 	//every node must split the brush in two
    428 	if (!front || !back)
    429 	{
    430 		Log_Print("HL_CreateBrushes_r: WARNING node not splitting brush\n");
    431 		//return NULL;
    432 	} //end if
    433 	//create brushes recursively
    434 	if (front) front = HL_CreateBrushes_r(front, hl_dnodes[nodenum].children[0]);
    435 	if (back) back = HL_CreateBrushes_r(back, hl_dnodes[nodenum].children[1]);
    436 	//link the brushes if possible and return them
    437 	if (front)
    438 	{
    439 		for (brush = front; brush->next; brush = brush->next);
    440 		brush->next = back;
    441 		return front;
    442 	} //end if
    443 	else
    444 	{
    445 		return back;
    446 	} //end else
    447 } //end of the function HL_CreateBrushes_r
    448 //===========================================================================
    449 //
    450 // Parameter:				-
    451 // Returns:					-
    452 // Changes Globals:		-
    453 //===========================================================================
    454 bspbrush_t *HL_CreateBrushesFromBSP(int modelnum)
    455 {
    456 	bspbrush_t *brushlist;
    457 	bspbrush_t *brush;
    458 	hl_dnode_t *headnode;
    459 	vec3_t mins, maxs;
    460 	int i;
    461 
    462 	//
    463 	headnode = &hl_dnodes[hl_dmodels[modelnum].headnode[0]];
    464 	//get the mins and maxs of the world
    465 	VectorCopy(headnode->mins, mins);
    466 	VectorCopy(headnode->maxs, maxs);
    467 	//enlarge these mins and maxs
    468 	for (i = 0; i < 3; i++)
    469 	{
    470 		mins[i] -= 8;
    471 		maxs[i] += 8;
    472 	} //end for
    473 	//NOTE: have to add the BSP tree mins and maxs to the MAP mins and maxs
    474 	AddPointToBounds(mins, map_mins, map_maxs);
    475 	AddPointToBounds(maxs, map_mins, map_maxs);
    476 	//
    477 	if (!modelnum)
    478 	{
    479 		Log_Print("brush size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n",
    480 							map_mins[0], map_mins[1], map_mins[2],
    481 							map_maxs[0], map_maxs[1], map_maxs[2]);
    482 	} //end if
    483 	//create one huge brush containing the whole world
    484 	brush = BrushFromBounds(mins, maxs);
    485 	VectorCopy(mins, brush->mins);
    486 	VectorCopy(maxs, brush->maxs);
    487 	//
    488 #ifdef HL_PRINT
    489 	qprintf("creating Half-Life brushes\n");
    490 	qprintf("%5d brushes", hl_numbrushes = 0);
    491 #endif //HL_PRINT
    492 	//create the brushes
    493 	brushlist = HL_CreateBrushes_r(brush, hl_dmodels[modelnum].headnode[0]);
    494 	//
    495 #ifdef HL_PRINT
    496 	qprintf("\n");
    497 #endif //HL_PRINT
    498 	//now we've got a list with brushes!
    499 	return brushlist;
    500 } //end of the function HL_CreateBrushesFromBSP
    501 //===========================================================================
    502 //
    503 // Parameter:				-
    504 // Returns:					-
    505 // Changes Globals:		-
    506 //===========================================================================
    507 bspbrush_t *HL_MergeBrushes(bspbrush_t *brushlist, int modelnum)
    508 {
    509 	int nummerges, merged;
    510 	bspbrush_t *b1, *b2, *tail, *newbrush, *newbrushlist;
    511 	bspbrush_t *lastb2;
    512 
    513 	if (!brushlist) return NULL;
    514 
    515 	if (!modelnum) qprintf("%5d brushes merged", nummerges = 0);
    516 	do
    517 	{
    518 		for (tail = brushlist; tail; tail = tail->next)
    519 		{
    520 			if (!tail->next) break;
    521 		} //end for
    522 		merged = 0;
    523 		newbrushlist = NULL;
    524 		for (b1 = brushlist; b1; b1 = brushlist)
    525 		{
    526 			lastb2 = b1;
    527 			for (b2 = b1->next; b2; b2 = b2->next)
    528 			{
    529 				//can't merge brushes with different contents
    530 				if (b1->side != b2->side) newbrush = NULL;
    531 				else newbrush = TryMergeBrushes(b1, b2);
    532 				//if a merged brush is created
    533 				if (newbrush)
    534 				{
    535 					//copy the brush contents
    536 					newbrush->side = b1->side;
    537 					//add the new brush to the end of the list
    538 					tail->next = newbrush;
    539 					//remove the second brush from the list
    540 					lastb2->next = b2->next;
    541 					//remove the first brush from the list
    542 					brushlist = brushlist->next;
    543 					//free the merged brushes
    544 					FreeBrush(b1);
    545 					FreeBrush(b2);
    546 					//get a new tail brush
    547 					for (tail = brushlist; tail; tail = tail->next)
    548 					{
    549 						if (!tail->next) break;
    550 					} //end for
    551 					merged++;
    552 					if (!modelnum) qprintf("\r%5d", nummerges++);
    553 					break;
    554 				} //end if
    555 				lastb2 = b2;
    556 			} //end for
    557 			//if b1 can't be merged with any of the other brushes
    558 			if (!b2)
    559 			{
    560 				brushlist = brushlist->next;
    561 				//keep b1
    562 				b1->next = newbrushlist;
    563 				newbrushlist = b1;
    564 			} //end else
    565 		} //end for
    566 		brushlist = newbrushlist;
    567 	} while(merged);
    568 	if (!modelnum) qprintf("\n");
    569 	return newbrushlist;
    570 } //end of the function HL_MergeBrushes
    571 //===========================================================================
    572 // returns the amount the face and the winding have overlap
    573 //
    574 // Parameter:				-
    575 // Returns:					-
    576 // Changes Globals:		-
    577 //===========================================================================
    578 float HL_FaceOnWinding(hl_dface_t *face, winding_t *winding)
    579 {
    580 	int i, edgenum, side;
    581 	float dist, area;
    582 	hl_dplane_t plane;
    583 	vec_t *v1, *v2;
    584 	vec3_t normal, edgevec;
    585 	winding_t *w;
    586 
    587 	//
    588 	w = CopyWinding(winding);
    589 	memcpy(&plane, &hl_dplanes[face->planenum], sizeof(hl_dplane_t));
    590 	//check on which side of the plane the face is
    591 	if (face->side)
    592 	{
    593 		VectorNegate(plane.normal, plane.normal);
    594 		plane.dist = -plane.dist;
    595 	} //end if
    596 	for (i = 0; i < face->numedges && w; i++)
    597 	{
    598 		//get the first and second vertex of the edge
    599 		edgenum = hl_dsurfedges[face->firstedge + i];
    600 		side = edgenum > 0;
    601 		//if the face plane is flipped
    602 		v1 = hl_dvertexes[hl_dedges[abs(edgenum)].v[side]].point;
    603 		v2 = hl_dvertexes[hl_dedges[abs(edgenum)].v[!side]].point;
    604 		//create a plane through the edge vector, orthogonal to the face plane
    605 		//and with the normal vector pointing out of the face
    606 		VectorSubtract(v1, v2, edgevec);
    607 		CrossProduct(edgevec, plane.normal, normal);
    608 		VectorNormalize(normal);
    609 		dist = DotProduct(normal, v1);
    610 		//
    611 		ChopWindingInPlace(&w, normal, dist, 0.9); //CLIP_EPSILON
    612 	} //end for
    613 	if (w)
    614 	{
    615 		area = WindingArea(w);
    616 		FreeWinding(w);
    617 		return area;
    618 	} //end if
    619 	return 0;
    620 } //end of the function HL_FaceOnWinding
    621 //===========================================================================
    622 // returns a list with brushes created by splitting the given brush with
    623 // planes that go through the face edges and are orthogonal to the face plane
    624 //
    625 // Parameter:				-
    626 // Returns:					-
    627 // Changes Globals:		-
    628 //===========================================================================
    629 bspbrush_t *HL_SplitBrushWithFace(bspbrush_t *brush, hl_dface_t *face)
    630 {
    631 	int i, edgenum, side, planenum, splits;
    632 	float dist;
    633 	hl_dplane_t plane;
    634 	vec_t *v1, *v2;
    635 	vec3_t normal, edgevec;
    636 	bspbrush_t *front, *back, *brushlist;
    637 
    638 	memcpy(&plane, &hl_dplanes[face->planenum], sizeof(hl_dplane_t));
    639 	//check on which side of the plane the face is
    640 	if (face->side)
    641 	{
    642 		VectorNegate(plane.normal, plane.normal);
    643 		plane.dist = -plane.dist;
    644 	} //end if
    645 	splits = 0;
    646 	brushlist = NULL;
    647 	for (i = 0; i < face->numedges; i++)
    648 	{
    649 		//get the first and second vertex of the edge
    650 		edgenum = hl_dsurfedges[face->firstedge + i];
    651 		side = edgenum > 0;
    652 		//if the face plane is flipped
    653 		v1 = hl_dvertexes[hl_dedges[abs(edgenum)].v[side]].point;
    654 		v2 = hl_dvertexes[hl_dedges[abs(edgenum)].v[!side]].point;
    655 		//create a plane through the edge vector, orthogonal to the face plane
    656 		//and with the normal vector pointing out of the face
    657 		VectorSubtract(v1, v2, edgevec);
    658 		CrossProduct(edgevec, plane.normal, normal);
    659 		VectorNormalize(normal);
    660 		dist = DotProduct(normal, v1);
    661 		//
    662 		planenum = FindFloatPlane(normal, dist);
    663 		//split the current brush
    664 		SplitBrush(brush, planenum, &front, &back);
    665 		//if there is a back brush just put it in the list
    666 		if (back)
    667 		{
    668 			//copy the brush contents
    669 			back->side = brush->side;
    670 			//
    671 			back->next = brushlist;
    672 			brushlist = back;
    673 			splits++;
    674 		} //end if
    675 		if (!front)
    676 		{
    677 			Log_Print("HL_SplitBrushWithFace: no new brush\n");
    678 			FreeBrushList(brushlist);
    679 			return NULL;
    680 		} //end if
    681 		//copy the brush contents
    682 		front->side = brush->side;
    683 		//continue splitting the front brush
    684 		brush = front;
    685 	} //end for
    686 	if (!splits)
    687 	{
    688 		FreeBrush(front);
    689 		return NULL;
    690 	} //end if
    691 	front->next = brushlist;
    692 	brushlist = front;
    693 	return brushlist;
    694 } //end of the function HL_SplitBrushWithFace
    695 //===========================================================================
    696 //
    697 // Parameter:				-
    698 // Returns:					-
    699 // Changes Globals:		-
    700 //===========================================================================
    701 bspbrush_t *HL_TextureBrushes(bspbrush_t *brushlist, int modelnum)
    702 {
    703 	float area, largestarea;
    704 	int i, n, texinfonum, sn, numbrushes, ofs;
    705 	int bestfacenum, sidenodenum;
    706 	side_t *side;
    707 	hl_dmiptexlump_t *miptexlump;
    708 	hl_miptex_t *miptex;
    709 	bspbrush_t *brush, *nextbrush, *prevbrush, *newbrushes, *brushlistend;
    710 	vec_t defaultvec[4] = {1, 0, 0, 0};
    711 
    712 	if (!modelnum) qprintf("texturing brushes\n");
    713 	if (!modelnum) qprintf("%5d brushes", numbrushes = 0);
    714 	//get a pointer to the last brush in the list
    715 	for (brushlistend = brushlist; brushlistend; brushlistend = brushlistend->next)
    716 	{
    717 		if (!brushlistend->next) break;
    718 	} //end for
    719 	//there's no previous brush when at the start of the list
    720 	prevbrush = NULL;
    721 	//go over the brush list
    722 	for (brush = brushlist; brush; brush = nextbrush)
    723 	{
    724 		nextbrush = brush->next;
    725 		//find a texinfo for every brush side
    726 		for (sn = 0; sn < brush->numsides; sn++)
    727 		{
    728 			side = &brush->sides[sn];
    729 			//
    730 			if (side->flags & SFL_TEXTURED) continue;
    731 			//number of the node that created this brush side
    732 			sidenodenum = side->surf;	//see midwinding in HL_SplitBrush
    733 			//no face found yet
    734 			bestfacenum = -1;
    735 			//minimum face size
    736 			largestarea = 1;
    737 			//if optimizing the texture placement and not going for the
    738 			//least number of brushes
    739 			if (!lessbrushes)
    740 			{
    741 				for (i = 0; i < hl_numfaces; i++)
    742 				{
    743 					//the face must be in the same plane as the node plane that created
    744 					//this brush side
    745 					if (hl_dfaces[i].planenum == hl_dnodes[sidenodenum].planenum)
    746 					{
    747 						//get the area the face and the brush side overlap
    748 						area = HL_FaceOnWinding(&hl_dfaces[i], side->winding);
    749 						//if this face overlaps the brush side winding more than previous faces
    750 						if (area > largestarea)
    751 						{
    752 							//if there already was a face for texturing this brush side with
    753 							//a different texture
    754 							if (bestfacenum >= 0 &&
    755 									(hl_dfaces[bestfacenum].texinfo != hl_dfaces[i].texinfo))
    756 							{
    757 								//split the brush to fit the texture
    758 								newbrushes = HL_SplitBrushWithFace(brush, &hl_dfaces[i]);
    759 								//if new brushes where created
    760 								if (newbrushes)
    761 								{
    762 									//remove the current brush from the list
    763 									if (prevbrush) prevbrush->next = brush->next;
    764 									else brushlist = brush->next;
    765 									if (brushlistend == brush)
    766 									{
    767 										brushlistend = prevbrush;
    768 										nextbrush = newbrushes;
    769 									} //end if
    770 									//add the new brushes to the end of the list
    771 									if (brushlistend) brushlistend->next = newbrushes;
    772 									else brushlist = newbrushes;
    773 									//free the current brush
    774 									FreeBrush(brush);
    775 									//don't forget about the prevbrush pointer at the bottom of
    776 									//the outer loop
    777 									brush = prevbrush;
    778 									//find the end of the list
    779 									for (brushlistend = brushlist; brushlistend; brushlistend = brushlistend->next)
    780 									{
    781 										if (!brushlistend->next) break;
    782 									} //end for
    783 									break;
    784 								} //end if
    785 								else
    786 								{
    787 									Log_Write("brush %d: no real texture split", numbrushes);
    788 								} //end else
    789 							} //end if
    790 							else
    791 							{
    792 								//best face for texturing this brush side
    793 								bestfacenum = i;
    794 							} //end else
    795 						} //end if
    796 					} //end if
    797 				} //end for
    798 				//if the brush was split the original brush is removed
    799 				//and we just continue with the next one in the list
    800 				if (i < hl_numfaces) break;
    801 			} //end if
    802 			else
    803 			{
    804 				//find the face with the largest overlap with this brush side
    805 				//for texturing the brush side
    806 				for (i = 0; i < hl_numfaces; i++)
    807 				{
    808 					//the face must be in the same plane as the node plane that created
    809 					//this brush side
    810 					if (hl_dfaces[i].planenum == hl_dnodes[sidenodenum].planenum)
    811 					{
    812 						//get the area the face and the brush side overlap
    813 						area = HL_FaceOnWinding(&hl_dfaces[i], side->winding);
    814 						//if this face overlaps the brush side winding more than previous faces
    815 						if (area > largestarea)
    816 						{
    817 							largestarea = area;
    818 							bestfacenum = i;
    819 						} //end if
    820 					} //end if
    821 				} //end for
    822 			} //end else
    823 			//if a face was found for texturing this brush side
    824 			if (bestfacenum >= 0)
    825 			{
    826 				//set the MAP texinfo values
    827 				texinfonum = hl_dfaces[bestfacenum].texinfo;
    828 				for (n = 0; n < 4; n++)
    829 				{
    830 					map_texinfo[texinfonum].vecs[0][n] = hl_texinfo[texinfonum].vecs[0][n];
    831 					map_texinfo[texinfonum].vecs[1][n] = hl_texinfo[texinfonum].vecs[1][n];
    832 				} //end for
    833 				//make sure the two vectors aren't of zero length otherwise use the default
    834 				//vector to prevent a divide by zero in the map writing
    835 				if (VectorLength(map_texinfo[texinfonum].vecs[0]) < 0.01)
    836 					memcpy(map_texinfo[texinfonum].vecs[0], defaultvec, sizeof(defaultvec));
    837 				if (VectorLength(map_texinfo[texinfonum].vecs[1]) < 0.01)
    838 					memcpy(map_texinfo[texinfonum].vecs[1], defaultvec, sizeof(defaultvec));
    839 				//
    840 				map_texinfo[texinfonum].flags = hl_texinfo[texinfonum].flags;
    841 				map_texinfo[texinfonum].value = 0; //HL_ and HL texinfos don't have a value
    842 				//the mip texture
    843 				miptexlump = (hl_dmiptexlump_t *) hl_dtexdata;
    844 				ofs = miptexlump->dataofs[hl_texinfo[texinfonum].miptex];
    845 				if ( ofs > hl_texdatasize ) {
    846 					ofs = miptexlump->dataofs[0];
    847 				}
    848 				miptex = (hl_miptex_t *)((byte *)miptexlump + ofs );
    849 				//get the mip texture name
    850 				strcpy(map_texinfo[texinfonum].texture, miptex->name);
    851 				//no animations in Quake1 and Half-Life mip textures
    852 				map_texinfo[texinfonum].nexttexinfo = -1;
    853 				//store the texinfo number
    854 				side->texinfo = texinfonum;
    855 				//
    856 				if (texinfonum > map_numtexinfo) map_numtexinfo = texinfonum;
    857 				//this side is textured
    858 				side->flags |= SFL_TEXTURED;
    859 			} //end if
    860 			else
    861 			{
    862 				//no texture for this side
    863 				side->texinfo = TEXINFO_NODE;
    864 				//this side is textured
    865 				side->flags |= SFL_TEXTURED;
    866 			} //end if
    867 		} //end for
    868 		//
    869 		if (!modelnum && prevbrush != brush) qprintf("\r%5d", ++numbrushes);
    870 		//previous brush in the list
    871 		prevbrush = brush;
    872 	} //end for
    873 	if (!modelnum) qprintf("\n");
    874 	//return the new list with brushes
    875 	return brushlist;
    876 } //end of the function HL_TextureBrushes
    877 //===========================================================================
    878 //
    879 // Parameter:				-
    880 // Returns:					-
    881 // Changes Globals:		-
    882 //===========================================================================
    883 void HL_FixContentsTextures(bspbrush_t *brushlist)
    884 {
    885 	int i, texinfonum;
    886 	bspbrush_t *brush;
    887 
    888 	for (brush = brushlist; brush; brush = brush->next)
    889 	{
    890 		//only fix the textures of water, slime and lava brushes
    891 		if (brush->side != CONTENTS_WATER &&
    892 			brush->side != CONTENTS_SLIME &&
    893 			brush->side != CONTENTS_LAVA) continue;
    894 		//
    895 		for (i = 0; i < brush->numsides; i++)
    896 		{
    897 			texinfonum = brush->sides[i].texinfo;
    898 			if (HL_TextureContents(map_texinfo[texinfonum].texture) == brush->side) break;
    899 		} //end for
    900 		//if no specific contents texture was found
    901 		if (i >= brush->numsides)
    902 		{
    903 			texinfonum = -1;
    904 			for (i = 0; i < map_numtexinfo; i++)
    905 			{
    906 				if (HL_TextureContents(map_texinfo[i].texture) == brush->side)
    907 				{
    908 					texinfonum = i;
    909 					break;
    910 				} //end if
    911 			} //end for
    912 		} //end if
    913 		//
    914 		if (texinfonum >= 0)
    915 		{
    916 			//give all the brush sides this contents texture
    917 			for (i = 0; i < brush->numsides; i++)
    918 			{
    919 				brush->sides[i].texinfo = texinfonum;
    920 			} //end for
    921 		} //end if
    922 		else Log_Print("brush contents %d with wrong textures\n", brush->side);
    923 		//
    924 	} //end for
    925 	/*
    926 	for (brush = brushlist; brush; brush = brush->next)
    927 	{
    928 		//give all the brush sides this contents texture
    929 		for (i = 0; i < brush->numsides; i++)
    930 		{
    931 			if (HL_TextureContents(map_texinfo[texinfonum].texture) != brush->side)
    932 			{
    933 				Error("brush contents %d with wrong contents textures %s\n", brush->side,
    934 							HL_TextureContents(map_texinfo[texinfonum].texture));
    935 			} //end if
    936 		} //end for
    937 	} //end for*/
    938 } //end of the function HL_FixContentsTextures
    939 //===========================================================================
    940 //
    941 // Parameter:				-
    942 // Returns:					-
    943 // Changes Globals:		-
    944 //===========================================================================
    945 void HL_BSPBrushToMapBrush(bspbrush_t *bspbrush, entity_t *mapent)
    946 {
    947 	mapbrush_t *mapbrush;
    948 	side_t *side;
    949 	int i, besttexinfo;
    950 
    951 	if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
    952 	Error ("nummapbrushes == MAX_MAPFILE_BRUSHES");
    953 
    954 	mapbrush = &mapbrushes[nummapbrushes];
    955 	mapbrush->original_sides = &brushsides[nummapbrushsides];
    956 	mapbrush->entitynum = mapent - entities;
    957 	mapbrush->brushnum = nummapbrushes - mapent->firstbrush;
    958 	mapbrush->leafnum = -1;
    959 	mapbrush->numsides = 0;
    960 
    961 	besttexinfo = TEXINFO_NODE;
    962 	for (i = 0; i < bspbrush->numsides; i++)
    963 	{
    964 		if (!bspbrush->sides[i].winding) continue;
    965 		//
    966 		if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
    967 			Error ("MAX_MAPFILE_BRUSHSIDES");
    968 		side = &brushsides[nummapbrushsides];
    969 		//the contents of the bsp brush is stored in the side variable
    970 		side->contents = bspbrush->side;
    971 		side->surf = 0;
    972 		side->planenum = bspbrush->sides[i].planenum;
    973 		side->texinfo = bspbrush->sides[i].texinfo;
    974 		if (side->texinfo != TEXINFO_NODE)
    975 		{
    976 			//this brush side is textured
    977 			side->flags |= SFL_TEXTURED;
    978 			besttexinfo = side->texinfo;
    979 		} //end if
    980 		//
    981 		nummapbrushsides++;
    982 		mapbrush->numsides++;
    983 	} //end for
    984 	//
    985 	if (besttexinfo == TEXINFO_NODE)
    986 	{
    987 		mapbrush->numsides = 0;
    988 		hl_numclipbrushes++;
    989 		return;
    990 	} //end if
    991 	//set the texinfo for all the brush sides without texture
    992 	for (i = 0; i < mapbrush->numsides; i++)
    993 	{
    994 		if (mapbrush->original_sides[i].texinfo == TEXINFO_NODE)
    995 		{
    996 			mapbrush->original_sides[i].texinfo = besttexinfo;
    997 		} //end if
    998 	} //end for
    999 	//contents of the brush
   1000 	mapbrush->contents = bspbrush->side;
   1001 	//
   1002 	if (create_aas)
   1003 	{
   1004 		//create the AAS brushes from this brush, add brush bevels
   1005 		AAS_CreateMapBrushes(mapbrush, mapent, true);
   1006 		return;
   1007 	} //end if
   1008 	//create windings for sides and bounds for brush
   1009 	MakeBrushWindings(mapbrush);
   1010 	//add brush bevels
   1011 	AddBrushBevels(mapbrush);
   1012 	//a new brush has been created
   1013 	nummapbrushes++;
   1014 	mapent->numbrushes++;
   1015 } //end of the function HL_BSPBrushToMapBrush
   1016 //===========================================================================
   1017 //
   1018 // Parameter:				-
   1019 // Returns:					-
   1020 // Changes Globals:		-
   1021 //===========================================================================
   1022 void HL_CreateMapBrushes(entity_t *mapent, int modelnum)
   1023 {
   1024 	bspbrush_t *brushlist, *brush, *nextbrush;
   1025 	int i;
   1026 
   1027 	//create brushes from the model BSP tree
   1028 	brushlist = HL_CreateBrushesFromBSP(modelnum);
   1029 	//texture the brushes and split them when necesary
   1030 	brushlist = HL_TextureBrushes(brushlist, modelnum);
   1031 	//fix the contents textures of all brushes
   1032 	HL_FixContentsTextures(brushlist);
   1033 	//
   1034 	if (!nobrushmerge)
   1035 	{
   1036 		brushlist = HL_MergeBrushes(brushlist, modelnum);
   1037 		//brushlist = HL_MergeBrushes(brushlist, modelnum);
   1038 	} //end if
   1039 	//
   1040 	if (!modelnum) qprintf("converting brushes to map brushes\n");
   1041 	if (!modelnum) qprintf("%5d brushes", i = 0);
   1042 	for (brush = brushlist; brush; brush = nextbrush)
   1043 	{
   1044 		nextbrush = brush->next;
   1045 		HL_BSPBrushToMapBrush(brush, mapent);
   1046 		brush->next = NULL;
   1047 		FreeBrush(brush);
   1048 		if (!modelnum) qprintf("\r%5d", ++i);
   1049 	} //end for
   1050 	if (!modelnum) qprintf("\n");
   1051 } //end of the function HL_CreateMapBrushes
   1052 //===========================================================================
   1053 //
   1054 // Parameter:				-
   1055 // Returns:					-
   1056 // Changes Globals:		-
   1057 //===========================================================================
   1058 void HL_ResetMapLoading(void)
   1059 {
   1060 } //end of the function HL_ResetMapLoading
   1061 //===========================================================================
   1062 //
   1063 // Parameter:				-
   1064 // Returns:					-
   1065 // Changes Globals:		-
   1066 //===========================================================================
   1067 void HL_LoadMapFromBSP(char *filename, int offset, int length)
   1068 {
   1069 	int i, modelnum;
   1070 	char *model, *classname;
   1071 
   1072 	Log_Print("-- HL_LoadMapFromBSP --\n");
   1073 	//loaded map type
   1074 	loadedmaptype = MAPTYPE_HALFLIFE;
   1075 	//
   1076 	qprintf("loading map from %s at %d\n", filename, offset);
   1077 	//load the Half-Life BSP file
   1078 	HL_LoadBSPFile(filename, offset, length);
   1079 	//
   1080 	hl_numclipbrushes = 0;
   1081 	//parse the entities from the BSP
   1082 	HL_ParseEntities();
   1083 	//clear the map mins and maxs
   1084 	ClearBounds(map_mins, map_maxs);
   1085 	//
   1086 	qprintf("creating Half-Life brushes\n");
   1087 	if (lessbrushes) qprintf("creating minimum number of brushes\n");
   1088 	else qprintf("placing textures correctly\n");
   1089 	//
   1090 	for (i = 0; i < num_entities; i++)
   1091 	{
   1092 		entities[i].firstbrush = nummapbrushes;
   1093 		entities[i].numbrushes = 0;
   1094 		//
   1095 		classname = ValueForKey(&entities[i], "classname");
   1096 		if (classname && !strcmp(classname, "worldspawn"))
   1097 		{
   1098 			modelnum = 0;
   1099 		} //end if
   1100 		else
   1101 		{
   1102 			//
   1103 			model = ValueForKey(&entities[i], "model");
   1104 			if (!model || *model != '*') continue;
   1105 			model++;
   1106 			modelnum = atoi(model);
   1107 		} //end else
   1108 		//create map brushes for the entity
   1109 		HL_CreateMapBrushes(&entities[i], modelnum);
   1110 	} //end for
   1111 	//
   1112 	qprintf("%5d map brushes\n", nummapbrushes);
   1113 	qprintf("%5d clip brushes\n", hl_numclipbrushes);
   1114 } //end of the function HL_LoadMapFromBSP