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