Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

map_q1.c (33367B)


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