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