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