]> icculus.org git repositories - divverent/netradiant.git/blob - tools/quake3/q3map2/light_ydnar.c
09a8e484090463a80981b0a1bc6d6037f92c05f5
[divverent/netradiant.git] / tools / quake3 / q3map2 / light_ydnar.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 LIGHT_YDNAR_C
33
34
35
36 /* dependencies */
37 #include "q3map2.h"
38
39
40
41
42 /*
43 ColorToBytes()
44 ydnar: moved to here 2001-02-04
45 */
46
47 #define Image_sRGBFloatFromLinear(c) (((c) < 0.8014848f) ? (c) * 0.05046875f : 1.055f * (float)pow((c)*(1.0f/256.0f), 1.0f/2.4f) - 0.055f)
48 void ColorToBytes( const float *color, byte *colorBytes, float scale )
49 {
50         int             i;
51         float   max, gamma;
52         vec3_t  sample;
53         float   inv, dif;
54         
55         
56         /* ydnar: scaling necessary for simulating r_overbrightBits on external lightmaps */
57         if( scale <= 0.0f )
58                 scale = 1.0f;
59         
60         /* make a local copy */
61         VectorScale( color, scale, sample );
62         
63         /* muck with it */
64         gamma = 1.0f / lightmapGamma;
65         for( i = 0; i < 3; i++ )
66         {
67                 /* handle negative light */
68                 if( sample[ i ] < 0.0f )
69                 {
70                         sample[ i ] = 0.0f;
71                         continue;
72                 }
73                 
74                 /* gamma */
75                 sample[ i ] = pow( sample[ i ] / 255.0f, gamma ) * 255.0f;
76         }
77
78         if (lightmapExposure == 1)
79         {
80                 /* clamp with color normalization */
81                 max = sample[ 0 ];
82                 if( sample[ 1 ] > max )
83                         max = sample[ 1 ];
84                 if( sample[ 2 ] > max )
85                         max = sample[ 2 ];
86                 if( max > 255.0f )
87                         VectorScale( sample, (255.0f / max), sample );
88         }
89         else
90         {
91                 if (lightmapExposure==0)
92                 {
93                         lightmapExposure=1.0f;
94                 }
95                 inv=1.f/lightmapExposure;
96                 //Exposure
97
98                 max = sample[ 0 ];
99                 if( sample[ 1 ] > max )
100                         max = sample[ 1 ];
101                 if( sample[ 2 ] > max )
102                         max = sample[ 2 ];
103
104                 dif = (1-  exp(-max * inv) )  *  255;
105
106                 if (max >0)
107                 {
108                         dif = dif / max;
109                 }
110                 else
111                 {
112                         dif = 0;
113                 }
114
115                 for (i=0;i<3;i++)
116                 {
117                         sample[i]*=dif;
118                 }
119         }
120
121         
122         /* compensate for ingame overbrighting/bitshifting */
123         VectorScale( sample, (1.0f / lightmapCompensate), sample );
124
125         /* sRGB lightmaps */
126         if(lightmapsRGB)
127         {
128                 sample[0] = floor(Image_sRGBFloatFromLinear(sample[0]) * 255.0 + 0.5);
129                 sample[1] = floor(Image_sRGBFloatFromLinear(sample[1]) * 255.0 + 0.5);
130                 sample[2] = floor(Image_sRGBFloatFromLinear(sample[2]) * 255.0 + 0.5);
131         }
132         
133         /* store it off */
134         colorBytes[ 0 ] = sample[ 0 ];
135         colorBytes[ 1 ] = sample[ 1 ];
136         colorBytes[ 2 ] = sample[ 2 ];
137 }
138
139
140
141 /* -------------------------------------------------------------------------------
142
143 this section deals with phong shading (normal interpolation across brush faces)
144
145 ------------------------------------------------------------------------------- */
146
147 /*
148 SmoothNormals()
149 smooths together coincident vertex normals across the bsp
150 */
151
152 #define MAX_SAMPLES                             256
153 #define THETA_EPSILON                   0.000001
154 #define EQUAL_NORMAL_EPSILON    0.01
155
156 void SmoothNormals( void )
157 {
158         int                                     i, j, k, f, cs, numVerts, numVotes, fOld, start;
159         float                           shadeAngle, defaultShadeAngle, maxShadeAngle, dot, testAngle;
160         bspDrawSurface_t        *ds;
161         shaderInfo_t            *si;
162         float                           *shadeAngles;
163         byte                            *smoothed;
164         vec3_t                          average, diff;
165         int                                     indexes[ MAX_SAMPLES ];
166         vec3_t                          votes[ MAX_SAMPLES ];
167         
168         
169         /* allocate shade angle table */
170         shadeAngles = safe_malloc( numBSPDrawVerts * sizeof( float ) );
171         memset( shadeAngles, 0, numBSPDrawVerts * sizeof( float ) );
172         
173         /* allocate smoothed table */
174         cs = (numBSPDrawVerts / 8) + 1;
175         smoothed = safe_malloc( cs );
176         memset( smoothed, 0, cs );
177         
178         /* set default shade angle */
179         defaultShadeAngle = DEG2RAD( shadeAngleDegrees );
180         maxShadeAngle = 0;
181         
182         /* run through every surface and flag verts belonging to non-lightmapped surfaces
183            and set per-vertex smoothing angle */
184         for( i = 0; i < numBSPDrawSurfaces; i++ )
185         {
186                 /* get drawsurf */
187                 ds = &bspDrawSurfaces[ i ];
188                 
189                 /* get shader for shade angle */
190                 si = surfaceInfos[ i ].si;
191                 if( si->shadeAngleDegrees )
192                         shadeAngle = DEG2RAD( si->shadeAngleDegrees );
193                 else
194                         shadeAngle = defaultShadeAngle;
195                 if( shadeAngle > maxShadeAngle )
196                         maxShadeAngle = shadeAngle;
197                 
198                 /* flag its verts */
199                 for( j = 0; j < ds->numVerts; j++ )
200                 {
201                         f = ds->firstVert + j;
202                         shadeAngles[ f ] = shadeAngle;
203                         if( ds->surfaceType == MST_TRIANGLE_SOUP )
204                                 smoothed[ f >> 3 ] |= (1 << (f & 7));
205                 }
206                 
207                 /* ydnar: optional force-to-trisoup */
208                 if( trisoup && ds->surfaceType == MST_PLANAR )
209                 {
210                         ds->surfaceType = MST_TRIANGLE_SOUP;
211                         ds->lightmapNum[ 0 ] = -3;
212                 }
213         }
214         
215         /* bail if no surfaces have a shade angle */
216         if( maxShadeAngle == 0 )
217         {
218                 free( shadeAngles );
219                 free( smoothed );
220                 return;
221         }
222         
223         /* init pacifier */
224         fOld = -1;
225         start = I_FloatTime();
226         
227         /* go through the list of vertexes */
228         for( i = 0; i < numBSPDrawVerts; i++ )
229         {
230                 /* print pacifier */
231                 f = 10 * i / numBSPDrawVerts;
232                 if( f != fOld )
233                 {
234                         fOld = f;
235                         Sys_Printf( "%i...", f );
236                 }
237                 
238                 /* already smoothed? */
239                 if( smoothed[ i >> 3 ] & (1 << (i & 7)) )
240                         continue;
241                 
242                 /* clear */
243                 VectorClear( average );
244                 numVerts = 0;
245                 numVotes = 0;
246                 
247                 /* build a table of coincident vertexes */
248                 for( j = i; j < numBSPDrawVerts && numVerts < MAX_SAMPLES; j++ )
249                 {
250                         /* already smoothed? */
251                         if( smoothed[ j >> 3 ] & (1 << (j & 7)) )
252                                 continue;
253                         
254                         /* test vertexes */
255                         if( VectorCompare( yDrawVerts[ i ].xyz, yDrawVerts[ j ].xyz ) == qfalse )
256                                 continue;
257                         
258                         /* use smallest shade angle */
259                         shadeAngle = (shadeAngles[ i ] < shadeAngles[ j ] ? shadeAngles[ i ] : shadeAngles[ j ]);
260                         
261                         /* check shade angle */
262                         dot = DotProduct( bspDrawVerts[ i ].normal, bspDrawVerts[ j ].normal );
263                         if( dot > 1.0 )
264                                 dot = 1.0;
265                         else if( dot < -1.0 )
266                                 dot = -1.0;
267                         testAngle = acos( dot ) + THETA_EPSILON;
268                         if( testAngle >= shadeAngle )
269                         {
270                                 //Sys_Printf( "F(%3.3f >= %3.3f) ", RAD2DEG( testAngle ), RAD2DEG( shadeAngle ) );
271                                 continue;
272                         }
273                         //Sys_Printf( "P(%3.3f < %3.3f) ", RAD2DEG( testAngle ), RAD2DEG( shadeAngle ) );
274                         
275                         /* add to the list */
276                         indexes[ numVerts++ ] = j;
277                         
278                         /* flag vertex */
279                         smoothed[ j >> 3 ] |= (1 << (j & 7));
280                         
281                         /* see if this normal has already been voted */
282                         for( k = 0; k < numVotes; k++ )
283                         {
284                                 VectorSubtract( bspDrawVerts[ j ].normal, votes[ k ], diff );
285                                 if( fabs( diff[ 0 ] ) < EQUAL_NORMAL_EPSILON &&
286                                         fabs( diff[ 1 ] ) < EQUAL_NORMAL_EPSILON &&
287                                         fabs( diff[ 2 ] ) < EQUAL_NORMAL_EPSILON )
288                                         break;
289                         }
290                         
291                         /* add a new vote? */
292                         if( k == numVotes && numVotes < MAX_SAMPLES )
293                         {
294                                 VectorAdd( average, bspDrawVerts[ j ].normal, average );
295                                 VectorCopy( bspDrawVerts[ j ].normal, votes[ numVotes ] );
296                                 numVotes++;
297                         }
298                 }
299                 
300                 /* don't average for less than 2 verts */
301                 if( numVerts < 2 )
302                         continue;
303                 
304                 /* average normal */
305                 if( VectorNormalize( average, average ) > 0 )
306                 {
307                         /* smooth */
308                         for( j = 0; j < numVerts; j++ )
309                                 VectorCopy( average, yDrawVerts[ indexes[ j ] ].normal );
310                 }
311         }
312         
313         /* free the tables */
314         free( shadeAngles );
315         free( smoothed );
316         
317         /* print time */
318         Sys_Printf( " (%i)\n", (int) (I_FloatTime() - start) );
319 }
320
321
322
323 /* -------------------------------------------------------------------------------
324
325 this section deals with phong shaded lightmap tracing
326
327 ------------------------------------------------------------------------------- */
328
329 /* 9th rewrite (recursive subdivision of a lightmap triangle) */
330
331 /*
332 CalcTangentVectors()
333 calculates the st tangent vectors for normalmapping
334 */
335
336 static qboolean CalcTangentVectors( int numVerts, bspDrawVert_t **dv, vec3_t *stv, vec3_t *ttv )
337 {
338         int                     i;
339         float           bb, s, t;
340         vec3_t          bary;
341         
342         
343         /* calculate barycentric basis for the triangle */
344         bb = (dv[ 1 ]->st[ 0 ] - dv[ 0 ]->st[ 0 ]) * (dv[ 2 ]->st[ 1 ] - dv[ 0 ]->st[ 1 ]) - (dv[ 2 ]->st[ 0 ] - dv[ 0 ]->st[ 0 ]) * (dv[ 1 ]->st[ 1 ] - dv[ 0 ]->st[ 1 ]);
345         if( fabs( bb ) < 0.00000001f )
346                 return qfalse;
347         
348         /* do each vertex */
349         for( i = 0; i < numVerts; i++ )
350         {
351                 /* calculate s tangent vector */
352                 s = dv[ i ]->st[ 0 ] + 10.0f;
353                 t = dv[ i ]->st[ 1 ];
354                 bary[ 0 ] = ((dv[ 1 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t) - (dv[ 2 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t)) / bb;
355                 bary[ 1 ] = ((dv[ 2 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t) - (dv[ 0 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t)) / bb;
356                 bary[ 2 ] = ((dv[ 0 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t) - (dv[ 1 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t)) / bb;
357                 
358                 stv[ i ][ 0 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 0 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 0 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 0 ];
359                 stv[ i ][ 1 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 1 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 1 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 1 ];
360                 stv[ i ][ 2 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 2 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 2 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 2 ];
361                 
362                 VectorSubtract( stv[ i ], dv[ i ]->xyz, stv[ i ] );
363                 VectorNormalize( stv[ i ], stv[ i ] );
364                 
365                 /* calculate t tangent vector */
366                 s = dv[ i ]->st[ 0 ];
367                 t = dv[ i ]->st[ 1 ] + 10.0f;
368                 bary[ 0 ] = ((dv[ 1 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t) - (dv[ 2 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t)) / bb;
369                 bary[ 1 ] = ((dv[ 2 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t) - (dv[ 0 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t)) / bb;
370                 bary[ 2 ] = ((dv[ 0 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t) - (dv[ 1 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t)) / bb;
371                 
372                 ttv[ i ][ 0 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 0 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 0 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 0 ];
373                 ttv[ i ][ 1 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 1 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 1 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 1 ];
374                 ttv[ i ][ 2 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 2 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 2 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 2 ];
375                 
376                 VectorSubtract( ttv[ i ], dv[ i ]->xyz, ttv[ i ] );
377                 VectorNormalize( ttv[ i ], ttv[ i ] );
378                 
379                 /* debug code */
380                 //%     Sys_FPrintf( SYS_VRB, "%d S: (%f %f %f) T: (%f %f %f)\n", i,
381                 //%             stv[ i ][ 0 ], stv[ i ][ 1 ], stv[ i ][ 2 ], ttv[ i ][ 0 ], ttv[ i ][ 1 ], ttv[ i ][ 2 ] );
382         }
383         
384         /* return to caller */
385         return qtrue;
386 }
387
388
389
390
391 /*
392 PerturbNormal()
393 perterbs the normal by the shader's normalmap in tangent space
394 */
395
396 static void PerturbNormal( bspDrawVert_t *dv, shaderInfo_t *si, vec3_t pNormal, vec3_t stv[ 3 ], vec3_t ttv[ 3 ] )
397 {
398         int                     i;
399         vec4_t          bump;
400         
401         
402         /* passthrough */
403         VectorCopy( dv->normal, pNormal );
404         
405         /* sample normalmap */
406         if( RadSampleImage( si->normalImage->pixels, si->normalImage->width, si->normalImage->height, dv->st, bump ) == qfalse )
407                 return;
408         
409         /* remap sampled normal from [0,255] to [-1,-1] */
410         for( i = 0; i < 3; i++ )
411                 bump[ i ] = (bump[ i ] - 127.0f) * (1.0f / 127.5f);
412         
413         /* scale tangent vectors and add to original normal */
414         VectorMA( dv->normal, bump[ 0 ], stv[ 0 ], pNormal );
415         VectorMA( pNormal, bump[ 1 ], ttv[ 0 ], pNormal );
416         VectorMA( pNormal, bump[ 2 ], dv->normal, pNormal );
417         
418         /* renormalize and return */
419         VectorNormalize( pNormal, pNormal );
420 }
421
422
423
424 /*
425 MapSingleLuxel()
426 maps a luxel for triangle bv at
427 */
428
429 #define NUDGE                   0.5f
430 #define BOGUS_NUDGE             -99999.0f
431
432 static int MapSingleLuxel( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv, vec4_t plane, float pass, vec3_t stv[ 3 ], vec3_t ttv[ 3 ], vec3_t worldverts[ 3 ] )
433 {
434         int                             i, x, y, numClusters, *clusters, pointCluster, *cluster;
435         float                   *luxel, *origin, *normal, d, lightmapSampleOffset;
436         shaderInfo_t    *si;
437         vec3_t                  pNormal;
438         vec3_t                  vecs[ 3 ];
439         vec3_t                  nudged;
440         vec3_t                  cverts[ 3 ];
441         vec3_t                  temp;
442         vec4_t                  sideplane, hostplane;
443         vec3_t                  origintwo;
444         int                             j, next;
445         float                   e;
446         float                   *nudge;
447         static float    nudges[][ 2 ] =
448                                         {
449                                                 //%{ 0, 0 },            /* try center first */
450                                                 { -NUDGE, 0 },          /* left */
451                                                 { NUDGE, 0 },           /* right */
452                                                 { 0, NUDGE },           /* up */
453                                                 { 0, -NUDGE },          /* down */
454                                                 { -NUDGE, NUDGE },      /* left/up */
455                                                 { NUDGE, -NUDGE },      /* right/down */
456                                                 { NUDGE, NUDGE },       /* right/up */
457                                                 { -NUDGE, -NUDGE },     /* left/down */
458                                                 { BOGUS_NUDGE, BOGUS_NUDGE }
459                                         };
460         
461         
462         /* find luxel xy coords (fixme: subtract 0.5?) */
463         x = dv->lightmap[ 0 ][ 0 ];
464         y = dv->lightmap[ 0 ][ 1 ];
465         if( x < 0 )
466                 x = 0;
467         else if( x >= lm->sw )
468                 x = lm->sw - 1;
469         if( y < 0 )
470                 y = 0;
471         else if( y >= lm->sh )
472                 y = lm->sh - 1;
473         
474         /* set shader and cluster list */
475         if( info != NULL )
476         {
477                 si = info->si;
478                 numClusters = info->numSurfaceClusters;
479                 clusters = &surfaceClusters[ info->firstSurfaceCluster ];
480         }
481         else
482         {
483                 si = NULL;
484                 numClusters = 0;
485                 clusters = NULL;
486         }
487         
488         /* get luxel, origin, cluster, and normal */
489         luxel = SUPER_LUXEL( 0, x, y );
490         origin = SUPER_ORIGIN( x, y );
491         normal = SUPER_NORMAL( x, y );
492         cluster = SUPER_CLUSTER( x, y );
493         
494         /* don't attempt to remap occluded luxels for planar surfaces */
495         if( (*cluster) == CLUSTER_OCCLUDED && lm->plane != NULL )
496                 return (*cluster);
497         
498         /* only average the normal for premapped luxels */
499         else if( (*cluster) >= 0 )
500         {
501                 /* do bumpmap calculations */
502                 if( stv != NULL )
503                         PerturbNormal( dv, si, pNormal, stv, ttv );
504                 else
505                         VectorCopy( dv->normal, pNormal );
506                 
507                 /* add the additional normal data */
508                 VectorAdd( normal, pNormal, normal );
509                 luxel[ 3 ] += 1.0f;
510                 return (*cluster);
511         }
512         
513         /* otherwise, unmapped luxels (*cluster == CLUSTER_UNMAPPED) will have their full attributes calculated */
514         
515         /* get origin */
516         
517         /* axial lightmap projection */
518         if( lm->vecs != NULL )
519         {
520                 /* calculate an origin for the sample from the lightmap vectors */
521                 VectorCopy( lm->origin, origin );
522                 for( i = 0; i < 3; i++ )
523                 {
524                         /* add unless it's the axis, which is taken care of later */
525                         if( i == lm->axisNum )
526                                 continue;
527                         origin[ i ] += (x * lm->vecs[ 0 ][ i ]) + (y * lm->vecs[ 1 ][ i ]);
528                 }
529                 
530                 /* project the origin onto the plane */
531                 d = DotProduct( origin, plane ) - plane[ 3 ];
532                 d /= plane[ lm->axisNum ];
533                 origin[ lm->axisNum ] -= d;
534         }
535         
536         /* non axial lightmap projection (explicit xyz) */
537         else
538                 VectorCopy( dv->xyz, origin );
539
540         //////////////////////
541         //27's test to make sure samples stay within the triangle boundaries
542         //1) Test the sample origin to see if it lays on the wrong side of any edge (x/y)
543         //2) if it does, nudge it onto the correct side.
544
545         if (worldverts!=NULL && lightmapTriangleCheck)
546         {
547                 for (j=0;j<3;j++)
548                 {
549                         VectorCopy(worldverts[j],cverts[j]);
550                 }
551                 PlaneFromPoints(hostplane,cverts[0],cverts[1],cverts[2]);
552
553                 for (j=0;j<3;j++)
554                 {
555                         for (i=0;i<3;i++)
556                         {
557                                 //build plane using 2 edges and a normal
558                                 next=(i+1)%3;
559
560                                 VectorCopy(cverts[next],temp);
561                                 VectorAdd(temp,hostplane,temp);
562                                 PlaneFromPoints(sideplane,cverts[i],cverts[ next ], temp);
563
564                                 //planetest sample point
565                                 e=DotProduct(origin,sideplane);
566                                 e=e-sideplane[3];
567                                 if (e>0)
568                                 {
569                                         //we're bad.
570                                         //VectorClear(origin);
571                                         //Move the sample point back inside triangle bounds
572                                         origin[0]-=sideplane[0]*(e+1);
573                                         origin[1]-=sideplane[1]*(e+1);
574                                         origin[2]-=sideplane[2]*(e+1);
575 #ifdef DEBUG_27_1
576                                         VectorClear(origin);
577 #endif
578                                 }
579                         }
580                 }
581         }
582
583         ////////////////////////
584         
585         /* planar surfaces have precalculated lightmap vectors for nudging */
586         if( lm->plane != NULL )
587         {
588                 VectorCopy( lm->vecs[ 0 ], vecs[ 0 ] );
589                 VectorCopy( lm->vecs[ 1 ], vecs[ 1 ] );
590                 VectorCopy( lm->plane, vecs[ 2 ] );
591         }
592         
593         /* non-planar surfaces must calculate them */
594         else
595         {
596                 if( plane != NULL )
597                         VectorCopy( plane, vecs[ 2 ] );
598                 else
599                         VectorCopy( dv->normal, vecs[ 2 ] );
600                 MakeNormalVectors( vecs[ 2 ], vecs[ 0 ], vecs[ 1 ] );
601         }
602         
603         /* push the origin off the surface a bit */
604         if( si != NULL )
605                 lightmapSampleOffset = si->lightmapSampleOffset;
606         else
607                 lightmapSampleOffset = DEFAULT_LIGHTMAP_SAMPLE_OFFSET;
608         if( lm->axisNum < 0 )
609                 VectorMA( origin, lightmapSampleOffset, vecs[ 2 ], origin );
610         else if( vecs[ 2 ][ lm->axisNum ] < 0.0f )
611                 origin[ lm->axisNum ] -= lightmapSampleOffset;
612         else
613                 origin[ lm->axisNum ] += lightmapSampleOffset;
614         
615         VectorCopy(origin,origintwo);
616         if(lightmapExtraVisClusterNudge)
617         {
618                 origintwo[0]+=vecs[2][0];
619                 origintwo[1]+=vecs[2][1];
620                 origintwo[2]+=vecs[2][2];
621         }
622
623         /* get cluster */
624         pointCluster = ClusterForPointExtFilter( origintwo, LUXEL_EPSILON, numClusters, clusters );
625         
626         /* another retarded hack, storing nudge count in luxel[ 1 ] */
627         luxel[ 1 ] = 0.0f;      
628         
629         /* point in solid? (except in dark mode) */
630         if( pointCluster < 0 && dark == qfalse )
631         {
632                 /* nudge the the location around */
633                 nudge = nudges[ 0 ];
634                 while( nudge[ 0 ] > BOGUS_NUDGE && pointCluster < 0 )
635                 {
636                         /* nudge the vector around a bit */
637                         for( i = 0; i < 3; i++ )
638                         {
639                                 /* set nudged point*/
640                                 nudged[ i ] = origintwo[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
641                         }
642                         nudge += 2;
643                         
644                         /* get pvs cluster */
645                         pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); //% + 0.625 );
646                         if( pointCluster >= 0 )
647                                 VectorCopy( nudged, origin );
648                         luxel[ 1 ] += 1.0f;
649                 }
650         }
651         
652         /* as a last resort, if still in solid, try drawvert origin offset by normal (except in dark mode) */
653         if( pointCluster < 0 && si != NULL && dark == qfalse )
654         {
655                 VectorMA( dv->xyz, lightmapSampleOffset, dv->normal, nudged );
656                 pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters );
657                 if( pointCluster >= 0 )
658                         VectorCopy( nudged, origin );
659                 luxel[ 1 ] += 1.0f;
660         }
661         
662         /* valid? */
663         if( pointCluster < 0 )
664         {
665                 (*cluster) = CLUSTER_OCCLUDED;
666                 VectorClear( origin );
667                 VectorClear( normal );
668                 numLuxelsOccluded++;
669                 return (*cluster);
670         }
671         
672         /* debug code */
673         //%     Sys_Printf( "%f %f %f\n", origin[ 0 ], origin[ 1 ], origin[ 2 ] );
674         
675         /* do bumpmap calculations */
676         if( stv )
677                 PerturbNormal( dv, si, pNormal, stv, ttv );
678         else
679                 VectorCopy( dv->normal, pNormal );
680         
681         /* store the cluster and normal */
682         (*cluster) = pointCluster;
683         VectorCopy( pNormal, normal );
684         
685         /* store explicit mapping pass and implicit mapping pass */
686         luxel[ 0 ] = pass;
687         luxel[ 3 ] = 1.0f;
688         
689         /* add to count */
690         numLuxelsMapped++;
691         
692         /* return ok */
693         return (*cluster);
694 }
695
696
697
698 /*
699 MapTriangle_r()
700 recursively subdivides a triangle until its edges are shorter
701 than the distance between two luxels (thanks jc :)
702 */
703
704 static void MapTriangle_r( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 3 ], vec4_t plane, vec3_t stv[ 3 ], vec3_t ttv[ 3 ], vec3_t worldverts[ 3 ] )
705 {
706         bspDrawVert_t   mid, *dv2[ 3 ];
707         int                             max;
708         
709         
710         /* map the vertexes */
711         #if 0
712         MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
713         MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
714         MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
715         #endif
716         
717         /* subdivide calc */
718         {
719                 int                     i;
720                 float           *a, *b, dx, dy, dist, maxDist;
721                 
722                 
723                 /* find the longest edge and split it */
724                 max = -1;
725                 maxDist = 0;
726                 for( i = 0; i < 3; i++ )
727                 {
728                         /* get verts */
729                         a = dv[ i ]->lightmap[ 0 ];
730                         b = dv[ (i + 1) % 3 ]->lightmap[ 0 ];
731                         
732                         /* get dists */
733                         dx = a[ 0 ] - b[ 0 ];
734                         dy = a[ 1 ] - b[ 1 ];
735                         dist = (dx * dx) + (dy * dy);   //% sqrt( (dx * dx) + (dy * dy) );
736                         
737                         /* longer? */
738                         if( dist > maxDist )
739                         {
740                                 maxDist = dist;
741                                 max = i;
742                         }
743                 }
744                 
745                 /* try to early out */
746                 if( max < 0 || maxDist <= subdivideThreshold )  /* ydnar: was i < 0 instead of max < 0 (?) */
747                         return;
748         }
749         
750         /* split the longest edge and map it */
751         LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid );
752         MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv, worldverts );
753         
754         /* push the point up a little bit to account for fp creep (fixme: revisit this) */
755         //%     VectorMA( mid.xyz, 2.0f, mid.normal, mid.xyz );
756         
757         /* recurse to first triangle */
758         VectorCopy( dv, dv2 );
759         dv2[ max ] = &mid;
760         MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
761         
762         /* recurse to second triangle */
763         VectorCopy( dv, dv2 );
764         dv2[ (max + 1) % 3 ] = &mid;
765         MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
766 }
767
768
769
770 /*
771 MapTriangle()
772 seed function for MapTriangle_r()
773 requires a cw ordered triangle
774 */
775
776 static qboolean MapTriangle( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 3 ], qboolean mapNonAxial )
777 {
778         int                             i;
779         vec4_t                  plane;
780         vec3_t                  *stv, *ttv, stvStatic[ 3 ], ttvStatic[ 3 ];
781         vec3_t                  worldverts[ 3 ];
782         
783         
784         /* get plane if possible */
785         if( lm->plane != NULL )
786         {
787                 VectorCopy( lm->plane, plane );
788                 plane[ 3 ] = lm->plane[ 3 ];
789         }
790         
791         /* otherwise make one from the points */
792         else if( PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) == qfalse )
793                 return qfalse;
794         
795         /* check to see if we need to calculate texture->world tangent vectors */
796         if( info->si->normalImage != NULL && CalcTangentVectors( 3, dv, stvStatic, ttvStatic ) )
797         {
798                 stv = stvStatic;
799                 ttv = ttvStatic;
800         }
801         else
802         {
803                 stv = NULL;
804                 ttv = NULL;
805         }
806         
807         VectorCopy( dv[ 0 ]->xyz, worldverts[ 0 ] );
808         VectorCopy( dv[ 1 ]->xyz, worldverts[ 1 ] );
809         VectorCopy( dv[ 2 ]->xyz, worldverts[ 2 ] );
810
811         /* map the vertexes */
812         MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, worldverts );
813         MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, worldverts );
814         MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, worldverts );
815         
816         /* 2002-11-20: prefer axial triangle edges */
817         if( mapNonAxial )
818         {
819                 /* subdivide the triangle */
820                 MapTriangle_r( lm, info, dv, plane, stv, ttv, worldverts );
821                 return qtrue;
822         }
823         
824         for( i = 0; i < 3; i++ )
825         {
826                 float                   *a, *b;
827                 bspDrawVert_t   *dv2[ 3 ];
828                 
829                 
830                 /* get verts */
831                 a = dv[ i ]->lightmap[ 0 ];
832                 b = dv[ (i + 1) % 3 ]->lightmap[ 0 ];
833                 
834                 /* make degenerate triangles for mapping edges */
835                 if( fabs( a[ 0 ] - b[ 0 ] ) < 0.01f || fabs( a[ 1 ] - b[ 1 ] ) < 0.01f )
836                 {
837                         dv2[ 0 ] = dv[ i ];
838                         dv2[ 1 ] = dv[ (i + 1) % 3 ];
839                         dv2[ 2 ] = dv[ (i + 1) % 3 ];
840                         
841                         /* map the degenerate triangle */
842                         MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
843                 }
844         }
845         
846         return qtrue;
847 }
848
849
850
851 /*
852 MapQuad_r()
853 recursively subdivides a quad until its edges are shorter
854 than the distance between two luxels
855 */
856
857 static void MapQuad_r( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 4 ], vec4_t plane, vec3_t stv[ 4 ], vec3_t ttv[ 4 ] )
858 {
859         bspDrawVert_t   mid[ 2 ], *dv2[ 4 ];
860         int                             max;
861         
862         
863         /* subdivide calc */
864         {
865                 int                     i;
866                 float           *a, *b, dx, dy, dist, maxDist;
867                 
868                 
869                 /* find the longest edge and split it */
870                 max = -1;
871                 maxDist = 0;
872                 for( i = 0; i < 4; i++ )
873                 {
874                         /* get verts */
875                         a = dv[ i ]->lightmap[ 0 ];
876                         b = dv[ (i + 1) % 4 ]->lightmap[ 0 ];
877                         
878                         /* get dists */
879                         dx = a[ 0 ] - b[ 0 ];
880                         dy = a[ 1 ] - b[ 1 ];
881                         dist = (dx * dx) + (dy * dy);   //% sqrt( (dx * dx) + (dy * dy) );
882                         
883                         /* longer? */
884                         if( dist > maxDist )
885                         {
886                                 maxDist = dist;
887                                 max = i;
888                         }
889                 }
890                 
891                 /* try to early out */
892                 if( max < 0 || maxDist <= subdivideThreshold )
893                         return;
894         }
895         
896         /* we only care about even/odd edges */
897         max &= 1;
898         
899         /* split the longest edges */
900         LerpDrawVert( dv[ max ], dv[ (max + 1) % 4 ], &mid[ 0 ] );
901         LerpDrawVert( dv[ max + 2 ], dv[ (max + 3) % 4 ], &mid[ 1 ] );
902         
903         /* map the vertexes */
904         MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv, NULL );
905         MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv, NULL );
906         
907         /* 0 and 2 */
908         if( max == 0 )
909         {
910                 /* recurse to first quad */
911                 dv2[ 0 ] = dv[ 0 ];
912                 dv2[ 1 ] = &mid[ 0 ];
913                 dv2[ 2 ] = &mid[ 1 ];
914                 dv2[ 3 ] = dv[ 3 ];
915                 MapQuad_r( lm, info, dv2, plane, stv, ttv );
916                 
917                 /* recurse to second quad */
918                 dv2[ 0 ] = &mid[ 0 ];
919                 dv2[ 1 ] = dv[ 1 ];
920                 dv2[ 2 ] = dv[ 2 ];
921                 dv2[ 3 ] = &mid[ 1 ];
922                 MapQuad_r( lm, info, dv2, plane, stv, ttv );
923         }
924         
925         /* 1 and 3 */
926         else
927         {
928                 /* recurse to first quad */
929                 dv2[ 0 ] = dv[ 0 ];
930                 dv2[ 1 ] = dv[ 1 ];
931                 dv2[ 2 ] = &mid[ 0 ];
932                 dv2[ 3 ] = &mid[ 1 ];
933                 MapQuad_r( lm, info, dv2, plane, stv, ttv );
934                 
935                 /* recurse to second quad */
936                 dv2[ 0 ] = &mid[ 1 ];
937                 dv2[ 1 ] = &mid[ 0 ];
938                 dv2[ 2 ] = dv[ 2 ];
939                 dv2[ 3 ] = dv[ 3 ];
940                 MapQuad_r( lm, info, dv2, plane, stv, ttv );
941         }
942 }
943
944
945
946 /*
947 MapQuad()
948 seed function for MapQuad_r()
949 requires a cw ordered triangle quad
950 */
951
952 #define QUAD_PLANAR_EPSILON             0.5f
953
954 static qboolean MapQuad( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 4 ] )
955 {
956         float                   dist;
957         vec4_t                  plane;
958         vec3_t                  *stv, *ttv, stvStatic[ 4 ], ttvStatic[ 4 ];
959         
960         
961         /* get plane if possible */
962         if( lm->plane != NULL )
963         {
964                 VectorCopy( lm->plane, plane );
965                 plane[ 3 ] = lm->plane[ 3 ];
966         }
967         
968         /* otherwise make one from the points */
969         else if( PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) == qfalse )
970                 return qfalse;
971         
972         /* 4th point must fall on the plane */
973         dist = DotProduct( plane, dv[ 3 ]->xyz ) - plane[ 3 ];
974         if( fabs( dist ) > QUAD_PLANAR_EPSILON )
975                 return qfalse;
976         
977         /* check to see if we need to calculate texture->world tangent vectors */
978         if( info->si->normalImage != NULL && CalcTangentVectors( 4, dv, stvStatic, ttvStatic ) )
979         {
980                 stv = stvStatic;
981                 ttv = ttvStatic;
982         }
983         else
984         {
985                 stv = NULL;
986                 ttv = NULL;
987         }
988         
989         /* map the vertexes */
990         MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, NULL );
991         MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, NULL );
992         MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, NULL );
993         MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv, NULL );
994         
995         /* subdivide the quad */
996         MapQuad_r( lm, info, dv, plane, stv, ttv );
997         return qtrue;
998 }
999
1000
1001
1002 /*
1003 MapRawLightmap()
1004 maps the locations, normals, and pvs clusters for a raw lightmap
1005 */
1006
1007 #define VectorDivide( in, d, out )      VectorScale( in, (1.0f / (d)), out )    //%     (out)[ 0 ] = (in)[ 0 ] / (d), (out)[ 1 ] = (in)[ 1 ] / (d), (out)[ 2 ] = (in)[ 2 ] / (d)
1008
1009 void MapRawLightmap( int rawLightmapNum )
1010 {
1011         int                                     n, num, i, x, y, sx, sy, pw[ 5 ], r, *cluster, mapNonAxial;
1012         float                           *luxel, *origin, *normal, samples, radius, pass;
1013         rawLightmap_t           *lm;
1014         bspDrawSurface_t        *ds;
1015         surfaceInfo_t           *info;
1016         mesh_t                          src, *subdivided, *mesh;
1017         bspDrawVert_t           *verts, *dv[ 4 ], fake;
1018         
1019         
1020         /* bail if this number exceeds the number of raw lightmaps */
1021         if( rawLightmapNum >= numRawLightmaps )
1022                 return;
1023         
1024         /* get lightmap */
1025         lm = &rawLightmaps[ rawLightmapNum ];
1026         
1027         /* -----------------------------------------------------------------
1028            map referenced surfaces onto the raw lightmap
1029            ----------------------------------------------------------------- */
1030         
1031         /* walk the list of surfaces on this raw lightmap */
1032         for( n = 0; n < lm->numLightSurfaces; n++ )
1033         {
1034                 /* with > 1 surface per raw lightmap, clear occluded */
1035                 if( n > 0 )
1036                 {
1037                         for( y = 0; y < lm->sh; y++ )
1038                         {
1039                                 for( x = 0; x < lm->sw; x++ )
1040                                 {
1041                                         /* get cluster */
1042                                         cluster = SUPER_CLUSTER( x, y );
1043                                         if( *cluster < 0 )
1044                                                 *cluster = CLUSTER_UNMAPPED;
1045                                 }
1046                         }
1047                 }
1048                 
1049                 /* get surface */
1050                 num = lightSurfaces[ lm->firstLightSurface + n ];
1051                 ds = &bspDrawSurfaces[ num ];
1052                 info = &surfaceInfos[ num ];
1053                 
1054                 /* bail if no lightmap to calculate */
1055                 if( info->lm != lm )
1056                 {
1057                         Sys_Printf( "!" );
1058                         continue;
1059                 }
1060                 
1061                 /* map the surface onto the lightmap origin/cluster/normal buffers */
1062                 switch( ds->surfaceType )
1063                 {
1064                         case MST_PLANAR:
1065                                 /* get verts */
1066                                 verts = yDrawVerts + ds->firstVert;
1067                                 
1068                                 /* map the triangles */
1069                                 for( mapNonAxial = 0; mapNonAxial < 2; mapNonAxial++ )
1070                                 {
1071                                         for( i = 0; i < ds->numIndexes; i += 3 )
1072                                         {
1073                                                 dv[ 0 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i ] ];
1074                                                 dv[ 1 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 1 ] ];
1075                                                 dv[ 2 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 2 ] ];
1076                                                 MapTriangle( lm, info, dv, mapNonAxial );
1077                                         }
1078                                 }
1079                                 break;
1080                         
1081                         case MST_PATCH:
1082                                 /* make a mesh from the drawsurf */ 
1083                                 src.width = ds->patchWidth;
1084                                 src.height = ds->patchHeight;
1085                                 src.verts = &yDrawVerts[ ds->firstVert ];
1086                                 //%     subdivided = SubdivideMesh( src, 8, 512 );
1087                                 subdivided = SubdivideMesh2( src, info->patchIterations );
1088                                 
1089                                 /* fit it to the curve and remove colinear verts on rows/columns */
1090                                 PutMeshOnCurve( *subdivided );
1091                                 mesh = RemoveLinearMeshColumnsRows( subdivided );
1092                                 FreeMesh( subdivided );
1093                                 
1094                                 /* get verts */
1095                                 verts = mesh->verts;
1096                                 
1097                                 /* debug code */
1098                                 #if 0
1099                                         if( lm->plane )
1100                                         {
1101                                                 Sys_Printf( "Planar patch: [%1.3f %1.3f %1.3f] [%1.3f %1.3f %1.3f] [%1.3f %1.3f %1.3f]\n",
1102                                                         lm->plane[ 0 ], lm->plane[ 1 ], lm->plane[ 2 ],
1103                                                         lm->vecs[ 0 ][ 0 ], lm->vecs[ 0 ][ 1 ], lm->vecs[ 0 ][ 2 ],
1104                                                         lm->vecs[ 1 ][ 0 ], lm->vecs[ 1 ][ 1 ], lm->vecs[ 1 ][ 2 ] );
1105                                         }
1106                                 #endif
1107                                 
1108                                 /* map the mesh quads */
1109                                 #if 0
1110
1111                                 for( mapNonAxial = 0; mapNonAxial < 2; mapNonAxial++ )
1112                                 {
1113                                         for( y = 0; y < (mesh->height - 1); y++ )
1114                                         {
1115                                                 for( x = 0; x < (mesh->width - 1); x++ )
1116                                                 {
1117                                                         /* set indexes */
1118                                                         pw[ 0 ] = x + (y * mesh->width);
1119                                                         pw[ 1 ] = x + ((y + 1) * mesh->width);
1120                                                         pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
1121                                                         pw[ 3 ] = x + 1 + (y * mesh->width);
1122                                                         pw[ 4 ] = x + (y * mesh->width);        /* same as pw[ 0 ] */
1123                                                         
1124                                                         /* set radix */
1125                                                         r = (x + y) & 1;
1126                                                         
1127                                                         /* get drawverts and map first triangle */
1128                                                         dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1129                                                         dv[ 1 ] = &verts[ pw[ r + 1 ] ];
1130                                                         dv[ 2 ] = &verts[ pw[ r + 2 ] ];
1131                                                         MapTriangle( lm, info, dv, mapNonAxial );
1132                                                         
1133                                                         /* get drawverts and map second triangle */
1134                                                         dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1135                                                         dv[ 1 ] = &verts[ pw[ r + 2 ] ];
1136                                                         dv[ 2 ] = &verts[ pw[ r + 3 ] ];
1137                                                         MapTriangle( lm, info, dv, mapNonAxial );
1138                                                 }
1139                                         }
1140                                 }
1141                                 
1142                                 #else
1143                                 
1144                                 for( y = 0; y < (mesh->height - 1); y++ )
1145                                 {
1146                                         for( x = 0; x < (mesh->width - 1); x++ )
1147                                         {
1148                                                 /* set indexes */
1149                                                 pw[ 0 ] = x + (y * mesh->width);
1150                                                 pw[ 1 ] = x + ((y + 1) * mesh->width);
1151                                                 pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
1152                                                 pw[ 3 ] = x + 1 + (y * mesh->width);
1153                                                 pw[ 4 ] = pw[ 0 ];
1154                                                 
1155                                                 /* set radix */
1156                                                 r = (x + y) & 1;
1157                                                 
1158                                                 /* attempt to map quad first */
1159                                                 dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1160                                                 dv[ 1 ] = &verts[ pw[ r + 1 ] ];
1161                                                 dv[ 2 ] = &verts[ pw[ r + 2 ] ];
1162                                                 dv[ 3 ] = &verts[ pw[ r + 3 ] ];
1163                                                 if( MapQuad( lm, info, dv ) )
1164                                                         continue;
1165                                                 
1166                                                 for( mapNonAxial = 0; mapNonAxial < 2; mapNonAxial++ )
1167                                                 {
1168                                                         /* get drawverts and map first triangle */
1169                                                         dv[ 1 ] = &verts[ pw[ r + 1 ] ];
1170                                                         dv[ 2 ] = &verts[ pw[ r + 2 ] ];
1171                                                         MapTriangle( lm, info, dv, mapNonAxial );
1172                                                         
1173                                                         /* get drawverts and map second triangle */
1174                                                         dv[ 1 ] = &verts[ pw[ r + 2 ] ];
1175                                                         dv[ 2 ] = &verts[ pw[ r + 3 ] ];
1176                                                         MapTriangle( lm, info, dv, mapNonAxial );
1177                                                 }
1178                                         }
1179                                 }
1180                                 
1181                                 #endif
1182                                 
1183                                 /* free the mesh */
1184                                 FreeMesh( mesh );
1185                                 break;
1186                         
1187                         default:
1188                                 break;
1189                 }
1190         }
1191         
1192         /* -----------------------------------------------------------------
1193            average and clean up luxel normals
1194            ----------------------------------------------------------------- */
1195         
1196         /* walk the luxels */
1197         for( y = 0; y < lm->sh; y++ )
1198         {
1199                 for( x = 0; x < lm->sw; x++ )
1200                 {
1201                         /* get luxel */
1202                         luxel = SUPER_LUXEL( 0, x, y );
1203                         normal = SUPER_NORMAL( x, y );
1204                         cluster = SUPER_CLUSTER( x, y );
1205
1206                         /* only look at mapped luxels */
1207                         if( *cluster < 0 )
1208                                 continue;
1209                         
1210                         /* the normal data could be the sum of multiple samples */
1211                         if( luxel[ 3 ] > 1.0f )
1212                                 VectorNormalize( normal, normal );
1213                         
1214                         /* mark this luxel as having only one normal */
1215                         luxel[ 3 ] = 1.0f;
1216                 }
1217         }
1218         
1219         /* non-planar surfaces stop here */
1220         if( lm->plane == NULL )
1221                 return;
1222         
1223         /* -----------------------------------------------------------------
1224            map occluded or unuxed luxels
1225            ----------------------------------------------------------------- */
1226         
1227         /* walk the luxels */
1228         radius = floor( superSample / 2 );
1229         radius = radius > 0 ? radius : 1.0f;
1230         radius += 1.0f;
1231         for( pass = 2.0f; pass <= radius; pass += 1.0f )
1232         {
1233                 for( y = 0; y < lm->sh; y++ )
1234                 {
1235                         for( x = 0; x < lm->sw; x++ )
1236                         {
1237                                 /* get luxel */
1238                                 luxel = SUPER_LUXEL( 0, x, y );
1239                                 normal = SUPER_NORMAL( x, y );
1240                                 cluster = SUPER_CLUSTER( x, y );
1241                                 
1242                                 /* only look at unmapped luxels */
1243                                 if( *cluster != CLUSTER_UNMAPPED )
1244                                         continue;
1245                                 
1246                                 /* divine a normal and origin from neighboring luxels */
1247                                 VectorClear( fake.xyz );
1248                                 VectorClear( fake.normal );
1249                                 fake.lightmap[ 0 ][ 0 ] = x;    //% 0.0001 + x;
1250                                 fake.lightmap[ 0 ][ 1 ] = y;    //% 0.0001 + y;
1251                                 samples = 0.0f;
1252                                 for( sy = (y - 1); sy <= (y + 1); sy++ )
1253                                 {
1254                                         if( sy < 0 || sy >= lm->sh )
1255                                                 continue;
1256                                         
1257                                         for( sx = (x - 1); sx <= (x + 1); sx++ )
1258                                         {
1259                                                 if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
1260                                                         continue;
1261                                                 
1262                                                 /* get neighboring luxel */
1263                                                 luxel = SUPER_LUXEL( 0, sx, sy );
1264                                                 origin = SUPER_ORIGIN( sx, sy );
1265                                                 normal = SUPER_NORMAL( sx, sy );
1266                                                 cluster = SUPER_CLUSTER( sx, sy );
1267                                                 
1268                                                 /* only consider luxels mapped in previous passes */
1269                                                 if( *cluster < 0 || luxel[ 0 ] >= pass )
1270                                                         continue;
1271                                                 
1272                                                 /* add its distinctiveness to our own */
1273                                                 VectorAdd( fake.xyz, origin, fake.xyz );
1274                                                 VectorAdd( fake.normal, normal, fake.normal );
1275                                                 samples += luxel[ 3 ];
1276                                         }
1277                                 }
1278                                 
1279                                 /* any samples? */
1280                                 if( samples == 0.0f )
1281                                         continue;
1282                                 
1283                                 /* average */
1284                                 VectorDivide( fake.xyz, samples, fake.xyz );
1285                                 //%     VectorDivide( fake.normal, samples, fake.normal );
1286                                 if( VectorNormalize( fake.normal, fake.normal ) == 0.0f )
1287                                         continue;
1288                                 
1289                                 /* map the fake vert */
1290                                 MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL, NULL );
1291                         }
1292                 }
1293         }
1294         
1295         /* -----------------------------------------------------------------
1296            average and clean up luxel normals
1297            ----------------------------------------------------------------- */
1298         
1299         /* walk the luxels */
1300         for( y = 0; y < lm->sh; y++ )
1301         {
1302                 for( x = 0; x < lm->sw; x++ )
1303                 {
1304                         /* get luxel */
1305                         luxel = SUPER_LUXEL( 0, x, y );
1306                         normal = SUPER_NORMAL( x, y );
1307                         cluster = SUPER_CLUSTER( x, y );
1308                         
1309                         /* only look at mapped luxels */
1310                         if( *cluster < 0 )
1311                                 continue;
1312                         
1313                         /* the normal data could be the sum of multiple samples */
1314                         if( luxel[ 3 ] > 1.0f )
1315                                 VectorNormalize( normal, normal );
1316                         
1317                         /* mark this luxel as having only one normal */
1318                         luxel[ 3 ] = 1.0f;
1319                 }
1320         }
1321         
1322         /* debug code */
1323         #if 0
1324                 Sys_Printf( "\n" );
1325                 for( y = 0; y < lm->sh; y++ )
1326                 {
1327                         for( x = 0; x < lm->sw; x++ )
1328                         {
1329                                 vec3_t  mins, maxs;
1330                                 
1331
1332                                 cluster = SUPER_CLUSTER( x, y );
1333                                 origin = SUPER_ORIGIN( x, y );
1334                                 normal = SUPER_NORMAL( x, y );
1335                                 luxel = SUPER_LUXEL( x, y );
1336                                 
1337                                 if( *cluster < 0 )
1338                                         continue;
1339                                 
1340                                 /* check if within the bounding boxes of all surfaces referenced */
1341                                 ClearBounds( mins, maxs );
1342                                 for( n = 0; n < lm->numLightSurfaces; n++ )
1343                                 {
1344                                         int TOL;
1345                                         info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + n ] ];
1346                                         TOL = info->sampleSize + 2;
1347                                         AddPointToBounds( info->mins, mins, maxs );
1348                                         AddPointToBounds( info->maxs, mins, maxs );
1349                                         if( origin[ 0 ] > (info->mins[ 0 ] - TOL) && origin[ 0 ] < (info->maxs[ 0 ] + TOL) &&
1350                                                 origin[ 1 ] > (info->mins[ 1 ] - TOL) && origin[ 1 ] < (info->maxs[ 1 ] + TOL) &&
1351                                                 origin[ 2 ] > (info->mins[ 2 ] - TOL) && origin[ 2 ] < (info->maxs[ 2 ] + TOL) )
1352                                                 break;
1353                                 }
1354                                 
1355                                 /* inside? */
1356                                 if( n < lm->numLightSurfaces )
1357                                         continue;
1358                                 
1359                                 /* report bogus origin */
1360                                 Sys_Printf( "%6d [%2d,%2d] (%4d): XYZ(%+4.1f %+4.1f %+4.1f) LO(%+4.1f %+4.1f %+4.1f) HI(%+4.1f %+4.1f %+4.1f) <%3.0f>\n",
1361                                         rawLightmapNum, x, y, *cluster,
1362                                         origin[ 0 ], origin[ 1 ], origin[ 2 ],
1363                                         mins[ 0 ], mins[ 1 ], mins[ 2 ],
1364                                         maxs[ 0 ], maxs[ 1 ], maxs[ 2 ],
1365                                         luxel[ 3 ] );
1366                         }
1367                 }
1368         #endif
1369 }
1370
1371
1372
1373 /*
1374 SetupDirt()
1375 sets up dirtmap (ambient occlusion)
1376 */
1377
1378 #define DIRT_CONE_ANGLE                         88      /* degrees */
1379 #define DIRT_NUM_ANGLE_STEPS            16
1380 #define DIRT_NUM_ELEVATION_STEPS        3
1381 #define DIRT_NUM_VECTORS                        (DIRT_NUM_ANGLE_STEPS * DIRT_NUM_ELEVATION_STEPS)
1382
1383 static vec3_t           dirtVectors[ DIRT_NUM_VECTORS ];
1384 static int                      numDirtVectors = 0;
1385
1386 void SetupDirt( void )
1387 {
1388         int             i, j;
1389         float   angle, elevation, angleStep, elevationStep;
1390         
1391         
1392         /* note it */
1393         Sys_FPrintf( SYS_VRB, "--- SetupDirt ---\n" );
1394         
1395         /* calculate angular steps */
1396         angleStep = DEG2RAD( 360.0f / DIRT_NUM_ANGLE_STEPS );
1397         elevationStep = DEG2RAD( DIRT_CONE_ANGLE / DIRT_NUM_ELEVATION_STEPS );
1398         
1399         /* iterate angle */
1400         angle = 0.0f;
1401         for( i = 0, angle = 0.0f; i < DIRT_NUM_ANGLE_STEPS; i++, angle += angleStep )
1402         {
1403                 /* iterate elevation */
1404                 for( j = 0, elevation = elevationStep * 0.5f; j < DIRT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep )
1405                 {
1406                         dirtVectors[ numDirtVectors ][ 0 ] = sin( elevation ) * cos( angle );
1407                         dirtVectors[ numDirtVectors ][ 1 ] = sin( elevation ) * sin( angle );
1408                         dirtVectors[ numDirtVectors ][ 2 ] = cos( elevation );
1409                         numDirtVectors++;
1410                 }
1411         }
1412         
1413         /* emit some statistics */
1414         Sys_FPrintf( SYS_VRB, "%9d dirtmap vectors\n", numDirtVectors );
1415 }
1416
1417
1418 /*
1419 DirtForSample()
1420 calculates dirt value for a given sample
1421 */
1422
1423 float DirtForSample( trace_t *trace )
1424 {
1425         int             i;
1426         float   gatherDirt, outDirt, angle, elevation, ooDepth;
1427         vec3_t  normal, worldUp, myUp, myRt, temp, direction, displacement;
1428         
1429         
1430         /* dummy check */
1431         if( !dirty )
1432                 return 1.0f;
1433         if( trace == NULL || trace->cluster < 0 )
1434                 return 0.0f;
1435         
1436         /* setup */
1437         gatherDirt = 0.0f;
1438         ooDepth = 1.0f / dirtDepth;
1439         VectorCopy( trace->normal, normal );
1440         
1441         /* check if the normal is aligned to the world-up */
1442         if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f && ( normal[ 2 ] == 1.0f || normal[ 2 ] == -1.0f ) )
1443         {
1444                 if( normal[ 2 ] == 1.0f )               
1445                 {
1446                         VectorSet( myRt, 1.0f, 0.0f, 0.0f );
1447                         VectorSet( myUp, 0.0f, 1.0f, 0.0f );
1448                 }
1449                 else if( normal[ 2 ] == -1.0f )
1450                 {
1451                         VectorSet( myRt, -1.0f, 0.0f, 0.0f );
1452                         VectorSet( myUp,  0.0f, 1.0f, 0.0f );
1453                 }
1454         }
1455         else
1456         {
1457                 VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
1458                 CrossProduct( normal, worldUp, myRt );
1459                 VectorNormalize( myRt, myRt );
1460                 CrossProduct( myRt, normal, myUp );
1461                 VectorNormalize( myUp, myUp );
1462         }
1463         
1464         /* 1 = random mode, 0 (well everything else) = non-random mode */
1465         if( dirtMode == 1 )
1466         {
1467                 /* iterate */
1468                 for( i = 0; i < numDirtVectors; i++ )
1469                 {
1470                         /* get random vector */
1471                         angle = Random() * DEG2RAD( 360.0f );
1472                         elevation = Random() * DEG2RAD( DIRT_CONE_ANGLE );
1473                         temp[ 0 ] = cos( angle ) * sin( elevation );
1474                         temp[ 1 ] = sin( angle ) * sin( elevation );
1475                         temp[ 2 ] = cos( elevation );
1476                         
1477                         /* transform into tangent space */
1478                         direction[ 0 ] = myRt[ 0 ] * temp[ 0 ] + myUp[ 0 ] * temp[ 1 ] + normal[ 0 ] * temp[ 2 ];
1479                         direction[ 1 ] = myRt[ 1 ] * temp[ 0 ] + myUp[ 1 ] * temp[ 1 ] + normal[ 1 ] * temp[ 2 ];
1480                         direction[ 2 ] = myRt[ 2 ] * temp[ 0 ] + myUp[ 2 ] * temp[ 1 ] + normal[ 2 ] * temp[ 2 ];
1481                         
1482                         /* set endpoint */
1483                         VectorMA( trace->origin, dirtDepth, direction, trace->end );
1484                         SetupTrace( trace );
1485                         
1486                         /* trace */
1487                         TraceLine( trace );
1488                         if( trace->opaque && !(trace->compileFlags & C_SKY) )
1489                         {
1490                                 VectorSubtract( trace->hit, trace->origin, displacement );
1491                                 gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1492                         }
1493                 }
1494         }
1495         else
1496         {
1497                 /* iterate through ordered vectors */
1498                 for( i = 0; i < numDirtVectors; i++ )
1499                 {
1500                         /* transform vector into tangent space */
1501                         direction[ 0 ] = myRt[ 0 ] * dirtVectors[ i ][ 0 ] + myUp[ 0 ] * dirtVectors[ i ][ 1 ] + normal[ 0 ] * dirtVectors[ i ][ 2 ];
1502                         direction[ 1 ] = myRt[ 1 ] * dirtVectors[ i ][ 0 ] + myUp[ 1 ] * dirtVectors[ i ][ 1 ] + normal[ 1 ] * dirtVectors[ i ][ 2 ];
1503                         direction[ 2 ] = myRt[ 2 ] * dirtVectors[ i ][ 0 ] + myUp[ 2 ] * dirtVectors[ i ][ 1 ] + normal[ 2 ] * dirtVectors[ i ][ 2 ];
1504                         
1505                         /* set endpoint */
1506                         VectorMA( trace->origin, dirtDepth, direction, trace->end );
1507                         SetupTrace( trace );
1508                         
1509                         /* trace */
1510                         TraceLine( trace );
1511                         if( trace->opaque )
1512                         {
1513                                 VectorSubtract( trace->hit, trace->origin, displacement );
1514                                 gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1515                         }
1516                 }
1517         }
1518         
1519         /* direct ray */
1520         VectorMA( trace->origin, dirtDepth, normal, trace->end );
1521         SetupTrace( trace );
1522         
1523         /* trace */
1524         TraceLine( trace );
1525         if( trace->opaque )
1526         {
1527                 VectorSubtract( trace->hit, trace->origin, displacement );
1528                 gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1529         }
1530         
1531         /* early out */
1532         if( gatherDirt <= 0.0f )
1533                 return 1.0f;
1534         
1535         /* apply gain (does this even do much? heh) */
1536         outDirt = pow( gatherDirt / (numDirtVectors + 1), dirtGain );
1537         if( outDirt > 1.0f )
1538                 outDirt = 1.0f;
1539         
1540         /* apply scale */
1541         outDirt *= dirtScale;
1542         if( outDirt > 1.0f )
1543                 outDirt = 1.0f;
1544         
1545         /* return to sender */
1546         return 1.0f - outDirt;
1547 }
1548
1549
1550
1551 /*
1552 DirtyRawLightmap()
1553 calculates dirty fraction for each luxel
1554 */
1555
1556 void DirtyRawLightmap( int rawLightmapNum )
1557 {
1558         int                                     i, x, y, sx, sy, *cluster;
1559         float                           *origin, *normal, *dirt, *dirt2, average, samples;
1560         rawLightmap_t           *lm;
1561         surfaceInfo_t           *info;
1562         trace_t                         trace;
1563         qboolean                        noDirty;
1564
1565         
1566         /* bail if this number exceeds the number of raw lightmaps */
1567         if( rawLightmapNum >= numRawLightmaps )
1568                 return;
1569         
1570         /* get lightmap */
1571         lm = &rawLightmaps[ rawLightmapNum ];
1572         
1573         /* setup trace */
1574         trace.testOcclusion = qtrue;
1575         trace.forceSunlight = qfalse;
1576         trace.recvShadows = lm->recvShadows;
1577         trace.numSurfaces = lm->numLightSurfaces;
1578         trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
1579         trace.inhibitRadius = 0.0f;
1580         trace.testAll = qfalse;
1581         
1582         /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
1583         trace.twoSided = qfalse;
1584         for( i = 0; i < trace.numSurfaces; i++ )
1585         {
1586                 /* get surface */
1587                 info = &surfaceInfos[ trace.surfaces[ i ] ];
1588                 
1589                 /* check twosidedness */
1590                 if( info->si->twoSided )
1591                 {
1592                         trace.twoSided = qtrue;
1593                         break;
1594                 }
1595         }
1596
1597         noDirty = qfalse;
1598         for( i = 0; i < trace.numSurfaces; i++ )
1599         {
1600                 /* get surface */
1601                 info = &surfaceInfos[ trace.surfaces[ i ] ];
1602
1603                 /* check twosidedness */
1604                 if( info->si->noDirty )
1605                 {
1606                         noDirty = qtrue;
1607                         break;
1608                 }
1609         }
1610         
1611         /* gather dirt */
1612         for( y = 0; y < lm->sh; y++ )
1613         {
1614                 for( x = 0; x < lm->sw; x++ )
1615                 {
1616                         /* get luxel */
1617                         cluster = SUPER_CLUSTER( x, y );
1618                         origin = SUPER_ORIGIN( x, y );
1619                         normal = SUPER_NORMAL( x, y );
1620                         dirt = SUPER_DIRT( x, y );
1621                         
1622                         /* set default dirt */
1623                         *dirt = 0.0f;
1624                         
1625                         /* only look at mapped luxels */
1626                         if( *cluster < 0 )
1627                                 continue;
1628
1629                         /* don't apply dirty on this surface */
1630                         if( noDirty )
1631                         {
1632                                 *dirt = 1.0f;
1633                                 continue;
1634                         }
1635                         
1636                         /* copy to trace */
1637                         trace.cluster = *cluster;
1638                         VectorCopy( origin, trace.origin );
1639                         VectorCopy( normal, trace.normal );
1640                         
1641                         /* get dirt */
1642                         *dirt = DirtForSample( &trace );
1643                 }
1644         }
1645         
1646         /* testing no filtering */
1647         //%     return;
1648         
1649         /* filter dirt */
1650         for( y = 0; y < lm->sh; y++ )
1651         {
1652                 for( x = 0; x < lm->sw; x++ )
1653                 {
1654                         /* get luxel */
1655                         cluster = SUPER_CLUSTER( x, y );
1656                         dirt = SUPER_DIRT( x, y );
1657                         
1658                         /* filter dirt by adjacency to unmapped luxels */
1659                         average = *dirt;
1660                         samples = 1.0f;
1661                         for( sy = (y - 1); sy <= (y + 1); sy++ )
1662                         {
1663                                 if( sy < 0 || sy >= lm->sh )
1664                                         continue;
1665                                 
1666                                 for( sx = (x - 1); sx <= (x + 1); sx++ )
1667                                 {
1668                                         if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
1669                                                 continue;
1670                                         
1671                                         /* get neighboring luxel */
1672                                         cluster = SUPER_CLUSTER( sx, sy );
1673                                         dirt2 = SUPER_DIRT( sx, sy );
1674                                         if( *cluster < 0 || *dirt2 <= 0.0f )
1675                                                 continue;
1676                                         
1677                                         /* add it */
1678                                         average += *dirt2;
1679                                         samples += 1.0f;
1680                                 }
1681                                 
1682                                 /* bail */
1683                                 if( samples <= 0.0f )
1684                                         break;
1685                         }
1686                         
1687                         /* bail */
1688                         if( samples <= 0.0f )
1689                                 continue;
1690                         
1691                         /* scale dirt */
1692                         *dirt = average / samples;
1693                 }
1694         }
1695 }
1696
1697
1698
1699 /*
1700 SubmapRawLuxel()
1701 calculates the pvs cluster, origin, normal of a sub-luxel
1702 */
1703
1704 static qboolean SubmapRawLuxel( rawLightmap_t *lm, int x, int y, float bx, float by, int *sampleCluster, vec3_t sampleOrigin, vec3_t sampleNormal )
1705 {
1706         int                     i, *cluster, *cluster2;
1707         float           *origin, *origin2, *normal;     //%     , *normal2;
1708         vec3_t          originVecs[ 2 ];                        //%     , normalVecs[ 2 ];
1709         
1710         
1711         /* calulate x vector */
1712         if( (x < (lm->sw - 1) && bx >= 0.0f) || (x == 0 && bx <= 0.0f) )
1713         {
1714                 cluster = SUPER_CLUSTER( x, y );
1715                 origin = SUPER_ORIGIN( x, y );
1716                 //%     normal = SUPER_NORMAL( x, y );
1717                 cluster2 = SUPER_CLUSTER( x + 1, y );
1718                 origin2 = *cluster2 < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x + 1, y );
1719                 //%     normal2 = *cluster2 < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x + 1, y );
1720         }
1721         else if( (x > 0 && bx <= 0.0f) || (x == (lm->sw - 1) && bx >= 0.0f) )
1722         {
1723                 cluster = SUPER_CLUSTER( x - 1, y );
1724                 origin = *cluster < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x - 1, y );
1725                 //%     normal = *cluster < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x - 1, y );
1726                 cluster2 = SUPER_CLUSTER( x, y );
1727                 origin2 = SUPER_ORIGIN( x, y );
1728                 //%     normal2 = SUPER_NORMAL( x, y );
1729         }
1730         else
1731         {
1732                 Error( "Spurious lightmap S vector\n" );
1733         }
1734         
1735         VectorSubtract( origin2, origin, originVecs[ 0 ] );
1736         //%     VectorSubtract( normal2, normal, normalVecs[ 0 ] );
1737         
1738         /* calulate y vector */
1739         if( (y < (lm->sh - 1) && bx >= 0.0f) || (y == 0 && bx <= 0.0f) )
1740         {
1741                 cluster = SUPER_CLUSTER( x, y );
1742                 origin = SUPER_ORIGIN( x, y );
1743                 //%     normal = SUPER_NORMAL( x, y );
1744                 cluster2 = SUPER_CLUSTER( x, y + 1 );
1745                 origin2 = *cluster2 < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x, y + 1 );
1746                 //%     normal2 = *cluster2 < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x, y + 1 );
1747         }
1748         else if( (y > 0 && bx <= 0.0f) || (y == (lm->sh - 1) && bx >= 0.0f) )
1749         {
1750                 cluster = SUPER_CLUSTER( x, y - 1 );
1751                 origin = *cluster < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x, y - 1 );
1752                 //%     normal = *cluster < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x, y - 1 );
1753                 cluster2 = SUPER_CLUSTER( x, y );
1754                 origin2 = SUPER_ORIGIN( x, y );
1755                 //%     normal2 = SUPER_NORMAL( x, y );
1756         }
1757         else
1758                 Sys_Printf( "WARNING: Spurious lightmap T vector\n" );
1759         
1760         VectorSubtract( origin2, origin, originVecs[ 1 ] );
1761         //%     VectorSubtract( normal2, normal, normalVecs[ 1 ] );
1762         
1763         /* calculate new origin */
1764         //%     VectorMA( origin, bx, originVecs[ 0 ], sampleOrigin );
1765         //%     VectorMA( sampleOrigin, by, originVecs[ 1 ], sampleOrigin );
1766         for( i = 0; i < 3; i++ )
1767                 sampleOrigin[ i ] = sampleOrigin[ i ] + (bx * originVecs[ 0 ][ i ]) + (by * originVecs[ 1 ][ i ]);
1768         
1769         /* get cluster */
1770         *sampleCluster = ClusterForPointExtFilter( sampleOrigin, (LUXEL_EPSILON * 2), lm->numLightClusters, lm->lightClusters );
1771         if( *sampleCluster < 0 )
1772                 return qfalse;
1773         
1774         /* calculate new normal */
1775         //%     VectorMA( normal, bx, normalVecs[ 0 ], sampleNormal );
1776         //%     VectorMA( sampleNormal, by, normalVecs[ 1 ], sampleNormal );
1777         //%     if( VectorNormalize( sampleNormal, sampleNormal ) <= 0.0f )
1778         //%             return qfalse;
1779         normal = SUPER_NORMAL( x, y );
1780         VectorCopy( normal, sampleNormal );
1781         
1782         /* return ok */
1783         return qtrue;
1784 }
1785
1786
1787 /*
1788 SubsampleRawLuxel_r()
1789 recursively subsamples a luxel until its color gradient is low enough or subsampling limit is reached
1790 */
1791
1792 static void SubsampleRawLuxel_r( rawLightmap_t *lm, trace_t *trace, vec3_t sampleOrigin, int x, int y, float bias, float *lightLuxel, float *lightDeluxel )
1793 {
1794         int                     b, samples, mapped, lighted;
1795         int                     cluster[ 4 ];
1796         vec4_t          luxel[ 4 ];
1797         vec3_t          deluxel[ 3 ];
1798         vec3_t          origin[ 4 ], normal[ 4 ];
1799         float           biasDirs[ 4 ][ 2 ] = { { -1.0f, -1.0f }, { 1.0f, -1.0f }, { -1.0f, 1.0f }, { 1.0f, 1.0f } };
1800         vec3_t          color, direction = { 0, 0, 0 }, total;
1801         
1802         
1803         /* limit check */
1804         if( lightLuxel[ 3 ] >= lightSamples )
1805                 return;
1806         
1807         /* setup */
1808         VectorClear( total );
1809         mapped = 0;
1810         lighted = 0;
1811         
1812         /* make 2x2 subsample stamp */
1813         for( b = 0; b < 4; b++ )
1814         {
1815                 /* set origin */
1816                 VectorCopy( sampleOrigin, origin[ b ] );
1817                 
1818                 /* calculate position */
1819                 if( !SubmapRawLuxel( lm, x, y, (bias * biasDirs[ b ][ 0 ]), (bias * biasDirs[ b ][ 1 ]), &cluster[ b ], origin[ b ], normal[ b ] ) )
1820                 {
1821                         cluster[ b ] = -1;
1822                         continue;
1823                 }
1824                 mapped++;
1825                 
1826                 /* increment sample count */
1827                 luxel[ b ][ 3 ] = lightLuxel[ 3 ] + 1.0f;
1828                 
1829                 /* setup trace */
1830                 trace->cluster = *cluster;
1831                 VectorCopy( origin[ b ], trace->origin );
1832                 VectorCopy( normal[ b ], trace->normal );
1833                 
1834                 /* sample light */
1835
1836                 LightContributionToSample( trace );
1837                 if(trace->forceSubsampling > 1.0f)
1838                 {
1839                         /* alphashadow: we subsample as deep as we can */
1840                         ++lighted;
1841                         ++mapped;
1842                         ++mapped;
1843                 }
1844                 
1845                 /* add to totals (fixme: make contrast function) */
1846                 VectorCopy( trace->color, luxel[ b ] );
1847                 if(lightDeluxel)
1848                 {
1849                         VectorCopy( trace->directionContribution, deluxel[ b ] );
1850                 }
1851                 VectorAdd( total, trace->color, total );
1852                 if( (luxel[ b ][ 0 ] + luxel[ b ][ 1 ] + luxel[ b ][ 2 ]) > 0.0f )
1853                         lighted++;
1854         }
1855         
1856         /* subsample further? */
1857         if( (lightLuxel[ 3 ] + 1.0f) < lightSamples &&
1858                 (total[ 0 ] > 4.0f || total[ 1 ] > 4.0f || total[ 2 ] > 4.0f) &&
1859                 lighted != 0 && lighted != mapped )
1860         {
1861                 for( b = 0; b < 4; b++ )
1862                 {
1863                         if( cluster[ b ] < 0 )
1864                                 continue;
1865                         SubsampleRawLuxel_r( lm, trace, origin[ b ], x, y, (bias * 0.5f), luxel[ b ], lightDeluxel ? deluxel[ b ] : NULL );
1866                 }
1867         }
1868         
1869         /* average */
1870         //%     VectorClear( color );
1871         //%     samples = 0;
1872         VectorCopy( lightLuxel, color );
1873         if(lightDeluxel)
1874         {
1875                 VectorCopy( lightDeluxel, direction );
1876         }
1877         samples = 1;
1878         for( b = 0; b < 4; b++ )
1879         {
1880                 if( cluster[ b ] < 0 )
1881                         continue;
1882                 VectorAdd( color, luxel[ b ], color );
1883                 if(lightDeluxel)
1884                 {
1885                         VectorAdd( direction, deluxel[ b ], direction );
1886                 }
1887                 samples++;
1888         }
1889         
1890         /* add to luxel */
1891         if( samples > 0 )
1892         {
1893                 /* average */
1894                 color[ 0 ] /= samples;
1895                 color[ 1 ] /= samples;
1896                 color[ 2 ] /= samples;
1897
1898                 /* add to color */
1899                 VectorCopy( color, lightLuxel );
1900                 lightLuxel[ 3 ] += 1.0f;
1901
1902                 if(lightDeluxel)
1903                 {
1904                         direction[ 0 ] /= samples;
1905                         direction[ 1 ] /= samples;
1906                         direction[ 2 ] /= samples;
1907                         VectorCopy( direction, lightDeluxel );
1908                 }
1909         }
1910 }
1911
1912 /* A mostly Gaussian-like bounded random distribution (sigma is expected standard deviation) */
1913 static void GaussLikeRandom(float sigma, float *x, float *y)
1914 {
1915         float r;
1916         r = Random() * 2 * Q_PI;
1917         *x = sigma * 2.73861278752581783822 * cos(r);
1918         *y = sigma * 2.73861278752581783822 * sin(r);
1919         r = Random();
1920         r = 1 - sqrt(r);
1921         r = 1 - sqrt(r);
1922         *x *= r;
1923         *y *= r;
1924 }
1925 static void RandomSubsampleRawLuxel( rawLightmap_t *lm, trace_t *trace, vec3_t sampleOrigin, int x, int y, float bias, float *lightLuxel, float *lightDeluxel )
1926 {
1927         int                     b, mapped;
1928         int                     cluster;
1929         vec3_t          origin, normal;
1930         vec3_t          total, totaldirection;
1931         float           dx, dy;
1932         
1933         VectorClear( total );
1934         VectorClear( totaldirection );
1935         mapped = 0;
1936         for(b = 0; b < lightSamples; ++b)
1937         {
1938                 /* set origin */
1939                 VectorCopy( sampleOrigin, origin );
1940                 GaussLikeRandom(bias, &dx, &dy);
1941
1942                 /* calculate position */
1943                 if( !SubmapRawLuxel( lm, x, y, dx, dy, &cluster, origin, normal ) )
1944                 {
1945                         cluster = -1;
1946                         continue;
1947                 }
1948                 mapped++;
1949
1950                 trace->cluster = cluster;
1951                 VectorCopy( origin, trace->origin );
1952                 VectorCopy( normal, trace->normal );
1953
1954                 LightContributionToSample( trace );
1955                 VectorAdd( total, trace->color, total );
1956                 if(lightDeluxel)
1957                 {
1958                         VectorAdd( totaldirection, trace->directionContribution, totaldirection );
1959                 }
1960         }
1961
1962         /* add to luxel */
1963         if( mapped > 0 )
1964         {
1965                 /* average */
1966                 lightLuxel[ 0 ] = total[ 0 ] / mapped;
1967                 lightLuxel[ 1 ] = total[ 1 ] / mapped;
1968                 lightLuxel[ 2 ] = total[ 2 ] / mapped;
1969
1970                 if(lightDeluxel)
1971                 {
1972                         lightDeluxel[ 0 ] = totaldirection[ 0 ] / mapped;
1973                         lightDeluxel[ 1 ] = totaldirection[ 1 ] / mapped;
1974                         lightDeluxel[ 2 ] = totaldirection[ 2 ] / mapped;
1975                 }
1976         }
1977 }
1978
1979
1980
1981 /*
1982 IlluminateRawLightmap()
1983 illuminates the luxels
1984 */
1985
1986 #define STACK_LL_SIZE                   (SUPER_LUXEL_SIZE * 64 * 64)
1987 #define LIGHT_LUXEL( x, y )             (lightLuxels + ((((y) * lm->sw) + (x)) * SUPER_LUXEL_SIZE))
1988 #define LIGHT_DELUXEL( x, y )           (lightDeluxels + ((((y) * lm->sw) + (x)) * SUPER_DELUXEL_SIZE))
1989
1990 void IlluminateRawLightmap( int rawLightmapNum )
1991 {
1992         int                                     i, t, x, y, sx, sy, size, luxelFilterRadius, lightmapNum;
1993         int                                     *cluster, *cluster2, mapped, lighted, totalLighted;
1994         size_t                                  llSize, ldSize;
1995         rawLightmap_t           *lm;
1996         surfaceInfo_t           *info;
1997         qboolean                        filterColor, filterDir;
1998         float                           brightness;
1999         float                           *origin, *normal, *dirt, *luxel, *luxel2, *deluxel, *deluxel2;
2000         unsigned char                   *flag;
2001         float                           *lightLuxels, *lightDeluxels, *lightLuxel, *lightDeluxel, samples, filterRadius, weight;
2002         vec3_t                          color, direction, averageColor, averageDir, total, temp, temp2;
2003         float                           tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
2004         trace_t                         trace;
2005         float                           stackLightLuxels[ STACK_LL_SIZE ];
2006         
2007         
2008         /* bail if this number exceeds the number of raw lightmaps */
2009         if( rawLightmapNum >= numRawLightmaps )
2010                 return;
2011         
2012         /* get lightmap */
2013         lm = &rawLightmaps[ rawLightmapNum ];
2014         
2015         /* setup trace */
2016         trace.testOcclusion = !noTrace;
2017         trace.forceSunlight = qfalse;
2018         trace.recvShadows = lm->recvShadows;
2019         trace.numSurfaces = lm->numLightSurfaces;
2020         trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
2021         trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
2022         
2023         /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
2024         trace.twoSided = qfalse;
2025         for( i = 0; i < trace.numSurfaces; i++ )
2026         {
2027                 /* get surface */
2028                 info = &surfaceInfos[ trace.surfaces[ i ] ];
2029                 
2030                 /* check twosidedness */
2031                 if( info->si->twoSided )
2032                 {
2033                         trace.twoSided = qtrue;
2034                         break;
2035                 }
2036         }
2037         
2038         /* create a culled light list for this raw lightmap */
2039         CreateTraceLightsForBounds( lm->mins, lm->maxs, lm->plane, lm->numLightClusters, lm->lightClusters, LIGHT_SURFACES, &trace );
2040         
2041         /* -----------------------------------------------------------------
2042            fill pass
2043            ----------------------------------------------------------------- */
2044         
2045         /* set counts */
2046         numLuxelsIlluminated += (lm->sw * lm->sh);
2047         
2048         /* test debugging state */
2049         if( debugSurfaces || debugAxis || debugCluster || debugOrigin || dirtDebug || normalmap )
2050         {
2051                 /* debug fill the luxels */
2052                 for( y = 0; y < lm->sh; y++ )
2053                 {
2054                         for( x = 0; x < lm->sw; x++ )
2055                         {
2056                                 /* get cluster */
2057                                 cluster = SUPER_CLUSTER( x, y );
2058
2059                                 /* only fill mapped luxels */
2060                                 if( *cluster < 0 )
2061                                         continue;
2062                                 
2063                                 /* get particulars */
2064                                 luxel = SUPER_LUXEL( 0, x, y );
2065                                 origin = SUPER_ORIGIN( x, y );
2066                                 normal = SUPER_NORMAL( x, y );
2067                                 
2068                                 /* color the luxel with raw lightmap num? */
2069                                 if( debugSurfaces )
2070                                         VectorCopy( debugColors[ rawLightmapNum % 12 ], luxel );
2071                                 
2072                                 /* color the luxel with lightmap axis? */
2073                                 else if( debugAxis )
2074                                 {
2075                                         luxel[ 0 ] = (lm->axis[ 0 ] + 1.0f) * 127.5f;
2076                                         luxel[ 1 ] = (lm->axis[ 1 ] + 1.0f) * 127.5f;
2077                                         luxel[ 2 ] = (lm->axis[ 2 ] + 1.0f) * 127.5f;
2078                                 }
2079                                 
2080                                 /* color the luxel with luxel cluster? */
2081                                 else if( debugCluster )
2082                                         VectorCopy( debugColors[ *cluster % 12 ], luxel );
2083                                 
2084                                 /* color the luxel with luxel origin? */
2085                                 else if( debugOrigin )
2086                                 {
2087                                         VectorSubtract( lm->maxs, lm->mins, temp );
2088                                         VectorScale( temp, (1.0f / 255.0f), temp );
2089                                         VectorSubtract( origin, lm->mins, temp2 );
2090                                         luxel[ 0 ] = lm->mins[ 0 ] + (temp[ 0 ] * temp2[ 0 ]);
2091                                         luxel[ 1 ] = lm->mins[ 1 ] + (temp[ 1 ] * temp2[ 1 ]);
2092                                         luxel[ 2 ] = lm->mins[ 2 ] + (temp[ 2 ] * temp2[ 2 ]);
2093                                 }
2094                                 
2095                                 /* color the luxel with the normal */
2096                                 else if( normalmap )
2097                                 {
2098                                         luxel[ 0 ] = (normal[ 0 ] + 1.0f) * 127.5f;
2099                                         luxel[ 1 ] = (normal[ 1 ] + 1.0f) * 127.5f;
2100                                         luxel[ 2 ] = (normal[ 2 ] + 1.0f) * 127.5f;
2101                                 }
2102                                 
2103                                 /* otherwise clear it */
2104                                 else
2105                                         VectorClear( luxel );
2106                                 
2107                                 /* add to counts */
2108                                 luxel[ 3 ] = 1.0f;
2109                         }
2110                 }
2111         }
2112         else
2113         {
2114                 /* allocate temporary per-light luxel storage */
2115                 llSize = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
2116                 ldSize = lm->sw * lm->sh * SUPER_DELUXEL_SIZE * sizeof( float );
2117                 if( llSize <= (STACK_LL_SIZE * sizeof( float )) )
2118                         lightLuxels = stackLightLuxels;
2119                 else
2120                         lightLuxels = safe_malloc( llSize );
2121                 if(deluxemap)
2122                         lightDeluxels = safe_malloc( ldSize );
2123                 else
2124                         lightDeluxels = NULL;
2125                 
2126                 /* clear luxels */
2127                 //%     memset( lm->superLuxels[ 0 ], 0, llSize );
2128                 
2129                 /* set ambient color */
2130                 for( y = 0; y < lm->sh; y++ )
2131                 {
2132                         for( x = 0; x < lm->sw; x++ )
2133                         {
2134                                 /* get cluster */
2135                                 cluster = SUPER_CLUSTER( x, y );
2136                                 luxel = SUPER_LUXEL( 0, x, y );
2137                                 normal = SUPER_NORMAL( x, y );
2138                                 deluxel = SUPER_DELUXEL( x, y );
2139                                 
2140                                 /* blacken unmapped clusters */
2141                                 if( *cluster < 0 )
2142                                         VectorClear( luxel );
2143                                 
2144                                 /* set ambient */
2145                                 else
2146                                 {
2147                                         VectorCopy( ambientColor, luxel );
2148                                         if( deluxemap )
2149                                         {
2150                                                 brightness = RGBTOGRAY( ambientColor ) * ( 1.0f/255.0f );
2151
2152                                                 // use AT LEAST this amount of contribution from ambient for the deluxemap, fixes points that receive ZERO light
2153                                                 if(brightness < 0.00390625f)
2154                                                         brightness = 0.00390625f;
2155
2156                                                 VectorScale( normal, brightness, deluxel );
2157                                         }
2158                                         luxel[ 3 ] = 1.0f;
2159                                 }
2160                         }
2161                 }
2162                 
2163                 /* clear styled lightmaps */
2164                 size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
2165                 for( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2166                 {
2167                         if( lm->superLuxels[ lightmapNum ] != NULL )
2168                                 memset( lm->superLuxels[ lightmapNum ], 0, size );
2169                 }
2170                 
2171                 /* debugging code */
2172                 //%     if( trace.numLights <= 0 )
2173                 //%             Sys_Printf( "Lightmap %9d: 0 lights, axis: %.2f, %.2f, %.2f\n", rawLightmapNum, lm->axis[ 0 ], lm->axis[ 1 ], lm->axis[ 2 ] );
2174                 
2175                 /* walk light list */
2176                 for( i = 0; i < trace.numLights; i++ )
2177                 {
2178                         /* setup trace */
2179                         trace.light = trace.lights[ i ];
2180                         
2181                         /* style check */
2182                         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2183                         {
2184                                 if( lm->styles[ lightmapNum ] == trace.light->style ||
2185                                         lm->styles[ lightmapNum ] == LS_NONE )
2186                                         break;
2187                         }
2188                         
2189                         /* max of MAX_LIGHTMAPS (4) styles allowed to hit a surface/lightmap */
2190                         if( lightmapNum >= MAX_LIGHTMAPS )
2191                         {
2192                                 Sys_Printf( "WARNING: Hit per-surface style limit (%d)\n", MAX_LIGHTMAPS );
2193                                 continue;
2194                         }
2195                         
2196                         /* setup */
2197                         memset( lightLuxels, 0, llSize );
2198                         if(deluxemap)
2199                                 memset( lightDeluxels, 0, ldSize );
2200                         totalLighted = 0;
2201                         
2202                         /* determine filter radius */
2203                         filterRadius = lm->filterRadius > trace.light->filterRadius
2204                                 ? lm->filterRadius
2205                                 : trace.light->filterRadius;
2206                         if( filterRadius < 0.0f )
2207                                 filterRadius = 0.0f;
2208                         
2209                         /* set luxel filter radius */
2210                         luxelFilterRadius = superSample * filterRadius / lm->sampleSize;
2211                         if( luxelFilterRadius == 0 && (filterRadius > 0.0f || filter) )
2212                                 luxelFilterRadius = 1;
2213
2214                         /* allocate sampling flags storage */
2215                         if((lightSamples > 1 || lightRandomSamples) && luxelFilterRadius == 0)
2216                         {
2217                                 size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( unsigned char );
2218                                 if(lm->superFlags == NULL)
2219                                         lm->superFlags = safe_malloc( size );
2220                                 memset( (void *) lm->superFlags, 0, size );
2221                         }
2222
2223                         /* initial pass, one sample per luxel */
2224                         for( y = 0; y < lm->sh; y++ )
2225                         {
2226                                 for( x = 0; x < lm->sw; x++ )
2227                                 {
2228                                         /* get cluster */
2229                                         cluster = SUPER_CLUSTER( x, y );
2230                                         if( *cluster < 0 )
2231                                                 continue;
2232                                         
2233                                         /* get particulars */
2234                                         lightLuxel = LIGHT_LUXEL( x, y );
2235                                         lightDeluxel = LIGHT_DELUXEL( x, y );
2236                                         origin = SUPER_ORIGIN( x, y );
2237                                         normal = SUPER_NORMAL( x, y );
2238                                         flag = SUPER_FLAG( x, y );
2239
2240 #if 0
2241                                         ////////// 27's temp hack for testing edge clipping ////
2242                                         if( origin[0]==0 && origin[1]==0 && origin[2]==0 )
2243                                         {
2244                                                 lightLuxel[ 1 ] = 255;
2245                                                 lightLuxel[ 3 ] = 1.0f;
2246                                                 totalLighted++;
2247                                         }
2248                                         else
2249 #endif
2250                                         {
2251                                                 /* set contribution count */
2252                                                 lightLuxel[ 3 ] = 1.0f;
2253
2254                                                 /* setup trace */
2255                                                 trace.cluster = *cluster;
2256                                                 VectorCopy( origin, trace.origin );
2257                                                 VectorCopy( normal, trace.normal );
2258
2259                                                 /* get light for this sample */
2260                                                 LightContributionToSample( &trace );
2261                                                 VectorCopy( trace.color, lightLuxel );
2262
2263                                                 /* add the contribution to the deluxemap */
2264                                                 if( deluxemap )
2265                                                 {
2266                                                         VectorCopy( trace.directionContribution, lightDeluxel );
2267                                                 }
2268
2269                                                 /* check for evilness */
2270                                                 if(trace.forceSubsampling > 1.0f && (lightSamples > 1 || lightRandomSamples) && luxelFilterRadius == 0)
2271                                                 {
2272                                                         totalLighted++;
2273                                                         *flag |= FLAG_FORCE_SUBSAMPLING; /* force */
2274                                                 }
2275                                                 /* add to count */
2276                                                 else if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
2277                                                         totalLighted++;
2278                                         }
2279                                 }
2280                         }
2281                         
2282                         /* don't even bother with everything else if nothing was lit */
2283                         if( totalLighted == 0 )
2284                                 continue;
2285                         
2286                         /* secondary pass, adaptive supersampling (fixme: use a contrast function to determine if subsampling is necessary) */
2287                         /* 2003-09-27: changed it so filtering disamples supersampling, as it would waste time */
2288                         if( (lightSamples > 1 || lightRandomSamples) && luxelFilterRadius == 0 )
2289                         {
2290                                 /* walk luxels */
2291                                 for( y = 0; y < (lm->sh - 1); y++ )
2292                                 {
2293                                         for( x = 0; x < (lm->sw - 1); x++ )
2294                                         {
2295                                                 /* setup */
2296                                                 mapped = 0;
2297                                                 lighted = 0;
2298                                                 VectorClear( total );
2299                                                 
2300                                                 /* test 2x2 stamp */
2301                                                 for( t = 0; t < 4; t++ )
2302                                                 {
2303                                                         /* set sample coords */
2304                                                         sx = x + tests[ t ][ 0 ];
2305                                                         sy = y + tests[ t ][ 1 ];
2306                                                         
2307                                                         /* get cluster */
2308                                                         cluster = SUPER_CLUSTER( sx, sy );
2309                                                         if( *cluster < 0 )
2310                                                                 continue;
2311                                                         mapped++;
2312                                                         
2313                                                         /* get luxel */
2314                                                         flag = SUPER_FLAG( sx, sy );
2315                                                         if(*flag & FLAG_FORCE_SUBSAMPLING)
2316                                                         {
2317                                                                 /* force a lighted/mapped discrepancy so we subsample */
2318                                                                 ++lighted;
2319                                                                 ++mapped;
2320                                                                 ++mapped;
2321                                                         }
2322                                                         lightLuxel = LIGHT_LUXEL( sx, sy );
2323                                                         VectorAdd( total, lightLuxel, total );
2324                                                         if( (lightLuxel[ 0 ] + lightLuxel[ 1 ] + lightLuxel[ 2 ]) > 0.0f )
2325                                                                 lighted++;
2326                                                 }
2327                                                 
2328                                                 /* if total color is under a certain amount, then don't bother subsampling */
2329                                                 if( total[ 0 ] <= 4.0f && total[ 1 ] <= 4.0f && total[ 2 ] <= 4.0f )
2330                                                         continue;
2331                                                 
2332                                                 /* if all 4 pixels are either in shadow or light, then don't subsample */
2333                                                 if( lighted != 0 && lighted != mapped )
2334                                                 {
2335                                                         for( t = 0; t < 4; t++ )
2336                                                         {
2337                                                                 /* set sample coords */
2338                                                                 sx = x + tests[ t ][ 0 ];
2339                                                                 sy = y + tests[ t ][ 1 ];
2340                                                                 
2341                                                                 /* get luxel */
2342                                                                 cluster = SUPER_CLUSTER( sx, sy );
2343                                                                 if( *cluster < 0 )
2344                                                                         continue;
2345                                                                 flag = SUPER_FLAG( sx, sy );
2346                                                                 if(*flag & FLAG_ALREADY_SUBSAMPLED) // already subsampled
2347                                                                         continue;
2348                                                                 lightLuxel = LIGHT_LUXEL( sx, sy );
2349                                                                 lightDeluxel = LIGHT_DELUXEL( sx, sy );
2350                                                                 origin = SUPER_ORIGIN( sx, sy );
2351                                                                 
2352                                                                 /* only subsample shadowed luxels */
2353                                                                 //%     if( (lightLuxel[ 0 ] + lightLuxel[ 1 ] + lightLuxel[ 2 ]) <= 0.0f )
2354                                                                 //%             continue;
2355                                                                 
2356                                                                 /* subsample it */
2357                                                                 if(lightRandomSamples)
2358                                                                         RandomSubsampleRawLuxel( lm, &trace, origin, sx, sy, 0.5f * lightSamplesSearchBoxSize, lightLuxel, deluxemap ? lightDeluxel : NULL );
2359                                                                 else
2360                                                                         SubsampleRawLuxel_r( lm, &trace, origin, sx, sy, 0.25f * lightSamplesSearchBoxSize, lightLuxel, deluxemap ? lightDeluxel : NULL );
2361
2362                                                                 *flag |= FLAG_ALREADY_SUBSAMPLED;
2363                                                                 
2364                                                                 /* debug code to colorize subsampled areas to yellow */
2365                                                                 //%     luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2366                                                                 //%     VectorSet( luxel, 255, 204, 0 );
2367                                                         }
2368                                                 }
2369                                         }
2370                                 }
2371                         }
2372                         
2373                         /* tertiary pass, apply dirt map (ambient occlusion) */
2374                         if( 0 && dirty )
2375                         {
2376                                 /* walk luxels */
2377                                 for( y = 0; y < lm->sh; y++ )
2378                                 {
2379                                         for( x = 0; x < lm->sw; x++ )
2380                                         {
2381                                                 /* get cluster  */
2382                                                 cluster = SUPER_CLUSTER( x, y );
2383                                                 if( *cluster < 0 )
2384                                                         continue;
2385                                                 
2386                                                 /* get particulars */
2387                                                 lightLuxel = LIGHT_LUXEL( x, y );
2388                                                 dirt = SUPER_DIRT( x, y );
2389                                                 
2390                                                 /* scale light value */
2391                                                 VectorScale( lightLuxel, *dirt, lightLuxel );
2392                                         }
2393                                 }
2394                         }
2395                         
2396                         /* allocate sampling lightmap storage */
2397                         if( lm->superLuxels[ lightmapNum ] == NULL )
2398                         {
2399                                 /* allocate sampling lightmap storage */
2400                                 size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
2401                                 lm->superLuxels[ lightmapNum ] = safe_malloc( size );
2402                                 memset( lm->superLuxels[ lightmapNum ], 0, size );
2403                         }
2404
2405                         /* set style */
2406                         if( lightmapNum > 0 )
2407                         {
2408                                 lm->styles[ lightmapNum ] = trace.light->style;
2409                                 //%     Sys_Printf( "Surface %6d has lightstyle %d\n", rawLightmapNum, trace.light->style );
2410                         }
2411                         
2412                         /* copy to permanent luxels */
2413                         for( y = 0; y < lm->sh; y++ )
2414                         {
2415                                 for( x = 0; x < lm->sw; x++ )
2416                                 {
2417                                         /* get cluster and origin */
2418                                         cluster = SUPER_CLUSTER( x, y );
2419                                         if( *cluster < 0 )
2420                                                 continue;
2421                                         origin = SUPER_ORIGIN( x, y );
2422                                         
2423                                         /* filter? */
2424                                         if( luxelFilterRadius )
2425                                         {
2426                                                 /* setup */
2427                                                 VectorClear( averageColor );
2428                                                 VectorClear( averageDir );
2429                                                 samples = 0.0f;
2430                                                 
2431                                                 /* cheaper distance-based filtering */
2432                                                 for( sy = (y - luxelFilterRadius); sy <= (y + luxelFilterRadius); sy++ )
2433                                                 {
2434                                                         if( sy < 0 || sy >= lm->sh )
2435                                                                 continue;
2436                                                         
2437                                                         for( sx = (x - luxelFilterRadius); sx <= (x + luxelFilterRadius); sx++ )
2438                                                         {
2439                                                                 if( sx < 0 || sx >= lm->sw )
2440                                                                         continue;
2441                                                                 
2442                                                                 /* get particulars */
2443                                                                 cluster = SUPER_CLUSTER( sx, sy );
2444                                                                 if( *cluster < 0 )
2445                                                                         continue;
2446                                                                 lightLuxel = LIGHT_LUXEL( sx, sy );
2447                                                                 lightDeluxel = LIGHT_DELUXEL( sx, sy );
2448                                                                 
2449                                                                 /* create weight */
2450                                                                 weight = (abs( sx - x ) == luxelFilterRadius ? 0.5f : 1.0f);
2451                                                                 weight *= (abs( sy - y ) == luxelFilterRadius ? 0.5f : 1.0f);
2452                                                                 
2453                                                                 /* scale luxel by filter weight */
2454                                                                 VectorScale( lightLuxel, weight, color );
2455                                                                 VectorAdd( averageColor, color, averageColor );
2456                                                                 if(deluxemap)
2457                                                                 {
2458                                                                         VectorScale( lightDeluxel, weight, direction );
2459                                                                         VectorAdd( averageDir, direction, averageDir );
2460                                                                 }
2461                                                                 samples += weight;
2462                                                         }
2463                                                 }
2464                                                 
2465                                                 /* any samples? */
2466                                                 if( samples <= 0.0f     )
2467                                                         continue;
2468                                                 
2469                                                 /* scale into luxel */
2470                                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
2471                                                 luxel[ 3 ] = 1.0f;
2472                                                 
2473                                                 /* handle negative light */
2474                                                 if( trace.light->flags & LIGHT_NEGATIVE )
2475                                                 { 
2476                                                         luxel[ 0 ] -= averageColor[ 0 ] / samples;
2477                                                         luxel[ 1 ] -= averageColor[ 1 ] / samples;
2478                                                         luxel[ 2 ] -= averageColor[ 2 ] / samples;
2479                                                 }
2480                                                 
2481                                                 /* handle normal light */
2482                                                 else
2483                                                 { 
2484                                                         luxel[ 0 ] += averageColor[ 0 ] / samples;
2485                                                         luxel[ 1 ] += averageColor[ 1 ] / samples;
2486                                                         luxel[ 2 ] += averageColor[ 2 ] / samples;
2487                                                 }
2488                                                 
2489                                                 if(deluxemap)
2490                                                 {
2491                                                         /* scale into luxel */
2492                                                         deluxel = SUPER_DELUXEL( x, y );
2493                                                         deluxel[ 0 ] += averageDir[ 0 ] / samples;
2494                                                         deluxel[ 1 ] += averageDir[ 1 ] / samples;
2495                                                         deluxel[ 2 ] += averageDir[ 2 ] / samples;
2496                                                 }
2497                                         }
2498                                         
2499                                         /* single sample */
2500                                         else
2501                                         {
2502                                                 /* get particulars */
2503                                                 lightLuxel = LIGHT_LUXEL( x, y );
2504                                                 lightDeluxel = LIGHT_DELUXEL( x, y );
2505                                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
2506                                                 deluxel = SUPER_DELUXEL( x, y );
2507                                                 
2508                                                 /* handle negative light */
2509                                                 if( trace.light->flags & LIGHT_NEGATIVE )
2510                                                         VectorScale( averageColor, -1.0f, averageColor );
2511
2512                                                 /* add color */
2513                                                 luxel[ 3 ] = 1.0f;
2514                                                 
2515                                                 /* handle negative light */
2516                                                 if( trace.light->flags & LIGHT_NEGATIVE )
2517                                                         VectorSubtract( luxel, lightLuxel, luxel );
2518                                                 
2519                                                 /* handle normal light */
2520                                                 else
2521                                                         VectorAdd( luxel, lightLuxel, luxel );
2522
2523                                                 if(deluxemap)
2524                                                 {
2525                                                         VectorAdd( deluxel, lightDeluxel, deluxel );
2526                                                 }
2527                                         }
2528                                 }
2529                         }
2530                 }
2531                 
2532                 /* free temporary luxels */
2533                 if( lightLuxels != stackLightLuxels )
2534                         free( lightLuxels );
2535                 
2536                 if(deluxemap)
2537                         free( lightDeluxels );
2538         }
2539         
2540         /* free light list */
2541         FreeTraceLights( &trace );
2542         
2543         /* floodlight pass */
2544         if( floodlighty )
2545                 FloodlightIlluminateLightmap(lm);
2546
2547         if (debugnormals)
2548         {
2549                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2550                 {
2551                         /* early out */
2552                         if( lm->superLuxels[ lightmapNum ] == NULL )
2553                                 continue;
2554                         
2555                         for( y = 0; y < lm->sh; y++ )
2556                         {
2557                                 for( x = 0; x < lm->sw; x++ )
2558                                 {
2559                                         /* get cluster */
2560                                         cluster = SUPER_CLUSTER( x, y );
2561                                         //%     if( *cluster < 0 )
2562                                         //%             continue;
2563                                         
2564                                         /* get particulars */
2565                                         luxel = SUPER_LUXEL( lightmapNum, x, y );
2566                                         normal = SUPER_NORMAL (  x, y );
2567                
2568                                         luxel[0]=(normal[0]*127)+127;
2569                                         luxel[1]=(normal[1]*127)+127;
2570                                         luxel[2]=(normal[2]*127)+127;
2571                                 }
2572                         }
2573                 }
2574         }
2575         
2576         /*      -----------------------------------------------------------------
2577                 dirt pass
2578                 ----------------------------------------------------------------- */
2579         
2580         if( dirty )
2581         {
2582                 /* walk lightmaps */
2583                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2584                 {
2585                         /* early out */
2586                         if( lm->superLuxels[ lightmapNum ] == NULL )
2587                                 continue;
2588                         
2589                         /* apply dirt to each luxel */
2590                         for( y = 0; y < lm->sh; y++ )
2591                         {
2592                                 for( x = 0; x < lm->sw; x++ )
2593                                 {
2594                                         /* get cluster */
2595                                         cluster = SUPER_CLUSTER( x, y );
2596                                         //%     if( *cluster < 0 ) // TODO why not do this check? These pixels should be zero anyway
2597                                         //%             continue;
2598                                         
2599                                         /* get particulars */
2600                                         luxel = SUPER_LUXEL( lightmapNum, x, y );
2601                                         dirt = SUPER_DIRT( x, y );
2602                                         
2603                                         /* apply dirt */
2604                                         VectorScale( luxel, *dirt, luxel );
2605                                         
2606                                         /* debugging */
2607                                         if( dirtDebug )
2608                                                 VectorSet( luxel, *dirt * 255.0f, *dirt * 255.0f, *dirt * 255.0f );
2609                                 }
2610                         }
2611                 }
2612         }
2613         
2614         /* -----------------------------------------------------------------
2615            filter pass
2616            ----------------------------------------------------------------- */
2617         
2618         /* walk lightmaps */
2619         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2620         {
2621                 /* early out */
2622                 if( lm->superLuxels[ lightmapNum ] == NULL )
2623                         continue;
2624                 
2625                 /* average occluded luxels from neighbors */
2626                 for( y = 0; y < lm->sh; y++ )
2627                 {
2628                         for( x = 0; x < lm->sw; x++ )
2629                         {
2630                                 /* get particulars */
2631                                 cluster = SUPER_CLUSTER( x, y );
2632                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
2633                                 deluxel = SUPER_DELUXEL( x, y );
2634                                 normal = SUPER_NORMAL( x, y );
2635                                 
2636                                 /* determine if filtering is necessary */
2637                                 filterColor = qfalse;
2638                                 filterDir = qfalse;
2639                                 if( *cluster < 0 ||
2640                                         (lm->splotchFix && (luxel[ 0 ] <= ambientColor[ 0 ] || luxel[ 1 ] <= ambientColor[ 1 ] || luxel[ 2 ] <= ambientColor[ 2 ])) )
2641                                         filterColor = qtrue;
2642
2643                                 if( deluxemap && lightmapNum == 0 && (*cluster < 0 || filter) )
2644                                         filterDir = qtrue;
2645                                 
2646                                 if( !filterColor && !filterDir )
2647                                         continue;
2648                                 
2649                                 /* choose seed amount */
2650                                 VectorClear( averageColor );
2651                                 VectorClear( averageDir );
2652                                 samples = 0.0f;
2653                                 
2654                                 /* walk 3x3 matrix */
2655                                 for( sy = (y - 1); sy <= (y + 1); sy++ )
2656                                 {
2657                                         if( sy < 0 || sy >= lm->sh )
2658                                                 continue;
2659                                         
2660                                         for( sx = (x - 1); sx <= (x + 1); sx++ )
2661                                         {
2662                                                 if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
2663                                                         continue;
2664                                                 
2665                                                 /* get neighbor's particulars */
2666                                                 cluster2 = SUPER_CLUSTER( sx, sy );
2667                                                 luxel2 = SUPER_LUXEL( lightmapNum, sx, sy );
2668                                                 deluxel2 = SUPER_DELUXEL( sx, sy );
2669                                                 
2670                                                 /* ignore unmapped/unlit luxels */
2671                                                 if( *cluster2 < 0 || luxel2[ 3 ] == 0.0f ||
2672                                                         (lm->splotchFix && VectorCompare( luxel2, ambientColor )) )
2673                                                         continue;
2674                                                 
2675                                                 /* add its distinctiveness to our own */
2676                                                 VectorAdd( averageColor, luxel2, averageColor );
2677                                                 samples += luxel2[ 3 ];
2678                                                 if( filterDir )
2679                                                         VectorAdd( averageDir, deluxel2, averageDir );
2680                                         }
2681                                 }
2682                                 
2683                                 /* fall through */
2684                                 if( samples <= 0.0f )
2685                                         continue;
2686                                 
2687                                 /* dark lightmap seams */
2688                                 if( dark )
2689                                 {
2690                                         if( lightmapNum == 0 )
2691                                                 VectorMA( averageColor, 2.0f, ambientColor, averageColor );
2692                                         samples += 2.0f;
2693                                 }
2694                                 
2695                                 /* average it */
2696                                 if( filterColor )
2697                                 {
2698                                         VectorDivide( averageColor, samples, luxel );
2699                                         luxel[ 3 ] = 1.0f;
2700                                 }
2701                                 if( filterDir )
2702                                         VectorDivide( averageDir, samples, deluxel );
2703                                 
2704                                 /* set cluster to -3 */
2705                                 if( *cluster < 0 )
2706                                         *cluster = CLUSTER_FLOODED;
2707                         }
2708                 }
2709         }
2710
2711
2712 #if 0
2713         // audit pass
2714         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2715         {
2716                 /* early out */
2717                 if( lm->superLuxels[ lightmapNum ] == NULL )
2718                         continue;
2719                 for( y = 0; y < lm->sh; y++ )
2720                         for( x = 0; x < lm->sw; x++ )
2721                         {
2722                                 /* get cluster */
2723                                 cluster = SUPER_CLUSTER( x, y );
2724                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
2725                                 deluxel = SUPER_DELUXEL( x, y );
2726                                 if(!luxel || !deluxel || !cluster)
2727                                 {
2728                                         Sys_FPrintf(SYS_VRB, "WARNING: I got NULL'd.\n");
2729                                         continue;
2730                                 }
2731                                 else if(*cluster < 0)
2732                                 {
2733                                         // unmapped pixel
2734                                         // should have neither deluxemap nor lightmap
2735                                         if(deluxel[3])
2736                                                 Sys_FPrintf(SYS_VRB, "WARNING: I have written deluxe to an unmapped luxel. Sorry.\n");
2737                                 }
2738                                 else
2739                                 {
2740                                         // mapped pixel
2741                                         // should have both deluxemap and lightmap
2742                                         if(deluxel[3])
2743                                                 Sys_FPrintf(SYS_VRB, "WARNING: I forgot to write deluxe to a mapped luxel. Sorry.\n");
2744                                 }
2745                         }
2746         }
2747 #endif
2748 }
2749
2750
2751
2752 /*
2753 IlluminateVertexes()
2754 light the surface vertexes
2755 */
2756
2757 #define VERTEX_NUDGE    4.0f
2758
2759 void IlluminateVertexes( int num )
2760 {
2761         int                                     i, x, y, z, x1, y1, z1, sx, sy, radius, maxRadius, *cluster;
2762         int                                     lightmapNum, numAvg;
2763         float                           samples, *vertLuxel, *radVertLuxel, *luxel, dirt;
2764         vec3_t                          origin, temp, temp2, colors[ MAX_LIGHTMAPS ], avgColors[ MAX_LIGHTMAPS ];
2765         bspDrawSurface_t        *ds;
2766         surfaceInfo_t           *info;
2767         rawLightmap_t           *lm;
2768         bspDrawVert_t           *verts;
2769         trace_t                         trace;
2770         float                           floodLightAmount;
2771         vec3_t                          floodColor;
2772         
2773         
2774         /* get surface, info, and raw lightmap */
2775         ds = &bspDrawSurfaces[ num ];
2776         info = &surfaceInfos[ num ];
2777         lm = info->lm;
2778         
2779         /* -----------------------------------------------------------------
2780            illuminate the vertexes
2781            ----------------------------------------------------------------- */
2782         
2783         /* calculate vertex lighting for surfaces without lightmaps */
2784         if( lm == NULL || cpmaHack )
2785         {
2786                 /* setup trace */
2787                 trace.testOcclusion = (cpmaHack && lm != NULL) ? qfalse : !noTrace;
2788                 trace.forceSunlight = info->si->forceSunlight;
2789                 trace.recvShadows = info->recvShadows;
2790                 trace.numSurfaces = 1;
2791                 trace.surfaces = &num;
2792                 trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
2793                 
2794                 /* twosided lighting */
2795                 trace.twoSided = info->si->twoSided;
2796                 
2797                 /* make light list for this surface */
2798                 CreateTraceLightsForSurface( num, &trace );
2799                 
2800                 /* setup */
2801                 verts = yDrawVerts + ds->firstVert;
2802                 numAvg = 0;
2803                 memset( avgColors, 0, sizeof( avgColors ) );
2804                 
2805                 /* walk the surface verts */
2806                 for( i = 0; i < ds->numVerts; i++ )
2807                 {
2808                         /* get vertex luxel */
2809                         radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2810                         
2811                         /* color the luxel with raw lightmap num? */
2812                         if( debugSurfaces )
2813                                 VectorCopy( debugColors[ num % 12 ], radVertLuxel );
2814                         
2815                         /* color the luxel with luxel origin? */
2816                         else if( debugOrigin )
2817                         {
2818                                 VectorSubtract( info->maxs, info->mins, temp );
2819                                 VectorScale( temp, (1.0f / 255.0f), temp );
2820                                 VectorSubtract( origin, lm->mins, temp2 );
2821                                 radVertLuxel[ 0 ] = info->mins[ 0 ] + (temp[ 0 ] * temp2[ 0 ]);
2822                                 radVertLuxel[ 1 ] = info->mins[ 1 ] + (temp[ 1 ] * temp2[ 1 ]);
2823                                 radVertLuxel[ 2 ] = info->mins[ 2 ] + (temp[ 2 ] * temp2[ 2 ]);
2824                         }
2825                         
2826                         /* color the luxel with the normal */
2827                         else if( normalmap )
2828                         {
2829                                 radVertLuxel[ 0 ] = (verts[ i ].normal[ 0 ] + 1.0f) * 127.5f;
2830                                 radVertLuxel[ 1 ] = (verts[ i ].normal[ 1 ] + 1.0f) * 127.5f;
2831                                 radVertLuxel[ 2 ] = (verts[ i ].normal[ 2 ] + 1.0f) * 127.5f;
2832                         }
2833                         
2834                         /* illuminate the vertex */
2835                         else
2836                         {
2837                                 /* clear vertex luxel */
2838                                 VectorSet( radVertLuxel, -1.0f, -1.0f, -1.0f );
2839                                 
2840                                 /* try at initial origin */
2841                                 trace.cluster = ClusterForPointExtFilter( verts[ i ].xyz, VERTEX_EPSILON, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ] );
2842                                 if( trace.cluster >= 0 )
2843                                 {
2844                                         /* setup trace */
2845                                         VectorCopy( verts[ i ].xyz, trace.origin );
2846                                         VectorCopy( verts[ i ].normal, trace.normal );
2847                                         
2848                                         /* r7 dirt */
2849                                         if( dirty && !bouncing )
2850                                                 dirt = DirtForSample( &trace );
2851                                         else
2852                                                 dirt = 1.0f;
2853
2854                                         /* jal: floodlight */
2855                                         floodLightAmount = 0.0f;
2856                                         VectorClear( floodColor );
2857                                         if( floodlighty && !bouncing )
2858                                         {
2859                                                 floodLightAmount = floodlightIntensity * FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality );
2860                                                 VectorScale( floodlightRGB, floodLightAmount, floodColor );
2861                                         }
2862
2863                                         /* trace */
2864                                         LightingAtSample( &trace, ds->vertexStyles, colors );
2865                                         
2866                                         /* store */
2867                                         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2868                                         {
2869                                                 /* r7 dirt */
2870                                                 VectorScale( colors[ lightmapNum ], dirt, colors[ lightmapNum ] );
2871
2872                                                 /* jal: floodlight */
2873                                                 VectorAdd( colors[ lightmapNum ], floodColor, colors[ lightmapNum ] ); 
2874                                                 
2875                                                 /* store */
2876                                                 radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
2877                                                 VectorCopy( colors[ lightmapNum ], radVertLuxel );
2878                                                 VectorAdd( avgColors[ lightmapNum ], colors[ lightmapNum ], colors[ lightmapNum ] );
2879                                         }
2880                                 }
2881                                 
2882                                 /* is this sample bright enough? */
2883                                 radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2884                                 if( radVertLuxel[ 0 ] <= ambientColor[ 0 ] &&
2885                                         radVertLuxel[ 1 ] <= ambientColor[ 1 ] &&
2886                                         radVertLuxel[ 2 ] <= ambientColor[ 2 ] )
2887                                 {
2888                                         /* nudge the sample point around a bit */
2889                                         for( x = 0; x < 5; x++ )
2890                                         {
2891                                                 /* two's complement 0, 1, -1, 2, -2, etc */
2892                                                 x1 = ((x >> 1) ^ (x & 1 ? -1 : 0)) + (x & 1);
2893                                                 
2894                                                 for( y = 0; y < 5; y++ )
2895                                                 {
2896                                                         y1 = ((y >> 1) ^ (y & 1 ? -1 : 0)) + (y & 1);
2897                                                         
2898                                                         for( z = 0; z < 5; z++ )
2899                                                         {
2900                                                                 z1 = ((z >> 1) ^ (z & 1 ? -1 : 0)) + (z & 1);
2901                                                                 
2902                                                                 /* nudge origin */
2903                                                                 trace.origin[ 0 ] = verts[ i ].xyz[ 0 ] + (VERTEX_NUDGE * x1);
2904                                                                 trace.origin[ 1 ] = verts[ i ].xyz[ 1 ] + (VERTEX_NUDGE * y1);
2905                                                                 trace.origin[ 2 ] = verts[ i ].xyz[ 2 ] + (VERTEX_NUDGE * z1);
2906                                                                 
2907                                                                 /* try at nudged origin */
2908                                                                 trace.cluster = ClusterForPointExtFilter( origin, VERTEX_EPSILON, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ] );
2909                                                                 if( trace.cluster < 0 )
2910                                                                         continue;
2911
2912                                                                 /* r7 dirt */
2913                                                                 if( dirty && !bouncing )
2914                                                                         dirt = DirtForSample( &trace );
2915                                                                 else
2916                                                                         dirt = 1.0f;
2917
2918                                                                 /* jal: floodlight */
2919                                                                 floodLightAmount = 0.0f;
2920                                                                 VectorClear( floodColor );
2921                                                                 if( floodlighty && !bouncing )
2922                                                                 {
2923                                                                         floodLightAmount = floodlightIntensity * FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality );
2924                                                                         VectorScale( floodlightRGB, floodLightAmount, floodColor );
2925                                                                 }
2926                                                                                                                         
2927                                                                 /* trace */
2928                                                                 LightingAtSample( &trace, ds->vertexStyles, colors );
2929                                                                 
2930                                                                 /* store */
2931                                                                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2932                                                                 {
2933                                                                         /* r7 dirt */
2934                                                                         VectorScale( colors[ lightmapNum ], dirt, colors[ lightmapNum ] );
2935
2936                                                                         /* jal: floodlight */
2937                                                                         VectorAdd( colors[ lightmapNum ], floodColor, colors[ lightmapNum ] ); 
2938                                                                         
2939                                                                         /* store */
2940                                                                         radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
2941                                                                         VectorCopy( colors[ lightmapNum ], radVertLuxel );
2942                                                                 }
2943                                                                 
2944                                                                 /* bright enough? */
2945                                                                 radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2946                                                                 if( radVertLuxel[ 0 ] > ambientColor[ 0 ] ||
2947                                                                         radVertLuxel[ 1 ] > ambientColor[ 1 ] ||
2948                                                                         radVertLuxel[ 2 ] > ambientColor[ 2 ] )
2949                                                                         x = y = z = 1000;
2950                                                         }
2951                                                 }
2952                                         }
2953                                 }
2954                                 
2955                                 /* add to average? */
2956                                 radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2957                                 if( radVertLuxel[ 0 ] > ambientColor[ 0 ] ||
2958                                         radVertLuxel[ 1 ] > ambientColor[ 1 ] ||
2959                                         radVertLuxel[ 2 ] > ambientColor[ 2 ] )
2960                                 {
2961                                         numAvg++;
2962                                         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2963                                         {
2964                                                 radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
2965                                                 VectorAdd( avgColors[ lightmapNum ], radVertLuxel, avgColors[ lightmapNum ] );
2966                                         }
2967                                 }
2968                         }
2969                         
2970                         /* another happy customer */
2971                         numVertsIlluminated++;
2972                 }
2973                 
2974                 /* set average color */
2975                 if( numAvg > 0 )
2976                 {
2977                         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2978                                 VectorScale( avgColors[ lightmapNum ], (1.0f / numAvg), avgColors[ lightmapNum ] );
2979                 }
2980                 else
2981                 {
2982                         VectorCopy( ambientColor, avgColors[ 0 ] );
2983                 }
2984                 
2985                 /* clean up and store vertex color */
2986                 for( i = 0; i < ds->numVerts; i++ )
2987                 {
2988                         /* get vertex luxel */
2989                         radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2990                         
2991                         /* store average in occluded vertexes */
2992                         if( radVertLuxel[ 0 ] < 0.0f )
2993                         {
2994                                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2995                                 {
2996                                         radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
2997                                         VectorCopy( avgColors[ lightmapNum ], radVertLuxel );
2998                                         
2999                                         /* debug code */
3000                                         //%     VectorSet( radVertLuxel, 255.0f, 0.0f, 0.0f );
3001                                 }
3002                         }
3003                         
3004                         /* store it */
3005                         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3006                         {
3007                                 /* get luxels */
3008                                 vertLuxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
3009                                 radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
3010                                 
3011                                 /* store */
3012                                 if( bouncing || bounce == 0 || !bounceOnly )
3013                                         VectorAdd( vertLuxel, radVertLuxel, vertLuxel );
3014                                 if( !info->si->noVertexLight )
3015                                         ColorToBytes( vertLuxel, verts[ i ].color[ lightmapNum ], info->si->vertexScale );
3016                         }
3017                 }
3018                 
3019                 /* free light list */
3020                 FreeTraceLights( &trace );
3021                 
3022                 /* return to sender */
3023                 return;
3024         }
3025         
3026         /* -----------------------------------------------------------------
3027            reconstitute vertex lighting from the luxels
3028            ----------------------------------------------------------------- */
3029         
3030         /* set styles from lightmap */
3031         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3032                 ds->vertexStyles[ lightmapNum ] = lm->styles[ lightmapNum ];
3033         
3034         /* get max search radius */
3035         maxRadius = lm->sw;
3036         maxRadius = maxRadius > lm->sh ? maxRadius : lm->sh;
3037         
3038         /* walk the surface verts */
3039         verts = yDrawVerts + ds->firstVert;
3040         for( i = 0; i < ds->numVerts; i++ )
3041         {
3042                 /* do each lightmap */
3043                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3044                 {
3045                         /* early out */
3046                         if( lm->superLuxels[ lightmapNum ] == NULL )
3047                                 continue;
3048                         
3049                         /* get luxel coords */
3050                         x = verts[ i ].lightmap[ lightmapNum ][ 0 ];
3051                         y = verts[ i ].lightmap[ lightmapNum ][ 1 ];
3052                         if( x < 0 )
3053                                 x = 0;
3054                         else if( x >= lm->sw )
3055                                 x = lm->sw - 1;
3056                         if( y < 0 )
3057                                 y = 0;
3058                         else if( y >= lm->sh )
3059                                 y = lm->sh - 1;
3060                         
3061                         /* get vertex luxels */
3062                         vertLuxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
3063                         radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
3064                         
3065                         /* color the luxel with the normal? */
3066                         if( normalmap )
3067                         {
3068                                 radVertLuxel[ 0 ] = (verts[ i ].normal[ 0 ] + 1.0f) * 127.5f;
3069                                 radVertLuxel[ 1 ] = (verts[ i ].normal[ 1 ] + 1.0f) * 127.5f;
3070                                 radVertLuxel[ 2 ] = (verts[ i ].normal[ 2 ] + 1.0f) * 127.5f;
3071                         }
3072                         
3073                         /* color the luxel with surface num? */
3074                         else if( debugSurfaces )
3075                                 VectorCopy( debugColors[ num % 12 ], radVertLuxel );
3076                         
3077                         /* divine color from the superluxels */
3078                         else
3079                         {
3080                                 /* increasing radius */
3081                                 VectorClear( radVertLuxel );
3082                                 samples = 0.0f;
3083                                 for( radius = 0; radius < maxRadius && samples <= 0.0f; radius++ )
3084                                 {
3085                                         /* sample within radius */
3086                                         for( sy = (y - radius); sy <= (y + radius); sy++ )
3087                                         {
3088                                                 if( sy < 0 || sy >= lm->sh )
3089                                                         continue;
3090                                                 
3091                                                 for( sx = (x - radius); sx <= (x + radius); sx++ )
3092                                                 {
3093                                                         if( sx < 0 || sx >= lm->sw )
3094                                                                 continue;
3095                                                         
3096                                                         /* get luxel particulars */
3097                                                         luxel = SUPER_LUXEL( lightmapNum, sx, sy );
3098                                                         cluster = SUPER_CLUSTER( sx, sy );
3099                                                         if( *cluster < 0 )
3100                                                                 continue;
3101                                                         
3102                                                         /* testing: must be brigher than ambient color */
3103                                                         //%     if( luxel[ 0 ] <= ambientColor[ 0 ] || luxel[ 1 ] <= ambientColor[ 1 ] || luxel[ 2 ] <= ambientColor[ 2 ] )
3104                                                         //%             continue;
3105                                                         
3106                                                         /* add its distinctiveness to our own */
3107                                                         VectorAdd( radVertLuxel, luxel, radVertLuxel );
3108                                                         samples += luxel[ 3 ];
3109                                                 }
3110                                         }
3111                                 }
3112                                 
3113                                 /* any color? */
3114                                 if( samples > 0.0f )
3115                                         VectorDivide( radVertLuxel, samples, radVertLuxel );
3116                                 else
3117                                         VectorCopy( ambientColor, radVertLuxel );
3118                         }
3119                         
3120                         /* store into floating point storage */
3121                         VectorAdd( vertLuxel, radVertLuxel, vertLuxel );
3122                         numVertsIlluminated++;
3123                         
3124                         /* store into bytes (for vertex approximation) */
3125                         if( !info->si->noVertexLight )
3126                                 ColorToBytes( vertLuxel, verts[ i ].color[ lightmapNum ], 1.0f );
3127                 }
3128         }
3129 }
3130
3131
3132
3133 /* -------------------------------------------------------------------------------
3134
3135 light optimization (-fast)
3136
3137 creates a list of lights that will affect a surface and stores it in tw
3138 this is to optimize surface lighting by culling out as many of the
3139 lights in the world as possible from further calculation
3140
3141 ------------------------------------------------------------------------------- */
3142
3143 /*
3144 SetupBrushes()
3145 determines opaque brushes in the world and find sky shaders for sunlight calculations
3146 */
3147
3148 void SetupBrushes( void )
3149 {
3150         int                             i, j, b, compileFlags;
3151         qboolean                inside;
3152         bspBrush_t              *brush;
3153         bspBrushSide_t  *side;
3154         bspShader_t             *shader;
3155         shaderInfo_t    *si;
3156         
3157         
3158         /* note it */
3159         Sys_FPrintf( SYS_VRB, "--- SetupBrushes ---\n" );
3160         
3161         /* allocate */
3162         if( opaqueBrushes == NULL )
3163                 opaqueBrushes = safe_malloc( numBSPBrushes / 8 + 1 );
3164         
3165         /* clear */
3166         memset( opaqueBrushes, 0, numBSPBrushes / 8 + 1 );
3167         numOpaqueBrushes = 0;
3168         
3169         /* walk the list of worldspawn brushes */
3170         for( i = 0; i < bspModels[ 0 ].numBSPBrushes; i++ )
3171         {
3172                 /* get brush */
3173                 b = bspModels[ 0 ].firstBSPBrush + i;
3174                 brush = &bspBrushes[ b ];
3175                 
3176                 /* check all sides */
3177                 inside = qtrue;
3178                 compileFlags = 0;
3179                 for( j = 0; j < brush->numSides && inside; j++ )
3180                 {
3181                         /* do bsp shader calculations */
3182                         side = &bspBrushSides[ brush->firstSide + j ];
3183                         shader = &bspShaders[ side->shaderNum ];
3184                         
3185                         /* get shader info */
3186                         si = ShaderInfoForShader( shader->shader );
3187                         if( si == NULL )
3188                                 continue;
3189                         
3190                         /* or together compile flags */
3191                         compileFlags |= si->compileFlags;
3192                 }
3193                 
3194                 /* determine if this brush is opaque to light */
3195                 if( !(compileFlags & C_TRANSLUCENT) )
3196                 {
3197                         opaqueBrushes[ b >> 3 ] |= (1 << (b & 7));
3198                         numOpaqueBrushes++;
3199                         maxOpaqueBrush = i;
3200                 }
3201         }
3202         
3203         /* emit some statistics */
3204         Sys_FPrintf( SYS_VRB, "%9d opaque brushes\n", numOpaqueBrushes );
3205 }
3206
3207
3208
3209 /*
3210 ClusterVisible()
3211 determines if two clusters are visible to each other using the PVS
3212 */
3213
3214 qboolean ClusterVisible( int a, int b )
3215 {
3216         int                     leafBytes;
3217         byte            *pvs;
3218         
3219         
3220         /* dummy check */
3221         if( a < 0 || b < 0 )
3222                 return qfalse;
3223         
3224         /* early out */
3225         if( a == b )
3226                 return qtrue;
3227         
3228         /* not vised? */
3229         if( numBSPVisBytes <=8 )
3230                 return qtrue;
3231         
3232         /* get pvs data */
3233         /* portalClusters = ((int *) bspVisBytes)[ 0 ]; */
3234         leafBytes = ((int*) bspVisBytes)[ 1 ];
3235         pvs = bspVisBytes + VIS_HEADER_SIZE + (a * leafBytes);
3236         
3237         /* check */
3238         if( (pvs[ b >> 3 ] & (1 << (b & 7))) )
3239                 return qtrue;
3240         return qfalse;
3241 }
3242
3243
3244
3245 /*
3246 PointInLeafNum_r()
3247 borrowed from vlight.c
3248 */
3249
3250 int     PointInLeafNum_r( vec3_t point, int nodenum )
3251 {
3252         int                     leafnum;
3253         vec_t           dist;
3254         bspNode_t               *node;
3255         bspPlane_t      *plane;
3256         
3257         
3258         while( nodenum >= 0 )
3259         {
3260                 node = &bspNodes[ nodenum ];
3261                 plane = &bspPlanes[ node->planeNum ];
3262                 dist = DotProduct( point, plane->normal ) - plane->dist;
3263                 if( dist > 0.1 )
3264                         nodenum = node->children[ 0 ];
3265                 else if( dist < -0.1 )
3266                         nodenum = node->children[ 1 ];
3267                 else
3268                 {
3269                         leafnum = PointInLeafNum_r( point, node->children[ 0 ] );
3270                         if( bspLeafs[ leafnum ].cluster != -1 )
3271                                 return leafnum;
3272                         nodenum = node->children[ 1 ];
3273                 }
3274         }
3275         
3276         leafnum = -nodenum - 1;
3277         return leafnum;
3278 }
3279
3280
3281
3282 /*
3283 PointInLeafnum()
3284 borrowed from vlight.c
3285 */
3286
3287 int     PointInLeafNum( vec3_t point )
3288 {
3289         return PointInLeafNum_r( point, 0 );
3290 }
3291
3292
3293
3294 /*
3295 ClusterVisibleToPoint() - ydnar
3296 returns qtrue if point can "see" cluster
3297 */
3298
3299 qboolean ClusterVisibleToPoint( vec3_t point, int cluster )
3300 {
3301         int             pointCluster;
3302         
3303
3304         /* get leafNum for point */
3305         pointCluster = ClusterForPoint( point );
3306         if( pointCluster < 0 )
3307                 return qfalse;
3308         
3309         /* check pvs */
3310         return ClusterVisible( pointCluster, cluster );
3311 }
3312
3313
3314
3315 /*
3316 ClusterForPoint() - ydnar
3317 returns the pvs cluster for point
3318 */
3319
3320 int ClusterForPoint( vec3_t point )
3321 {
3322         int             leafNum;
3323         
3324
3325         /* get leafNum for point */
3326         leafNum = PointInLeafNum( point );
3327         if( leafNum < 0 )
3328                 return -1;
3329         
3330         /* return the cluster */
3331         return bspLeafs[ leafNum ].cluster;
3332 }
3333
3334
3335
3336 /*
3337 ClusterForPointExt() - ydnar
3338 also takes brushes into account for occlusion testing
3339 */
3340
3341 int ClusterForPointExt( vec3_t point, float epsilon )
3342 {
3343         int                             i, j, b, leafNum, cluster;
3344         float                   dot;
3345         qboolean                inside;
3346         int                             *brushes, numBSPBrushes;
3347         bspLeaf_t               *leaf;
3348         bspBrush_t              *brush;
3349         bspPlane_t              *plane;
3350         
3351         
3352         /* get leaf for point */
3353         leafNum = PointInLeafNum( point );
3354         if( leafNum < 0 )
3355                 return -1;
3356         leaf = &bspLeafs[ leafNum ];
3357         
3358         /* get the cluster */
3359         cluster = leaf->cluster;
3360         if( cluster < 0 )
3361                 return -1;
3362         
3363         /* transparent leaf, so check point against all brushes in the leaf */
3364         brushes = &bspLeafBrushes[ leaf->firstBSPLeafBrush ];
3365         numBSPBrushes = leaf->numBSPLeafBrushes;
3366         for( i = 0; i < numBSPBrushes; i++ )
3367         {
3368                 /* get parts */
3369                 b = brushes[ i ];
3370                 if( b > maxOpaqueBrush )
3371                         continue;
3372                 brush = &bspBrushes[ b ];
3373                 if( !(opaqueBrushes[ b >> 3 ] & (1 << (b & 7))) )
3374                         continue;
3375                 
3376                 /* check point against all planes */
3377                 inside = qtrue;
3378                 for( j = 0; j < brush->numSides && inside; j++ )
3379                 {
3380                         plane = &bspPlanes[ bspBrushSides[ brush->firstSide + j ].planeNum ];
3381                         dot = DotProduct( point, plane->normal );
3382                         dot -= plane->dist;
3383                         if( dot > epsilon )
3384                                 inside = qfalse;
3385                 }
3386                 
3387                 /* if inside, return bogus cluster */
3388                 if( inside )
3389                         return -1 - b;
3390         }
3391         
3392         /* if the point made it this far, it's not inside any opaque brushes */
3393         return cluster;
3394 }
3395
3396
3397
3398 /*
3399 ClusterForPointExtFilter() - ydnar
3400 adds cluster checking against a list of known valid clusters
3401 */
3402
3403 int ClusterForPointExtFilter( vec3_t point, float epsilon, int numClusters, int *clusters )
3404 {
3405         int             i, cluster;
3406         
3407         
3408         /* get cluster for point */
3409         cluster = ClusterForPointExt( point, epsilon );
3410         
3411         /* check if filtering is necessary */
3412         if( cluster < 0 || numClusters <= 0 || clusters == NULL )
3413                 return cluster;
3414         
3415         /* filter */
3416         for( i = 0; i < numClusters; i++ )
3417         {
3418                 if( cluster == clusters[ i ] || ClusterVisible( cluster, clusters[ i ] ) )
3419                         return cluster;
3420         }
3421         
3422         /* failed */
3423         return -1;
3424 }
3425
3426
3427
3428 /*
3429 ShaderForPointInLeaf() - ydnar
3430 checks a point against all brushes in a leaf, returning the shader of the brush
3431 also sets the cumulative surface and content flags for the brush hit
3432 */
3433
3434 int ShaderForPointInLeaf( vec3_t point, int leafNum, float epsilon, int wantContentFlags, int wantSurfaceFlags, int *contentFlags, int *surfaceFlags )
3435 {
3436         int                             i, j;
3437         float                   dot;
3438         qboolean                inside;
3439         int                             *brushes, numBSPBrushes;
3440         bspLeaf_t                       *leaf;
3441         bspBrush_t              *brush;
3442         bspBrushSide_t  *side;
3443         bspPlane_t              *plane;
3444         bspShader_t             *shader;
3445         int                             allSurfaceFlags, allContentFlags;
3446
3447         
3448         /* clear things out first */
3449         *surfaceFlags = 0;
3450         *contentFlags = 0;
3451         
3452         /* get leaf */
3453         if( leafNum < 0 )
3454                 return -1;
3455         leaf = &bspLeafs[ leafNum ];
3456         
3457         /* transparent leaf, so check point against all brushes in the leaf */
3458         brushes = &bspLeafBrushes[ leaf->firstBSPLeafBrush ];
3459         numBSPBrushes = leaf->numBSPLeafBrushes;
3460         for( i = 0; i < numBSPBrushes; i++ )
3461         {
3462                 /* get parts */
3463                 brush = &bspBrushes[ brushes[ i ] ];
3464                 
3465                 /* check point against all planes */
3466                 inside = qtrue;
3467                 allSurfaceFlags = 0;
3468                 allContentFlags = 0;
3469                 for( j = 0; j < brush->numSides && inside; j++ )
3470                 {
3471                         side = &bspBrushSides[ brush->firstSide + j ];
3472                         plane = &bspPlanes[ side->planeNum ];
3473                         dot = DotProduct( point, plane->normal );
3474                         dot -= plane->dist;
3475                         if( dot > epsilon )
3476                                 inside = qfalse;
3477                         else
3478                         {
3479                                 shader = &bspShaders[ side->shaderNum ];
3480                                 allSurfaceFlags |= shader->surfaceFlags;
3481                                 allContentFlags |= shader->contentFlags;
3482                         }
3483                 }
3484                 
3485                 /* handle if inside */
3486                 if( inside )
3487                 {
3488                         /* if there are desired flags, check for same and continue if they aren't matched */
3489                         if( wantContentFlags && !(wantContentFlags & allContentFlags) )
3490                                 continue;
3491                         if( wantSurfaceFlags && !(wantSurfaceFlags & allSurfaceFlags) )
3492                                 continue;
3493                         
3494                         /* store the cumulative flags and return the brush shader (which is mostly useless) */
3495                         *surfaceFlags = allSurfaceFlags;
3496                         *contentFlags = allContentFlags;
3497                         return brush->shaderNum;
3498                 }
3499         }
3500         
3501         /* if the point made it this far, it's not inside any brushes */
3502         return -1;
3503 }
3504
3505
3506
3507 /*
3508 ChopBounds()
3509 chops a bounding box by the plane defined by origin and normal
3510 returns qfalse if the bounds is entirely clipped away
3511
3512 this is not exactly the fastest way to do this...
3513 */
3514
3515 qboolean ChopBounds( vec3_t mins, vec3_t maxs, vec3_t origin, vec3_t normal )
3516 {
3517         /* FIXME: rewrite this so it doesn't use bloody brushes */
3518         return qtrue;
3519 }
3520
3521
3522
3523 /*
3524 SetupEnvelopes()
3525 calculates each light's effective envelope,
3526 taking into account brightness, type, and pvs.
3527 */
3528
3529 #define LIGHT_EPSILON   0.125f
3530 #define LIGHT_NUDGE             2.0f
3531
3532 void SetupEnvelopes( qboolean forGrid, qboolean fastFlag )
3533 {
3534         int                     i, x, y, z, x1, y1, z1;
3535         light_t         *light, *light2, **owner;
3536         bspLeaf_t       *leaf;
3537         vec3_t          origin, dir, mins, maxs;
3538         float           radius, intensity;
3539         light_t         *buckets[ 256 ];
3540         
3541         
3542         /* early out for weird cases where there are no lights */
3543         if( lights == NULL )
3544                 return;
3545         
3546         /* note it */
3547         Sys_FPrintf( SYS_VRB, "--- SetupEnvelopes%s ---\n", fastFlag ? " (fast)" : "" );
3548         
3549         /* count lights */
3550         numLights = 0;
3551         numCulledLights = 0;
3552         owner = &lights;
3553         while( *owner != NULL )
3554         {
3555                 /* get light */
3556                 light = *owner;
3557                 
3558                 /* handle negative lights */
3559                 if( light->photons < 0.0f || light->add < 0.0f )
3560                 {
3561                         light->photons *= -1.0f;
3562                         light->add *= -1.0f;
3563                         light->flags |= LIGHT_NEGATIVE;
3564                 }
3565                 
3566                 /* sunlight? */
3567                 if( light->type == EMIT_SUN )
3568                 {
3569                         /* special cased */
3570                         light->cluster = 0;
3571                         light->envelope = MAX_WORLD_COORD * 8.0f;
3572                         VectorSet( light->mins, MIN_WORLD_COORD * 8.0f, MIN_WORLD_COORD * 8.0f, MIN_WORLD_COORD * 8.0f );
3573                         VectorSet( light->maxs, MAX_WORLD_COORD * 8.0f, MAX_WORLD_COORD * 8.0f, MAX_WORLD_COORD * 8.0f );
3574                 }
3575                 
3576                 /* everything else */
3577                 else
3578                 {
3579                         /* get pvs cluster for light */
3580                         light->cluster = ClusterForPointExt( light->origin, LIGHT_EPSILON );
3581                         
3582                         /* invalid cluster? */
3583                         if( light->cluster < 0 )
3584                         {
3585                                 /* nudge the sample point around a bit */
3586                                 for( x = 0; x < 4; x++ )
3587                                 {
3588                                         /* two's complement 0, 1, -1, 2, -2, etc */
3589                                         x1 = ((x >> 1) ^ (x & 1 ? -1 : 0)) + (x & 1);
3590                                         
3591                                         for( y = 0; y < 4; y++ )
3592                                         {
3593                                                 y1 = ((y >> 1) ^ (y & 1 ? -1 : 0)) + (y & 1);
3594                                                 
3595                                                 for( z = 0; z < 4; z++ )
3596                                                 {
3597                                                         z1 = ((z >> 1) ^ (z & 1 ? -1 : 0)) + (z & 1);
3598                                                         
3599                                                         /* nudge origin */
3600                                                         origin[ 0 ] = light->origin[ 0 ] + (LIGHT_NUDGE * x1);
3601                                                         origin[ 1 ] = light->origin[ 1 ] + (LIGHT_NUDGE * y1);
3602                                                         origin[ 2 ] = light->origin[ 2 ] + (LIGHT_NUDGE * z1);
3603                                                         
3604                                                         /* try at nudged origin */
3605                                                         light->cluster = ClusterForPointExt( origin, LIGHT_EPSILON );
3606                                                         if( light->cluster < 0 )
3607                                                                 continue;
3608                                                                         
3609                                                         /* set origin */
3610                                                         VectorCopy( origin, light->origin );
3611                                                 }
3612                                         }
3613                                 }
3614                         }
3615                         
3616                         /* only calculate for lights in pvs and outside of opaque brushes */
3617                         if( light->cluster >= 0 )
3618                         {
3619                                 /* set light fast flag */
3620                                 if( fastFlag )
3621                                         light->flags |= LIGHT_FAST_TEMP;
3622                                 else
3623                                         light->flags &= ~LIGHT_FAST_TEMP;
3624                                 if( light->si && light->si->noFast )
3625                                         light->flags &= ~(LIGHT_FAST | LIGHT_FAST_TEMP);
3626                                 
3627                                 /* clear light envelope */
3628                                 light->envelope = 0;
3629                                 
3630                                 /* handle area lights */
3631                                 if( exactPointToPolygon && light->type == EMIT_AREA && light->w != NULL )
3632                                 {
3633                                         /* ugly hack to calculate extent for area lights, but only done once */
3634                                         VectorScale( light->normal, -1.0f, dir );
3635                                         for( radius = 100.0f; radius < 130000.0f && light->envelope == 0; radius += 10.0f )
3636                                         {
3637                                                 float   factor;
3638                                                 
3639                                                 VectorMA( light->origin, radius, light->normal, origin );
3640                                                 factor = PointToPolygonFormFactor( origin, dir, light->w );
3641                                                 if( factor < 0.0f )
3642                                                         factor *= -1.0f;
3643                                                 if( (factor * light->add) <= light->falloffTolerance )
3644                                                         light->envelope = radius;
3645                                         }
3646                                         
3647                                         /* check for fast mode */
3648                                         if( !(light->flags & LIGHT_FAST) && !(light->flags & LIGHT_FAST_TEMP) )
3649                                                 light->envelope = MAX_WORLD_COORD * 8.0f;
3650                                         intensity = light->photons; /* hopefully not used */
3651                                 }
3652                                 else
3653                                 {
3654                                         radius = 0.0f;
3655                                         intensity = light->photons;
3656                                 }
3657                                 
3658                                 /* other calcs */
3659                                 if( light->envelope <= 0.0f )
3660                                 {
3661                                         /* solve distance for non-distance lights */
3662                                         if( !(light->flags & LIGHT_ATTEN_DISTANCE) )
3663                                                 light->envelope = MAX_WORLD_COORD * 8.0f;
3664                                         
3665                                         /* solve distance for linear lights */
3666                                         else if( (light->flags & LIGHT_ATTEN_LINEAR ) )
3667                                                 //% light->envelope = ((intensity / light->falloffTolerance) * linearScale - 1 + radius) / light->fade;
3668                                                 light->envelope = ((intensity * linearScale) - light->falloffTolerance) / light->fade;
3669
3670                                                 /*
3671                                                 add = angle * light->photons * linearScale - (dist * light->fade);
3672                                                 T = (light->photons * linearScale) - (dist * light->fade);
3673                                                 T + (dist * light->fade) = (light->photons * linearScale);
3674                                                 dist * light->fade = (light->photons * linearScale) - T;
3675                                                 dist = ((light->photons * linearScale) - T) / light->fade;
3676                                                 */
3677                                         
3678                                         /* solve for inverse square falloff */
3679                                         else
3680                                                 light->envelope = sqrt( intensity / light->falloffTolerance ) + radius;
3681                                                 
3682                                                 /*
3683                                                 add = light->photons / (dist * dist);
3684                                                 T = light->photons / (dist * dist);
3685                                                 T * (dist * dist) = light->photons;
3686                                                 dist = sqrt( light->photons / T );
3687                                                 */
3688                                 }
3689                                 
3690                                 /* chop radius against pvs */
3691                                 {
3692                                         /* clear bounds */
3693                                         ClearBounds( mins, maxs );
3694                                         
3695                                         /* check all leaves */
3696                                         for( i = 0; i < numBSPLeafs; i++ )
3697                                         {
3698                                                 /* get test leaf */
3699                                                 leaf = &bspLeafs[ i ];
3700                                                 
3701                                                 /* in pvs? */
3702                                                 if( leaf->cluster < 0 )
3703                                                         continue;
3704                                                 if( ClusterVisible( light->cluster, leaf->cluster ) == qfalse ) /* ydnar: thanks Arnout for exposing my stupid error (this never failed before) */
3705                                                         continue;
3706                                                 
3707                                                 /* add this leafs bbox to the bounds */
3708                                                 VectorCopy( leaf->mins, origin );
3709                                                 AddPointToBounds( origin, mins, maxs );
3710                                                 VectorCopy( leaf->maxs, origin );
3711                                                 AddPointToBounds( origin, mins, maxs );
3712                                         }
3713                                         
3714                                         /* test to see if bounds encompass light */
3715                                         for( i = 0; i < 3; i++ )
3716                                         {
3717                                                 if( mins[ i ] > light->origin[ i ] || maxs[ i ] < light->origin[ i ] )
3718                                                 {
3719                                                         //% Sys_Printf( "WARNING: Light PVS bounds (%.0f, %.0f, %.0f) -> (%.0f, %.0f, %.0f)\ndo not encompass light %d (%f, %f, %f)\n",
3720                                                         //%     mins[ 0 ], mins[ 1 ], mins[ 2 ],
3721                                                         //%     maxs[ 0 ], maxs[ 1 ], maxs[ 2 ],
3722                                                         //%     numLights, light->origin[ 0 ], light->origin[ 1 ], light->origin[ 2 ] );
3723                                                         AddPointToBounds( light->origin, mins, maxs );
3724                                                 }
3725                                         }
3726                                         
3727                                         /* chop the bounds by a plane for area lights and spotlights */
3728                                         if( light->type == EMIT_AREA || light->type == EMIT_SPOT )
3729                                                 ChopBounds( mins, maxs, light->origin, light->normal );
3730                                         
3731                                         /* copy bounds */
3732                                         VectorCopy( mins, light->mins );
3733                                         VectorCopy( maxs, light->maxs );
3734                                         
3735                                         /* reflect bounds around light origin */
3736                                         //%     VectorMA( light->origin, -1.0f, origin, origin );
3737                                         VectorScale( light->origin, 2, origin );
3738                                         VectorSubtract( origin, maxs, origin );
3739                                         AddPointToBounds( origin, mins, maxs );
3740                                         //%     VectorMA( light->origin, -1.0f, mins, origin );
3741                                         VectorScale( light->origin, 2, origin );
3742                                         VectorSubtract( origin, mins, origin );
3743                                         AddPointToBounds( origin, mins, maxs );
3744                                          
3745                                         /* calculate spherical bounds */
3746                                         VectorSubtract( maxs, light->origin, dir );
3747                                         radius = (float) VectorLength( dir );
3748                                         
3749                                         /* if this radius is smaller than the envelope, then set the envelope to it */
3750                                         if( radius < light->envelope )
3751                                         {
3752                                                 light->envelope = radius;
3753                                                 //%     Sys_FPrintf( SYS_VRB, "PVS Cull (%d): culled\n", numLights );
3754                                         }
3755                                         //%     else
3756                                         //%             Sys_FPrintf( SYS_VRB, "PVS Cull (%d): failed (%8.0f > %8.0f)\n", numLights, radius, light->envelope );
3757                                 }
3758                                 
3759                                 /* add grid/surface only check */
3760                                 if( forGrid )
3761                                 {
3762                                         if( !(light->flags & LIGHT_GRID) )
3763                                                 light->envelope = 0.0f;
3764                                 }
3765                                 else
3766                                 {
3767                                         if( !(light->flags & LIGHT_SURFACES) )
3768                                                 light->envelope = 0.0f;
3769                                 }
3770                         }
3771                         
3772                         /* culled? */
3773                         if( light->cluster < 0 || light->envelope <= 0.0f )
3774                         {
3775                                 /* debug code */
3776                                 //%     Sys_Printf( "Culling light: Cluster: %d Envelope: %f\n", light->cluster, light->envelope );
3777                                 
3778                                 /* delete the light */
3779                                 numCulledLights++;
3780                                 *owner = light->next;
3781                                 if( light->w != NULL )
3782                                         free( light->w );
3783                                 free( light );
3784                                 continue;
3785                         }
3786                 }
3787                 
3788                 /* square envelope */
3789                 light->envelope2 = (light->envelope * light->envelope);
3790                 
3791                 /* increment light count */
3792                 numLights++;
3793                 
3794                 /* set next light */
3795                 owner = &((**owner).next);
3796         }
3797         
3798         /* bucket sort lights by style */
3799         memset( buckets, 0, sizeof( buckets ) );
3800         light2 = NULL;
3801         for( light = lights; light != NULL; light = light2 )
3802         {
3803                 /* get next light */
3804                 light2 = light->next;
3805                 
3806                 /* filter into correct bucket */
3807                 light->next = buckets[ light->style ];
3808                 buckets[ light->style ] = light;
3809                 
3810                 /* if any styled light is present, automatically set nocollapse */
3811                 if( light->style != LS_NORMAL )
3812                         noCollapse = qtrue;
3813         }
3814         
3815         /* filter back into light list */
3816         lights = NULL;
3817         for( i = 255; i >= 0; i-- )
3818         {
3819                 light2 = NULL;
3820                 for( light = buckets[ i ]; light != NULL; light = light2 )
3821                 {
3822                         light2 = light->next;
3823                         light->next = lights;
3824                         lights = light;
3825                 }
3826         }
3827         
3828         /* emit some statistics */
3829         Sys_Printf( "%9d total lights\n", numLights );
3830         Sys_Printf( "%9d culled lights\n", numCulledLights );
3831 }
3832
3833
3834
3835 /*
3836 CreateTraceLightsForBounds()
3837 creates a list of lights that affect the given bounding box and pvs clusters (bsp leaves)
3838 */
3839
3840 void CreateTraceLightsForBounds( vec3_t mins, vec3_t maxs, vec3_t normal, int numClusters, int *clusters, int flags, trace_t *trace )
3841 {
3842         int                     i;
3843         light_t         *light;
3844         vec3_t          origin, dir, nullVector = { 0.0f, 0.0f, 0.0f };
3845         float           radius, dist, length;
3846         
3847         
3848         /* potential pre-setup  */
3849         if( numLights == 0 )
3850                 SetupEnvelopes( qfalse, fast );
3851         
3852         /* debug code */
3853         //% Sys_Printf( "CTWLFB: (%4.1f %4.1f %4.1f) (%4.1f %4.1f %4.1f)\n", mins[ 0 ], mins[ 1 ], mins[ 2 ], maxs[ 0 ], maxs[ 1 ], maxs[ 2 ] );
3854         
3855         /* allocate the light list */
3856         trace->lights = safe_malloc( sizeof( light_t* ) * (numLights + 1) );
3857         trace->numLights = 0;
3858         
3859         /* calculate spherical bounds */
3860         VectorAdd( mins, maxs, origin );
3861         VectorScale( origin, 0.5f, origin );
3862         VectorSubtract( maxs, origin, dir );
3863         radius = (float) VectorLength( dir );
3864         
3865         /* get length of normal vector */
3866         if( normal != NULL )
3867                 length = VectorLength( normal );
3868         else
3869         {
3870                 normal = nullVector;
3871                 length = 0;
3872         }
3873         
3874         /* test each light and see if it reaches the sphere */
3875         /* note: the attenuation code MUST match LightingAtSample() */
3876         for( light = lights; light; light = light->next )
3877         {
3878                 /* check zero sized envelope */
3879                 if( light->envelope <= 0 )
3880                 {
3881                         lightsEnvelopeCulled++;
3882                         continue;
3883                 }
3884                 
3885                 /* check flags */
3886                 if( !(light->flags & flags) )
3887                         continue;
3888                 
3889                 /* sunlight skips all this nonsense */
3890                 if( light->type != EMIT_SUN )
3891                 {
3892                         /* sun only? */
3893                         if( sunOnly )
3894                                 continue;
3895                         
3896                         /* check against pvs cluster */
3897                         if( numClusters > 0 && clusters != NULL )
3898                         {
3899                                 for( i = 0; i < numClusters; i++ )
3900                                 {
3901                                         if( ClusterVisible( light->cluster, clusters[ i ] ) )
3902                                                 break;
3903                                 }
3904                                 
3905                                 /* fixme! */
3906                                 if( i == numClusters )
3907                                 {
3908                                         lightsClusterCulled++;
3909                                         continue;
3910                                 }
3911                         }
3912                         
3913                         /* if the light's bounding sphere intersects with the bounding sphere then this light needs to be tested */
3914                         VectorSubtract( light->origin, origin, dir );
3915                         dist = VectorLength( dir );
3916                         dist -= light->envelope;
3917                         dist -= radius;
3918                         if( dist > 0 )
3919                         {
3920                                 lightsEnvelopeCulled++;
3921                                 continue;
3922                         }
3923                         
3924                         /* check bounding box against light's pvs envelope (note: this code never eliminated any lights, so disabling it) */
3925                         #if 0
3926                         skip = qfalse;
3927                         for( i = 0; i < 3; i++ )
3928                         {
3929                                 if( mins[ i ] > light->maxs[ i ] || maxs[ i ] < light->mins[ i ] )
3930                                         skip = qtrue;
3931                         }
3932                         if( skip )
3933                         {
3934                                 lightsBoundsCulled++;
3935                                 continue;
3936                         }
3937                         #endif
3938                 }
3939                 
3940                 /* planar surfaces (except twosided surfaces) have a couple more checks */
3941                 if( length > 0.0f && trace->twoSided == qfalse )
3942                 {
3943                         /* lights coplanar with a surface won't light it */
3944                         if( !(light->flags & LIGHT_TWOSIDED) && DotProduct( light->normal, normal ) > 0.999f )
3945                         {
3946                                 lightsPlaneCulled++;
3947                                 continue;
3948                         }
3949                         
3950                         /* check to see if light is behind the plane */
3951                         if( DotProduct( light->origin, normal ) - DotProduct( origin, normal ) < -1.0f )
3952                         {
3953                                 lightsPlaneCulled++;
3954                                 continue;
3955                         }
3956                 }
3957                 
3958                 /* add this light */
3959                 trace->lights[ trace->numLights++ ] = light;
3960         }
3961         
3962         /* make last night null */
3963         trace->lights[ trace->numLights ] = NULL;
3964 }
3965
3966
3967
3968 void FreeTraceLights( trace_t *trace )
3969 {
3970         if( trace->lights != NULL )
3971                 free( trace->lights );
3972 }
3973
3974
3975
3976 /*
3977 CreateTraceLightsForSurface()
3978 creates a list of lights that can potentially affect a drawsurface
3979 */
3980
3981 void CreateTraceLightsForSurface( int num, trace_t *trace )
3982 {
3983         int                                     i;
3984         vec3_t                          mins, maxs, normal;
3985         bspDrawVert_t           *dv;
3986         bspDrawSurface_t        *ds;
3987         surfaceInfo_t           *info;
3988         
3989         
3990         /* dummy check */
3991         if( num < 0 )
3992                 return;
3993         
3994         /* get drawsurface and info */
3995         ds = &bspDrawSurfaces[ num ];
3996         info = &surfaceInfos[ num ];
3997         
3998         /* get the mins/maxs for the dsurf */
3999         ClearBounds( mins, maxs );
4000         VectorCopy( bspDrawVerts[ ds->firstVert ].normal, normal );
4001         for( i = 0; i < ds->numVerts; i++ )
4002         {
4003                 dv = &yDrawVerts[ ds->firstVert + i ];
4004                 AddPointToBounds( dv->xyz, mins, maxs );
4005                 if( !VectorCompare( dv->normal, normal ) )
4006                         VectorClear( normal );
4007         }
4008         
4009         /* create the lights for the bounding box */
4010         CreateTraceLightsForBounds( mins, maxs, normal, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ], LIGHT_SURFACES, trace );
4011 }
4012
4013 /////////////////////////////////////////////////////////////
4014
4015 #define FLOODLIGHT_CONE_ANGLE                   88      /* degrees */
4016 #define FLOODLIGHT_NUM_ANGLE_STEPS              16
4017 #define FLOODLIGHT_NUM_ELEVATION_STEPS  4
4018 #define FLOODLIGHT_NUM_VECTORS                  (FLOODLIGHT_NUM_ANGLE_STEPS * FLOODLIGHT_NUM_ELEVATION_STEPS)
4019
4020 static vec3_t   floodVectors[ FLOODLIGHT_NUM_VECTORS ];
4021 static int              numFloodVectors = 0;
4022
4023 void SetupFloodLight( void )
4024 {
4025         int             i, j;
4026         float   angle, elevation, angleStep, elevationStep;
4027         const char      *value;
4028         double v1,v2,v3,v4,v5,v6;
4029
4030         /* note it */
4031         Sys_FPrintf( SYS_VRB, "--- SetupFloodLight ---\n" );
4032
4033         /* calculate angular steps */
4034         angleStep = DEG2RAD( 360.0f / FLOODLIGHT_NUM_ANGLE_STEPS );
4035         elevationStep = DEG2RAD( FLOODLIGHT_CONE_ANGLE / FLOODLIGHT_NUM_ELEVATION_STEPS );
4036
4037         /* iterate angle */
4038         angle = 0.0f;
4039         for( i = 0, angle = 0.0f; i < FLOODLIGHT_NUM_ANGLE_STEPS; i++, angle += angleStep )
4040         {
4041                 /* iterate elevation */
4042                 for( j = 0, elevation = elevationStep * 0.5f; j < FLOODLIGHT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep )
4043                 {
4044                         floodVectors[ numFloodVectors ][ 0 ] = sin( elevation ) * cos( angle );
4045                         floodVectors[ numFloodVectors ][ 1 ] = sin( elevation ) * sin( angle );
4046                         floodVectors[ numFloodVectors ][ 2 ] = cos( elevation );
4047                         numFloodVectors++;
4048                 }
4049         }
4050
4051         /* emit some statistics */
4052         Sys_FPrintf( SYS_VRB, "%9d numFloodVectors\n", numFloodVectors );
4053
4054       /* floodlight */
4055         value = ValueForKey( &entities[ 0 ], "_floodlight" );
4056
4057         if( value[ 0 ] != '\0' )
4058         {
4059                 v1=v2=v3=0;
4060                 v4=floodlightDistance;
4061                 v5=floodlightIntensity;
4062                 v6=floodlightDirectionScale;
4063
4064                 sscanf( value, "%lf %lf %lf %lf %lf %lf", &v1, &v2, &v3, &v4, &v5, &v6);
4065
4066                 floodlightRGB[0]=v1;
4067                 floodlightRGB[1]=v2;
4068                 floodlightRGB[2]=v3;
4069
4070                 if (VectorLength(floodlightRGB)==0)
4071                 {
4072                         VectorSet(floodlightRGB,240,240,255);
4073                 }
4074
4075                 if (v4<1) v4=1024;
4076                 if (v5<1) v5=128;
4077                 if (v6<0) v6=1;
4078
4079                 floodlightDistance=v4;
4080                 floodlightIntensity=v5;
4081                 floodlightDirectionScale=v6;
4082
4083                 floodlighty = qtrue;
4084                 Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
4085         }
4086         else
4087         {
4088                 VectorSet(floodlightRGB,240,240,255);
4089                 //floodlighty = qtrue;
4090                 //Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
4091         }
4092         VectorNormalize(floodlightRGB,floodlightRGB);
4093 }
4094
4095 /*
4096 FloodLightForSample()
4097 calculates floodlight value for a given sample
4098 once again, kudos to the dirtmapping coder
4099 */
4100
4101 float FloodLightForSample( trace_t *trace , float floodLightDistance, qboolean floodLightLowQuality)
4102 {
4103         int             i;
4104         float   d;
4105         float   contribution;
4106         int     sub = 0;
4107         float   gatherLight, outLight;
4108         vec3_t  normal, worldUp, myUp, myRt, direction, displacement;
4109         float   dd;
4110         int     vecs = 0;
4111  
4112         gatherLight=0;
4113         /* dummy check */
4114         //if( !dirty )
4115         //      return 1.0f;
4116         if( trace == NULL || trace->cluster < 0 )
4117                 return 0.0f;
4118         
4119
4120         /* setup */
4121         dd = floodLightDistance;
4122         VectorCopy( trace->normal, normal );
4123         
4124         /* check if the normal is aligned to the world-up */
4125         if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f && ( normal[ 2 ] == 1.0f || normal[ 2 ] == -1.0f ) )
4126         {
4127                 if( normal[ 2 ] == 1.0f )               
4128                 {
4129                         VectorSet( myRt, 1.0f, 0.0f, 0.0f );
4130                         VectorSet( myUp, 0.0f, 1.0f, 0.0f );
4131                 }
4132                 else if( normal[ 2 ] == -1.0f )
4133                 {
4134                         VectorSet( myRt, -1.0f, 0.0f, 0.0f );
4135                         VectorSet( myUp,  0.0f, 1.0f, 0.0f );
4136                 }
4137         }
4138         else
4139         {
4140                 VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
4141                 CrossProduct( normal, worldUp, myRt );
4142                 VectorNormalize( myRt, myRt );
4143                 CrossProduct( myRt, normal, myUp );
4144                 VectorNormalize( myUp, myUp );
4145         }
4146
4147         /* vortex: optimise floodLightLowQuality a bit */
4148         if ( floodLightLowQuality == qtrue )
4149     {
4150                 /* iterate through ordered vectors */
4151                 for( i = 0; i < numFloodVectors; i++ )
4152                         if (rand()%10 != 0 ) continue;
4153         }
4154         else
4155         {
4156                 /* iterate through ordered vectors */
4157                 for( i = 0; i < numFloodVectors; i++ )
4158                 {
4159                         vecs++;
4160                  
4161                         /* transform vector into tangent space */
4162                         direction[ 0 ] = myRt[ 0 ] * floodVectors[ i ][ 0 ] + myUp[ 0 ] * floodVectors[ i ][ 1 ] + normal[ 0 ] * floodVectors[ i ][ 2 ];
4163                         direction[ 1 ] = myRt[ 1 ] * floodVectors[ i ][ 0 ] + myUp[ 1 ] * floodVectors[ i ][ 1 ] + normal[ 1 ] * floodVectors[ i ][ 2 ];
4164                         direction[ 2 ] = myRt[ 2 ] * floodVectors[ i ][ 0 ] + myUp[ 2 ] * floodVectors[ i ][ 1 ] + normal[ 2 ] * floodVectors[ i ][ 2 ];
4165
4166                         /* set endpoint */
4167                         VectorMA( trace->origin, dd, direction, trace->end );
4168
4169                         //VectorMA( trace->origin, 1, direction, trace->origin );
4170                                 
4171                         SetupTrace( trace );
4172                         /* trace */
4173                         TraceLine( trace );
4174                         contribution=1;
4175
4176                         if ( trace->compileFlags & C_SKY || trace->compileFlags & C_TRANSLUCENT )
4177                         {
4178                                 contribution=1.0f;
4179                         }
4180                         else if ( trace->opaque )
4181                         {
4182                                 VectorSubtract( trace->hit, trace->origin, displacement );
4183                                 d=VectorLength( displacement );
4184
4185                                 // d=trace->distance;            
4186                                 //if (d>256) gatherDirt+=1;
4187                                 contribution=d/dd;
4188                                 if (contribution>1) contribution=1.0f; 
4189                      
4190                                 //gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
4191                         }
4192                  
4193                         gatherLight+=contribution;
4194                 }
4195         }
4196    
4197         /* early out */
4198         if( gatherLight <= 0.0f )
4199                 return 0.0f;
4200         
4201         sub=vecs;
4202
4203         if (sub<1) sub=1;
4204         gatherLight/=(sub);
4205
4206         outLight=gatherLight;
4207         if( outLight > 1.0f )
4208                 outLight = 1.0f;
4209         
4210         /* return to sender */
4211         return outLight;
4212 }
4213
4214 /*
4215 FloodLightRawLightmap
4216 lighttracer style ambient occlusion light hack.
4217 Kudos to the dirtmapping author for most of this source.
4218 VorteX: modified to floodlight up custom surfaces (q3map_floodLight)
4219 VorteX: fixed problems with deluxemapping
4220 */
4221
4222 // floodlight pass on a lightmap
4223 void FloodLightRawLightmapPass( rawLightmap_t *lm , vec3_t lmFloodLightRGB, float lmFloodLightIntensity, float lmFloodLightDistance, qboolean lmFloodLightLowQuality, float floodlightDirectionScale)
4224 {
4225         int                                     i, x, y, *cluster;
4226         float                           *origin, *normal, *floodlight, floodLightAmount;
4227         surfaceInfo_t           *info;
4228         trace_t                         trace;
4229         // int sx, sy;
4230         // float samples, average, *floodlight2;
4231         
4232         memset(&trace,0,sizeof(trace_t));
4233
4234         /* setup trace */
4235         trace.testOcclusion = qtrue;
4236         trace.forceSunlight = qfalse;
4237         trace.twoSided = qtrue;
4238         trace.recvShadows = lm->recvShadows;
4239         trace.numSurfaces = lm->numLightSurfaces;
4240         trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
4241         trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
4242         trace.testAll = qfalse;
4243         trace.distance = 1024;
4244         
4245         /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
4246         //trace.twoSided = qfalse;
4247         for( i = 0; i < trace.numSurfaces; i++ )
4248         {
4249                 /* get surface */
4250                 info = &surfaceInfos[ trace.surfaces[ i ] ];
4251                 
4252                 /* check twosidedness */
4253                 if( info->si->twoSided )
4254                 {
4255                         trace.twoSided = qtrue;
4256                         break;
4257                 }
4258         }
4259         
4260         /* gather floodlight */
4261         for( y = 0; y < lm->sh; y++ )
4262         {
4263                 for( x = 0; x < lm->sw; x++ )
4264                 {
4265                         /* get luxel */
4266                         cluster = SUPER_CLUSTER( x, y );
4267                         origin = SUPER_ORIGIN( x, y );
4268                         normal = SUPER_NORMAL( x, y );
4269                         floodlight = SUPER_FLOODLIGHT( x, y );
4270                         
4271                         /* set default dirt */
4272                         *floodlight = 0.0f;
4273                         
4274                         /* only look at mapped luxels */
4275                         if( *cluster < 0 )
4276                                 continue;
4277                         
4278                         /* copy to trace */
4279                         trace.cluster = *cluster;
4280                         VectorCopy( origin, trace.origin );
4281                         VectorCopy( normal, trace.normal );
4282    
4283                         /* get floodlight */
4284                         floodLightAmount = FloodLightForSample( &trace , lmFloodLightDistance, lmFloodLightLowQuality)*lmFloodLightIntensity;
4285                         
4286                         /* add floodlight */
4287                         floodlight[0] += lmFloodLightRGB[0]*floodLightAmount;
4288                         floodlight[1] += lmFloodLightRGB[1]*floodLightAmount;
4289                         floodlight[2] += lmFloodLightRGB[2]*floodLightAmount;
4290                         floodlight[3] += floodlightDirectionScale;
4291                 }
4292         }
4293         
4294         /* testing no filtering */
4295         return;
4296
4297 #if 0
4298         
4299         /* filter "dirt" */
4300         for( y = 0; y < lm->sh; y++ )
4301         {
4302                 for( x = 0; x < lm->sw; x++ )
4303                 {
4304                         /* get luxel */
4305                         cluster = SUPER_CLUSTER( x, y );
4306                         floodlight = SUPER_FLOODLIGHT(x, y );
4307                         
4308                         /* filter dirt by adjacency to unmapped luxels */
4309                         average = *floodlight;
4310                         samples = 1.0f;
4311                         for( sy = (y - 1); sy <= (y + 1); sy++ )
4312                         {
4313                                 if( sy < 0 || sy >= lm->sh )
4314                                         continue;
4315                                 
4316                                 for( sx = (x - 1); sx <= (x + 1); sx++ )
4317                                 {
4318                                         if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
4319                                                 continue;
4320                                         
4321                                         /* get neighboring luxel */
4322                                         cluster = SUPER_CLUSTER( sx, sy );
4323                                         floodlight2 = SUPER_FLOODLIGHT( sx, sy );
4324                                         if( *cluster < 0 || *floodlight2 <= 0.0f )
4325                                                 continue;
4326                                         
4327                                         /* add it */
4328                                         average += *floodlight2;
4329                                         samples += 1.0f;
4330                                 }
4331                                 
4332                                 /* bail */
4333                                 if( samples <= 0.0f )
4334                                         break;
4335                         }
4336                         
4337                         /* bail */
4338                         if( samples <= 0.0f )
4339                                 continue;
4340                         
4341                         /* scale dirt */
4342                         *floodlight = average / samples;
4343                 }
4344         }
4345 #endif
4346 }
4347
4348 void FloodLightRawLightmap( int rawLightmapNum )
4349 {
4350         rawLightmap_t           *lm;
4351
4352         /* bail if this number exceeds the number of raw lightmaps */
4353         if( rawLightmapNum >= numRawLightmaps )
4354                 return;
4355         /* get lightmap */
4356         lm = &rawLightmaps[ rawLightmapNum ];
4357
4358         /* global pass */
4359         if (floodlighty && floodlightIntensity)
4360                 FloodLightRawLightmapPass(lm, floodlightRGB, floodlightIntensity, floodlightDistance, floodlight_lowquality, floodlightDirectionScale);
4361
4362         /* custom pass */
4363         if (lm->floodlightIntensity)
4364         {
4365                 FloodLightRawLightmapPass(lm, lm->floodlightRGB, lm->floodlightIntensity, lm->floodlightDistance, qfalse, lm->floodlightDirectionScale);
4366                 numSurfacesFloodlighten += 1;
4367         }
4368 }
4369
4370 void FloodlightRawLightmaps()
4371 {
4372         Sys_Printf( "--- FloodlightRawLightmap ---\n" );
4373         numSurfacesFloodlighten = 0;
4374         RunThreadsOnIndividual( numRawLightmaps, qtrue, FloodLightRawLightmap );
4375         Sys_Printf( "%9d custom lightmaps floodlighted\n", numSurfacesFloodlighten );
4376 }
4377
4378 /*
4379 FloodLightIlluminate()
4380 illuminate floodlight into lightmap luxels
4381 */
4382
4383 void FloodlightIlluminateLightmap( rawLightmap_t *lm )
4384 {
4385         float                           *luxel, *floodlight, *deluxel, *normal;
4386         int                                     *cluster;
4387         float                           brightness;
4388         int                                     x, y, lightmapNum;
4389
4390         /* walk lightmaps */
4391         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
4392         {
4393                 /* early out */
4394                 if( lm->superLuxels[ lightmapNum ] == NULL )
4395                         continue;
4396
4397                 /* apply floodlight to each luxel */
4398                 for( y = 0; y < lm->sh; y++ )
4399                 {
4400                         for( x = 0; x < lm->sw; x++ )
4401                         {
4402                                 /* get floodlight */
4403                                 floodlight = SUPER_FLOODLIGHT( x, y );
4404                                 if (!floodlight[0] && !floodlight[1] && !floodlight[2])
4405                                         continue;
4406                                                 
4407                                 /* get cluster */
4408                                 cluster = SUPER_CLUSTER( x, y );
4409
4410                                 /* only process mapped luxels */
4411                                 if( *cluster < 0 )
4412                                         continue;
4413
4414                                 /* get particulars */
4415                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
4416                                 deluxel = SUPER_DELUXEL( x, y );
4417
4418                                 /* add to lightmap */
4419                                 luxel[0]+=floodlight[0];
4420                                 luxel[1]+=floodlight[1];
4421                                 luxel[2]+=floodlight[2];
4422
4423                                 if (luxel[3]==0) luxel[3]=1;
4424
4425                                 /* add to deluxemap */
4426                                 if (deluxemap && floodlight[3] > 0)
4427                                 {
4428                                         vec3_t                          lightvector;
4429
4430                                         normal = SUPER_NORMAL( x, y );
4431                                         brightness = RGBTOGRAY( floodlight ) * ( 1.0f/255.0f ) * floodlight[3];
4432
4433                                         // use AT LEAST this amount of contribution from ambient for the deluxemap, fixes points that receive ZERO light
4434                                         if(brightness < 0.00390625f)
4435                                                 brightness = 0.00390625f;
4436
4437                                         VectorScale( normal, brightness, lightvector );
4438                                         VectorAdd( deluxel, lightvector, deluxel );
4439                                 }
4440                         }
4441                 }
4442         }
4443 }