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