1 /* -------------------------------------------------------------------------------
2 
3    Copyright (C) 1999-2007 id Software, Inc. and contributors.
4    For a list of contributors, see the accompanying CONTRIBUTORS file.
5 
6    This file is part of GtkRadiant.
7 
8    GtkRadiant is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12 
13    GtkRadiant is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with GtkRadiant; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21 
22    ----------------------------------------------------------------------------------
23 
24    This code has been altered significantly from its original form, to support
25    several games based on the Quake III Arena engine, in the form of "Q3Map2."
26 
27    ------------------------------------------------------------------------------- */
28 
29 
30 
31 /* marker */
32 #define SURFACE_C
33 
34 
35 
36 /* dependencies */
37 #include "q3map2.h"
38 
39 
40 
41 /*
42    AllocDrawSurface()
43    ydnar: gs mods: changed to force an explicit type when allocating
44  */
45 
AllocDrawSurface(surfaceType_t type)46 mapDrawSurface_t *AllocDrawSurface( surfaceType_t type ){
47 	mapDrawSurface_t    *ds;
48 
49 
50 	/* ydnar: gs mods: only allocate valid types */
51 	if ( type <= SURFACE_BAD || type >= NUM_SURFACE_TYPES ) {
52 		Error( "AllocDrawSurface: Invalid surface type %d specified", type );
53 	}
54 
55 	/* bounds check */
56 	if ( numMapDrawSurfs >= MAX_MAP_DRAW_SURFS ) {
57 		Error( "MAX_MAP_DRAW_SURFS (%d) exceeded", MAX_MAP_DRAW_SURFS );
58 	}
59 	ds = &mapDrawSurfs[ numMapDrawSurfs ];
60 	numMapDrawSurfs++;
61 
62 	/* ydnar: do initial surface setup */
63 	memset( ds, 0, sizeof( mapDrawSurface_t ) );
64 	ds->type = type;
65 	ds->planeNum = -1;
66 	ds->fogNum = defaultFogNum;             /* ydnar 2003-02-12 */
67 	ds->outputNum = -1;                     /* ydnar 2002-08-13 */
68 	ds->surfaceNum = numMapDrawSurfs - 1;   /* ydnar 2003-02-16 */
69 
70 	return ds;
71 }
72 
73 
74 
75 /*
76    FinishSurface()
77    ydnar: general surface finish pass
78  */
79 
FinishSurface(mapDrawSurface_t * ds)80 void FinishSurface( mapDrawSurface_t *ds ){
81 	mapDrawSurface_t    *ds2;
82 
83 
84 	/* dummy check */
85 	if ( ds->type <= SURFACE_BAD || ds->type >= NUM_SURFACE_TYPES || ds == NULL || ds->shaderInfo == NULL ) {
86 		return;
87 	}
88 
89 	/* ydnar: rocking tek-fu celshading */
90 	if ( ds->celShader != NULL ) {
91 		MakeCelSurface( ds, ds->celShader );
92 	}
93 
94 	/* backsides stop here */
95 	if ( ds->backSide ) {
96 		return;
97 	}
98 
99 	/* ydnar: rocking surface cloning (fur baby yeah!) */
100 	if ( ds->shaderInfo->cloneShader != NULL && ds->shaderInfo->cloneShader[ 0 ] != '\0' ) {
101 		CloneSurface( ds, ShaderInfoForShader( ds->shaderInfo->cloneShader ) );
102 	}
103 
104 	/* ydnar: q3map_backShader support */
105 	if ( ds->shaderInfo->backShader != NULL && ds->shaderInfo->backShader[ 0 ] != '\0' ) {
106 		ds2 = CloneSurface( ds, ShaderInfoForShader( ds->shaderInfo->backShader ) );
107 		ds2->backSide = qtrue;
108 	}
109 }
110 
111 
112 
113 /*
114    CloneSurface()
115    clones a map drawsurface, using the specified shader
116  */
117 
CloneSurface(mapDrawSurface_t * src,shaderInfo_t * si)118 mapDrawSurface_t *CloneSurface( mapDrawSurface_t *src, shaderInfo_t *si ){
119 	mapDrawSurface_t    *ds;
120 
121 
122 	/* dummy check */
123 	if ( src == NULL || si == NULL ) {
124 		return NULL;
125 	}
126 
127 	/* allocate a new surface */
128 	ds = AllocDrawSurface( src->type );
129 	if ( ds == NULL ) {
130 		return NULL;
131 	}
132 
133 	/* copy it */
134 	memcpy( ds, src, sizeof( *ds ) );
135 
136 	/* destroy side reference */
137 	ds->sideRef = NULL;
138 
139 	/* set shader */
140 	ds->shaderInfo = si;
141 
142 	/* copy verts */
143 	if ( ds->numVerts > 0 ) {
144 		ds->verts = safe_malloc( ds->numVerts * sizeof( *ds->verts ) );
145 		memcpy( ds->verts, src->verts, ds->numVerts * sizeof( *ds->verts ) );
146 	}
147 
148 	/* copy indexes */
149 	if ( ds->numIndexes <= 0 ) {
150 		return ds;
151 	}
152 	ds->indexes = safe_malloc( ds->numIndexes * sizeof( *ds->indexes ) );
153 	memcpy( ds->indexes, src->indexes, ds->numIndexes * sizeof( *ds->indexes ) );
154 
155 	/* return the surface */
156 	return ds;
157 }
158 
159 
160 
161 /*
162    MakeCelSurface() - ydnar
163    makes a copy of a surface, but specific to cel shading
164  */
165 
MakeCelSurface(mapDrawSurface_t * src,shaderInfo_t * si)166 mapDrawSurface_t *MakeCelSurface( mapDrawSurface_t *src, shaderInfo_t *si ){
167 	mapDrawSurface_t    *ds;
168 
169 
170 	/* dummy check */
171 	if ( src == NULL || si == NULL ) {
172 		return NULL;
173 	}
174 
175 	/* don't create cel surfaces for certain types of shaders */
176 	if ( ( src->shaderInfo->compileFlags & C_TRANSLUCENT ) ||
177 		 ( src->shaderInfo->compileFlags & C_SKY ) ) {
178 		return NULL;
179 	}
180 
181 	/* make a copy */
182 	ds = CloneSurface( src, si );
183 	if ( ds == NULL ) {
184 		return NULL;
185 	}
186 
187 	/* do some fixups for celshading */
188 	ds->planar = qfalse;
189 	ds->planeNum = -1;
190 	ds->celShader = NULL; /* don't cel shade cels :P */
191 
192 	/* return the surface */
193 	return ds;
194 }
195 
196 
197 
198 /*
199    MakeSkyboxSurface() - ydnar
200    generates a skybox surface, viewable from everywhere there is sky
201  */
202 
MakeSkyboxSurface(mapDrawSurface_t * src)203 mapDrawSurface_t *MakeSkyboxSurface( mapDrawSurface_t *src ){
204 	int i;
205 	mapDrawSurface_t    *ds;
206 
207 
208 	/* dummy check */
209 	if ( src == NULL ) {
210 		return NULL;
211 	}
212 
213 	/* make a copy */
214 	ds = CloneSurface( src, src->shaderInfo );
215 	if ( ds == NULL ) {
216 		return NULL;
217 	}
218 
219 	/* set parent */
220 	ds->parent = src;
221 
222 	/* scale the surface vertexes */
223 	for ( i = 0; i < ds->numVerts; i++ )
224 	{
225 		m4x4_transform_point( skyboxTransform, ds->verts[ i ].xyz );
226 
227 		/* debug code */
228 		//%	bspDrawVerts[ bspDrawSurfaces[ ds->outputNum ].firstVert + i ].color[ 0 ][ 1 ] = 0;
229 		//%	bspDrawVerts[ bspDrawSurfaces[ ds->outputNum ].firstVert + i ].color[ 0 ][ 2 ] = 0;
230 	}
231 
232 	/* so backface culling creep doesn't bork the surface */
233 	VectorClear( ds->lightmapVecs[ 2 ] );
234 
235 	/* return the surface */
236 	return ds;
237 }
238 
239 
240 
241 /*
242    IsTriangleDegenerate
243    returns qtrue if all three points are colinear, backwards, or the triangle is just plain bogus
244  */
245 
246 #define TINY_AREA   1.0f
247 
IsTriangleDegenerate(bspDrawVert_t * points,int a,int b,int c)248 qboolean IsTriangleDegenerate( bspDrawVert_t *points, int a, int b, int c ){
249 	vec3_t v1, v2, v3;
250 	float d;
251 
252 
253 	/* calcuate the area of the triangle */
254 	VectorSubtract( points[ b ].xyz, points[ a ].xyz, v1 );
255 	VectorSubtract( points[ c ].xyz, points[ a ].xyz, v2 );
256 	CrossProduct( v1, v2, v3 );
257 	d = VectorLength( v3 );
258 
259 	/* assume all very small or backwards triangles will cause problems */
260 	if ( d < TINY_AREA ) {
261 		return qtrue;
262 	}
263 
264 	/* must be a good triangle */
265 	return qfalse;
266 }
267 
268 
269 
270 /*
271    ClearSurface() - ydnar
272    clears a surface and frees any allocated memory
273  */
274 
ClearSurface(mapDrawSurface_t * ds)275 void ClearSurface( mapDrawSurface_t *ds ){
276 	ds->type = SURFACE_BAD;
277 	ds->planar = qfalse;
278 	ds->planeNum = -1;
279 	ds->numVerts = 0;
280 	if ( ds->verts != NULL ) {
281 		free( ds->verts );
282 	}
283 	ds->verts = NULL;
284 	ds->numIndexes = 0;
285 	if ( ds->indexes != NULL ) {
286 		free( ds->indexes );
287 	}
288 	ds->indexes = NULL;
289 	numClearedSurfaces++;
290 }
291 
292 
293 
294 /*
295    TidyEntitySurfaces() - ydnar
296    deletes all empty or bad surfaces from the surface list
297  */
298 
TidyEntitySurfaces(entity_t * e)299 void TidyEntitySurfaces( entity_t *e ){
300 	int i, j, deleted;
301 	mapDrawSurface_t    *out, *in = NULL;
302 
303 
304 	/* note it */
305 	Sys_FPrintf( SYS_VRB, "--- TidyEntitySurfaces ---\n" );
306 
307 	/* walk the surface list */
308 	deleted = 0;
309 	for ( i = e->firstDrawSurf, j = e->firstDrawSurf; j < numMapDrawSurfs; i++, j++ )
310 	{
311 		/* get out surface */
312 		out = &mapDrawSurfs[ i ];
313 
314 		/* walk the surface list again until a proper surface is found */
315 		for ( ; j < numMapDrawSurfs; j++ )
316 		{
317 			/* get in surface */
318 			in = &mapDrawSurfs[ j ];
319 
320 			/* this surface ok? */
321 			if ( in->type == SURFACE_FLARE || in->type == SURFACE_SHADER ||
322 				 ( in->type != SURFACE_BAD && in->numVerts > 0 ) ) {
323 				break;
324 			}
325 
326 			/* nuke it */
327 			ClearSurface( in );
328 			deleted++;
329 		}
330 
331 		/* copy if necessary */
332 		if ( i != j ) {
333 			memcpy( out, in, sizeof( mapDrawSurface_t ) );
334 		}
335 	}
336 
337 	/* set the new number of drawsurfs */
338 	numMapDrawSurfs = i;
339 
340 	/* emit some stats */
341 	Sys_FPrintf( SYS_VRB, "%9d empty or malformed surfaces deleted\n", deleted );
342 }
343 
344 
345 
346 /*
347    CalcSurfaceTextureRange() - ydnar
348    calculates the clamped texture range for a given surface, returns qtrue if it's within [-texRange,texRange]
349  */
350 
CalcSurfaceTextureRange(mapDrawSurface_t * ds)351 qboolean CalcSurfaceTextureRange( mapDrawSurface_t *ds ){
352 	int i, j, v, size[ 2 ];
353 	float mins[ 2 ], maxs[ 2 ];
354 
355 
356 	/* try to early out */
357 	if ( ds->numVerts <= 0 ) {
358 		return qtrue;
359 	}
360 
361 	/* walk the verts and determine min/max st values */
362 	mins[ 0 ] = 999999;
363 	mins[ 1 ] = 999999;
364 	maxs[ 0 ] = -999999;
365 	maxs[ 1 ] = -999999;
366 	for ( i = 0; i < ds->numVerts; i++ )
367 	{
368 		for ( j = 0; j < 2; j++ )
369 		{
370 			if ( ds->verts[ i ].st[ j ] < mins[ j ] ) {
371 				mins[ j ] = ds->verts[ i ].st[ j ];
372 			}
373 			if ( ds->verts[ i ].st[ j ] > maxs[ j ] ) {
374 				maxs[ j ] = ds->verts[ i ].st[ j ];
375 			}
376 		}
377 	}
378 
379 	/* clamp to integer range and calculate surface bias values */
380 	for ( j = 0; j < 2; j++ )
381 		ds->bias[ j ] = -floor( 0.5f * ( mins[ j ] + maxs[ j ] ) );
382 
383 	/* find biased texture coordinate mins/maxs */
384 	size[ 0 ] = ds->shaderInfo->shaderWidth;
385 	size[ 1 ] = ds->shaderInfo->shaderHeight;
386 	ds->texMins[ 0 ] = 999999;
387 	ds->texMins[ 1 ] = 999999;
388 	ds->texMaxs[ 0 ] = -999999;
389 	ds->texMaxs[ 1 ] = -999999;
390 	for ( i = 0; i < ds->numVerts; i++ )
391 	{
392 		for ( j = 0; j < 2; j++ )
393 		{
394 			v = ( (float) ds->verts[ i ].st[ j ] + ds->bias[ j ] ) * size[ j ];
395 			if ( v < ds->texMins[ j ] ) {
396 				ds->texMins[ j ] = v;
397 			}
398 			if ( v > ds->texMaxs[ j ] ) {
399 				ds->texMaxs[ j ] = v;
400 			}
401 		}
402 	}
403 
404 	/* calc ranges */
405 	for ( j = 0; j < 2; j++ )
406 		ds->texRange[ j ] = ( ds->texMaxs[ j ] - ds->texMins[ j ] );
407 
408 	/* if range is zero, then assume unlimited precision */
409 	if ( texRange == 0 ) {
410 		return qtrue;
411 	}
412 
413 	/* within range? */
414 	for ( j = 0; j < 2; j++ )
415 	{
416 		if ( ds->texMins[ j ] < -texRange || ds->texMaxs[ j ] > texRange ) {
417 			return qfalse;
418 		}
419 	}
420 
421 	/* within range */
422 	return qtrue;
423 }
424 
425 
426 
427 /*
428    CalcLightmapAxis() - ydnar
429    gives closed lightmap axis for a plane normal
430  */
431 
CalcLightmapAxis(vec3_t normal,vec3_t axis)432 qboolean CalcLightmapAxis( vec3_t normal, vec3_t axis ){
433 	vec3_t absolute;
434 
435 
436 	/* test */
437 	if ( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f && normal[ 2 ] == 0.0f ) {
438 		VectorClear( axis );
439 		return qfalse;
440 	}
441 
442 	/* get absolute normal */
443 	absolute[ 0 ] = fabs( normal[ 0 ] );
444 	absolute[ 1 ] = fabs( normal[ 1 ] );
445 	absolute[ 2 ] = fabs( normal[ 2 ] );
446 
447 	/* test and set */
448 	if ( absolute[ 2 ] > absolute[ 0 ] - 0.0001f && absolute[ 2 ] > absolute[ 1 ] - 0.0001f ) {
449 		if ( normal[ 2 ] > 0.0f ) {
450 			VectorSet( axis, 0.0f, 0.0f, 1.0f );
451 		}
452 		else{
453 			VectorSet( axis, 0.0f, 0.0f, -1.0f );
454 		}
455 	}
456 	else if ( absolute[ 0 ] > absolute[ 1 ] - 0.0001f && absolute[ 0 ] > absolute[ 2 ] - 0.0001f ) {
457 		if ( normal[ 0 ] > 0.0f ) {
458 			VectorSet( axis, 1.0f, 0.0f, 0.0f );
459 		}
460 		else{
461 			VectorSet( axis, -1.0f, 0.0f, 0.0f );
462 		}
463 	}
464 	else
465 	{
466 		if ( normal[ 1 ] > 0.0f ) {
467 			VectorSet( axis, 0.0f, 1.0f, 0.0f );
468 		}
469 		else{
470 			VectorSet( axis, 0.0f, -1.0f, 0.0f );
471 		}
472 	}
473 
474 	/* return ok */
475 	return qtrue;
476 }
477 
478 
479 
480 /*
481    ClassifySurfaces() - ydnar
482    fills out a bunch of info in the surfaces, including planar status, lightmap projection, and bounding box
483  */
484 
485 #define PLANAR_EPSILON  0.5f    //% 0.126f 0.25f
486 
ClassifySurfaces(int numSurfs,mapDrawSurface_t * ds)487 void ClassifySurfaces( int numSurfs, mapDrawSurface_t *ds ){
488 	int i, bestAxis;
489 	float dist;
490 	vec4_t plane;
491 	shaderInfo_t        *si;
492 	static vec3_t axii[ 6 ] =
493 	{
494 		{ 0, 0, -1 },
495 		{ 0, 0, 1 },
496 		{ -1, 0, 0 },
497 		{ 1, 0, 0 },
498 		{ 0, -1, 0 },
499 		{ 0, 1, 0 }
500 	};
501 
502 
503 	/* walk the list of surfaces */
504 	for ( ; numSurfs > 0; numSurfs--, ds++ )
505 	{
506 		/* ignore bogus (or flare) surfaces */
507 		if ( ds->type == SURFACE_BAD || ds->numVerts <= 0 ) {
508 			continue;
509 		}
510 
511 		/* get shader */
512 		si = ds->shaderInfo;
513 
514 		/* -----------------------------------------------------------------
515 		   force meta if vertex count is too high or shader requires it
516 		   ----------------------------------------------------------------- */
517 
518 		if ( ds->type != SURFACE_PATCH && ds->type != SURFACE_FACE ) {
519 			if ( ds->numVerts > SHADER_MAX_VERTEXES ) {
520 				ds->type = SURFACE_FORCED_META;
521 			}
522 		}
523 
524 		/* -----------------------------------------------------------------
525 		   plane and bounding box classification
526 		   ----------------------------------------------------------------- */
527 
528 		/* set surface bounding box */
529 		ClearBounds( ds->mins, ds->maxs );
530 		for ( i = 0; i < ds->numVerts; i++ )
531 			AddPointToBounds( ds->verts[ i ].xyz, ds->mins, ds->maxs );
532 
533 		/* try to get an existing plane */
534 		if ( ds->planeNum >= 0 ) {
535 			VectorCopy( mapplanes[ ds->planeNum ].normal, plane );
536 			plane[ 3 ] = mapplanes[ ds->planeNum ].dist;
537 		}
538 
539 		/* construct one from the first vert with a valid normal */
540 		else
541 		{
542 			VectorClear( plane );
543 			plane[ 3 ] = 0.0f;
544 			for ( i = 0; i < ds->numVerts; i++ )
545 			{
546 				if ( ds->verts[ i ].normal[ 0 ] != 0.0f && ds->verts[ i ].normal[ 1 ] != 0.0f && ds->verts[ i ].normal[ 2 ] != 0.0f ) {
547 					VectorCopy( ds->verts[ i ].normal, plane );
548 					plane[ 3 ] = DotProduct( ds->verts[ i ].xyz, plane );
549 					break;
550 				}
551 			}
552 		}
553 
554 		/* test for bogus plane */
555 		if ( VectorLength( plane ) <= 0.0f ) {
556 			ds->planar = qfalse;
557 			ds->planeNum = -1;
558 		}
559 		else
560 		{
561 			/* determine if surface is planar */
562 			ds->planar = qtrue;
563 
564 			/* test each vert */
565 			for ( i = 0; i < ds->numVerts; i++ )
566 			{
567 				/* point-plane test */
568 				dist = DotProduct( ds->verts[ i ].xyz, plane ) - plane[ 3 ];
569 				if ( fabs( dist ) > PLANAR_EPSILON ) {
570 					//%	if( ds->planeNum >= 0 )
571 					//%	{
572 					//%		Sys_Printf( "WARNING: Planar surface marked unplanar (%f > %f)\n", fabs( dist ), PLANAR_EPSILON );
573 					//%		ds->verts[ i ].color[ 0 ][ 0 ] = ds->verts[ i ].color[ 0 ][ 2 ] = 0;
574 					//%	}
575 					ds->planar = qfalse;
576 					break;
577 				}
578 			}
579 		}
580 
581 		/* find map plane if necessary */
582 		if ( ds->planar ) {
583 			if ( ds->planeNum < 0 ) {
584 				ds->planeNum = FindFloatPlane( plane, plane[ 3 ], 1, &ds->verts[ 0 ].xyz );
585 			}
586 			VectorCopy( plane, ds->lightmapVecs[ 2 ] );
587 		}
588 		else
589 		{
590 			ds->planeNum = -1;
591 			VectorClear( ds->lightmapVecs[ 2 ] );
592 			//% if( ds->type == SURF_META || ds->type == SURF_FACE )
593 			//%		Sys_Printf( "WARNING: Non-planar face (%d): %s\n", ds->planeNum, ds->shaderInfo->shader );
594 		}
595 
596 		/* -----------------------------------------------------------------
597 		   lightmap bounds and axis projection
598 		   ----------------------------------------------------------------- */
599 
600 		/* vertex lit surfaces don't need this information */
601 		if ( si->compileFlags & C_VERTEXLIT || ds->type == SURFACE_TRIANGLES ) {
602 			VectorClear( ds->lightmapAxis );
603 			//%	VectorClear( ds->lightmapVecs[ 2 ] );
604 			ds->sampleSize = 0;
605 			continue;
606 		}
607 
608 		/* the shader can specify an explicit lightmap axis */
609 		if ( si->lightmapAxis[ 0 ] || si->lightmapAxis[ 1 ] || si->lightmapAxis[ 2 ] ) {
610 			VectorCopy( si->lightmapAxis, ds->lightmapAxis );
611 		}
612 		else if ( ds->type == SURFACE_FORCED_META ) {
613 			VectorClear( ds->lightmapAxis );
614 		}
615 		else if ( ds->planar ) {
616 			CalcLightmapAxis( plane, ds->lightmapAxis );
617 		}
618 		else
619 		{
620 			/* find best lightmap axis */
621 			for ( bestAxis = 0; bestAxis < 6; bestAxis++ )
622 			{
623 				for ( i = 0; i < ds->numVerts && bestAxis < 6; i++ )
624 				{
625 					//% Sys_Printf( "Comparing %1.3f %1.3f %1.3f to %1.3f %1.3f %1.3f\n",
626 					//%     ds->verts[ i ].normal[ 0 ], ds->verts[ i ].normal[ 1 ], ds->verts[ i ].normal[ 2 ],
627 					//%     axii[ bestAxis ][ 0 ], axii[ bestAxis ][ 1 ], axii[ bestAxis ][ 2 ] );
628 					if ( DotProduct( ds->verts[ i ].normal, axii[ bestAxis ] ) < 0.25f ) { /* fixme: adjust this tolerance to taste */
629 						break;
630 					}
631 				}
632 
633 				if ( i == ds->numVerts ) {
634 					break;
635 				}
636 			}
637 
638 			/* set axis if possible */
639 			if ( bestAxis < 6 ) {
640 				//% if( ds->type == SURFACE_PATCH )
641 				//%     Sys_Printf( "Mapped axis %d onto patch\n", bestAxis );
642 				VectorCopy( axii[ bestAxis ], ds->lightmapAxis );
643 			}
644 
645 			/* debug code */
646 			//% if( ds->type == SURFACE_PATCH )
647 			//%     Sys_Printf( "Failed to map axis %d onto patch\n", bestAxis );
648 		}
649 
650 		/* calculate lightmap sample size */
651 		if ( ds->shaderInfo->lightmapSampleSize > 0 ) { /* shader value overrides every other */
652 			ds->sampleSize = ds->shaderInfo->lightmapSampleSize;
653 		}
654 		else if ( ds->sampleSize <= 0 ) { /* may contain the entity asigned value */
655 			ds->sampleSize = sampleSize; /* otherwise use global default */
656 
657 		}
658 		if ( ds->lightmapScale > 0.0f ) { /* apply surface lightmap scaling factor */
659 			ds->sampleSize = ds->lightmapScale * (float)ds->sampleSize;
660 			ds->lightmapScale = 0; /* applied */
661 		}
662 
663 		if ( ds->sampleSize < minSampleSize ) {
664 			ds->sampleSize = minSampleSize;
665 		}
666 
667 		if ( ds->sampleSize < 1 ) {
668 			ds->sampleSize = 1;
669 		}
670 
671 		if ( ds->sampleSize > 16384 ) { /* powers of 2 are preferred */
672 			ds->sampleSize = 16384;
673 		}
674 	}
675 }
676 
677 
678 
679 /*
680    ClassifyEntitySurfaces() - ydnar
681    classifies all surfaces in an entity
682  */
683 
ClassifyEntitySurfaces(entity_t * e)684 void ClassifyEntitySurfaces( entity_t *e ){
685 	int i;
686 
687 
688 	/* note it */
689 	Sys_FPrintf( SYS_VRB, "--- ClassifyEntitySurfaces ---\n" );
690 
691 	/* walk the surface list */
692 	for ( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ )
693 	{
694 		FinishSurface( &mapDrawSurfs[ i ] );
695 		ClassifySurfaces( 1, &mapDrawSurfs[ i ] );
696 	}
697 
698 	/* tidy things up */
699 	TidyEntitySurfaces( e );
700 }
701 
702 
703 
704 /*
705    GetShaderIndexForPoint() - ydnar
706    for shader-indexed surfaces (terrain), find a matching index from the indexmap
707  */
708 
GetShaderIndexForPoint(indexMap_t * im,vec3_t eMins,vec3_t eMaxs,vec3_t point)709 byte GetShaderIndexForPoint( indexMap_t *im, vec3_t eMins, vec3_t eMaxs, vec3_t point ){
710 	int i, x, y;
711 	float s, t;
712 	vec3_t mins, maxs, size;
713 
714 
715 	/* early out if no indexmap */
716 	if ( im == NULL ) {
717 		return 0;
718 	}
719 
720 	/* this code is really broken */
721 	#if 0
722 	/* legacy precision fudges for terrain */
723 	for ( i = 0; i < 3; i++ )
724 	{
725 		mins[ i ] = floor( eMins[ i ] + 0.1 );
726 		maxs[ i ] = floor( eMaxs[ i ] + 0.1 );
727 		size[ i ] = maxs[ i ] - mins[ i ];
728 	}
729 
730 	/* find st (fixme: support more than just z-axis projection) */
731 	s = floor( point[ 0 ] + 0.1f - mins[ 0 ] ) / size[ 0 ];
732 	t = floor( maxs[ 1 ] - point[ 1 ] + 0.1f ) / size[ 1 ];
733 	if ( s < 0.0f ) {
734 		s = 0.0f;
735 	}
736 	else if ( s > 1.0f ) {
737 		s = 1.0f;
738 	}
739 	if ( t < 0.0f ) {
740 		t = 0.0f;
741 	}
742 	else if ( t > 1.0f ) {
743 		t = 1.0f;
744 	}
745 
746 	/* make xy */
747 	x = ( im->w - 1 ) * s;
748 	y = ( im->h - 1 ) * t;
749 	#else
750 	/* get size */
751 	for ( i = 0; i < 3; i++ )
752 	{
753 		mins[ i ] = eMins[ i ];
754 		maxs[ i ] = eMaxs[ i ];
755 		size[ i ] = maxs[ i ] - mins[ i ];
756 	}
757 
758 	/* calc st */
759 	s = ( point[ 0 ] - mins[ 0 ] ) / size[ 0 ];
760 	t = ( maxs[ 1 ] - point[ 1 ] ) / size[ 1 ];
761 
762 	/* calc xy */
763 	x = s * im->w;
764 	y = t * im->h;
765 	if ( x < 0 ) {
766 		x = 0;
767 	}
768 	else if ( x > ( im->w - 1 ) ) {
769 		x = ( im->w - 1 );
770 	}
771 	if ( y < 0 ) {
772 		y = 0;
773 	}
774 	else if ( y > ( im->h - 1 ) ) {
775 		y = ( im->h - 1 );
776 	}
777 	#endif
778 
779 	/* return index */
780 	return im->pixels[ y * im->w + x ];
781 }
782 
783 
784 
785 /*
786    GetIndexedShader() - ydnar
787    for a given set of indexes and an indexmap, get a shader and set the vertex alpha in-place
788    this combines a couple different functions from terrain.c
789  */
790 
GetIndexedShader(shaderInfo_t * parent,indexMap_t * im,int numPoints,byte * shaderIndexes)791 shaderInfo_t *GetIndexedShader( shaderInfo_t *parent, indexMap_t *im, int numPoints, byte *shaderIndexes ){
792 	int i;
793 	byte minShaderIndex, maxShaderIndex;
794 	char shader[ MAX_QPATH ];
795 	shaderInfo_t    *si;
796 
797 
798 	/* early out if bad data */
799 	if ( im == NULL || numPoints <= 0 || shaderIndexes == NULL ) {
800 		return ShaderInfoForShader( "default" );
801 	}
802 
803 	/* determine min/max index */
804 	minShaderIndex = 255;
805 	maxShaderIndex = 0;
806 	for ( i = 0; i < numPoints; i++ )
807 	{
808 		if ( shaderIndexes[ i ] < minShaderIndex ) {
809 			minShaderIndex = shaderIndexes[ i ];
810 		}
811 		if ( shaderIndexes[ i ] > maxShaderIndex ) {
812 			maxShaderIndex = shaderIndexes[ i ];
813 		}
814 	}
815 
816 	/* set alpha inline */
817 	for ( i = 0; i < numPoints; i++ )
818 	{
819 		/* straight rip from terrain.c */
820 		if ( shaderIndexes[ i ] < maxShaderIndex ) {
821 			shaderIndexes[ i ] = 0;
822 		}
823 		else{
824 			shaderIndexes[ i ] = 255;
825 		}
826 	}
827 
828 	/* make a shader name */
829 	if ( minShaderIndex == maxShaderIndex ) {
830 		sprintf( shader, "textures/%s_%d", im->shader, maxShaderIndex );
831 	}
832 	else{
833 		sprintf( shader, "textures/%s_%dto%d", im->shader, minShaderIndex, maxShaderIndex );
834 	}
835 
836 	/* get the shader */
837 	si = ShaderInfoForShader( shader );
838 
839 	/* inherit a few things from parent shader */
840 	if ( parent->globalTexture ) {
841 		si->globalTexture = qtrue;
842 	}
843 	if ( parent->forceMeta ) {
844 		si->forceMeta = qtrue;
845 	}
846 	if ( parent->nonplanar ) {
847 		si->nonplanar = qtrue;
848 	}
849 	if ( si->shadeAngleDegrees == 0.0 ) {
850 		si->shadeAngleDegrees = parent->shadeAngleDegrees;
851 	}
852 	if ( parent->tcGen && si->tcGen == qfalse ) {
853 		/* set xy texture projection */
854 		si->tcGen = qtrue;
855 		VectorCopy( parent->vecs[ 0 ], si->vecs[ 0 ] );
856 		VectorCopy( parent->vecs[ 1 ], si->vecs[ 1 ] );
857 	}
858 	if ( VectorLength( parent->lightmapAxis ) > 0.0f && VectorLength( si->lightmapAxis ) <= 0.0f ) {
859 		/* set lightmap projection axis */
860 		VectorCopy( parent->lightmapAxis, si->lightmapAxis );
861 	}
862 
863 	/* return the shader */
864 	return si;
865 }
866 
867 
868 
869 
870 /*
871    DrawSurfaceForSide()
872    creates a SURF_FACE drawsurface from a given brush side and winding
873  */
874 
875 #define SNAP_FLOAT_TO_INT   8
876 #define SNAP_INT_TO_FLOAT   ( 1.0 / SNAP_FLOAT_TO_INT )
877 
DrawSurfaceForSide(entity_t * e,brush_t * b,side_t * s,winding_t * w)878 mapDrawSurface_t *DrawSurfaceForSide( entity_t *e, brush_t *b, side_t *s, winding_t *w ){
879 	int i, j, k;
880 	mapDrawSurface_t    *ds;
881 	shaderInfo_t        *si, *parent;
882 	bspDrawVert_t       *dv;
883 	vec3_t texX, texY;
884 	vec_t x, y;
885 	vec3_t vTranslated;
886 	qboolean indexed;
887 	byte shaderIndexes[ 256 ];
888 	float offsets[ 256 ];
889 	char tempShader[ MAX_QPATH ];
890 
891 
892 	/* ydnar: don't make a drawsurf for culled sides */
893 	if ( s->culled ) {
894 		return NULL;
895 	}
896 
897 	/* range check */
898 	if ( w->numpoints > MAX_POINTS_ON_WINDING ) {
899 		Error( "DrawSurfaceForSide: w->numpoints = %d (> %d)", w->numpoints, MAX_POINTS_ON_WINDING );
900 	}
901 
902 	/* get shader */
903 	si = s->shaderInfo;
904 
905 	/* ydnar: gs mods: check for indexed shader */
906 	if ( si->indexed && b->im != NULL ) {
907 		/* indexed */
908 		indexed = qtrue;
909 
910 		/* get shader indexes for each point */
911 		for ( i = 0; i < w->numpoints; i++ )
912 		{
913 			shaderIndexes[ i ] = GetShaderIndexForPoint( b->im, b->eMins, b->eMaxs, w->p[ i ] );
914 			offsets[ i ] = b->im->offsets[ shaderIndexes[ i ] ];
915 			//%	Sys_Printf( "%f ", offsets[ i ] );
916 		}
917 
918 		/* get matching shader and set alpha */
919 		parent = si;
920 		si = GetIndexedShader( parent, b->im, w->numpoints, shaderIndexes );
921 	}
922 	else{
923 		indexed = qfalse;
924 	}
925 
926 	/* ydnar: sky hack/fix for GL_CLAMP borders on ati cards */
927 	if ( skyFixHack && si->skyParmsImageBase[ 0 ] != '\0' ) {
928 		//%	Sys_FPrintf( SYS_VRB, "Enabling sky hack for shader %s using env %s\n", si->shader, si->skyParmsImageBase );
929 		sprintf( tempShader, "%s_lf", si->skyParmsImageBase );
930 		DrawSurfaceForShader( tempShader );
931 		sprintf( tempShader, "%s_rt", si->skyParmsImageBase );
932 		DrawSurfaceForShader( tempShader );
933 		sprintf( tempShader, "%s_ft", si->skyParmsImageBase );
934 		DrawSurfaceForShader( tempShader );
935 		sprintf( tempShader, "%s_bk", si->skyParmsImageBase );
936 		DrawSurfaceForShader( tempShader );
937 		sprintf( tempShader, "%s_up", si->skyParmsImageBase );
938 		DrawSurfaceForShader( tempShader );
939 		sprintf( tempShader, "%s_dn", si->skyParmsImageBase );
940 		DrawSurfaceForShader( tempShader );
941 	}
942 
943 	/* ydnar: gs mods */
944 	ds = AllocDrawSurface( SURFACE_FACE );
945 	ds->entityNum = b->entityNum;
946 	ds->castShadows = b->castShadows;
947 	ds->recvShadows = b->recvShadows;
948 
949 	ds->planar = qtrue;
950 	ds->planeNum = s->planenum;
951 	VectorCopy( mapplanes[ s->planenum ].normal, ds->lightmapVecs[ 2 ] );
952 
953 	ds->shaderInfo = si;
954 	ds->mapBrush = b;
955 	ds->sideRef = AllocSideRef( s, NULL );
956 	ds->fogNum = -1;
957 	ds->sampleSize = b->lightmapSampleSize;
958 	ds->lightmapScale = b->lightmapScale;
959 	ds->numVerts = w->numpoints;
960 	ds->verts = safe_malloc( ds->numVerts * sizeof( *ds->verts ) );
961 	memset( ds->verts, 0, ds->numVerts * sizeof( *ds->verts ) );
962 
963 	/* compute s/t coordinates from brush primitive texture matrix (compute axis base) */
964 	ComputeAxisBase( mapplanes[ s->planenum ].normal, texX, texY );
965 
966 	/* create the vertexes */
967 	for ( j = 0; j < w->numpoints; j++ )
968 	{
969 		/* get the drawvert */
970 		dv = ds->verts + j;
971 
972 		/* copy xyz and do potential z offset */
973 		VectorCopy( w->p[ j ], dv->xyz );
974 		if ( indexed ) {
975 			dv->xyz[ 2 ] += offsets[ j ];
976 		}
977 
978 		/* round the xyz to a given precision and translate by origin */
979 		for ( i = 0 ; i < 3 ; i++ )
980 			dv->xyz[ i ] = SNAP_INT_TO_FLOAT * floor( dv->xyz[ i ] * SNAP_FLOAT_TO_INT + 0.5f );
981 		VectorAdd( dv->xyz, e->origin, vTranslated );
982 
983 		/* ydnar: tek-fu celshading support for flat shaded shit */
984 		if ( flat ) {
985 			dv->st[ 0 ] = si->stFlat[ 0 ];
986 			dv->st[ 1 ] = si->stFlat[ 1 ];
987 		}
988 
989 		/* ydnar: gs mods: added support for explicit shader texcoord generation */
990 		else if ( si->tcGen ) {
991 			dv->st[ 0 ] = DotProduct( si->vecs[ 0 ], vTranslated );
992 			dv->st[ 1 ] = DotProduct( si->vecs[ 1 ], vTranslated );
993 		}
994 
995 		/* old quake-style texturing */
996 		else if ( g_bBrushPrimit == BPRIMIT_OLDBRUSHES ) {
997 			/* nearest-axial projection */
998 			dv->st[ 0 ] = s->vecs[ 0 ][ 3 ] + DotProduct( s->vecs[ 0 ], vTranslated );
999 			dv->st[ 1 ] = s->vecs[ 1 ][ 3 ] + DotProduct( s->vecs[ 1 ], vTranslated );
1000 			dv->st[ 0 ] /= si->shaderWidth;
1001 			dv->st[ 1 ] /= si->shaderHeight;
1002 		}
1003 
1004 		/* brush primitive texturing */
1005 		else
1006 		{
1007 			/* calculate texture s/t from brush primitive texture matrix */
1008 			x = DotProduct( vTranslated, texX );
1009 			y = DotProduct( vTranslated, texY );
1010 			dv->st[ 0 ] = s->texMat[ 0 ][ 0 ] * x + s->texMat[ 0 ][ 1 ] * y + s->texMat[ 0 ][ 2 ];
1011 			dv->st[ 1 ] = s->texMat[ 1 ][ 0 ] * x + s->texMat[ 1 ][ 1 ] * y + s->texMat[ 1 ][ 2 ];
1012 		}
1013 
1014 		/* copy normal */
1015 		VectorCopy( mapplanes[ s->planenum ].normal, dv->normal );
1016 
1017 		/* ydnar: set color */
1018 		for ( k = 0; k < MAX_LIGHTMAPS; k++ )
1019 		{
1020 			dv->color[ k ][ 0 ] = 255;
1021 			dv->color[ k ][ 1 ] = 255;
1022 			dv->color[ k ][ 2 ] = 255;
1023 
1024 			/* ydnar: gs mods: handle indexed shader blending */
1025 			dv->color[ k ][ 3 ] = ( indexed ? shaderIndexes[ j ] : 255 );
1026 		}
1027 	}
1028 
1029 	/* set cel shader */
1030 	ds->celShader = b->celShader;
1031 
1032 	/* set shade angle */
1033 	if ( b->shadeAngleDegrees > 0.0f ) {
1034 		ds->shadeAngleDegrees = b->shadeAngleDegrees;
1035 	}
1036 
1037 	/* ydnar: gs mods: moved st biasing elsewhere */
1038 	return ds;
1039 }
1040 
1041 
1042 
1043 /*
1044    DrawSurfaceForMesh()
1045    moved here from patch.c
1046  */
1047 
1048 #define YDNAR_NORMAL_EPSILON 0.50f
1049 
VectorCompareExt(vec3_t n1,vec3_t n2,float epsilon)1050 qboolean VectorCompareExt( vec3_t n1, vec3_t n2, float epsilon ){
1051 	int i;
1052 
1053 
1054 	/* test */
1055 	for ( i = 0; i < 3; i++ )
1056 		if ( fabs( n1[ i ] - n2[ i ] ) > epsilon ) {
1057 			return qfalse;
1058 		}
1059 	return qtrue;
1060 }
1061 
DrawSurfaceForMesh(entity_t * e,parseMesh_t * p,mesh_t * mesh)1062 mapDrawSurface_t *DrawSurfaceForMesh( entity_t *e, parseMesh_t *p, mesh_t *mesh ){
1063 	int i, k, numVerts;
1064 	vec4_t plane;
1065 	qboolean planar;
1066 	float dist;
1067 	mapDrawSurface_t    *ds;
1068 	shaderInfo_t        *si, *parent;
1069 	bspDrawVert_t       *dv;
1070 	vec3_t vTranslated;
1071 	mesh_t              *copy;
1072 	qboolean indexed;
1073 	byte shaderIndexes[ MAX_EXPANDED_AXIS * MAX_EXPANDED_AXIS ];
1074 	float offsets[ MAX_EXPANDED_AXIS * MAX_EXPANDED_AXIS ];
1075 
1076 
1077 	/* get mesh and shader shader */
1078 	if ( mesh == NULL ) {
1079 		mesh = &p->mesh;
1080 	}
1081 	si = p->shaderInfo;
1082 	if ( mesh == NULL || si == NULL ) {
1083 		return NULL;
1084 	}
1085 
1086 	/* get vertex count */
1087 	numVerts = mesh->width * mesh->height;
1088 
1089 	/* to make valid normals for patches with degenerate edges,
1090 	   we need to make a copy of the mesh and put the aproximating
1091 	   points onto the curve */
1092 
1093 	/* create a copy of the mesh */
1094 	copy = CopyMesh( mesh );
1095 
1096 	/* store off the original (potentially bad) normals */
1097 	MakeMeshNormals( *copy );
1098 	for ( i = 0; i < numVerts; i++ )
1099 		VectorCopy( copy->verts[ i ].normal, mesh->verts[ i ].normal );
1100 
1101 	/* put the mesh on the curve */
1102 	PutMeshOnCurve( *copy );
1103 
1104 	/* find new normals (to take into account degenerate/flipped edges */
1105 	MakeMeshNormals( *copy );
1106 	for ( i = 0; i < numVerts; i++ )
1107 	{
1108 		/* ydnar: only copy normals that are significantly different from the originals */
1109 		if ( DotProduct( copy->verts[ i ].normal, mesh->verts[ i ].normal ) < 0.75f ) {
1110 			VectorCopy( copy->verts[ i ].normal, mesh->verts[ i ].normal );
1111 		}
1112 	}
1113 
1114 	/* free the old mesh */
1115 	FreeMesh( copy );
1116 
1117 	/* ydnar: gs mods: check for indexed shader */
1118 	if ( si->indexed && p->im != NULL ) {
1119 		/* indexed */
1120 		indexed = qtrue;
1121 
1122 		/* get shader indexes for each point */
1123 		for ( i = 0; i < numVerts; i++ )
1124 		{
1125 			shaderIndexes[ i ] = GetShaderIndexForPoint( p->im, p->eMins, p->eMaxs, mesh->verts[ i ].xyz );
1126 			offsets[ i ] = p->im->offsets[ shaderIndexes[ i ] ];
1127 		}
1128 
1129 		/* get matching shader and set alpha */
1130 		parent = si;
1131 		si = GetIndexedShader( parent, p->im, numVerts, shaderIndexes );
1132 	}
1133 	else{
1134 		indexed = qfalse;
1135 	}
1136 
1137 
1138 	/* ydnar: gs mods */
1139 	ds = AllocDrawSurface( SURFACE_PATCH );
1140 	ds->entityNum = p->entityNum;
1141 	ds->castShadows = p->castShadows;
1142 	ds->recvShadows = p->recvShadows;
1143 
1144 	ds->shaderInfo = si;
1145 	ds->mapMesh = p;
1146 	ds->sampleSize = p->lightmapSampleSize;
1147 	ds->lightmapScale = p->lightmapScale;   /* ydnar */
1148 	ds->patchWidth = mesh->width;
1149 	ds->patchHeight = mesh->height;
1150 	ds->numVerts = ds->patchWidth * ds->patchHeight;
1151 	ds->verts = safe_malloc( ds->numVerts * sizeof( *ds->verts ) );
1152 	memcpy( ds->verts, mesh->verts, ds->numVerts * sizeof( *ds->verts ) );
1153 
1154 	ds->fogNum = -1;
1155 	ds->planeNum = -1;
1156 
1157 	ds->longestCurve = p->longestCurve;
1158 	ds->maxIterations = p->maxIterations;
1159 
1160 	/* construct a plane from the first vert */
1161 	VectorCopy( mesh->verts[ 0 ].normal, plane );
1162 	plane[ 3 ] = DotProduct( mesh->verts[ 0 ].xyz, plane );
1163 	planar = qtrue;
1164 
1165 	/* spew forth errors */
1166 	if ( VectorLength( plane ) < 0.001f ) {
1167 		Sys_Printf( "BOGUS " );
1168 	}
1169 
1170 	/* test each vert */
1171 	for ( i = 1; i < ds->numVerts && planar; i++ )
1172 	{
1173 		/* normal test */
1174 		if ( VectorCompare( plane, mesh->verts[ i ].normal ) == qfalse ) {
1175 			planar = qfalse;
1176 		}
1177 
1178 		/* point-plane test */
1179 		dist = DotProduct( mesh->verts[ i ].xyz, plane ) - plane[ 3 ];
1180 		if ( fabs( dist ) > EQUAL_EPSILON ) {
1181 			planar = qfalse;
1182 		}
1183 	}
1184 
1185 	/* add a map plane */
1186 	if ( planar ) {
1187 		/* make a map plane */
1188 		ds->planeNum = FindFloatPlane( plane, plane[ 3 ], 1, &mesh->verts[ 0 ].xyz );
1189 		VectorCopy( plane, ds->lightmapVecs[ 2 ] );
1190 
1191 		/* push this normal to all verts (ydnar 2003-02-14: bad idea, small patches get screwed up) */
1192 		for ( i = 0; i < ds->numVerts; i++ )
1193 			VectorCopy( plane, ds->verts[ i ].normal );
1194 	}
1195 
1196 	/* walk the verts to do special stuff */
1197 	for ( i = 0; i < ds->numVerts; i++ )
1198 	{
1199 		/* get the drawvert */
1200 		dv = &ds->verts[ i ];
1201 
1202 		/* ydnar: tek-fu celshading support for flat shaded shit */
1203 		if ( flat ) {
1204 			dv->st[ 0 ] = si->stFlat[ 0 ];
1205 			dv->st[ 1 ] = si->stFlat[ 1 ];
1206 		}
1207 
1208 		/* ydnar: gs mods: added support for explicit shader texcoord generation */
1209 		else if ( si->tcGen ) {
1210 			/* translate by origin and project the texture */
1211 			VectorAdd( dv->xyz, e->origin, vTranslated );
1212 			dv->st[ 0 ] = DotProduct( si->vecs[ 0 ], vTranslated );
1213 			dv->st[ 1 ] = DotProduct( si->vecs[ 1 ], vTranslated );
1214 		}
1215 
1216 		/* ydnar: set color */
1217 		for ( k = 0; k < MAX_LIGHTMAPS; k++ )
1218 		{
1219 			dv->color[ k ][ 0 ] = 255;
1220 			dv->color[ k ][ 1 ] = 255;
1221 			dv->color[ k ][ 2 ] = 255;
1222 
1223 			/* ydnar: gs mods: handle indexed shader blending */
1224 			dv->color[ k ][ 3 ] = ( indexed ? shaderIndexes[ i ] : 255 );
1225 		}
1226 
1227 		/* ydnar: offset */
1228 		if ( indexed ) {
1229 			dv->xyz[ 2 ] += offsets[ i ];
1230 		}
1231 	}
1232 
1233 	/* set cel shader */
1234 	ds->celShader = p->celShader;
1235 
1236 	/* return the drawsurface */
1237 	return ds;
1238 }
1239 
1240 
1241 
1242 /*
1243    DrawSurfaceForFlare() - ydnar
1244    creates a flare draw surface
1245  */
1246 
DrawSurfaceForFlare(int entNum,vec3_t origin,vec3_t normal,vec3_t color,const char * flareShader,int lightStyle)1247 mapDrawSurface_t *DrawSurfaceForFlare( int entNum, vec3_t origin, vec3_t normal, vec3_t color, const char *flareShader, int lightStyle ){
1248 	mapDrawSurface_t    *ds;
1249 
1250 
1251 	/* emit flares? */
1252 	if ( emitFlares == qfalse ) {
1253 		return NULL;
1254 	}
1255 
1256 	/* allocate drawsurface */
1257 	ds = AllocDrawSurface( SURFACE_FLARE );
1258 	ds->entityNum = entNum;
1259 
1260 	/* set it up */
1261 	if ( flareShader != NULL && flareShader[ 0 ] != '\0' ) {
1262 		ds->shaderInfo = ShaderInfoForShader( flareShader );
1263 	}
1264 	else{
1265 		ds->shaderInfo = ShaderInfoForShader( game->flareShader );
1266 	}
1267 	if ( origin != NULL ) {
1268 		VectorCopy( origin, ds->lightmapOrigin );
1269 	}
1270 	if ( normal != NULL ) {
1271 		VectorCopy( normal, ds->lightmapVecs[ 2 ] );
1272 	}
1273 	if ( color != NULL ) {
1274 		VectorCopy( color, ds->lightmapVecs[ 0 ] );
1275 	}
1276 
1277 	/* store light style */
1278 	ds->lightStyle = lightStyle;
1279 	if ( ds->lightStyle < 0 || ds->lightStyle >= LS_NONE ) {
1280 		ds->lightStyle = LS_NORMAL;
1281 	}
1282 
1283 	/* fixme: fog */
1284 
1285 	/* return to sender */
1286 	return ds;
1287 }
1288 
1289 
1290 
1291 /*
1292    DrawSurfaceForShader() - ydnar
1293    creates a bogus surface to forcing the game to load a shader
1294  */
1295 
DrawSurfaceForShader(char * shader)1296 mapDrawSurface_t *DrawSurfaceForShader( char *shader ){
1297 	int i;
1298 	shaderInfo_t        *si;
1299 	mapDrawSurface_t    *ds;
1300 
1301 
1302 	/* get shader */
1303 	si = ShaderInfoForShader( shader );
1304 
1305 	/* find existing surface */
1306 	for ( i = 0; i < numMapDrawSurfs; i++ )
1307 	{
1308 		/* get surface */
1309 		ds = &mapDrawSurfs[ i ];
1310 
1311 		/* check it */
1312 		if ( ds->shaderInfo == si ) {
1313 			return ds;
1314 		}
1315 	}
1316 
1317 	/* create a new surface */
1318 	ds = AllocDrawSurface( SURFACE_SHADER );
1319 	ds->entityNum = 0;
1320 	ds->shaderInfo = ShaderInfoForShader( shader );
1321 
1322 	/* return to sender */
1323 	return ds;
1324 }
1325 
1326 
1327 
1328 /*
1329    AddSurfaceFlare() - ydnar
1330    creates flares (coronas) centered on surfaces
1331  */
1332 
AddSurfaceFlare(mapDrawSurface_t * ds,vec3_t entityOrigin)1333 static void AddSurfaceFlare( mapDrawSurface_t *ds, vec3_t entityOrigin ){
1334 	vec3_t origin;
1335 	int i;
1336 
1337 
1338 	/* find centroid */
1339 	VectorClear( origin );
1340 	for ( i = 0; i < ds->numVerts; i++ )
1341 		VectorAdd( origin, ds->verts[ i ].xyz, origin );
1342 	VectorScale( origin, ( 1.0f / ds->numVerts ), origin );
1343 	if ( entityOrigin != NULL ) {
1344 		VectorAdd( origin, entityOrigin, origin );
1345 	}
1346 
1347 	/* push origin off surface a bit */
1348 	VectorMA( origin, 2.0f,  ds->lightmapVecs[ 2 ], origin );
1349 
1350 	/* create the drawsurface */
1351 	DrawSurfaceForFlare( ds->entityNum, origin, ds->lightmapVecs[ 2 ], ds->shaderInfo->color, ds->shaderInfo->flareShader, ds->shaderInfo->lightStyle );
1352 }
1353 
1354 
1355 
1356 /*
1357    SubdivideFace()
1358    subdivides a face surface until it is smaller than the specified size (subdivisions)
1359  */
1360 
SubdivideFace_r(entity_t * e,brush_t * brush,side_t * side,winding_t * w,int fogNum,float subdivisions)1361 static void SubdivideFace_r( entity_t *e, brush_t *brush, side_t *side, winding_t *w, int fogNum, float subdivisions ){
1362 	int i;
1363 	int axis;
1364 	vec3_t bounds[ 2 ];
1365 	const float epsilon = 0.1;
1366 	int subFloor, subCeil;
1367 	winding_t           *frontWinding, *backWinding;
1368 	mapDrawSurface_t    *ds;
1369 
1370 
1371 	/* dummy check */
1372 	if ( w == NULL ) {
1373 		return;
1374 	}
1375 	if ( w->numpoints < 3 ) {
1376 		Error( "SubdivideFace_r: Bad w->numpoints (%d < 3)", w->numpoints );
1377 	}
1378 
1379 	/* determine surface bounds */
1380 	ClearBounds( bounds[ 0 ], bounds[ 1 ] );
1381 	for ( i = 0; i < w->numpoints; i++ )
1382 		AddPointToBounds( w->p[ i ], bounds[ 0 ], bounds[ 1 ] );
1383 
1384 	/* split the face */
1385 	for ( axis = 0; axis < 3; axis++ )
1386 	{
1387 		vec3_t planePoint = { 0, 0, 0 };
1388 		vec3_t planeNormal = { 0, 0, 0 };
1389 		float d;
1390 
1391 
1392 		/* create an axial clipping plane */
1393 		subFloor = floor( bounds[ 0 ][ axis ] / subdivisions ) * subdivisions;
1394 		subCeil = ceil( bounds[ 1 ][ axis ] / subdivisions ) * subdivisions;
1395 		planePoint[ axis ] = subFloor + subdivisions;
1396 		planeNormal[ axis ] = -1;
1397 		d = DotProduct( planePoint, planeNormal );
1398 
1399 		/* subdivide if necessary */
1400 		if ( ( subCeil - subFloor ) > subdivisions ) {
1401 			/* clip the winding */
1402 			ClipWindingEpsilon( w, planeNormal, d, epsilon, &frontWinding, &backWinding ); /* not strict; we assume we always keep a winding */
1403 
1404 			/* the clip may not produce two polygons if it was epsilon close */
1405 			if ( frontWinding == NULL ) {
1406 				w = backWinding;
1407 			}
1408 			else if ( backWinding == NULL ) {
1409 				w = frontWinding;
1410 			}
1411 			else
1412 			{
1413 				SubdivideFace_r( e, brush, side, frontWinding, fogNum, subdivisions );
1414 				SubdivideFace_r( e, brush, side, backWinding, fogNum, subdivisions );
1415 				return;
1416 			}
1417 		}
1418 	}
1419 
1420 	/* create a face surface */
1421 	ds = DrawSurfaceForSide( e, brush, side, w );
1422 
1423 	/* set correct fog num */
1424 	ds->fogNum = fogNum;
1425 }
1426 
1427 
1428 
1429 /*
1430    SubdivideFaceSurfaces()
1431    chop up brush face surfaces that have subdivision attributes
1432    ydnar: and subdivide surfaces that exceed specified texture coordinate range
1433  */
1434 
SubdivideFaceSurfaces(entity_t * e,tree_t * tree)1435 void SubdivideFaceSurfaces( entity_t *e, tree_t *tree ){
1436 	int i, j, numBaseDrawSurfs, fogNum;
1437 	mapDrawSurface_t    *ds;
1438 	brush_t             *brush;
1439 	side_t              *side;
1440 	shaderInfo_t        *si;
1441 	winding_t           *w;
1442 	float range, size, subdivisions, s2;
1443 
1444 
1445 	/* note it */
1446 	Sys_FPrintf( SYS_VRB, "--- SubdivideFaceSurfaces ---\n" );
1447 
1448 	/* walk the list of surfaces */
1449 	numBaseDrawSurfs = numMapDrawSurfs;
1450 	for ( i = e->firstDrawSurf; i < numBaseDrawSurfs; i++ )
1451 	{
1452 		/* get surface */
1453 		ds = &mapDrawSurfs[ i ];
1454 
1455 		/* only subdivide brush sides */
1456 		if ( ds->type != SURFACE_FACE || ds->mapBrush == NULL || ds->sideRef == NULL || ds->sideRef->side == NULL ) {
1457 			continue;
1458 		}
1459 
1460 		/* get bits */
1461 		brush = ds->mapBrush;
1462 		side = ds->sideRef->side;
1463 
1464 		/* check subdivision for shader */
1465 		si = side->shaderInfo;
1466 		if ( si == NULL ) {
1467 			continue;
1468 		}
1469 
1470 		/* ydnar: don't subdivide sky surfaces */
1471 		if ( si->compileFlags & C_SKY ) {
1472 			continue;
1473 		}
1474 
1475 		/* do texture coordinate range check */
1476 		ClassifySurfaces( 1, ds );
1477 		if ( CalcSurfaceTextureRange( ds ) == qfalse ) {
1478 			/* calculate subdivisions texture range (this code is shit) */
1479 			range = ( ds->texRange[ 0 ] > ds->texRange[ 1 ] ? ds->texRange[ 0 ] : ds->texRange[ 1 ] );
1480 			size = ds->maxs[ 0 ] - ds->mins[ 0 ];
1481 			for ( j = 1; j < 3; j++ )
1482 				if ( ( ds->maxs[ j ] - ds->mins[ j ] ) > size ) {
1483 					size = ds->maxs[ j ] - ds->mins[ j ];
1484 				}
1485 			subdivisions = ( size / range ) * texRange;
1486 			subdivisions = ceil( subdivisions / 2 ) * 2;
1487 			for ( j = 1; j < 8; j++ )
1488 			{
1489 				s2 = ceil( (float) texRange / j );
1490 				if ( fabs( subdivisions - s2 ) <= 4.0 ) {
1491 					subdivisions = s2;
1492 					break;
1493 				}
1494 			}
1495 		}
1496 		else{
1497 			subdivisions = si->subdivisions;
1498 		}
1499 
1500 		/* get subdivisions from shader */
1501 		if ( si->subdivisions > 0 && si->subdivisions < subdivisions ) {
1502 			subdivisions = si->subdivisions;
1503 		}
1504 		if ( subdivisions < 1.0f ) {
1505 			continue;
1506 		}
1507 
1508 		/* preserve fog num */
1509 		fogNum = ds->fogNum;
1510 
1511 		/* make a winding and free the surface */
1512 		w = WindingFromDrawSurf( ds );
1513 		ClearSurface( ds );
1514 
1515 		/* subdivide it */
1516 		SubdivideFace_r( e, brush, side, w, fogNum, subdivisions );
1517 	}
1518 }
1519 
1520 
1521 
1522 /*
1523    ====================
1524    ClipSideIntoTree_r
1525 
1526    Adds non-opaque leaf fragments to the convex hull
1527    ====================
1528  */
1529 
ClipSideIntoTree_r(winding_t * w,side_t * side,node_t * node)1530 void ClipSideIntoTree_r( winding_t *w, side_t *side, node_t *node ){
1531 	plane_t         *plane;
1532 	winding_t       *front, *back;
1533 
1534 	if ( !w ) {
1535 		return;
1536 	}
1537 
1538 	if ( node->planenum != PLANENUM_LEAF ) {
1539 		if ( side->planenum == node->planenum ) {
1540 			ClipSideIntoTree_r( w, side, node->children[0] );
1541 			return;
1542 		}
1543 		if ( side->planenum == ( node->planenum ^ 1 ) ) {
1544 			ClipSideIntoTree_r( w, side, node->children[1] );
1545 			return;
1546 		}
1547 
1548 		plane = &mapplanes[ node->planenum ];
1549 		ClipWindingEpsilonStrict( w, plane->normal, plane->dist,
1550 								  ON_EPSILON, &front, &back ); /* strict, we handle the "winding disappeared" case */
1551 		if ( !front && !back ) {
1552 			/* in doubt, register it in both nodes */
1553 			front = CopyWinding( w );
1554 			back = CopyWinding( w );
1555 		}
1556 		FreeWinding( w );
1557 
1558 		ClipSideIntoTree_r( front, side, node->children[0] );
1559 		ClipSideIntoTree_r( back, side, node->children[1] );
1560 
1561 		return;
1562 	}
1563 
1564 	// if opaque leaf, don't add
1565 	if ( !node->opaque ) {
1566 		AddWindingToConvexHull( w, &side->visibleHull, mapplanes[ side->planenum ].normal );
1567 	}
1568 
1569 	FreeWinding( w );
1570 	return;
1571 }
1572 
1573 
1574 
1575 
1576 
1577 static int g_numHiddenFaces, g_numCoinFaces;
1578 
1579 
1580 
1581 /*
1582    CullVectorCompare() - ydnar
1583    compares two vectors with an epsilon
1584  */
1585 
1586 #define CULL_EPSILON 0.1f
1587 
CullVectorCompare(const vec3_t v1,const vec3_t v2)1588 qboolean CullVectorCompare( const vec3_t v1, const vec3_t v2 ){
1589 	int i;
1590 
1591 
1592 	for ( i = 0; i < 3; i++ )
1593 		if ( fabs( v1[ i ] - v2[ i ] ) > CULL_EPSILON ) {
1594 			return qfalse;
1595 		}
1596 	return qtrue;
1597 }
1598 
1599 
1600 
1601 /*
1602    SideInBrush() - ydnar
1603    determines if a brushside lies inside another brush
1604  */
1605 
SideInBrush(side_t * side,brush_t * b)1606 qboolean SideInBrush( side_t *side, brush_t *b ){
1607 	int i, s;
1608 	plane_t     *plane;
1609 
1610 
1611 	/* ignore sides w/o windings or shaders */
1612 	if ( side->winding == NULL || side->shaderInfo == NULL ) {
1613 		return qtrue;
1614 	}
1615 
1616 	/* ignore culled sides and translucent brushes */
1617 	if ( side->culled == qtrue || ( b->compileFlags & C_TRANSLUCENT ) ) {
1618 		return qfalse;
1619 	}
1620 
1621 	/* side iterator */
1622 	for ( i = 0; i < b->numsides; i++ )
1623 	{
1624 		/* fail if any sides are caulk */
1625 		if ( b->sides[ i ].compileFlags & C_NODRAW ) {
1626 			return qfalse;
1627 		}
1628 
1629 		/* check if side's winding is on or behind the plane */
1630 		plane = &mapplanes[ b->sides[ i ].planenum ];
1631 		s = WindingOnPlaneSide( side->winding, plane->normal, plane->dist );
1632 		if ( s == SIDE_FRONT || s == SIDE_CROSS ) {
1633 			return qfalse;
1634 		}
1635 	}
1636 
1637 	/* don't cull autosprite or polygonoffset surfaces */
1638 	if ( side->shaderInfo ) {
1639 		if ( side->shaderInfo->autosprite || side->shaderInfo->polygonOffset ) {
1640 			return qfalse;
1641 		}
1642 	}
1643 
1644 	/* inside */
1645 	side->culled = qtrue;
1646 	g_numHiddenFaces++;
1647 	return qtrue;
1648 }
1649 
1650 
1651 /*
1652    CullSides() - ydnar
1653    culls obscured or buried brushsides from the map
1654  */
1655 
CullSides(entity_t * e)1656 void CullSides( entity_t *e ){
1657 	int numPoints;
1658 	int i, j, k, l, first, second, dir;
1659 	winding_t   *w1, *w2;
1660 	brush_t *b1, *b2;
1661 	side_t      *side1, *side2;
1662 
1663 
1664 	/* note it */
1665 	Sys_FPrintf( SYS_VRB, "--- CullSides ---\n" );
1666 
1667 	g_numHiddenFaces = 0;
1668 	g_numCoinFaces = 0;
1669 
1670 	/* brush interator 1 */
1671 	for ( b1 = e->brushes; b1; b1 = b1->next )
1672 	{
1673 		/* sides check */
1674 		if ( b1->numsides < 1 ) {
1675 			continue;
1676 		}
1677 
1678 		/* brush iterator 2 */
1679 		for ( b2 = b1->next; b2; b2 = b2->next )
1680 		{
1681 			/* sides check */
1682 			if ( b2->numsides < 1 ) {
1683 				continue;
1684 			}
1685 
1686 			/* original check */
1687 			if ( b1->original == b2->original && b1->original != NULL ) {
1688 				continue;
1689 			}
1690 
1691 			/* bbox check */
1692 			j = 0;
1693 			for ( i = 0; i < 3; i++ )
1694 				if ( b1->mins[ i ] > b2->maxs[ i ] || b1->maxs[ i ] < b2->mins[ i ] ) {
1695 					j++;
1696 				}
1697 			if ( j ) {
1698 				continue;
1699 			}
1700 
1701 			/* cull inside sides */
1702 			for ( i = 0; i < b1->numsides; i++ )
1703 				SideInBrush( &b1->sides[ i ], b2 );
1704 			for ( i = 0; i < b2->numsides; i++ )
1705 				SideInBrush( &b2->sides[ i ], b1 );
1706 
1707 			/* side iterator 1 */
1708 			for ( i = 0; i < b1->numsides; i++ )
1709 			{
1710 				/* winding check */
1711 				side1 = &b1->sides[ i ];
1712 				w1 = side1->winding;
1713 				if ( w1 == NULL ) {
1714 					continue;
1715 				}
1716 				numPoints = w1->numpoints;
1717 				if ( side1->shaderInfo == NULL ) {
1718 					continue;
1719 				}
1720 
1721 				/* side iterator 2 */
1722 				for ( j = 0; j < b2->numsides; j++ )
1723 				{
1724 					/* winding check */
1725 					side2 = &b2->sides[ j ];
1726 					w2 = side2->winding;
1727 					if ( w2 == NULL ) {
1728 						continue;
1729 					}
1730 					if ( side2->shaderInfo == NULL ) {
1731 						continue;
1732 					}
1733 					if ( w1->numpoints != w2->numpoints ) {
1734 						continue;
1735 					}
1736 					if ( side1->culled == qtrue && side2->culled == qtrue ) {
1737 						continue;
1738 					}
1739 
1740 					/* compare planes */
1741 					if ( ( side1->planenum & ~0x00000001 ) != ( side2->planenum & ~0x00000001 ) ) {
1742 						continue;
1743 					}
1744 
1745 					/* get autosprite and polygonoffset status */
1746 					if ( side1->shaderInfo &&
1747 						 ( side1->shaderInfo->autosprite || side1->shaderInfo->polygonOffset ) ) {
1748 						continue;
1749 					}
1750 					if ( side2->shaderInfo &&
1751 						 ( side2->shaderInfo->autosprite || side2->shaderInfo->polygonOffset ) ) {
1752 						continue;
1753 					}
1754 
1755 					/* find first common point */
1756 					first = -1;
1757 					for ( k = 0; k < numPoints; k++ )
1758 					{
1759 						if ( VectorCompare( w1->p[ 0 ], w2->p[ k ] ) ) {
1760 							first = k;
1761 							k = numPoints;
1762 						}
1763 					}
1764 					if ( first == -1 ) {
1765 						continue;
1766 					}
1767 
1768 					/* find second common point (regardless of winding order) */
1769 					second = -1;
1770 					dir = 0;
1771 					if ( ( first + 1 ) < numPoints ) {
1772 						second = first + 1;
1773 					}
1774 					else{
1775 						second = 0;
1776 					}
1777 					if ( CullVectorCompare( w1->p[ 1 ], w2->p[ second ] ) ) {
1778 						dir = 1;
1779 					}
1780 					else
1781 					{
1782 						if ( first > 0 ) {
1783 							second = first - 1;
1784 						}
1785 						else{
1786 							second = numPoints - 1;
1787 						}
1788 						if ( CullVectorCompare( w1->p[ 1 ], w2->p[ second ] ) ) {
1789 							dir = -1;
1790 						}
1791 					}
1792 					if ( dir == 0 ) {
1793 						continue;
1794 					}
1795 
1796 					/* compare the rest of the points */
1797 					l = first;
1798 					for ( k = 0; k < numPoints; k++ )
1799 					{
1800 						if ( !CullVectorCompare( w1->p[ k ], w2->p[ l ] ) ) {
1801 							k = 100000;
1802 						}
1803 
1804 						l += dir;
1805 						if ( l < 0 ) {
1806 							l = numPoints - 1;
1807 						}
1808 						else if ( l >= numPoints ) {
1809 							l = 0;
1810 						}
1811 					}
1812 					if ( k >= 100000 ) {
1813 						continue;
1814 					}
1815 
1816 					/* cull face 1 */
1817 					if ( !side2->culled && !( side2->compileFlags & C_TRANSLUCENT ) && !( side2->compileFlags & C_NODRAW ) ) {
1818 						side1->culled = qtrue;
1819 						g_numCoinFaces++;
1820 					}
1821 
1822 					if ( side1->planenum == side2->planenum && side1->culled == qtrue ) {
1823 						continue;
1824 					}
1825 
1826 					/* cull face 2 */
1827 					if ( !side1->culled && !( side1->compileFlags & C_TRANSLUCENT ) && !( side1->compileFlags & C_NODRAW ) ) {
1828 						side2->culled = qtrue;
1829 						g_numCoinFaces++;
1830 					}
1831 				}
1832 			}
1833 		}
1834 	}
1835 
1836 	/* emit some stats */
1837 	Sys_FPrintf( SYS_VRB, "%9d hidden faces culled\n", g_numHiddenFaces );
1838 	Sys_FPrintf( SYS_VRB, "%9d coincident faces culled\n", g_numCoinFaces );
1839 }
1840 
1841 
1842 
1843 
1844 /*
1845    ClipSidesIntoTree()
1846 
1847    creates side->visibleHull for all visible sides
1848 
1849    the drawsurf for a side will consist of the convex hull of
1850    all points in non-opaque clusters, which allows overlaps
1851    to be trimmed off automatically.
1852  */
1853 
ClipSidesIntoTree(entity_t * e,tree_t * tree)1854 void ClipSidesIntoTree( entity_t *e, tree_t *tree ){
1855 	brush_t     *b;
1856 	int i;
1857 	winding_t       *w;
1858 	side_t          *side, *newSide;
1859 	shaderInfo_t    *si;
1860 
1861 
1862 	/* ydnar: cull brush sides */
1863 	CullSides( e );
1864 
1865 	/* note it */
1866 	Sys_FPrintf( SYS_VRB, "--- ClipSidesIntoTree ---\n" );
1867 
1868 	/* walk the brush list */
1869 	for ( b = e->brushes; b; b = b->next )
1870 	{
1871 		/* walk the brush sides */
1872 		for ( i = 0; i < b->numsides; i++ )
1873 		{
1874 			/* get side */
1875 			side = &b->sides[ i ];
1876 			if ( side->winding == NULL ) {
1877 				continue;
1878 			}
1879 
1880 			/* copy the winding */
1881 			w = CopyWinding( side->winding );
1882 			side->visibleHull = NULL;
1883 			ClipSideIntoTree_r( w, side, tree->headnode );
1884 
1885 			/* anything left? */
1886 			w = side->visibleHull;
1887 			if ( w == NULL ) {
1888 				continue;
1889 			}
1890 
1891 			/* shader? */
1892 			si = side->shaderInfo;
1893 			if ( si == NULL ) {
1894 				continue;
1895 			}
1896 
1897 			/* don't create faces for non-visible sides */
1898 			/* ydnar: except indexed shaders, like common/terrain and nodraw fog surfaces */
1899 			if ( ( si->compileFlags & C_NODRAW ) && si->indexed == qfalse && !( si->compileFlags & C_FOG ) ) {
1900 				continue;
1901 			}
1902 
1903 			/* always use the original winding for autosprites and noclip faces */
1904 			if ( si->autosprite || si->noClip ) {
1905 				w = side->winding;
1906 			}
1907 
1908 			/* save this winding as a visible surface */
1909 			DrawSurfaceForSide( e, b, side, w );
1910 
1911 			/* make a back side for fog */
1912 			if ( !( si->compileFlags & C_FOG ) ) {
1913 				continue;
1914 			}
1915 
1916 			/* duplicate the up-facing side */
1917 			w = ReverseWinding( w );
1918 			newSide = safe_malloc( sizeof( *side ) );
1919 			*newSide = *side;
1920 			newSide->visibleHull = w;
1921 			newSide->planenum ^= 1;
1922 
1923 			/* save this winding as a visible surface */
1924 			DrawSurfaceForSide( e, b, newSide, w );
1925 		}
1926 	}
1927 }
1928 
1929 
1930 
1931 /*
1932 
1933    this section deals with filtering drawsurfaces into the bsp tree,
1934    adding references to each leaf a surface touches
1935 
1936  */
1937 
1938 /*
1939    AddReferenceToLeaf() - ydnar
1940    adds a reference to surface ds in the bsp leaf node
1941  */
1942 
AddReferenceToLeaf(mapDrawSurface_t * ds,node_t * node)1943 int AddReferenceToLeaf( mapDrawSurface_t *ds, node_t *node ){
1944 	drawSurfRef_t   *dsr;
1945 
1946 
1947 	/* dummy check */
1948 	if ( node->planenum != PLANENUM_LEAF || node->opaque ) {
1949 		return 0;
1950 	}
1951 
1952 	/* try to find an existing reference */
1953 	for ( dsr = node->drawSurfReferences; dsr; dsr = dsr->nextRef )
1954 	{
1955 		if ( dsr->outputNum == numBSPDrawSurfaces ) {
1956 			return 0;
1957 		}
1958 	}
1959 
1960 	/* add a new reference */
1961 	dsr = safe_malloc( sizeof( *dsr ) );
1962 	dsr->outputNum = numBSPDrawSurfaces;
1963 	dsr->nextRef = node->drawSurfReferences;
1964 	node->drawSurfReferences = dsr;
1965 
1966 	/* ydnar: sky/skybox surfaces */
1967 	if ( node->skybox ) {
1968 		ds->skybox = qtrue;
1969 	}
1970 	if ( ds->shaderInfo->compileFlags & C_SKY ) {
1971 		node->sky = qtrue;
1972 	}
1973 
1974 	/* return */
1975 	return 1;
1976 }
1977 
1978 
1979 
1980 /*
1981    AddReferenceToTree_r() - ydnar
1982    adds a reference to the specified drawsurface to every leaf in the tree
1983  */
1984 
AddReferenceToTree_r(mapDrawSurface_t * ds,node_t * node,qboolean skybox)1985 int AddReferenceToTree_r( mapDrawSurface_t *ds, node_t *node, qboolean skybox ){
1986 	int i, refs = 0;
1987 
1988 
1989 	/* dummy check */
1990 	if ( node == NULL ) {
1991 		return 0;
1992 	}
1993 
1994 	/* is this a decision node? */
1995 	if ( node->planenum != PLANENUM_LEAF ) {
1996 		/* add to child nodes and return */
1997 		refs += AddReferenceToTree_r( ds, node->children[ 0 ], skybox );
1998 		refs += AddReferenceToTree_r( ds, node->children[ 1 ], skybox );
1999 		return refs;
2000 	}
2001 
2002 	/* ydnar */
2003 	if ( skybox ) {
2004 		/* skybox surfaces only get added to sky leaves */
2005 		if ( !node->sky ) {
2006 			return 0;
2007 		}
2008 
2009 		/* increase the leaf bounds */
2010 		for ( i = 0; i < ds->numVerts; i++ )
2011 			AddPointToBounds( ds->verts[ i ].xyz, node->mins, node->maxs );
2012 	}
2013 
2014 	/* add a reference */
2015 	return AddReferenceToLeaf( ds, node );
2016 }
2017 
2018 
2019 
2020 /*
2021    FilterPointIntoTree_r() - ydnar
2022    filters a single point from a surface into the tree
2023  */
2024 
FilterPointIntoTree_r(vec3_t point,mapDrawSurface_t * ds,node_t * node)2025 int FilterPointIntoTree_r( vec3_t point, mapDrawSurface_t *ds, node_t *node ){
2026 	float d;
2027 	plane_t         *plane;
2028 	int refs = 0;
2029 
2030 
2031 	/* is this a decision node? */
2032 	if ( node->planenum != PLANENUM_LEAF ) {
2033 		/* classify the point in relation to the plane */
2034 		plane = &mapplanes[ node->planenum ];
2035 		d = DotProduct( point, plane->normal ) - plane->dist;
2036 
2037 		/* filter by this plane */
2038 		refs = 0;
2039 		if ( d >= -ON_EPSILON ) {
2040 			refs += FilterPointIntoTree_r( point, ds, node->children[ 0 ] );
2041 		}
2042 		if ( d <= ON_EPSILON ) {
2043 			refs += FilterPointIntoTree_r( point, ds, node->children[ 1 ] );
2044 		}
2045 
2046 		/* return */
2047 		return refs;
2048 	}
2049 
2050 	/* add a reference */
2051 	return AddReferenceToLeaf( ds, node );
2052 }
2053 
2054 /*
2055    FilterPointConvexHullIntoTree_r() - ydnar
2056    filters the convex hull of multiple points from a surface into the tree
2057  */
2058 
FilterPointConvexHullIntoTree_r(vec3_t ** points,int npoints,mapDrawSurface_t * ds,node_t * node)2059 int FilterPointConvexHullIntoTree_r( vec3_t **points, int npoints, mapDrawSurface_t *ds, node_t *node ){
2060 	float d, dmin, dmax;
2061 	plane_t         *plane;
2062 	int refs = 0;
2063 	int i;
2064 
2065 	if ( !points ) {
2066 		return 0;
2067 	}
2068 
2069 	/* is this a decision node? */
2070 	if ( node->planenum != PLANENUM_LEAF ) {
2071 		/* classify the point in relation to the plane */
2072 		plane = &mapplanes[ node->planenum ];
2073 
2074 		dmin = dmax = DotProduct( *( points[0] ), plane->normal ) - plane->dist;
2075 		for ( i = 1; i < npoints; ++i )
2076 		{
2077 			d = DotProduct( *( points[i] ), plane->normal ) - plane->dist;
2078 			if ( d > dmax ) {
2079 				dmax = d;
2080 			}
2081 			if ( d < dmin ) {
2082 				dmin = d;
2083 			}
2084 		}
2085 
2086 		/* filter by this plane */
2087 		refs = 0;
2088 		if ( dmax >= -ON_EPSILON ) {
2089 			refs += FilterPointConvexHullIntoTree_r( points, npoints, ds, node->children[ 0 ] );
2090 		}
2091 		if ( dmin <= ON_EPSILON ) {
2092 			refs += FilterPointConvexHullIntoTree_r( points, npoints, ds, node->children[ 1 ] );
2093 		}
2094 
2095 		/* return */
2096 		return refs;
2097 	}
2098 
2099 	/* add a reference */
2100 	return AddReferenceToLeaf( ds, node );
2101 }
2102 
2103 
2104 /*
2105    FilterWindingIntoTree_r() - ydnar
2106    filters a winding from a drawsurface into the tree
2107  */
2108 
FilterWindingIntoTree_r(winding_t * w,mapDrawSurface_t * ds,node_t * node)2109 int FilterWindingIntoTree_r( winding_t *w, mapDrawSurface_t *ds, node_t *node ){
2110 	int i, refs = 0;
2111 	plane_t         *p1, *p2;
2112 	vec4_t plane1, plane2;
2113 	winding_t       *fat, *front, *back;
2114 	shaderInfo_t    *si;
2115 
2116 
2117 	/* get shaderinfo */
2118 	si = ds->shaderInfo;
2119 
2120 	/* ydnar: is this the head node? */
2121 	if ( node->parent == NULL && si != NULL &&
2122 		 ( si->mins[ 0 ] != 0.0f || si->maxs[ 0 ] != 0.0f ||
2123 		   si->mins[ 1 ] != 0.0f || si->maxs[ 1 ] != 0.0f ||
2124 		   si->mins[ 2 ] != 0.0f || si->maxs[ 2 ] != 0.0f ) ) {
2125 		static qboolean warned = qfalse;
2126 		if ( !warned ) {
2127 			Sys_Printf( "WARNING: this map uses the deformVertexes move hack\n" );
2128 			warned = qtrue;
2129 		}
2130 
2131 		/* 'fatten' the winding by the shader mins/maxs (parsed from vertexDeform move) */
2132 		/* note this winding is completely invalid (concave, nonplanar, etc) */
2133 		fat = AllocWinding( w->numpoints * 3 + 3 );
2134 		fat->numpoints = w->numpoints * 3 + 3;
2135 		for ( i = 0; i < w->numpoints; i++ )
2136 		{
2137 			VectorCopy( w->p[ i ], fat->p[ i ] );
2138 			VectorAdd( w->p[ i ], si->mins, fat->p[ i + ( w->numpoints + 1 ) ] );
2139 			VectorAdd( w->p[ i ], si->maxs, fat->p[ i + ( w->numpoints + 1 ) * 2 ] );
2140 		}
2141 		VectorCopy( w->p[ 0 ], fat->p[ i ] );
2142 		VectorAdd( w->p[ 0 ], si->mins, fat->p[ i + w->numpoints ] );
2143 		VectorAdd( w->p[ 0 ], si->maxs, fat->p[ i + w->numpoints * 2 ] );
2144 
2145 		/*
2146 		 * note: this winding is STILL not suitable for ClipWindingEpsilon, and
2147 		 * also does not really fulfill the intention as it only contains
2148 		 * origin, +mins, +maxs, but thanks to the "closing" points I just
2149 		 * added to the three sub-windings, the fattening at least doesn't make
2150 		 * it worse
2151 		 */
2152 
2153 		FreeWinding( w );
2154 		w = fat;
2155 	}
2156 
2157 	/* is this a decision node? */
2158 	if ( node->planenum != PLANENUM_LEAF ) {
2159 		/* get node plane */
2160 		p1 = &mapplanes[ node->planenum ];
2161 		VectorCopy( p1->normal, plane1 );
2162 		plane1[ 3 ] = p1->dist;
2163 
2164 		/* check if surface is planar */
2165 		if ( ds->planeNum >= 0 ) {
2166 			/* get surface plane */
2167 			p2 = &mapplanes[ ds->planeNum ];
2168 			VectorCopy( p2->normal, plane2 );
2169 			plane2[ 3 ] = p2->dist;
2170 
2171 			#if 0
2172 			/* div0: this is the plague (inaccurate) */
2173 			vec4_t reverse;
2174 
2175 			/* invert surface plane */
2176 			VectorSubtract( vec3_origin, plane2, reverse );
2177 			reverse[ 3 ] = -plane2[ 3 ];
2178 
2179 			/* compare planes */
2180 			if ( DotProduct( plane1, plane2 ) > 0.999f && fabs( plane1[ 3 ] - plane2[ 3 ] ) < 0.001f ) {
2181 				return FilterWindingIntoTree_r( w, ds, node->children[ 0 ] );
2182 			}
2183 			if ( DotProduct( plane1, reverse ) > 0.999f && fabs( plane1[ 3 ] - reverse[ 3 ] ) < 0.001f ) {
2184 				return FilterWindingIntoTree_r( w, ds, node->children[ 1 ] );
2185 			}
2186 			#else
2187 			/* div0: this is the cholera (doesn't hit enough) */
2188 
2189 			/* the drawsurf might have an associated plane, if so, force a filter here */
2190 			if ( ds->planeNum == node->planenum ) {
2191 				return FilterWindingIntoTree_r( w, ds, node->children[ 0 ] );
2192 			}
2193 			if ( ds->planeNum == ( node->planenum ^ 1 ) ) {
2194 				return FilterWindingIntoTree_r( w, ds, node->children[ 1 ] );
2195 			}
2196 			#endif
2197 		}
2198 
2199 		/* clip the winding by this plane */
2200 		ClipWindingEpsilonStrict( w, plane1, plane1[ 3 ], ON_EPSILON, &front, &back ); /* strict; we handle the "winding disappeared" case */
2201 
2202 		/* filter by this plane */
2203 		refs = 0;
2204 		if ( front == NULL && back == NULL ) {
2205 			/* same plane, this is an ugly hack */
2206 			/* but better too many than too few refs */
2207 			refs += FilterWindingIntoTree_r( CopyWinding( w ), ds, node->children[ 0 ] );
2208 			refs += FilterWindingIntoTree_r( CopyWinding( w ), ds, node->children[ 1 ] );
2209 		}
2210 		if ( front != NULL ) {
2211 			refs += FilterWindingIntoTree_r( front, ds, node->children[ 0 ] );
2212 		}
2213 		if ( back != NULL ) {
2214 			refs += FilterWindingIntoTree_r( back, ds, node->children[ 1 ] );
2215 		}
2216 		FreeWinding( w );
2217 
2218 		/* return */
2219 		return refs;
2220 	}
2221 
2222 	/* add a reference */
2223 	return AddReferenceToLeaf( ds, node );
2224 }
2225 
2226 
2227 
2228 /*
2229    FilterFaceIntoTree()
2230    filters a planar winding face drawsurface into the bsp tree
2231  */
2232 
FilterFaceIntoTree(mapDrawSurface_t * ds,tree_t * tree)2233 int FilterFaceIntoTree( mapDrawSurface_t *ds, tree_t *tree ){
2234 	winding_t   *w;
2235 	int refs = 0;
2236 
2237 
2238 	/* make a winding and filter it into the tree */
2239 	w = WindingFromDrawSurf( ds );
2240 	refs = FilterWindingIntoTree_r( w, ds, tree->headnode );
2241 
2242 	/* return */
2243 	return refs;
2244 }
2245 
2246 
2247 
2248 /*
2249    FilterPatchIntoTree()
2250    subdivides a patch into an approximate curve and filters it into the tree
2251  */
2252 
2253 #define FILTER_SUBDIVISION      8
2254 
FilterPatchIntoTree(mapDrawSurface_t * ds,tree_t * tree)2255 static int FilterPatchIntoTree( mapDrawSurface_t *ds, tree_t *tree ){
2256 	int x, y, refs = 0;
2257 
2258 	for ( y = 0; y + 2 < ds->patchHeight; y += 2 )
2259 		for ( x = 0; x + 2 < ds->patchWidth; x += 2 )
2260 		{
2261 			vec3_t *points[9];
2262 			points[0] = &ds->verts[( y + 0 ) * ds->patchWidth + ( x + 0 )].xyz;
2263 			points[1] = &ds->verts[( y + 0 ) * ds->patchWidth + ( x + 1 )].xyz;
2264 			points[2] = &ds->verts[( y + 0 ) * ds->patchWidth + ( x + 2 )].xyz;
2265 			points[3] = &ds->verts[( y + 1 ) * ds->patchWidth + ( x + 0 )].xyz;
2266 			points[4] = &ds->verts[( y + 1 ) * ds->patchWidth + ( x + 1 )].xyz;
2267 			points[5] = &ds->verts[( y + 1 ) * ds->patchWidth + ( x + 2 )].xyz;
2268 			points[6] = &ds->verts[( y + 2 ) * ds->patchWidth + ( x + 0 )].xyz;
2269 			points[7] = &ds->verts[( y + 2 ) * ds->patchWidth + ( x + 1 )].xyz;
2270 			points[8] = &ds->verts[( y + 2 ) * ds->patchWidth + ( x + 2 )].xyz;
2271 			refs += FilterPointConvexHullIntoTree_r( points, 9, ds, tree->headnode );
2272 		}
2273 
2274 	return refs;
2275 }
2276 
2277 
2278 
2279 /*
2280    FilterTrianglesIntoTree()
2281    filters a triangle surface (meta, model) into the bsp
2282  */
2283 
FilterTrianglesIntoTree(mapDrawSurface_t * ds,tree_t * tree)2284 static int FilterTrianglesIntoTree( mapDrawSurface_t *ds, tree_t *tree ){
2285 	int i, refs;
2286 	winding_t   *w;
2287 
2288 
2289 	/* ydnar: gs mods: this was creating bogus triangles before */
2290 	refs = 0;
2291 	for ( i = 0; i < ds->numIndexes; i += 3 )
2292 	{
2293 		/* error check */
2294 		if ( ds->indexes[ i ] >= ds->numVerts ||
2295 			 ds->indexes[ i + 1 ] >= ds->numVerts ||
2296 			 ds->indexes[ i + 2 ] >= ds->numVerts ) {
2297 			Error( "Index %d greater than vertex count %d", ds->indexes[ i ], ds->numVerts );
2298 		}
2299 
2300 		/* make a triangle winding and filter it into the tree */
2301 		w = AllocWinding( 3 );
2302 		w->numpoints = 3;
2303 		VectorCopy( ds->verts[ ds->indexes[ i ] ].xyz, w->p[ 0 ] );
2304 		VectorCopy( ds->verts[ ds->indexes[ i + 1 ] ].xyz, w->p[ 1 ] );
2305 		VectorCopy( ds->verts[ ds->indexes[ i + 2 ] ].xyz, w->p[ 2 ] );
2306 		refs += FilterWindingIntoTree_r( w, ds, tree->headnode );
2307 	}
2308 
2309 	/* use point filtering as well */
2310 	for ( i = 0; i < ds->numVerts; i++ )
2311 		refs += FilterPointIntoTree_r( ds->verts[ i ].xyz, ds, tree->headnode );
2312 
2313 	return refs;
2314 }
2315 
2316 
2317 
2318 /*
2319    FilterFoliageIntoTree()
2320    filters a foliage surface (wolf et/splash damage)
2321  */
2322 
FilterFoliageIntoTree(mapDrawSurface_t * ds,tree_t * tree)2323 static int FilterFoliageIntoTree( mapDrawSurface_t *ds, tree_t *tree ){
2324 	int f, i, refs;
2325 	bspDrawVert_t   *instance;
2326 	vec3_t xyz;
2327 	winding_t       *w;
2328 
2329 
2330 	/* walk origin list */
2331 	refs = 0;
2332 	for ( f = 0; f < ds->numFoliageInstances; f++ )
2333 	{
2334 		/* get instance */
2335 		instance = ds->verts + ds->patchHeight + f;
2336 
2337 		/* walk triangle list */
2338 		for ( i = 0; i < ds->numIndexes; i += 3 )
2339 		{
2340 			/* error check */
2341 			if ( ds->indexes[ i ] >= ds->numVerts ||
2342 				 ds->indexes[ i + 1 ] >= ds->numVerts ||
2343 				 ds->indexes[ i + 2 ] >= ds->numVerts ) {
2344 				Error( "Index %d greater than vertex count %d", ds->indexes[ i ], ds->numVerts );
2345 			}
2346 
2347 			/* make a triangle winding and filter it into the tree */
2348 			w = AllocWinding( 3 );
2349 			w->numpoints = 3;
2350 			VectorAdd( instance->xyz, ds->verts[ ds->indexes[ i ] ].xyz, w->p[ 0 ] );
2351 			VectorAdd( instance->xyz, ds->verts[ ds->indexes[ i + 1 ] ].xyz, w->p[ 1 ] );
2352 			VectorAdd( instance->xyz, ds->verts[ ds->indexes[ i + 2 ] ].xyz, w->p[ 2 ] );
2353 			refs += FilterWindingIntoTree_r( w, ds, tree->headnode );
2354 		}
2355 
2356 		/* use point filtering as well */
2357 		for ( i = 0; i < ( ds->numVerts - ds->numFoliageInstances ); i++ )
2358 		{
2359 			VectorAdd( instance->xyz, ds->verts[ i ].xyz, xyz );
2360 			refs += FilterPointIntoTree_r( xyz, ds, tree->headnode );
2361 		}
2362 	}
2363 
2364 	return refs;
2365 }
2366 
2367 
2368 
2369 /*
2370    FilterFlareIntoTree()
2371    simple point filtering for flare surfaces
2372  */
FilterFlareSurfIntoTree(mapDrawSurface_t * ds,tree_t * tree)2373 static int FilterFlareSurfIntoTree( mapDrawSurface_t *ds, tree_t *tree ){
2374 	return FilterPointIntoTree_r( ds->lightmapOrigin, ds, tree->headnode );
2375 }
2376 
2377 
2378 
2379 /*
2380    EmitDrawVerts() - ydnar
2381    emits bsp drawverts from a map drawsurface
2382  */
2383 
EmitDrawVerts(mapDrawSurface_t * ds,bspDrawSurface_t * out)2384 void EmitDrawVerts( mapDrawSurface_t *ds, bspDrawSurface_t *out ){
2385 	int i, k;
2386 	bspDrawVert_t   *dv;
2387 	shaderInfo_t    *si;
2388 	float offset;
2389 
2390 
2391 	/* get stuff */
2392 	si = ds->shaderInfo;
2393 	offset = si->offset;
2394 
2395 	/* copy the verts */
2396 	out->firstVert = numBSPDrawVerts;
2397 	out->numVerts = ds->numVerts;
2398 	for ( i = 0; i < ds->numVerts; i++ )
2399 	{
2400 		/* allocate a new vert */
2401 		IncDrawVerts();
2402 		dv = &bspDrawVerts[ numBSPDrawVerts - 1 ];
2403 
2404 		/* copy it */
2405 		memcpy( dv, &ds->verts[ i ], sizeof( *dv ) );
2406 
2407 		/* offset? */
2408 		if ( offset != 0.0f ) {
2409 			VectorMA( dv->xyz, offset, dv->normal, dv->xyz );
2410 		}
2411 
2412 		/* expand model bounds
2413 		   necessary because of misc_model surfaces on entities
2414 		   note: does not happen on worldspawn as its bounds is only used for determining lightgrid bounds */
2415 		if ( numBSPModels > 0 ) {
2416 			AddPointToBounds( dv->xyz, bspModels[ numBSPModels ].mins, bspModels[ numBSPModels ].maxs );
2417 		}
2418 
2419 		/* debug color? */
2420 		if ( debugSurfaces ) {
2421 			for ( k = 0; k < MAX_LIGHTMAPS; k++ )
2422 				VectorCopy( debugColors[ ( ds - mapDrawSurfs ) % 12 ], dv->color[ k ] );
2423 		}
2424 	}
2425 }
2426 
2427 
2428 
2429 /*
2430    FindDrawIndexes() - ydnar
2431    this attempts to find a run of indexes in the bsp that match the given indexes
2432    this tends to reduce the size of the bsp index pool by 1/3 or more
2433    returns numIndexes + 1 if the search failed
2434  */
2435 
FindDrawIndexes(int numIndexes,int * indexes)2436 int FindDrawIndexes( int numIndexes, int *indexes ){
2437 	int i, j, numTestIndexes;
2438 
2439 
2440 	/* dummy check */
2441 	if ( numIndexes < 3 || numBSPDrawIndexes < numIndexes || indexes == NULL ) {
2442 		return numBSPDrawIndexes;
2443 	}
2444 
2445 	/* set limit */
2446 	numTestIndexes = 1 + numBSPDrawIndexes - numIndexes;
2447 
2448 	/* handle 3 indexes as a special case for performance */
2449 	if ( numIndexes == 3 ) {
2450 		/* run through all indexes */
2451 		for ( i = 0; i < numTestIndexes; i++ )
2452 		{
2453 			/* test 3 indexes */
2454 			if ( indexes[ 0 ] == bspDrawIndexes[ i ] &&
2455 				 indexes[ 1 ] == bspDrawIndexes[ i + 1 ] &&
2456 				 indexes[ 2 ] == bspDrawIndexes[ i + 2 ] ) {
2457 				numRedundantIndexes += numIndexes;
2458 				return i;
2459 			}
2460 		}
2461 
2462 		/* failed */
2463 		return numBSPDrawIndexes;
2464 	}
2465 
2466 	/* handle 4 or more indexes */
2467 	for ( i = 0; i < numTestIndexes; i++ )
2468 	{
2469 		/* test first 4 indexes */
2470 		if ( indexes[ 0 ] == bspDrawIndexes[ i ] &&
2471 			 indexes[ 1 ] == bspDrawIndexes[ i + 1 ] &&
2472 			 indexes[ 2 ] == bspDrawIndexes[ i + 2 ] &&
2473 			 indexes[ 3 ] == bspDrawIndexes[ i + 3 ] ) {
2474 			/* handle 4 indexes */
2475 			if ( numIndexes == 4 ) {
2476 				return i;
2477 			}
2478 
2479 			/* test the remainder */
2480 			for ( j = 4; j < numIndexes; j++ )
2481 			{
2482 				if ( indexes[ j ] != bspDrawIndexes[ i + j ] ) {
2483 					break;
2484 				}
2485 				else if ( j == ( numIndexes - 1 ) ) {
2486 					numRedundantIndexes += numIndexes;
2487 					return i;
2488 				}
2489 			}
2490 		}
2491 	}
2492 
2493 	/* failed */
2494 	return numBSPDrawIndexes;
2495 }
2496 
2497 
2498 
2499 /*
2500    EmitDrawIndexes() - ydnar
2501    attempts to find an existing run of drawindexes before adding new ones
2502  */
2503 
EmitDrawIndexes(mapDrawSurface_t * ds,bspDrawSurface_t * out)2504 void EmitDrawIndexes( mapDrawSurface_t *ds, bspDrawSurface_t *out ){
2505 	int i;
2506 
2507 
2508 	/* attempt to use redundant indexing */
2509 	out->firstIndex = FindDrawIndexes( ds->numIndexes, ds->indexes );
2510 	out->numIndexes = ds->numIndexes;
2511 	if ( out->firstIndex == numBSPDrawIndexes ) {
2512 		/* copy new unique indexes */
2513 		for ( i = 0; i < ds->numIndexes; i++ )
2514 		{
2515 			AUTOEXPAND_BY_REALLOC_BSP( DrawIndexes, 1024 );
2516 			bspDrawIndexes[ numBSPDrawIndexes ] = ds->indexes[ i ];
2517 
2518 			/* validate the index */
2519 			if ( ds->type != SURFACE_PATCH ) {
2520 				if ( bspDrawIndexes[ numBSPDrawIndexes ] < 0 || bspDrawIndexes[ numBSPDrawIndexes ] >= ds->numVerts ) {
2521 					Sys_Printf( "WARNING: %d %s has invalid index %d (%d)\n",
2522 								numBSPDrawSurfaces,
2523 								ds->shaderInfo->shader,
2524 								bspDrawIndexes[ numBSPDrawIndexes ],
2525 								i );
2526 					bspDrawIndexes[ numBSPDrawIndexes ] = 0;
2527 				}
2528 			}
2529 
2530 			/* increment index count */
2531 			numBSPDrawIndexes++;
2532 		}
2533 	}
2534 }
2535 
2536 
2537 
2538 
2539 /*
2540    EmitFlareSurface()
2541    emits a bsp flare drawsurface
2542  */
2543 
EmitFlareSurface(mapDrawSurface_t * ds)2544 void EmitFlareSurface( mapDrawSurface_t *ds ){
2545 	int i;
2546 	bspDrawSurface_t        *out;
2547 
2548 
2549 	/* ydnar: nuking useless flare drawsurfaces */
2550 	if ( emitFlares == qfalse && ds->type != SURFACE_SHADER ) {
2551 		return;
2552 	}
2553 
2554 	/* limit check */
2555 	if ( numBSPDrawSurfaces == MAX_MAP_DRAW_SURFS ) {
2556 		Error( "MAX_MAP_DRAW_SURFS" );
2557 	}
2558 
2559 	/* allocate a new surface */
2560 	if ( numBSPDrawSurfaces == MAX_MAP_DRAW_SURFS ) {
2561 		Error( "MAX_MAP_DRAW_SURFS" );
2562 	}
2563 	out = &bspDrawSurfaces[ numBSPDrawSurfaces ];
2564 	ds->outputNum = numBSPDrawSurfaces;
2565 	numBSPDrawSurfaces++;
2566 	memset( out, 0, sizeof( *out ) );
2567 
2568 	/* set it up */
2569 	out->surfaceType = MST_FLARE;
2570 	out->shaderNum = EmitShader( ds->shaderInfo->shader, &ds->shaderInfo->contentFlags, &ds->shaderInfo->surfaceFlags );
2571 	out->fogNum = ds->fogNum;
2572 
2573 	/* RBSP */
2574 	for ( i = 0; i < MAX_LIGHTMAPS; i++ )
2575 	{
2576 		out->lightmapNum[ i ] = -3;
2577 		out->lightmapStyles[ i ] = LS_NONE;
2578 		out->vertexStyles[ i ] = LS_NONE;
2579 	}
2580 	out->lightmapStyles[ 0 ] = ds->lightStyle;
2581 	out->vertexStyles[ 0 ] = ds->lightStyle;
2582 
2583 	VectorCopy( ds->lightmapOrigin, out->lightmapOrigin );          /* origin */
2584 	VectorCopy( ds->lightmapVecs[ 0 ], out->lightmapVecs[ 0 ] );    /* color */
2585 	VectorCopy( ds->lightmapVecs[ 1 ], out->lightmapVecs[ 1 ] );
2586 	VectorCopy( ds->lightmapVecs[ 2 ], out->lightmapVecs[ 2 ] );    /* normal */
2587 
2588 	/* add to count */
2589 	numSurfacesByType[ ds->type ]++;
2590 }
2591 
2592 /*
2593    EmitPatchSurface()
2594    emits a bsp patch drawsurface
2595  */
2596 
EmitPatchSurface(entity_t * e,mapDrawSurface_t * ds)2597 void EmitPatchSurface( entity_t *e, mapDrawSurface_t *ds ){
2598 	int i, j;
2599 	bspDrawSurface_t    *out;
2600 	int surfaceFlags, contentFlags;
2601 	int forcePatchMeta;
2602 
2603 	/* vortex: _patchMeta support */
2604 	forcePatchMeta = IntForKey( e, "_patchMeta" );
2605 	if ( !forcePatchMeta ) {
2606 		forcePatchMeta = IntForKey( e, "patchMeta" );
2607 	}
2608 
2609 	/* invert the surface if necessary */
2610 	if ( ds->backSide || ds->shaderInfo->invert ) {
2611 		bspDrawVert_t   *dv1, *dv2, temp;
2612 
2613 		/* walk the verts, flip the normal */
2614 		for ( i = 0; i < ds->numVerts; i++ )
2615 			VectorScale( ds->verts[ i ].normal, -1.0f, ds->verts[ i ].normal );
2616 
2617 		/* walk the verts again, but this time reverse their order */
2618 		for ( j = 0; j < ds->patchHeight; j++ )
2619 		{
2620 			for ( i = 0; i < ( ds->patchWidth / 2 ); i++ )
2621 			{
2622 				dv1 = &ds->verts[ j * ds->patchWidth + i ];
2623 				dv2 = &ds->verts[ j * ds->patchWidth + ( ds->patchWidth - i - 1 ) ];
2624 				memcpy( &temp, dv1, sizeof( bspDrawVert_t ) );
2625 				memcpy( dv1, dv2, sizeof( bspDrawVert_t ) );
2626 				memcpy( dv2, &temp, sizeof( bspDrawVert_t ) );
2627 			}
2628 		}
2629 
2630 		/* invert facing */
2631 		VectorScale( ds->lightmapVecs[ 2 ], -1.0f, ds->lightmapVecs[ 2 ] );
2632 	}
2633 
2634 	/* allocate a new surface */
2635 	if ( numBSPDrawSurfaces == MAX_MAP_DRAW_SURFS ) {
2636 		Error( "MAX_MAP_DRAW_SURFS" );
2637 	}
2638 	out = &bspDrawSurfaces[ numBSPDrawSurfaces ];
2639 	ds->outputNum = numBSPDrawSurfaces;
2640 	numBSPDrawSurfaces++;
2641 	memset( out, 0, sizeof( *out ) );
2642 
2643 	/* set it up */
2644 	out->surfaceType = MST_PATCH;
2645 	if ( debugSurfaces ) {
2646 		out->shaderNum = EmitShader( "debugsurfaces", NULL, NULL );
2647 	}
2648 	else if ( patchMeta || forcePatchMeta ) {
2649 		/* patch meta requires that we have nodraw patches for collision */
2650 		surfaceFlags = ds->shaderInfo->surfaceFlags;
2651 		contentFlags = ds->shaderInfo->contentFlags;
2652 		ApplySurfaceParm( "nodraw", &contentFlags, &surfaceFlags, NULL );
2653 		ApplySurfaceParm( "pointlight", &contentFlags, &surfaceFlags, NULL );
2654 
2655 		/* we don't want this patch getting lightmapped */
2656 		VectorClear( ds->lightmapVecs[ 2 ] );
2657 		VectorClear( ds->lightmapAxis );
2658 		ds->sampleSize = 0;
2659 
2660 		/* emit the new fake shader */
2661 		out->shaderNum = EmitShader( ds->shaderInfo->shader, &contentFlags, &surfaceFlags );
2662 	}
2663 	else{
2664 		out->shaderNum = EmitShader( ds->shaderInfo->shader, &ds->shaderInfo->contentFlags, &ds->shaderInfo->surfaceFlags );
2665 	}
2666 	out->patchWidth = ds->patchWidth;
2667 	out->patchHeight = ds->patchHeight;
2668 	out->fogNum = ds->fogNum;
2669 
2670 	/* RBSP */
2671 	for ( i = 0; i < MAX_LIGHTMAPS; i++ )
2672 	{
2673 		out->lightmapNum[ i ] = -3;
2674 		out->lightmapStyles[ i ] = LS_NONE;
2675 		out->vertexStyles[ i ] = LS_NONE;
2676 	}
2677 	out->lightmapStyles[ 0 ] = LS_NORMAL;
2678 	out->vertexStyles[ 0 ] = LS_NORMAL;
2679 
2680 	/* ydnar: gs mods: previously, the lod bounds were stored in lightmapVecs[ 0 ] and [ 1 ], moved to bounds[ 0 ] and [ 1 ] */
2681 	VectorCopy( ds->lightmapOrigin, out->lightmapOrigin );
2682 	VectorCopy( ds->bounds[ 0 ], out->lightmapVecs[ 0 ] );
2683 	VectorCopy( ds->bounds[ 1 ], out->lightmapVecs[ 1 ] );
2684 	VectorCopy( ds->lightmapVecs[ 2 ], out->lightmapVecs[ 2 ] );
2685 
2686 	/* ydnar: gs mods: clear out the plane normal */
2687 	if ( ds->planar == qfalse ) {
2688 		VectorClear( out->lightmapVecs[ 2 ] );
2689 	}
2690 
2691 	/* emit the verts and indexes */
2692 	EmitDrawVerts( ds, out );
2693 	EmitDrawIndexes( ds, out );
2694 
2695 	/* add to count */
2696 	numSurfacesByType[ ds->type ]++;
2697 }
2698 
2699 /*
2700    OptimizeTriangleSurface() - ydnar
2701    optimizes the vertex/index data in a triangle surface
2702  */
2703 
2704 #define VERTEX_CACHE_SIZE   16
2705 
OptimizeTriangleSurface(mapDrawSurface_t * ds)2706 static void OptimizeTriangleSurface( mapDrawSurface_t *ds ){
2707 	int i, j, k, temp, first, best, bestScore, score;
2708 	int vertexCache[ VERTEX_CACHE_SIZE + 1 ];       /* one more for optimizing insert */
2709 	int     *indexes;
2710 
2711 
2712 	/* certain surfaces don't get optimized */
2713 	if ( ds->numIndexes <= VERTEX_CACHE_SIZE ||
2714 		 ds->shaderInfo->autosprite ) {
2715 		return;
2716 	}
2717 
2718 	/* create index scratch pad */
2719 	indexes = safe_malloc( ds->numIndexes * sizeof( *indexes ) );
2720 	memcpy( indexes, ds->indexes, ds->numIndexes * sizeof( *indexes ) );
2721 
2722 	/* setup */
2723 	for ( i = 0; i <= VERTEX_CACHE_SIZE && i < ds->numIndexes; i++ )
2724 		vertexCache[ i ] = indexes[ i ];
2725 
2726 	/* add triangles in a vertex cache-aware order */
2727 	for ( i = 0; i < ds->numIndexes; i += 3 )
2728 	{
2729 		/* find best triangle given the current vertex cache */
2730 		first = -1;
2731 		best = -1;
2732 		bestScore = -1;
2733 		for ( j = 0; j < ds->numIndexes; j += 3 )
2734 		{
2735 			/* valid triangle? */
2736 			if ( indexes[ j ] != -1 ) {
2737 				/* set first if necessary */
2738 				if ( first < 0 ) {
2739 					first = j;
2740 				}
2741 
2742 				/* score the triangle */
2743 				score = 0;
2744 				for ( k = 0; k < VERTEX_CACHE_SIZE; k++ )
2745 				{
2746 					if ( indexes[ j ] == vertexCache[ k ] || indexes[ j + 1 ] == vertexCache[ k ] || indexes[ j + 2 ] == vertexCache[ k ] ) {
2747 						score++;
2748 					}
2749 				}
2750 
2751 				/* better triangle? */
2752 				if ( score > bestScore ) {
2753 					bestScore = score;
2754 					best = j;
2755 				}
2756 
2757 				/* a perfect score of 3 means this triangle's verts are already present in the vertex cache */
2758 				if ( score == 3 ) {
2759 					break;
2760 				}
2761 			}
2762 		}
2763 
2764 		/* check if no decent triangle was found, and use first available */
2765 		if ( best < 0 ) {
2766 			best = first;
2767 		}
2768 
2769 		/* valid triangle? */
2770 		if ( best >= 0 ) {
2771 			/* add triangle to vertex cache */
2772 			for ( j = 0; j < 3; j++ )
2773 			{
2774 				for ( k = 0; k < VERTEX_CACHE_SIZE; k++ )
2775 				{
2776 					if ( indexes[ best + j ] == vertexCache[ k ] ) {
2777 						break;
2778 					}
2779 				}
2780 
2781 				if ( k >= VERTEX_CACHE_SIZE ) {
2782 					/* pop off top of vertex cache */
2783 					for ( k = VERTEX_CACHE_SIZE; k > 0; k-- )
2784 						vertexCache[ k ] = vertexCache[ k - 1 ];
2785 
2786 					/* add vertex */
2787 					vertexCache[ 0 ] = indexes[ best + j ];
2788 				}
2789 			}
2790 
2791 			/* add triangle to surface */
2792 			ds->indexes[ i ] = indexes[ best ];
2793 			ds->indexes[ i + 1 ] = indexes[ best + 1 ];
2794 			ds->indexes[ i + 2 ] = indexes[ best + 2 ];
2795 
2796 			/* clear from input pool */
2797 			indexes[ best ] = -1;
2798 			indexes[ best + 1 ] = -1;
2799 			indexes[ best + 2 ] = -1;
2800 
2801 			/* sort triangle windings (312 -> 123) */
2802 			while ( ds->indexes[ i ] > ds->indexes[ i + 1 ] || ds->indexes[ i ] > ds->indexes[ i + 2 ] )
2803 			{
2804 				temp = ds->indexes[ i ];
2805 				ds->indexes[ i ] = ds->indexes[ i + 1 ];
2806 				ds->indexes[ i + 1 ] = ds->indexes[ i + 2 ];
2807 				ds->indexes[ i + 2 ] = temp;
2808 			}
2809 		}
2810 	}
2811 
2812 	/* clean up */
2813 	free( indexes );
2814 }
2815 
2816 
2817 
2818 /*
2819    EmitTriangleSurface()
2820    creates a bsp drawsurface from arbitrary triangle surfaces
2821  */
2822 
EmitTriangleSurface(mapDrawSurface_t * ds)2823 void EmitTriangleSurface( mapDrawSurface_t *ds ){
2824 	int i, temp;
2825 	bspDrawSurface_t        *out;
2826 
2827 	/* invert the surface if necessary */
2828 	if ( ds->backSide || ds->shaderInfo->invert ) {
2829 		/* walk the indexes, reverse the triangle order */
2830 		for ( i = 0; i < ds->numIndexes; i += 3 )
2831 		{
2832 			temp = ds->indexes[ i ];
2833 			ds->indexes[ i ] = ds->indexes[ i + 1 ];
2834 			ds->indexes[ i + 1 ] = temp;
2835 		}
2836 
2837 		/* walk the verts, flip the normal */
2838 		for ( i = 0; i < ds->numVerts; i++ )
2839 			VectorScale( ds->verts[ i ].normal, -1.0f, ds->verts[ i ].normal );
2840 
2841 		/* invert facing */
2842 		VectorScale( ds->lightmapVecs[ 2 ], -1.0f, ds->lightmapVecs[ 2 ] );
2843 	}
2844 
2845 	/* allocate a new surface */
2846 	if ( numBSPDrawSurfaces == MAX_MAP_DRAW_SURFS ) {
2847 		Error( "MAX_MAP_DRAW_SURFS" );
2848 	}
2849 	out = &bspDrawSurfaces[ numBSPDrawSurfaces ];
2850 	ds->outputNum = numBSPDrawSurfaces;
2851 	numBSPDrawSurfaces++;
2852 	memset( out, 0, sizeof( *out ) );
2853 
2854 	/* ydnar/sd: handle wolf et foliage surfaces */
2855 	if ( ds->type == SURFACE_FOLIAGE ) {
2856 		out->surfaceType = MST_FOLIAGE;
2857 	}
2858 
2859 	/* ydnar: gs mods: handle lightmapped terrain (force to planar type) */
2860 	//%	else if( VectorLength( ds->lightmapAxis ) <= 0.0f || ds->type == SURFACE_TRIANGLES || ds->type == SURFACE_FOGHULL || debugSurfaces )
2861 	else if ( ( VectorLength( ds->lightmapAxis ) <= 0.0f && ds->planar == qfalse ) ||
2862 			  ds->type == SURFACE_TRIANGLES ||
2863 			  ds->type == SURFACE_FOGHULL ||
2864 			  ds->numVerts > maxLMSurfaceVerts ||
2865 			  debugSurfaces ) {
2866 		out->surfaceType = MST_TRIANGLE_SOUP;
2867 	}
2868 
2869 	/* set to a planar face */
2870 	else{
2871 		out->surfaceType = MST_PLANAR;
2872 	}
2873 
2874 	/* set it up */
2875 	if ( debugSurfaces ) {
2876 		out->shaderNum = EmitShader( "debugsurfaces", NULL, NULL );
2877 	}
2878 	else{
2879 		out->shaderNum = EmitShader( ds->shaderInfo->shader, &ds->shaderInfo->contentFlags, &ds->shaderInfo->surfaceFlags );
2880 	}
2881 	out->patchWidth = ds->patchWidth;
2882 	out->patchHeight = ds->patchHeight;
2883 	out->fogNum = ds->fogNum;
2884 
2885 	/* debug inset (push each triangle vertex towards the center of each triangle it is on */
2886 	if ( debugInset ) {
2887 		bspDrawVert_t   *a, *b, *c;
2888 		vec3_t cent, dir;
2889 
2890 
2891 		/* walk triangle list */
2892 		for ( i = 0; i < ds->numIndexes; i += 3 )
2893 		{
2894 			/* get verts */
2895 			a = &ds->verts[ ds->indexes[ i ] ];
2896 			b = &ds->verts[ ds->indexes[ i + 1 ] ];
2897 			c = &ds->verts[ ds->indexes[ i + 2 ] ];
2898 
2899 			/* calculate centroid */
2900 			VectorCopy( a->xyz, cent );
2901 			VectorAdd( cent, b->xyz, cent );
2902 			VectorAdd( cent, c->xyz, cent );
2903 			VectorScale( cent, 1.0f / 3.0f, cent );
2904 
2905 			/* offset each vertex */
2906 			VectorSubtract( cent, a->xyz, dir );
2907 			VectorNormalize( dir, dir );
2908 			VectorAdd( a->xyz, dir, a->xyz );
2909 			VectorSubtract( cent, b->xyz, dir );
2910 			VectorNormalize( dir, dir );
2911 			VectorAdd( b->xyz, dir, b->xyz );
2912 			VectorSubtract( cent, c->xyz, dir );
2913 			VectorNormalize( dir, dir );
2914 			VectorAdd( c->xyz, dir, c->xyz );
2915 		}
2916 	}
2917 
2918 	/* RBSP */
2919 	for ( i = 0; i < MAX_LIGHTMAPS; i++ )
2920 	{
2921 		out->lightmapNum[ i ] = -3;
2922 		out->lightmapStyles[ i ] = LS_NONE;
2923 		out->vertexStyles[ i ] = LS_NONE;
2924 	}
2925 	out->lightmapStyles[ 0 ] = LS_NORMAL;
2926 	out->vertexStyles[ 0 ] = LS_NORMAL;
2927 
2928 	/* lightmap vectors (lod bounds for patches */
2929 	VectorCopy( ds->lightmapOrigin, out->lightmapOrigin );
2930 	VectorCopy( ds->lightmapVecs[ 0 ], out->lightmapVecs[ 0 ] );
2931 	VectorCopy( ds->lightmapVecs[ 1 ], out->lightmapVecs[ 1 ] );
2932 	VectorCopy( ds->lightmapVecs[ 2 ], out->lightmapVecs[ 2 ] );
2933 
2934 	/* ydnar: gs mods: clear out the plane normal */
2935 	if ( ds->planar == qfalse ) {
2936 		VectorClear( out->lightmapVecs[ 2 ] );
2937 	}
2938 
2939 	/* optimize the surface's triangles */
2940 	OptimizeTriangleSurface( ds );
2941 
2942 	/* emit the verts and indexes */
2943 	EmitDrawVerts( ds, out );
2944 	EmitDrawIndexes( ds, out );
2945 
2946 	/* add to count */
2947 	numSurfacesByType[ ds->type ]++;
2948 }
2949 
2950 
2951 
2952 /*
2953    EmitFaceSurface()
2954    emits a bsp planar winding (brush face) drawsurface
2955  */
2956 
EmitFaceSurface(mapDrawSurface_t * ds)2957 static void EmitFaceSurface( mapDrawSurface_t *ds ){
2958 	/* strip/fan finding was moved elsewhere */
2959 	if ( maxAreaFaceSurface ) {
2960 		MaxAreaFaceSurface( ds );
2961 	}
2962 	else{
2963 		StripFaceSurface( ds );
2964 	}
2965 	EmitTriangleSurface( ds );
2966 }
2967 
2968 
2969 /*
2970    MakeDebugPortalSurfs_r() - ydnar
2971    generates drawsurfaces for passable portals in the bsp
2972  */
2973 
MakeDebugPortalSurfs_r(node_t * node,shaderInfo_t * si)2974 static void MakeDebugPortalSurfs_r( node_t *node, shaderInfo_t *si ){
2975 	int i, k, c, s;
2976 	portal_t            *p;
2977 	winding_t           *w;
2978 	mapDrawSurface_t    *ds;
2979 	bspDrawVert_t       *dv;
2980 
2981 
2982 	/* recurse if decision node */
2983 	if ( node->planenum != PLANENUM_LEAF ) {
2984 		MakeDebugPortalSurfs_r( node->children[ 0 ], si );
2985 		MakeDebugPortalSurfs_r( node->children[ 1 ], si );
2986 		return;
2987 	}
2988 
2989 	/* don't bother with opaque leaves */
2990 	if ( node->opaque ) {
2991 		return;
2992 	}
2993 
2994 	/* walk the list of portals */
2995 	for ( c = 0, p = node->portals; p != NULL; c++, p = p->next[ s ] )
2996 	{
2997 		/* get winding and side even/odd */
2998 		w = p->winding;
2999 		s = ( p->nodes[ 1 ] == node );
3000 
3001 		/* is this a valid portal for this leaf? */
3002 		if ( w && p->nodes[ 0 ] == node ) {
3003 			/* is this portal passable? */
3004 			if ( PortalPassable( p ) == qfalse ) {
3005 				continue;
3006 			}
3007 
3008 			/* check max points */
3009 			if ( w->numpoints > 64 ) {
3010 				Error( "MakePortalSurfs_r: w->numpoints = %d", w->numpoints );
3011 			}
3012 
3013 			/* allocate a drawsurface */
3014 			ds = AllocDrawSurface( SURFACE_FACE );
3015 			ds->shaderInfo = si;
3016 			ds->planar = qtrue;
3017 			ds->sideRef = AllocSideRef( p->side, NULL );
3018 			ds->planeNum = FindFloatPlane( p->plane.normal, p->plane.dist, 0, NULL );
3019 			VectorCopy( p->plane.normal, ds->lightmapVecs[ 2 ] );
3020 			ds->fogNum = -1;
3021 			ds->numVerts = w->numpoints;
3022 			ds->verts = safe_malloc( ds->numVerts * sizeof( *ds->verts ) );
3023 			memset( ds->verts, 0, ds->numVerts * sizeof( *ds->verts ) );
3024 
3025 			/* walk the winding */
3026 			for ( i = 0; i < ds->numVerts; i++ )
3027 			{
3028 				/* get vert */
3029 				dv = ds->verts + i;
3030 
3031 				/* set it */
3032 				VectorCopy( w->p[ i ], dv->xyz );
3033 				VectorCopy( p->plane.normal, dv->normal );
3034 				dv->st[ 0 ] = 0;
3035 				dv->st[ 1 ] = 0;
3036 				for ( k = 0; k < MAX_LIGHTMAPS; k++ )
3037 				{
3038 					VectorCopy( debugColors[ c % 12 ], dv->color[ k ] );
3039 					dv->color[ k ][ 3 ] = 32;
3040 				}
3041 			}
3042 		}
3043 	}
3044 }
3045 
3046 
3047 
3048 /*
3049    MakeDebugPortalSurfs() - ydnar
3050    generates drawsurfaces for passable portals in the bsp
3051  */
3052 
MakeDebugPortalSurfs(tree_t * tree)3053 void MakeDebugPortalSurfs( tree_t *tree ){
3054 	shaderInfo_t    *si;
3055 
3056 
3057 	/* note it */
3058 	Sys_FPrintf( SYS_VRB, "--- MakeDebugPortalSurfs ---\n" );
3059 
3060 	/* get portal debug shader */
3061 	si = ShaderInfoForShader( "debugportals" );
3062 
3063 	/* walk the tree */
3064 	MakeDebugPortalSurfs_r( tree->headnode, si );
3065 }
3066 
3067 
3068 
3069 /*
3070    MakeFogHullSurfs()
3071    generates drawsurfaces for a foghull (this MUST use a sky shader)
3072  */
3073 
MakeFogHullSurfs(entity_t * e,tree_t * tree,char * shader)3074 void MakeFogHullSurfs( entity_t *e, tree_t *tree, char *shader ){
3075 	shaderInfo_t        *si;
3076 	mapDrawSurface_t    *ds;
3077 	vec3_t fogMins, fogMaxs;
3078 	int i, indexes[] =
3079 	{
3080 		0, 1, 2, 0, 2, 3,
3081 		4, 7, 5, 5, 7, 6,
3082 		1, 5, 6, 1, 6, 2,
3083 		0, 4, 5, 0, 5, 1,
3084 		2, 6, 7, 2, 7, 3,
3085 		3, 7, 4, 3, 4, 0
3086 	};
3087 
3088 
3089 	/* dummy check */
3090 	if ( shader == NULL || shader[ 0 ] == '\0' ) {
3091 		return;
3092 	}
3093 
3094 	/* note it */
3095 	Sys_FPrintf( SYS_VRB, "--- MakeFogHullSurfs ---\n" );
3096 
3097 	/* get hull bounds */
3098 	VectorCopy( mapMins, fogMins );
3099 	VectorCopy( mapMaxs, fogMaxs );
3100 	for ( i = 0; i < 3; i++ )
3101 	{
3102 		fogMins[ i ] -= 128;
3103 		fogMaxs[ i ] += 128;
3104 	}
3105 
3106 	/* get foghull shader */
3107 	si = ShaderInfoForShader( shader );
3108 
3109 	/* allocate a drawsurface */
3110 	ds = AllocDrawSurface( SURFACE_FOGHULL );
3111 	ds->shaderInfo = si;
3112 	ds->fogNum = -1;
3113 	ds->numVerts = 8;
3114 	ds->verts = safe_malloc( ds->numVerts * sizeof( *ds->verts ) );
3115 	memset( ds->verts, 0, ds->numVerts * sizeof( *ds->verts ) );
3116 	ds->numIndexes = 36;
3117 	ds->indexes = safe_malloc( ds->numIndexes * sizeof( *ds->indexes ) );
3118 	memset( ds->indexes, 0, ds->numIndexes * sizeof( *ds->indexes ) );
3119 
3120 	/* set verts */
3121 	VectorSet( ds->verts[ 0 ].xyz, fogMins[ 0 ], fogMins[ 1 ], fogMins[ 2 ] );
3122 	VectorSet( ds->verts[ 1 ].xyz, fogMins[ 0 ], fogMaxs[ 1 ], fogMins[ 2 ] );
3123 	VectorSet( ds->verts[ 2 ].xyz, fogMaxs[ 0 ], fogMaxs[ 1 ], fogMins[ 2 ] );
3124 	VectorSet( ds->verts[ 3 ].xyz, fogMaxs[ 0 ], fogMins[ 1 ], fogMins[ 2 ] );
3125 
3126 	VectorSet( ds->verts[ 4 ].xyz, fogMins[ 0 ], fogMins[ 1 ], fogMaxs[ 2 ] );
3127 	VectorSet( ds->verts[ 5 ].xyz, fogMins[ 0 ], fogMaxs[ 1 ], fogMaxs[ 2 ] );
3128 	VectorSet( ds->verts[ 6 ].xyz, fogMaxs[ 0 ], fogMaxs[ 1 ], fogMaxs[ 2 ] );
3129 	VectorSet( ds->verts[ 7 ].xyz, fogMaxs[ 0 ], fogMins[ 1 ], fogMaxs[ 2 ] );
3130 
3131 	/* set indexes */
3132 	memcpy( ds->indexes, indexes, ds->numIndexes * sizeof( *ds->indexes ) );
3133 }
3134 
3135 
3136 
3137 /*
3138    BiasSurfaceTextures()
3139    biases a surface's texcoords as close to 0 as possible
3140  */
3141 
BiasSurfaceTextures(mapDrawSurface_t * ds)3142 void BiasSurfaceTextures( mapDrawSurface_t *ds ){
3143 	int i;
3144 
3145 
3146 	/* calculate the surface texture bias */
3147 	CalcSurfaceTextureRange( ds );
3148 
3149 	/* don't bias globaltextured shaders */
3150 	if ( ds->shaderInfo->globalTexture ) {
3151 		return;
3152 	}
3153 
3154 	/* bias the texture coordinates */
3155 	for ( i = 0; i < ds->numVerts; i++ )
3156 	{
3157 		ds->verts[ i ].st[ 0 ] += ds->bias[ 0 ];
3158 		ds->verts[ i ].st[ 1 ] += ds->bias[ 1 ];
3159 	}
3160 }
3161 
3162 
3163 
3164 /*
3165    AddSurfaceModelsToTriangle_r()
3166    adds models to a specified triangle, returns the number of models added
3167  */
3168 
AddSurfaceModelsToTriangle_r(mapDrawSurface_t * ds,surfaceModel_t * model,bspDrawVert_t ** tri)3169 int AddSurfaceModelsToTriangle_r( mapDrawSurface_t *ds, surfaceModel_t *model, bspDrawVert_t **tri ){
3170 	bspDrawVert_t mid, *tri2[ 3 ];
3171 	int max, n, localNumSurfaceModels;
3172 
3173 
3174 	/* init */
3175 	localNumSurfaceModels = 0;
3176 
3177 	/* subdivide calc */
3178 	{
3179 		int i;
3180 		float       *a, *b, dx, dy, dz, dist, maxDist;
3181 
3182 
3183 		/* find the longest edge and split it */
3184 		max = -1;
3185 		maxDist = 0.0f;
3186 		for ( i = 0; i < 3; i++ )
3187 		{
3188 			/* get verts */
3189 			a = tri[ i ]->xyz;
3190 			b = tri[ ( i + 1 ) % 3 ]->xyz;
3191 
3192 			/* get dists */
3193 			dx = a[ 0 ] - b[ 0 ];
3194 			dy = a[ 1 ] - b[ 1 ];
3195 			dz = a[ 2 ] - b[ 2 ];
3196 			dist = ( dx * dx ) + ( dy * dy ) + ( dz * dz );
3197 
3198 			/* longer? */
3199 			if ( dist > maxDist ) {
3200 				maxDist = dist;
3201 				max = i;
3202 			}
3203 		}
3204 
3205 		/* is the triangle small enough? */
3206 		if ( max < 0 || maxDist <= ( model->density * model->density ) ) {
3207 			float odds, r, angle;
3208 			vec3_t origin, normal, scale, axis[ 3 ], angles;
3209 			m4x4_t transform, temp;
3210 
3211 
3212 			/* roll the dice (model's odds scaled by vertex alpha) */
3213 			odds = model->odds * ( tri[ 0 ]->color[ 0 ][ 3 ] + tri[ 0 ]->color[ 0 ][ 3 ] + tri[ 0 ]->color[ 0 ][ 3 ] ) / 765.0f;
3214 			r = Random();
3215 			if ( r > odds ) {
3216 				return 0;
3217 			}
3218 
3219 			/* calculate scale */
3220 			r = model->minScale + Random() * ( model->maxScale - model->minScale );
3221 			VectorSet( scale, r, r, r );
3222 
3223 			/* calculate angle */
3224 			angle = model->minAngle + Random() * ( model->maxAngle - model->minAngle );
3225 
3226 			/* calculate average origin */
3227 			VectorCopy( tri[ 0 ]->xyz, origin );
3228 			VectorAdd( origin, tri[ 1 ]->xyz, origin );
3229 			VectorAdd( origin, tri[ 2 ]->xyz, origin );
3230 			VectorScale( origin, ( 1.0f / 3.0f ), origin );
3231 
3232 			/* clear transform matrix */
3233 			m4x4_identity( transform );
3234 
3235 			/* handle oriented models */
3236 			if ( model->oriented ) {
3237 				/* set angles */
3238 				VectorSet( angles, 0.0f, 0.0f, angle );
3239 
3240 				/* calculate average normal */
3241 				VectorCopy( tri[ 0 ]->normal, normal );
3242 				VectorAdd( normal, tri[ 1 ]->normal, normal );
3243 				VectorAdd( normal, tri[ 2 ]->normal, normal );
3244 				if ( VectorNormalize( normal, axis[ 2 ] ) == 0.0f ) {
3245 					VectorCopy( tri[ 0 ]->normal, axis[ 2 ] );
3246 				}
3247 
3248 				/* make perpendicular vectors */
3249 				MakeNormalVectors( axis[ 2 ], axis[ 1 ], axis[ 0 ] );
3250 
3251 				/* copy to matrix */
3252 				m4x4_identity( temp );
3253 				temp[ 0 ] = axis[ 0 ][ 0 ]; temp[ 1 ] = axis[ 0 ][ 1 ]; temp[ 2 ] = axis[ 0 ][ 2 ];
3254 				temp[ 4 ] = axis[ 1 ][ 0 ]; temp[ 5 ] = axis[ 1 ][ 1 ]; temp[ 6 ] = axis[ 1 ][ 2 ];
3255 				temp[ 8 ] = axis[ 2 ][ 0 ]; temp[ 9 ] = axis[ 2 ][ 1 ]; temp[ 10 ] = axis[ 2 ][ 2 ];
3256 
3257 				/* scale */
3258 				m4x4_scale_by_vec3( temp, scale );
3259 
3260 				/* rotate around z axis */
3261 				m4x4_rotate_by_vec3( temp, angles, eXYZ );
3262 
3263 				/* translate */
3264 				m4x4_translate_by_vec3( transform, origin );
3265 
3266 				/* tranform into axis space */
3267 				m4x4_multiply_by_m4x4( transform, temp );
3268 			}
3269 
3270 			/* handle z-up models */
3271 			else
3272 			{
3273 				/* set angles */
3274 				VectorSet( angles, 0.0f, 0.0f, angle );
3275 
3276 				/* set matrix */
3277 				m4x4_pivoted_transform_by_vec3( transform, origin, angles, eXYZ, scale, vec3_origin );
3278 			}
3279 
3280 			/* insert the model */
3281 			InsertModel( (char *) model->model, 0, 0, transform, NULL, ds->celShader, ds->entityNum, ds->castShadows, ds->recvShadows, 0, ds->lightmapScale, 0, 0 );
3282 
3283 			/* return to sender */
3284 			return 1;
3285 		}
3286 	}
3287 
3288 	/* split the longest edge and map it */
3289 	LerpDrawVert( tri[ max ], tri[ ( max + 1 ) % 3 ], &mid );
3290 
3291 	/* recurse to first triangle */
3292 	VectorCopy( tri, tri2 );
3293 	tri2[ max ] = &mid;
3294 	n = AddSurfaceModelsToTriangle_r( ds, model, tri2 );
3295 	if ( n < 0 ) {
3296 		return n;
3297 	}
3298 	localNumSurfaceModels += n;
3299 
3300 	/* recurse to second triangle */
3301 	VectorCopy( tri, tri2 );
3302 	tri2[ ( max + 1 ) % 3 ] = &mid;
3303 	n = AddSurfaceModelsToTriangle_r( ds, model, tri2 );
3304 	if ( n < 0 ) {
3305 		return n;
3306 	}
3307 	localNumSurfaceModels += n;
3308 
3309 	/* return count */
3310 	return localNumSurfaceModels;
3311 }
3312 
3313 
3314 
3315 /*
3316    AddSurfaceModels()
3317    adds a surface's shader models to the surface
3318  */
3319 
AddSurfaceModels(mapDrawSurface_t * ds)3320 int AddSurfaceModels( mapDrawSurface_t *ds ){
3321 	surfaceModel_t  *model;
3322 	int i, x, y, n, pw[ 5 ], r, localNumSurfaceModels, iterations;
3323 	mesh_t src, *mesh, *subdivided;
3324 	bspDrawVert_t centroid, *tri[ 3 ];
3325 	float alpha;
3326 
3327 
3328 	/* dummy check */
3329 	if ( ds == NULL || ds->shaderInfo == NULL || ds->shaderInfo->surfaceModel == NULL ) {
3330 		return 0;
3331 	}
3332 
3333 	/* init */
3334 	localNumSurfaceModels = 0;
3335 
3336 	/* walk the model list */
3337 	for ( model = ds->shaderInfo->surfaceModel; model != NULL; model = model->next )
3338 	{
3339 		/* switch on type */
3340 		switch ( ds->type )
3341 		{
3342 		/* handle brush faces and decals */
3343 		case SURFACE_FACE:
3344 		case SURFACE_DECAL:
3345 			/* calculate centroid */
3346 			memset( &centroid, 0, sizeof( centroid ) );
3347 			alpha = 0.0f;
3348 
3349 			/* walk verts */
3350 			for ( i = 0; i < ds->numVerts; i++ )
3351 			{
3352 				VectorAdd( centroid.xyz, ds->verts[ i ].xyz, centroid.xyz );
3353 				VectorAdd( centroid.normal, ds->verts[ i ].normal, centroid.normal );
3354 				centroid.st[ 0 ] += ds->verts[ i ].st[ 0 ];
3355 				centroid.st[ 1 ] += ds->verts[ i ].st[ 1 ];
3356 				alpha += ds->verts[ i ].color[ 0 ][ 3 ];
3357 			}
3358 
3359 			/* average */
3360 			centroid.xyz[ 0 ] /= ds->numVerts;
3361 			centroid.xyz[ 1 ] /= ds->numVerts;
3362 			centroid.xyz[ 2 ] /= ds->numVerts;
3363 			if ( VectorNormalize( centroid.normal, centroid.normal ) == 0.0f ) {
3364 				VectorCopy( ds->verts[ 0 ].normal, centroid.normal );
3365 			}
3366 			centroid.st[ 0 ]  /= ds->numVerts;
3367 			centroid.st[ 1 ]  /= ds->numVerts;
3368 			alpha /= ds->numVerts;
3369 			centroid.color[ 0 ][ 0 ] = 0xFF;
3370 			centroid.color[ 0 ][ 1 ] = 0xFF;
3371 			centroid.color[ 0 ][ 2 ] = 0xFF;
3372 			centroid.color[ 0 ][ 2 ] = ( alpha > 255.0f ? 0xFF : alpha );
3373 
3374 			/* head vert is centroid */
3375 			tri[ 0 ] = &centroid;
3376 
3377 			/* walk fanned triangles */
3378 			for ( i = 0; i < ds->numVerts; i++ )
3379 			{
3380 				/* set triangle */
3381 				tri[ 1 ] = &ds->verts[ i ];
3382 				tri[ 2 ] = &ds->verts[ ( i + 1 ) % ds->numVerts ];
3383 
3384 				/* create models */
3385 				n = AddSurfaceModelsToTriangle_r( ds, model, tri );
3386 				if ( n < 0 ) {
3387 					return n;
3388 				}
3389 				localNumSurfaceModels += n;
3390 			}
3391 			break;
3392 
3393 		/* handle patches */
3394 		case SURFACE_PATCH:
3395 			/* subdivide the surface */
3396 			src.width = ds->patchWidth;
3397 			src.height = ds->patchHeight;
3398 			src.verts = ds->verts;
3399 			//%	subdivided = SubdivideMesh( src, 8.0f, 512 );
3400 			iterations = IterationsForCurve( ds->longestCurve, patchSubdivisions );
3401 			subdivided = SubdivideMesh2( src, iterations );
3402 
3403 			/* fit it to the curve and remove colinear verts on rows/columns */
3404 			PutMeshOnCurve( *subdivided );
3405 			mesh = RemoveLinearMeshColumnsRows( subdivided );
3406 			FreeMesh( subdivided );
3407 
3408 			/* subdivide each quad to place the models */
3409 			for ( y = 0; y < ( mesh->height - 1 ); y++ )
3410 			{
3411 				for ( x = 0; x < ( mesh->width - 1 ); x++ )
3412 				{
3413 					/* set indexes */
3414 					pw[ 0 ] = x + ( y * mesh->width );
3415 					pw[ 1 ] = x + ( ( y + 1 ) * mesh->width );
3416 					pw[ 2 ] = x + 1 + ( ( y + 1 ) * mesh->width );
3417 					pw[ 3 ] = x + 1 + ( y * mesh->width );
3418 					pw[ 4 ] = x + ( y * mesh->width );      /* same as pw[ 0 ] */
3419 
3420 					/* set radix */
3421 					r = ( x + y ) & 1;
3422 
3423 					/* triangle 1 */
3424 					tri[ 0 ] = &mesh->verts[ pw[ r + 0 ] ];
3425 					tri[ 1 ] = &mesh->verts[ pw[ r + 1 ] ];
3426 					tri[ 2 ] = &mesh->verts[ pw[ r + 2 ] ];
3427 					n = AddSurfaceModelsToTriangle_r( ds, model, tri );
3428 					if ( n < 0 ) {
3429 						return n;
3430 					}
3431 					localNumSurfaceModels += n;
3432 
3433 					/* triangle 2 */
3434 					tri[ 0 ] = &mesh->verts[ pw[ r + 0 ] ];
3435 					tri[ 1 ] = &mesh->verts[ pw[ r + 2 ] ];
3436 					tri[ 2 ] = &mesh->verts[ pw[ r + 3 ] ];
3437 					n = AddSurfaceModelsToTriangle_r( ds, model, tri );
3438 					if ( n < 0 ) {
3439 						return n;
3440 					}
3441 					localNumSurfaceModels += n;
3442 				}
3443 			}
3444 
3445 			/* free the subdivided mesh */
3446 			FreeMesh( mesh );
3447 			break;
3448 
3449 		/* handle triangle surfaces */
3450 		case SURFACE_TRIANGLES:
3451 		case SURFACE_FORCED_META:
3452 		case SURFACE_META:
3453 			/* walk the triangle list */
3454 			for ( i = 0; i < ds->numIndexes; i += 3 )
3455 			{
3456 				tri[ 0 ] = &ds->verts[ ds->indexes[ i ] ];
3457 				tri[ 1 ] = &ds->verts[ ds->indexes[ i + 1 ] ];
3458 				tri[ 2 ] = &ds->verts[ ds->indexes[ i + 2 ] ];
3459 				n = AddSurfaceModelsToTriangle_r( ds, model, tri );
3460 				if ( n < 0 ) {
3461 					return n;
3462 				}
3463 				localNumSurfaceModels += n;
3464 			}
3465 			break;
3466 
3467 		/* no support for flares, foghull, etc */
3468 		default:
3469 			break;
3470 		}
3471 	}
3472 
3473 	/* return count */
3474 	return localNumSurfaceModels;
3475 }
3476 
3477 
3478 
3479 /*
3480    AddEntitySurfaceModels() - ydnar
3481    adds surfacemodels to an entity's surfaces
3482  */
3483 
AddEntitySurfaceModels(entity_t * e)3484 void AddEntitySurfaceModels( entity_t *e ){
3485 	int i;
3486 
3487 
3488 	/* note it */
3489 	Sys_FPrintf( SYS_VRB, "--- AddEntitySurfaceModels ---\n" );
3490 
3491 	/* walk the surface list */
3492 	for ( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ )
3493 		numSurfaceModels += AddSurfaceModels( &mapDrawSurfs[ i ] );
3494 }
3495 
3496 
3497 
3498 /*
3499    VolumeColorMods() - ydnar
3500    applies brush/volumetric color/alpha modulation to vertexes
3501  */
3502 
VolumeColorMods(entity_t * e,mapDrawSurface_t * ds)3503 static void VolumeColorMods( entity_t *e, mapDrawSurface_t *ds ){
3504 	int i, j;
3505 	float d;
3506 	brush_t     *b;
3507 	plane_t     *plane;
3508 
3509 
3510 	/* early out */
3511 	if ( e->colorModBrushes == NULL ) {
3512 		return;
3513 	}
3514 
3515 	/* iterate brushes */
3516 	for ( b = e->colorModBrushes; b != NULL; b = b->nextColorModBrush )
3517 	{
3518 		/* worldspawn alpha brushes affect all, grouped ones only affect original entity */
3519 		if ( b->entityNum != 0 && b->entityNum != ds->entityNum ) {
3520 			continue;
3521 		}
3522 
3523 		/* test bbox */
3524 		if ( b->mins[ 0 ] > ds->maxs[ 0 ] || b->maxs[ 0 ] < ds->mins[ 0 ] ||
3525 			 b->mins[ 1 ] > ds->maxs[ 1 ] || b->maxs[ 1 ] < ds->mins[ 1 ] ||
3526 			 b->mins[ 2 ] > ds->maxs[ 2 ] || b->maxs[ 2 ] < ds->mins[ 2 ] ) {
3527 			continue;
3528 		}
3529 
3530 		/* iterate verts */
3531 		for ( i = 0; i < ds->numVerts; i++ )
3532 		{
3533 			/* iterate planes */
3534 			for ( j = 0; j < b->numsides; j++ )
3535 			{
3536 				/* point-plane test */
3537 				plane = &mapplanes[ b->sides[ j ].planenum ];
3538 				d = DotProduct( ds->verts[ i ].xyz, plane->normal ) - plane->dist;
3539 				if ( d > 1.0f ) {
3540 					break;
3541 				}
3542 			}
3543 
3544 			/* apply colormods */
3545 			if ( j == b->numsides ) {
3546 				ColorMod( b->contentShader->colorMod, 1, &ds->verts[ i ] );
3547 			}
3548 		}
3549 	}
3550 }
3551 
3552 
3553 
3554 /*
3555    FilterDrawsurfsIntoTree()
3556    upon completion, all drawsurfs that actually generate a reference
3557    will have been emited to the bspfile arrays, and the references
3558    will have valid final indexes
3559  */
3560 
FilterDrawsurfsIntoTree(entity_t * e,tree_t * tree)3561 void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree ){
3562 	int i, j;
3563 	mapDrawSurface_t    *ds;
3564 	shaderInfo_t        *si;
3565 	vec3_t origin, mins, maxs;
3566 	int refs;
3567 	int numSurfs, numRefs, numSkyboxSurfaces;
3568 	qboolean sb;
3569 
3570 
3571 	/* note it */
3572 	Sys_FPrintf( SYS_VRB, "--- FilterDrawsurfsIntoTree ---\n" );
3573 
3574 	/* filter surfaces into the tree */
3575 	numSurfs = 0;
3576 	numRefs = 0;
3577 	numSkyboxSurfaces = 0;
3578 	for ( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ )
3579 	{
3580 		/* get surface and try to early out */
3581 		ds = &mapDrawSurfs[ i ];
3582 		if ( ds->numVerts == 0 && ds->type != SURFACE_FLARE && ds->type != SURFACE_SHADER ) {
3583 			continue;
3584 		}
3585 
3586 		/* get shader */
3587 		si = ds->shaderInfo;
3588 
3589 		/* ydnar: skybox surfaces are special */
3590 		if ( ds->skybox ) {
3591 			refs = AddReferenceToTree_r( ds, tree->headnode, qtrue );
3592 			ds->skybox = qfalse;
3593 			sb = qtrue;
3594 		}
3595 		else
3596 		{
3597 			sb = qfalse;
3598 
3599 			/* refs initially zero */
3600 			refs = 0;
3601 
3602 			/* apply texture coordinate mods */
3603 			for ( j = 0; j < ds->numVerts; j++ )
3604 				TCMod( si->mod, ds->verts[ j ].st );
3605 
3606 			/* ydnar: apply shader colormod */
3607 			ColorMod( ds->shaderInfo->colorMod, ds->numVerts, ds->verts );
3608 
3609 			/* ydnar: apply brush colormod */
3610 			VolumeColorMods( e, ds );
3611 
3612 			/* ydnar: make fur surfaces */
3613 			if ( si->furNumLayers > 0 ) {
3614 				Fur( ds );
3615 			}
3616 
3617 			/* ydnar/sd: make foliage surfaces */
3618 			if ( si->foliage != NULL ) {
3619 				Foliage( ds );
3620 			}
3621 
3622 			/* create a flare surface if necessary */
3623 			if ( si->flareShader != NULL && si->flareShader[ 0 ] ) {
3624 				AddSurfaceFlare( ds, e->origin );
3625 			}
3626 
3627 			/* ydnar: don't emit nodraw surfaces (like nodraw fog) */
3628 			if ( ( si->compileFlags & C_NODRAW ) && ds->type != SURFACE_PATCH ) {
3629 				continue;
3630 			}
3631 
3632 			/* ydnar: bias the surface textures */
3633 			BiasSurfaceTextures( ds );
3634 
3635 			/* ydnar: globalizing of fog volume handling (eek a hack) */
3636 			if ( e != entities && si->noFog == qfalse ) {
3637 				/* find surface origin and offset by entity origin */
3638 				VectorAdd( ds->mins, ds->maxs, origin );
3639 				VectorScale( origin, 0.5f, origin );
3640 				VectorAdd( origin, e->origin, origin );
3641 
3642 				VectorAdd( ds->mins, e->origin, mins );
3643 				VectorAdd( ds->maxs, e->origin, maxs );
3644 
3645 				/* set the fog number for this surface */
3646 				ds->fogNum = FogForBounds( mins, maxs, 1.0f );  //%	FogForPoint( origin, 0.0f );
3647 			}
3648 		}
3649 
3650 		/* ydnar: remap shader */
3651 		if ( ds->shaderInfo->remapShader && ds->shaderInfo->remapShader[ 0 ] ) {
3652 			ds->shaderInfo = ShaderInfoForShader( ds->shaderInfo->remapShader );
3653 		}
3654 
3655 		/* ydnar: gs mods: handle the various types of surfaces */
3656 		switch ( ds->type )
3657 		{
3658 		/* handle brush faces */
3659 		case SURFACE_FACE:
3660 		case SURFACE_DECAL:
3661 			if ( refs == 0 ) {
3662 				refs = FilterFaceIntoTree( ds, tree );
3663 			}
3664 			if ( refs > 0 ) {
3665 				EmitFaceSurface( ds );
3666 			}
3667 			break;
3668 
3669 		/* handle patches */
3670 		case SURFACE_PATCH:
3671 			if ( refs == 0 ) {
3672 				refs = FilterPatchIntoTree( ds, tree );
3673 			}
3674 			if ( refs > 0 ) {
3675 				EmitPatchSurface( e, ds );
3676 			}
3677 			break;
3678 
3679 		/* handle triangle surfaces */
3680 		case SURFACE_TRIANGLES:
3681 		case SURFACE_FORCED_META:
3682 		case SURFACE_META:
3683 			//%	Sys_FPrintf( SYS_VRB, "Surface %4d: [%1d] %4d verts %s\n", numSurfs, ds->planar, ds->numVerts, si->shader );
3684 			if ( refs == 0 ) {
3685 				refs = FilterTrianglesIntoTree( ds, tree );
3686 			}
3687 			if ( refs > 0 ) {
3688 				EmitTriangleSurface( ds );
3689 			}
3690 			break;
3691 
3692 		/* handle foliage surfaces (splash damage/wolf et) */
3693 		case SURFACE_FOLIAGE:
3694 			//%	Sys_FPrintf( SYS_VRB, "Surface %4d: [%d] %4d verts %s\n", numSurfs, ds->numFoliageInstances, ds->numVerts, si->shader );
3695 			if ( refs == 0 ) {
3696 				refs = FilterFoliageIntoTree( ds, tree );
3697 			}
3698 			if ( refs > 0 ) {
3699 				EmitTriangleSurface( ds );
3700 			}
3701 			break;
3702 
3703 		/* handle foghull surfaces */
3704 		case SURFACE_FOGHULL:
3705 			if ( refs == 0 ) {
3706 				refs = AddReferenceToTree_r( ds, tree->headnode, qfalse );
3707 			}
3708 			if ( refs > 0 ) {
3709 				EmitTriangleSurface( ds );
3710 			}
3711 			break;
3712 
3713 		/* handle flares */
3714 		case SURFACE_FLARE:
3715 			if ( refs == 0 ) {
3716 				refs = FilterFlareSurfIntoTree( ds, tree );
3717 			}
3718 			if ( refs > 0 ) {
3719 				EmitFlareSurface( ds );
3720 			}
3721 			break;
3722 
3723 		/* handle shader-only surfaces */
3724 		case SURFACE_SHADER:
3725 			refs = 1;
3726 			EmitFlareSurface( ds );
3727 			break;
3728 
3729 		/* no references */
3730 		default:
3731 			refs = 0;
3732 			break;
3733 		}
3734 
3735 		/* maybe surface got marked as skybox again */
3736 		/* if we keep that flag, it will get scaled up AGAIN */
3737 		if ( sb ) {
3738 			ds->skybox = qfalse;
3739 		}
3740 
3741 		/* tot up the references */
3742 		if ( refs > 0 ) {
3743 			/* tot up counts */
3744 			numSurfs++;
3745 			numRefs += refs;
3746 
3747 			/* emit extra surface data */
3748 			SetSurfaceExtra( ds, numBSPDrawSurfaces - 1 );
3749 			//%	Sys_FPrintf( SYS_VRB, "%d verts %d indexes\n", ds->numVerts, ds->numIndexes );
3750 
3751 			/* one last sanity check */
3752 			{
3753 				bspDrawSurface_t    *out;
3754 				out = &bspDrawSurfaces[ numBSPDrawSurfaces - 1 ];
3755 				if ( out->numVerts == 3 && out->numIndexes > 3 ) {
3756 					Sys_Printf( "\nWARNING: Potentially bad %s surface (%d: %d, %d)\n     %s\n",
3757 								surfaceTypes[ ds->type ],
3758 								numBSPDrawSurfaces - 1, out->numVerts, out->numIndexes, si->shader );
3759 				}
3760 			}
3761 
3762 			/* ydnar: handle skybox surfaces */
3763 			if ( ds->skybox ) {
3764 				MakeSkyboxSurface( ds );
3765 				numSkyboxSurfaces++;
3766 			}
3767 		}
3768 	}
3769 
3770 	/* emit some statistics */
3771 	Sys_FPrintf( SYS_VRB, "%9d references\n", numRefs );
3772 	Sys_FPrintf( SYS_VRB, "%9d (%d) emitted drawsurfs\n", numSurfs, numBSPDrawSurfaces );
3773 	Sys_FPrintf( SYS_VRB, "%9d stripped face surfaces\n", numStripSurfaces );
3774 	Sys_FPrintf( SYS_VRB, "%9d fanned face surfaces\n", numFanSurfaces );
3775 	Sys_FPrintf( SYS_VRB, "%9d maxarea'd face surfaces\n", numMaxAreaSurfaces );
3776 	Sys_FPrintf( SYS_VRB, "%9d surface models generated\n", numSurfaceModels );
3777 	Sys_FPrintf( SYS_VRB, "%9d skybox surfaces generated\n", numSkyboxSurfaces );
3778 	for ( i = 0; i < NUM_SURFACE_TYPES; i++ )
3779 		Sys_FPrintf( SYS_VRB, "%9d %s surfaces\n", numSurfacesByType[ i ], surfaceTypes[ i ] );
3780 
3781 	Sys_FPrintf( SYS_VRB, "%9d redundant indexes supressed, saving %d Kbytes\n", numRedundantIndexes, ( numRedundantIndexes * 4 / 1024 ) );
3782 }
3783