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