add option -nofastpoint; make old buggy behaviour default as it is typically a lot...
[xonotic/netradiant.git] / tools / quake3 / q3map2 / light_ydnar.c
1 /* -------------------------------------------------------------------------------
2
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
5
6 This file is part of GtkRadiant.
7
8 GtkRadiant is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 GtkRadiant is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GtkRadiant; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21
22 ----------------------------------------------------------------------------------
23
24 This code has been altered significantly from its original form, to support
25 several games based on the Quake III Arena engine, in the form of "Q3Map2."
26
27 ------------------------------------------------------------------------------- */
28
29
30
31 /* marker */
32 #define LIGHT_YDNAR_C
33
34
35
36 /* dependencies */
37 #include "q3map2.h"
38
39
40
41
42 /*
43 ColorToBytes()
44 ydnar: moved to here 2001-02-04
45 */
46
47 void ColorToBytes( const float *color, byte *colorBytes, float scale )
48 {
49         int             i;
50         float   max, gamma;
51         vec3_t  sample;
52         float   inv, dif;
53         
54         
55         /* ydnar: scaling necessary for simulating r_overbrightBits on external lightmaps */
56         if( scale <= 0.0f )
57                 scale = 1.0f;
58         
59         /* make a local copy */
60         VectorScale( color, scale, sample );
61         
62         /* muck with it */
63         gamma = 1.0f / lightmapGamma;
64         for( i = 0; i < 3; i++ )
65         {
66                 /* handle negative light */
67                 if( sample[ i ] < 0.0f )
68                 {
69                         sample[ i ] = 0.0f;
70                         continue;
71                 }
72                 
73                 /* gamma */
74                 sample[ i ] = pow( sample[ i ] / 255.0f, gamma ) * 255.0f;
75         }
76
77         if (lightmapExposure == 0)
78         {
79                 /* clamp with color normalization */
80                 max = sample[ 0 ];
81                 if( sample[ 1 ] > max )
82                         max = sample[ 1 ];
83                 if( sample[ 2 ] > max )
84                         max = sample[ 2 ];
85                 if( max > 255.0f )
86                         VectorScale( sample, (255.0f / max), sample );
87         }
88         else
89         {
90                 inv=1.f/lightmapExposure;
91                 //Exposure
92
93                 max = sample[ 0 ];
94                 if( sample[ 1 ] > max )
95                         max = sample[ 1 ];
96                 if( sample[ 2 ] > max )
97                         max = sample[ 2 ];
98
99                 dif = (1-  exp(-max * inv) )  *  255;
100
101                 if (max >0)
102                 {
103                         dif = dif / max;
104                 }
105                 else
106                 {
107                         dif = 0;
108                 }
109
110                 for (i=0;i<3;i++)
111                 {
112                         sample[i]*=dif;
113                 }
114         }
115
116         
117         /* compensate for ingame overbrighting/bitshifting */
118         VectorScale( sample, (1.0f / lightmapCompensate), sample );
119
120         /* sRGB lightmaps */
121         if(lightmapsRGB)
122         {
123                 sample[0] = floor(Image_sRGBFloatFromLinearFloat(sample[0] * (1.0 / 255.0)) * 255.0 + 0.5);
124                 sample[1] = floor(Image_sRGBFloatFromLinearFloat(sample[1] * (1.0 / 255.0)) * 255.0 + 0.5);
125                 sample[2] = floor(Image_sRGBFloatFromLinearFloat(sample[2] * (1.0 / 255.0)) * 255.0 + 0.5);
126         }
127         
128         /* store it off */
129         colorBytes[ 0 ] = sample[ 0 ];
130         colorBytes[ 1 ] = sample[ 1 ];
131         colorBytes[ 2 ] = sample[ 2 ];
132 }
133
134
135
136 /* -------------------------------------------------------------------------------
137
138 this section deals with phong shading (normal interpolation across brush faces)
139
140 ------------------------------------------------------------------------------- */
141
142 /*
143 SmoothNormals()
144 smooths together coincident vertex normals across the bsp
145 */
146
147 #define MAX_SAMPLES                             256
148 #define THETA_EPSILON                   0.000001
149 #define EQUAL_NORMAL_EPSILON    0.01
150
151 void SmoothNormals( void )
152 {
153         int                                     i, j, k, f, cs, numVerts, numVotes, fOld, start;
154         float                           shadeAngle, defaultShadeAngle, maxShadeAngle, dot, testAngle;
155         bspDrawSurface_t        *ds;
156         shaderInfo_t            *si;
157         float                           *shadeAngles;
158         byte                            *smoothed;
159         vec3_t                          average, diff;
160         int                                     indexes[ MAX_SAMPLES ];
161         vec3_t                          votes[ MAX_SAMPLES ];
162         
163         
164         /* allocate shade angle table */
165         shadeAngles = safe_malloc( numBSPDrawVerts * sizeof( float ) );
166         memset( shadeAngles, 0, numBSPDrawVerts * sizeof( float ) );
167         
168         /* allocate smoothed table */
169         cs = (numBSPDrawVerts / 8) + 1;
170         smoothed = safe_malloc( cs );
171         memset( smoothed, 0, cs );
172         
173         /* set default shade angle */
174         defaultShadeAngle = DEG2RAD( shadeAngleDegrees );
175         maxShadeAngle = 0;
176         
177         /* run through every surface and flag verts belonging to non-lightmapped surfaces
178            and set per-vertex smoothing angle */
179         for( i = 0; i < numBSPDrawSurfaces; i++ )
180         {
181                 /* get drawsurf */
182                 ds = &bspDrawSurfaces[ i ];
183                 
184                 /* get shader for shade angle */
185                 si = surfaceInfos[ i ].si;
186                 if( si->shadeAngleDegrees )
187                         shadeAngle = DEG2RAD( si->shadeAngleDegrees );
188                 else
189                         shadeAngle = defaultShadeAngle;
190                 if( shadeAngle > maxShadeAngle )
191                         maxShadeAngle = shadeAngle;
192                 
193                 /* flag its verts */
194                 for( j = 0; j < ds->numVerts; j++ )
195                 {
196                         f = ds->firstVert + j;
197                         shadeAngles[ f ] = shadeAngle;
198                         if( ds->surfaceType == MST_TRIANGLE_SOUP )
199                                 smoothed[ f >> 3 ] |= (1 << (f & 7));
200                 }
201                 
202                 /* ydnar: optional force-to-trisoup */
203                 if( trisoup && ds->surfaceType == MST_PLANAR )
204                 {
205                         ds->surfaceType = MST_TRIANGLE_SOUP;
206                         ds->lightmapNum[ 0 ] = -3;
207                 }
208         }
209         
210         /* bail if no surfaces have a shade angle */
211         if( maxShadeAngle == 0 )
212         {
213                 free( shadeAngles );
214                 free( smoothed );
215                 return;
216         }
217         
218         /* init pacifier */
219         fOld = -1;
220         start = I_FloatTime();
221         
222         /* go through the list of vertexes */
223         for( i = 0; i < numBSPDrawVerts; i++ )
224         {
225                 /* print pacifier */
226                 f = 10 * i / numBSPDrawVerts;
227                 if( f != fOld )
228                 {
229                         fOld = f;
230                         Sys_Printf( "%i...", f );
231                 }
232                 
233                 /* already smoothed? */
234                 if( smoothed[ i >> 3 ] & (1 << (i & 7)) )
235                         continue;
236                 
237                 /* clear */
238                 VectorClear( average );
239                 numVerts = 0;
240                 numVotes = 0;
241                 
242                 /* build a table of coincident vertexes */
243                 for( j = i; j < numBSPDrawVerts && numVerts < MAX_SAMPLES; j++ )
244                 {
245                         /* already smoothed? */
246                         if( smoothed[ j >> 3 ] & (1 << (j & 7)) )
247                                 continue;
248                         
249                         /* test vertexes */
250                         if( VectorCompare( yDrawVerts[ i ].xyz, yDrawVerts[ j ].xyz ) == qfalse )
251                                 continue;
252                         
253                         /* use smallest shade angle */
254                         shadeAngle = (shadeAngles[ i ] < shadeAngles[ j ] ? shadeAngles[ i ] : shadeAngles[ j ]);
255                         
256                         /* check shade angle */
257                         dot = DotProduct( bspDrawVerts[ i ].normal, bspDrawVerts[ j ].normal );
258                         if( dot > 1.0 )
259                                 dot = 1.0;
260                         else if( dot < -1.0 )
261                                 dot = -1.0;
262                         testAngle = acos( dot ) + THETA_EPSILON;
263                         if( testAngle >= shadeAngle )
264                         {
265                                 //Sys_Printf( "F(%3.3f >= %3.3f) ", RAD2DEG( testAngle ), RAD2DEG( shadeAngle ) );
266                                 continue;
267                         }
268                         //Sys_Printf( "P(%3.3f < %3.3f) ", RAD2DEG( testAngle ), RAD2DEG( shadeAngle ) );
269                         
270                         /* add to the list */
271                         indexes[ numVerts++ ] = j;
272                         
273                         /* flag vertex */
274                         smoothed[ j >> 3 ] |= (1 << (j & 7));
275                         
276                         /* see if this normal has already been voted */
277                         for( k = 0; k < numVotes; k++ )
278                         {
279                                 VectorSubtract( bspDrawVerts[ j ].normal, votes[ k ], diff );
280                                 if( fabs( diff[ 0 ] ) < EQUAL_NORMAL_EPSILON &&
281                                         fabs( diff[ 1 ] ) < EQUAL_NORMAL_EPSILON &&
282                                         fabs( diff[ 2 ] ) < EQUAL_NORMAL_EPSILON )
283                                         break;
284                         }
285                         
286                         /* add a new vote? */
287                         if( k == numVotes && numVotes < MAX_SAMPLES )
288                         {
289                                 VectorAdd( average, bspDrawVerts[ j ].normal, average );
290                                 VectorCopy( bspDrawVerts[ j ].normal, votes[ numVotes ] );
291                                 numVotes++;
292                         }
293                 }
294                 
295                 /* don't average for less than 2 verts */
296                 if( numVerts < 2 )
297                         continue;
298                 
299                 /* average normal */
300                 if( VectorNormalize( average, average ) > 0 )
301                 {
302                         /* smooth */
303                         for( j = 0; j < numVerts; j++ )
304                                 VectorCopy( average, yDrawVerts[ indexes[ j ] ].normal );
305                 }
306         }
307         
308         /* free the tables */
309         free( shadeAngles );
310         free( smoothed );
311         
312         /* print time */
313         Sys_Printf( " (%i)\n", (int) (I_FloatTime() - start) );
314 }
315
316
317
318 /* -------------------------------------------------------------------------------
319
320 this section deals with phong shaded lightmap tracing
321
322 ------------------------------------------------------------------------------- */
323
324 /* 9th rewrite (recursive subdivision of a lightmap triangle) */
325
326 /*
327 CalcTangentVectors()
328 calculates the st tangent vectors for normalmapping
329 */
330
331 static qboolean CalcTangentVectors( int numVerts, bspDrawVert_t **dv, vec3_t *stv, vec3_t *ttv )
332 {
333         int                     i;
334         float           bb, s, t;
335         vec3_t          bary;
336         
337         
338         /* calculate barycentric basis for the triangle */
339         bb = (dv[ 1 ]->st[ 0 ] - dv[ 0 ]->st[ 0 ]) * (dv[ 2 ]->st[ 1 ] - dv[ 0 ]->st[ 1 ]) - (dv[ 2 ]->st[ 0 ] - dv[ 0 ]->st[ 0 ]) * (dv[ 1 ]->st[ 1 ] - dv[ 0 ]->st[ 1 ]);
340         if( fabs( bb ) < 0.00000001f )
341                 return qfalse;
342         
343         /* do each vertex */
344         for( i = 0; i < numVerts; i++ )
345         {
346                 /* calculate s tangent vector */
347                 s = dv[ i ]->st[ 0 ] + 10.0f;
348                 t = dv[ i ]->st[ 1 ];
349                 bary[ 0 ] = ((dv[ 1 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t) - (dv[ 2 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t)) / bb;
350                 bary[ 1 ] = ((dv[ 2 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t) - (dv[ 0 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t)) / bb;
351                 bary[ 2 ] = ((dv[ 0 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t) - (dv[ 1 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t)) / bb;
352                 
353                 stv[ i ][ 0 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 0 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 0 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 0 ];
354                 stv[ i ][ 1 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 1 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 1 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 1 ];
355                 stv[ i ][ 2 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 2 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 2 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 2 ];
356                 
357                 VectorSubtract( stv[ i ], dv[ i ]->xyz, stv[ i ] );
358                 VectorNormalize( stv[ i ], stv[ i ] );
359                 
360                 /* calculate t tangent vector */
361                 s = dv[ i ]->st[ 0 ];
362                 t = dv[ i ]->st[ 1 ] + 10.0f;
363                 bary[ 0 ] = ((dv[ 1 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t) - (dv[ 2 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t)) / bb;
364                 bary[ 1 ] = ((dv[ 2 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t) - (dv[ 0 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t)) / bb;
365                 bary[ 2 ] = ((dv[ 0 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t) - (dv[ 1 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t)) / bb;
366                 
367                 ttv[ i ][ 0 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 0 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 0 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 0 ];
368                 ttv[ i ][ 1 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 1 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 1 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 1 ];
369                 ttv[ i ][ 2 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 2 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 2 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 2 ];
370                 
371                 VectorSubtract( ttv[ i ], dv[ i ]->xyz, ttv[ i ] );
372                 VectorNormalize( ttv[ i ], ttv[ i ] );
373                 
374                 /* debug code */
375                 //%     Sys_FPrintf( SYS_VRB, "%d S: (%f %f %f) T: (%f %f %f)\n", i,
376                 //%             stv[ i ][ 0 ], stv[ i ][ 1 ], stv[ i ][ 2 ], ttv[ i ][ 0 ], ttv[ i ][ 1 ], ttv[ i ][ 2 ] );
377         }
378         
379         /* return to caller */
380         return qtrue;
381 }
382
383
384
385
386 /*
387 PerturbNormal()
388 perterbs the normal by the shader's normalmap in tangent space
389 */
390
391 static void PerturbNormal( bspDrawVert_t *dv, shaderInfo_t *si, vec3_t pNormal, vec3_t stv[ 3 ], vec3_t ttv[ 3 ] )
392 {
393         int                     i;
394         vec4_t          bump;
395         
396         
397         /* passthrough */
398         VectorCopy( dv->normal, pNormal );
399         
400         /* sample normalmap */
401         if( RadSampleImage( si->normalImage->pixels, si->normalImage->width, si->normalImage->height, dv->st, bump ) == qfalse )
402                 return;
403         
404         /* remap sampled normal from [0,255] to [-1,-1] */
405         for( i = 0; i < 3; i++ )
406                 bump[ i ] = (bump[ i ] - 127.0f) * (1.0f / 127.5f);
407         
408         /* scale tangent vectors and add to original normal */
409         VectorMA( dv->normal, bump[ 0 ], stv[ 0 ], pNormal );
410         VectorMA( pNormal, bump[ 1 ], ttv[ 0 ], pNormal );
411         VectorMA( pNormal, bump[ 2 ], dv->normal, pNormal );
412         
413         /* renormalize and return */
414         VectorNormalize( pNormal, pNormal );
415 }
416
417
418
419 /*
420 MapSingleLuxel()
421 maps a luxel for triangle bv at
422 */
423
424 #define NUDGE                   0.5f
425 #define BOGUS_NUDGE             -99999.0f
426
427 static int MapSingleLuxel( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv, vec4_t plane, float pass, vec3_t stv[ 3 ], vec3_t ttv[ 3 ], vec3_t worldverts[ 3 ] )
428 {
429         int                             i, x, y, numClusters, *clusters, pointCluster, *cluster;
430         float                   *luxel, *origin, *normal, d, lightmapSampleOffset;
431         shaderInfo_t    *si;
432         vec3_t                  pNormal;
433         vec3_t                  vecs[ 3 ];
434         vec3_t                  nudged;
435         vec3_t                  cverts[ 3 ];
436         vec3_t                  temp;
437         vec4_t                  sideplane, hostplane;
438         vec3_t                  origintwo;
439         int                             j, next;
440         float                   e;
441         float                   *nudge;
442         static float    nudges[][ 2 ] =
443                                         {
444                                                 //%{ 0, 0 },            /* try center first */
445                                                 { -NUDGE, 0 },          /* left */
446                                                 { NUDGE, 0 },           /* right */
447                                                 { 0, NUDGE },           /* up */
448                                                 { 0, -NUDGE },          /* down */
449                                                 { -NUDGE, NUDGE },      /* left/up */
450                                                 { NUDGE, -NUDGE },      /* right/down */
451                                                 { NUDGE, NUDGE },       /* right/up */
452                                                 { -NUDGE, -NUDGE },     /* left/down */
453                                                 { BOGUS_NUDGE, BOGUS_NUDGE }
454                                         };
455         
456         
457         /* find luxel xy coords (fixme: subtract 0.5?) */
458         x = dv->lightmap[ 0 ][ 0 ];
459         y = dv->lightmap[ 0 ][ 1 ];
460         if( x < 0 )
461                 x = 0;
462         else if( x >= lm->sw )
463                 x = lm->sw - 1;
464         if( y < 0 )
465                 y = 0;
466         else if( y >= lm->sh )
467                 y = lm->sh - 1;
468         
469         /* set shader and cluster list */
470         if( info != NULL )
471         {
472                 si = info->si;
473                 numClusters = info->numSurfaceClusters;
474                 clusters = &surfaceClusters[ info->firstSurfaceCluster ];
475         }
476         else
477         {
478                 si = NULL;
479                 numClusters = 0;
480                 clusters = NULL;
481         }
482         
483         /* get luxel, origin, cluster, and normal */
484         luxel = SUPER_LUXEL( 0, x, y );
485         origin = SUPER_ORIGIN( x, y );
486         normal = SUPER_NORMAL( x, y );
487         cluster = SUPER_CLUSTER( x, y );
488         
489         /* don't attempt to remap occluded luxels for planar surfaces */
490         if( (*cluster) == CLUSTER_OCCLUDED && lm->plane != NULL )
491                 return (*cluster);
492         
493         /* only average the normal for premapped luxels */
494         else if( (*cluster) >= 0 )
495         {
496                 /* do bumpmap calculations */
497                 if( stv != NULL )
498                         PerturbNormal( dv, si, pNormal, stv, ttv );
499                 else
500                         VectorCopy( dv->normal, pNormal );
501                 
502                 /* add the additional normal data */
503                 VectorAdd( normal, pNormal, normal );
504                 luxel[ 3 ] += 1.0f;
505                 return (*cluster);
506         }
507         
508         /* otherwise, unmapped luxels (*cluster == CLUSTER_UNMAPPED) will have their full attributes calculated */
509         
510         /* get origin */
511         
512         /* axial lightmap projection */
513         if( lm->vecs != NULL )
514         {
515                 /* calculate an origin for the sample from the lightmap vectors */
516                 VectorCopy( lm->origin, origin );
517                 for( i = 0; i < 3; i++ )
518                 {
519                         /* add unless it's the axis, which is taken care of later */
520                         if( i == lm->axisNum )
521                                 continue;
522                         origin[ i ] += (x * lm->vecs[ 0 ][ i ]) + (y * lm->vecs[ 1 ][ i ]);
523                 }
524                 
525                 /* project the origin onto the plane */
526                 d = DotProduct( origin, plane ) - plane[ 3 ];
527                 d /= plane[ lm->axisNum ];
528                 origin[ lm->axisNum ] -= d;
529         }
530         
531         /* non axial lightmap projection (explicit xyz) */
532         else
533                 VectorCopy( dv->xyz, origin );
534
535         //////////////////////
536         //27's test to make sure samples stay within the triangle boundaries
537         //1) Test the sample origin to see if it lays on the wrong side of any edge (x/y)
538         //2) if it does, nudge it onto the correct side.
539
540         if (worldverts!=NULL && lightmapTriangleCheck)
541         {
542                 for (j=0;j<3;j++)
543                 {
544                         VectorCopy(worldverts[j],cverts[j]);
545                 }
546                 PlaneFromPoints(hostplane,cverts[0],cverts[1],cverts[2]);
547
548                 for (j=0;j<3;j++)
549                 {
550                         for (i=0;i<3;i++)
551                         {
552                                 //build plane using 2 edges and a normal
553                                 next=(i+1)%3;
554
555                                 VectorCopy(cverts[next],temp);
556                                 VectorAdd(temp,hostplane,temp);
557                                 PlaneFromPoints(sideplane,cverts[i],cverts[ next ], temp);
558
559                                 //planetest sample point
560                                 e=DotProduct(origin,sideplane);
561                                 e=e-sideplane[3];
562                                 if (e>0)
563                                 {
564                                         //we're bad.
565                                         //VectorClear(origin);
566                                         //Move the sample point back inside triangle bounds
567                                         origin[0]-=sideplane[0]*(e+1);
568                                         origin[1]-=sideplane[1]*(e+1);
569                                         origin[2]-=sideplane[2]*(e+1);
570 #ifdef DEBUG_27_1
571                                         VectorClear(origin);
572 #endif
573                                 }
574                         }
575                 }
576         }
577
578         ////////////////////////
579         
580         /* planar surfaces have precalculated lightmap vectors for nudging */
581         if( lm->plane != NULL )
582         {
583                 VectorCopy( lm->vecs[ 0 ], vecs[ 0 ] );
584                 VectorCopy( lm->vecs[ 1 ], vecs[ 1 ] );
585                 VectorCopy( lm->plane, vecs[ 2 ] );
586         }
587         
588         /* non-planar surfaces must calculate them */
589         else
590         {
591                 if( plane != NULL )
592                         VectorCopy( plane, vecs[ 2 ] );
593                 else
594                         VectorCopy( dv->normal, vecs[ 2 ] );
595                 MakeNormalVectors( vecs[ 2 ], vecs[ 0 ], vecs[ 1 ] );
596         }
597         
598         /* push the origin off the surface a bit */
599         if( si != NULL )
600                 lightmapSampleOffset = si->lightmapSampleOffset;
601         else
602                 lightmapSampleOffset = DEFAULT_LIGHTMAP_SAMPLE_OFFSET;
603         if( lm->axisNum < 0 )
604                 VectorMA( origin, lightmapSampleOffset, vecs[ 2 ], origin );
605         else if( vecs[ 2 ][ lm->axisNum ] < 0.0f )
606                 origin[ lm->axisNum ] -= lightmapSampleOffset;
607         else
608                 origin[ lm->axisNum ] += lightmapSampleOffset;
609         
610         VectorCopy(origin,origintwo);
611         if(lightmapExtraVisClusterNudge)
612         {
613                 origintwo[0]+=vecs[2][0];
614                 origintwo[1]+=vecs[2][1];
615                 origintwo[2]+=vecs[2][2];
616         }
617
618         /* get cluster */
619         pointCluster = ClusterForPointExtFilter( origintwo, LUXEL_EPSILON, numClusters, clusters );
620         
621         /* another retarded hack, storing nudge count in luxel[ 1 ] */
622         luxel[ 1 ] = 0.0f;      
623         
624         /* point in solid? (except in dark mode) */
625         if( pointCluster < 0 && dark == qfalse )
626         {
627                 /* nudge the the location around */
628                 nudge = nudges[ 0 ];
629                 while( nudge[ 0 ] > BOGUS_NUDGE && pointCluster < 0 )
630                 {
631                         /* nudge the vector around a bit */
632                         for( i = 0; i < 3; i++ )
633                         {
634                                 /* set nudged point*/
635                                 nudged[ i ] = origintwo[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
636                         }
637                         nudge += 2;
638                         
639                         /* get pvs cluster */
640                         pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); //% + 0.625 );
641                         if( pointCluster >= 0 )
642                                 VectorCopy( nudged, origin );
643                         luxel[ 1 ] += 1.0f;
644                 }
645         }
646         
647         /* as a last resort, if still in solid, try drawvert origin offset by normal (except in dark mode) */
648         if( pointCluster < 0 && si != NULL && dark == qfalse )
649         {
650                 VectorMA( dv->xyz, lightmapSampleOffset, dv->normal, nudged );
651                 pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters );
652                 if( pointCluster >= 0 )
653                         VectorCopy( nudged, origin );
654                 luxel[ 1 ] += 1.0f;
655         }
656         
657         /* valid? */
658         if( pointCluster < 0 )
659         {
660                 (*cluster) = CLUSTER_OCCLUDED;
661                 VectorClear( origin );
662                 VectorClear( normal );
663                 numLuxelsOccluded++;
664                 return (*cluster);
665         }
666         
667         /* debug code */
668         //%     Sys_Printf( "%f %f %f\n", origin[ 0 ], origin[ 1 ], origin[ 2 ] );
669         
670         /* do bumpmap calculations */
671         if( stv )
672                 PerturbNormal( dv, si, pNormal, stv, ttv );
673         else
674                 VectorCopy( dv->normal, pNormal );
675         
676         /* store the cluster and normal */
677         (*cluster) = pointCluster;
678         VectorCopy( pNormal, normal );
679         
680         /* store explicit mapping pass and implicit mapping pass */
681         luxel[ 0 ] = pass;
682         luxel[ 3 ] = 1.0f;
683         
684         /* add to count */
685         numLuxelsMapped++;
686         
687         /* return ok */
688         return (*cluster);
689 }
690
691
692
693 /*
694 MapTriangle_r()
695 recursively subdivides a triangle until its edges are shorter
696 than the distance between two luxels (thanks jc :)
697 */
698
699 static void MapTriangle_r( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 3 ], vec4_t plane, vec3_t stv[ 3 ], vec3_t ttv[ 3 ], vec3_t worldverts[ 3 ] )
700 {
701         bspDrawVert_t   mid, *dv2[ 3 ];
702         int                             max;
703         
704         
705         /* map the vertexes */
706         #if 0
707         MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
708         MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
709         MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
710         #endif
711         
712         /* subdivide calc */
713         {
714                 int                     i;
715                 float           *a, *b, dx, dy, dist, maxDist;
716                 
717                 
718                 /* find the longest edge and split it */
719                 max = -1;
720                 maxDist = 0;
721                 for( i = 0; i < 3; i++ )
722                 {
723                         /* get verts */
724                         a = dv[ i ]->lightmap[ 0 ];
725                         b = dv[ (i + 1) % 3 ]->lightmap[ 0 ];
726                         
727                         /* get dists */
728                         dx = a[ 0 ] - b[ 0 ];
729                         dy = a[ 1 ] - b[ 1 ];
730                         dist = (dx * dx) + (dy * dy);   //% sqrt( (dx * dx) + (dy * dy) );
731                         
732                         /* longer? */
733                         if( dist > maxDist )
734                         {
735                                 maxDist = dist;
736                                 max = i;
737                         }
738                 }
739                 
740                 /* try to early out */
741                 if( max < 0 || maxDist <= subdivideThreshold )  /* ydnar: was i < 0 instead of max < 0 (?) */
742                         return;
743         }
744         
745         /* split the longest edge and map it */
746         LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid );
747         MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv, worldverts );
748         
749         /* push the point up a little bit to account for fp creep (fixme: revisit this) */
750         //%     VectorMA( mid.xyz, 2.0f, mid.normal, mid.xyz );
751         
752         /* recurse to first triangle */
753         VectorCopy( dv, dv2 );
754         dv2[ max ] = &mid;
755         MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
756         
757         /* recurse to second triangle */
758         VectorCopy( dv, dv2 );
759         dv2[ (max + 1) % 3 ] = &mid;
760         MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
761 }
762
763
764
765 /*
766 MapTriangle()
767 seed function for MapTriangle_r()
768 requires a cw ordered triangle
769 */
770
771 static qboolean MapTriangle( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 3 ], qboolean mapNonAxial )
772 {
773         int                             i;
774         vec4_t                  plane;
775         vec3_t                  *stv, *ttv, stvStatic[ 3 ], ttvStatic[ 3 ];
776         vec3_t                  worldverts[ 3 ];
777         
778         
779         /* get plane if possible */
780         if( lm->plane != NULL )
781         {
782                 VectorCopy( lm->plane, plane );
783                 plane[ 3 ] = lm->plane[ 3 ];
784         }
785         
786         /* otherwise make one from the points */
787         else if( PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) == qfalse )
788                 return qfalse;
789         
790         /* check to see if we need to calculate texture->world tangent vectors */
791         if( info->si->normalImage != NULL && CalcTangentVectors( 3, dv, stvStatic, ttvStatic ) )
792         {
793                 stv = stvStatic;
794                 ttv = ttvStatic;
795         }
796         else
797         {
798                 stv = NULL;
799                 ttv = NULL;
800         }
801         
802         VectorCopy( dv[ 0 ]->xyz, worldverts[ 0 ] );
803         VectorCopy( dv[ 1 ]->xyz, worldverts[ 1 ] );
804         VectorCopy( dv[ 2 ]->xyz, worldverts[ 2 ] );
805
806         /* map the vertexes */
807         MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, worldverts );
808         MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, worldverts );
809         MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, worldverts );
810         
811         /* 2002-11-20: prefer axial triangle edges */
812         if( mapNonAxial )
813         {
814                 /* subdivide the triangle */
815                 MapTriangle_r( lm, info, dv, plane, stv, ttv, worldverts );
816                 return qtrue;
817         }
818         
819         for( i = 0; i < 3; i++ )
820         {
821                 float                   *a, *b;
822                 bspDrawVert_t   *dv2[ 3 ];
823                 
824                 
825                 /* get verts */
826                 a = dv[ i ]->lightmap[ 0 ];
827                 b = dv[ (i + 1) % 3 ]->lightmap[ 0 ];
828                 
829                 /* make degenerate triangles for mapping edges */
830                 if( fabs( a[ 0 ] - b[ 0 ] ) < 0.01f || fabs( a[ 1 ] - b[ 1 ] ) < 0.01f )
831                 {
832                         dv2[ 0 ] = dv[ i ];
833                         dv2[ 1 ] = dv[ (i + 1) % 3 ];
834                         dv2[ 2 ] = dv[ (i + 1) % 3 ];
835                         
836                         /* map the degenerate triangle */
837                         MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
838                 }
839         }
840         
841         return qtrue;
842 }
843
844
845
846 /*
847 MapQuad_r()
848 recursively subdivides a quad until its edges are shorter
849 than the distance between two luxels
850 */
851
852 static void MapQuad_r( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 4 ], vec4_t plane, vec3_t stv[ 4 ], vec3_t ttv[ 4 ] )
853 {
854         bspDrawVert_t   mid[ 2 ], *dv2[ 4 ];
855         int                             max;
856         
857         
858         /* subdivide calc */
859         {
860                 int                     i;
861                 float           *a, *b, dx, dy, dist, maxDist;
862                 
863                 
864                 /* find the longest edge and split it */
865                 max = -1;
866                 maxDist = 0;
867                 for( i = 0; i < 4; i++ )
868                 {
869                         /* get verts */
870                         a = dv[ i ]->lightmap[ 0 ];
871                         b = dv[ (i + 1) % 4 ]->lightmap[ 0 ];
872                         
873                         /* get dists */
874                         dx = a[ 0 ] - b[ 0 ];
875                         dy = a[ 1 ] - b[ 1 ];
876                         dist = (dx * dx) + (dy * dy);   //% sqrt( (dx * dx) + (dy * dy) );
877                         
878                         /* longer? */
879                         if( dist > maxDist )
880                         {
881                                 maxDist = dist;
882                                 max = i;
883                         }
884                 }
885                 
886                 /* try to early out */
887                 if( max < 0 || maxDist <= subdivideThreshold )
888                         return;
889         }
890         
891         /* we only care about even/odd edges */
892         max &= 1;
893         
894         /* split the longest edges */
895         LerpDrawVert( dv[ max ], dv[ (max + 1) % 4 ], &mid[ 0 ] );
896         LerpDrawVert( dv[ max + 2 ], dv[ (max + 3) % 4 ], &mid[ 1 ] );
897         
898         /* map the vertexes */
899         MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv, NULL );
900         MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv, NULL );
901         
902         /* 0 and 2 */
903         if( max == 0 )
904         {
905                 /* recurse to first quad */
906                 dv2[ 0 ] = dv[ 0 ];
907                 dv2[ 1 ] = &mid[ 0 ];
908                 dv2[ 2 ] = &mid[ 1 ];
909                 dv2[ 3 ] = dv[ 3 ];
910                 MapQuad_r( lm, info, dv2, plane, stv, ttv );
911                 
912                 /* recurse to second quad */
913                 dv2[ 0 ] = &mid[ 0 ];
914                 dv2[ 1 ] = dv[ 1 ];
915                 dv2[ 2 ] = dv[ 2 ];
916                 dv2[ 3 ] = &mid[ 1 ];
917                 MapQuad_r( lm, info, dv2, plane, stv, ttv );
918         }
919         
920         /* 1 and 3 */
921         else
922         {
923                 /* recurse to first quad */
924                 dv2[ 0 ] = dv[ 0 ];
925                 dv2[ 1 ] = dv[ 1 ];
926                 dv2[ 2 ] = &mid[ 0 ];
927                 dv2[ 3 ] = &mid[ 1 ];
928                 MapQuad_r( lm, info, dv2, plane, stv, ttv );
929                 
930                 /* recurse to second quad */
931                 dv2[ 0 ] = &mid[ 1 ];
932                 dv2[ 1 ] = &mid[ 0 ];
933                 dv2[ 2 ] = dv[ 2 ];
934                 dv2[ 3 ] = dv[ 3 ];
935                 MapQuad_r( lm, info, dv2, plane, stv, ttv );
936         }
937 }
938
939
940
941 /*
942 MapQuad()
943 seed function for MapQuad_r()
944 requires a cw ordered triangle quad
945 */
946
947 #define QUAD_PLANAR_EPSILON             0.5f
948
949 static qboolean MapQuad( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 4 ] )
950 {
951         float                   dist;
952         vec4_t                  plane;
953         vec3_t                  *stv, *ttv, stvStatic[ 4 ], ttvStatic[ 4 ];
954         
955         
956         /* get plane if possible */
957         if( lm->plane != NULL )
958         {
959                 VectorCopy( lm->plane, plane );
960                 plane[ 3 ] = lm->plane[ 3 ];
961         }
962         
963         /* otherwise make one from the points */
964         else if( PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) == qfalse )
965                 return qfalse;
966         
967         /* 4th point must fall on the plane */
968         dist = DotProduct( plane, dv[ 3 ]->xyz ) - plane[ 3 ];
969         if( fabs( dist ) > QUAD_PLANAR_EPSILON )
970                 return qfalse;
971         
972         /* check to see if we need to calculate texture->world tangent vectors */
973         if( info->si->normalImage != NULL && CalcTangentVectors( 4, dv, stvStatic, ttvStatic ) )
974         {
975                 stv = stvStatic;
976                 ttv = ttvStatic;
977         }
978         else
979         {
980                 stv = NULL;
981                 ttv = NULL;
982         }
983         
984         /* map the vertexes */
985         MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, NULL );
986         MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, NULL );
987         MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, NULL );
988         MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv, NULL );
989         
990         /* subdivide the quad */
991         MapQuad_r( lm, info, dv, plane, stv, ttv );
992         return qtrue;
993 }
994
995
996
997 /*
998 MapRawLightmap()
999 maps the locations, normals, and pvs clusters for a raw lightmap
1000 */
1001
1002 #define VectorDivide( in, d, out )      VectorScale( in, (1.0f / (d)), out )    //%     (out)[ 0 ] = (in)[ 0 ] / (d), (out)[ 1 ] = (in)[ 1 ] / (d), (out)[ 2 ] = (in)[ 2 ] / (d)
1003
1004 void MapRawLightmap( int rawLightmapNum )
1005 {
1006         int                                     n, num, i, x, y, sx, sy, pw[ 5 ], r, *cluster, mapNonAxial;
1007         float                           *luxel, *origin, *normal, samples, radius, pass;
1008         rawLightmap_t           *lm;
1009         bspDrawSurface_t        *ds;
1010         surfaceInfo_t           *info;
1011         mesh_t                          src, *subdivided, *mesh;
1012         bspDrawVert_t           *verts, *dv[ 4 ], fake;
1013         
1014         
1015         /* bail if this number exceeds the number of raw lightmaps */
1016         if( rawLightmapNum >= numRawLightmaps )
1017                 return;
1018         
1019         /* get lightmap */
1020         lm = &rawLightmaps[ rawLightmapNum ];
1021         
1022         /* -----------------------------------------------------------------
1023            map referenced surfaces onto the raw lightmap
1024            ----------------------------------------------------------------- */
1025         
1026         /* walk the list of surfaces on this raw lightmap */
1027         for( n = 0; n < lm->numLightSurfaces; n++ )
1028         {
1029                 /* with > 1 surface per raw lightmap, clear occluded */
1030                 if( n > 0 )
1031                 {
1032                         for( y = 0; y < lm->sh; y++ )
1033                         {
1034                                 for( x = 0; x < lm->sw; x++ )
1035                                 {
1036                                         /* get cluster */
1037                                         cluster = SUPER_CLUSTER( x, y );
1038                                         if( *cluster < 0 )
1039                                                 *cluster = CLUSTER_UNMAPPED;
1040                                 }
1041                         }
1042                 }
1043                 
1044                 /* get surface */
1045                 num = lightSurfaces[ lm->firstLightSurface + n ];
1046                 ds = &bspDrawSurfaces[ num ];
1047                 info = &surfaceInfos[ num ];
1048                 
1049                 /* bail if no lightmap to calculate */
1050                 if( info->lm != lm )
1051                 {
1052                         Sys_Printf( "!" );
1053                         continue;
1054                 }
1055                 
1056                 /* map the surface onto the lightmap origin/cluster/normal buffers */
1057                 switch( ds->surfaceType )
1058                 {
1059                         case MST_PLANAR:
1060                                 /* get verts */
1061                                 verts = yDrawVerts + ds->firstVert;
1062                                 
1063                                 /* map the triangles */
1064                                 for( mapNonAxial = 0; mapNonAxial < 2; mapNonAxial++ )
1065                                 {
1066                                         for( i = 0; i < ds->numIndexes; i += 3 )
1067                                         {
1068                                                 dv[ 0 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i ] ];
1069                                                 dv[ 1 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 1 ] ];
1070                                                 dv[ 2 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 2 ] ];
1071                                                 MapTriangle( lm, info, dv, mapNonAxial );
1072                                         }
1073                                 }
1074                                 break;
1075                         
1076                         case MST_PATCH:
1077                                 /* make a mesh from the drawsurf */ 
1078                                 src.width = ds->patchWidth;
1079                                 src.height = ds->patchHeight;
1080                                 src.verts = &yDrawVerts[ ds->firstVert ];
1081                                 //%     subdivided = SubdivideMesh( src, 8, 512 );
1082                                 subdivided = SubdivideMesh2( src, info->patchIterations );
1083                                 
1084                                 /* fit it to the curve and remove colinear verts on rows/columns */
1085                                 PutMeshOnCurve( *subdivided );
1086                                 mesh = RemoveLinearMeshColumnsRows( subdivided );
1087                                 FreeMesh( subdivided );
1088                                 
1089                                 /* get verts */
1090                                 verts = mesh->verts;
1091                                 
1092                                 /* debug code */
1093                                 #if 0
1094                                         if( lm->plane )
1095                                         {
1096                                                 Sys_Printf( "Planar patch: [%1.3f %1.3f %1.3f] [%1.3f %1.3f %1.3f] [%1.3f %1.3f %1.3f]\n",
1097                                                         lm->plane[ 0 ], lm->plane[ 1 ], lm->plane[ 2 ],
1098                                                         lm->vecs[ 0 ][ 0 ], lm->vecs[ 0 ][ 1 ], lm->vecs[ 0 ][ 2 ],
1099                                                         lm->vecs[ 1 ][ 0 ], lm->vecs[ 1 ][ 1 ], lm->vecs[ 1 ][ 2 ] );
1100                                         }
1101                                 #endif
1102                                 
1103                                 /* map the mesh quads */
1104                                 #if 0
1105
1106                                 for( mapNonAxial = 0; mapNonAxial < 2; mapNonAxial++ )
1107                                 {
1108                                         for( y = 0; y < (mesh->height - 1); y++ )
1109                                         {
1110                                                 for( x = 0; x < (mesh->width - 1); x++ )
1111                                                 {
1112                                                         /* set indexes */
1113                                                         pw[ 0 ] = x + (y * mesh->width);
1114                                                         pw[ 1 ] = x + ((y + 1) * mesh->width);
1115                                                         pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
1116                                                         pw[ 3 ] = x + 1 + (y * mesh->width);
1117                                                         pw[ 4 ] = x + (y * mesh->width);        /* same as pw[ 0 ] */
1118                                                         
1119                                                         /* set radix */
1120                                                         r = (x + y) & 1;
1121                                                         
1122                                                         /* get drawverts and map first triangle */
1123                                                         dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1124                                                         dv[ 1 ] = &verts[ pw[ r + 1 ] ];
1125                                                         dv[ 2 ] = &verts[ pw[ r + 2 ] ];
1126                                                         MapTriangle( lm, info, dv, mapNonAxial );
1127                                                         
1128                                                         /* get drawverts and map second triangle */
1129                                                         dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1130                                                         dv[ 1 ] = &verts[ pw[ r + 2 ] ];
1131                                                         dv[ 2 ] = &verts[ pw[ r + 3 ] ];
1132                                                         MapTriangle( lm, info, dv, mapNonAxial );
1133                                                 }
1134                                         }
1135                                 }
1136                                 
1137                                 #else
1138                                 
1139                                 for( y = 0; y < (mesh->height - 1); y++ )
1140                                 {
1141                                         for( x = 0; x < (mesh->width - 1); x++ )
1142                                         {
1143                                                 /* set indexes */
1144                                                 pw[ 0 ] = x + (y * mesh->width);
1145                                                 pw[ 1 ] = x + ((y + 1) * mesh->width);
1146                                                 pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
1147                                                 pw[ 3 ] = x + 1 + (y * mesh->width);
1148                                                 pw[ 4 ] = pw[ 0 ];
1149                                                 
1150                                                 /* set radix */
1151                                                 r = (x + y) & 1;
1152                                                 
1153                                                 /* attempt to map quad first */
1154                                                 dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1155                                                 dv[ 1 ] = &verts[ pw[ r + 1 ] ];
1156                                                 dv[ 2 ] = &verts[ pw[ r + 2 ] ];
1157                                                 dv[ 3 ] = &verts[ pw[ r + 3 ] ];
1158                                                 if( MapQuad( lm, info, dv ) )
1159                                                         continue;
1160                                                 
1161                                                 for( mapNonAxial = 0; mapNonAxial < 2; mapNonAxial++ )
1162                                                 {
1163                                                         /* get drawverts and map first triangle */
1164                                                         dv[ 1 ] = &verts[ pw[ r + 1 ] ];
1165                                                         dv[ 2 ] = &verts[ pw[ r + 2 ] ];
1166                                                         MapTriangle( lm, info, dv, mapNonAxial );
1167                                                         
1168                                                         /* get drawverts and map second triangle */
1169                                                         dv[ 1 ] = &verts[ pw[ r + 2 ] ];
1170                                                         dv[ 2 ] = &verts[ pw[ r + 3 ] ];
1171                                                         MapTriangle( lm, info, dv, mapNonAxial );
1172                                                 }
1173                                         }
1174                                 }
1175                                 
1176                                 #endif
1177                                 
1178                                 /* free the mesh */
1179                                 FreeMesh( mesh );
1180                                 break;
1181                         
1182                         default:
1183                                 break;
1184                 }
1185         }
1186         
1187         /* -----------------------------------------------------------------
1188            average and clean up luxel normals
1189            ----------------------------------------------------------------- */
1190         
1191         /* walk the luxels */
1192         for( y = 0; y < lm->sh; y++ )
1193         {
1194                 for( x = 0; x < lm->sw; x++ )
1195                 {
1196                         /* get luxel */
1197                         luxel = SUPER_LUXEL( 0, x, y );
1198                         normal = SUPER_NORMAL( x, y );
1199                         cluster = SUPER_CLUSTER( x, y );
1200
1201                         /* only look at mapped luxels */
1202                         if( *cluster < 0 )
1203                                 continue;
1204                         
1205                         /* the normal data could be the sum of multiple samples */
1206                         if( luxel[ 3 ] > 1.0f )
1207                                 VectorNormalize( normal, normal );
1208                         
1209                         /* mark this luxel as having only one normal */
1210                         luxel[ 3 ] = 1.0f;
1211                 }
1212         }
1213         
1214         /* non-planar surfaces stop here */
1215         if( lm->plane == NULL )
1216                 return;
1217         
1218         /* -----------------------------------------------------------------
1219            map occluded or unuxed luxels
1220            ----------------------------------------------------------------- */
1221         
1222         /* walk the luxels */
1223         radius = floor( superSample / 2 );
1224         radius = radius > 0 ? radius : 1.0f;
1225         radius += 1.0f;
1226         for( pass = 2.0f; pass <= radius; pass += 1.0f )
1227         {
1228                 for( y = 0; y < lm->sh; y++ )
1229                 {
1230                         for( x = 0; x < lm->sw; x++ )
1231                         {
1232                                 /* get luxel */
1233                                 luxel = SUPER_LUXEL( 0, x, y );
1234                                 normal = SUPER_NORMAL( x, y );
1235                                 cluster = SUPER_CLUSTER( x, y );
1236                                 
1237                                 /* only look at unmapped luxels */
1238                                 if( *cluster != CLUSTER_UNMAPPED )
1239                                         continue;
1240                                 
1241                                 /* divine a normal and origin from neighboring luxels */
1242                                 VectorClear( fake.xyz );
1243                                 VectorClear( fake.normal );
1244                                 fake.lightmap[ 0 ][ 0 ] = x;    //% 0.0001 + x;
1245                                 fake.lightmap[ 0 ][ 1 ] = y;    //% 0.0001 + y;
1246                                 samples = 0.0f;
1247                                 for( sy = (y - 1); sy <= (y + 1); sy++ )
1248                                 {
1249                                         if( sy < 0 || sy >= lm->sh )
1250                                                 continue;
1251                                         
1252                                         for( sx = (x - 1); sx <= (x + 1); sx++ )
1253                                         {
1254                                                 if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
1255                                                         continue;
1256                                                 
1257                                                 /* get neighboring luxel */
1258                                                 luxel = SUPER_LUXEL( 0, sx, sy );
1259                                                 origin = SUPER_ORIGIN( sx, sy );
1260                                                 normal = SUPER_NORMAL( sx, sy );
1261                                                 cluster = SUPER_CLUSTER( sx, sy );
1262                                                 
1263                                                 /* only consider luxels mapped in previous passes */
1264                                                 if( *cluster < 0 || luxel[ 0 ] >= pass )
1265                                                         continue;
1266                                                 
1267                                                 /* add its distinctiveness to our own */
1268                                                 VectorAdd( fake.xyz, origin, fake.xyz );
1269                                                 VectorAdd( fake.normal, normal, fake.normal );
1270                                                 samples += luxel[ 3 ];
1271                                         }
1272                                 }
1273                                 
1274                                 /* any samples? */
1275                                 if( samples == 0.0f )
1276                                         continue;
1277                                 
1278                                 /* average */
1279                                 VectorDivide( fake.xyz, samples, fake.xyz );
1280                                 //%     VectorDivide( fake.normal, samples, fake.normal );
1281                                 if( VectorNormalize( fake.normal, fake.normal ) == 0.0f )
1282                                         continue;
1283                                 
1284                                 /* map the fake vert */
1285                                 MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL, NULL );
1286                         }
1287                 }
1288         }
1289         
1290         /* -----------------------------------------------------------------
1291            average and clean up luxel normals
1292            ----------------------------------------------------------------- */
1293         
1294         /* walk the luxels */
1295         for( y = 0; y < lm->sh; y++ )
1296         {
1297                 for( x = 0; x < lm->sw; x++ )
1298                 {
1299                         /* get luxel */
1300                         luxel = SUPER_LUXEL( 0, x, y );
1301                         normal = SUPER_NORMAL( x, y );
1302                         cluster = SUPER_CLUSTER( x, y );
1303                         
1304                         /* only look at mapped luxels */
1305                         if( *cluster < 0 )
1306                                 continue;
1307                         
1308                         /* the normal data could be the sum of multiple samples */
1309                         if( luxel[ 3 ] > 1.0f )
1310                                 VectorNormalize( normal, normal );
1311                         
1312                         /* mark this luxel as having only one normal */
1313                         luxel[ 3 ] = 1.0f;
1314                 }
1315         }
1316         
1317         /* debug code */
1318         #if 0
1319                 Sys_Printf( "\n" );
1320                 for( y = 0; y < lm->sh; y++ )
1321                 {
1322                         for( x = 0; x < lm->sw; x++ )
1323                         {
1324                                 vec3_t  mins, maxs;
1325                                 
1326
1327                                 cluster = SUPER_CLUSTER( x, y );
1328                                 origin = SUPER_ORIGIN( x, y );
1329                                 normal = SUPER_NORMAL( x, y );
1330                                 luxel = SUPER_LUXEL( x, y );
1331                                 
1332                                 if( *cluster < 0 )
1333                                         continue;
1334                                 
1335                                 /* check if within the bounding boxes of all surfaces referenced */
1336                                 ClearBounds( mins, maxs );
1337                                 for( n = 0; n < lm->numLightSurfaces; n++ )
1338                                 {
1339                                         int TOL;
1340                                         info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + n ] ];
1341                                         TOL = info->sampleSize + 2;
1342                                         AddPointToBounds( info->mins, mins, maxs );
1343                                         AddPointToBounds( info->maxs, mins, maxs );
1344                                         if( origin[ 0 ] > (info->mins[ 0 ] - TOL) && origin[ 0 ] < (info->maxs[ 0 ] + TOL) &&
1345                                                 origin[ 1 ] > (info->mins[ 1 ] - TOL) && origin[ 1 ] < (info->maxs[ 1 ] + TOL) &&
1346                                                 origin[ 2 ] > (info->mins[ 2 ] - TOL) && origin[ 2 ] < (info->maxs[ 2 ] + TOL) )
1347                                                 break;
1348                                 }
1349                                 
1350                                 /* inside? */
1351                                 if( n < lm->numLightSurfaces )
1352                                         continue;
1353                                 
1354                                 /* report bogus origin */
1355                                 Sys_Printf( "%6d [%2d,%2d] (%4d): XYZ(%+4.1f %+4.1f %+4.1f) LO(%+4.1f %+4.1f %+4.1f) HI(%+4.1f %+4.1f %+4.1f) <%3.0f>\n",
1356                                         rawLightmapNum, x, y, *cluster,
1357                                         origin[ 0 ], origin[ 1 ], origin[ 2 ],
1358                                         mins[ 0 ], mins[ 1 ], mins[ 2 ],
1359                                         maxs[ 0 ], maxs[ 1 ], maxs[ 2 ],
1360                                         luxel[ 3 ] );
1361                         }
1362                 }
1363         #endif
1364 }
1365
1366
1367
1368 /*
1369 SetupDirt()
1370 sets up dirtmap (ambient occlusion)
1371 */
1372
1373 #define DIRT_CONE_ANGLE                         88      /* degrees */
1374 #define DIRT_NUM_ANGLE_STEPS            16
1375 #define DIRT_NUM_ELEVATION_STEPS        3
1376 #define DIRT_NUM_VECTORS                        (DIRT_NUM_ANGLE_STEPS * DIRT_NUM_ELEVATION_STEPS)
1377
1378 static vec3_t           dirtVectors[ DIRT_NUM_VECTORS ];
1379 static int                      numDirtVectors = 0;
1380
1381 void SetupDirt( void )
1382 {
1383         int             i, j;
1384         float   angle, elevation, angleStep, elevationStep;
1385         
1386         
1387         /* note it */
1388         Sys_FPrintf( SYS_VRB, "--- SetupDirt ---\n" );
1389         
1390         /* calculate angular steps */
1391         angleStep = DEG2RAD( 360.0f / DIRT_NUM_ANGLE_STEPS );
1392         elevationStep = DEG2RAD( DIRT_CONE_ANGLE / DIRT_NUM_ELEVATION_STEPS );
1393         
1394         /* iterate angle */
1395         angle = 0.0f;
1396         for( i = 0, angle = 0.0f; i < DIRT_NUM_ANGLE_STEPS; i++, angle += angleStep )
1397         {
1398                 /* iterate elevation */
1399                 for( j = 0, elevation = elevationStep * 0.5f; j < DIRT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep )
1400                 {
1401                         dirtVectors[ numDirtVectors ][ 0 ] = sin( elevation ) * cos( angle );
1402                         dirtVectors[ numDirtVectors ][ 1 ] = sin( elevation ) * sin( angle );
1403                         dirtVectors[ numDirtVectors ][ 2 ] = cos( elevation );
1404                         numDirtVectors++;
1405                 }
1406         }
1407         
1408         /* emit some statistics */
1409         Sys_FPrintf( SYS_VRB, "%9d dirtmap vectors\n", numDirtVectors );
1410 }
1411
1412
1413 /*
1414 DirtForSample()
1415 calculates dirt value for a given sample
1416 */
1417
1418 float DirtForSample( trace_t *trace )
1419 {
1420         int             i;
1421         float   gatherDirt, outDirt, angle, elevation, ooDepth;
1422         vec3_t  normal, worldUp, myUp, myRt, temp, direction, displacement;
1423         
1424         
1425         /* dummy check */
1426         if( !dirty )
1427                 return 1.0f;
1428         if( trace == NULL || trace->cluster < 0 )
1429                 return 0.0f;
1430         
1431         /* setup */
1432         gatherDirt = 0.0f;
1433         ooDepth = 1.0f / dirtDepth;
1434         VectorCopy( trace->normal, normal );
1435         
1436         /* check if the normal is aligned to the world-up */
1437         if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f && ( normal[ 2 ] == 1.0f || normal[ 2 ] == -1.0f ) )
1438         {
1439                 if( normal[ 2 ] == 1.0f )               
1440                 {
1441                         VectorSet( myRt, 1.0f, 0.0f, 0.0f );
1442                         VectorSet( myUp, 0.0f, 1.0f, 0.0f );
1443                 }
1444                 else if( normal[ 2 ] == -1.0f )
1445                 {
1446                         VectorSet( myRt, -1.0f, 0.0f, 0.0f );
1447                         VectorSet( myUp,  0.0f, 1.0f, 0.0f );
1448                 }
1449         }
1450         else
1451         {
1452                 VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
1453                 CrossProduct( normal, worldUp, myRt );
1454                 VectorNormalize( myRt, myRt );
1455                 CrossProduct( myRt, normal, myUp );
1456                 VectorNormalize( myUp, myUp );
1457         }
1458         
1459         /* 1 = random mode, 0 (well everything else) = non-random mode */
1460         if( dirtMode == 1 )
1461         {
1462                 /* iterate */
1463                 for( i = 0; i < numDirtVectors; i++ )
1464                 {
1465                         /* get random vector */
1466                         angle = Random() * DEG2RAD( 360.0f );
1467                         elevation = Random() * DEG2RAD( DIRT_CONE_ANGLE );
1468                         temp[ 0 ] = cos( angle ) * sin( elevation );
1469                         temp[ 1 ] = sin( angle ) * sin( elevation );
1470                         temp[ 2 ] = cos( elevation );
1471                         
1472                         /* transform into tangent space */
1473                         direction[ 0 ] = myRt[ 0 ] * temp[ 0 ] + myUp[ 0 ] * temp[ 1 ] + normal[ 0 ] * temp[ 2 ];
1474                         direction[ 1 ] = myRt[ 1 ] * temp[ 0 ] + myUp[ 1 ] * temp[ 1 ] + normal[ 1 ] * temp[ 2 ];
1475                         direction[ 2 ] = myRt[ 2 ] * temp[ 0 ] + myUp[ 2 ] * temp[ 1 ] + normal[ 2 ] * temp[ 2 ];
1476                         
1477                         /* set endpoint */
1478                         VectorMA( trace->origin, dirtDepth, direction, trace->end );
1479                         SetupTrace( trace );
1480                         
1481                         /* trace */
1482                         TraceLine( trace );
1483                         if( trace->opaque && !(trace->compileFlags & C_SKY) )
1484                         {
1485                                 VectorSubtract( trace->hit, trace->origin, displacement );
1486                                 gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1487                         }
1488                 }
1489         }
1490         else
1491         {
1492                 /* iterate through ordered vectors */
1493                 for( i = 0; i < numDirtVectors; i++ )
1494                 {
1495                         /* transform vector into tangent space */
1496                         direction[ 0 ] = myRt[ 0 ] * dirtVectors[ i ][ 0 ] + myUp[ 0 ] * dirtVectors[ i ][ 1 ] + normal[ 0 ] * dirtVectors[ i ][ 2 ];
1497                         direction[ 1 ] = myRt[ 1 ] * dirtVectors[ i ][ 0 ] + myUp[ 1 ] * dirtVectors[ i ][ 1 ] + normal[ 1 ] * dirtVectors[ i ][ 2 ];
1498                         direction[ 2 ] = myRt[ 2 ] * dirtVectors[ i ][ 0 ] + myUp[ 2 ] * dirtVectors[ i ][ 1 ] + normal[ 2 ] * dirtVectors[ i ][ 2 ];
1499                         
1500                         /* set endpoint */
1501                         VectorMA( trace->origin, dirtDepth, direction, trace->end );
1502                         SetupTrace( trace );
1503                         
1504                         /* trace */
1505                         TraceLine( trace );
1506                         if( trace->opaque )
1507                         {
1508                                 VectorSubtract( trace->hit, trace->origin, displacement );
1509                                 gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1510                         }
1511                 }
1512         }
1513         
1514         /* direct ray */
1515         VectorMA( trace->origin, dirtDepth, normal, trace->end );
1516         SetupTrace( trace );
1517         
1518         /* trace */
1519         TraceLine( trace );
1520         if( trace->opaque )
1521         {
1522                 VectorSubtract( trace->hit, trace->origin, displacement );
1523                 gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1524         }
1525         
1526         /* early out */
1527         if( gatherDirt <= 0.0f )
1528                 return 1.0f;
1529         
1530         /* apply gain (does this even do much? heh) */
1531         outDirt = pow( gatherDirt / (numDirtVectors + 1), dirtGain );
1532         if( outDirt > 1.0f )
1533                 outDirt = 1.0f;
1534         
1535         /* apply scale */
1536         outDirt *= dirtScale;
1537         if( outDirt > 1.0f )
1538                 outDirt = 1.0f;
1539         
1540         /* return to sender */
1541         return 1.0f - outDirt;
1542 }
1543
1544
1545
1546 /*
1547 DirtyRawLightmap()
1548 calculates dirty fraction for each luxel
1549 */
1550
1551 void DirtyRawLightmap( int rawLightmapNum )
1552 {
1553         int                                     i, x, y, sx, sy, *cluster;
1554         float                           *origin, *normal, *dirt, *dirt2, average, samples;
1555         rawLightmap_t           *lm;
1556         surfaceInfo_t           *info;
1557         trace_t                         trace;
1558         qboolean                        noDirty;
1559
1560         
1561         /* bail if this number exceeds the number of raw lightmaps */
1562         if( rawLightmapNum >= numRawLightmaps )
1563                 return;
1564         
1565         /* get lightmap */
1566         lm = &rawLightmaps[ rawLightmapNum ];
1567         
1568         /* setup trace */
1569         trace.testOcclusion = qtrue;
1570         trace.forceSunlight = qfalse;
1571         trace.recvShadows = lm->recvShadows;
1572         trace.numSurfaces = lm->numLightSurfaces;
1573         trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
1574         trace.inhibitRadius = 0.0f;
1575         trace.testAll = qfalse;
1576         
1577         /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
1578         trace.twoSided = qfalse;
1579         for( i = 0; i < trace.numSurfaces; i++ )
1580         {
1581                 /* get surface */
1582                 info = &surfaceInfos[ trace.surfaces[ i ] ];
1583                 
1584                 /* check twosidedness */
1585                 if( info->si->twoSided )
1586                 {
1587                         trace.twoSided = qtrue;
1588                         break;
1589                 }
1590         }
1591
1592         noDirty = qfalse;
1593         for( i = 0; i < trace.numSurfaces; i++ )
1594         {
1595                 /* get surface */
1596                 info = &surfaceInfos[ trace.surfaces[ i ] ];
1597
1598                 /* check twosidedness */
1599                 if( info->si->noDirty )
1600                 {
1601                         noDirty = qtrue;
1602                         break;
1603                 }
1604         }
1605         
1606         /* gather dirt */
1607         for( y = 0; y < lm->sh; y++ )
1608         {
1609                 for( x = 0; x < lm->sw; x++ )
1610                 {
1611                         /* get luxel */
1612                         cluster = SUPER_CLUSTER( x, y );
1613                         origin = SUPER_ORIGIN( x, y );
1614                         normal = SUPER_NORMAL( x, y );
1615                         dirt = SUPER_DIRT( x, y );
1616                         
1617                         /* set default dirt */
1618                         *dirt = 0.0f;
1619                         
1620                         /* only look at mapped luxels */
1621                         if( *cluster < 0 )
1622                                 continue;
1623
1624                         /* don't apply dirty on this surface */
1625                         if( noDirty )
1626                         {
1627                                 *dirt = 1.0f;
1628                                 continue;
1629                         }
1630                         
1631                         /* copy to trace */
1632                         trace.cluster = *cluster;
1633                         VectorCopy( origin, trace.origin );
1634                         VectorCopy( normal, trace.normal );
1635                         
1636                         /* get dirt */
1637                         *dirt = DirtForSample( &trace );
1638                 }
1639         }
1640         
1641         /* testing no filtering */
1642         //%     return;
1643         
1644         /* filter dirt */
1645         for( y = 0; y < lm->sh; y++ )
1646         {
1647                 for( x = 0; x < lm->sw; x++ )
1648                 {
1649                         /* get luxel */
1650                         cluster = SUPER_CLUSTER( x, y );
1651                         dirt = SUPER_DIRT( x, y );
1652                         
1653                         /* filter dirt by adjacency to unmapped luxels */
1654                         average = *dirt;
1655                         samples = 1.0f;
1656                         for( sy = (y - 1); sy <= (y + 1); sy++ )
1657                         {
1658                                 if( sy < 0 || sy >= lm->sh )
1659                                         continue;
1660                                 
1661                                 for( sx = (x - 1); sx <= (x + 1); sx++ )
1662                                 {
1663                                         if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
1664                                                 continue;
1665                                         
1666                                         /* get neighboring luxel */
1667                                         cluster = SUPER_CLUSTER( sx, sy );
1668                                         dirt2 = SUPER_DIRT( sx, sy );
1669                                         if( *cluster < 0 || *dirt2 <= 0.0f )
1670                                                 continue;
1671                                         
1672                                         /* add it */
1673                                         average += *dirt2;
1674                                         samples += 1.0f;
1675                                 }
1676                                 
1677                                 /* bail */
1678                                 if( samples <= 0.0f )
1679                                         break;
1680                         }
1681                         
1682                         /* bail */
1683                         if( samples <= 0.0f )
1684                                 continue;
1685                         
1686                         /* scale dirt */
1687                         *dirt = average / samples;
1688                 }
1689         }
1690 }
1691
1692
1693
1694 /*
1695 SubmapRawLuxel()
1696 calculates the pvs cluster, origin, normal of a sub-luxel
1697 */
1698
1699 static qboolean SubmapRawLuxel( rawLightmap_t *lm, int x, int y, float bx, float by, int *sampleCluster, vec3_t sampleOrigin, vec3_t sampleNormal )
1700 {
1701         int                     i, *cluster, *cluster2;
1702         float           *origin, *origin2, *normal;     //%     , *normal2;
1703         vec3_t          originVecs[ 2 ];                        //%     , normalVecs[ 2 ];
1704         
1705         
1706         /* calulate x vector */
1707         if( (x < (lm->sw - 1) && bx >= 0.0f) || (x == 0 && bx <= 0.0f) )
1708         {
1709                 cluster = SUPER_CLUSTER( x, y );
1710                 origin = SUPER_ORIGIN( x, y );
1711                 //%     normal = SUPER_NORMAL( x, y );
1712                 cluster2 = SUPER_CLUSTER( x + 1, y );
1713                 origin2 = *cluster2 < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x + 1, y );
1714                 //%     normal2 = *cluster2 < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x + 1, y );
1715         }
1716         else if( (x > 0 && bx <= 0.0f) || (x == (lm->sw - 1) && bx >= 0.0f) )
1717         {
1718                 cluster = SUPER_CLUSTER( x - 1, y );
1719                 origin = *cluster < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x - 1, y );
1720                 //%     normal = *cluster < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x - 1, y );
1721                 cluster2 = SUPER_CLUSTER( x, y );
1722                 origin2 = SUPER_ORIGIN( x, y );
1723                 //%     normal2 = SUPER_NORMAL( x, y );
1724         }
1725         else
1726         {
1727                 Error( "Spurious lightmap S vector\n" );
1728         }
1729         
1730         VectorSubtract( origin2, origin, originVecs[ 0 ] );
1731         //%     VectorSubtract( normal2, normal, normalVecs[ 0 ] );
1732         
1733         /* calulate y vector */
1734         if( (y < (lm->sh - 1) && bx >= 0.0f) || (y == 0 && bx <= 0.0f) )
1735         {
1736                 cluster = SUPER_CLUSTER( x, y );
1737                 origin = SUPER_ORIGIN( x, y );
1738                 //%     normal = SUPER_NORMAL( x, y );
1739                 cluster2 = SUPER_CLUSTER( x, y + 1 );
1740                 origin2 = *cluster2 < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x, y + 1 );
1741                 //%     normal2 = *cluster2 < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x, y + 1 );
1742         }
1743         else if( (y > 0 && bx <= 0.0f) || (y == (lm->sh - 1) && bx >= 0.0f) )
1744         {
1745                 cluster = SUPER_CLUSTER( x, y - 1 );
1746                 origin = *cluster < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x, y - 1 );
1747                 //%     normal = *cluster < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x, y - 1 );
1748                 cluster2 = SUPER_CLUSTER( x, y );
1749                 origin2 = SUPER_ORIGIN( x, y );
1750                 //%     normal2 = SUPER_NORMAL( x, y );
1751         }
1752         else
1753                 Sys_Printf( "WARNING: Spurious lightmap T vector\n" );
1754         
1755         VectorSubtract( origin2, origin, originVecs[ 1 ] );
1756         //%     VectorSubtract( normal2, normal, normalVecs[ 1 ] );
1757         
1758         /* calculate new origin */
1759         //%     VectorMA( origin, bx, originVecs[ 0 ], sampleOrigin );
1760         //%     VectorMA( sampleOrigin, by, originVecs[ 1 ], sampleOrigin );
1761         for( i = 0; i < 3; i++ )
1762                 sampleOrigin[ i ] = sampleOrigin[ i ] + (bx * originVecs[ 0 ][ i ]) + (by * originVecs[ 1 ][ i ]);
1763         
1764         /* get cluster */
1765         *sampleCluster = ClusterForPointExtFilter( sampleOrigin, (LUXEL_EPSILON * 2), lm->numLightClusters, lm->lightClusters );
1766         if( *sampleCluster < 0 )
1767                 return qfalse;
1768         
1769         /* calculate new normal */
1770         //%     VectorMA( normal, bx, normalVecs[ 0 ], sampleNormal );
1771         //%     VectorMA( sampleNormal, by, normalVecs[ 1 ], sampleNormal );
1772         //%     if( VectorNormalize( sampleNormal, sampleNormal ) <= 0.0f )
1773         //%             return qfalse;
1774         normal = SUPER_NORMAL( x, y );
1775         VectorCopy( normal, sampleNormal );
1776         
1777         /* return ok */
1778         return qtrue;
1779 }
1780
1781
1782 /*
1783 SubsampleRawLuxel_r()
1784 recursively subsamples a luxel until its color gradient is low enough or subsampling limit is reached
1785 */
1786
1787 static void SubsampleRawLuxel_r( rawLightmap_t *lm, trace_t *trace, vec3_t sampleOrigin, int x, int y, float bias, float *lightLuxel, float *lightDeluxel )
1788 {
1789         int                     b, samples, mapped, lighted;
1790         int                     cluster[ 4 ];
1791         vec4_t          luxel[ 4 ];
1792         vec3_t          deluxel[ 3 ];
1793         vec3_t          origin[ 4 ], normal[ 4 ];
1794         float           biasDirs[ 4 ][ 2 ] = { { -1.0f, -1.0f }, { 1.0f, -1.0f }, { -1.0f, 1.0f }, { 1.0f, 1.0f } };
1795         vec3_t          color, direction = { 0, 0, 0 }, total;
1796         
1797         
1798         /* limit check */
1799         if( lightLuxel[ 3 ] >= lightSamples )
1800                 return;
1801         
1802         /* setup */
1803         VectorClear( total );
1804         mapped = 0;
1805         lighted = 0;
1806         
1807         /* make 2x2 subsample stamp */
1808         for( b = 0; b < 4; b++ )
1809         {
1810                 /* set origin */
1811                 VectorCopy( sampleOrigin, origin[ b ] );
1812                 
1813                 /* calculate position */
1814                 if( !SubmapRawLuxel( lm, x, y, (bias * biasDirs[ b ][ 0 ]), (bias * biasDirs[ b ][ 1 ]), &cluster[ b ], origin[ b ], normal[ b ] ) )
1815                 {
1816                         cluster[ b ] = -1;
1817                         continue;
1818                 }
1819                 mapped++;
1820                 
1821                 /* increment sample count */
1822                 luxel[ b ][ 3 ] = lightLuxel[ 3 ] + 1.0f;
1823                 
1824                 /* setup trace */
1825                 trace->cluster = *cluster;
1826                 VectorCopy( origin[ b ], trace->origin );
1827                 VectorCopy( normal[ b ], trace->normal );
1828                 
1829                 /* sample light */
1830
1831                 LightContributionToSample( trace );
1832                 if(trace->forceSubsampling > 1.0f)
1833                 {
1834                         /* alphashadow: we subsample as deep as we can */
1835                         ++lighted;
1836                         ++mapped;
1837                         ++mapped;
1838                 }
1839                 
1840                 /* add to totals (fixme: make contrast function) */
1841                 VectorCopy( trace->color, luxel[ b ] );
1842                 if(lightDeluxel)
1843                 {
1844                         VectorCopy( trace->directionContribution, deluxel[ b ] );
1845                 }
1846                 VectorAdd( total, trace->color, total );
1847                 if( (luxel[ b ][ 0 ] + luxel[ b ][ 1 ] + luxel[ b ][ 2 ]) > 0.0f )
1848                         lighted++;
1849         }
1850         
1851         /* subsample further? */
1852         if( (lightLuxel[ 3 ] + 1.0f) < lightSamples &&
1853                 (total[ 0 ] > 4.0f || total[ 1 ] > 4.0f || total[ 2 ] > 4.0f) &&
1854                 lighted != 0 && lighted != mapped )
1855         {
1856                 for( b = 0; b < 4; b++ )
1857                 {
1858                         if( cluster[ b ] < 0 )
1859                                 continue;
1860                         SubsampleRawLuxel_r( lm, trace, origin[ b ], x, y, (bias * 0.5f), luxel[ b ], lightDeluxel ? deluxel[ b ] : NULL );
1861                 }
1862         }
1863         
1864         /* average */
1865         //%     VectorClear( color );
1866         //%     samples = 0;
1867         VectorCopy( lightLuxel, color );
1868         if(lightDeluxel)
1869         {
1870                 VectorCopy( lightDeluxel, direction );
1871         }
1872         samples = 1;
1873         for( b = 0; b < 4; b++ )
1874         {
1875                 if( cluster[ b ] < 0 )
1876                         continue;
1877                 VectorAdd( color, luxel[ b ], color );
1878                 if(lightDeluxel)
1879                 {
1880                         VectorAdd( direction, deluxel[ b ], direction );
1881                 }
1882                 samples++;
1883         }
1884         
1885         /* add to luxel */
1886         if( samples > 0 )
1887         {
1888                 /* average */
1889                 color[ 0 ] /= samples;
1890                 color[ 1 ] /= samples;
1891                 color[ 2 ] /= samples;
1892
1893                 /* add to color */
1894                 VectorCopy( color, lightLuxel );
1895                 lightLuxel[ 3 ] += 1.0f;
1896
1897                 if(lightDeluxel)
1898                 {
1899                         direction[ 0 ] /= samples;
1900                         direction[ 1 ] /= samples;
1901                         direction[ 2 ] /= samples;
1902                         VectorCopy( direction, lightDeluxel );
1903                 }
1904         }
1905 }
1906
1907 /* A mostly Gaussian-like bounded random distribution (sigma is expected standard deviation) */
1908 static void GaussLikeRandom(float sigma, float *x, float *y)
1909 {
1910         float r;
1911         r = Random() * 2 * Q_PI;
1912         *x = sigma * 2.73861278752581783822 * cos(r);
1913         *y = sigma * 2.73861278752581783822 * sin(r);
1914         r = Random();
1915         r = 1 - sqrt(r);
1916         r = 1 - sqrt(r);
1917         *x *= r;
1918         *y *= r;
1919 }
1920 static void RandomSubsampleRawLuxel( rawLightmap_t *lm, trace_t *trace, vec3_t sampleOrigin, int x, int y, float bias, float *lightLuxel, float *lightDeluxel )
1921 {
1922         int                     b, mapped;
1923         int                     cluster;
1924         vec3_t          origin, normal;
1925         vec3_t          total, totaldirection;
1926         float           dx, dy;
1927         
1928         VectorClear( total );
1929         VectorClear( totaldirection );
1930         mapped = 0;
1931         for(b = 0; b < lightSamples; ++b)
1932         {
1933                 /* set origin */
1934                 VectorCopy( sampleOrigin, origin );
1935                 GaussLikeRandom(bias, &dx, &dy);
1936
1937                 /* calculate position */
1938                 if( !SubmapRawLuxel( lm, x, y, dx, dy, &cluster, origin, normal ) )
1939                 {
1940                         cluster = -1;
1941                         continue;
1942                 }
1943                 mapped++;
1944
1945                 trace->cluster = cluster;
1946                 VectorCopy( origin, trace->origin );
1947                 VectorCopy( normal, trace->normal );
1948
1949                 LightContributionToSample( trace );
1950                 VectorAdd( total, trace->color, total );
1951                 if(lightDeluxel)
1952                 {
1953                         VectorAdd( totaldirection, trace->directionContribution, totaldirection );
1954                 }
1955         }
1956
1957         /* add to luxel */
1958         if( mapped > 0 )
1959         {
1960                 /* average */
1961                 lightLuxel[ 0 ] = total[ 0 ] / mapped;
1962                 lightLuxel[ 1 ] = total[ 1 ] / mapped;
1963                 lightLuxel[ 2 ] = total[ 2 ] / mapped;
1964
1965                 if(lightDeluxel)
1966                 {
1967                         lightDeluxel[ 0 ] = totaldirection[ 0 ] / mapped;
1968                         lightDeluxel[ 1 ] = totaldirection[ 1 ] / mapped;
1969                         lightDeluxel[ 2 ] = totaldirection[ 2 ] / mapped;
1970                 }
1971         }
1972 }
1973
1974
1975
1976 /*
1977 IlluminateRawLightmap()
1978 illuminates the luxels
1979 */
1980
1981 #define STACK_LL_SIZE                   (SUPER_LUXEL_SIZE * 64 * 64)
1982 #define LIGHT_LUXEL( x, y )             (lightLuxels + ((((y) * lm->sw) + (x)) * SUPER_LUXEL_SIZE))
1983 #define LIGHT_DELUXEL( x, y )           (lightDeluxels + ((((y) * lm->sw) + (x)) * SUPER_DELUXEL_SIZE))
1984
1985 void IlluminateRawLightmap( int rawLightmapNum )
1986 {
1987         int                                     i, t, x, y, sx, sy, size, luxelFilterRadius, lightmapNum;
1988         int                                     *cluster, *cluster2, mapped, lighted, totalLighted;
1989         size_t                                  llSize, ldSize;
1990         rawLightmap_t           *lm;
1991         surfaceInfo_t           *info;
1992         qboolean                        filterColor, filterDir;
1993         float                           brightness;
1994         float                           *origin, *normal, *dirt, *luxel, *luxel2, *deluxel, *deluxel2;
1995         unsigned char                   *flag;
1996         float                           *lightLuxels, *lightDeluxels, *lightLuxel, *lightDeluxel, samples, filterRadius, weight;
1997         vec3_t                          color, direction, averageColor, averageDir, total, temp, temp2;
1998         float                           tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
1999         trace_t                         trace;
2000         float                           stackLightLuxels[ STACK_LL_SIZE ];
2001         
2002         
2003         /* bail if this number exceeds the number of raw lightmaps */
2004         if( rawLightmapNum >= numRawLightmaps )
2005                 return;
2006         
2007         /* get lightmap */
2008         lm = &rawLightmaps[ rawLightmapNum ];
2009         
2010         /* setup trace */
2011         trace.testOcclusion = !noTrace;
2012         trace.forceSunlight = qfalse;
2013         trace.recvShadows = lm->recvShadows;
2014         trace.numSurfaces = lm->numLightSurfaces;
2015         trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
2016         trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
2017         
2018         /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
2019         trace.twoSided = qfalse;
2020         for( i = 0; i < trace.numSurfaces; i++ )
2021         {
2022                 /* get surface */
2023                 info = &surfaceInfos[ trace.surfaces[ i ] ];
2024                 
2025                 /* check twosidedness */
2026                 if( info->si->twoSided )
2027                 {
2028                         trace.twoSided = qtrue;
2029                         break;
2030                 }
2031         }
2032         
2033         /* create a culled light list for this raw lightmap */
2034         CreateTraceLightsForBounds( lm->mins, lm->maxs, lm->plane, lm->numLightClusters, lm->lightClusters, LIGHT_SURFACES, &trace );
2035         
2036         /* -----------------------------------------------------------------
2037            fill pass
2038            ----------------------------------------------------------------- */
2039         
2040         /* set counts */
2041         numLuxelsIlluminated += (lm->sw * lm->sh);
2042         
2043         /* test debugging state */
2044         if( debugSurfaces || debugAxis || debugCluster || debugOrigin || dirtDebug || normalmap )
2045         {
2046                 /* debug fill the luxels */
2047                 for( y = 0; y < lm->sh; y++ )
2048                 {
2049                         for( x = 0; x < lm->sw; x++ )
2050                         {
2051                                 /* get cluster */
2052                                 cluster = SUPER_CLUSTER( x, y );
2053
2054                                 /* only fill mapped luxels */
2055                                 if( *cluster < 0 )
2056                                         continue;
2057                                 
2058                                 /* get particulars */
2059                                 luxel = SUPER_LUXEL( 0, x, y );
2060                                 origin = SUPER_ORIGIN( x, y );
2061                                 normal = SUPER_NORMAL( x, y );
2062                                 
2063                                 /* color the luxel with raw lightmap num? */
2064                                 if( debugSurfaces )
2065                                         VectorCopy( debugColors[ rawLightmapNum % 12 ], luxel );
2066                                 
2067                                 /* color the luxel with lightmap axis? */
2068                                 else if( debugAxis )
2069                                 {
2070                                         luxel[ 0 ] = (lm->axis[ 0 ] + 1.0f) * 127.5f;
2071                                         luxel[ 1 ] = (lm->axis[ 1 ] + 1.0f) * 127.5f;
2072                                         luxel[ 2 ] = (lm->axis[ 2 ] + 1.0f) * 127.5f;
2073                                 }
2074                                 
2075                                 /* color the luxel with luxel cluster? */
2076                                 else if( debugCluster )
2077                                         VectorCopy( debugColors[ *cluster % 12 ], luxel );
2078                                 
2079                                 /* color the luxel with luxel origin? */
2080                                 else if( debugOrigin )
2081                                 {
2082                                         VectorSubtract( lm->maxs, lm->mins, temp );
2083                                         VectorScale( temp, (1.0f / 255.0f), temp );
2084                                         VectorSubtract( origin, lm->mins, temp2 );
2085                                         luxel[ 0 ] = lm->mins[ 0 ] + (temp[ 0 ] * temp2[ 0 ]);
2086                                         luxel[ 1 ] = lm->mins[ 1 ] + (temp[ 1 ] * temp2[ 1 ]);
2087                                         luxel[ 2 ] = lm->mins[ 2 ] + (temp[ 2 ] * temp2[ 2 ]);
2088                                 }
2089                                 
2090                                 /* color the luxel with the normal */
2091                                 else if( normalmap )
2092                                 {
2093                                         luxel[ 0 ] = (normal[ 0 ] + 1.0f) * 127.5f;
2094                                         luxel[ 1 ] = (normal[ 1 ] + 1.0f) * 127.5f;
2095                                         luxel[ 2 ] = (normal[ 2 ] + 1.0f) * 127.5f;
2096                                 }
2097                                 
2098                                 /* otherwise clear it */
2099                                 else
2100                                         VectorClear( luxel );
2101                                 
2102                                 /* add to counts */
2103                                 luxel[ 3 ] = 1.0f;
2104                         }
2105                 }
2106         }
2107         else
2108         {
2109                 /* allocate temporary per-light luxel storage */
2110                 llSize = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
2111                 ldSize = lm->sw * lm->sh * SUPER_DELUXEL_SIZE * sizeof( float );
2112                 if( llSize <= (STACK_LL_SIZE * sizeof( float )) )
2113                         lightLuxels = stackLightLuxels;
2114                 else
2115                         lightLuxels = safe_malloc( llSize );
2116                 if(deluxemap)
2117                         lightDeluxels = safe_malloc( ldSize );
2118                 else
2119                         lightDeluxels = NULL;
2120                 
2121                 /* clear luxels */
2122                 //%     memset( lm->superLuxels[ 0 ], 0, llSize );
2123                 
2124                 /* set ambient color */
2125                 for( y = 0; y < lm->sh; y++ )
2126                 {
2127                         for( x = 0; x < lm->sw; x++ )
2128                         {
2129                                 /* get cluster */
2130                                 cluster = SUPER_CLUSTER( x, y );
2131                                 luxel = SUPER_LUXEL( 0, x, y );
2132                                 normal = SUPER_NORMAL( x, y );
2133                                 deluxel = SUPER_DELUXEL( x, y );
2134                                 
2135                                 /* blacken unmapped clusters */
2136                                 if( *cluster < 0 )
2137                                         VectorClear( luxel );
2138                                 
2139                                 /* set ambient */
2140                                 else
2141                                 {
2142                                         VectorCopy( ambientColor, luxel );
2143                                         if( deluxemap )
2144                                         {
2145                                                 brightness = RGBTOGRAY( ambientColor ) * ( 1.0f/255.0f );
2146
2147                                                 // use AT LEAST this amount of contribution from ambient for the deluxemap, fixes points that receive ZERO light
2148                                                 if(brightness < 0.00390625f)
2149                                                         brightness = 0.00390625f;
2150
2151                                                 VectorScale( normal, brightness, deluxel );
2152                                         }
2153                                         luxel[ 3 ] = 1.0f;
2154                                 }
2155                         }
2156                 }
2157                 
2158                 /* clear styled lightmaps */
2159                 size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
2160                 for( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2161                 {
2162                         if( lm->superLuxels[ lightmapNum ] != NULL )
2163                                 memset( lm->superLuxels[ lightmapNum ], 0, size );
2164                 }
2165                 
2166                 /* debugging code */
2167                 //%     if( trace.numLights <= 0 )
2168                 //%             Sys_Printf( "Lightmap %9d: 0 lights, axis: %.2f, %.2f, %.2f\n", rawLightmapNum, lm->axis[ 0 ], lm->axis[ 1 ], lm->axis[ 2 ] );
2169                 
2170                 /* walk light list */
2171                 for( i = 0; i < trace.numLights; i++ )
2172                 {
2173                         /* setup trace */
2174                         trace.light = trace.lights[ i ];
2175                         
2176                         /* style check */
2177                         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2178                         {
2179                                 if( lm->styles[ lightmapNum ] == trace.light->style ||
2180                                         lm->styles[ lightmapNum ] == LS_NONE )
2181                                         break;
2182                         }
2183                         
2184                         /* max of MAX_LIGHTMAPS (4) styles allowed to hit a surface/lightmap */
2185                         if( lightmapNum >= MAX_LIGHTMAPS )
2186                         {
2187                                 Sys_Printf( "WARNING: Hit per-surface style limit (%d)\n", MAX_LIGHTMAPS );
2188                                 continue;
2189                         }
2190                         
2191                         /* setup */
2192                         memset( lightLuxels, 0, llSize );
2193                         if(deluxemap)
2194                                 memset( lightDeluxels, 0, ldSize );
2195                         totalLighted = 0;
2196                         
2197                         /* determine filter radius */
2198                         filterRadius = lm->filterRadius > trace.light->filterRadius
2199                                 ? lm->filterRadius
2200                                 : trace.light->filterRadius;
2201                         if( filterRadius < 0.0f )
2202                                 filterRadius = 0.0f;
2203                         
2204                         /* set luxel filter radius */
2205                         luxelFilterRadius = superSample * filterRadius / lm->sampleSize;
2206                         if( luxelFilterRadius == 0 && (filterRadius > 0.0f || filter) )
2207                                 luxelFilterRadius = 1;
2208
2209                         /* allocate sampling flags storage */
2210                         if((lightSamples > 1 || lightRandomSamples) && luxelFilterRadius == 0)
2211                         {
2212                                 size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( unsigned char );
2213                                 if(lm->superFlags == NULL)
2214                                         lm->superFlags = safe_malloc( size );
2215                                 memset( (void *) lm->superFlags, 0, size );
2216                         }
2217
2218                         /* initial pass, one sample per luxel */
2219                         for( y = 0; y < lm->sh; y++ )
2220                         {
2221                                 for( x = 0; x < lm->sw; x++ )
2222                                 {
2223                                         /* get cluster */
2224                                         cluster = SUPER_CLUSTER( x, y );
2225                                         if( *cluster < 0 )
2226                                                 continue;
2227                                         
2228                                         /* get particulars */
2229                                         lightLuxel = LIGHT_LUXEL( x, y );
2230                                         lightDeluxel = LIGHT_DELUXEL( x, y );
2231                                         origin = SUPER_ORIGIN( x, y );
2232                                         normal = SUPER_NORMAL( x, y );
2233                                         flag = SUPER_FLAG( x, y );
2234
2235 #if 0
2236                                         ////////// 27's temp hack for testing edge clipping ////
2237                                         if( origin[0]==0 && origin[1]==0 && origin[2]==0 )
2238                                         {
2239                                                 lightLuxel[ 1 ] = 255;
2240                                                 lightLuxel[ 3 ] = 1.0f;
2241                                                 totalLighted++;
2242                                         }
2243                                         else
2244 #endif
2245                                         {
2246                                                 /* set contribution count */
2247                                                 lightLuxel[ 3 ] = 1.0f;
2248
2249                                                 /* setup trace */
2250                                                 trace.cluster = *cluster;
2251                                                 VectorCopy( origin, trace.origin );
2252                                                 VectorCopy( normal, trace.normal );
2253
2254                                                 /* get light for this sample */
2255                                                 LightContributionToSample( &trace );
2256                                                 VectorCopy( trace.color, lightLuxel );
2257
2258                                                 /* add the contribution to the deluxemap */
2259                                                 if( deluxemap )
2260                                                 {
2261                                                         VectorCopy( trace.directionContribution, lightDeluxel );
2262                                                 }
2263
2264                                                 /* check for evilness */
2265                                                 if(trace.forceSubsampling > 1.0f && (lightSamples > 1 || lightRandomSamples) && luxelFilterRadius == 0)
2266                                                 {
2267                                                         totalLighted++;
2268                                                         *flag |= FLAG_FORCE_SUBSAMPLING; /* force */
2269                                                 }
2270                                                 /* add to count */
2271                                                 else if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
2272                                                         totalLighted++;
2273                                         }
2274                                 }
2275                         }
2276                         
2277                         /* don't even bother with everything else if nothing was lit */
2278                         if( totalLighted == 0 )
2279                                 continue;
2280                         
2281                         /* secondary pass, adaptive supersampling (fixme: use a contrast function to determine if subsampling is necessary) */
2282                         /* 2003-09-27: changed it so filtering disamples supersampling, as it would waste time */
2283                         if( (lightSamples > 1 || lightRandomSamples) && luxelFilterRadius == 0 )
2284                         {
2285                                 /* walk luxels */
2286                                 for( y = 0; y < (lm->sh - 1); y++ )
2287                                 {
2288                                         for( x = 0; x < (lm->sw - 1); x++ )
2289                                         {
2290                                                 /* setup */
2291                                                 mapped = 0;
2292                                                 lighted = 0;
2293                                                 VectorClear( total );
2294                                                 
2295                                                 /* test 2x2 stamp */
2296                                                 for( t = 0; t < 4; t++ )
2297                                                 {
2298                                                         /* set sample coords */
2299                                                         sx = x + tests[ t ][ 0 ];
2300                                                         sy = y + tests[ t ][ 1 ];
2301                                                         
2302                                                         /* get cluster */
2303                                                         cluster = SUPER_CLUSTER( sx, sy );
2304                                                         if( *cluster < 0 )
2305                                                                 continue;
2306                                                         mapped++;
2307                                                         
2308                                                         /* get luxel */
2309                                                         flag = SUPER_FLAG( sx, sy );
2310                                                         if(*flag & FLAG_FORCE_SUBSAMPLING)
2311                                                         {
2312                                                                 /* force a lighted/mapped discrepancy so we subsample */
2313                                                                 ++lighted;
2314                                                                 ++mapped;
2315                                                                 ++mapped;
2316                                                         }
2317                                                         lightLuxel = LIGHT_LUXEL( sx, sy );
2318                                                         VectorAdd( total, lightLuxel, total );
2319                                                         if( (lightLuxel[ 0 ] + lightLuxel[ 1 ] + lightLuxel[ 2 ]) > 0.0f )
2320                                                                 lighted++;
2321                                                 }
2322                                                 
2323                                                 /* if total color is under a certain amount, then don't bother subsampling */
2324                                                 if( total[ 0 ] <= 4.0f && total[ 1 ] <= 4.0f && total[ 2 ] <= 4.0f )
2325                                                         continue;
2326                                                 
2327                                                 /* if all 4 pixels are either in shadow or light, then don't subsample */
2328                                                 if( lighted != 0 && lighted != mapped )
2329                                                 {
2330                                                         for( t = 0; t < 4; t++ )
2331                                                         {
2332                                                                 /* set sample coords */
2333                                                                 sx = x + tests[ t ][ 0 ];
2334                                                                 sy = y + tests[ t ][ 1 ];
2335                                                                 
2336                                                                 /* get luxel */
2337                                                                 cluster = SUPER_CLUSTER( sx, sy );
2338                                                                 if( *cluster < 0 )
2339                                                                         continue;
2340                                                                 flag = SUPER_FLAG( sx, sy );
2341                                                                 if(*flag & FLAG_ALREADY_SUBSAMPLED) // already subsampled
2342                                                                         continue;
2343                                                                 lightLuxel = LIGHT_LUXEL( sx, sy );
2344                                                                 lightDeluxel = LIGHT_DELUXEL( sx, sy );
2345                                                                 origin = SUPER_ORIGIN( sx, sy );
2346                                                                 
2347                                                                 /* only subsample shadowed luxels */
2348                                                                 //%     if( (lightLuxel[ 0 ] + lightLuxel[ 1 ] + lightLuxel[ 2 ]) <= 0.0f )
2349                                                                 //%             continue;
2350                                                                 
2351                                                                 /* subsample it */
2352                                                                 if(lightRandomSamples)
2353                                                                         RandomSubsampleRawLuxel( lm, &trace, origin, sx, sy, 0.5f * lightSamplesSearchBoxSize, lightLuxel, deluxemap ? lightDeluxel : NULL );
2354                                                                 else
2355                                                                         SubsampleRawLuxel_r( lm, &trace, origin, sx, sy, 0.25f * lightSamplesSearchBoxSize, lightLuxel, deluxemap ? lightDeluxel : NULL );
2356
2357                                                                 *flag |= FLAG_ALREADY_SUBSAMPLED;
2358                                                                 
2359                                                                 /* debug code to colorize subsampled areas to yellow */
2360                                                                 //%     luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2361                                                                 //%     VectorSet( luxel, 255, 204, 0 );
2362                                                         }
2363                                                 }
2364                                         }
2365                                 }
2366                         }
2367                         
2368                         /* tertiary pass, apply dirt map (ambient occlusion) */
2369                         if( 0 && dirty )
2370                         {
2371                                 /* walk luxels */
2372                                 for( y = 0; y < lm->sh; y++ )
2373                                 {
2374                                         for( x = 0; x < lm->sw; x++ )
2375                                         {
2376                                                 /* get cluster  */
2377                                                 cluster = SUPER_CLUSTER( x, y );
2378                                                 if( *cluster < 0 )
2379                                                         continue;
2380                                                 
2381                                                 /* get particulars */
2382                                                 lightLuxel = LIGHT_LUXEL( x, y );
2383                                                 dirt = SUPER_DIRT( x, y );
2384                                                 
2385                                                 /* scale light value */
2386                                                 VectorScale( lightLuxel, *dirt, lightLuxel );
2387                                         }
2388                                 }
2389                         }
2390                         
2391                         /* allocate sampling lightmap storage */
2392                         if( lm->superLuxels[ lightmapNum ] == NULL )
2393                         {
2394                                 /* allocate sampling lightmap storage */
2395                                 size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
2396                                 lm->superLuxels[ lightmapNum ] = safe_malloc( size );
2397                                 memset( lm->superLuxels[ lightmapNum ], 0, size );
2398                         }
2399
2400                         /* set style */
2401                         if( lightmapNum > 0 )
2402                         {
2403                                 lm->styles[ lightmapNum ] = trace.light->style;
2404                                 //%     Sys_Printf( "Surface %6d has lightstyle %d\n", rawLightmapNum, trace.light->style );
2405                         }
2406                         
2407                         /* copy to permanent luxels */
2408                         for( y = 0; y < lm->sh; y++ )
2409                         {
2410                                 for( x = 0; x < lm->sw; x++ )
2411                                 {
2412                                         /* get cluster and origin */
2413                                         cluster = SUPER_CLUSTER( x, y );
2414                                         if( *cluster < 0 )
2415                                                 continue;
2416                                         origin = SUPER_ORIGIN( x, y );
2417                                         
2418                                         /* filter? */
2419                                         if( luxelFilterRadius )
2420                                         {
2421                                                 /* setup */
2422                                                 VectorClear( averageColor );
2423                                                 VectorClear( averageDir );
2424                                                 samples = 0.0f;
2425                                                 
2426                                                 /* cheaper distance-based filtering */
2427                                                 for( sy = (y - luxelFilterRadius); sy <= (y + luxelFilterRadius); sy++ )
2428                                                 {
2429                                                         if( sy < 0 || sy >= lm->sh )
2430                                                                 continue;
2431                                                         
2432                                                         for( sx = (x - luxelFilterRadius); sx <= (x + luxelFilterRadius); sx++ )
2433                                                         {
2434                                                                 if( sx < 0 || sx >= lm->sw )
2435                                                                         continue;
2436                                                                 
2437                                                                 /* get particulars */
2438                                                                 cluster = SUPER_CLUSTER( sx, sy );
2439                                                                 if( *cluster < 0 )
2440                                                                         continue;
2441                                                                 lightLuxel = LIGHT_LUXEL( sx, sy );
2442                                                                 lightDeluxel = LIGHT_DELUXEL( sx, sy );
2443                                                                 
2444                                                                 /* create weight */
2445                                                                 weight = (abs( sx - x ) == luxelFilterRadius ? 0.5f : 1.0f);
2446                                                                 weight *= (abs( sy - y ) == luxelFilterRadius ? 0.5f : 1.0f);
2447                                                                 
2448                                                                 /* scale luxel by filter weight */
2449                                                                 VectorScale( lightLuxel, weight, color );
2450                                                                 VectorAdd( averageColor, color, averageColor );
2451                                                                 if(deluxemap)
2452                                                                 {
2453                                                                         VectorScale( lightDeluxel, weight, direction );
2454                                                                         VectorAdd( averageDir, direction, averageDir );
2455                                                                 }
2456                                                                 samples += weight;
2457                                                         }
2458                                                 }
2459                                                 
2460                                                 /* any samples? */
2461                                                 if( samples <= 0.0f     )
2462                                                         continue;
2463                                                 
2464                                                 /* scale into luxel */
2465                                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
2466                                                 luxel[ 3 ] = 1.0f;
2467                                                 
2468                                                 /* handle negative light */
2469                                                 if( trace.light->flags & LIGHT_NEGATIVE )
2470                                                 { 
2471                                                         luxel[ 0 ] -= averageColor[ 0 ] / samples;
2472                                                         luxel[ 1 ] -= averageColor[ 1 ] / samples;
2473                                                         luxel[ 2 ] -= averageColor[ 2 ] / samples;
2474                                                 }
2475                                                 
2476                                                 /* handle normal light */
2477                                                 else
2478                                                 { 
2479                                                         luxel[ 0 ] += averageColor[ 0 ] / samples;
2480                                                         luxel[ 1 ] += averageColor[ 1 ] / samples;
2481                                                         luxel[ 2 ] += averageColor[ 2 ] / samples;
2482                                                 }
2483                                                 
2484                                                 if(deluxemap)
2485                                                 {
2486                                                         /* scale into luxel */
2487                                                         deluxel = SUPER_DELUXEL( x, y );
2488                                                         deluxel[ 0 ] += averageDir[ 0 ] / samples;
2489                                                         deluxel[ 1 ] += averageDir[ 1 ] / samples;
2490                                                         deluxel[ 2 ] += averageDir[ 2 ] / samples;
2491                                                 }
2492                                         }
2493                                         
2494                                         /* single sample */
2495                                         else
2496                                         {
2497                                                 /* get particulars */
2498                                                 lightLuxel = LIGHT_LUXEL( x, y );
2499                                                 lightDeluxel = LIGHT_DELUXEL( x, y );
2500                                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
2501                                                 deluxel = SUPER_DELUXEL( x, y );
2502                                                 
2503                                                 /* handle negative light */
2504                                                 if( trace.light->flags & LIGHT_NEGATIVE )
2505                                                         VectorScale( averageColor, -1.0f, averageColor );
2506
2507                                                 /* add color */
2508                                                 luxel[ 3 ] = 1.0f;
2509                                                 
2510                                                 /* handle negative light */
2511                                                 if( trace.light->flags & LIGHT_NEGATIVE )
2512                                                         VectorSubtract( luxel, lightLuxel, luxel );
2513                                                 
2514                                                 /* handle normal light */
2515                                                 else
2516                                                         VectorAdd( luxel, lightLuxel, luxel );
2517
2518                                                 if(deluxemap)
2519                                                 {
2520                                                         VectorAdd( deluxel, lightDeluxel, deluxel );
2521                                                 }
2522                                         }
2523                                 }
2524                         }
2525                 }
2526                 
2527                 /* free temporary luxels */
2528                 if( lightLuxels != stackLightLuxels )
2529                         free( lightLuxels );
2530                 
2531                 if(deluxemap)
2532                         free( lightDeluxels );
2533         }
2534         
2535         /* free light list */
2536         FreeTraceLights( &trace );
2537         
2538         /* floodlight pass */
2539         if( floodlighty )
2540                 FloodlightIlluminateLightmap(lm);
2541
2542         if (debugnormals)
2543         {
2544                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2545                 {
2546                         /* early out */
2547                         if( lm->superLuxels[ lightmapNum ] == NULL )
2548                                 continue;
2549                         
2550                         for( y = 0; y < lm->sh; y++ )
2551                         {
2552                                 for( x = 0; x < lm->sw; x++ )
2553                                 {
2554                                         /* get cluster */
2555                                         cluster = SUPER_CLUSTER( x, y );
2556                                         //%     if( *cluster < 0 )
2557                                         //%             continue;
2558                                         
2559                                         /* get particulars */
2560                                         luxel = SUPER_LUXEL( lightmapNum, x, y );
2561                                         normal = SUPER_NORMAL (  x, y );
2562                
2563                                         luxel[0]=(normal[0]*127)+127;
2564                                         luxel[1]=(normal[1]*127)+127;
2565                                         luxel[2]=(normal[2]*127)+127;
2566                                 }
2567                         }
2568                 }
2569         }
2570         
2571         /*      -----------------------------------------------------------------
2572                 dirt pass
2573                 ----------------------------------------------------------------- */
2574         
2575         if( dirty )
2576         {
2577                 /* walk lightmaps */
2578                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2579                 {
2580                         /* early out */
2581                         if( lm->superLuxels[ lightmapNum ] == NULL )
2582                                 continue;
2583                         
2584                         /* apply dirt to each luxel */
2585                         for( y = 0; y < lm->sh; y++ )
2586                         {
2587                                 for( x = 0; x < lm->sw; x++ )
2588                                 {
2589                                         /* get cluster */
2590                                         cluster = SUPER_CLUSTER( x, y );
2591                                         //%     if( *cluster < 0 ) // TODO why not do this check? These pixels should be zero anyway
2592                                         //%             continue;
2593                                         
2594                                         /* get particulars */
2595                                         luxel = SUPER_LUXEL( lightmapNum, x, y );
2596                                         dirt = SUPER_DIRT( x, y );
2597                                         
2598                                         /* apply dirt */
2599                                         VectorScale( luxel, *dirt, luxel );
2600                                         
2601                                         /* debugging */
2602                                         if( dirtDebug )
2603                                                 VectorSet( luxel, *dirt * 255.0f, *dirt * 255.0f, *dirt * 255.0f );
2604                                 }
2605                         }
2606                 }
2607         }
2608         
2609         /* -----------------------------------------------------------------
2610            filter pass
2611            ----------------------------------------------------------------- */
2612         
2613         /* walk lightmaps */
2614         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2615         {
2616                 /* early out */
2617                 if( lm->superLuxels[ lightmapNum ] == NULL )
2618                         continue;
2619