]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/light_ydnar.c
add a missing VectorClear
[xonotic/netradiant.git] / tools / quake3 / q3map2 / light_ydnar.c
1 /* -------------------------------------------------------------------------------
2
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
5
6 This file is part of GtkRadiant.
7
8 GtkRadiant is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 GtkRadiant is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GtkRadiant; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21
22 ----------------------------------------------------------------------------------
23
24 This code has been altered significantly from its original form, to support
25 several games based on the Quake III Arena engine, in the form of "Q3Map2."
26
27 ------------------------------------------------------------------------------- */
28
29
30
31 /* marker */
32 #define LIGHT_YDNAR_C
33
34
35
36 /* dependencies */
37 #include "q3map2.h"
38
39
40
41
42 /*
43 ColorToBytes()
44 ydnar: moved to here 2001-02-04
45 */
46
47 void ColorToBytes( const float *color, byte *colorBytes, float scale )
48 {
49         int             i;
50         float   max, gamma;
51         vec3_t  sample;
52         float   inv, dif;
53         
54         
55         /* ydnar: scaling necessary for simulating r_overbrightBits on external lightmaps */
56         if( scale <= 0.0f )
57                 scale = 1.0f;
58         
59         /* make a local copy */
60         VectorScale( color, scale, sample );
61         
62         /* muck with it */
63         gamma = 1.0f / lightmapGamma;
64         for( i = 0; i < 3; i++ )
65         {
66                 /* handle negative light */
67                 if( sample[ i ] < 0.0f )
68                 {
69                         sample[ i ] = 0.0f;
70                         continue;
71                 }
72                 
73                 /* gamma */
74                 sample[ i ] = pow( sample[ i ] / 255.0f, gamma ) * 255.0f;
75         }
76
77         if (lightmapExposure == 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                                                 /* get drawverts and map first triangle */
1158                                                 MapTriangle( lm, info, dv, mapNonAxial );
1159                                                 
1160                                                 /* get drawverts and map second triangle */
1161                                                 dv[ 1 ] = &verts[ pw[ r + 2 ] ];
1162                                                 dv[ 2 ] = &verts[ pw[ r + 3 ] ];
1163                                                 MapTriangle( lm, info, dv, mapNonAxial );
1164                                         }
1165                                 }
1166                                 
1167                                 #endif
1168                                 
1169                                 /* free the mesh */
1170                                 FreeMesh( mesh );
1171                                 break;
1172                         
1173                         default:
1174                                 break;
1175                 }
1176         }
1177         
1178         /* -----------------------------------------------------------------
1179            average and clean up luxel normals
1180            ----------------------------------------------------------------- */
1181         
1182         /* walk the luxels */
1183         for( y = 0; y < lm->sh; y++ )
1184         {
1185                 for( x = 0; x < lm->sw; x++ )
1186                 {
1187                         /* get luxel */
1188                         luxel = SUPER_LUXEL( 0, x, y );
1189                         normal = SUPER_NORMAL( x, y );
1190                         cluster = SUPER_CLUSTER( x, y );
1191
1192                         /* only look at mapped luxels */
1193                         if( *cluster < 0 )
1194                                 continue;
1195                         
1196                         /* the normal data could be the sum of multiple samples */
1197                         if( luxel[ 3 ] > 1.0f )
1198                                 VectorNormalize( normal, normal );
1199                         
1200                         /* mark this luxel as having only one normal */
1201                         luxel[ 3 ] = 1.0f;
1202                 }
1203         }
1204         
1205         /* non-planar surfaces stop here */
1206         if( lm->plane == NULL )
1207                 return;
1208         
1209         /* -----------------------------------------------------------------
1210            map occluded or unuxed luxels
1211            ----------------------------------------------------------------- */
1212         
1213         /* walk the luxels */
1214         radius = floor( superSample / 2 );
1215         radius = radius > 0 ? radius : 1.0f;
1216         radius += 1.0f;
1217         for( pass = 2.0f; pass <= radius; pass += 1.0f )
1218         {
1219                 for( y = 0; y < lm->sh; y++ )
1220                 {
1221                         for( x = 0; x < lm->sw; x++ )
1222                         {
1223                                 /* get luxel */
1224                                 luxel = SUPER_LUXEL( 0, x, y );
1225                                 normal = SUPER_NORMAL( x, y );
1226                                 cluster = SUPER_CLUSTER( x, y );
1227                                 
1228                                 /* only look at unmapped luxels */
1229                                 if( *cluster != CLUSTER_UNMAPPED )
1230                                         continue;
1231                                 
1232                                 /* divine a normal and origin from neighboring luxels */
1233                                 VectorClear( fake.xyz );
1234                                 VectorClear( fake.normal );
1235                                 fake.lightmap[ 0 ][ 0 ] = x;    //% 0.0001 + x;
1236                                 fake.lightmap[ 0 ][ 1 ] = y;    //% 0.0001 + y;
1237                                 samples = 0.0f;
1238                                 for( sy = (y - 1); sy <= (y + 1); sy++ )
1239                                 {
1240                                         if( sy < 0 || sy >= lm->sh )
1241                                                 continue;
1242                                         
1243                                         for( sx = (x - 1); sx <= (x + 1); sx++ )
1244                                         {
1245                                                 if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
1246                                                         continue;
1247                                                 
1248                                                 /* get neighboring luxel */
1249                                                 luxel = SUPER_LUXEL( 0, sx, sy );
1250                                                 origin = SUPER_ORIGIN( sx, sy );
1251                                                 normal = SUPER_NORMAL( sx, sy );
1252                                                 cluster = SUPER_CLUSTER( sx, sy );
1253                                                 
1254                                                 /* only consider luxels mapped in previous passes */
1255                                                 if( *cluster < 0 || luxel[ 0 ] >= pass )
1256                                                         continue;
1257                                                 
1258                                                 /* add its distinctiveness to our own */
1259                                                 VectorAdd( fake.xyz, origin, fake.xyz );
1260                                                 VectorAdd( fake.normal, normal, fake.normal );
1261                                                 samples += luxel[ 3 ];
1262                                         }
1263                                 }
1264                                 
1265                                 /* any samples? */
1266                                 if( samples == 0.0f )
1267                                         continue;
1268                                 
1269                                 /* average */
1270                                 VectorDivide( fake.xyz, samples, fake.xyz );
1271                                 //%     VectorDivide( fake.normal, samples, fake.normal );
1272                                 if( VectorNormalize( fake.normal, fake.normal ) == 0.0f )
1273                                         continue;
1274                                 
1275                                 /* map the fake vert */
1276                                 MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL, NULL );
1277                         }
1278                 }
1279         }
1280         
1281         /* -----------------------------------------------------------------
1282            average and clean up luxel normals
1283            ----------------------------------------------------------------- */
1284         
1285         /* walk the luxels */
1286         for( y = 0; y < lm->sh; y++ )
1287         {
1288                 for( x = 0; x < lm->sw; x++ )
1289                 {
1290                         /* get luxel */
1291                         luxel = SUPER_LUXEL( 0, x, y );
1292                         normal = SUPER_NORMAL( x, y );
1293                         cluster = SUPER_CLUSTER( x, y );
1294                         
1295                         /* only look at mapped luxels */
1296                         if( *cluster < 0 )
1297                                 continue;
1298                         
1299                         /* the normal data could be the sum of multiple samples */
1300                         if( luxel[ 3 ] > 1.0f )
1301                                 VectorNormalize( normal, normal );
1302                         
1303                         /* mark this luxel as having only one normal */
1304                         luxel[ 3 ] = 1.0f;
1305                 }
1306         }
1307         
1308         /* debug code */
1309         #if 0
1310                 Sys_Printf( "\n" );
1311                 for( y = 0; y < lm->sh; y++ )
1312                 {
1313                         for( x = 0; x < lm->sw; x++ )
1314                         {
1315                                 vec3_t  mins, maxs;
1316                                 
1317
1318                                 cluster = SUPER_CLUSTER( x, y );
1319                                 origin = SUPER_ORIGIN( x, y );
1320                                 normal = SUPER_NORMAL( x, y );
1321                                 luxel = SUPER_LUXEL( x, y );
1322                                 
1323                                 if( *cluster < 0 )
1324                                         continue;
1325                                 
1326                                 /* check if within the bounding boxes of all surfaces referenced */
1327                                 ClearBounds( mins, maxs );
1328                                 for( n = 0; n < lm->numLightSurfaces; n++ )
1329                                 {
1330                                         int TOL;
1331                                         info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + n ] ];
1332                                         TOL = info->sampleSize + 2;
1333                                         AddPointToBounds( info->mins, mins, maxs );
1334                                         AddPointToBounds( info->maxs, mins, maxs );
1335                                         if( origin[ 0 ] > (info->mins[ 0 ] - TOL) && origin[ 0 ] < (info->maxs[ 0 ] + TOL) &&
1336                                                 origin[ 1 ] > (info->mins[ 1 ] - TOL) && origin[ 1 ] < (info->maxs[ 1 ] + TOL) &&
1337                                                 origin[ 2 ] > (info->mins[ 2 ] - TOL) && origin[ 2 ] < (info->maxs[ 2 ] + TOL) )
1338                                                 break;
1339                                 }
1340                                 
1341                                 /* inside? */
1342                                 if( n < lm->numLightSurfaces )
1343                                         continue;
1344                                 
1345                                 /* report bogus origin */
1346                                 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",
1347                                         rawLightmapNum, x, y, *cluster,
1348                                         origin[ 0 ], origin[ 1 ], origin[ 2 ],
1349                                         mins[ 0 ], mins[ 1 ], mins[ 2 ],
1350                                         maxs[ 0 ], maxs[ 1 ], maxs[ 2 ],
1351                                         luxel[ 3 ] );
1352                         }
1353                 }
1354         #endif
1355 }
1356
1357
1358
1359 /*
1360 SetupDirt()
1361 sets up dirtmap (ambient occlusion)
1362 */
1363
1364 #define DIRT_CONE_ANGLE                         88      /* degrees */
1365 #define DIRT_NUM_ANGLE_STEPS            16
1366 #define DIRT_NUM_ELEVATION_STEPS        3
1367 #define DIRT_NUM_VECTORS                        (DIRT_NUM_ANGLE_STEPS * DIRT_NUM_ELEVATION_STEPS)
1368
1369 static vec3_t           dirtVectors[ DIRT_NUM_VECTORS ];
1370 static int                      numDirtVectors = 0;
1371
1372 void SetupDirt( void )
1373 {
1374         int             i, j;
1375         float   angle, elevation, angleStep, elevationStep;
1376         
1377         
1378         /* note it */
1379         Sys_FPrintf( SYS_VRB, "--- SetupDirt ---\n" );
1380         
1381         /* calculate angular steps */
1382         angleStep = DEG2RAD( 360.0f / DIRT_NUM_ANGLE_STEPS );
1383         elevationStep = DEG2RAD( DIRT_CONE_ANGLE / DIRT_NUM_ELEVATION_STEPS );
1384         
1385         /* iterate angle */
1386         angle = 0.0f;
1387         for( i = 0, angle = 0.0f; i < DIRT_NUM_ANGLE_STEPS; i++, angle += angleStep )
1388         {
1389                 /* iterate elevation */
1390                 for( j = 0, elevation = elevationStep * 0.5f; j < DIRT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep )
1391                 {
1392                         dirtVectors[ numDirtVectors ][ 0 ] = sin( elevation ) * cos( angle );
1393                         dirtVectors[ numDirtVectors ][ 1 ] = sin( elevation ) * sin( angle );
1394                         dirtVectors[ numDirtVectors ][ 2 ] = cos( elevation );
1395                         numDirtVectors++;
1396                 }
1397         }
1398         
1399         /* emit some statistics */
1400         Sys_FPrintf( SYS_VRB, "%9d dirtmap vectors\n", numDirtVectors );
1401 }
1402
1403
1404 /*
1405 DirtForSample()
1406 calculates dirt value for a given sample
1407 */
1408
1409 float DirtForSample( trace_t *trace )
1410 {
1411         int             i;
1412         float   gatherDirt, outDirt, angle, elevation, ooDepth;
1413         vec3_t  normal, worldUp, myUp, myRt, temp, direction, displacement;
1414         
1415         
1416         /* dummy check */
1417         if( !dirty )
1418                 return 1.0f;
1419         if( trace == NULL || trace->cluster < 0 )
1420                 return 0.0f;
1421         
1422         /* setup */
1423         gatherDirt = 0.0f;
1424         ooDepth = 1.0f / dirtDepth;
1425         VectorCopy( trace->normal, normal );
1426         
1427         /* check if the normal is aligned to the world-up */
1428         if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f && ( normal[ 2 ] == 1.0f || normal[ 2 ] == -1.0f ) )
1429         {
1430                 if( normal[ 2 ] == 1.0f )               
1431                 {
1432                         VectorSet( myRt, 1.0f, 0.0f, 0.0f );
1433                         VectorSet( myUp, 0.0f, 1.0f, 0.0f );
1434                 }
1435                 else if( normal[ 2 ] == -1.0f )
1436                 {
1437                         VectorSet( myRt, -1.0f, 0.0f, 0.0f );
1438                         VectorSet( myUp,  0.0f, 1.0f, 0.0f );
1439                 }
1440         }
1441         else
1442         {
1443                 VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
1444                 CrossProduct( normal, worldUp, myRt );
1445                 VectorNormalize( myRt, myRt );
1446                 CrossProduct( myRt, normal, myUp );
1447                 VectorNormalize( myUp, myUp );
1448         }
1449         
1450         /* 1 = random mode, 0 (well everything else) = non-random mode */
1451         if( dirtMode == 1 )
1452         {
1453                 /* iterate */
1454                 for( i = 0; i < numDirtVectors; i++ )
1455                 {
1456                         /* get random vector */
1457                         angle = Random() * DEG2RAD( 360.0f );
1458                         elevation = Random() * DEG2RAD( DIRT_CONE_ANGLE );
1459                         temp[ 0 ] = cos( angle ) * sin( elevation );
1460                         temp[ 1 ] = sin( angle ) * sin( elevation );
1461                         temp[ 2 ] = cos( elevation );
1462                         
1463                         /* transform into tangent space */
1464                         direction[ 0 ] = myRt[ 0 ] * temp[ 0 ] + myUp[ 0 ] * temp[ 1 ] + normal[ 0 ] * temp[ 2 ];
1465                         direction[ 1 ] = myRt[ 1 ] * temp[ 0 ] + myUp[ 1 ] * temp[ 1 ] + normal[ 1 ] * temp[ 2 ];
1466                         direction[ 2 ] = myRt[ 2 ] * temp[ 0 ] + myUp[ 2 ] * temp[ 1 ] + normal[ 2 ] * temp[ 2 ];
1467                         
1468                         /* set endpoint */
1469                         VectorMA( trace->origin, dirtDepth, direction, trace->end );
1470                         SetupTrace( trace );
1471                         
1472                         /* trace */
1473                         TraceLine( trace );
1474                         if( trace->opaque )
1475                         {
1476                                 VectorSubtract( trace->hit, trace->origin, displacement );
1477                                 gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1478                         }
1479                 }
1480         }
1481         else
1482         {
1483                 /* iterate through ordered vectors */
1484                 for( i = 0; i < numDirtVectors; i++ )
1485                 {
1486                         /* transform vector into tangent space */
1487                         direction[ 0 ] = myRt[ 0 ] * dirtVectors[ i ][ 0 ] + myUp[ 0 ] * dirtVectors[ i ][ 1 ] + normal[ 0 ] * dirtVectors[ i ][ 2 ];
1488                         direction[ 1 ] = myRt[ 1 ] * dirtVectors[ i ][ 0 ] + myUp[ 1 ] * dirtVectors[ i ][ 1 ] + normal[ 1 ] * dirtVectors[ i ][ 2 ];
1489                         direction[ 2 ] = myRt[ 2 ] * dirtVectors[ i ][ 0 ] + myUp[ 2 ] * dirtVectors[ i ][ 1 ] + normal[ 2 ] * dirtVectors[ i ][ 2 ];
1490                         
1491                         /* set endpoint */
1492                         VectorMA( trace->origin, dirtDepth, direction, trace->end );
1493                         SetupTrace( trace );
1494                         
1495                         /* trace */
1496                         TraceLine( trace );
1497                         if( trace->opaque )
1498                         {
1499                                 VectorSubtract( trace->hit, trace->origin, displacement );
1500                                 gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1501                         }
1502                 }
1503         }
1504         
1505         /* direct ray */
1506         VectorMA( trace->origin, dirtDepth, normal, trace->end );
1507         SetupTrace( trace );
1508         
1509         /* trace */
1510         TraceLine( trace );
1511         if( trace->opaque )
1512         {
1513                 VectorSubtract( trace->hit, trace->origin, displacement );
1514                 gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1515         }
1516         
1517         /* early out */
1518         if( gatherDirt <= 0.0f )
1519                 return 1.0f;
1520         
1521         /* apply gain (does this even do much? heh) */
1522         outDirt = pow( gatherDirt / (numDirtVectors + 1), dirtGain );
1523         if( outDirt > 1.0f )
1524                 outDirt = 1.0f;
1525         
1526         /* apply scale */
1527         outDirt *= dirtScale;
1528         if( outDirt > 1.0f )
1529                 outDirt = 1.0f;
1530         
1531         /* return to sender */
1532         return 1.0f - outDirt;
1533 }
1534
1535
1536
1537 /*
1538 DirtyRawLightmap()
1539 calculates dirty fraction for each luxel
1540 */
1541
1542 void DirtyRawLightmap( int rawLightmapNum )
1543 {
1544         int                                     i, x, y, sx, sy, *cluster;
1545         float                           *origin, *normal, *dirt, *dirt2, average, samples;
1546         rawLightmap_t           *lm;
1547         surfaceInfo_t           *info;
1548         trace_t                         trace;
1549         qboolean                        noDirty;
1550
1551         
1552         /* bail if this number exceeds the number of raw lightmaps */
1553         if( rawLightmapNum >= numRawLightmaps )
1554                 return;
1555         
1556         /* get lightmap */
1557         lm = &rawLightmaps[ rawLightmapNum ];
1558         
1559         /* setup trace */
1560         trace.testOcclusion = qtrue;
1561         trace.forceSunlight = qfalse;
1562         trace.recvShadows = lm->recvShadows;
1563         trace.numSurfaces = lm->numLightSurfaces;
1564         trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
1565         trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1566         trace.testAll = qtrue;
1567         
1568         /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
1569         trace.twoSided = qfalse;
1570         for( i = 0; i < trace.numSurfaces; i++ )
1571         {
1572                 /* get surface */
1573                 info = &surfaceInfos[ trace.surfaces[ i ] ];
1574                 
1575                 /* check twosidedness */
1576                 if( info->si->twoSided )
1577                 {
1578                         trace.twoSided = qtrue;
1579                         break;
1580                 }
1581         }
1582
1583         noDirty = qfalse;
1584         for( i = 0; i < trace.numSurfaces; i++ )
1585         {
1586                 /* get surface */
1587                 info = &surfaceInfos[ trace.surfaces[ i ] ];
1588
1589                 /* check twosidedness */
1590                 if( info->si->noDirty )
1591                 {
1592                         noDirty = qtrue;
1593                         break;
1594                 }
1595         }
1596         
1597         /* gather dirt */
1598         for( y = 0; y < lm->sh; y++ )
1599         {
1600                 for( x = 0; x < lm->sw; x++ )
1601                 {
1602                         /* get luxel */
1603                         cluster = SUPER_CLUSTER( x, y );
1604                         origin = SUPER_ORIGIN( x, y );
1605                         normal = SUPER_NORMAL( x, y );
1606                         dirt = SUPER_DIRT( x, y );
1607                         
1608                         /* set default dirt */
1609                         *dirt = 0.0f;
1610                         
1611                         /* only look at mapped luxels */
1612                         if( *cluster < 0 )
1613                                 continue;
1614
1615                         /* don't apply dirty on this surface */
1616                         if( noDirty )
1617                         {
1618                                 *dirt = 1.0f;
1619                                 continue;
1620                         }
1621                         
1622                         /* copy to trace */
1623                         trace.cluster = *cluster;
1624                         VectorCopy( origin, trace.origin );
1625                         VectorCopy( normal, trace.normal );
1626                         
1627                         /* get dirt */
1628                         *dirt = DirtForSample( &trace );
1629                 }
1630         }
1631         
1632         /* testing no filtering */
1633         //%     return;
1634         
1635         /* filter dirt */
1636         for( y = 0; y < lm->sh; y++ )
1637         {
1638                 for( x = 0; x < lm->sw; x++ )
1639                 {
1640                         /* get luxel */
1641                         cluster = SUPER_CLUSTER( x, y );
1642                         dirt = SUPER_DIRT( x, y );
1643                         
1644                         /* filter dirt by adjacency to unmapped luxels */
1645                         average = *dirt;
1646                         samples = 1.0f;
1647                         for( sy = (y - 1); sy <= (y + 1); sy++ )
1648                         {
1649                                 if( sy < 0 || sy >= lm->sh )
1650                                         continue;
1651                                 
1652                                 for( sx = (x - 1); sx <= (x + 1); sx++ )
1653                                 {
1654                                         if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
1655                                                 continue;
1656                                         
1657                                         /* get neighboring luxel */
1658                                         cluster = SUPER_CLUSTER( sx, sy );
1659                                         dirt2 = SUPER_DIRT( sx, sy );
1660                                         if( *cluster < 0 || *dirt2 <= 0.0f )
1661                                                 continue;
1662                                         
1663                                         /* add it */
1664                                         average += *dirt2;
1665                                         samples += 1.0f;
1666                                 }
1667                                 
1668                                 /* bail */
1669                                 if( samples <= 0.0f )
1670                                         break;
1671                         }
1672                         
1673                         /* bail */
1674                         if( samples <= 0.0f )
1675                                 continue;
1676                         
1677                         /* scale dirt */
1678                         *dirt = average / samples;
1679                 }
1680         }
1681 }
1682
1683
1684
1685 /*
1686 SubmapRawLuxel()
1687 calculates the pvs cluster, origin, normal of a sub-luxel
1688 */
1689
1690 static qboolean SubmapRawLuxel( rawLightmap_t *lm, int x, int y, float bx, float by, int *sampleCluster, vec3_t sampleOrigin, vec3_t sampleNormal )
1691 {
1692         int                     i, *cluster, *cluster2;
1693         float           *origin, *origin2, *normal;     //%     , *normal2;
1694         vec3_t          originVecs[ 2 ];                        //%     , normalVecs[ 2 ];
1695         
1696         
1697         /* calulate x vector */
1698         if( (x < (lm->sw - 1) && bx >= 0.0f) || (x == 0 && bx <= 0.0f) )
1699         {
1700                 cluster = SUPER_CLUSTER( x, y );
1701                 origin = SUPER_ORIGIN( x, y );
1702                 //%     normal = SUPER_NORMAL( x, y );
1703                 cluster2 = SUPER_CLUSTER( x + 1, y );
1704                 origin2 = *cluster2 < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x + 1, y );
1705                 //%     normal2 = *cluster2 < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x + 1, y );
1706         }
1707         else if( (x > 0 && bx <= 0.0f) || (x == (lm->sw - 1) && bx >= 0.0f) )
1708         {
1709                 cluster = SUPER_CLUSTER( x - 1, y );
1710                 origin = *cluster < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x - 1, y );
1711                 //%     normal = *cluster < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x - 1, y );
1712                 cluster2 = SUPER_CLUSTER( x, y );
1713                 origin2 = SUPER_ORIGIN( x, y );
1714                 //%     normal2 = SUPER_NORMAL( x, y );
1715         }
1716         else
1717                 Sys_Printf( "WARNING: Spurious lightmap S vector\n" );
1718         
1719         VectorSubtract( origin2, origin, originVecs[ 0 ] );
1720         //%     VectorSubtract( normal2, normal, normalVecs[ 0 ] );
1721         
1722         /* calulate y vector */
1723         if( (y < (lm->sh - 1) && bx >= 0.0f) || (y == 0 && bx <= 0.0f) )
1724         {
1725                 cluster = SUPER_CLUSTER( x, y );
1726                 origin = SUPER_ORIGIN( x, y );
1727                 //%     normal = SUPER_NORMAL( x, y );
1728                 cluster2 = SUPER_CLUSTER( x, y + 1 );
1729                 origin2 = *cluster2 < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x, y + 1 );
1730                 //%     normal2 = *cluster2 < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x, y + 1 );
1731         }
1732         else if( (y > 0 && bx <= 0.0f) || (y == (lm->sh - 1) && bx >= 0.0f) )
1733         {
1734                 cluster = SUPER_CLUSTER( x, y - 1 );
1735                 origin = *cluster < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x, y - 1 );
1736                 //%     normal = *cluster < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x, y - 1 );
1737                 cluster2 = SUPER_CLUSTER( x, y );
1738                 origin2 = SUPER_ORIGIN( x, y );
1739                 //%     normal2 = SUPER_NORMAL( x, y );
1740         }
1741         else
1742                 Sys_Printf( "WARNING: Spurious lightmap T vector\n" );
1743         
1744         VectorSubtract( origin2, origin, originVecs[ 1 ] );
1745         //%     VectorSubtract( normal2, normal, normalVecs[ 1 ] );
1746         
1747         /* calculate new origin */
1748         //%     VectorMA( origin, bx, originVecs[ 0 ], sampleOrigin );
1749         //%     VectorMA( sampleOrigin, by, originVecs[ 1 ], sampleOrigin );
1750         for( i = 0; i < 3; i++ )
1751                 sampleOrigin[ i ] = sampleOrigin[ i ] + (bx * originVecs[ 0 ][ i ]) + (by * originVecs[ 1 ][ i ]);
1752         
1753         /* get cluster */
1754         *sampleCluster = ClusterForPointExtFilter( sampleOrigin, (LUXEL_EPSILON * 2), lm->numLightClusters, lm->lightClusters );
1755         if( *sampleCluster < 0 )
1756                 return qfalse;
1757         
1758         /* calculate new normal */
1759         //%     VectorMA( normal, bx, normalVecs[ 0 ], sampleNormal );
1760         //%     VectorMA( sampleNormal, by, normalVecs[ 1 ], sampleNormal );
1761         //%     if( VectorNormalize( sampleNormal, sampleNormal ) <= 0.0f )
1762         //%             return qfalse;
1763         normal = SUPER_NORMAL( x, y );
1764         VectorCopy( normal, sampleNormal );
1765         
1766         /* return ok */
1767         return qtrue;
1768 }
1769
1770
1771 /*
1772 SubsampleRawLuxel_r()
1773 recursively subsamples a luxel until its color gradient is low enough or subsampling limit is reached
1774 */
1775
1776 static void SubsampleRawLuxel_r( rawLightmap_t *lm, trace_t *trace, vec3_t sampleOrigin, int x, int y, float bias, float *lightLuxel, float *lightDeluxel )
1777 {
1778         int                     b, samples, mapped, lighted;
1779         int                     cluster[ 4 ];
1780         vec4_t          luxel[ 4 ];
1781         vec3_t          deluxel[ 3 ];
1782         vec3_t          origin[ 4 ], normal[ 4 ];
1783         float           biasDirs[ 4 ][ 2 ] = { { -1.0f, -1.0f }, { 1.0f, -1.0f }, { -1.0f, 1.0f }, { 1.0f, 1.0f } };
1784         vec3_t          color, direction, total;
1785         
1786         
1787         /* limit check */
1788         if( lightLuxel[ 3 ] >= lightSamples )
1789                 return;
1790         
1791         /* setup */
1792         VectorClear( total );
1793         mapped = 0;
1794         lighted = 0;
1795         
1796         /* make 2x2 subsample stamp */
1797         for( b = 0; b < 4; b++ )
1798         {
1799                 /* set origin */
1800                 VectorCopy( sampleOrigin, origin[ b ] );
1801                 
1802                 /* calculate position */
1803                 if( !SubmapRawLuxel( lm, x, y, (bias * biasDirs[ b ][ 0 ]), (bias * biasDirs[ b ][ 1 ]), &cluster[ b ], origin[ b ], normal[ b ] ) )
1804                 {
1805                         cluster[ b ] = -1;
1806                         continue;
1807                 }
1808                 mapped++;
1809                 
1810                 /* increment sample count */
1811                 luxel[ b ][ 3 ] = lightLuxel[ 3 ] + 1.0f;
1812                 
1813                 /* setup trace */
1814                 trace->cluster = *cluster;
1815                 VectorCopy( origin[ b ], trace->origin );
1816                 VectorCopy( normal[ b ], trace->normal );
1817                 
1818                 /* sample light */
1819
1820                 LightContributionToSample( trace );
1821                 if(trace->forceSubsampling > 1.0f)
1822                 {
1823                         /* alphashadow: we subsample as deep as we can */
1824                         ++lighted;
1825                         ++mapped;
1826                         ++mapped;
1827                 }
1828                 
1829                 /* add to totals (fixme: make contrast function) */
1830                 VectorCopy( trace->color, luxel[ b ] );
1831                 if(lightDeluxel)
1832                 {
1833                         VectorCopy( trace->directionContribution, deluxel[ b ] );
1834                 }
1835                 VectorAdd( total, trace->color, total );
1836                 if( (luxel[ b ][ 0 ] + luxel[ b ][ 1 ] + luxel[ b ][ 2 ]) > 0.0f )
1837                         lighted++;
1838         }
1839         
1840         /* subsample further? */
1841         if( (lightLuxel[ 3 ] + 1.0f) < lightSamples &&
1842                 (total[ 0 ] > 4.0f || total[ 1 ] > 4.0f || total[ 2 ] > 4.0f) &&
1843                 lighted != 0 && lighted != mapped )
1844         {
1845                 for( b = 0; b < 4; b++ )
1846                 {
1847                         if( cluster[ b ] < 0 )
1848                                 continue;
1849                         SubsampleRawLuxel_r( lm, trace, origin[ b ], x, y, (bias * 0.5f), luxel[ b ], lightDeluxel ? deluxel[ b ] : NULL );
1850                 }
1851         }
1852         
1853         /* average */
1854         //%     VectorClear( color );
1855         //%     samples = 0;
1856         VectorCopy( lightLuxel, color );
1857         VectorCopy( lightDeluxel, direction );
1858         samples = 1;
1859         for( b = 0; b < 4; b++ )
1860         {
1861                 if( cluster[ b ] < 0 )
1862                         continue;
1863                 VectorAdd( color, luxel[ b ], color );
1864                 if(lightDeluxel)
1865                 {
1866                         VectorAdd( direction, deluxel[ b ], direction );
1867                 }
1868                 samples++;
1869         }
1870         
1871         /* add to luxel */
1872         if( samples > 0 )
1873         {
1874                 /* average */
1875                 color[ 0 ] /= samples;
1876                 color[ 1 ] /= samples;
1877                 color[ 2 ] /= samples;
1878
1879                 /* add to color */
1880                 VectorCopy( color, lightLuxel );
1881                 lightLuxel[ 3 ] += 1.0f;
1882
1883                 if(lightDeluxel)
1884                 {
1885                         direction[ 0 ] /= samples;
1886                         direction[ 1 ] /= samples;
1887                         direction[ 2 ] /= samples;
1888                         VectorCopy( direction, lightDeluxel );
1889                 }
1890         }
1891 }
1892
1893 /* A mostly Gaussian-like bounded random distribution (sigma is expected standard deviation) */
1894 static void GaussLikeRandom(float sigma, float *x, float *y)
1895 {
1896         float r;
1897         r = Random() * 2 * Q_PI;
1898         *x = sigma * 2.73861278752581783822 * cos(r);
1899         *y = sigma * 2.73861278752581783822 * sin(r);
1900         r = Random();
1901         r = 1 - sqrt(r);
1902         r = 1 - sqrt(r);
1903         *x *= r;
1904         *y *= r;
1905 }
1906 static void RandomSubsampleRawLuxel( rawLightmap_t *lm, trace_t *trace, vec3_t sampleOrigin, int x, int y, float bias, float *lightLuxel, float *lightDeluxel )
1907 {
1908         int                     b, mapped;
1909         int                     cluster;
1910         vec3_t          origin, normal;
1911         vec3_t          total, totaldirection;
1912         float           dx, dy;
1913         
1914         VectorClear( total );
1915         VectorClear( totaldirection );
1916         mapped = 0;
1917         for(b = 0; b < lightSamples; ++b)
1918         {
1919                 /* set origin */
1920                 VectorCopy( sampleOrigin, origin );
1921                 GaussLikeRandom(bias, &dx, &dy);
1922                 if(dx > 1) dx = 1;
1923                 if(dy > 1) dy = 1;
1924                 if(dx < -1) dx = -1;
1925                 if(dy < -1) dy = -1;
1926
1927                 /* calculate position */
1928                 if( !SubmapRawLuxel( lm, x, y, dx, dy, &cluster, origin, normal ) )
1929                 {
1930                         cluster = -1;
1931                         continue;
1932                 }
1933                 mapped++;
1934
1935                 trace->cluster = cluster;
1936                 VectorCopy( origin, trace->origin );
1937                 VectorCopy( normal, trace->normal );
1938
1939                 LightContributionToSample( trace );
1940                 VectorAdd( total, trace->color, total );
1941                 if(lightDeluxel)
1942                 {
1943                         VectorAdd( totaldirection, trace->directionContribution, totaldirection );
1944                 }
1945         }
1946
1947         /* add to luxel */
1948         if( mapped > 0 )
1949         {
1950                 /* average */
1951                 lightLuxel[ 0 ] = total[ 0 ] / mapped;
1952                 lightLuxel[ 1 ] = total[ 1 ] / mapped;
1953                 lightLuxel[ 2 ] = total[ 2 ] / mapped;
1954
1955                 if(lightDeluxel)
1956                 {
1957                         lightDeluxel[ 0 ] = totaldirection[ 0 ] / mapped;
1958                         lightDeluxel[ 1 ] = totaldirection[ 1 ] / mapped;
1959                         lightDeluxel[ 2 ] = totaldirection[ 2 ] / mapped;
1960                 }
1961         }
1962 }
1963
1964
1965
1966 /*
1967 IlluminateRawLightmap()
1968 illuminates the luxels
1969 */
1970
1971 #define STACK_LL_SIZE                   (SUPER_LUXEL_SIZE * 64 * 64)
1972 #define LIGHT_LUXEL( x, y )             (lightLuxels + ((((y) * lm->sw) + (x)) * SUPER_LUXEL_SIZE))
1973 #define LIGHT_DELUXEL( x, y )           (lightDeluxels + ((((y) * lm->sw) + (x)) * SUPER_DELUXEL_SIZE))
1974
1975 void IlluminateRawLightmap( int rawLightmapNum )
1976 {
1977         int                                     i, t, x, y, sx, sy, size, llSize, ldSize, luxelFilterRadius, lightmapNum;
1978         int                                     *cluster, *cluster2, mapped, lighted, totalLighted;
1979         rawLightmap_t           *lm;
1980         surfaceInfo_t           *info;
1981         qboolean                        filterColor, filterDir;
1982         float                           brightness;
1983         float                           *origin, *normal, *dirt, *luxel, *luxel2, *deluxel, *deluxel2;
1984         unsigned char                   *flag;
1985         float                           *lightLuxels, *lightDeluxels, *lightLuxel, *lightDeluxel, samples, filterRadius, weight;
1986         vec3_t                          color, direction, averageColor, averageDir, total, temp, temp2;
1987         float                           tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
1988         trace_t                         trace;
1989         float                           stackLightLuxels[ STACK_LL_SIZE ];
1990         
1991         
1992         /* bail if this number exceeds the number of raw lightmaps */
1993         if( rawLightmapNum >= numRawLightmaps )
1994                 return;
1995         
1996         /* get lightmap */
1997         lm = &rawLightmaps[ rawLightmapNum ];
1998         
1999         /* setup trace */
2000         trace.testOcclusion = !noTrace;
2001         trace.forceSunlight = qfalse;
2002         trace.recvShadows = lm->recvShadows;
2003         trace.numSurfaces = lm->numLightSurfaces;
2004         trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
2005         trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
2006         
2007         /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
2008         trace.twoSided = qfalse;
2009         for( i = 0; i < trace.numSurfaces; i++ )
2010         {
2011                 /* get surface */
2012                 info = &surfaceInfos[ trace.surfaces[ i ] ];
2013                 
2014                 /* check twosidedness */
2015                 if( info->si->twoSided )
2016                 {
2017                         trace.twoSided = qtrue;
2018                         break;
2019                 }
2020         }
2021         
2022         /* create a culled light list for this raw lightmap */
2023         CreateTraceLightsForBounds( lm->mins, lm->maxs, lm->plane, lm->numLightClusters, lm->lightClusters, LIGHT_SURFACES, &trace );
2024         
2025         /* -----------------------------------------------------------------
2026            fill pass
2027            ----------------------------------------------------------------- */
2028         
2029         /* set counts */
2030         numLuxelsIlluminated += (lm->sw * lm->sh);
2031         
2032         /* test debugging state */
2033         if( debugSurfaces || debugAxis || debugCluster || debugOrigin || dirtDebug || normalmap )
2034         {
2035                 /* debug fill the luxels */
2036                 for( y = 0; y < lm->sh; y++ )
2037                 {
2038                         for( x = 0; x < lm->sw; x++ )
2039                         {
2040                                 /* get cluster */
2041                                 cluster = SUPER_CLUSTER( x, y );
2042
2043                                 /* only fill mapped luxels */
2044                                 if( *cluster < 0 )
2045                                         continue;
2046                                 
2047                                 /* get particulars */
2048                                 luxel = SUPER_LUXEL( 0, x, y );
2049                                 origin = SUPER_ORIGIN( x, y );
2050                                 normal = SUPER_NORMAL( x, y );
2051                                 
2052                                 /* color the luxel with raw lightmap num? */
2053                                 if( debugSurfaces )
2054                                         VectorCopy( debugColors[ rawLightmapNum % 12 ], luxel );
2055                                 
2056                                 /* color the luxel with lightmap axis? */
2057                                 else if( debugAxis )
2058                                 {
2059                                         luxel[ 0 ] = (lm->axis[ 0 ] + 1.0f) * 127.5f;
2060                                         luxel[ 1 ] = (lm->axis[ 1 ] + 1.0f) * 127.5f;
2061                                         luxel[ 2 ] = (lm->axis[ 2 ] + 1.0f) * 127.5f;
2062                                 }
2063                                 
2064                                 /* color the luxel with luxel cluster? */
2065                                 else if( debugCluster )
2066                                         VectorCopy( debugColors[ *cluster % 12 ], luxel );
2067                                 
2068                                 /* color the luxel with luxel origin? */
2069                                 else if( debugOrigin )
2070                                 {
2071                                         VectorSubtract( lm->maxs, lm->mins, temp );
2072                                         VectorScale( temp, (1.0f / 255.0f), temp );
2073                                         VectorSubtract( origin, lm->mins, temp2 );
2074                                         luxel[ 0 ] = lm->mins[ 0 ] + (temp[ 0 ] * temp2[ 0 ]);
2075                                         luxel[ 1 ] = lm->mins[ 1 ] + (temp[ 1 ] * temp2[ 1 ]);
2076                                         luxel[ 2 ] = lm->mins[ 2 ] + (temp[ 2 ] * temp2[ 2 ]);
2077                                 }
2078                                 
2079                                 /* color the luxel with the normal */
2080                                 else if( normalmap )
2081                                 {
2082                                         luxel[ 0 ] = (normal[ 0 ] + 1.0f) * 127.5f;
2083                                         luxel[ 1 ] = (normal[ 1 ] + 1.0f) * 127.5f;
2084                                         luxel[ 2 ] = (normal[ 2 ] + 1.0f) * 127.5f;
2085                                 }
2086                                 
2087                                 /* otherwise clear it */
2088                                 else
2089                                         VectorClear( luxel );
2090                                 
2091                                 /* add to counts */
2092                                 luxel[ 3 ] = 1.0f;
2093                         }
2094                 }
2095         }
2096         else
2097         {
2098                 /* allocate temporary per-light luxel storage */
2099                 llSize = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
2100                 ldSize = lm->sw * lm->sh * SUPER_DELUXEL_SIZE * sizeof( float );
2101                 if( llSize <= (STACK_LL_SIZE * sizeof( float )) )
2102                         lightLuxels = stackLightLuxels;
2103                 else
2104                         lightLuxels = safe_malloc( llSize );
2105                 if(deluxemap)
2106                         lightDeluxels = safe_malloc( ldSize );
2107                 else
2108                         lightDeluxels = NULL;
2109                 
2110                 /* clear luxels */
2111                 //%     memset( lm->superLuxels[ 0 ], 0, llSize );
2112                 
2113                 /* set ambient color */
2114                 for( y = 0; y < lm->sh; y++ )
2115                 {
2116                         for( x = 0; x < lm->sw; x++ )
2117                         {
2118                                 /* get cluster */
2119                                 cluster = SUPER_CLUSTER( x, y );
2120                                 luxel = SUPER_LUXEL( 0, x, y );
2121                                 normal = SUPER_NORMAL( x, y );
2122                                 deluxel = SUPER_DELUXEL( x, y );
2123                                 
2124                                 /* blacken unmapped clusters */
2125                                 if( *cluster < 0 )
2126                                         VectorClear( luxel );
2127                                 
2128                                 /* set ambient */
2129                                 else
2130                                 {
2131                                         VectorCopy( ambientColor, luxel );
2132                                         if( deluxemap )
2133                                         {
2134                                                 brightness = RGBTOGRAY( ambientColor ) * ( 1.0f/255.0f );
2135
2136                                                 // use AT LEAST this amount of contribution from ambient for the deluxemap, fixes points that receive ZERO light
2137                                                 if(brightness < 0.00390625f)
2138                                                         brightness = 0.00390625f;
2139
2140                                                 VectorScale( normal, brightness, deluxel );
2141                                         }
2142                                         luxel[ 3 ] = 1.0f;
2143                                 }
2144                         }
2145                 }
2146                 
2147                 /* clear styled lightmaps */
2148                 size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
2149                 for( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2150                 {
2151                         if( lm->superLuxels[ lightmapNum ] != NULL )
2152                                 memset( lm->superLuxels[ lightmapNum ], 0, size );
2153                 }
2154                 
2155                 /* debugging code */
2156                 //%     if( trace.numLights <= 0 )
2157                 //%             Sys_Printf( "Lightmap %9d: 0 lights, axis: %.2f, %.2f, %.2f\n", rawLightmapNum, lm->axis[ 0 ], lm->axis[ 1 ], lm->axis[ 2 ] );
2158                 
2159                 /* walk light list */
2160                 for( i = 0; i < trace.numLights; i++ )
2161                 {
2162                         /* setup trace */
2163                         trace.light = trace.lights[ i ];
2164                         
2165                         /* style check */
2166                         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2167                         {
2168                                 if( lm->styles[ lightmapNum ] == trace.light->style ||
2169                                         lm->styles[ lightmapNum ] == LS_NONE )
2170                                         break;
2171                         }
2172                         
2173                         /* max of MAX_LIGHTMAPS (4) styles allowed to hit a surface/lightmap */
2174                         if( lightmapNum >= MAX_LIGHTMAPS )
2175                         {
2176                                 Sys_Printf( "WARNING: Hit per-surface style limit (%d)\n", MAX_LIGHTMAPS );
2177                                 continue;
2178                         }
2179                         
2180                         /* setup */
2181                         memset( lightLuxels, 0, llSize );
2182                         if(deluxemap)
2183                                 memset( lightDeluxels, 0, ldSize );
2184                         totalLighted = 0;
2185                         
2186                         /* determine filter radius */
2187                         filterRadius = lm->filterRadius > trace.light->filterRadius
2188                                 ? lm->filterRadius
2189                                 : trace.light->filterRadius;
2190                         if( filterRadius < 0.0f )
2191                                 filterRadius = 0.0f;
2192                         
2193                         /* set luxel filter radius */
2194                         luxelFilterRadius = superSample * filterRadius / lm->sampleSize;
2195                         if( luxelFilterRadius == 0 && (filterRadius > 0.0f || filter) )
2196                                 luxelFilterRadius = 1;
2197
2198                         /* allocate sampling flags storage */
2199                         if((lightSamples > 1 || lightRandomSamples) && luxelFilterRadius == 0)
2200                         {
2201                                 size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( unsigned char );
2202                                 if(lm->superFlags == NULL)
2203                                         lm->superFlags = safe_malloc( size );
2204                                 memset( (void *) lm->superFlags, 0, size );
2205                         }
2206
2207                         /* initial pass, one sample per luxel */
2208                         for( y = 0; y < lm->sh; y++ )
2209                         {
2210                                 for( x = 0; x < lm->sw; x++ )
2211                                 {
2212                                         /* get cluster */
2213                                         cluster = SUPER_CLUSTER( x, y );
2214                                         if( *cluster < 0 )
2215                                                 continue;
2216                                         
2217                                         /* get particulars */
2218                                         lightLuxel = LIGHT_LUXEL( x, y );
2219                                         lightDeluxel = LIGHT_DELUXEL( x, y );
2220                                         origin = SUPER_ORIGIN( x, y );
2221                                         normal = SUPER_NORMAL( x, y );
2222                                         flag = SUPER_FLAG( x, y );
2223
2224 #if 0
2225                                         ////////// 27's temp hack for testing edge clipping ////
2226                                         if( origin[0]==0 && origin[1]==0 && origin[2]==0 )
2227                                         {
2228                                                 lightLuxel[ 1 ] = 255;
2229                                                 lightLuxel[ 3 ] = 1.0f;
2230                                                 totalLighted++;
2231                                         }
2232                                         else
2233 #endif
2234                                         {
2235                                                 /* set contribution count */
2236                                                 lightLuxel[ 3 ] = 1.0f;
2237
2238                                                 /* setup trace */
2239                                                 trace.cluster = *cluster;
2240                                                 VectorCopy( origin, trace.origin );
2241                                                 VectorCopy( normal, trace.normal );
2242
2243                                                 /* get light for this sample */
2244                                                 LightContributionToSample( &trace );
2245                                                 VectorCopy( trace.color, lightLuxel );
2246
2247                                                 /* add the contribution to the deluxemap */
2248                                                 if( deluxemap )
2249                                                 {
2250                                                         VectorCopy( trace.directionContribution, lightDeluxel );
2251                                                 }
2252
2253                                                 /* check for evilness */
2254                                                 if(trace.forceSubsampling > 1.0f && (lightSamples > 1 || lightRandomSamples) && luxelFilterRadius == 0)
2255                                                 {
2256                                                         totalLighted++;
2257                                                         *flag |= FLAG_FORCE_SUBSAMPLING; /* force */
2258                                                 }
2259                                                 /* add to count */
2260                                                 else if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
2261                                                         totalLighted++;
2262                                         }
2263                                 }
2264                         }
2265                         
2266                         /* don't even bother with everything else if nothing was lit */
2267                         if( totalLighted == 0 )
2268                                 continue;
2269                         
2270                         /* secondary pass, adaptive supersampling (fixme: use a contrast function to determine if subsampling is necessary) */
2271                         /* 2003-09-27: changed it so filtering disamples supersampling, as it would waste time */
2272                         if( (lightSamples > 1 || lightRandomSamples) && luxelFilterRadius == 0 )
2273                         {
2274                                 /* walk luxels */
2275                                 for( y = 0; y < (lm->sh - 1); y++ )
2276                                 {
2277                                         for( x = 0; x < (lm->sw - 1); x++ )
2278                                         {
2279                                                 /* setup */
2280                                                 mapped = 0;
2281                                                 lighted = 0;
2282                                                 VectorClear( total );
2283                                                 
2284                                                 /* test 2x2 stamp */
2285                                                 for( t = 0; t < 4; t++ )
2286                                                 {
2287                                                         /* set sample coords */
2288                                                         sx = x + tests[ t ][ 0 ];
2289                                                         sy = y + tests[ t ][ 1 ];
2290                                                         
2291                                                         /* get cluster */
2292                                                         cluster = SUPER_CLUSTER( sx, sy );
2293                                                         if( *cluster < 0 )
2294                                                                 continue;
2295                                                         mapped++;
2296                                                         
2297                                                         /* get luxel */
2298                                                         flag = SUPER_FLAG( sx, sy );
2299                                                         if(*flag & FLAG_FORCE_SUBSAMPLING)
2300                                                         {
2301                                                                 /* force a lighted/mapped discrepancy so we subsample */
2302                                                                 ++lighted;
2303                                                                 ++mapped;
2304                                                                 ++mapped;
2305                                                         }
2306                                                         lightLuxel = LIGHT_LUXEL( sx, sy );
2307                                                         VectorAdd( total, lightLuxel, total );
2308                                                         if( (lightLuxel[ 0 ] + lightLuxel[ 1 ] + lightLuxel[ 2 ]) > 0.0f )
2309                                                                 lighted++;
2310                                                 }
2311                                                 
2312                                                 /* if total color is under a certain amount, then don't bother subsampling */
2313                                                 if( total[ 0 ] <= 4.0f && total[ 1 ] <= 4.0f && total[ 2 ] <= 4.0f )
2314                                                         continue;
2315                                                 
2316                                                 /* if all 4 pixels are either in shadow or light, then don't subsample */
2317                                                 if( lighted != 0 && lighted != mapped )
2318                                                 {
2319                                                         for( t = 0; t < 4; t++ )
2320                                                         {
2321                                                                 /* set sample coords */
2322                                                                 sx = x + tests[ t ][ 0 ];
2323                                                                 sy = y + tests[ t ][ 1 ];
2324                                                                 
2325                                                                 /* get luxel */
2326                                                                 cluster = SUPER_CLUSTER( sx, sy );
2327                                                                 if( *cluster < 0 )
2328                                                                         continue;
2329                                                                 flag = SUPER_FLAG( sx, sy );
2330                                                                 if(*flag & FLAG_ALREADY_SUBSAMPLED) // already subsampled
2331                                                                         continue;
2332                                                                 lightLuxel = LIGHT_LUXEL( sx, sy );
2333                                                                 lightDeluxel = LIGHT_DELUXEL( sx, sy );
2334                                                                 origin = SUPER_ORIGIN( sx, sy );
2335                                                                 
2336                                                                 /* only subsample shadowed luxels */
2337                                                                 //%     if( (lightLuxel[ 0 ] + lightLuxel[ 1 ] + lightLuxel[ 2 ]) <= 0.0f )
2338                                                                 //%             continue;
2339                                                                 
2340                                                                 /* subsample it */
2341                                                                 if(lightRandomSamples)
2342                                                                         RandomSubsampleRawLuxel( lm, &trace, origin, sx, sy, 0.5f, lightLuxel, deluxemap ? lightDeluxel : NULL );
2343                                                                 else
2344                                                                         SubsampleRawLuxel_r( lm, &trace, origin, sx, sy, 0.25f * lightSamplesSearchBoxSize, lightLuxel, deluxemap ? lightDeluxel : NULL );
2345
2346                                                                 *flag |= FLAG_ALREADY_SUBSAMPLED;
2347                                                                 
2348                                                                 /* debug code to colorize subsampled areas to yellow */
2349                                                                 //%     luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2350                                                                 //%     VectorSet( luxel, 255, 204, 0 );
2351                                                         }
2352                                                 }
2353                                         }
2354                                 }
2355                         }
2356                         
2357                         /* tertiary pass, apply dirt map (ambient occlusion) */
2358                         if( 0 && dirty )
2359                         {
2360                                 /* walk luxels */
2361                                 for( y = 0; y < lm->sh; y++ )
2362                                 {
2363                                         for( x = 0; x < lm->sw; x++ )
2364                                         {
2365                                                 /* get cluster  */
2366                                                 cluster = SUPER_CLUSTER( x, y );
2367                                                 if( *cluster < 0 )
2368                                                         continue;
2369                                                 
2370                                                 /* get particulars */
2371                                                 lightLuxel = LIGHT_LUXEL( x, y );
2372                                                 dirt = SUPER_DIRT( x, y );
2373                                                 
2374                                                 /* scale light value */
2375                                                 VectorScale( lightLuxel, *dirt, lightLuxel );
2376                                         }
2377                                 }
2378                         }
2379                         
2380                         /* allocate sampling lightmap storage */
2381                         if( lm->superLuxels[ lightmapNum ] == NULL )
2382                         {
2383                                 /* allocate sampling lightmap storage */
2384                                 size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
2385                                 lm->superLuxels[ lightmapNum ] = safe_malloc( size );
2386                                 memset( lm->superLuxels[ lightmapNum ], 0, size );
2387                         }
2388
2389                         /* set style */
2390                         if( lightmapNum > 0 )
2391                         {
2392                                 lm->styles[ lightmapNum ] = trace.light->style;
2393                                 //%     Sys_Printf( "Surface %6d has lightstyle %d\n", rawLightmapNum, trace.light->style );
2394                         }
2395                         
2396                         /* copy to permanent luxels */
2397                         for( y = 0; y < lm->sh; y++ )
2398                         {
2399                                 for( x = 0; x < lm->sw; x++ )
2400                                 {
2401                                         /* get cluster and origin */
2402                                         cluster = SUPER_CLUSTER( x, y );
2403                                         if( *cluster < 0 )
2404                                                 continue;
2405                                         origin = SUPER_ORIGIN( x, y );
2406                                         
2407                                         /* filter? */
2408                                         if( luxelFilterRadius )
2409                                         {
2410                                                 /* setup */
2411                                                 VectorClear( averageColor );
2412                                                 VectorClear( averageDir );
2413                                                 samples = 0.0f;
2414                                                 
2415                                                 /* cheaper distance-based filtering */
2416                                                 for( sy = (y - luxelFilterRadius); sy <= (y + luxelFilterRadius); sy++ )
2417                                                 {
2418                                                         if( sy < 0 || sy >= lm->sh )
2419                                                                 continue;
2420                                                         
2421                                                         for( sx = (x - luxelFilterRadius); sx <= (x + luxelFilterRadius); sx++ )
2422                                                         {
2423                                                                 if( sx < 0 || sx >= lm->sw )
2424                                                                         continue;
2425                                                                 
2426                                                                 /* get particulars */
2427                                                                 cluster = SUPER_CLUSTER( sx, sy );
2428                                                                 if( *cluster < 0 )
2429                                                                         continue;
2430                                                                 lightLuxel = LIGHT_LUXEL( sx, sy );
2431                                                                 lightDeluxel = LIGHT_DELUXEL( sx, sy );
2432                                                                 
2433                                                                 /* create weight */
2434                                                                 weight = (abs( sx - x ) == luxelFilterRadius ? 0.5f : 1.0f);
2435                                                                 weight *= (abs( sy - y ) == luxelFilterRadius ? 0.5f : 1.0f);
2436                                                                 
2437                                                                 /* scale luxel by filter weight */
2438                                                                 VectorScale( lightLuxel, weight, color );
2439                                                                 VectorAdd( averageColor, color, averageColor );
2440                                                                 if(deluxemap)
2441                                                                 {
2442                                                                         VectorScale( lightDeluxel, weight, direction );
2443                                                                         VectorAdd( averageDir, direction, averageDir );
2444                                                                 }
2445                                                                 samples += weight;
2446                                                         }
2447                                                 }
2448                                                 
2449                                                 /* any samples? */
2450                                                 if( samples <= 0.0f     )
2451                                                         continue;
2452                                                 
2453                                                 /* scale into luxel */
2454                                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
2455                                                 luxel[ 3 ] = 1.0f;
2456                                                 
2457                                                 /* handle negative light */
2458                                                 if( trace.light->flags & LIGHT_NEGATIVE )
2459                                                 { 
2460                                                         luxel[ 0 ] -= averageColor[ 0 ] / samples;
2461                                                         luxel[ 1 ] -= averageColor[ 1 ] / samples;
2462                                                         luxel[ 2 ] -= averageColor[ 2 ] / samples;
2463                                                 }
2464                                                 
2465                                                 /* handle normal light */
2466                                                 else
2467                                                 { 
2468                                                         luxel[ 0 ] += averageColor[ 0 ] / samples;
2469                                                         luxel[ 1 ] += averageColor[ 1 ] / samples;
2470                                                         luxel[ 2 ] += averageColor[ 2 ] / samples;
2471                                                 }
2472                                                 
2473                                                 if(deluxemap)
2474                                                 {
2475                                                         /* scale into luxel */
2476                                                         deluxel = SUPER_DELUXEL( x, y );
2477                                                         deluxel[ 0 ] += averageDir[ 0 ] / samples;
2478                                                         deluxel[ 1 ] += averageDir[ 1 ] / samples;
2479                                                         deluxel[ 2 ] += averageDir[ 2 ] / samples;
2480                                                 }
2481                                         }
2482                                         
2483                                         /* single sample */
2484                                         else
2485                                         {
2486                                                 /* get particulars */
2487                                                 lightLuxel = LIGHT_LUXEL( x, y );
2488                                                 lightDeluxel = LIGHT_DELUXEL( x, y );
2489                                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
2490                                                 deluxel = SUPER_DELUXEL( x, y );
2491                                                 
2492                                                 /* handle negative light */
2493                                                 if( trace.light->flags & LIGHT_NEGATIVE )
2494                                                         VectorScale( averageColor, -1.0f, averageColor );
2495
2496                                                 /* add color */
2497                                                 luxel[ 3 ] = 1.0f;
2498                                                 
2499                                                 /* handle negative light */
2500                                                 if( trace.light->flags & LIGHT_NEGATIVE )
2501                                                         VectorSubtract( luxel, lightLuxel, luxel );
2502                                                 
2503                                                 /* handle normal light */
2504                                                 else
2505                                                         VectorAdd( luxel, lightLuxel, luxel );
2506
2507                                                 if(deluxemap)
2508                                                 {
2509                                                         VectorAdd( deluxel, lightDeluxel, deluxel );
2510                                                 }
2511                                         }
2512                                 }
2513                         }
2514                 }
2515                 
2516                 /* free temporary luxels */
2517                 if( lightLuxels != stackLightLuxels )
2518                         free( lightLuxels );
2519                 
2520                 if(deluxemap)
2521                         free( lightDeluxels );
2522         }
2523         
2524         /* free light list */
2525         FreeTraceLights( &trace );
2526         
2527         /* floodlight pass */
2528         if( floodlighty )
2529                 FloodlightIlluminateLightmap(lm);
2530
2531         if (debugnormals)
2532         {
2533                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2534                 {
2535                         /* early out */
2536                         if( lm->superLuxels[ lightmapNum ] == NULL )
2537                                 continue;
2538                         
2539                         for( y = 0; y < lm->sh; y++ )
2540                         {
2541                                 for( x = 0; x < lm->sw; x++ )
2542                                 {
2543                                         /* get cluster */
2544                                         cluster = SUPER_CLUSTER( x, y );
2545                                         //%     if( *cluster < 0 )
2546                                         //%             continue;
2547                                         
2548                                         /* get particulars */
2549                                         luxel = SUPER_LUXEL( lightmapNum, x, y );
2550                                         normal = SUPER_NORMAL (  x, y );
2551                
2552                                         luxel[0]=(normal[0]*127)+127;
2553                                         luxel[1]=(normal[1]*127)+127;
2554                                         luxel[2]=(normal[2]*127)+127;
2555                                 }
2556                         }
2557                 }
2558         }
2559         
2560         /*      -----------------------------------------------------------------
2561                 dirt pass
2562                 ----------------------------------------------------------------- */
2563         
2564         if( dirty )
2565         {
2566                 /* walk lightmaps */
2567                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2568                 {
2569                         /* early out */
2570                         if( lm->superLuxels[ lightmapNum ] == NULL )
2571                                 continue;
2572                         
2573                         /* apply dirt to each luxel */
2574                         for( y = 0; y < lm->sh; y++ )
2575                         {
2576                                 for( x = 0; x < lm->sw; x++ )
2577                                 {
2578                                         /* get cluster */
2579                                         cluster = SUPER_CLUSTER( x, y );
2580                                         //%     if( *cluster < 0 ) // TODO why not do this check? These pixels should be zero anyway
2581                                         //%             continue;
2582                                         
2583                                         /* get particulars */
2584                                         luxel = SUPER_LUXEL( lightmapNum, x, y );
2585                                         dirt = SUPER_DIRT( x, y );
2586                                         
2587                                         /* apply dirt */
2588                                         VectorScale( luxel, *dirt, luxel );
2589                                         
2590                                         /* debugging */
2591                                         if( dirtDebug )
2592                                                 VectorSet( luxel, *dirt * 255.0f, *dirt * 255.0f, *dirt * 255.0f );
2593                                 }
2594                         }
2595                 }
2596         }
2597         
2598         /* -----------------------------------------------------------------
2599            filter pass
2600            ----------------------------------------------------------------- */
2601         
2602         /* walk lightmaps */
2603         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2604         {
2605                 /* early out */
2606                 if( lm->superLuxels[ lightmapNum ] == NULL )
2607                         continue;
2608                 
2609                 /* average occluded luxels from neighbors */
2610                 for( y = 0; y < lm->sh; y++ )
2611                 {
2612                         for( x = 0; x < lm->sw; x++ )
2613                         {
2614                                 /* get particulars */
2615                                 cluster = SUPER_CLUSTER( x, y );
2616                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
2617                                 deluxel = SUPER_DELUXEL( x, y );
2618                                 normal = SUPER_NORMAL( x, y );
2619                                 
2620                                 /* determine if filtering is necessary */
2621                                 filterColor = qfalse;
2622                                 filterDir = qfalse;
2623                                 if( *cluster < 0 ||
2624                                         (lm->splotchFix && (luxel[ 0 ] <= ambientColor[ 0 ] || luxel[ 1 ] <= ambientColor[ 1 ] || luxel[ 2 ] <= ambientColor[ 2 ])) )
2625                                         filterColor = qtrue;
2626
2627                                 if( deluxemap && lightmapNum == 0 && (*cluster < 0 || filter) )
2628                                         filterDir = qtrue;
2629                                 
2630                                 if( !filterColor && !filterDir )
2631                                         continue;
2632                                 
2633                                 /* choose seed amount */
2634                                 VectorClear( averageColor );
2635                                 VectorClear( averageDir );
2636                                 samples = 0.0f;
2637                                 
2638                                 /* walk 3x3 matrix */
2639                                 for( sy = (y - 1); sy <= (y + 1); sy++ )
2640                                 {
2641                                         if( sy < 0 || sy >= lm->sh )
2642                                                 continue;
2643                                         
2644                                         for( sx = (x - 1); sx <= (x + 1); sx++ )
2645                                         {
2646                                                 if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
2647                                                         continue;
2648                                                 
2649                                                 /* get neighbor's particulars */
2650                                                 cluster2 = SUPER_CLUSTER( sx, sy );
2651                                                 luxel2 = SUPER_LUXEL( lightmapNum, sx, sy );
2652                                                 deluxel2 = SUPER_DELUXEL( sx, sy );
2653                                                 
2654                                                 /* ignore unmapped/unlit luxels */
2655                                                 if( *cluster2 < 0 || luxel2[ 3 ] == 0.0f ||
2656                                                         (lm->splotchFix && VectorCompare( luxel2, ambientColor )) )
2657                                                         continue;
2658                                                 
2659                                                 /* add its distinctiveness to our own */
2660                                                 VectorAdd( averageColor, luxel2, averageColor );
2661                                                 samples += luxel2[ 3 ];
2662                                                 if( filterDir )
2663                                                         VectorAdd( averageDir, deluxel2, averageDir );
2664                                         }
2665                                 }
2666                                 
2667                                 /* fall through */
2668                                 if( samples <= 0.0f )
2669                                         continue;
2670                                 
2671                                 /* dark lightmap seams */
2672                                 if( dark )
2673                                 {
2674                                         if( lightmapNum == 0 )
2675                                                 VectorMA( averageColor, 2.0f, ambientColor, averageColor );
2676                                         samples += 2.0f;
2677                                 }
2678                                 
2679                                 /* average it */
2680                                 if( filterColor )
2681                                 {
2682                                         VectorDivide( averageColor, samples, luxel );
2683                                         luxel[ 3 ] = 1.0f;
2684                                 }
2685                                 if( filterDir )
2686                                         VectorDivide( averageDir, samples, deluxel );
2687                                 
2688                                 /* set cluster to -3 */
2689                                 if( *cluster < 0 )
2690                                         *cluster = CLUSTER_FLOODED;
2691                         }
2692                 }
2693         }
2694
2695
2696 #if 0
2697         // audit pass
2698         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2699         {
2700                 /* early out */
2701                 if( lm->superLuxels[ lightmapNum ] == NULL )
2702                         continue;
2703                 for( y = 0; y < lm->sh; y++ )
2704                         for( x = 0; x < lm->sw; x++ )
2705                         {
2706                                 /* get cluster */
2707                                 cluster = SUPER_CLUSTER( x, y );
2708                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
2709                                 deluxel = SUPER_DELUXEL( x, y );
2710                                 if(!luxel || !deluxel || !cluster)
2711                                 {
2712                                         Sys_FPrintf(SYS_VRB, "WARNING: I got NULL'd.\n");
2713                                         continue;
2714                                 }
2715                                 else if(*cluster < 0)
2716                                 {
2717                                         // unmapped pixel
2718                                         // should have neither deluxemap nor lightmap
2719                                         if(deluxel[3])
2720                                                 Sys_FPrintf(SYS_VRB, "WARNING: I have written deluxe to an unmapped luxel. Sorry.\n");
2721                                 }
2722                                 else
2723                                 {
2724                                         // mapped pixel
2725                                         // should have both deluxemap and lightmap
2726                                         if(deluxel[3])
2727                                                 Sys_FPrintf(SYS_VRB, "WARNING: I forgot to write deluxe to a mapped luxel. Sorry.\n");
2728                                 }
2729                         }
2730         }
2731 #endif
2732 }
2733
2734
2735
2736 /*
2737 IlluminateVertexes()
2738 light the surface vertexes
2739 */
2740
2741 #define VERTEX_NUDGE    4.0f
2742
2743 void IlluminateVertexes( int num )
2744 {
2745         int                                     i, x, y, z, x1, y1, z1, sx, sy, radius, maxRadius, *cluster;
2746         int                                     lightmapNum, numAvg;
2747         float                           samples, *vertLuxel, *radVertLuxel, *luxel, dirt;
2748         vec3_t                          origin, temp, temp2, colors[ MAX_LIGHTMAPS ], avgColors[ MAX_LIGHTMAPS ];
2749         bspDrawSurface_t        *ds;
2750         surfaceInfo_t           *info;
2751         rawLightmap_t           *lm;
2752         bspDrawVert_t           *verts;
2753         trace_t                         trace;
2754         float                           floodLightAmount;
2755         vec3_t                          floodColor;
2756         
2757         
2758         /* get surface, info, and raw lightmap */
2759         ds = &bspDrawSurfaces[ num ];
2760         info = &surfaceInfos[ num ];
2761         lm = info->lm;
2762         
2763         /* -----------------------------------------------------------------
2764            illuminate the vertexes
2765            ----------------------------------------------------------------- */
2766         
2767         /* calculate vertex lighting for surfaces without lightmaps */
2768         if( lm == NULL || cpmaHack )
2769         {
2770                 /* setup trace */
2771                 trace.testOcclusion = (cpmaHack && lm != NULL) ? qfalse : !noTrace;
2772                 trace.forceSunlight = info->si->forceSunlight;
2773                 trace.recvShadows = info->recvShadows;
2774                 trace.numSurfaces = 1;
2775                 trace.surfaces = &num;
2776                 trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
2777                 
2778                 /* twosided lighting */
2779                 trace.twoSided = info->si->twoSided;
2780                 
2781                 /* make light list for this surface */
2782                 CreateTraceLightsForSurface( num, &trace );
2783                 
2784                 /* setup */
2785                 verts = yDrawVerts + ds->firstVert;
2786                 numAvg = 0;
2787                 memset( avgColors, 0, sizeof( avgColors ) );
2788                 
2789                 /* walk the surface verts */
2790                 for( i = 0; i < ds->numVerts; i++ )
2791                 {
2792                         /* get vertex luxel */
2793                         radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2794                         
2795                         /* color the luxel with raw lightmap num? */
2796                         if( debugSurfaces )
2797                                 VectorCopy( debugColors[ num % 12 ], radVertLuxel );
2798                         
2799                         /* color the luxel with luxel origin? */
2800                         else if( debugOrigin )
2801                         {
2802                                 VectorSubtract( info->maxs, info->mins, temp );
2803                                 VectorScale( temp, (1.0f / 255.0f), temp );
2804                                 VectorSubtract( origin, lm->mins, temp2 );
2805                                 radVertLuxel[ 0 ] = info->mins[ 0 ] + (temp[ 0 ] * temp2[ 0 ]);
2806                                 radVertLuxel[ 1 ] = info->mins[ 1 ] + (temp[ 1 ] * temp2[ 1 ]);
2807                                 radVertLuxel[ 2 ] = info->mins[ 2 ] + (temp[ 2 ] * temp2[ 2 ]);
2808                         }
2809                         
2810                         /* color the luxel with the normal */
2811                         else if( normalmap )
2812                         {
2813                                 radVertLuxel[ 0 ] = (verts[ i ].normal[ 0 ] + 1.0f) * 127.5f;
2814                                 radVertLuxel[ 1 ] = (verts[ i ].normal[ 1 ] + 1.0f) * 127.5f;
2815                                 radVertLuxel[ 2 ] = (verts[ i ].normal[ 2 ] + 1.0f) * 127.5f;
2816                         }
2817                         
2818                         /* illuminate the vertex */
2819                         else
2820                         {
2821                                 /* clear vertex luxel */
2822                                 VectorSet( radVertLuxel, -1.0f, -1.0f, -1.0f );
2823                                 
2824                                 /* try at initial origin */
2825                                 trace.cluster = ClusterForPointExtFilter( verts[ i ].xyz, VERTEX_EPSILON, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ] );
2826                                 if( trace.cluster >= 0 )
2827                                 {
2828                                         /* setup trace */
2829                                         VectorCopy( verts[ i ].xyz, trace.origin );
2830                                         VectorCopy( verts[ i ].normal, trace.normal );
2831                                         
2832                                         /* r7 dirt */
2833                                         if( dirty && !bouncing )
2834                                                 dirt = DirtForSample( &trace );
2835                                         else
2836                                                 dirt = 1.0f;
2837
2838                                         /* jal: floodlight */
2839                                         floodLightAmount = 0.0f;
2840                                         VectorClear( floodColor );
2841                                         if( floodlighty && !bouncing )
2842                                         {
2843                                                 floodLightAmount = floodlightIntensity * FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality );
2844                                                 VectorScale( floodlightRGB, floodLightAmount, floodColor );
2845                                         }
2846
2847                                         /* trace */
2848                                         LightingAtSample( &trace, ds->vertexStyles, colors );
2849                                         
2850                                         /* store */
2851                                         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2852                                         {
2853                                                 /* r7 dirt */
2854                                                 VectorScale( colors[ lightmapNum ], dirt, colors[ lightmapNum ] );
2855
2856                                                 /* jal: floodlight */
2857                                                 VectorAdd( colors[ lightmapNum ], floodColor, colors[ lightmapNum ] ); 
2858                                                 
2859                                                 /* store */
2860                                                 radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
2861                                                 VectorCopy( colors[ lightmapNum ], radVertLuxel );
2862                                                 VectorAdd( avgColors[ lightmapNum ], colors[ lightmapNum ], colors[ lightmapNum ] );
2863                                         }
2864                                 }
2865                                 
2866                                 /* is this sample bright enough? */
2867                                 radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2868                                 if( radVertLuxel[ 0 ] <= ambientColor[ 0 ] &&
2869                                         radVertLuxel[ 1 ] <= ambientColor[ 1 ] &&
2870                                         radVertLuxel[ 2 ] <= ambientColor[ 2 ] )
2871                                 {
2872                                         /* nudge the sample point around a bit */
2873                                         for( x = 0; x < 4; x++ )
2874                                         {
2875                                                 /* two's complement 0, 1, -1, 2, -2, etc */
2876                                                 x1 = ((x >> 1) ^ (x & 1 ? -1 : 0)) + (x & 1);
2877                                                 
2878                                                 for( y = 0; y < 4; y++ )
2879                                                 {
2880                                                         y1 = ((y >> 1) ^ (y & 1 ? -1 : 0)) + (y & 1);
2881                                                         
2882                                                         for( z = 0; z < 4; z++ )
2883                                                         {
2884                                                                 z1 = ((z >> 1) ^ (z & 1 ? -1 : 0)) + (z & 1);
2885                                                                 
2886                                                                 /* nudge origin */
2887                                                                 trace.origin[ 0 ] = verts[ i ].xyz[ 0 ] + (VERTEX_NUDGE * x1);
2888                                                                 trace.origin[ 1 ] = verts[ i ].xyz[ 1 ] + (VERTEX_NUDGE * y1);
2889                                                                 trace.origin[ 2 ] = verts[ i ].xyz[ 2 ] + (VERTEX_NUDGE * z1);
2890                                                                 
2891                                                                 /* try at nudged origin */
2892                                                                 trace.cluster = ClusterForPointExtFilter( origin, VERTEX_EPSILON, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ] );
2893                                                                 if( trace.cluster < 0 )
2894                                                                         continue;
2895                                                                                                                         
2896                                                                 /* trace */
2897                                                                 LightingAtSample( &trace, ds->vertexStyles, colors );
2898                                                                 
2899                                                                 /* store */
2900                                                                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2901                                                                 {
2902                                                                         /* r7 dirt */
2903                                                                         VectorScale( colors[ lightmapNum ], dirt, colors[ lightmapNum ] );
2904
2905                                                                         /* jal: floodlight */
2906                                                                         VectorAdd( colors[ lightmapNum ], floodColor, colors[ lightmapNum ] ); 
2907                                                                         
2908                                                                         /* store */
2909                                                                         radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
2910                                                                         VectorCopy( colors[ lightmapNum ], radVertLuxel );
2911                                                                 }
2912                                                                 
2913                                                                 /* bright enough? */
2914                                                                 radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2915                                                                 if( radVertLuxel[ 0 ] > ambientColor[ 0 ] ||
2916                                                                         radVertLuxel[ 1 ] > ambientColor[ 1 ] ||
2917                                                                         radVertLuxel[ 2 ] > ambientColor[ 2 ] )
2918                                                                         x = y = z = 1000;
2919                                                         }
2920                                                 }
2921                                         }
2922                                 }
2923                                 
2924                                 /* add to average? */
2925                                 radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2926                                 if( radVertLuxel[ 0 ] > ambientColor[ 0 ] ||
2927                                         radVertLuxel[ 1 ] > ambientColor[ 1 ] ||
2928                                         radVertLuxel[ 2 ] > ambientColor[ 2 ] )
2929                                 {
2930                                         numAvg++;
2931                                         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2932                                         {
2933                                                 radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
2934                                                 VectorAdd( avgColors[ lightmapNum ], radVertLuxel, avgColors[ lightmapNum ] );
2935                                         }
2936                                 }
2937                         }
2938                         
2939                         /* another happy customer */
2940                         numVertsIlluminated++;
2941                 }
2942                 
2943                 /* set average color */
2944                 if( numAvg > 0 )
2945                 {
2946                         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2947                                 VectorScale( avgColors[ lightmapNum ], (1.0f / numAvg), avgColors[ lightmapNum ] );
2948                 }
2949                 else
2950                 {
2951                         VectorCopy( ambientColor, avgColors[ 0 ] );
2952                 }
2953                 
2954                 /* clean up and store vertex color */
2955                 for( i = 0; i < ds->numVerts; i++ )
2956                 {
2957                         /* get vertex luxel */
2958                         radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2959                         
2960                         /* store average in occluded vertexes */
2961                         if( radVertLuxel[ 0 ] < 0.0f )
2962                         {
2963                                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2964                                 {
2965                                         radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
2966                                         VectorCopy( avgColors[ lightmapNum ], radVertLuxel );
2967                                         
2968                                         /* debug code */
2969                                         //%     VectorSet( radVertLuxel, 255.0f, 0.0f, 0.0f );
2970                                 }
2971                         }
2972                         
2973                         /* store it */
2974                         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2975                         {
2976                                 /* get luxels */
2977                                 vertLuxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
2978                                 radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
2979                                 
2980                                 /* store */
2981                                 if( bouncing || bounce == 0 || !bounceOnly )
2982                                         VectorAdd( vertLuxel, radVertLuxel, vertLuxel );
2983                                 if( !info->si->noVertexLight )
2984                                         ColorToBytes( vertLuxel, verts[ i ].color[ lightmapNum ], info->si->vertexScale );
2985                         }
2986                 }
2987                 
2988                 /* free light list */
2989                 FreeTraceLights( &trace );
2990                 
2991                 /* return to sender */
2992                 return;
2993         }
2994         
2995         /* -----------------------------------------------------------------
2996            reconstitute vertex lighting from the luxels
2997            ----------------------------------------------------------------- */
2998         
2999         /* set styles from lightmap */
3000         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3001                 ds->vertexStyles[ lightmapNum ] = lm->styles[ lightmapNum ];
3002         
3003         /* get max search radius */
3004         maxRadius = lm->sw;
3005         maxRadius = maxRadius > lm->sh ? maxRadius : lm->sh;
3006         
3007         /* walk the surface verts */
3008         verts = yDrawVerts + ds->firstVert;
3009         for( i = 0; i < ds->numVerts; i++ )
3010         {
3011                 /* do each lightmap */
3012                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3013                 {
3014                         /* early out */
3015                         if( lm->superLuxels[ lightmapNum ] == NULL )
3016                                 continue;
3017                         
3018                         /* get luxel coords */
3019                         x = verts[ i ].lightmap[ lightmapNum ][ 0 ];
3020                         y = verts[ i ].lightmap[ lightmapNum ][ 1 ];
3021                         if( x < 0 )
3022                                 x = 0;
3023                         else if( x >= lm->sw )
3024                                 x = lm->sw - 1;
3025                         if( y < 0 )
3026                                 y = 0;
3027                         else if( y >= lm->sh )
3028                                 y = lm->sh - 1;
3029                         
3030                         /* get vertex luxels */
3031                         vertLuxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
3032                         radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
3033                         
3034                         /* color the luxel with the normal? */
3035                         if( normalmap )
3036                         {
3037                                 radVertLuxel[ 0 ] = (verts[ i ].normal[ 0 ] + 1.0f) * 127.5f;
3038                                 radVertLuxel[ 1 ] = (verts[ i ].normal[ 1 ] + 1.0f) * 127.5f;
3039                                 radVertLuxel[ 2 ] = (verts[ i ].normal[ 2 ] + 1.0f) * 127.5f;
3040                         }
3041                         
3042                         /* color the luxel with surface num? */
3043                         else if( debugSurfaces )
3044                                 VectorCopy( debugColors[ num % 12 ], radVertLuxel );
3045                         
3046                         /* divine color from the superluxels */
3047                         else
3048                         {
3049                                 /* increasing radius */
3050                                 VectorClear( radVertLuxel );
3051                                 samples = 0.0f;
3052                                 for( radius = 0; radius < maxRadius && samples <= 0.0f; radius++ )
3053                                 {
3054                                         /* sample within radius */
3055                                         for( sy = (y - radius); sy <= (y + radius); sy++ )
3056                                         {
3057                                                 if( sy < 0 || sy >= lm->sh )
3058                                                         continue;
3059                                                 
3060                                                 for( sx = (x - radius); sx <= (x + radius); sx++ )
3061                                                 {
3062                                                         if( sx < 0 || sx >= lm->sw )
3063                                                                 continue;
3064                                                         
3065                                                         /* get luxel particulars */
3066                                                         luxel = SUPER_LUXEL( lightmapNum, sx, sy );
3067                                                         cluster = SUPER_CLUSTER( sx, sy );
3068                                                         if( *cluster < 0 )
3069                                                                 continue;
3070                                                         
3071                                                         /* testing: must be brigher than ambient color */
3072                                                         //%     if( luxel[ 0 ] <= ambientColor[ 0 ] || luxel[ 1 ] <= ambientColor[ 1 ] || luxel[ 2 ] <= ambientColor[ 2 ] )
3073                                                         //%             continue;
3074                                                         
3075                                                         /* add its distinctiveness to our own */
3076                                                         VectorAdd( radVertLuxel, luxel, radVertLuxel );
3077                                                         samples += luxel[ 3 ];
3078                                                 }
3079                                         }
3080                                 }
3081                                 
3082                                 /* any color? */
3083                                 if( samples > 0.0f )
3084                                         VectorDivide( radVertLuxel, samples, radVertLuxel );
3085                                 else
3086                                         VectorCopy( ambientColor, radVertLuxel );
3087                         }
3088                         
3089                         /* store into floating point storage */
3090                         VectorAdd( vertLuxel, radVertLuxel, vertLuxel );
3091                         numVertsIlluminated++;
3092                         
3093                         /* store into bytes (for vertex approximation) */
3094                         if( !info->si->noVertexLight )
3095                                 ColorToBytes( vertLuxel, verts[ i ].color[ lightmapNum ], 1.0f );
3096                 }
3097         }
3098 }
3099
3100
3101
3102 /* -------------------------------------------------------------------------------
3103
3104 light optimization (-fast)
3105
3106 creates a list of lights that will affect a surface and stores it in tw
3107 this is to optimize surface lighting by culling out as many of the
3108 lights in the world as possible from further calculation
3109
3110 ------------------------------------------------------------------------------- */
3111
3112 /*
3113 SetupBrushes()
3114 determines opaque brushes in the world and find sky shaders for sunlight calculations
3115 */
3116
3117 void SetupBrushes( void )
3118 {
3119         int                             i, j, b, compileFlags;
3120         qboolean                inside;
3121         bspBrush_t              *brush;
3122         bspBrushSide_t  *side;
3123         bspShader_t             *shader;
3124         shaderInfo_t    *si;
3125         
3126         
3127         /* note it */
3128         Sys_FPrintf( SYS_VRB, "--- SetupBrushes ---\n" );
3129         
3130         /* allocate */
3131         if( opaqueBrushes == NULL )
3132                 opaqueBrushes = safe_malloc( numBSPBrushes / 8 + 1 );
3133         
3134         /* clear */
3135         memset( opaqueBrushes, 0, numBSPBrushes / 8 + 1 );
3136         numOpaqueBrushes = 0;
3137         
3138         /* walk the list of worldspawn brushes */
3139         for( i = 0; i < bspModels[ 0 ].numBSPBrushes; i++ )
3140         {
3141                 /* get brush */
3142                 b = bspModels[ 0 ].firstBSPBrush + i;
3143                 brush = &bspBrushes[ b ];
3144                 
3145                 /* check all sides */
3146                 inside = qtrue;
3147                 compileFlags = 0;
3148                 for( j = 0; j < brush->numSides && inside; j++ )
3149                 {
3150                         /* do bsp shader calculations */
3151                         side = &bspBrushSides[ brush->firstSide + j ];
3152                         shader = &bspShaders[ side->shaderNum ];
3153                         
3154                         /* get shader info */
3155                         si = ShaderInfoForShader( shader->shader );
3156                         if( si == NULL )
3157                                 continue;
3158                         
3159                         /* or together compile flags */
3160                         compileFlags |= si->compileFlags;
3161                 }
3162                 
3163                 /* determine if this brush is opaque to light */
3164                 if( !(compileFlags & C_TRANSLUCENT) )
3165                 {
3166                         opaqueBrushes[ b >> 3 ] |= (1 << (b & 7));
3167                         numOpaqueBrushes++;
3168                         maxOpaqueBrush = i;
3169                 }
3170         }
3171         
3172         /* emit some statistics */
3173         Sys_FPrintf( SYS_VRB, "%9d opaque brushes\n", numOpaqueBrushes );
3174 }
3175
3176
3177
3178 /*
3179 ClusterVisible()
3180 determines if two clusters are visible to each other using the PVS
3181 */
3182
3183 qboolean ClusterVisible( int a, int b )
3184 {
3185         int                     portalClusters, leafBytes;
3186         byte            *pvs;
3187         
3188         
3189         /* dummy check */
3190         if( a < 0 || b < 0 )
3191                 return qfalse;
3192         
3193         /* early out */
3194         if( a == b )
3195                 return qtrue;
3196         
3197         /* not vised? */
3198         if( numBSPVisBytes <=8 )
3199                 return qtrue;
3200         
3201         /* get pvs data */
3202         portalClusters = ((int *) bspVisBytes)[ 0 ];
3203         leafBytes = ((int*) bspVisBytes)[ 1 ];
3204         pvs = bspVisBytes + VIS_HEADER_SIZE + (a * leafBytes);
3205         
3206         /* check */
3207         if( (pvs[ b >> 3 ] & (1 << (b & 7))) )
3208                 return qtrue;
3209         return qfalse;
3210 }
3211
3212
3213
3214 /*
3215 PointInLeafNum_r()
3216 borrowed from vlight.c
3217 */
3218
3219 int     PointInLeafNum_r( vec3_t point, int nodenum )
3220 {
3221         int                     leafnum;
3222         vec_t           dist;
3223         bspNode_t               *node;
3224         bspPlane_t      *plane;
3225         
3226         
3227         while( nodenum >= 0 )
3228         {
3229                 node = &bspNodes[ nodenum ];
3230                 plane = &bspPlanes[ node->planeNum ];
3231                 dist = DotProduct( point, plane->normal ) - plane->dist;
3232                 if( dist > 0.1 )
3233                         nodenum = node->children[ 0 ];
3234                 else if( dist < -0.1 )
3235                         nodenum = node->children[ 1 ];
3236                 else
3237                 {
3238                         leafnum = PointInLeafNum_r( point, node->children[ 0 ] );
3239                         if( bspLeafs[ leafnum ].cluster != -1 )
3240                                 return leafnum;
3241                         nodenum = node->children[ 1 ];
3242                 }
3243         }
3244         
3245         leafnum = -nodenum - 1;
3246         return leafnum;
3247 }
3248
3249
3250
3251 /*
3252 PointInLeafnum()
3253 borrowed from vlight.c
3254 */
3255
3256 int     PointInLeafNum( vec3_t point )
3257 {
3258         return PointInLeafNum_r( point, 0 );
3259 }
3260
3261
3262
3263 /*
3264 ClusterVisibleToPoint() - ydnar
3265 returns qtrue if point can "see" cluster
3266 */
3267
3268 qboolean ClusterVisibleToPoint( vec3_t point, int cluster )
3269 {
3270         int             pointCluster;
3271         
3272
3273         /* get leafNum for point */
3274         pointCluster = ClusterForPoint( point );
3275         if( pointCluster < 0 )
3276                 return qfalse;
3277         
3278         /* check pvs */
3279         return ClusterVisible( pointCluster, cluster );
3280 }
3281
3282
3283
3284 /*
3285 ClusterForPoint() - ydnar
3286 returns the pvs cluster for point
3287 */
3288
3289 int ClusterForPoint( vec3_t point )
3290 {
3291         int             leafNum;
3292         
3293
3294         /* get leafNum for point */
3295         leafNum = PointInLeafNum( point );
3296         if( leafNum < 0 )
3297                 return -1;
3298         
3299         /* return the cluster */
3300         return bspLeafs[ leafNum ].cluster;
3301 }
3302
3303
3304
3305 /*
3306 ClusterForPointExt() - ydnar
3307 also takes brushes into account for occlusion testing
3308 */
3309
3310 int ClusterForPointExt( vec3_t point, float epsilon )
3311 {
3312         int                             i, j, b, leafNum, cluster;
3313         float                   dot;
3314         qboolean                inside;
3315         int                             *brushes, numBSPBrushes;
3316         bspLeaf_t               *leaf;
3317         bspBrush_t              *brush;
3318         bspPlane_t              *plane;
3319         
3320         
3321         /* get leaf for point */
3322         leafNum = PointInLeafNum( point );
3323         if( leafNum < 0 )
3324                 return -1;
3325         leaf = &bspLeafs[ leafNum ];
3326         
3327         /* get the cluster */
3328         cluster = leaf->cluster;
3329         if( cluster < 0 )
3330                 return -1;
3331         
3332         /* transparent leaf, so check point against all brushes in the leaf */
3333         brushes = &bspLeafBrushes[ leaf->firstBSPLeafBrush ];
3334         numBSPBrushes = leaf->numBSPLeafBrushes;
3335         for( i = 0; i < numBSPBrushes; i++ )
3336         {
3337                 /* get parts */
3338                 b = brushes[ i ];
3339                 if( b > maxOpaqueBrush )
3340                         continue;
3341                 brush = &bspBrushes[ b ];
3342                 if( !(opaqueBrushes[ b >> 3 ] & (1 << (b & 7))) )
3343                         continue;
3344                 
3345                 /* check point against all planes */
3346                 inside = qtrue;
3347                 for( j = 0; j < brush->numSides && inside; j++ )
3348                 {
3349                         plane = &bspPlanes[ bspBrushSides[ brush->firstSide + j ].planeNum ];
3350                         dot = DotProduct( point, plane->normal );
3351                         dot -= plane->dist;
3352                         if( dot > epsilon )
3353                                 inside = qfalse;
3354                 }
3355                 
3356                 /* if inside, return bogus cluster */
3357                 if( inside )
3358                         return -1 - b;
3359         }
3360         
3361         /* if the point made it this far, it's not inside any opaque brushes */
3362         return cluster;
3363 }
3364
3365
3366
3367 /*
3368 ClusterForPointExtFilter() - ydnar
3369 adds cluster checking against a list of known valid clusters
3370 */
3371
3372 int ClusterForPointExtFilter( vec3_t point, float epsilon, int numClusters, int *clusters )
3373 {
3374         int             i, cluster;
3375         
3376         
3377         /* get cluster for point */
3378         cluster = ClusterForPointExt( point, epsilon );
3379         
3380         /* check if filtering is necessary */
3381         if( cluster < 0 || numClusters <= 0 || clusters == NULL )
3382                 return cluster;
3383         
3384         /* filter */
3385         for( i = 0; i < numClusters; i++ )
3386         {
3387                 if( cluster == clusters[ i ] || ClusterVisible( cluster, clusters[ i ] ) )
3388                         return cluster;
3389         }
3390         
3391         /* failed */
3392         return -1;
3393 }
3394
3395
3396
3397 /*
3398 ShaderForPointInLeaf() - ydnar
3399 checks a point against all brushes in a leaf, returning the shader of the brush
3400 also sets the cumulative surface and content flags for the brush hit
3401 */
3402
3403 int ShaderForPointInLeaf( vec3_t point, int leafNum, float epsilon, int wantContentFlags, int wantSurfaceFlags, int *contentFlags, int *surfaceFlags )
3404 {
3405         int                             i, j;
3406         float                   dot;
3407         qboolean                inside;
3408         int                             *brushes, numBSPBrushes;
3409         bspLeaf_t                       *leaf;
3410         bspBrush_t              *brush;
3411         bspBrushSide_t  *side;
3412         bspPlane_t              *plane;
3413         bspShader_t             *shader;
3414         int                             allSurfaceFlags, allContentFlags;
3415
3416         
3417         /* clear things out first */
3418         *surfaceFlags = 0;
3419         *contentFlags = 0;
3420         
3421         /* get leaf */
3422         if( leafNum < 0 )
3423                 return -1;
3424         leaf = &bspLeafs[ leafNum ];
3425         
3426         /* transparent leaf, so check point against all brushes in the leaf */
3427         brushes = &bspLeafBrushes[ leaf->firstBSPLeafBrush ];
3428         numBSPBrushes = leaf->numBSPLeafBrushes;
3429         for( i = 0; i < numBSPBrushes; i++ )
3430         {
3431                 /* get parts */
3432                 brush = &bspBrushes[ brushes[ i ] ];
3433                 
3434                 /* check point against all planes */
3435                 inside = qtrue;
3436                 allSurfaceFlags = 0;
3437                 allContentFlags = 0;
3438                 for( j = 0; j < brush->numSides && inside; j++ )
3439                 {
3440                         side = &bspBrushSides[ brush->firstSide + j ];
3441                         plane = &bspPlanes[ side->planeNum ];
3442                         dot = DotProduct( point, plane->normal );
3443                         dot -= plane->dist;
3444                         if( dot > epsilon )
3445                                 inside = qfalse;
3446                         else
3447                         {
3448                                 shader = &bspShaders[ side->shaderNum ];
3449                                 allSurfaceFlags |= shader->surfaceFlags;
3450                                 allContentFlags |= shader->contentFlags;
3451                         }
3452                 }
3453                 
3454                 /* handle if inside */
3455                 if( inside )
3456                 {
3457                         /* if there are desired flags, check for same and continue if they aren't matched */
3458                         if( wantContentFlags && !(wantContentFlags & allContentFlags) )
3459                                 continue;
3460                         if( wantSurfaceFlags && !(wantSurfaceFlags & allSurfaceFlags) )
3461                                 continue;
3462                         
3463                         /* store the cumulative flags and return the brush shader (which is mostly useless) */
3464                         *surfaceFlags = allSurfaceFlags;
3465                         *contentFlags = allContentFlags;
3466                         return brush->shaderNum;
3467                 }
3468         }
3469         
3470         /* if the point made it this far, it's not inside any brushes */
3471         return -1;
3472 }
3473
3474
3475
3476 /*
3477 ChopBounds()
3478 chops a bounding box by the plane defined by origin and normal
3479 returns qfalse if the bounds is entirely clipped away
3480
3481 this is not exactly the fastest way to do this...
3482 */
3483
3484 qboolean ChopBounds( vec3_t mins, vec3_t maxs, vec3_t origin, vec3_t normal )
3485 {
3486         /* FIXME: rewrite this so it doesn't use bloody brushes */
3487         return qtrue;
3488 }
3489
3490
3491
3492 /*
3493 SetupEnvelopes()
3494 calculates each light's effective envelope,
3495 taking into account brightness, type, and pvs.
3496 */
3497
3498 #define LIGHT_EPSILON   0.125f
3499 #define LIGHT_NUDGE             2.0f
3500
3501 void SetupEnvelopes( qboolean forGrid, qboolean fastFlag )
3502 {
3503         int                     i, x, y, z, x1, y1, z1;
3504         light_t         *light, *light2, **owner;
3505         bspLeaf_t       *leaf;
3506         vec3_t          origin, dir, mins, maxs, nullVector = { 0, 0, 0 };
3507         float           radius, intensity;
3508         light_t         *buckets[ 256 ];
3509         
3510         
3511         /* early out for weird cases where there are no lights */
3512         if( lights == NULL )
3513                 return;
3514         
3515         /* note it */
3516         Sys_FPrintf( SYS_VRB, "--- SetupEnvelopes%s ---\n", fastFlag ? " (fast)" : "" );
3517         
3518         /* count lights */
3519         numLights = 0;
3520         numCulledLights = 0;
3521         owner = &lights;
3522         while( *owner != NULL )
3523         {
3524                 /* get light */
3525                 light = *owner;
3526                 
3527                 /* handle negative lights */
3528                 if( light->photons < 0.0f || light->add < 0.0f )
3529                 {
3530                         light->photons *= -1.0f;
3531                         light->add *= -1.0f;
3532                         light->flags |= LIGHT_NEGATIVE;
3533                 }
3534                 
3535                 /* sunlight? */
3536                 if( light->type == EMIT_SUN )
3537                 {
3538                         /* special cased */
3539                         light->cluster = 0;
3540                         light->envelope = MAX_WORLD_COORD * 8.0f;
3541                         VectorSet( light->mins, MIN_WORLD_COORD * 8.0f, MIN_WORLD_COORD * 8.0f, MIN_WORLD_COORD * 8.0f );
3542                         VectorSet( light->maxs, MAX_WORLD_COORD * 8.0f, MAX_WORLD_COORD * 8.0f, MAX_WORLD_COORD * 8.0f );
3543                 }
3544                 
3545                 /* everything else */
3546                 else
3547                 {
3548                         /* get pvs cluster for light */
3549                         light->cluster = ClusterForPointExt( light->origin, LIGHT_EPSILON );
3550                         
3551                         /* invalid cluster? */
3552                         if( light->cluster < 0 )
3553                         {
3554                                 /* nudge the sample point around a bit */
3555                                 for( x = 0; x < 4; x++ )
3556                                 {
3557                                         /* two's complement 0, 1, -1, 2, -2, etc */
3558                                         x1 = ((x >> 1) ^ (x & 1 ? -1 : 0)) + (x & 1);
3559                                         
3560                                         for( y = 0; y < 4; y++ )
3561                                         {
3562                                                 y1 = ((y >> 1) ^ (y & 1 ? -1 : 0)) + (y & 1);
3563                                                 
3564                                                 for( z = 0; z < 4; z++ )
3565                                                 {
3566                                                         z1 = ((z >> 1) ^ (z & 1 ? -1 : 0)) + (z & 1);
3567                                                         
3568                                                         /* nudge origin */
3569                                                         origin[ 0 ] = light->origin[ 0 ] + (LIGHT_NUDGE * x1);
3570                                                         origin[ 1 ] = light->origin[ 1 ] + (LIGHT_NUDGE * y1);
3571                                                         origin[ 2 ] = light->origin[ 2 ] + (LIGHT_NUDGE * z1);
3572                                                         
3573                                                         /* try at nudged origin */
3574                                                         light->cluster = ClusterForPointExt( origin, LIGHT_EPSILON );
3575                                                         if( light->cluster < 0 )
3576                                                                 continue;
3577                                                                         
3578                                                         /* set origin */
3579                                                         VectorCopy( origin, light->origin );
3580                                                 }
3581                                         }
3582                                 }
3583                         }
3584                         
3585                         /* only calculate for lights in pvs and outside of opaque brushes */
3586                         if( light->cluster >= 0 )
3587                         {
3588                                 /* set light fast flag */
3589                                 if( fastFlag )
3590                                         light->flags |= LIGHT_FAST_TEMP;
3591                                 else
3592                                         light->flags &= ~LIGHT_FAST_TEMP;
3593                                 if( light->si && light->si->noFast )
3594                                         light->flags &= ~(LIGHT_FAST | LIGHT_FAST_TEMP);
3595                                 
3596                                 /* clear light envelope */
3597                                 light->envelope = 0;
3598                                 
3599                                 /* handle area lights */
3600                                 if( exactPointToPolygon && light->type == EMIT_AREA && light->w != NULL )
3601                                 {
3602                                         /* ugly hack to calculate extent for area lights, but only done once */
3603                                         VectorScale( light->normal, -1.0f, dir );
3604                                         for( radius = 100.0f; radius < 130000.0f && light->envelope == 0; radius += 10.0f )
3605                                         {
3606                                                 float   factor;
3607                                                 
3608                                                 VectorMA( light->origin, radius, light->normal, origin );
3609                                                 factor = PointToPolygonFormFactor( origin, dir, light->w );
3610                                                 if( factor < 0.0f )
3611                                                         factor *= -1.0f;
3612                                                 if( (factor * light->add) <= light->falloffTolerance )
3613                                                         light->envelope = radius;
3614                                         }
3615                                         
3616                                         /* check for fast mode */
3617                                         if( !(light->flags & LIGHT_FAST) && !(light->flags & LIGHT_FAST_TEMP) )
3618                                                 light->envelope = MAX_WORLD_COORD * 8.0f;
3619                                 }
3620                                 else
3621                                 {
3622                                         radius = 0.0f;
3623                                         intensity = light->photons;
3624                                 }
3625                                 
3626                                 /* other calcs */
3627                                 if( light->envelope <= 0.0f )
3628                                 {
3629                                         /* solve distance for non-distance lights */
3630                                         if( !(light->flags & LIGHT_ATTEN_DISTANCE) )
3631                                                 light->envelope = MAX_WORLD_COORD * 8.0f;
3632                                         
3633                                         /* solve distance for linear lights */
3634                                         else if( (light->flags & LIGHT_ATTEN_LINEAR ) )
3635                                                 //% light->envelope = ((intensity / light->falloffTolerance) * linearScale - 1 + radius) / light->fade;
3636                                                 light->envelope = ((intensity * linearScale) - light->falloffTolerance) / light->fade;
3637
3638                                                 /*
3639                                                 add = angle * light->photons * linearScale - (dist * light->fade);
3640                                                 T = (light->photons * linearScale) - (dist * light->fade);
3641                                                 T + (dist * light->fade) = (light->photons * linearScale);
3642                                                 dist * light->fade = (light->photons * linearScale) - T;
3643                                                 dist = ((light->photons * linearScale) - T) / light->fade;
3644                                                 */
3645                                         
3646                                         /* solve for inverse square falloff */
3647                                         else
3648                                                 light->envelope = sqrt( intensity / light->falloffTolerance ) + radius;
3649                                                 
3650                                                 /*
3651                                                 add = light->photons / (dist * dist);
3652                                                 T = light->photons / (dist * dist);
3653                                                 T * (dist * dist) = light->photons;
3654                                                 dist = sqrt( light->photons / T );
3655                                                 */
3656                                 }
3657                                 
3658                                 /* chop radius against pvs */
3659                                 {
3660                                         /* clear bounds */
3661                                         ClearBounds( mins, maxs );
3662                                         
3663                                         /* check all leaves */
3664                                         for( i = 0; i < numBSPLeafs; i++ )
3665                                         {
3666                                                 /* get test leaf */
3667                                                 leaf = &bspLeafs[ i ];
3668                                                 
3669                                                 /* in pvs? */
3670                                                 if( leaf->cluster < 0 )
3671                                                         continue;
3672                                                 if( ClusterVisible( light->cluster, leaf->cluster ) == qfalse ) /* ydnar: thanks Arnout for exposing my stupid error (this never failed before) */
3673                                                         continue;
3674                                                 
3675                                                 /* add this leafs bbox to the bounds */
3676                                                 VectorCopy( leaf->mins, origin );
3677                                                 AddPointToBounds( origin, mins, maxs );
3678                                                 VectorCopy( leaf->maxs, origin );
3679                                                 AddPointToBounds( origin, mins, maxs );
3680                                         }
3681                                         
3682                                         /* test to see if bounds encompass light */
3683                                         for( i = 0; i < 3; i++ )
3684                                         {
3685                                                 if( mins[ i ] > light->origin[ i ] || maxs[ i ] < light->origin[ i ] )
3686                                                 {
3687                                                         //% Sys_Printf( "WARNING: Light PVS bounds (%.0f, %.0f, %.0f) -> (%.0f, %.0f, %.0f)\ndo not encompass light %d (%f, %f, %f)\n",
3688                                                         //%     mins[ 0 ], mins[ 1 ], mins[ 2 ],
3689                                                         //%     maxs[ 0 ], maxs[ 1 ], maxs[ 2 ],
3690                                                         //%     numLights, light->origin[ 0 ], light->origin[ 1 ], light->origin[ 2 ] );
3691                                                         AddPointToBounds( light->origin, mins, maxs );
3692                                                 }
3693                                         }
3694                                         
3695                                         /* chop the bounds by a plane for area lights and spotlights */
3696                                         if( light->type == EMIT_AREA || light->type == EMIT_SPOT )
3697                                                 ChopBounds( mins, maxs, light->origin, light->normal );
3698                                         
3699                                         /* copy bounds */
3700                                         VectorCopy( mins, light->mins );
3701                                         VectorCopy( maxs, light->maxs );
3702                                         
3703                                         /* reflect bounds around light origin */
3704                                         //%     VectorMA( light->origin, -1.0f, origin, origin );
3705                                         VectorScale( light->origin, 2, origin );
3706                                         VectorSubtract( origin, maxs, origin );
3707                                         AddPointToBounds( origin, mins, maxs );
3708                                         //%     VectorMA( light->origin, -1.0f, mins, origin );
3709                                         VectorScale( light->origin, 2, origin );
3710                                         VectorSubtract( origin, mins, origin );
3711                                         AddPointToBounds( origin, mins, maxs );
3712                                          
3713                                         /* calculate spherical bounds */
3714                                         VectorSubtract( maxs, light->origin, dir );
3715                                         radius = (float) VectorLength( dir );
3716                                         
3717                                         /* if this radius is smaller than the envelope, then set the envelope to it */
3718                                         if( radius < light->envelope )
3719                                         {
3720                                                 light->envelope = radius;
3721                                                 //%     Sys_FPrintf( SYS_VRB, "PVS Cull (%d): culled\n", numLights );
3722                                         }
3723                                         //%     else
3724                                         //%             Sys_FPrintf( SYS_VRB, "PVS Cull (%d): failed (%8.0f > %8.0f)\n", numLights, radius, light->envelope );
3725                                 }
3726                                 
3727                                 /* add grid/surface only check */
3728                                 if( forGrid )
3729                                 {
3730                                         if( !(light->flags & LIGHT_GRID) )
3731                                                 light->envelope = 0.0f;
3732                                 }
3733                                 else
3734                                 {
3735                                         if( !(light->flags & LIGHT_SURFACES) )
3736                                                 light->envelope = 0.0f;
3737                                 }
3738                         }
3739                         
3740                         /* culled? */
3741                         if( light->cluster < 0 || light->envelope <= 0.0f )
3742                         {
3743                                 /* debug code */
3744                                 //%     Sys_Printf( "Culling light: Cluster: %d Envelope: %f\n", light->cluster, light->envelope );
3745                                 
3746                                 /* delete the light */
3747                                 numCulledLights++;
3748                                 *owner = light->next;
3749                                 if( light->w != NULL )
3750                                         free( light->w );
3751                                 free( light );
3752                                 continue;
3753                         }
3754                 }
3755                 
3756                 /* square envelope */
3757                 light->envelope2 = (light->envelope * light->envelope);
3758                 
3759                 /* increment light count */
3760                 numLights++;
3761                 
3762                 /* set next light */
3763                 owner = &((**owner).next);
3764         }
3765         
3766         /* bucket sort lights by style */
3767         memset( buckets, 0, sizeof( buckets ) );
3768         light2 = NULL;
3769         for( light = lights; light != NULL; light = light2 )
3770         {
3771                 /* get next light */
3772                 light2 = light->next;
3773                 
3774                 /* filter into correct bucket */
3775                 light->next = buckets[ light->style ];
3776                 buckets[ light->style ] = light;
3777                 
3778                 /* if any styled light is present, automatically set nocollapse */
3779                 if( light->style != LS_NORMAL )
3780                         noCollapse = qtrue;
3781         }
3782         
3783         /* filter back into light list */
3784         lights = NULL;
3785         for( i = 255; i >= 0; i-- )
3786         {
3787                 light2 = NULL;
3788                 for( light = buckets[ i ]; light != NULL; light = light2 )
3789                 {
3790                         light2 = light->next;
3791                         light->next = lights;
3792                         lights = light;
3793                 }
3794         }
3795         
3796         /* emit some statistics */
3797         Sys_Printf( "%9d total lights\n", numLights );
3798         Sys_Printf( "%9d culled lights\n", numCulledLights );
3799 }
3800
3801
3802
3803 /*
3804 CreateTraceLightsForBounds()
3805 creates a list of lights that affect the given bounding box and pvs clusters (bsp leaves)
3806 */
3807
3808 void CreateTraceLightsForBounds( vec3_t mins, vec3_t maxs, vec3_t normal, int numClusters, int *clusters, int flags, trace_t *trace )
3809 {
3810         int                     i;
3811         light_t         *light;
3812         vec3_t          origin, dir, nullVector = { 0.0f, 0.0f, 0.0f };
3813         float           radius, dist, length;
3814         
3815         
3816         /* potential pre-setup  */
3817         if( numLights == 0 )
3818                 SetupEnvelopes( qfalse, fast );
3819         
3820         /* debug code */
3821         //% 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 ] );
3822         
3823         /* allocate the light list */
3824         trace->lights = safe_malloc( sizeof( light_t* ) * (numLights + 1) );
3825         trace->numLights = 0;
3826         
3827         /* calculate spherical bounds */
3828         VectorAdd( mins, maxs, origin );
3829         VectorScale( origin, 0.5f, origin );
3830         VectorSubtract( maxs, origin, dir );
3831         radius = (float) VectorLength( dir );
3832         
3833         /* get length of normal vector */
3834         if( normal != NULL )
3835                 length = VectorLength( normal );
3836         else
3837         {
3838                 normal = nullVector;
3839                 length = 0;
3840         }
3841         
3842         /* test each light and see if it reaches the sphere */
3843         /* note: the attenuation code MUST match LightingAtSample() */
3844         for( light = lights; light; light = light->next )
3845         {
3846                 /* check zero sized envelope */
3847                 if( light->envelope <= 0 )
3848                 {
3849                         lightsEnvelopeCulled++;
3850                         continue;
3851                 }
3852                 
3853                 /* check flags */
3854                 if( !(light->flags & flags) )
3855                         continue;
3856                 
3857                 /* sunlight skips all this nonsense */
3858                 if( light->type != EMIT_SUN )
3859                 {
3860                         /* sun only? */
3861                         if( sunOnly )
3862                                 continue;
3863                         
3864                         /* check against pvs cluster */
3865                         if( numClusters > 0 && clusters != NULL )
3866                         {
3867                                 for( i = 0; i < numClusters; i++ )
3868                                 {
3869                                         if( ClusterVisible( light->cluster, clusters[ i ] ) )
3870                                                 break;
3871                                 }
3872                                 
3873                                 /* fixme! */
3874                                 if( i == numClusters )
3875                                 {
3876                                         lightsClusterCulled++;
3877                                         continue;
3878                                 }
3879                         }
3880                         
3881                         /* if the light's bounding sphere intersects with the bounding sphere then this light needs to be tested */
3882                         VectorSubtract( light->origin, origin, dir );
3883                         dist = VectorLength( dir );
3884                         dist -= light->envelope;
3885                         dist -= radius;
3886                         if( dist > 0 )
3887                         {
3888                                 lightsEnvelopeCulled++;
3889                                 continue;
3890                         }
3891                         
3892                         /* check bounding box against light's pvs envelope (note: this code never eliminated any lights, so disabling it) */
3893                         #if 0
3894                         skip = qfalse;
3895                         for( i = 0; i < 3; i++ )
3896                         {
3897                                 if( mins[ i ] > light->maxs[ i ] || maxs[ i ] < light->mins[ i ] )
3898                                         skip = qtrue;
3899                         }
3900                         if( skip )
3901                         {
3902                                 lightsBoundsCulled++;
3903                                 continue;
3904                         }
3905                         #endif
3906                 }
3907                 
3908                 /* planar surfaces (except twosided surfaces) have a couple more checks */
3909                 if( length > 0.0f && trace->twoSided == qfalse )
3910                 {
3911                         /* lights coplanar with a surface won't light it */
3912                         if( !(light->flags & LIGHT_TWOSIDED) && DotProduct( light->normal, normal ) > 0.999f )
3913                         {
3914                                 lightsPlaneCulled++;
3915                                 continue;
3916                         }
3917                         
3918                         /* check to see if light is behind the plane */
3919                         if( DotProduct( light->origin, normal ) - DotProduct( origin, normal ) < -1.0f )
3920                         {
3921                                 lightsPlaneCulled++;
3922                                 continue;
3923                         }
3924                 }
3925                 
3926                 /* add this light */
3927                 trace->lights[ trace->numLights++ ] = light;
3928         }
3929         
3930         /* make last night null */
3931         trace->lights[ trace->numLights ] = NULL;
3932 }
3933
3934
3935
3936 void FreeTraceLights( trace_t *trace )
3937 {
3938         if( trace->lights != NULL )
3939                 free( trace->lights );
3940 }
3941
3942
3943
3944 /*
3945 CreateTraceLightsForSurface()
3946 creates a list of lights that can potentially affect a drawsurface
3947 */
3948
3949 void CreateTraceLightsForSurface( int num, trace_t *trace )
3950 {
3951         int                                     i;
3952         vec3_t                          mins, maxs, normal;
3953         bspDrawVert_t           *dv;
3954         bspDrawSurface_t        *ds;
3955         surfaceInfo_t           *info;
3956         
3957         
3958         /* dummy check */
3959         if( num < 0 )
3960                 return;
3961         
3962         /* get drawsurface and info */
3963         ds = &bspDrawSurfaces[ num ];
3964         info = &surfaceInfos[ num ];
3965         
3966         /* get the mins/maxs for the dsurf */
3967         ClearBounds( mins, maxs );
3968         VectorCopy( bspDrawVerts[ ds->firstVert ].normal, normal );
3969         for( i = 0; i < ds->numVerts; i++ )
3970         {
3971                 dv = &yDrawVerts[ ds->firstVert + i ];
3972                 AddPointToBounds( dv->xyz, mins, maxs );
3973                 if( !VectorCompare( dv->normal, normal ) )
3974                         VectorClear( normal );
3975         }
3976         
3977         /* create the lights for the bounding box */
3978         CreateTraceLightsForBounds( mins, maxs, normal, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ], LIGHT_SURFACES, trace );
3979 }
3980
3981 /////////////////////////////////////////////////////////////
3982
3983 #define FLOODLIGHT_CONE_ANGLE                   88      /* degrees */
3984 #define FLOODLIGHT_NUM_ANGLE_STEPS              16
3985 #define FLOODLIGHT_NUM_ELEVATION_STEPS  4
3986 #define FLOODLIGHT_NUM_VECTORS                  (FLOODLIGHT_NUM_ANGLE_STEPS * FLOODLIGHT_NUM_ELEVATION_STEPS)
3987
3988 static vec3_t   floodVectors[ FLOODLIGHT_NUM_VECTORS ];
3989 static int              numFloodVectors = 0;
3990
3991 void SetupFloodLight( void )
3992 {
3993         int             i, j;
3994         float   angle, elevation, angleStep, elevationStep;
3995         const char      *value;
3996         double v1,v2,v3,v4,v5;
3997
3998         /* note it */
3999         Sys_FPrintf( SYS_VRB, "--- SetupFloodLight ---\n" );
4000
4001         /* calculate angular steps */
4002         angleStep = DEG2RAD( 360.0f / FLOODLIGHT_NUM_ANGLE_STEPS );
4003         elevationStep = DEG2RAD( FLOODLIGHT_CONE_ANGLE / FLOODLIGHT_NUM_ELEVATION_STEPS );
4004
4005         /* iterate angle */
4006         angle = 0.0f;
4007         for( i = 0, angle = 0.0f; i < FLOODLIGHT_NUM_ANGLE_STEPS; i++, angle += angleStep )
4008         {
4009                 /* iterate elevation */
4010                 for( j = 0, elevation = elevationStep * 0.5f; j < FLOODLIGHT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep )
4011                 {
4012                         floodVectors[ numFloodVectors ][ 0 ] = sin( elevation ) * cos( angle );
4013                         floodVectors[ numFloodVectors ][ 1 ] = sin( elevation ) * sin( angle );
4014                         floodVectors[ numFloodVectors ][ 2 ] = cos( elevation );
4015                         numFloodVectors++;
4016                 }
4017         }
4018
4019         /* emit some statistics */
4020         Sys_FPrintf( SYS_VRB, "%9d numFloodVectors\n", numFloodVectors );
4021
4022       /* floodlight */
4023         value = ValueForKey( &entities[ 0 ], "_floodlight" );
4024
4025         if( value[ 0 ] != '\0' )
4026         {
4027                 v1=v2=v3=0;
4028                 v4=floodlightDistance;
4029                 v5=floodlightIntensity;
4030
4031                 sscanf( value, "%lf %lf %lf %lf %lf", &v1, &v2, &v3, &v4, &v5);
4032
4033                 floodlightRGB[0]=v1;
4034                 floodlightRGB[1]=v2;
4035                 floodlightRGB[2]=v3;
4036
4037                 if (VectorLength(floodlightRGB)==0)
4038                 {
4039                         VectorSet(floodlightRGB,240,240,255);
4040                 }
4041
4042                 if (v4<1) v4=1024;
4043                 if (v5<1) v5=128;
4044
4045                 floodlightDistance=v4;
4046                 floodlightIntensity=v5;
4047
4048                 floodlighty = qtrue;
4049                 Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
4050         }
4051         else
4052         {
4053                 VectorSet(floodlightRGB,240,240,255);
4054                 //floodlighty = qtrue;
4055                 //Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
4056         }
4057         VectorNormalize(floodlightRGB,floodlightRGB);
4058 }
4059
4060 /*
4061 FloodLightForSample()
4062 calculates floodlight value for a given sample
4063 once again, kudos to the dirtmapping coder
4064 */
4065
4066 float FloodLightForSample( trace_t *trace , float floodLightDistance, qboolean floodLightLowQuality)
4067 {
4068         int             i;
4069         float   d;
4070         float   contribution;
4071         int     sub = 0;
4072         float   gatherLight, outLight;
4073         vec3_t  normal, worldUp, myUp, myRt, direction, displacement;
4074         float   dd;
4075         int     vecs = 0;
4076  
4077         gatherLight=0;
4078         /* dummy check */
4079         //if( !dirty )
4080         //      return 1.0f;
4081         if( trace == NULL || trace->cluster < 0 )
4082                 return 0.0f;
4083         
4084
4085         /* setup */
4086         dd = floodLightDistance;
4087         VectorCopy( trace->normal, normal );
4088         
4089         /* check if the normal is aligned to the world-up */
4090         if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f && ( normal[ 2 ] == 1.0f || normal[ 2 ] == -1.0f ) )
4091         {
4092                 if( normal[ 2 ] == 1.0f )               
4093                 {
4094                         VectorSet( myRt, 1.0f, 0.0f, 0.0f );
4095                         VectorSet( myUp, 0.0f, 1.0f, 0.0f );
4096                 }
4097                 else if( normal[ 2 ] == -1.0f )
4098                 {
4099                         VectorSet( myRt, -1.0f, 0.0f, 0.0f );
4100                         VectorSet( myUp,  0.0f, 1.0f, 0.0f );
4101                 }
4102         }
4103         else
4104         {
4105                 VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
4106                 CrossProduct( normal, worldUp, myRt );
4107                 VectorNormalize( myRt, myRt );
4108                 CrossProduct( myRt, normal, myUp );
4109                 VectorNormalize( myUp, myUp );
4110         }
4111
4112         /* vortex: optimise floodLightLowQuality a bit */
4113         if ( floodLightLowQuality == qtrue )
4114     {
4115                 /* iterate through ordered vectors */
4116                 for( i = 0; i < numFloodVectors; i++ )
4117                         if (rand()%10 != 0 ) continue;
4118         }
4119         else
4120         {
4121                 /* iterate through ordered vectors */
4122                 for( i = 0; i < numFloodVectors; i++ )
4123                 {
4124                         vecs++;
4125                  
4126                         /* transform vector into tangent space */
4127                         direction[ 0 ] = myRt[ 0 ] * floodVectors[ i ][ 0 ] + myUp[ 0 ] * floodVectors[ i ][ 1 ] + normal[ 0 ] * floodVectors[ i ][ 2 ];
4128                         direction[ 1 ] = myRt[ 1 ] * floodVectors[ i ][ 0 ] + myUp[ 1 ] * floodVectors[ i ][ 1 ] + normal[ 1 ] * floodVectors[ i ][ 2 ];
4129                         direction[ 2 ] = myRt[ 2 ] * floodVectors[ i ][ 0 ] + myUp[ 2 ] * floodVectors[ i ][ 1 ] + normal[ 2 ] * floodVectors[ i ][ 2 ];
4130
4131                         /* set endpoint */
4132                         VectorMA( trace->origin, dd, direction, trace->end );
4133
4134                         //VectorMA( trace->origin, 1, direction, trace->origin );
4135                                 
4136                         SetupTrace( trace );
4137                         /* trace */
4138                         TraceLine( trace );
4139                         contribution=1;
4140
4141                         if (trace->compileFlags & C_SKY )
4142                         {
4143                                 contribution=1.0f;
4144                         }
4145                         else if ( trace->opaque )
4146                         {
4147                                 VectorSubtract( trace->hit, trace->origin, displacement );
4148                                 d=VectorLength( displacement );
4149
4150                                 // d=trace->distance;            
4151                                 //if (d>256) gatherDirt+=1;
4152                                 contribution=d/dd;
4153                                 if (contribution>1) contribution=1.0f; 
4154                      
4155                                 //gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
4156                         }
4157                  
4158                         gatherLight+=contribution;
4159                 }
4160         }
4161    
4162         /* early out */
4163         if( gatherLight <= 0.0f )
4164                 return 0.0f;
4165         
4166         sub=vecs;
4167
4168         if (sub<1) sub=1;
4169         gatherLight/=(sub);
4170
4171         outLight=gatherLight;
4172         if( outLight > 1.0f )
4173                 outLight = 1.0f;
4174         
4175         /* return to sender */
4176         return outLight;
4177 }
4178
4179 /*
4180 FloodLightRawLightmap
4181 lighttracer style ambient occlusion light hack.
4182 Kudos to the dirtmapping author for most of this source.
4183 VorteX: modified to floodlight up custom surfaces (q3map_floodLight)
4184 VorteX: fixed problems with deluxemapping
4185 */
4186
4187 // floodlight pass on a lightmap
4188 void FloodLightRawLightmapPass( rawLightmap_t *lm , vec3_t lmFloodLightRGB, float lmFloodLightIntensity, float lmFloodLightDistance, qboolean lmFloodLightLowQuality, float floodlightDirectionScale)
4189 {
4190         int                                     i, x, y, *cluster;
4191         float                           *origin, *normal, *floodlight, floodLightAmount;
4192         surfaceInfo_t           *info;
4193         trace_t                         trace;
4194         // int sx, sy;
4195         // float samples, average, *floodlight2;
4196         
4197         memset(&trace,0,sizeof(trace_t));
4198
4199         /* setup trace */
4200         trace.testOcclusion = qtrue;
4201         trace.forceSunlight = qfalse;
4202         trace.twoSided = qtrue;
4203         trace.recvShadows = lm->recvShadows;
4204         trace.numSurfaces = lm->numLightSurfaces;
4205         trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
4206         trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
4207         trace.testAll = qfalse;
4208         trace.distance = 1024;
4209         
4210         /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
4211         //trace.twoSided = qfalse;
4212         for( i = 0; i < trace.numSurfaces; i++ )
4213         {
4214                 /* get surface */
4215                 info = &surfaceInfos[ trace.surfaces[ i ] ];
4216                 
4217                 /* check twosidedness */
4218                 if( info->si->twoSided )
4219                 {
4220                         trace.twoSided = qtrue;
4221                         break;
4222                 }
4223         }
4224         
4225         /* gather floodlight */
4226         for( y = 0; y < lm->sh; y++ )
4227         {
4228                 for( x = 0; x < lm->sw; x++ )
4229                 {
4230                         /* get luxel */
4231                         cluster = SUPER_CLUSTER( x, y );
4232                         origin = SUPER_ORIGIN( x, y );
4233                         normal = SUPER_NORMAL( x, y );
4234                         floodlight = SUPER_FLOODLIGHT( x, y );
4235                         
4236                         /* set default dirt */
4237                         *floodlight = 0.0f;
4238                         
4239                         /* only look at mapped luxels */
4240                         if( *cluster < 0 )
4241                                 continue;
4242                         
4243                         /* copy to trace */
4244                         trace.cluster = *cluster;
4245                         VectorCopy( origin, trace.origin );
4246                         VectorCopy( normal, trace.normal );
4247    
4248                         /* get floodlight */
4249                         floodLightAmount = FloodLightForSample( &trace , lmFloodLightDistance, lmFloodLightLowQuality)*lmFloodLightIntensity;
4250                         
4251                         /* add floodlight */
4252                         floodlight[0] += lmFloodLightRGB[0]*floodLightAmount;
4253                         floodlight[1] += lmFloodLightRGB[1]*floodLightAmount;
4254                         floodlight[2] += lmFloodLightRGB[2]*floodLightAmount;
4255                         floodlight[3] += floodlightDirectionScale;
4256                 }
4257         }
4258         
4259         /* testing no filtering */
4260         return;
4261
4262 #if 0
4263         
4264         /* filter "dirt" */
4265         for( y = 0; y < lm->sh; y++ )
4266         {
4267                 for( x = 0; x < lm->sw; x++ )
4268                 {
4269                         /* get luxel */
4270                         cluster = SUPER_CLUSTER( x, y );
4271                         floodlight = SUPER_FLOODLIGHT(x, y );
4272                         
4273                         /* filter dirt by adjacency to unmapped luxels */
4274                         average = *floodlight;
4275                         samples = 1.0f;
4276                         for( sy = (y - 1); sy <= (y + 1); sy++ )
4277                         {
4278                                 if( sy < 0 || sy >= lm->sh )
4279                                         continue;
4280                                 
4281                                 for( sx = (x - 1); sx <= (x + 1); sx++ )
4282                                 {
4283                                         if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
4284                                                 continue;
4285                                         
4286                                         /* get neighboring luxel */
4287                                         cluster = SUPER_CLUSTER( sx, sy );
4288                                         floodlight2 = SUPER_FLOODLIGHT( sx, sy );
4289                                         if( *cluster < 0 || *floodlight2 <= 0.0f )
4290                                                 continue;
4291                                         
4292                                         /* add it */
4293                                         average += *floodlight2;
4294                                         samples += 1.0f;
4295                                 }
4296                                 
4297                                 /* bail */
4298                                 if( samples <= 0.0f )
4299                                         break;
4300                         }
4301                         
4302                         /* bail */
4303                         if( samples <= 0.0f )
4304                                 continue;
4305                         
4306                         /* scale dirt */
4307                         *floodlight = average / samples;
4308                 }
4309         }
4310 #endif
4311 }
4312
4313 void FloodLightRawLightmap( int rawLightmapNum )
4314 {
4315         rawLightmap_t           *lm;
4316
4317         /* bail if this number exceeds the number of raw lightmaps */
4318         if( rawLightmapNum >= numRawLightmaps )
4319                 return;
4320         /* get lightmap */
4321         lm = &rawLightmaps[ rawLightmapNum ];
4322
4323         /* global pass */
4324         if (floodlighty && floodlightIntensity)
4325                 FloodLightRawLightmapPass(lm, floodlightRGB, floodlightIntensity, floodlightDistance, floodlight_lowquality, 1.0f);
4326
4327         /* custom pass */
4328         if (lm->floodlightIntensity)
4329         {
4330                 FloodLightRawLightmapPass(lm, lm->floodlightRGB, lm->floodlightIntensity, lm->floodlightDistance, qfalse, lm->floodlightDirectionScale);
4331                 numSurfacesFloodlighten += 1;
4332         }
4333 }
4334
4335 void FloodlightRawLightmaps()
4336 {
4337         Sys_Printf( "--- FloodlightRawLightmap ---\n" );
4338         numSurfacesFloodlighten = 0;
4339         RunThreadsOnIndividual( numRawLightmaps, qtrue, FloodLightRawLightmap );
4340         Sys_Printf( "%9d custom lightmaps floodlighted\n", numSurfacesFloodlighten );
4341 }
4342
4343 /*
4344 FloodLightIlluminate()
4345 illuminate floodlight into lightmap luxels
4346 */
4347
4348 void FloodlightIlluminateLightmap( rawLightmap_t *lm )
4349 {
4350         float                           *luxel, *floodlight, *deluxel, *normal;
4351         int                                     *cluster;
4352         float                           brightness;
4353         int                                     x, y, lightmapNum;
4354
4355         /* walk lightmaps */
4356         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
4357         {
4358                 /* early out */
4359                 if( lm->superLuxels[ lightmapNum ] == NULL )
4360                         continue;
4361
4362                 /* apply floodlight to each luxel */
4363                 for( y = 0; y < lm->sh; y++ )
4364                 {
4365                         for( x = 0; x < lm->sw; x++ )
4366                         {
4367                                 /* get floodlight */
4368                                 floodlight = SUPER_FLOODLIGHT( x, y );
4369                                 if (!floodlight[0] && !floodlight[1] && !floodlight[2])
4370                                         continue;
4371                                                 
4372                                 /* get cluster */
4373                                 cluster = SUPER_CLUSTER( x, y );
4374
4375                                 /* only process mapped luxels */
4376                                 if( *cluster < 0 )
4377                                         continue;
4378
4379                                 /* get particulars */
4380                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
4381                                 deluxel = SUPER_DELUXEL( x, y );
4382
4383                                 /* add to lightmap */
4384                                 luxel[0]+=floodlight[0];
4385                                 luxel[1]+=floodlight[1];
4386                                 luxel[2]+=floodlight[2];
4387
4388                                 if (luxel[3]==0) luxel[3]=1;
4389
4390                                 /* add to deluxemap */
4391                                 if (deluxemap && floodlight[3] > 0)
4392                                 {
4393                                         vec3_t                          lightvector;
4394
4395                                         normal = SUPER_NORMAL( x, y );
4396                                         brightness = RGBTOGRAY( floodlight ) * ( 1.0f/255.0f ) * floodlight[3];
4397
4398                                         // use AT LEAST this amount of contribution from ambient for the deluxemap, fixes points that receive ZERO light
4399                                         if(brightness < 0.00390625f)
4400                                                 brightness = 0.00390625f;
4401
4402                                         VectorScale( normal, brightness, lightvector );
4403                                         VectorAdd( deluxel, lightvector, deluxel );
4404                                 }
4405                         }
4406                 }
4407         }
4408 }