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