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