]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/surface.c
a51db8c176c7e91f59c67e183da6db59bcc3f137
[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->type <= SURFACE_BAD || ds->type >= NUM_SURFACE_TYPES || ds == NULL || ds->shaderInfo == NULL ) {
86                 return;
87         }
88
89         /* ydnar: rocking tek-fu celshading */
90         if ( ds->celShader != NULL ) {
91                 MakeCelSurface( ds, ds->celShader );
92         }
93
94         /* backsides stop here */
95         if ( ds->backSide ) {
96                 return;
97         }
98
99         /* ydnar: rocking surface cloning (fur baby yeah!) */
100         if ( ds->shaderInfo->cloneShader != NULL && ds->shaderInfo->cloneShader[ 0 ] != '\0' ) {
101                 CloneSurface( ds, ShaderInfoForShader( ds->shaderInfo->cloneShader ) );
102         }
103
104         /* ydnar: q3map_backShader support */
105         if ( ds->shaderInfo->backShader != NULL && ds->shaderInfo->backShader[ 0 ] != '\0' ) {
106                 ds2 = CloneSurface( ds, ShaderInfoForShader( ds->shaderInfo->backShader ) );
107                 ds2->backSide = qtrue;
108         }
109 }
110
111
112
113 /*
114    CloneSurface()
115    clones a map drawsurface, using the specified shader
116  */
117
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 ) {
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, *p2;
2119         vec4_t plane1, plane2;
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                         /* get surface plane */
2174                         p2 = &mapplanes[ ds->planeNum ];
2175                         VectorCopy( p2->normal, plane2 );
2176                         plane2[ 3 ] = p2->dist;
2177
2178                         #if 0
2179                         /* div0: this is the plague (inaccurate) */
2180                         vec4_t reverse;
2181
2182                         /* invert surface plane */
2183                         VectorSubtract( vec3_origin, plane2, reverse );
2184                         reverse[ 3 ] = -plane2[ 3 ];
2185
2186                         /* compare planes */
2187                         if ( DotProduct( plane1, plane2 ) > 0.999f && fabs( plane1[ 3 ] - plane2[ 3 ] ) < 0.001f ) {
2188                                 return FilterWindingIntoTree_r( w, ds, node->children[ 0 ] );
2189                         }
2190                         if ( DotProduct( plane1, reverse ) > 0.999f && fabs( plane1[ 3 ] - reverse[ 3 ] ) < 0.001f ) {
2191                                 return FilterWindingIntoTree_r( w, ds, node->children[ 1 ] );
2192                         }
2193                         #else
2194                         (void) plane2;
2195                         /* div0: this is the cholera (doesn't hit enough) */
2196
2197                         /* the drawsurf might have an associated plane, if so, force a filter here */
2198                         if ( ds->planeNum == node->planenum ) {
2199                                 return FilterWindingIntoTree_r( w, ds, node->children[ 0 ] );
2200                         }
2201                         if ( ds->planeNum == ( node->planenum ^ 1 ) ) {
2202                                 return FilterWindingIntoTree_r( w, ds, node->children[ 1 ] );
2203                         }
2204                         #endif
2205                 }
2206
2207                 /* clip the winding by this plane */
2208                 ClipWindingEpsilonStrict( w, plane1, plane1[ 3 ], ON_EPSILON, &front, &back ); /* strict; we handle the "winding disappeared" case */
2209
2210                 /* filter by this plane */
2211                 refs = 0;
2212                 if ( front == NULL && back == NULL ) {
2213                         /* same plane, this is an ugly hack */
2214                         /* but better too many than too few refs */
2215                         refs += FilterWindingIntoTree_r( CopyWinding( w ), ds, node->children[ 0 ] );
2216                         refs += FilterWindingIntoTree_r( CopyWinding( w ), ds, node->children[ 1 ] );
2217                 }
2218                 if ( front != NULL ) {
2219                         refs += FilterWindingIntoTree_r( front, ds, node->children[ 0 ] );
2220                 }
2221                 if ( back != NULL ) {
2222                         refs += FilterWindingIntoTree_r( back, ds, node->children[ 1 ] );
2223                 }
2224                 FreeWinding( w );
2225
2226                 /* return */
2227                 return refs;
2228         }
2229
2230         /* add a reference */
2231         return AddReferenceToLeaf( ds, node );
2232 }
2233
2234
2235
2236 /*
2237    FilterFaceIntoTree()
2238    filters a planar winding face drawsurface into the bsp tree
2239  */
2240
2241 int FilterFaceIntoTree( mapDrawSurface_t *ds, tree_t *tree ){
2242         winding_t   *w;
2243         int refs = 0;
2244
2245
2246         /* make a winding and filter it into the tree */
2247         w = WindingFromDrawSurf( ds );
2248         refs = FilterWindingIntoTree_r( w, ds, tree->headnode );
2249
2250         /* return */
2251         return refs;
2252 }
2253
2254
2255
2256 /*
2257    FilterPatchIntoTree()
2258    subdivides a patch into an approximate curve and filters it into the tree
2259  */
2260
2261 #define FILTER_SUBDIVISION      8
2262
2263 static int FilterPatchIntoTree( mapDrawSurface_t *ds, tree_t *tree ){
2264         int x, y, refs = 0;
2265
2266         for ( y = 0; y + 2 < ds->patchHeight; y += 2 )
2267                 for ( x = 0; x + 2 < ds->patchWidth; x += 2 )
2268                 {
2269                         vec3_t *points[9];
2270                         points[0] = &ds->verts[( y + 0 ) * ds->patchWidth + ( x + 0 )].xyz;
2271                         points[1] = &ds->verts[( y + 0 ) * ds->patchWidth + ( x + 1 )].xyz;
2272                         points[2] = &ds->verts[( y + 0 ) * ds->patchWidth + ( x + 2 )].xyz;
2273                         points[3] = &ds->verts[( y + 1 ) * ds->patchWidth + ( x + 0 )].xyz;
2274                         points[4] = &ds->verts[( y + 1 ) * ds->patchWidth + ( x + 1 )].xyz;
2275                         points[5] = &ds->verts[( y + 1 ) * ds->patchWidth + ( x + 2 )].xyz;
2276                         points[6] = &ds->verts[( y + 2 ) * ds->patchWidth + ( x + 0 )].xyz;
2277                         points[7] = &ds->verts[( y + 2 ) * ds->patchWidth + ( x + 1 )].xyz;
2278                         points[8] = &ds->verts[( y + 2 ) * ds->patchWidth + ( x + 2 )].xyz;
2279                         refs += FilterPointConvexHullIntoTree_r( points, 9, ds, tree->headnode );
2280                 }
2281
2282         return refs;
2283 }
2284
2285
2286
2287 /*
2288    FilterTrianglesIntoTree()
2289    filters a triangle surface (meta, model) into the bsp
2290  */
2291
2292 static int FilterTrianglesIntoTree( mapDrawSurface_t *ds, tree_t *tree ){
2293         int i, refs;
2294         winding_t   *w;
2295
2296
2297         /* ydnar: gs mods: this was creating bogus triangles before */
2298         refs = 0;
2299         for ( i = 0; i < ds->numIndexes; i += 3 )
2300         {
2301                 /* error check */
2302                 if ( ds->indexes[ i ] >= ds->numVerts ||
2303                          ds->indexes[ i + 1 ] >= ds->numVerts ||
2304                          ds->indexes[ i + 2 ] >= ds->numVerts ) {
2305                         Error( "Index %d greater than vertex count %d", ds->indexes[ i ], ds->numVerts );
2306                 }
2307
2308                 /* make a triangle winding and filter it into the tree */
2309                 w = AllocWinding( 3 );
2310                 w->numpoints = 3;
2311                 VectorCopy( ds->verts[ ds->indexes[ i ] ].xyz, w->p[ 0 ] );
2312                 VectorCopy( ds->verts[ ds->indexes[ i + 1 ] ].xyz, w->p[ 1 ] );
2313                 VectorCopy( ds->verts[ ds->indexes[ i + 2 ] ].xyz, w->p[ 2 ] );
2314                 refs += FilterWindingIntoTree_r( w, ds, tree->headnode );
2315         }
2316
2317         /* use point filtering as well */
2318         for ( i = 0; i < ds->numVerts; i++ )
2319                 refs += FilterPointIntoTree_r( ds->verts[ i ].xyz, ds, tree->headnode );
2320
2321         return refs;
2322 }
2323
2324
2325
2326 /*
2327    FilterFoliageIntoTree()
2328    filters a foliage surface (wolf et/splash damage)
2329  */
2330
2331 static int FilterFoliageIntoTree( mapDrawSurface_t *ds, tree_t *tree ){
2332         int f, i, refs;
2333         bspDrawVert_t   *instance;
2334         vec3_t xyz;
2335         winding_t       *w;
2336
2337
2338         /* walk origin list */
2339         refs = 0;
2340         for ( f = 0; f < ds->numFoliageInstances; f++ )
2341         {
2342                 /* get instance */
2343                 instance = ds->verts + ds->patchHeight + f;
2344
2345                 /* walk triangle list */
2346                 for ( i = 0; i < ds->numIndexes; i += 3 )
2347                 {
2348                         /* error check */
2349                         if ( ds->indexes[ i ] >= ds->numVerts ||
2350                                  ds->indexes[ i + 1 ] >= ds->numVerts ||
2351                                  ds->indexes[ i + 2 ] >= ds->numVerts ) {
2352                                 Error( "Index %d greater than vertex count %d", ds->indexes[ i ], ds->numVerts );
2353                         }
2354
2355                         /* make a triangle winding and filter it into the tree */
2356                         w = AllocWinding( 3 );
2357                         w->numpoints = 3;
2358                         VectorAdd( instance->xyz, ds->verts[ ds->indexes[ i ] ].xyz, w->p[ 0 ] );
2359                         VectorAdd( instance->xyz, ds->verts[ ds->indexes[ i + 1 ] ].xyz, w->p[ 1 ] );
2360                         VectorAdd( instance->xyz, ds->verts[ ds->indexes[ i + 2 ] ].xyz, w->p[ 2 ] );
2361                         refs += FilterWindingIntoTree_r( w, ds, tree->headnode );
2362                 }
2363
2364                 /* use point filtering as well */
2365                 for ( i = 0; i < ( ds->numVerts - ds->numFoliageInstances ); i++ )
2366                 {
2367                         VectorAdd( instance->xyz, ds->verts[ i ].xyz, xyz );
2368                         refs += FilterPointIntoTree_r( xyz, ds, tree->headnode );
2369                 }
2370         }
2371
2372         return refs;
2373 }
2374
2375
2376
2377 /*
2378    FilterFlareIntoTree()
2379    simple point filtering for flare surfaces
2380  */
2381 static int FilterFlareSurfIntoTree( mapDrawSurface_t *ds, tree_t *tree ){
2382         return FilterPointIntoTree_r( ds->lightmapOrigin, ds, tree->headnode );
2383 }
2384
2385
2386
2387 /*
2388    EmitDrawVerts() - ydnar
2389    emits bsp drawverts from a map drawsurface
2390  */
2391
2392 void EmitDrawVerts( mapDrawSurface_t *ds, bspDrawSurface_t *out ){
2393         int i, k;
2394         bspDrawVert_t   *dv;
2395         shaderInfo_t    *si;
2396         float offset;
2397
2398
2399         /* get stuff */
2400         si = ds->shaderInfo;
2401         offset = si->offset;
2402
2403         /* copy the verts */
2404         out->firstVert = numBSPDrawVerts;
2405         out->numVerts = ds->numVerts;
2406         for ( i = 0; i < ds->numVerts; i++ )
2407         {
2408                 /* allocate a new vert */
2409                 IncDrawVerts();
2410                 dv = &bspDrawVerts[ numBSPDrawVerts - 1 ];
2411
2412                 /* copy it */
2413                 memcpy( dv, &ds->verts[ i ], sizeof( *dv ) );
2414
2415                 /* offset? */
2416                 if ( offset != 0.0f ) {
2417                         VectorMA( dv->xyz, offset, dv->normal, dv->xyz );
2418                 }
2419
2420                 /* expand model bounds
2421                    necessary because of misc_model surfaces on entities
2422                    note: does not happen on worldspawn as its bounds is only used for determining lightgrid bounds */
2423                 if ( numBSPModels > 0 ) {
2424                         AddPointToBounds( dv->xyz, bspModels[ numBSPModels ].mins, bspModels[ numBSPModels ].maxs );
2425                 }
2426
2427                 /* debug color? */
2428                 if ( debugSurfaces ) {
2429                         for ( k = 0; k < MAX_LIGHTMAPS; k++ )
2430                                 VectorCopy( debugColors[ ( ds - mapDrawSurfs ) % 12 ], dv->color[ k ] );
2431                 }
2432         }
2433 }
2434
2435
2436
2437 /*
2438    FindDrawIndexes() - ydnar
2439    this attempts to find a run of indexes in the bsp that match the given indexes
2440    this tends to reduce the size of the bsp index pool by 1/3 or more
2441    returns numIndexes + 1 if the search failed
2442  */
2443
2444 int FindDrawIndexes( int numIndexes, int *indexes ){
2445         int i, j, numTestIndexes;
2446
2447
2448         /* dummy check */
2449         if ( numIndexes < 3 || numBSPDrawIndexes < numIndexes || indexes == NULL ) {
2450                 return numBSPDrawIndexes;
2451         }
2452
2453         /* set limit */
2454         numTestIndexes = 1 + numBSPDrawIndexes - numIndexes;
2455
2456         /* handle 3 indexes as a special case for performance */
2457         if ( numIndexes == 3 ) {
2458                 /* run through all indexes */
2459                 for ( i = 0; i < numTestIndexes; i++ )
2460                 {
2461                         /* test 3 indexes */
2462                         if ( indexes[ 0 ] == bspDrawIndexes[ i ] &&
2463                                  indexes[ 1 ] == bspDrawIndexes[ i + 1 ] &&
2464                                  indexes[ 2 ] == bspDrawIndexes[ i + 2 ] ) {
2465                                 numRedundantIndexes += numIndexes;
2466                                 return i;
2467                         }
2468                 }
2469
2470                 /* failed */
2471                 return numBSPDrawIndexes;
2472         }
2473
2474         /* handle 4 or more indexes */
2475         for ( i = 0; i < numTestIndexes; i++ )
2476         {
2477                 /* test first 4 indexes */
2478                 if ( indexes[ 0 ] == bspDrawIndexes[ i ] &&
2479                          indexes[ 1 ] == bspDrawIndexes[ i + 1 ] &&
2480                          indexes[ 2 ] == bspDrawIndexes[ i + 2 ] &&
2481                          indexes[ 3 ] == bspDrawIndexes[ i + 3 ] ) {
2482                         /* handle 4 indexes */
2483                         if ( numIndexes == 4 ) {
2484                                 return i;
2485                         }
2486
2487                         /* test the remainder */
2488                         for ( j = 4; j < numIndexes; j++ )
2489                         {
2490                                 if ( indexes[ j ] != bspDrawIndexes[ i + j ] ) {
2491                                         break;
2492                                 }
2493                                 else if ( j == ( numIndexes - 1 ) ) {
2494                                         numRedundantIndexes += numIndexes;
2495                                         return i;
2496                                 }
2497                         }
2498                 }
2499         }
2500
2501         /* failed */
2502         return numBSPDrawIndexes;
2503 }
2504
2505
2506
2507 /*
2508    EmitDrawIndexes() - ydnar
2509    attempts to find an existing run of drawindexes before adding new ones
2510  */
2511
2512 void EmitDrawIndexes( mapDrawSurface_t *ds, bspDrawSurface_t *out ){
2513         int i;
2514
2515
2516         /* attempt to use redundant indexing */
2517         out->firstIndex = FindDrawIndexes( ds->numIndexes, ds->indexes );
2518         out->numIndexes = ds->numIndexes;
2519         if ( out->firstIndex == numBSPDrawIndexes ) {
2520                 /* copy new unique indexes */
2521                 for ( i = 0; i < ds->numIndexes; i++ )
2522                 {
2523                         AUTOEXPAND_BY_REALLOC_BSP( DrawIndexes, 1024 );
2524                         bspDrawIndexes[ numBSPDrawIndexes ] = ds->indexes[ i ];
2525
2526                         /* validate the index */
2527                         if ( ds->type != SURFACE_PATCH ) {
2528                                 if ( bspDrawIndexes[ numBSPDrawIndexes ] < 0 || bspDrawIndexes[ numBSPDrawIndexes ] >= ds->numVerts ) {
2529                                         Sys_FPrintf( SYS_WRN, "WARNING: %d %s has invalid index %d (%d)\n",
2530                                                                 numBSPDrawSurfaces,
2531                                                                 ds->shaderInfo->shader,
2532                                                                 bspDrawIndexes[ numBSPDrawIndexes ],
2533                                                                 i );
2534                                         bspDrawIndexes[ numBSPDrawIndexes ] = 0;
2535                                 }
2536                         }
2537
2538                         /* increment index count */
2539                         numBSPDrawIndexes++;
2540                 }
2541         }
2542 }
2543
2544
2545
2546
2547 /*
2548    EmitFlareSurface()
2549    emits a bsp flare drawsurface
2550  */
2551
2552 void EmitFlareSurface( mapDrawSurface_t *ds ){
2553         int i;
2554         bspDrawSurface_t        *out;
2555
2556
2557         /* ydnar: nuking useless flare drawsurfaces */
2558         if ( emitFlares == qfalse && ds->type != SURFACE_SHADER ) {
2559                 return;
2560         }
2561
2562         /* limit check */
2563         if ( numBSPDrawSurfaces == MAX_MAP_DRAW_SURFS ) {
2564                 Error( "MAX_MAP_DRAW_SURFS" );
2565         }
2566
2567         /* allocate a new surface */
2568         if ( numBSPDrawSurfaces == MAX_MAP_DRAW_SURFS ) {
2569                 Error( "MAX_MAP_DRAW_SURFS" );
2570         }
2571         out = &bspDrawSurfaces[ numBSPDrawSurfaces ];
2572         ds->outputNum = numBSPDrawSurfaces;
2573         numBSPDrawSurfaces++;
2574         memset( out, 0, sizeof( *out ) );
2575
2576         /* set it up */
2577         out->surfaceType = MST_FLARE;
2578         out->shaderNum = EmitShader( ds->shaderInfo->shader, &ds->shaderInfo->contentFlags, &ds->shaderInfo->surfaceFlags );
2579         out->fogNum = ds->fogNum;
2580
2581         /* RBSP */
2582         for ( i = 0; i < MAX_LIGHTMAPS; i++ )
2583         {
2584                 out->lightmapNum[ i ] = -3;
2585                 out->lightmapStyles[ i ] = LS_NONE;
2586                 out->vertexStyles[ i ] = LS_NONE;
2587         }
2588         out->lightmapStyles[ 0 ] = ds->lightStyle;
2589         out->vertexStyles[ 0 ] = ds->lightStyle;
2590
2591         VectorCopy( ds->lightmapOrigin, out->lightmapOrigin );          /* origin */
2592         VectorCopy( ds->lightmapVecs[ 0 ], out->lightmapVecs[ 0 ] );    /* color */
2593         VectorCopy( ds->lightmapVecs[ 1 ], out->lightmapVecs[ 1 ] );
2594         VectorCopy( ds->lightmapVecs[ 2 ], out->lightmapVecs[ 2 ] );    /* normal */
2595
2596         /* add to count */
2597         numSurfacesByType[ ds->type ]++;
2598 }
2599
2600
2601
2602 /*
2603    EmitPatchSurface()
2604    emits a bsp patch drawsurface
2605  */
2606
2607 void EmitPatchSurface( entity_t *e, mapDrawSurface_t *ds ){
2608         int i, j;
2609         bspDrawSurface_t    *out;
2610         int surfaceFlags, contentFlags;
2611         int forcePatchMeta;
2612
2613         /* vortex: _patchMeta support */
2614         forcePatchMeta = IntForKey( e, "_patchMeta" );
2615         if ( !forcePatchMeta ) {
2616                 forcePatchMeta = IntForKey( e, "patchMeta" );
2617         }
2618
2619         /* invert the surface if necessary */
2620         if ( ds->backSide || ds->shaderInfo->invert ) {
2621                 bspDrawVert_t   *dv1, *dv2, temp;
2622
2623                 /* walk the verts, flip the normal */
2624                 for ( i = 0; i < ds->numVerts; i++ )
2625                         VectorScale( ds->verts[ i ].normal, -1.0f, ds->verts[ i ].normal );
2626
2627                 /* walk the verts again, but this time reverse their order */
2628                 for ( j = 0; j < ds->patchHeight; j++ )
2629                 {
2630                         for ( i = 0; i < ( ds->patchWidth / 2 ); i++ )
2631                         {
2632                                 dv1 = &ds->verts[ j * ds->patchWidth + i ];
2633                                 dv2 = &ds->verts[ j * ds->patchWidth + ( ds->patchWidth - i - 1 ) ];
2634                                 memcpy( &temp, dv1, sizeof( bspDrawVert_t ) );
2635                                 memcpy( dv1, dv2, sizeof( bspDrawVert_t ) );
2636                                 memcpy( dv2, &temp, sizeof( bspDrawVert_t ) );
2637                         }
2638                 }
2639
2640                 /* invert facing */
2641                 VectorScale( ds->lightmapVecs[ 2 ], -1.0f, ds->lightmapVecs[ 2 ] );
2642         }
2643
2644         /* allocate a new surface */
2645         if ( numBSPDrawSurfaces == MAX_MAP_DRAW_SURFS ) {
2646                 Error( "MAX_MAP_DRAW_SURFS" );
2647         }
2648         out = &bspDrawSurfaces[ numBSPDrawSurfaces ];
2649         ds->outputNum = numBSPDrawSurfaces;
2650         numBSPDrawSurfaces++;
2651         memset( out, 0, sizeof( *out ) );
2652
2653         /* set it up */
2654         out->surfaceType = MST_PATCH;
2655         if ( debugSurfaces ) {
2656                 out->shaderNum = EmitShader( "debugsurfaces", NULL, NULL );
2657         }
2658         else if ( patchMeta || forcePatchMeta ) {
2659                 /* patch meta requires that we have nodraw patches for collision */
2660                 surfaceFlags = ds->shaderInfo->surfaceFlags;
2661                 contentFlags = ds->shaderInfo->contentFlags;
2662                 ApplySurfaceParm( "nodraw", &contentFlags, &surfaceFlags, NULL );
2663                 ApplySurfaceParm( "pointlight", &contentFlags, &surfaceFlags, NULL );
2664
2665                 /* we don't want this patch getting lightmapped */
2666                 VectorClear( ds->lightmapVecs[ 2 ] );
2667                 VectorClear( ds->lightmapAxis );
2668                 ds->sampleSize = 0;
2669
2670                 /* emit the new fake shader */
2671                 out->shaderNum = EmitShader( ds->shaderInfo->shader, &contentFlags, &surfaceFlags );
2672         }
2673         else{
2674                 out->shaderNum = EmitShader( ds->shaderInfo->shader, &ds->shaderInfo->contentFlags, &ds->shaderInfo->surfaceFlags );
2675         }
2676         out->patchWidth = ds->patchWidth;
2677         out->patchHeight = ds->patchHeight;
2678         out->fogNum = ds->fogNum;
2679
2680         /* RBSP */
2681         for ( i = 0; i < MAX_LIGHTMAPS; i++ )
2682         {
2683                 out->lightmapNum[ i ] = -3;
2684                 out->lightmapStyles[ i ] = LS_NONE;
2685                 out->vertexStyles[ i ] = LS_NONE;
2686         }
2687         out->lightmapStyles[ 0 ] = LS_NORMAL;
2688         out->vertexStyles[ 0 ] = LS_NORMAL;
2689
2690         /* ydnar: gs mods: previously, the lod bounds were stored in lightmapVecs[ 0 ] and [ 1 ], moved to bounds[ 0 ] and [ 1 ] */
2691         VectorCopy( ds->lightmapOrigin, out->lightmapOrigin );
2692         VectorCopy( ds->bounds[ 0 ], out->lightmapVecs[ 0 ] );
2693         VectorCopy( ds->bounds[ 1 ], out->lightmapVecs[ 1 ] );
2694         VectorCopy( ds->lightmapVecs[ 2 ], out->lightmapVecs[ 2 ] );
2695
2696         /* ydnar: gs mods: clear out the plane normal */
2697         if ( ds->planar == qfalse ) {
2698                 VectorClear( out->lightmapVecs[ 2 ] );
2699         }
2700
2701         /* emit the verts and indexes */
2702         EmitDrawVerts( ds, out );
2703         EmitDrawIndexes( ds, out );
2704
2705         /* add to count */
2706         numSurfacesByType[ ds->type ]++;
2707 }
2708
2709
2710
2711 /*
2712    OptimizeTriangleSurface() - ydnar
2713    optimizes the vertex/index data in a triangle surface
2714  */
2715
2716 #define VERTEX_CACHE_SIZE   16
2717
2718 static void OptimizeTriangleSurface( mapDrawSurface_t *ds ){
2719         int i, j, k, temp, first, best, bestScore, score;
2720         int vertexCache[ VERTEX_CACHE_SIZE + 1 ];       /* one more for optimizing insert */
2721         int     *indexes;
2722
2723
2724         /* certain surfaces don't get optimized */
2725         if ( ds->numIndexes <= VERTEX_CACHE_SIZE ||
2726                  ds->shaderInfo->autosprite ) {
2727                 return;
2728         }
2729
2730         /* create index scratch pad */
2731         indexes = safe_malloc( ds->numIndexes * sizeof( *indexes ) );
2732         memcpy( indexes, ds->indexes, ds->numIndexes * sizeof( *indexes ) );
2733
2734         /* setup */
2735         for ( i = 0; i <= VERTEX_CACHE_SIZE && i < ds->numIndexes; i++ )
2736                 vertexCache[ i ] = indexes[ i ];
2737
2738         /* add triangles in a vertex cache-aware order */
2739         for ( i = 0; i < ds->numIndexes; i += 3 )
2740         {
2741                 /* find best triangle given the current vertex cache */
2742                 first = -1;
2743                 best = -1;
2744                 bestScore = -1;
2745                 for ( j = 0; j < ds->numIndexes; j += 3 )
2746                 {
2747                         /* valid triangle? */
2748                         if ( indexes[ j ] != -1 ) {
2749                                 /* set first if necessary */
2750                                 if ( first < 0 ) {
2751                                         first = j;
2752                                 }
2753
2754                                 /* score the triangle */
2755                                 score = 0;
2756                                 for ( k = 0; k < VERTEX_CACHE_SIZE; k++ )
2757                                 {
2758                                         if ( indexes[ j ] == vertexCache[ k ] || indexes[ j + 1 ] == vertexCache[ k ] || indexes[ j + 2 ] == vertexCache[ k ] ) {
2759                                                 score++;
2760                                         }
2761                                 }
2762
2763                                 /* better triangle? */
2764                                 if ( score > bestScore ) {
2765                                         bestScore = score;
2766                                         best = j;
2767                                 }
2768
2769                                 /* a perfect score of 3 means this triangle's verts are already present in the vertex cache */
2770                                 if ( score == 3 ) {
2771                                         break;
2772                                 }
2773                         }
2774                 }
2775
2776                 /* check if no decent triangle was found, and use first available */
2777                 if ( best < 0 ) {
2778                         best = first;
2779                 }
2780
2781                 /* valid triangle? */
2782                 if ( best >= 0 ) {
2783                         /* add triangle to vertex cache */
2784                         for ( j = 0; j < 3; j++ )
2785                         {
2786                                 for ( k = 0; k < VERTEX_CACHE_SIZE; k++ )
2787                                 {
2788                                         if ( indexes[ best + j ] == vertexCache[ k ] ) {
2789                                                 break;
2790                                         }
2791                                 }
2792
2793                                 if ( k >= VERTEX_CACHE_SIZE ) {
2794                                         /* pop off top of vertex cache */
2795                                         for ( k = VERTEX_CACHE_SIZE; k > 0; k-- )
2796                                                 vertexCache[ k ] = vertexCache[ k - 1 ];
2797
2798                                         /* add vertex */
2799                                         vertexCache[ 0 ] = indexes[ best + j ];
2800                                 }
2801                         }
2802
2803                         /* add triangle to surface */
2804                         ds->indexes[ i ] = indexes[ best ];
2805                         ds->indexes[ i + 1 ] = indexes[ best + 1 ];
2806                         ds->indexes[ i + 2 ] = indexes[ best + 2 ];
2807
2808                         /* clear from input pool */
2809                         indexes[ best ] = -1;
2810                         indexes[ best + 1 ] = -1;
2811                         indexes[ best + 2 ] = -1;
2812
2813                         /* sort triangle windings (312 -> 123) */
2814                         while ( ds->indexes[ i ] > ds->indexes[ i + 1 ] || ds->indexes[ i ] > ds->indexes[ i + 2 ] )
2815                         {
2816                                 temp = ds->indexes[ i ];
2817                                 ds->indexes[ i ] = ds->indexes[ i + 1 ];
2818                                 ds->indexes[ i + 1 ] = ds->indexes[ i + 2 ];
2819                                 ds->indexes[ i + 2 ] = temp;
2820                         }
2821                 }
2822         }
2823
2824         /* clean up */
2825         free( indexes );
2826 }
2827
2828
2829
2830 /*
2831    EmitTriangleSurface()
2832    creates a bsp drawsurface from arbitrary triangle surfaces
2833  */
2834
2835 void EmitTriangleSurface( mapDrawSurface_t *ds ){
2836         int i, temp;
2837         bspDrawSurface_t        *out;
2838
2839         /* invert the surface if necessary */
2840         if ( ds->backSide || ds->shaderInfo->invert ) {
2841                 /* walk the indexes, reverse the triangle order */
2842                 for ( i = 0; i < ds->numIndexes; i += 3 )
2843                 {
2844                         temp = ds->indexes[ i ];
2845                         ds->indexes[ i ] = ds->indexes[ i + 1 ];
2846                         ds->indexes[ i + 1 ] = temp;
2847                 }
2848
2849                 /* walk the verts, flip the normal */
2850                 for ( i = 0; i < ds->numVerts; i++ )
2851                         VectorScale( ds->verts[ i ].normal, -1.0f, ds->verts[ i ].normal );
2852
2853                 /* invert facing */
2854                 VectorScale( ds->lightmapVecs[ 2 ], -1.0f, ds->lightmapVecs[ 2 ] );
2855         }
2856
2857         /* allocate a new surface */
2858         if ( numBSPDrawSurfaces == MAX_MAP_DRAW_SURFS ) {
2859                 Error( "MAX_MAP_DRAW_SURFS" );
2860         }
2861         out = &bspDrawSurfaces[ numBSPDrawSurfaces ];
2862         ds->outputNum = numBSPDrawSurfaces;
2863         numBSPDrawSurfaces++;
2864         memset( out, 0, sizeof( *out ) );
2865
2866         /* ydnar/sd: handle wolf et foliage surfaces */
2867         if ( ds->type == SURFACE_FOLIAGE ) {
2868                 out->surfaceType = MST_FOLIAGE;
2869         }
2870
2871         /* ydnar: gs mods: handle lightmapped terrain (force to planar type) */
2872         //%     else if( VectorLength( ds->lightmapAxis ) <= 0.0f || ds->type == SURFACE_TRIANGLES || ds->type == SURFACE_FOGHULL || debugSurfaces )
2873         else if ( ( VectorLength( ds->lightmapAxis ) <= 0.0f && ds->planar == qfalse ) ||
2874                           ds->type == SURFACE_TRIANGLES ||
2875                           ds->type == SURFACE_FOGHULL ||
2876                           ds->numVerts > maxLMSurfaceVerts ||
2877                           debugSurfaces ) {
2878                 out->surfaceType = MST_TRIANGLE_SOUP;
2879         }
2880
2881         /* set to a planar face */
2882         else{
2883                 out->surfaceType = MST_PLANAR;
2884         }
2885
2886         /* set it up */
2887         if ( debugSurfaces ) {
2888                 out->shaderNum = EmitShader( "debugsurfaces", NULL, NULL );
2889         }
2890         else{
2891                 out->shaderNum = EmitShader( ds->shaderInfo->shader, &ds->shaderInfo->contentFlags, &ds->shaderInfo->surfaceFlags );
2892         }
2893         out->patchWidth = ds->patchWidth;
2894         out->patchHeight = ds->patchHeight;
2895         out->fogNum = ds->fogNum;
2896
2897         /* debug inset (push each triangle vertex towards the center of each triangle it is on */
2898         if ( debugInset ) {
2899                 bspDrawVert_t   *a, *b, *c;
2900                 vec3_t cent, dir;
2901
2902
2903                 /* walk triangle list */
2904                 for ( i = 0; i < ds->numIndexes; i += 3 )
2905                 {
2906                         /* get verts */
2907                         a = &ds->verts[ ds->indexes[ i ] ];
2908                         b = &ds->verts[ ds->indexes[ i + 1 ] ];
2909                         c = &ds->verts[ ds->indexes[ i + 2 ] ];
2910
2911                         /* calculate centroid */
2912                         VectorCopy( a->xyz, cent );
2913                         VectorAdd( cent, b->xyz, cent );
2914                         VectorAdd( cent, c->xyz, cent );
2915                         VectorScale( cent, 1.0f / 3.0f, cent );
2916
2917                         /* offset each vertex */
2918                         VectorSubtract( cent, a->xyz, dir );
2919                         VectorNormalize( dir, dir );
2920                         VectorAdd( a->xyz, dir, a->xyz );
2921                         VectorSubtract( cent, b->xyz, dir );
2922                         VectorNormalize( dir, dir );
2923                         VectorAdd( b->xyz, dir, b->xyz );
2924                         VectorSubtract( cent, c->xyz, dir );
2925                         VectorNormalize( dir, dir );
2926                         VectorAdd( c->xyz, dir, c->xyz );
2927                 }
2928         }
2929
2930         /* RBSP */
2931         for ( i = 0; i < MAX_LIGHTMAPS; i++ )
2932         {
2933                 out->lightmapNum[ i ] = -3;
2934                 out->lightmapStyles[ i ] = LS_NONE;
2935                 out->vertexStyles[ i ] = LS_NONE;
2936         }
2937         out->lightmapStyles[ 0 ] = LS_NORMAL;
2938         out->vertexStyles[ 0 ] = LS_NORMAL;
2939
2940         /* lightmap vectors (lod bounds for patches */
2941         VectorCopy( ds->lightmapOrigin, out->lightmapOrigin );
2942         VectorCopy( ds->lightmapVecs[ 0 ], out->lightmapVecs[ 0 ] );
2943         VectorCopy( ds->lightmapVecs[ 1 ], out->lightmapVecs[ 1 ] );
2944         VectorCopy( ds->lightmapVecs[ 2 ], out->lightmapVecs[ 2 ] );
2945
2946         /* ydnar: gs mods: clear out the plane normal */
2947         if ( ds->planar == qfalse ) {
2948                 VectorClear( out->lightmapVecs[ 2 ] );
2949         }
2950
2951         /* optimize the surface's triangles */
2952         OptimizeTriangleSurface( ds );
2953
2954         /* emit the verts and indexes */
2955         EmitDrawVerts( ds, out );
2956         EmitDrawIndexes( ds, out );
2957
2958         /* add to count */
2959         numSurfacesByType[ ds->type ]++;
2960 }
2961
2962
2963
2964 /*
2965    EmitFaceSurface()
2966    emits a bsp planar winding (brush face) drawsurface
2967  */
2968
2969 static void EmitFaceSurface( mapDrawSurface_t *ds ){
2970         /* strip/fan finding was moved elsewhere */
2971         if ( maxAreaFaceSurface ) {
2972                 MaxAreaFaceSurface( ds );
2973         }
2974         else{
2975                 StripFaceSurface( ds );
2976         }
2977         EmitTriangleSurface( ds );
2978 }
2979
2980
2981
2982 /*
2983    MakeDebugPortalSurfs_r() - ydnar
2984    generates drawsurfaces for passable portals in the bsp
2985  */
2986
2987 static void MakeDebugPortalSurfs_r( node_t *node, shaderInfo_t *si ){
2988         int i, k, c, s;
2989         portal_t            *p;
2990         winding_t           *w;
2991         mapDrawSurface_t    *ds;
2992         bspDrawVert_t       *dv;
2993
2994
2995         /* recurse if decision node */
2996         if ( node->planenum != PLANENUM_LEAF ) {
2997                 MakeDebugPortalSurfs_r( node->children[ 0 ], si );
2998                 MakeDebugPortalSurfs_r( node->children[ 1 ], si );
2999                 return;
3000         }
3001
3002         /* don't bother with opaque leaves */
3003         if ( node->opaque ) {
3004                 return;
3005         }
3006
3007         /* walk the list of portals */
3008         for ( c = 0, p = node->portals; p != NULL; c++, p = p->next[ s ] )
3009         {
3010                 /* get winding and side even/odd */
3011                 w = p->winding;
3012                 s = ( p->nodes[ 1 ] == node );
3013
3014                 /* is this a valid portal for this leaf? */
3015                 if ( w && p->nodes[ 0 ] == node ) {
3016                         /* is this portal passable? */
3017                         if ( PortalPassable( p ) == qfalse ) {
3018                                 continue;
3019                         }
3020
3021                         /* check max points */
3022                         if ( w->numpoints > 64 ) {
3023                                 Error( "MakePortalSurfs_r: w->numpoints = %d", w->numpoints );
3024                         }
3025
3026                         /* allocate a drawsurface */
3027                         ds = AllocDrawSurface( SURFACE_FACE );
3028                         ds->shaderInfo = si;
3029                         ds->planar = qtrue;
3030                         ds->sideRef = AllocSideRef( p->side, NULL );
3031                         ds->planeNum = FindFloatPlane( p->plane.normal, p->plane.dist, 0, NULL );
3032                         VectorCopy( p->plane.normal, ds->lightmapVecs[ 2 ] );
3033                         ds->fogNum = -1;
3034                         ds->numVerts = w->numpoints;
3035                         ds->verts = safe_malloc( ds->numVerts * sizeof( *ds->verts ) );
3036                         memset( ds->verts, 0, ds->numVerts * sizeof( *ds->verts ) );
3037
3038                         /* walk the winding */
3039                         for ( i = 0; i < ds->numVerts; i++ )
3040                         {
3041                                 /* get vert */
3042                                 dv = ds->verts + i;
3043
3044                                 /* set it */
3045                                 VectorCopy( w->p[ i ], dv->xyz );
3046                                 VectorCopy( p->plane.normal, dv->normal );
3047                                 dv->st[ 0 ] = 0;
3048                                 dv->st[ 1 ] = 0;
3049                                 for ( k = 0; k < MAX_LIGHTMAPS; k++ )
3050                                 {
3051                                         VectorCopy( debugColors[ c % 12 ], dv->color[ k ] );
3052                                         dv->color[ k ][ 3 ] = 32;
3053                                 }
3054                         }
3055                 }
3056         }
3057 }
3058
3059
3060
3061 /*
3062    MakeDebugPortalSurfs() - ydnar
3063    generates drawsurfaces for passable portals in the bsp
3064  */
3065
3066 void MakeDebugPortalSurfs( tree_t *tree ){
3067         shaderInfo_t    *si;
3068
3069
3070         /* note it */
3071         Sys_FPrintf( SYS_VRB, "--- MakeDebugPortalSurfs ---\n" );
3072
3073         /* get portal debug shader */
3074         si = ShaderInfoForShader( "debugportals" );
3075
3076         /* walk the tree */
3077         MakeDebugPortalSurfs_r( tree->headnode, si );
3078 }
3079
3080
3081
3082 /*
3083    MakeFogHullSurfs()
3084    generates drawsurfaces for a foghull (this MUST use a sky shader)
3085  */
3086
3087 void MakeFogHullSurfs( entity_t *e, tree_t *tree, char *shader ){
3088         shaderInfo_t        *si;
3089         mapDrawSurface_t    *ds;
3090         vec3_t fogMins, fogMaxs;
3091         int i, indexes[] =
3092         {
3093                 0, 1, 2, 0, 2, 3,
3094                 4, 7, 5, 5, 7, 6,
3095                 1, 5, 6, 1, 6, 2,
3096                 0, 4, 5, 0, 5, 1,
3097                 2, 6, 7, 2, 7, 3,
3098                 3, 7, 4, 3, 4, 0
3099         };
3100
3101
3102         /* dummy check */
3103         if ( shader == NULL || shader[ 0 ] == '\0' ) {
3104                 return;
3105         }
3106
3107         /* note it */
3108         Sys_FPrintf( SYS_VRB, "--- MakeFogHullSurfs ---\n" );
3109
3110         /* get hull bounds */
3111         VectorCopy( mapMins, fogMins );
3112         VectorCopy( mapMaxs, fogMaxs );
3113         for ( i = 0; i < 3; i++ )
3114         {
3115                 fogMins[ i ] -= 128;
3116                 fogMaxs[ i ] += 128;
3117         }
3118
3119         /* get foghull shader */
3120         si = ShaderInfoForShader( shader );
3121
3122         /* allocate a drawsurface */
3123         ds = AllocDrawSurface( SURFACE_FOGHULL );
3124         ds->shaderInfo = si;
3125         ds->fogNum = -1;
3126         ds->numVerts = 8;
3127         ds->verts = safe_malloc( ds->numVerts * sizeof( *ds->verts ) );
3128         memset( ds->verts, 0, ds->numVerts * sizeof( *ds->verts ) );
3129         ds->numIndexes = 36;
3130         ds->indexes = safe_malloc( ds->numIndexes * sizeof( *ds->indexes ) );
3131         memset( ds->indexes, 0, ds->numIndexes * sizeof( *ds->indexes ) );
3132
3133         /* set verts */
3134         VectorSet( ds->verts[ 0 ].xyz, fogMins[ 0 ], fogMins[ 1 ], fogMins[ 2 ] );
3135         VectorSet( ds->verts[ 1 ].xyz, fogMins[ 0 ], fogMaxs[ 1 ], fogMins[ 2 ] );
3136         VectorSet( ds->verts[ 2 ].xyz, fogMaxs[ 0 ], fogMaxs[ 1 ], fogMins[ 2 ] );
3137         VectorSet( ds->verts[ 3 ].xyz, fogMaxs[ 0 ], fogMins[ 1 ], fogMins[ 2 ] );
3138
3139         VectorSet( ds->verts[ 4 ].xyz, fogMins[ 0 ], fogMins[ 1 ], fogMaxs[ 2 ] );
3140         VectorSet( ds->verts[ 5 ].xyz, fogMins[ 0 ], fogMaxs[ 1 ], fogMaxs[ 2 ] );
3141         VectorSet( ds->verts[ 6 ].xyz, fogMaxs[ 0 ], fogMaxs[ 1 ], fogMaxs[ 2 ] );
3142         VectorSet( ds->verts[ 7 ].xyz, fogMaxs[ 0 ], fogMins[ 1 ], fogMaxs[ 2 ] );
3143
3144         /* set indexes */
3145         memcpy( ds->indexes, indexes, ds->numIndexes * sizeof( *ds->indexes ) );
3146 }
3147
3148
3149
3150 /*
3151    BiasSurfaceTextures()
3152    biases a surface's texcoords as close to 0 as possible
3153  */
3154
3155 void BiasSurfaceTextures( mapDrawSurface_t *ds ){
3156         int i;
3157
3158
3159         /* calculate the surface texture bias */
3160         CalcSurfaceTextureRange( ds );
3161
3162         /* don't bias globaltextured shaders */
3163         if ( ds->shaderInfo->globalTexture ) {
3164                 return;
3165         }
3166
3167         /* bias the texture coordinates */
3168         for ( i = 0; i < ds->numVerts; i++ )
3169         {
3170                 ds->verts[ i ].st[ 0 ] += ds->bias[ 0 ];
3171                 ds->verts[ i ].st[ 1 ] += ds->bias[ 1 ];
3172         }
3173 }
3174
3175
3176
3177 /*
3178    AddSurfaceModelsToTriangle_r()
3179    adds models to a specified triangle, returns the number of models added
3180  */
3181
3182 int AddSurfaceModelsToTriangle_r( mapDrawSurface_t *ds, surfaceModel_t *model, bspDrawVert_t **tri ){
3183         bspDrawVert_t mid, *tri2[ 3 ];
3184         int max, n, localNumSurfaceModels;
3185
3186
3187         /* init */
3188         localNumSurfaceModels = 0;
3189
3190         /* subdivide calc */
3191         {
3192                 int i;
3193                 float       *a, *b, dx, dy, dz, dist, maxDist;
3194
3195
3196                 /* find the longest edge and split it */
3197                 max = -1;
3198                 maxDist = 0.0f;
3199                 for ( i = 0; i < 3; i++ )
3200                 {
3201                         /* get verts */
3202                         a = tri[ i ]->xyz;
3203                         b = tri[ ( i + 1 ) % 3 ]->xyz;
3204
3205                         /* get dists */
3206                         dx = a[ 0 ] - b[ 0 ];
3207                         dy = a[ 1 ] - b[ 1 ];
3208                         dz = a[ 2 ] - b[ 2 ];
3209                         dist = ( dx * dx ) + ( dy * dy ) + ( dz * dz );
3210
3211                         /* longer? */
3212                         if ( dist > maxDist ) {
3213                                 maxDist = dist;
3214                                 max = i;
3215                         }
3216                 }
3217
3218                 /* is the triangle small enough? */
3219                 if ( max < 0 || maxDist <= ( model->density * model->density ) ) {
3220                         float odds, r, angle;
3221                         vec3_t origin, normal, scale, axis[ 3 ], angles;
3222                         m4x4_t transform, temp;
3223
3224
3225                         /* roll the dice (model's odds scaled by vertex alpha) */
3226                         odds = model->odds * ( tri[ 0 ]->color[ 0 ][ 3 ] + tri[ 0 ]->color[ 0 ][ 3 ] + tri[ 0 ]->color[ 0 ][ 3 ] ) / 765.0f;
3227                         r = Random();
3228                         if ( r > odds ) {
3229                                 return 0;
3230                         }
3231
3232                         /* calculate scale */
3233                         r = model->minScale + Random() * ( model->maxScale - model->minScale );
3234                         VectorSet( scale, r, r, r );
3235
3236                         /* calculate angle */
3237                         angle = model->minAngle + Random() * ( model->maxAngle - model->minAngle );
3238
3239                         /* calculate average origin */
3240                         VectorCopy( tri[ 0 ]->xyz, origin );
3241                         VectorAdd( origin, tri[ 1 ]->xyz, origin );
3242                         VectorAdd( origin, tri[ 2 ]->xyz, origin );
3243                         VectorScale( origin, ( 1.0f / 3.0f ), origin );
3244
3245                         /* clear transform matrix */
3246                         m4x4_identity( transform );
3247
3248                         /* handle oriented models */
3249                         if ( model->oriented ) {
3250                                 /* set angles */
3251                                 VectorSet( angles, 0.0f, 0.0f, angle );
3252
3253                                 /* calculate average normal */
3254                                 VectorCopy( tri[ 0 ]->normal, normal );
3255                                 VectorAdd( normal, tri[ 1 ]->normal, normal );
3256                                 VectorAdd( normal, tri[ 2 ]->normal, normal );
3257                                 if ( VectorNormalize( normal, axis[ 2 ] ) == 0.0f ) {
3258                                         VectorCopy( tri[ 0 ]->normal, axis[ 2 ] );
3259                                 }
3260
3261                                 /* make perpendicular vectors */
3262                                 MakeNormalVectors( axis[ 2 ], axis[ 1 ], axis[ 0 ] );
3263
3264                                 /* copy to matrix */
3265                                 m4x4_identity( temp );
3266                                 temp[ 0 ] = axis[ 0 ][ 0 ]; temp[ 1 ] = axis[ 0 ][ 1 ]; temp[ 2 ] = axis[ 0 ][ 2 ];
3267                                 temp[ 4 ] = axis[ 1 ][ 0 ]; temp[ 5 ] = axis[ 1 ][ 1 ]; temp[ 6 ] = axis[ 1 ][ 2 ];
3268                                 temp[ 8 ] = axis[ 2 ][ 0 ]; temp[ 9 ] = axis[ 2 ][ 1 ]; temp[ 10 ] = axis[ 2 ][ 2 ];
3269
3270                                 /* scale */
3271                                 m4x4_scale_by_vec3( temp, scale );
3272
3273                                 /* rotate around z axis */
3274                                 m4x4_rotate_by_vec3( temp, angles, eXYZ );
3275
3276                                 /* translate */
3277                                 m4x4_translate_by_vec3( transform, origin );
3278
3279                                 /* tranform into axis space */
3280                                 m4x4_multiply_by_m4x4( transform, temp );
3281                         }
3282
3283                         /* handle z-up models */
3284                         else
3285                         {
3286                                 /* set angles */
3287                                 VectorSet( angles, 0.0f, 0.0f, angle );
3288
3289                                 /* set matrix */
3290                                 m4x4_pivoted_transform_by_vec3( transform, origin, angles, eXYZ, scale, vec3_origin );
3291                         }
3292
3293                         /* insert the model */
3294                         InsertModel( (char *) model->model, 0, 0, transform, NULL, ds->celShader, ds->entityNum, ds->castShadows, ds->recvShadows, 0, ds->lightmapScale, 0, 0 );
3295
3296                         /* return to sender */
3297                         return 1;
3298                 }
3299         }
3300
3301         /* split the longest edge and map it */
3302         LerpDrawVert( tri[ max ], tri[ ( max + 1 ) % 3 ], &mid );
3303
3304         /* recurse to first triangle */
3305         VectorCopy( tri, tri2 );
3306         tri2[ max ] = &mid;
3307         n = AddSurfaceModelsToTriangle_r( ds, model, tri2 );
3308         if ( n < 0 ) {
3309                 return n;
3310         }
3311         localNumSurfaceModels += n;
3312
3313         /* recurse to second triangle */
3314         VectorCopy( tri, tri2 );
3315         tri2[ ( max + 1 ) % 3 ] = &mid;
3316         n = AddSurfaceModelsToTriangle_r( ds, model, tri2 );
3317         if ( n < 0 ) {
3318                 return n;
3319         }
3320         localNumSurfaceModels += n;
3321
3322         /* return count */
3323         return localNumSurfaceModels;
3324 }
3325
3326
3327
3328 /*
3329    AddSurfaceModels()
3330    adds a surface's shader models to the surface
3331  */
3332
3333 int AddSurfaceModels( mapDrawSurface_t *ds ){
3334         surfaceModel_t  *model;
3335         int i, x, y, n, pw[ 5 ], r, localNumSurfaceModels, iterations;
3336         mesh_t src, *mesh, *subdivided;
3337         bspDrawVert_t centroid, *tri[ 3 ];
3338         float alpha;
3339
3340
3341         /* dummy check */
3342         if ( ds == NULL || ds->shaderInfo == NULL || ds->shaderInfo->surfaceModel == NULL ) {
3343                 return 0;
3344         }
3345
3346         /* init */
3347         localNumSurfaceModels = 0;
3348
3349         /* walk the model list */
3350         for ( model = ds->shaderInfo->surfaceModel; model != NULL; model = model->next )
3351         {
3352                 /* switch on type */
3353                 switch ( ds->type )
3354                 {
3355                 /* handle brush faces and decals */
3356                 case SURFACE_FACE:
3357                 case SURFACE_DECAL:
3358                         /* calculate centroid */
3359                         memset( &centroid, 0, sizeof( centroid ) );
3360                         alpha = 0.0f;
3361
3362                         /* walk verts */
3363                         for ( i = 0; i < ds->numVerts; i++ )
3364                         {
3365                                 VectorAdd( centroid.xyz, ds->verts[ i ].xyz, centroid.xyz );
3366                                 VectorAdd( centroid.normal, ds->verts[ i ].normal, centroid.normal );
3367                                 centroid.st[ 0 ] += ds->verts[ i ].st[ 0 ];
3368                                 centroid.st[ 1 ] += ds->verts[ i ].st[ 1 ];
3369                                 alpha += ds->verts[ i ].color[ 0 ][ 3 ];
3370                         }
3371
3372                         /* average */
3373                         centroid.xyz[ 0 ] /= ds->numVerts;
3374                         centroid.xyz[ 1 ] /= ds->numVerts;
3375                         centroid.xyz[ 2 ] /= ds->numVerts;
3376                         if ( VectorNormalize( centroid.normal, centroid.normal ) == 0.0f ) {
3377                                 VectorCopy( ds->verts[ 0 ].normal, centroid.normal );
3378                         }
3379                         centroid.st[ 0 ]  /= ds->numVerts;
3380                         centroid.st[ 1 ]  /= ds->numVerts;
3381                         alpha /= ds->numVerts;
3382                         centroid.color[ 0 ][ 0 ] = 0xFF;
3383                         centroid.color[ 0 ][ 1 ] = 0xFF;
3384                         centroid.color[ 0 ][ 2 ] = 0xFF;
3385                         centroid.color[ 0 ][ 2 ] = ( alpha > 255.0f ? 0xFF : alpha );
3386
3387                         /* head vert is centroid */
3388                         tri[ 0 ] = &centroid;
3389
3390                         /* walk fanned triangles */
3391                         for ( i = 0; i < ds->numVerts; i++ )
3392                         {
3393                                 /* set triangle */
3394                                 tri[ 1 ] = &ds->verts[ i ];
3395                                 tri[ 2 ] = &ds->verts[ ( i + 1 ) % ds->numVerts ];
3396
3397                                 /* create models */
3398                                 n = AddSurfaceModelsToTriangle_r( ds, model, tri );
3399                                 if ( n < 0 ) {
3400                                         return n;
3401                                 }
3402                                 localNumSurfaceModels += n;
3403                         }
3404                         break;
3405
3406                 /* handle patches */
3407                 case SURFACE_PATCH:
3408                         /* subdivide the surface */
3409                         src.width = ds->patchWidth;
3410                         src.height = ds->patchHeight;
3411                         src.verts = ds->verts;
3412                         //%     subdivided = SubdivideMesh( src, 8.0f, 512 );
3413                         iterations = IterationsForCurve( ds->longestCurve, patchSubdivisions );
3414                         subdivided = SubdivideMesh2( src, iterations );
3415
3416                         /* fit it to the curve and remove colinear verts on rows/columns */
3417                         PutMeshOnCurve( *subdivided );
3418                         mesh = RemoveLinearMeshColumnsRows( subdivided );
3419                         FreeMesh( subdivided );
3420
3421                         /* subdivide each quad to place the models */
3422                         for ( y = 0; y < ( mesh->height - 1 ); y++ )
3423                         {
3424                                 for ( x = 0; x < ( mesh->width - 1 ); x++ )
3425                                 {
3426                                         /* set indexes */
3427                                         pw[ 0 ] = x + ( y * mesh->width );
3428                                         pw[ 1 ] = x + ( ( y + 1 ) * mesh->width );
3429                                         pw[ 2 ] = x + 1 + ( ( y + 1 ) * mesh->width );
3430                                         pw[ 3 ] = x + 1 + ( y * mesh->width );
3431                                         pw[ 4 ] = x + ( y * mesh->width );      /* same as pw[ 0 ] */
3432
3433                                         /* set radix */
3434                                         r = ( x + y ) & 1;
3435
3436                                         /* triangle 1 */
3437                                         tri[ 0 ] = &mesh->verts[ pw[ r + 0 ] ];
3438                                         tri[ 1 ] = &mesh->verts[ pw[ r + 1 ] ];
3439                                         tri[ 2 ] = &mesh->verts[ pw[ r + 2 ] ];
3440                                         n = AddSurfaceModelsToTriangle_r( ds, model, tri );
3441                                         if ( n < 0 ) {
3442                                                 return n;
3443                                         }
3444                                         localNumSurfaceModels += n;
3445
3446                                         /* triangle 2 */
3447                                         tri[ 0 ] = &mesh->verts[ pw[ r + 0 ] ];
3448                                         tri[ 1 ] = &mesh->verts[ pw[ r + 2 ] ];
3449                                         tri[ 2 ] = &mesh->verts[ pw[ r + 3 ] ];
3450                                         n = AddSurfaceModelsToTriangle_r( ds, model, tri );
3451                                         if ( n < 0 ) {
3452                                                 return n;
3453                                         }
3454                                         localNumSurfaceModels += n;
3455                                 }
3456                         }
3457
3458                         /* free the subdivided mesh */
3459                         FreeMesh( mesh );
3460                         break;
3461
3462                 /* handle triangle surfaces */
3463                 case SURFACE_TRIANGLES:
3464                 case SURFACE_FORCED_META:
3465                 case SURFACE_META:
3466                         /* walk the triangle list */
3467                         for ( i = 0; i < ds->numIndexes; i += 3 )
3468                         {
3469                                 tri[ 0 ] = &ds->verts[ ds->indexes[ i ] ];
3470                                 tri[ 1 ] = &ds->verts[ ds->indexes[ i + 1 ] ];
3471                                 tri[ 2 ] = &ds->verts[ ds->indexes[ i + 2 ] ];
3472                                 n = AddSurfaceModelsToTriangle_r( ds, model, tri );
3473                                 if ( n < 0 ) {
3474                                         return n;
3475                                 }
3476                                 localNumSurfaceModels += n;
3477                         }
3478                         break;
3479
3480                 /* no support for flares, foghull, etc */
3481                 default:
3482                         break;
3483                 }
3484         }
3485
3486         /* return count */
3487         return localNumSurfaceModels;
3488 }
3489
3490
3491
3492 /*
3493    AddEntitySurfaceModels() - ydnar
3494    adds surfacemodels to an entity's surfaces
3495  */
3496
3497 void AddEntitySurfaceModels( entity_t *e ){
3498         int i;
3499
3500
3501         /* note it */
3502         Sys_FPrintf( SYS_VRB, "--- AddEntitySurfaceModels ---\n" );
3503
3504         /* walk the surface list */
3505         for ( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ )
3506                 numSurfaceModels += AddSurfaceModels( &mapDrawSurfs[ i ] );
3507 }
3508
3509
3510
3511 /*
3512    VolumeColorMods() - ydnar
3513    applies brush/volumetric color/alpha modulation to vertexes
3514  */
3515
3516 static void VolumeColorMods( entity_t *e, mapDrawSurface_t *ds ){
3517         int i, j;
3518         float d;
3519         brush_t     *b;
3520         plane_t     *plane;
3521
3522
3523         /* early out */
3524         if ( e->colorModBrushes == NULL ) {
3525                 return;
3526         }
3527
3528         /* iterate brushes */
3529         for ( b = e->colorModBrushes; b != NULL; b = b->nextColorModBrush )
3530         {
3531                 /* worldspawn alpha brushes affect all, grouped ones only affect original entity */
3532                 if ( b->entityNum != 0 && b->entityNum != ds->entityNum ) {
3533                         continue;
3534                 }
3535
3536                 /* test bbox */
3537                 if ( b->mins[ 0 ] > ds->maxs[ 0 ] || b->maxs[ 0 ] < ds->mins[ 0 ] ||
3538                          b->mins[ 1 ] > ds->maxs[ 1 ] || b->maxs[ 1 ] < ds->mins[ 1 ] ||
3539                          b->mins[ 2 ] > ds->maxs[ 2 ] || b->maxs[ 2 ] < ds->mins[ 2 ] ) {
3540                         continue;
3541                 }
3542
3543                 /* iterate verts */
3544                 for ( i = 0; i < ds->numVerts; i++ )
3545                 {
3546                         /* iterate planes */
3547                         for ( j = 0; j < b->numsides; j++ )
3548                         {
3549                                 /* point-plane test */
3550                                 plane = &mapplanes[ b->sides[ j ].planenum ];
3551                                 d = DotProduct( ds->verts[ i ].xyz, plane->normal ) - plane->dist;
3552                                 if ( d > 1.0f ) {
3553                                         break;
3554                                 }
3555                         }
3556
3557                         /* apply colormods */
3558                         if ( j == b->numsides ) {
3559                                 ColorMod( b->contentShader->colorMod, 1, &ds->verts[ i ] );
3560                         }
3561                 }
3562         }
3563 }
3564
3565
3566
3567 /*
3568    FilterDrawsurfsIntoTree()
3569    upon completion, all drawsurfs that actually generate a reference
3570    will have been emited to the bspfile arrays, and the references
3571    will have valid final indexes
3572  */
3573
3574 void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree ){
3575         int i, j;
3576         mapDrawSurface_t    *ds;
3577         shaderInfo_t        *si;
3578         vec3_t origin, mins, maxs;
3579         int refs;
3580         int numSurfs, numRefs, numSkyboxSurfaces;
3581         qboolean sb;
3582
3583
3584         /* note it */
3585         Sys_FPrintf( SYS_VRB, "--- FilterDrawsurfsIntoTree ---\n" );
3586
3587         /* filter surfaces into the tree */
3588         numSurfs = 0;
3589         numRefs = 0;
3590         numSkyboxSurfaces = 0;
3591         for ( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ )
3592         {
3593                 /* get surface and try to early out */
3594                 ds = &mapDrawSurfs[ i ];
3595                 if ( ds->numVerts == 0 && ds->type != SURFACE_FLARE && ds->type != SURFACE_SHADER ) {
3596                         continue;
3597                 }
3598
3599                 /* get shader */
3600                 si = ds->shaderInfo;
3601
3602                 /* ydnar: skybox surfaces are special */
3603                 if ( ds->skybox ) {
3604                         refs = AddReferenceToTree_r( ds, tree->headnode, qtrue );
3605                         ds->skybox = qfalse;
3606                         sb = qtrue;
3607                 }
3608                 else
3609                 {
3610                         sb = qfalse;
3611
3612                         /* refs initially zero */
3613                         refs = 0;
3614
3615                         /* apply texture coordinate mods */
3616                         for ( j = 0; j < ds->numVerts; j++ )
3617                                 TCMod( si->mod, ds->verts[ j ].st );
3618
3619                         /* ydnar: apply shader colormod */
3620                         ColorMod( ds->shaderInfo->colorMod, ds->numVerts, ds->verts );
3621
3622                         /* ydnar: apply brush colormod */
3623                         VolumeColorMods( e, ds );
3624
3625                         /* ydnar: make fur surfaces */
3626                         if ( si->furNumLayers > 0 ) {
3627                                 Fur( ds );
3628                         }
3629
3630                         /* ydnar/sd: make foliage surfaces */
3631                         if ( si->foliage != NULL ) {
3632                                 Foliage( ds );
3633                         }
3634
3635                         /* create a flare surface if necessary */
3636                         if ( si->flareShader != NULL && si->flareShader[ 0 ] ) {
3637                                 AddSurfaceFlare( ds, e->origin );
3638                         }
3639
3640                         /* ydnar: don't emit nodraw surfaces (like nodraw fog) */
3641                         if ( ( si->compileFlags & C_NODRAW ) && ds->type != SURFACE_PATCH ) {
3642                                 continue;
3643                         }
3644
3645                         /* ydnar: bias the surface textures */
3646                         BiasSurfaceTextures( ds );
3647
3648                         /* ydnar: globalizing of fog volume handling (eek a hack) */
3649                         if ( e != entities && si->noFog == qfalse ) {
3650                                 /* find surface origin and offset by entity origin */
3651                                 VectorAdd( ds->mins, ds->maxs, origin );
3652                                 VectorScale( origin, 0.5f, origin );
3653                                 VectorAdd( origin, e->origin, origin );
3654
3655                                 VectorAdd( ds->mins, e->origin, mins );
3656                                 VectorAdd( ds->maxs, e->origin, maxs );
3657
3658                                 /* set the fog number for this surface */
3659                                 ds->fogNum = FogForBounds( mins, maxs, 1.0f );  //%     FogForPoint( origin, 0.0f );
3660                         }
3661                 }
3662
3663                 /* ydnar: remap shader */
3664                 if ( ds->shaderInfo->remapShader && ds->shaderInfo->remapShader[ 0 ] ) {
3665                         ds->shaderInfo = ShaderInfoForShader( ds->shaderInfo->remapShader );
3666                 }
3667
3668                 /* ydnar: gs mods: handle the various types of surfaces */
3669                 switch ( ds->type )
3670                 {
3671                 /* handle brush faces */
3672                 case SURFACE_FACE:
3673                 case SURFACE_DECAL:
3674                         if ( refs == 0 ) {
3675                                 refs = FilterFaceIntoTree( ds, tree );
3676                         }
3677                         if ( refs > 0 ) {
3678                                 EmitFaceSurface( ds );
3679                         }
3680                         break;
3681
3682                 /* handle patches */
3683                 case SURFACE_PATCH:
3684                         if ( refs == 0 ) {
3685                                 refs = FilterPatchIntoTree( ds, tree );
3686                         }
3687                         if ( refs > 0 ) {
3688                                 EmitPatchSurface( e, ds );
3689                         }
3690                         break;
3691
3692                 /* handle triangle surfaces */
3693                 case SURFACE_TRIANGLES:
3694                 case SURFACE_FORCED_META:
3695                 case SURFACE_META:
3696                         //%     Sys_FPrintf( SYS_VRB, "Surface %4d: [%1d] %4d verts %s\n", numSurfs, ds->planar, ds->numVerts, si->shader );
3697                         if ( refs == 0 ) {
3698                                 refs = FilterTrianglesIntoTree( ds, tree );
3699                         }
3700                         if ( refs > 0 ) {
3701                                 EmitTriangleSurface( ds );
3702                         }
3703                         break;
3704
3705                 /* handle foliage surfaces (splash damage/wolf et) */
3706                 case SURFACE_FOLIAGE:
3707                         //%     Sys_FPrintf( SYS_VRB, "Surface %4d: [%d] %4d verts %s\n", numSurfs, ds->numFoliageInstances, ds->numVerts, si->shader );
3708                         if ( refs == 0 ) {
3709                                 refs = FilterFoliageIntoTree( ds, tree );
3710                         }
3711                         if ( refs > 0 ) {
3712                                 EmitTriangleSurface( ds );
3713                         }
3714                         break;
3715
3716                 /* handle foghull surfaces */
3717                 case SURFACE_FOGHULL:
3718                         if ( refs == 0 ) {
3719                                 refs = AddReferenceToTree_r( ds, tree->headnode, qfalse );
3720                         }
3721                         if ( refs > 0 ) {
3722                                 EmitTriangleSurface( ds );
3723                         }
3724                         break;
3725
3726                 /* handle flares */
3727                 case SURFACE_FLARE:
3728                         if ( refs == 0 ) {
3729                                 refs = FilterFlareSurfIntoTree( ds, tree );
3730                         }
3731                         if ( refs > 0 ) {
3732                                 EmitFlareSurface( ds );
3733                         }
3734                         break;
3735
3736                 /* handle shader-only surfaces */
3737                 case SURFACE_SHADER:
3738                         refs = 1;
3739                         EmitFlareSurface( ds );
3740                         break;
3741
3742                 /* no references */
3743                 default:
3744                         refs = 0;
3745                         break;
3746                 }
3747
3748                 /* maybe surface got marked as skybox again */
3749                 /* if we keep that flag, it will get scaled up AGAIN */
3750                 if ( sb ) {
3751                         ds->skybox = qfalse;
3752                 }
3753
3754                 /* tot up the references */
3755                 if ( refs > 0 ) {
3756                         /* tot up counts */
3757                         numSurfs++;
3758                         numRefs += refs;
3759
3760                         /* emit extra surface data */
3761                         SetSurfaceExtra( ds, numBSPDrawSurfaces - 1 );
3762                         //%     Sys_FPrintf( SYS_VRB, "%d verts %d indexes\n", ds->numVerts, ds->numIndexes );
3763
3764                         /* one last sanity check */
3765                         {
3766                                 bspDrawSurface_t    *out;
3767                                 out = &bspDrawSurfaces[ numBSPDrawSurfaces - 1 ];
3768                                 if ( out->numVerts == 3 && out->numIndexes > 3 ) {
3769                                         Sys_FPrintf( SYS_WRN, "WARNING: Potentially bad %s surface (%d: %d, %d)\n     %s\n",
3770                                                                 surfaceTypes[ ds->type ],
3771                                                                 numBSPDrawSurfaces - 1, out->numVerts, out->numIndexes, si->shader );
3772                                 }
3773                         }
3774
3775                         /* ydnar: handle skybox surfaces */
3776                         if ( ds->skybox ) {
3777                                 MakeSkyboxSurface( ds );
3778                                 numSkyboxSurfaces++;
3779                         }
3780                 }
3781         }
3782
3783         /* emit some statistics */
3784         Sys_FPrintf( SYS_VRB, "%9d references\n", numRefs );
3785         Sys_FPrintf( SYS_VRB, "%9d (%d) emitted drawsurfs\n", numSurfs, numBSPDrawSurfaces );
3786         Sys_FPrintf( SYS_VRB, "%9d stripped face surfaces\n", numStripSurfaces );
3787         Sys_FPrintf( SYS_VRB, "%9d fanned face surfaces\n", numFanSurfaces );
3788         Sys_FPrintf( SYS_VRB, "%9d maxarea'd face surfaces\n", numMaxAreaSurfaces );
3789         Sys_FPrintf( SYS_VRB, "%9d surface models generated\n", numSurfaceModels );
3790         Sys_FPrintf( SYS_VRB, "%9d skybox surfaces generated\n", numSkyboxSurfaces );
3791         for ( i = 0; i < NUM_SURFACE_TYPES; i++ )
3792                 Sys_FPrintf( SYS_VRB, "%9d %s surfaces\n", numSurfacesByType[ i ], surfaceTypes[ i ] );
3793
3794         Sys_FPrintf( SYS_VRB, "%9d redundant indexes supressed, saving %d Kbytes\n", numRedundantIndexes, ( numRedundantIndexes * 4 / 1024 ) );
3795 }