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