]> icculus.org git repositories - divverent/netradiant.git/blob - tools/quake3/q3map2/light_ydnar.c
some warning fixes
[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 = { 0, 0, 0 }, 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         if(lightDeluxel)
1865         {
1866                 VectorCopy( lightDeluxel, direction );
1867         }
1868         samples = 1;
1869         for( b = 0; b < 4; b++ )
1870         {
1871                 if( cluster[ b ] < 0 )
1872                         continue;
1873                 VectorAdd( color, luxel[ b ], color );
1874                 if(lightDeluxel)
1875                 {
1876                         VectorAdd( direction, deluxel[ b ], direction );
1877                 }
1878                 samples++;
1879         }
1880         
1881         /* add to luxel */
1882         if( samples > 0 )
1883         {
1884                 /* average */
1885                 color[ 0 ] /= samples;
1886                 color[ 1 ] /= samples;
1887                 color[ 2 ] /= samples;
1888
1889                 /* add to color */
1890                 VectorCopy( color, lightLuxel );
1891                 lightLuxel[ 3 ] += 1.0f;
1892
1893                 if(lightDeluxel)
1894                 {
1895                         direction[ 0 ] /= samples;
1896                         direction[ 1 ] /= samples;
1897                         direction[ 2 ] /= samples;
1898                         VectorCopy( direction, lightDeluxel );
1899                 }
1900         }
1901 }
1902
1903 /* A mostly Gaussian-like bounded random distribution (sigma is expected standard deviation) */
1904 static void GaussLikeRandom(float sigma, float *x, float *y)
1905 {
1906         float r;
1907         r = Random() * 2 * Q_PI;
1908         *x = sigma * 2.73861278752581783822 * cos(r);
1909         *y = sigma * 2.73861278752581783822 * sin(r);
1910         r = Random();
1911         r = 1 - sqrt(r);
1912         r = 1 - sqrt(r);
1913         *x *= r;
1914         *y *= r;
1915 }
1916 static void RandomSubsampleRawLuxel( rawLightmap_t *lm, trace_t *trace, vec3_t sampleOrigin, int x, int y, float bias, float *lightLuxel, float *lightDeluxel )
1917 {
1918         int                     b, mapped;
1919         int                     cluster;
1920         vec3_t          origin, normal;
1921         vec3_t          total, totaldirection;
1922         float           dx, dy;
1923         
1924         VectorClear( total );
1925         VectorClear( totaldirection );
1926         mapped = 0;
1927         for(b = 0; b < lightSamples; ++b)
1928         {
1929                 /* set origin */
1930                 VectorCopy( sampleOrigin, origin );
1931                 GaussLikeRandom(bias, &dx, &dy);
1932
1933                 /* calculate position */
1934                 if( !SubmapRawLuxel( lm, x, y, dx, dy, &cluster, origin, normal ) )
1935                 {
1936                         cluster = -1;
1937                         continue;
1938                 }
1939                 mapped++;
1940
1941                 trace->cluster = cluster;
1942                 VectorCopy( origin, trace->origin );
1943                 VectorCopy( normal, trace->normal );
1944
1945                 LightContributionToSample( trace );
1946                 VectorAdd( total, trace->color, total );
1947                 if(lightDeluxel)
1948                 {
1949                         VectorAdd( totaldirection, trace->directionContribution, totaldirection );
1950                 }
1951         }
1952
1953         /* add to luxel */
1954         if( mapped > 0 )
1955         {
1956                 /* average */
1957                 lightLuxel[ 0 ] = total[ 0 ] / mapped;
1958                 lightLuxel[ 1 ] = total[ 1 ] / mapped;
1959                 lightLuxel[ 2 ] = total[ 2 ] / mapped;
1960
1961                 if(lightDeluxel)
1962                 {
1963                         lightDeluxel[ 0 ] = totaldirection[ 0 ] / mapped;
1964                         lightDeluxel[ 1 ] = totaldirection[ 1 ] / mapped;
1965                         lightDeluxel[ 2 ] = totaldirection[ 2 ] / mapped;
1966                 }
1967         }
1968 }
1969
1970
1971
1972 /*
1973 IlluminateRawLightmap()
1974 illuminates the luxels
1975 */
1976
1977 #define STACK_LL_SIZE                   (SUPER_LUXEL_SIZE * 64 * 64)
1978 #define LIGHT_LUXEL( x, y )             (lightLuxels + ((((y) * lm->sw) + (x)) * SUPER_LUXEL_SIZE))
1979 #define LIGHT_DELUXEL( x, y )           (lightDeluxels + ((((y) * lm->sw) + (x)) * SUPER_DELUXEL_SIZE))
1980
1981 void IlluminateRawLightmap( int rawLightmapNum )
1982 {
1983         int                                     i, t, x, y, sx, sy, size, luxelFilterRadius, lightmapNum;
1984         int                                     *cluster, *cluster2, mapped, lighted, totalLighted;
1985         size_t                                  llSize, ldSize;
1986         rawLightmap_t           *lm;
1987         surfaceInfo_t           *info;
1988         qboolean                        filterColor, filterDir;
1989         float                           brightness;
1990         float                           *origin, *normal, *dirt, *luxel, *luxel2, *deluxel, *deluxel2;
1991         unsigned char                   *flag;
1992         float                           *lightLuxels, *lightDeluxels, *lightLuxel, *lightDeluxel, samples, filterRadius, weight;
1993         vec3_t                          color, direction, averageColor, averageDir, total, temp, temp2;
1994         float                           tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
1995         trace_t                         trace;
1996         float                           stackLightLuxels[ STACK_LL_SIZE ];
1997         
1998         
1999         /* bail if this number exceeds the number of raw lightmaps */
2000         if( rawLightmapNum >= numRawLightmaps )
2001                 return;
2002         
2003         /* get lightmap */
2004         lm = &rawLightmaps[ rawLightmapNum ];
2005         
2006         /* setup trace */
2007         trace.testOcclusion = !noTrace;
2008         trace.forceSunlight = qfalse;
2009         trace.recvShadows = lm->recvShadows;
2010         trace.numSurfaces = lm->numLightSurfaces;
2011         trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
2012         trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
2013         
2014         /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
2015         trace.twoSided = qfalse;
2016         for( i = 0; i < trace.numSurfaces; i++ )
2017         {
2018                 /* get surface */
2019                 info = &surfaceInfos[ trace.surfaces[ i ] ];
2020                 
2021                 /* check twosidedness */
2022                 if( info->si->twoSided )
2023                 {
2024                         trace.twoSided = qtrue;
2025                         break;
2026                 }
2027         }
2028         
2029         /* create a culled light list for this raw lightmap */
2030         CreateTraceLightsForBounds( lm->mins, lm->maxs, lm->plane, lm->numLightClusters, lm->lightClusters, LIGHT_SURFACES, &trace );
2031         
2032         /* -----------------------------------------------------------------
2033            fill pass
2034            ----------------------------------------------------------------- */
2035         
2036         /* set counts */
2037         numLuxelsIlluminated += (lm->sw * lm->sh);
2038         
2039         /* test debugging state */
2040         if( debugSurfaces || debugAxis || debugCluster || debugOrigin || dirtDebug || normalmap )
2041         {
2042                 /* debug fill the luxels */
2043                 for( y = 0; y < lm->sh; y++ )
2044                 {
2045                         for( x = 0; x < lm->sw; x++ )
2046                         {
2047                                 /* get cluster */
2048                                 cluster = SUPER_CLUSTER( x, y );
2049
2050                                 /* only fill mapped luxels */
2051                                 if( *cluster < 0 )
2052                                         continue;
2053                                 
2054                                 /* get particulars */
2055                                 luxel = SUPER_LUXEL( 0, x, y );
2056                                 origin = SUPER_ORIGIN( x, y );
2057                                 normal = SUPER_NORMAL( x, y );
2058                                 
2059                                 /* color the luxel with raw lightmap num? */
2060                                 if( debugSurfaces )
2061                                         VectorCopy( debugColors[ rawLightmapNum % 12 ], luxel );
2062                                 
2063                                 /* color the luxel with lightmap axis? */
2064                                 else if( debugAxis )
2065                                 {
2066                                         luxel[ 0 ] = (lm->axis[ 0 ] + 1.0f) * 127.5f;
2067                                         luxel[ 1 ] = (lm->axis[ 1 ] + 1.0f) * 127.5f;
2068                                         luxel[ 2 ] = (lm->axis[ 2 ] + 1.0f) * 127.5f;
2069                                 }
2070                                 
2071                                 /* color the luxel with luxel cluster? */
2072                                 else if( debugCluster )
2073                                         VectorCopy( debugColors[ *cluster % 12 ], luxel );
2074                                 
2075                                 /* color the luxel with luxel origin? */
2076                                 else if( debugOrigin )
2077                                 {
2078                                         VectorSubtract( lm->maxs, lm->mins, temp );
2079                                         VectorScale( temp, (1.0f / 255.0f), temp );
2080                                         VectorSubtract( origin, lm->mins, temp2 );
2081                                         luxel[ 0 ] = lm->mins[ 0 ] + (temp[ 0 ] * temp2[ 0 ]);
2082                                         luxel[ 1 ] = lm->mins[ 1 ] + (temp[ 1 ] * temp2[ 1 ]);
2083                                         luxel[ 2 ] = lm->mins[ 2 ] + (temp[ 2 ] * temp2[ 2 ]);
2084                                 }
2085                                 
2086                                 /* color the luxel with the normal */
2087                                 else if( normalmap )
2088                                 {
2089                                         luxel[ 0 ] = (normal[ 0 ] + 1.0f) * 127.5f;
2090                                         luxel[ 1 ] = (normal[ 1 ] + 1.0f) * 127.5f;
2091                                         luxel[ 2 ] = (normal[ 2 ] + 1.0f) * 127.5f;
2092                                 }
2093                                 
2094                                 /* otherwise clear it */
2095                                 else
2096                                         VectorClear( luxel );
2097                                 
2098                                 /* add to counts */
2099                                 luxel[ 3 ] = 1.0f;
2100                         }
2101                 }
2102         }
2103         else
2104         {
2105                 /* allocate temporary per-light luxel storage */
2106                 llSize = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
2107                 ldSize = lm->sw * lm->sh * SUPER_DELUXEL_SIZE * sizeof( float );
2108                 if( llSize <= (STACK_LL_SIZE * sizeof( float )) )
2109                         lightLuxels = stackLightLuxels;
2110                 else
2111                         lightLuxels = safe_malloc( llSize );
2112                 if(deluxemap)
2113                         lightDeluxels = safe_malloc( ldSize );
2114                 else
2115                         lightDeluxels = NULL;
2116                 
2117                 /* clear luxels */
2118                 //%     memset( lm->superLuxels[ 0 ], 0, llSize );
2119                 
2120                 /* set ambient color */
2121                 for( y = 0; y < lm->sh; y++ )
2122                 {
2123                         for( x = 0; x < lm->sw; x++ )
2124                         {
2125                                 /* get cluster */
2126                                 cluster = SUPER_CLUSTER( x, y );
2127                                 luxel = SUPER_LUXEL( 0, x, y );
2128                                 normal = SUPER_NORMAL( x, y );
2129                                 deluxel = SUPER_DELUXEL( x, y );
2130                                 
2131                                 /* blacken unmapped clusters */
2132                                 if( *cluster < 0 )
2133                                         VectorClear( luxel );
2134                                 
2135                                 /* set ambient */
2136                                 else
2137                                 {
2138                                         VectorCopy( ambientColor, luxel );
2139                                         if( deluxemap )
2140                                         {
2141                                                 brightness = RGBTOGRAY( ambientColor ) * ( 1.0f/255.0f );
2142
2143                                                 // use AT LEAST this amount of contribution from ambient for the deluxemap, fixes points that receive ZERO light
2144                                                 if(brightness < 0.00390625f)
2145                                                         brightness = 0.00390625f;
2146
2147                                                 VectorScale( normal, brightness, deluxel );
2148                                         }
2149                                         luxel[ 3 ] = 1.0f;
2150                                 }
2151                         }
2152                 }
2153                 
2154                 /* clear styled lightmaps */
2155                 size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
2156                 for( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2157                 {
2158                         if( lm->superLuxels[ lightmapNum ] != NULL )
2159                                 memset( lm->superLuxels[ lightmapNum ], 0, size );
2160                 }
2161                 
2162                 /* debugging code */
2163                 //%     if( trace.numLights <= 0 )
2164                 //%             Sys_Printf( "Lightmap %9d: 0 lights, axis: %.2f, %.2f, %.2f\n", rawLightmapNum, lm->axis[ 0 ], lm->axis[ 1 ], lm->axis[ 2 ] );
2165                 
2166                 /* walk light list */
2167                 for( i = 0; i < trace.numLights; i++ )
2168                 {
2169                         /* setup trace */
2170                         trace.light = trace.lights[ i ];
2171                         
2172                         /* style check */
2173                         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2174                         {
2175                                 if( lm->styles[ lightmapNum ] == trace.light->style ||
2176                                         lm->styles[ lightmapNum ] == LS_NONE )
2177                                         break;
2178                         }
2179                         
2180                         /* max of MAX_LIGHTMAPS (4) styles allowed to hit a surface/lightmap */
2181                         if( lightmapNum >= MAX_LIGHTMAPS )
2182                         {
2183                                 Sys_Printf( "WARNING: Hit per-surface style limit (%d)\n", MAX_LIGHTMAPS );
2184                                 continue;
2185                         }
2186                         
2187                         /* setup */
2188                         memset( lightLuxels, 0, llSize );
2189                         if(deluxemap)
2190                                 memset( lightDeluxels, 0, ldSize );
2191                         totalLighted = 0;
2192                         
2193                         /* determine filter radius */
2194                         filterRadius = lm->filterRadius > trace.light->filterRadius
2195                                 ? lm->filterRadius
2196                                 : trace.light->filterRadius;
2197                         if( filterRadius < 0.0f )
2198                                 filterRadius = 0.0f;
2199                         
2200                         /* set luxel filter radius */
2201                         luxelFilterRadius = superSample * filterRadius / lm->sampleSize;
2202                         if( luxelFilterRadius == 0 && (filterRadius > 0.0f || filter) )
2203                                 luxelFilterRadius = 1;
2204
2205                         /* allocate sampling flags storage */
2206                         if((lightSamples > 1 || lightRandomSamples) && luxelFilterRadius == 0)
2207                         {
2208                                 size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( unsigned char );
2209                                 if(lm->superFlags == NULL)
2210                                         lm->superFlags = safe_malloc( size );
2211                                 memset( (void *) lm->superFlags, 0, size );
2212                         }
2213
2214                         /* initial pass, one sample per luxel */
2215                         for( y = 0; y < lm->sh; y++ )
2216                         {
2217                                 for( x = 0; x < lm->sw; x++ )
2218                                 {
2219                                         /* get cluster */
2220                                         cluster = SUPER_CLUSTER( x, y );
2221                                         if( *cluster < 0 )
2222                                                 continue;
2223                                         
2224                                         /* get particulars */
2225                                         lightLuxel = LIGHT_LUXEL( x, y );
2226                                         lightDeluxel = LIGHT_DELUXEL( x, y );
2227                                         origin = SUPER_ORIGIN( x, y );
2228                                         normal = SUPER_NORMAL( x, y );
2229                                         flag = SUPER_FLAG( x, y );
2230
2231 #if 0
2232                                         ////////// 27's temp hack for testing edge clipping ////
2233                                         if( origin[0]==0 && origin[1]==0 && origin[2]==0 )
2234                                         {
2235                                                 lightLuxel[ 1 ] = 255;
2236                                                 lightLuxel[ 3 ] = 1.0f;
2237                                                 totalLighted++;
2238                                         }
2239                                         else
2240 #endif
2241                                         {
2242                                                 /* set contribution count */
2243                                                 lightLuxel[ 3 ] = 1.0f;
2244
2245                                                 /* setup trace */
2246                                                 trace.cluster = *cluster;
2247                                                 VectorCopy( origin, trace.origin );
2248                                                 VectorCopy( normal, trace.normal );
2249
2250                                                 /* get light for this sample */
2251                                                 LightContributionToSample( &trace );
2252                                                 VectorCopy( trace.color, lightLuxel );
2253
2254                                                 /* add the contribution to the deluxemap */
2255                                                 if( deluxemap )
2256                                                 {
2257                                                         VectorCopy( trace.directionContribution, lightDeluxel );
2258                                                 }
2259
2260                                                 /* check for evilness */
2261                                                 if(trace.forceSubsampling > 1.0f && (lightSamples > 1 || lightRandomSamples) && luxelFilterRadius == 0)
2262                                                 {
2263                                                         totalLighted++;
2264                                                         *flag |= FLAG_FORCE_SUBSAMPLING; /* force */
2265                                                 }
2266                                                 /* add to count */
2267                                                 else if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
2268                                                         totalLighted++;
2269                                         }
2270                                 }
2271                         }
2272                         
2273                         /* don't even bother with everything else if nothing was lit */
2274                         if( totalLighted == 0 )
2275                                 continue;
2276                         
2277                         /* secondary pass, adaptive supersampling (fixme: use a contrast function to determine if subsampling is necessary) */
2278                         /* 2003-09-27: changed it so filtering disamples supersampling, as it would waste time */
2279                         if( (lightSamples > 1 || lightRandomSamples) && luxelFilterRadius == 0 )
2280                         {
2281                                 /* walk luxels */
2282                                 for( y = 0; y < (lm->sh - 1); y++ )
2283                                 {
2284                                         for( x = 0; x < (lm->sw - 1); x++ )
2285                                         {
2286                                                 /* setup */
2287                                                 mapped = 0;
2288                                                 lighted = 0;
2289                                                 VectorClear( total );
2290                                                 
2291                                                 /* test 2x2 stamp */
2292                                                 for( t = 0; t < 4; t++ )
2293                                                 {
2294                                                         /* set sample coords */
2295                                                         sx = x + tests[ t ][ 0 ];
2296                                                         sy = y + tests[ t ][ 1 ];
2297                                                         
2298                                                         /* get cluster */
2299                                                         cluster = SUPER_CLUSTER( sx, sy );
2300                                                         if( *cluster < 0 )
2301                                                                 continue;
2302                                                         mapped++;
2303                                                         
2304                                                         /* get luxel */
2305                                                         flag = SUPER_FLAG( sx, sy );
2306                                                         if(*flag & FLAG_FORCE_SUBSAMPLING)
2307                                                         {
2308                                                                 /* force a lighted/mapped discrepancy so we subsample */
2309                                                                 ++lighted;
2310                                                                 ++mapped;
2311                                                                 ++mapped;
2312                                                         }
2313                                                         lightLuxel = LIGHT_LUXEL( sx, sy );
2314                                                         VectorAdd( total, lightLuxel, total );
2315                                                         if( (lightLuxel[ 0 ] + lightLuxel[ 1 ] + lightLuxel[ 2 ]) > 0.0f )
2316                                                                 lighted++;
2317                                                 }
2318                                                 
2319                                                 /* if total color is under a certain amount, then don't bother subsampling */
2320                                                 if( total[ 0 ] <= 4.0f && total[ 1 ] <= 4.0f && total[ 2 ] <= 4.0f )
2321                                                         continue;
2322                                                 
2323                                                 /* if all 4 pixels are either in shadow or light, then don't subsample */
2324                                                 if( lighted != 0 && lighted != mapped )
2325                                                 {
2326                                                         for( t = 0; t < 4; t++ )
2327                                                         {
2328                                                                 /* set sample coords */
2329                                                                 sx = x + tests[ t ][ 0 ];
2330                                                                 sy = y + tests[ t ][ 1 ];
2331                                                                 
2332                                                                 /* get luxel */
2333                                                                 cluster = SUPER_CLUSTER( sx, sy );
2334                                                                 if( *cluster < 0 )
2335                                                                         continue;
2336                                                                 flag = SUPER_FLAG( sx, sy );
2337                                                                 if(*flag & FLAG_ALREADY_SUBSAMPLED) // already subsampled
2338                                                                         continue;
2339                                                                 lightLuxel = LIGHT_LUXEL( sx, sy );
2340                                                                 lightDeluxel = LIGHT_DELUXEL( sx, sy );
2341                                                                 origin = SUPER_ORIGIN( sx, sy );
2342                                                                 
2343                                                                 /* only subsample shadowed luxels */
2344                                                                 //%     if( (lightLuxel[ 0 ] + lightLuxel[ 1 ] + lightLuxel[ 2 ]) <= 0.0f )
2345                                                                 //%             continue;
2346                                                                 
2347                                                                 /* subsample it */
2348                                                                 if(lightRandomSamples)
2349                                                                         RandomSubsampleRawLuxel( lm, &trace, origin, sx, sy, 0.5f * lightSamplesSearchBoxSize, lightLuxel, deluxemap ? lightDeluxel : NULL );
2350                                                                 else
2351                                                                         SubsampleRawLuxel_r( lm, &trace, origin, sx, sy, 0.25f * lightSamplesSearchBoxSize, lightLuxel, deluxemap ? lightDeluxel : NULL );
2352
2353                                                                 *flag |= FLAG_ALREADY_SUBSAMPLED;
2354                                                                 
2355                                                                 /* debug code to colorize subsampled areas to yellow */
2356                                                                 //%     luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2357                                                                 //%     VectorSet( luxel, 255, 204, 0 );
2358                                                         }
2359                                                 }
2360                                         }
2361                                 }
2362                         }
2363                         
2364                         /* tertiary pass, apply dirt map (ambient occlusion) */
2365                         if( 0 && dirty )
2366                         {
2367                                 /* walk luxels */
2368                                 for( y = 0; y < lm->sh; y++ )
2369                                 {
2370                                         for( x = 0; x < lm->sw; x++ )
2371                                         {
2372                                                 /* get cluster  */
2373                                                 cluster = SUPER_CLUSTER( x, y );
2374                                                 if( *cluster < 0 )
2375                                                         continue;
2376                                                 
2377                                                 /* get particulars */
2378                                                 lightLuxel = LIGHT_LUXEL( x, y );
2379                                                 dirt = SUPER_DIRT( x, y );
2380                                                 
2381                                                 /* scale light value */
2382                                                 VectorScale( lightLuxel, *dirt, lightLuxel );
2383                                         }
2384                                 }
2385                         }
2386                         
2387                         /* allocate sampling lightmap storage */
2388                         if( lm->superLuxels[ lightmapNum ] == NULL )
2389                         {
2390                                 /* allocate sampling lightmap storage */
2391                                 size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
2392                                 lm->superLuxels[ lightmapNum ] = safe_malloc( size );
2393                                 memset( lm->superLuxels[ lightmapNum ], 0, size );
2394                         }
2395
2396                         /* set style */
2397                         if( lightmapNum > 0 )
2398                         {
2399                                 lm->styles[ lightmapNum ] = trace.light->style;
2400                                 //%     Sys_Printf( "Surface %6d has lightstyle %d\n", rawLightmapNum, trace.light->style );
2401                         }
2402                         
2403                         /* copy to permanent luxels */
2404                         for( y = 0; y < lm->sh; y++ )
2405                         {
2406                                 for( x = 0; x < lm->sw; x++ )
2407                                 {
2408                                         /* get cluster and origin */
2409                                         cluster = SUPER_CLUSTER( x, y );
2410                                         if( *cluster < 0 )
2411                                                 continue;
2412                                         origin = SUPER_ORIGIN( x, y );
2413                                         
2414                                         /* filter? */
2415                                         if( luxelFilterRadius )
2416                                         {
2417                                                 /* setup */
2418                                                 VectorClear( averageColor );
2419                                                 VectorClear( averageDir );
2420                                                 samples = 0.0f;
2421                                                 
2422                                                 /* cheaper distance-based filtering */
2423                                                 for( sy = (y - luxelFilterRadius); sy <= (y + luxelFilterRadius); sy++ )
2424                                                 {
2425                                                         if( sy < 0 || sy >= lm->sh )
2426                                                                 continue;
2427                                                         
2428                                                         for( sx = (x - luxelFilterRadius); sx <= (x + luxelFilterRadius); sx++ )
2429                                                         {
2430                                                                 if( sx < 0 || sx >= lm->sw )
2431                                                                         continue;
2432                                                                 
2433                                                                 /* get particulars */
2434                                                                 cluster = SUPER_CLUSTER( sx, sy );
2435                                                                 if( *cluster < 0 )
2436                                                                         continue;
2437                                                                 lightLuxel = LIGHT_LUXEL( sx, sy );
2438                                                                 lightDeluxel = LIGHT_DELUXEL( sx, sy );
2439                                                                 
2440                                                                 /* create weight */
2441                                                                 weight = (abs( sx - x ) == luxelFilterRadius ? 0.5f : 1.0f);
2442                                                                 weight *= (abs( sy - y ) == luxelFilterRadius ? 0.5f : 1.0f);
2443                                                                 
2444                                                                 /* scale luxel by filter weight */
2445                                                                 VectorScale( lightLuxel, weight, color );
2446                                                                 VectorAdd( averageColor, color, averageColor );
2447                                                                 if(deluxemap)
2448                                                                 {
2449                                                                         VectorScale( lightDeluxel, weight, direction );
2450                                                                         VectorAdd( averageDir, direction, averageDir );
2451                                                                 }
2452                                                                 samples += weight;
2453                                                         }
2454                                                 }
2455                                                 
2456                                                 /* any samples? */
2457                                                 if( samples <= 0.0f     )
2458                                                         continue;
2459                                                 
2460                                                 /* scale into luxel */
2461                                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
2462                                                 luxel[ 3 ] = 1.0f;
2463                                                 
2464                                                 /* handle negative light */
2465                                                 if( trace.light->flags & LIGHT_NEGATIVE )
2466                                                 { 
2467                                                         luxel[ 0 ] -= averageColor[ 0 ] / samples;
2468                                                         luxel[ 1 ] -= averageColor[ 1 ] / samples;
2469                                                         luxel[ 2 ] -= averageColor[ 2 ] / samples;
2470                                                 }
2471                                                 
2472                                                 /* handle normal light */
2473                                                 else
2474                                                 { 
2475                                                         luxel[ 0 ] += averageColor[ 0 ] / samples;
2476                                                         luxel[ 1 ] += averageColor[ 1 ] / samples;
2477                                                         luxel[ 2 ] += averageColor[ 2 ] / samples;
2478                                                 }
2479                                                 
2480                                                 if(deluxemap)
2481                                                 {
2482                                                         /* scale into luxel */
2483                                                         deluxel = SUPER_DELUXEL( x, y );
2484                                                         deluxel[ 0 ] += averageDir[ 0 ] / samples;
2485                                                         deluxel[ 1 ] += averageDir[ 1 ] / samples;
2486                                                         deluxel[ 2 ] += averageDir[ 2 ] / samples;
2487                                                 }
2488                                         }
2489                                         
2490                                         /* single sample */
2491                                         else
2492                                         {
2493                                                 /* get particulars */
2494                                                 lightLuxel = LIGHT_LUXEL( x, y );
2495                                                 lightDeluxel = LIGHT_DELUXEL( x, y );
2496                                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
2497                                                 deluxel = SUPER_DELUXEL( x, y );
2498                                                 
2499                                                 /* handle negative light */
2500                                                 if( trace.light->flags & LIGHT_NEGATIVE )
2501                                                         VectorScale( averageColor, -1.0f, averageColor );
2502
2503                                                 /* add color */
2504                                                 luxel[ 3 ] = 1.0f;
2505                                                 
2506                                                 /* handle negative light */
2507                                                 if( trace.light->flags & LIGHT_NEGATIVE )
2508                                                         VectorSubtract( luxel, lightLuxel, luxel );
2509                                                 
2510                                                 /* handle normal light */
2511                                                 else
2512                                                         VectorAdd( luxel, lightLuxel, luxel );
2513
2514                                                 if(deluxemap)
2515                                                 {
2516                                                         VectorAdd( deluxel, lightDeluxel, deluxel );
2517                                                 }
2518                                         }
2519                                 }
2520                         }
2521                 }
2522                 
2523                 /* free temporary luxels */
2524                 if( lightLuxels != stackLightLuxels )
2525                         free( lightLuxels );
2526                 
2527                 if(deluxemap)
2528                         free( lightDeluxels );
2529         }
2530         
2531         /* free light list */
2532         FreeTraceLights( &trace );
2533         
2534         /* floodlight pass */
2535         if( floodlighty )
2536                 FloodlightIlluminateLightmap(lm);
2537
2538         if (debugnormals)
2539         {
2540                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2541                 {
2542                         /* early out */
2543                         if( lm->superLuxels[ lightmapNum ] == NULL )
2544                                 continue;
2545                         
2546                         for( y = 0; y < lm->sh; y++ )
2547                         {
2548                                 for( x = 0; x < lm->sw; x++ )
2549                                 {
2550                                         /* get cluster */
2551                                         cluster = SUPER_CLUSTER( x, y );
2552                                         //%     if( *cluster < 0 )
2553                                         //%             continue;
2554                                         
2555                                         /* get particulars */
2556                                         luxel = SUPER_LUXEL( lightmapNum, x, y );
2557                                         normal = SUPER_NORMAL (  x, y );
2558                
2559                                         luxel[0]=(normal[0]*127)+127;
2560                                         luxel[1]=(normal[1]*127)+127;
2561                                         luxel[2]=(normal[2]*127)+127;
2562                                 }
2563                         }
2564                 }
2565         }
2566         
2567         /*      -----------------------------------------------------------------
2568                 dirt pass
2569                 ----------------------------------------------------------------- */
2570         
2571         if( dirty )
2572         {
2573                 /* walk lightmaps */
2574                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2575                 {
2576                         /* early out */
2577                         if( lm->superLuxels[ lightmapNum ] == NULL )
2578                                 continue;
2579                         
2580                         /* apply dirt to each luxel */
2581                         for( y = 0; y < lm->sh; y++ )
2582                         {
2583                                 for( x = 0; x < lm->sw; x++ )
2584                                 {
2585                                         /* get cluster */
2586                                         cluster = SUPER_CLUSTER( x, y );
2587                                         //%     if( *cluster < 0 ) // TODO why not do this check? These pixels should be zero anyway
2588                                         //%             continue;
2589                                         
2590                                         /* get particulars */
2591                                         luxel = SUPER_LUXEL( lightmapNum, x, y );
2592                                         dirt = SUPER_DIRT( x, y );
2593                                         
2594                                         /* apply dirt */
2595                                         VectorScale( luxel, *dirt, luxel );
2596                                         
2597                                         /* debugging */
2598                                         if( dirtDebug )
2599                                                 VectorSet( luxel, *dirt * 255.0f, *dirt * 255.0f, *dirt * 255.0f );
2600                                 }
2601                         }
2602                 }
2603         }
2604         
2605         /* -----------------------------------------------------------------
2606            filter pass
2607            ----------------------------------------------------------------- */
2608         
2609         /* walk lightmaps */
2610         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2611         {
2612                 /* early out */
2613                 if( lm->superLuxels[ lightmapNum ] == NULL )
2614                         continue;
2615                 
2616                 /* average occluded luxels from neighbors */
2617                 for( y = 0; y < lm->sh; y++ )
2618                 {
2619                         for( x = 0; x < lm->sw; x++ )
2620                         {
2621                                 /* get particulars */
2622                                 cluster = SUPER_CLUSTER( x, y );
2623                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
2624                                 deluxel = SUPER_DELUXEL( x, y );
2625                                 normal = SUPER_NORMAL( x, y );
2626                                 
2627                                 /* determine if filtering is necessary */
2628                                 filterColor = qfalse;
2629                                 filterDir = qfalse;
2630                                 if( *cluster < 0 ||
2631                                         (lm->splotchFix && (luxel[ 0 ] <= ambientColor[ 0 ] || luxel[ 1 ] <= ambientColor[ 1 ] || luxel[ 2 ] <= ambientColor[ 2 ])) )
2632                                         filterColor = qtrue;
2633
2634                                 if( deluxemap && lightmapNum == 0 && (*cluster < 0 || filter) )
2635                                         filterDir = qtrue;
2636                                 
2637                                 if( !filterColor && !filterDir )
2638                                         continue;
2639                                 
2640                                 /* choose seed amount */
2641                                 VectorClear( averageColor );
2642                                 VectorClear( averageDir );
2643                                 samples = 0.0f;
2644                                 
2645                                 /* walk 3x3 matrix */
2646                                 for( sy = (y - 1); sy <= (y + 1); sy++ )
2647                                 {
2648                                         if( sy < 0 || sy >= lm->sh )
2649                                                 continue;
2650                                         
2651                                         for( sx = (x - 1); sx <= (x + 1); sx++ )
2652                                         {
2653                                                 if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
2654                                                         continue;
2655                                                 
2656                                                 /* get neighbor's particulars */
2657                                                 cluster2 = SUPER_CLUSTER( sx, sy );
2658                                                 luxel2 = SUPER_LUXEL( lightmapNum, sx, sy );
2659                                                 deluxel2 = SUPER_DELUXEL( sx, sy );
2660                                                 
2661                                                 /* ignore unmapped/unlit luxels */
2662                                                 if( *cluster2 < 0 || luxel2[ 3 ] == 0.0f ||
2663                                                         (lm->splotchFix && VectorCompare( luxel2, ambientColor )) )
2664                                                         continue;
2665                                                 
2666                                                 /* add its distinctiveness to our own */
2667                                                 VectorAdd( averageColor, luxel2, averageColor );
2668                                                 samples += luxel2[ 3 ];
2669                                                 if( filterDir )
2670                                                         VectorAdd( averageDir, deluxel2, averageDir );
2671                                         }
2672                                 }
2673                                 
2674                                 /* fall through */
2675                                 if( samples <= 0.0f )
2676                                         continue;
2677                                 
2678                                 /* dark lightmap seams */
2679                                 if( dark )
2680                                 {
2681                                         if( lightmapNum == 0 )
2682                                                 VectorMA( averageColor, 2.0f, ambientColor, averageColor );
2683                                         samples += 2.0f;
2684                                 }
2685                                 
2686                                 /* average it */
2687                                 if( filterColor )
2688                                 {
2689                                         VectorDivide( averageColor, samples, luxel );
2690                                         luxel[ 3 ] = 1.0f;
2691                                 }
2692                                 if( filterDir )
2693                                         VectorDivide( averageDir, samples, deluxel );
2694                                 
2695                                 /* set cluster to -3 */
2696                                 if( *cluster < 0 )
2697                                         *cluster = CLUSTER_FLOODED;
2698                         }
2699                 }
2700         }
2701
2702
2703 #if 0
2704         // audit pass
2705         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2706         {
2707                 /* early out */
2708                 if( lm->superLuxels[ lightmapNum ] == NULL )
2709                         continue;
2710                 for( y = 0; y < lm->sh; y++ )
2711                         for( x = 0; x < lm->sw; x++ )
2712                         {
2713                                 /* get cluster */
2714                                 cluster = SUPER_CLUSTER( x, y );
2715                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
2716                                 deluxel = SUPER_DELUXEL( x, y );
2717                                 if(!luxel || !deluxel || !cluster)
2718                                 {
2719                                         Sys_FPrintf(SYS_VRB, "WARNING: I got NULL'd.\n");
2720                                         continue;
2721                                 }
2722                                 else if(*cluster < 0)
2723                                 {
2724                                         // unmapped pixel
2725                                         // should have neither deluxemap nor lightmap
2726                                         if(deluxel[3])
2727                                                 Sys_FPrintf(SYS_VRB, "WARNING: I have written deluxe to an unmapped luxel. Sorry.\n");
2728                                 }
2729                                 else
2730                                 {
2731                                         // mapped pixel
2732                                         // should have both deluxemap and lightmap
2733                                         if(deluxel[3])
2734                                                 Sys_FPrintf(SYS_VRB, "WARNING: I forgot to write deluxe to a mapped luxel. Sorry.\n");
2735                                 }
2736                         }
2737         }
2738 #endif
2739 }
2740
2741
2742
2743 /*
2744 IlluminateVertexes()
2745 light the surface vertexes
2746 */
2747
2748 #define VERTEX_NUDGE    4.0f
2749
2750 void IlluminateVertexes( int num )
2751 {
2752         int                                     i, x, y, z, x1, y1, z1, sx, sy, radius, maxRadius, *cluster;
2753         int                                     lightmapNum, numAvg;
2754         float                           samples, *vertLuxel, *radVertLuxel, *luxel, dirt;
2755         vec3_t                          origin, temp, temp2, colors[ MAX_LIGHTMAPS ], avgColors[ MAX_LIGHTMAPS ];
2756         bspDrawSurface_t        *ds;
2757         surfaceInfo_t           *info;
2758         rawLightmap_t           *lm;
2759         bspDrawVert_t           *verts;
2760         trace_t                         trace;
2761         float                           floodLightAmount;
2762         vec3_t                          floodColor;
2763         
2764         
2765         /* get surface, info, and raw lightmap */
2766         ds = &bspDrawSurfaces[ num ];
2767         info = &surfaceInfos[ num ];
2768         lm = info->lm;
2769         
2770         /* -----------------------------------------------------------------
2771            illuminate the vertexes
2772            ----------------------------------------------------------------- */
2773         
2774         /* calculate vertex lighting for surfaces without lightmaps */
2775         if( lm == NULL || cpmaHack )
2776         {
2777                 /* setup trace */
2778                 trace.testOcclusion = (cpmaHack && lm != NULL) ? qfalse : !noTrace;
2779                 trace.forceSunlight = info->si->forceSunlight;
2780                 trace.recvShadows = info->recvShadows;
2781                 trace.numSurfaces = 1;
2782                 trace.surfaces = &num;
2783                 trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
2784                 
2785                 /* twosided lighting */
2786                 trace.twoSided = info->si->twoSided;
2787                 
2788                 /* make light list for this surface */
2789                 CreateTraceLightsForSurface( num, &trace );
2790                 
2791                 /* setup */
2792                 verts = yDrawVerts + ds->firstVert;
2793                 numAvg = 0;
2794                 memset( avgColors, 0, sizeof( avgColors ) );
2795                 
2796                 /* walk the surface verts */
2797                 for( i = 0; i < ds->numVerts; i++ )
2798                 {
2799                         /* get vertex luxel */
2800                         radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2801                         
2802                         /* color the luxel with raw lightmap num? */
2803                         if( debugSurfaces )
2804                                 VectorCopy( debugColors[ num % 12 ], radVertLuxel );
2805                         
2806                         /* color the luxel with luxel origin? */
2807                         else if( debugOrigin )
2808                         {
2809                                 VectorSubtract( info->maxs, info->mins, temp );
2810                                 VectorScale( temp, (1.0f / 255.0f), temp );
2811                                 VectorSubtract( origin, lm->mins, temp2 );
2812                                 radVertLuxel[ 0 ] = info->mins[ 0 ] + (temp[ 0 ] * temp2[ 0 ]);
2813                                 radVertLuxel[ 1 ] = info->mins[ 1 ] + (temp[ 1 ] * temp2[ 1 ]);
2814                                 radVertLuxel[ 2 ] = info->mins[ 2 ] + (temp[ 2 ] * temp2[ 2 ]);
2815                         }
2816                         
2817                         /* color the luxel with the normal */
2818                         else if( normalmap )
2819                         {
2820                                 radVertLuxel[ 0 ] = (verts[ i ].normal[ 0 ] + 1.0f) * 127.5f;
2821                                 radVertLuxel[ 1 ] = (verts[ i ].normal[ 1 ] + 1.0f) * 127.5f;
2822                                 radVertLuxel[ 2 ] = (verts[ i ].normal[ 2 ] + 1.0f) * 127.5f;
2823                         }
2824                         
2825                         /* illuminate the vertex */
2826                         else
2827                         {
2828                                 /* clear vertex luxel */
2829                                 VectorSet( radVertLuxel, -1.0f, -1.0f, -1.0f );
2830                                 
2831                                 /* try at initial origin */
2832                                 trace.cluster = ClusterForPointExtFilter( verts[ i ].xyz, VERTEX_EPSILON, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ] );
2833                                 if( trace.cluster >= 0 )
2834                                 {
2835                                         /* setup trace */
2836                                         VectorCopy( verts[ i ].xyz, trace.origin );
2837                                         VectorCopy( verts[ i ].normal, trace.normal );
2838                                         
2839                                         /* r7 dirt */
2840                                         if( dirty && !bouncing )
2841                                                 dirt = DirtForSample( &trace );
2842                                         else
2843                                                 dirt = 1.0f;
2844
2845                                         /* jal: floodlight */
2846                                         floodLightAmount = 0.0f;
2847                                         VectorClear( floodColor );
2848                                         if( floodlighty && !bouncing )
2849                                         {
2850                                                 floodLightAmount = floodlightIntensity * FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality );
2851                                                 VectorScale( floodlightRGB, floodLightAmount, floodColor );
2852                                         }
2853
2854                                         /* trace */
2855                                         LightingAtSample( &trace, ds->vertexStyles, colors );
2856                                         
2857                                         /* store */
2858                                         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2859                                         {
2860                                                 /* r7 dirt */
2861                                                 VectorScale( colors[ lightmapNum ], dirt, colors[ lightmapNum ] );
2862
2863                                                 /* jal: floodlight */
2864                                                 VectorAdd( colors[ lightmapNum ], floodColor, colors[ lightmapNum ] ); 
2865                                                 
2866                                                 /* store */
2867                                                 radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
2868                                                 VectorCopy( colors[ lightmapNum ], radVertLuxel );
2869                                                 VectorAdd( avgColors[ lightmapNum ], colors[ lightmapNum ], colors[ lightmapNum ] );
2870                                         }
2871                                 }
2872                                 
2873                                 /* is this sample bright enough? */
2874                                 radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2875                                 if( radVertLuxel[ 0 ] <= ambientColor[ 0 ] &&
2876                                         radVertLuxel[ 1 ] <= ambientColor[ 1 ] &&
2877                                         radVertLuxel[ 2 ] <= ambientColor[ 2 ] )
2878                                 {
2879                                         /* nudge the sample point around a bit */
2880                                         for( x = 0; x < 5; x++ )
2881                                         {
2882                                                 /* two's complement 0, 1, -1, 2, -2, etc */
2883                                                 x1 = ((x >> 1) ^ (x & 1 ? -1 : 0)) + (x & 1);
2884                                                 
2885                                                 for( y = 0; y < 5; y++ )
2886                                                 {
2887                                                         y1 = ((y >> 1) ^ (y & 1 ? -1 : 0)) + (y & 1);
2888                                                         
2889                                                         for( z = 0; z < 5; z++ )
2890                                                         {
2891                                                                 z1 = ((z >> 1) ^ (z & 1 ? -1 : 0)) + (z & 1);
2892                                                                 
2893                                                                 /* nudge origin */
2894                                                                 trace.origin[ 0 ] = verts[ i ].xyz[ 0 ] + (VERTEX_NUDGE * x1);
2895                                                                 trace.origin[ 1 ] = verts[ i ].xyz[ 1 ] + (VERTEX_NUDGE * y1);
2896                                                                 trace.origin[ 2 ] = verts[ i ].xyz[ 2 ] + (VERTEX_NUDGE * z1);
2897                                                                 
2898                                                                 /* try at nudged origin */
2899                                                                 trace.cluster = ClusterForPointExtFilter( origin, VERTEX_EPSILON, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ] );
2900                                                                 if( trace.cluster < 0 )
2901                                                                         continue;
2902
2903                                                                 /* r7 dirt */
2904                                                                 if( dirty && !bouncing )
2905                                                                         dirt = DirtForSample( &trace );
2906                                                                 else
2907                                                                         dirt = 1.0f;
2908
2909                                                                 /* jal: floodlight */
2910                                                                 floodLightAmount = 0.0f;
2911                                                                 VectorClear( floodColor );
2912                                                                 if( floodlighty && !bouncing )
2913                                                                 {
2914                                                                         floodLightAmount = floodlightIntensity * FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality );
2915                                                                         VectorScale( floodlightRGB, floodLightAmount, floodColor );
2916                                                                 }
2917                                                                                                                         
2918                                                                 /* trace */
2919                                                                 LightingAtSample( &trace, ds->vertexStyles, colors );
2920                                                                 
2921                                                                 /* store */
2922                                                                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2923                                                                 {
2924                                                                         /* r7 dirt */
2925                                                                         VectorScale( colors[ lightmapNum ], dirt, colors[ lightmapNum ] );
2926
2927                                                                         /* jal: floodlight */
2928                                                                         VectorAdd( colors[ lightmapNum ], floodColor, colors[ lightmapNum ] ); 
2929                                                                         
2930                                                                         /* store */
2931                                                                         radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
2932                                                                         VectorCopy( colors[ lightmapNum ], radVertLuxel );
2933                                                                 }
2934                                                                 
2935                                                                 /* bright enough? */
2936                                                                 radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2937                                                                 if( radVertLuxel[ 0 ] > ambientColor[ 0 ] ||
2938                                                                         radVertLuxel[ 1 ] > ambientColor[ 1 ] ||
2939                                                                         radVertLuxel[ 2 ] > ambientColor[ 2 ] )
2940                                                                         x = y = z = 1000;
2941                                                         }
2942                                                 }
2943                                         }
2944                                 }
2945                                 
2946                                 /* add to average? */
2947                                 radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2948                                 if( radVertLuxel[ 0 ] > ambientColor[ 0 ] ||
2949                                         radVertLuxel[ 1 ] > ambientColor[ 1 ] ||
2950                                         radVertLuxel[ 2 ] > ambientColor[ 2 ] )
2951                                 {
2952                                         numAvg++;
2953                                         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2954                                         {
2955                                                 radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
2956                                                 VectorAdd( avgColors[ lightmapNum ], radVertLuxel, avgColors[ lightmapNum ] );
2957                                         }
2958                                 }
2959                         }
2960                         
2961                         /* another happy customer */
2962                         numVertsIlluminated++;
2963                 }
2964                 
2965                 /* set average color */
2966                 if( numAvg > 0 )
2967                 {
2968                         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2969                                 VectorScale( avgColors[ lightmapNum ], (1.0f / numAvg), avgColors[ lightmapNum ] );
2970                 }
2971                 else
2972                 {
2973                         VectorCopy( ambientColor, avgColors[ 0 ] );
2974                 }
2975                 
2976                 /* clean up and store vertex color */
2977                 for( i = 0; i < ds->numVerts; i++ )
2978                 {
2979                         /* get vertex luxel */
2980                         radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2981                         
2982                         /* store average in occluded vertexes */
2983                         if( radVertLuxel[ 0 ] < 0.0f )
2984                         {
2985                                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2986                                 {
2987                                         radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
2988                                         VectorCopy( avgColors[ lightmapNum ], radVertLuxel );
2989                                         
2990                                         /* debug code */
2991                                         //%     VectorSet( radVertLuxel, 255.0f, 0.0f, 0.0f );
2992                                 }
2993                         }
2994                         
2995                         /* store it */
2996                         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2997                         {
2998                                 /* get luxels */
2999                                 vertLuxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
3000                                 radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
3001                                 
3002                                 /* store */
3003                                 if( bouncing || bounce == 0 || !bounceOnly )
3004                                         VectorAdd( vertLuxel, radVertLuxel, vertLuxel );
3005                                 if( !info->si->noVertexLight )
3006                                         ColorToBytes( vertLuxel, verts[ i ].color[ lightmapNum ], info->si->vertexScale );
3007                         }
3008                 }
3009                 
3010                 /* free light list */
3011                 FreeTraceLights( &trace );
3012                 
3013                 /* return to sender */
3014                 return;
3015         }
3016         
3017         /* -----------------------------------------------------------------
3018            reconstitute vertex lighting from the luxels
3019            ----------------------------------------------------------------- */
3020         
3021         /* set styles from lightmap */
3022         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3023                 ds->vertexStyles[ lightmapNum ] = lm->styles[ lightmapNum ];
3024         
3025         /* get max search radius */
3026         maxRadius = lm->sw;
3027         maxRadius = maxRadius > lm->sh ? maxRadius : lm->sh;
3028         
3029         /* walk the surface verts */
3030         verts = yDrawVerts + ds->firstVert;
3031         for( i = 0; i < ds->numVerts; i++ )
3032         {
3033                 /* do each lightmap */
3034                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3035                 {
3036                         /* early out */
3037                         if( lm->superLuxels[ lightmapNum ] == NULL )
3038                                 continue;
3039                         
3040                         /* get luxel coords */
3041                         x = verts[ i ].lightmap[ lightmapNum ][ 0 ];
3042                         y = verts[ i ].lightmap[ lightmapNum ][ 1 ];
3043                         if( x < 0 )
3044                                 x = 0;
3045                         else if( x >= lm->sw )
3046                                 x = lm->sw - 1;
3047                         if( y < 0 )
3048                                 y = 0;
3049                         else if( y >= lm->sh )
3050                                 y = lm->sh - 1;
3051                         
3052                         /* get vertex luxels */
3053                         vertLuxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
3054                         radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
3055                         
3056                         /* color the luxel with the normal? */
3057                         if( normalmap )
3058                         {
3059                                 radVertLuxel[ 0 ] = (verts[ i ].normal[ 0 ] + 1.0f) * 127.5f;
3060                                 radVertLuxel[ 1 ] = (verts[ i ].normal[ 1 ] + 1.0f) * 127.5f;
3061                                 radVertLuxel[ 2 ] = (verts[ i ].normal[ 2 ] + 1.0f) * 127.5f;
3062                         }
3063                         
3064                         /* color the luxel with surface num? */
3065                         else if( debugSurfaces )
3066                                 VectorCopy( debugColors[ num % 12 ], radVertLuxel );
3067                         
3068                         /* divine color from the superluxels */
3069                         else
3070                         {
3071                                 /* increasing radius */
3072                                 VectorClear( radVertLuxel );
3073                                 samples = 0.0f;
3074                                 for( radius = 0; radius < maxRadius && samples <= 0.0f; radius++ )
3075                                 {
3076                                         /* sample within radius */
3077                                         for( sy = (y - radius); sy <= (y + radius); sy++ )
3078                                         {
3079                                                 if( sy < 0 || sy >= lm->sh )
3080                                                         continue;
3081                                                 
3082                                                 for( sx = (x - radius); sx <= (x + radius); sx++ )
3083                                                 {
3084                                                         if( sx < 0 || sx >= lm->sw )
3085                                                                 continue;
3086                                                         
3087                                                         /* get luxel particulars */
3088                                                         luxel = SUPER_LUXEL( lightmapNum, sx, sy );
3089                                                         cluster = SUPER_CLUSTER( sx, sy );
3090                                                         if( *cluster < 0 )
3091                                                                 continue;
3092                                                         
3093                                                         /* testing: must be brigher than ambient color */
3094                                                         //%     if( luxel[ 0 ] <= ambientColor[ 0 ] || luxel[ 1 ] <= ambientColor[ 1 ] || luxel[ 2 ] <= ambientColor[ 2 ] )
3095                                                         //%             continue;
3096                                                         
3097                                                         /* add its distinctiveness to our own */
3098                                                         VectorAdd( radVertLuxel, luxel, radVertLuxel );
3099                                                         samples += luxel[ 3 ];
3100                                                 }
3101                                         }
3102                                 }
3103                                 
3104                                 /* any color? */
3105                                 if( samples > 0.0f )
3106                                         VectorDivide( radVertLuxel, samples, radVertLuxel );
3107                                 else
3108                                         VectorCopy( ambientColor, radVertLuxel );
3109                         }
3110                         
3111                         /* store into floating point storage */
3112                         VectorAdd( vertLuxel, radVertLuxel, vertLuxel );
3113                         numVertsIlluminated++;
3114                         
3115                         /* store into bytes (for vertex approximation) */
3116                         if( !info->si->noVertexLight )
3117                                 ColorToBytes( vertLuxel, verts[ i ].color[ lightmapNum ], 1.0f );
3118                 }
3119         }
3120 }
3121
3122
3123
3124 /* -------------------------------------------------------------------------------
3125
3126 light optimization (-fast)
3127
3128 creates a list of lights that will affect a surface and stores it in tw
3129 this is to optimize surface lighting by culling out as many of the
3130 lights in the world as possible from further calculation
3131
3132 ------------------------------------------------------------------------------- */
3133
3134 /*
3135 SetupBrushes()
3136 determines opaque brushes in the world and find sky shaders for sunlight calculations
3137 */
3138
3139 void SetupBrushes( void )
3140 {
3141         int                             i, j, b, compileFlags;
3142         qboolean                inside;
3143         bspBrush_t              *brush;
3144         bspBrushSide_t  *side;
3145         bspShader_t             *shader;
3146         shaderInfo_t    *si;
3147         
3148         
3149         /* note it */
3150         Sys_FPrintf( SYS_VRB, "--- SetupBrushes ---\n" );
3151         
3152         /* allocate */
3153         if( opaqueBrushes == NULL )
3154                 opaqueBrushes = safe_malloc( numBSPBrushes / 8 + 1 );
3155         
3156         /* clear */
3157         memset( opaqueBrushes, 0, numBSPBrushes / 8 + 1 );
3158         numOpaqueBrushes = 0;
3159         
3160         /* walk the list of worldspawn brushes */
3161         for( i = 0; i < bspModels[ 0 ].numBSPBrushes; i++ )
3162         {
3163                 /* get brush */
3164                 b = bspModels[ 0 ].firstBSPBrush + i;
3165                 brush = &bspBrushes[ b ];
3166                 
3167                 /* check all sides */
3168                 inside = qtrue;
3169                 compileFlags = 0;
3170                 for( j = 0; j < brush->numSides && inside; j++ )
3171                 {
3172                         /* do bsp shader calculations */
3173                         side = &bspBrushSides[ brush->firstSide + j ];
3174                         shader = &bspShaders[ side->shaderNum ];
3175                         
3176                         /* get shader info */
3177                         si = ShaderInfoForShader( shader->shader );
3178                         if( si == NULL )
3179                                 continue;
3180                         
3181                         /* or together compile flags */
3182                         compileFlags |= si->compileFlags;
3183                 }
3184                 
3185                 /* determine if this brush is opaque to light */
3186                 if( !(compileFlags & C_TRANSLUCENT) )
3187                 {
3188                         opaqueBrushes[ b >> 3 ] |= (1 << (b & 7));
3189                         numOpaqueBrushes++;
3190                         maxOpaqueBrush = i;
3191                 }
3192         }
3193         
3194         /* emit some statistics */
3195         Sys_FPrintf( SYS_VRB, "%9d opaque brushes\n", numOpaqueBrushes );
3196 }
3197
3198
3199
3200 /*
3201 ClusterVisible()
3202 determines if two clusters are visible to each other using the PVS
3203 */
3204
3205 qboolean ClusterVisible( int a, int b )
3206 {
3207         int                     leafBytes;
3208         byte            *pvs;
3209         
3210         
3211         /* dummy check */
3212         if( a < 0 || b < 0 )
3213                 return qfalse;
3214         
3215         /* early out */
3216         if( a == b )
3217                 return qtrue;
3218         
3219         /* not vised? */
3220         if( numBSPVisBytes <=8 )
3221                 return qtrue;
3222         
3223         /* get pvs data */
3224         /* portalClusters = ((int *) bspVisBytes)[ 0 ]; */
3225         leafBytes = ((int*) bspVisBytes)[ 1 ];
3226         pvs = bspVisBytes + VIS_HEADER_SIZE + (a * leafBytes);
3227         
3228         /* check */
3229         if( (pvs[ b >> 3 ] & (1 << (b & 7))) )
3230                 return qtrue;
3231         return qfalse;
3232 }
3233
3234
3235
3236 /*
3237 PointInLeafNum_r()
3238 borrowed from vlight.c
3239 */
3240
3241 int     PointInLeafNum_r( vec3_t point, int nodenum )
3242 {
3243         int                     leafnum;
3244         vec_t           dist;
3245         bspNode_t               *node;
3246         bspPlane_t      *plane;
3247         
3248         
3249         while( nodenum >= 0 )
3250         {
3251                 node = &bspNodes[ nodenum ];
3252                 plane = &bspPlanes[ node->planeNum ];
3253                 dist = DotProduct( point, plane->normal ) - plane->dist;
3254                 if( dist > 0.1 )
3255                         nodenum = node->children[ 0 ];
3256                 else if( dist < -0.1 )
3257                         nodenum = node->children[ 1 ];
3258                 else
3259                 {
3260                         leafnum = PointInLeafNum_r( point, node->children[ 0 ] );
3261                         if( bspLeafs[ leafnum ].cluster != -1 )
3262                                 return leafnum;
3263                         nodenum = node->children[ 1 ];
3264                 }
3265         }
3266         
3267         leafnum = -nodenum - 1;
3268         return leafnum;
3269 }
3270
3271
3272
3273 /*
3274 PointInLeafnum()
3275 borrowed from vlight.c
3276 */
3277
3278 int     PointInLeafNum( vec3_t point )
3279 {
3280         return PointInLeafNum_r( point, 0 );
3281 }
3282
3283
3284
3285 /*
3286 ClusterVisibleToPoint() - ydnar
3287 returns qtrue if point can "see" cluster
3288 */
3289
3290 qboolean ClusterVisibleToPoint( vec3_t point, int cluster )
3291 {
3292         int             pointCluster;
3293         
3294
3295         /* get leafNum for point */
3296         pointCluster = ClusterForPoint( point );
3297         if( pointCluster < 0 )
3298                 return qfalse;
3299         
3300         /* check pvs */
3301         return ClusterVisible( pointCluster, cluster );
3302 }
3303
3304
3305
3306 /*
3307 ClusterForPoint() - ydnar
3308 returns the pvs cluster for point
3309 */
3310
3311 int ClusterForPoint( vec3_t point )
3312 {
3313         int             leafNum;
3314         
3315
3316         /* get leafNum for point */
3317         leafNum = PointInLeafNum( point );
3318         if( leafNum < 0 )
3319                 return -1;
3320         
3321         /* return the cluster */
3322         return bspLeafs[ leafNum ].cluster;
3323 }
3324
3325
3326
3327 /*
3328 ClusterForPointExt() - ydnar
3329 also takes brushes into account for occlusion testing
3330 */
3331
3332 int ClusterForPointExt( vec3_t point, float epsilon )
3333 {
3334         int                             i, j, b, leafNum, cluster;
3335         float                   dot;
3336         qboolean                inside;
3337         int                             *brushes, numBSPBrushes;
3338         bspLeaf_t               *leaf;
3339         bspBrush_t              *brush;
3340         bspPlane_t              *plane;
3341         
3342         
3343         /* get leaf for point */
3344         leafNum = PointInLeafNum( point );
3345         if( leafNum < 0 )
3346                 return -1;
3347         leaf = &bspLeafs[ leafNum ];
3348         
3349         /* get the cluster */
3350         cluster = leaf->cluster;
3351         if( cluster < 0 )
3352                 return -1;
3353         
3354         /* transparent leaf, so check point against all brushes in the leaf */
3355         brushes = &bspLeafBrushes[ leaf->firstBSPLeafBrush ];
3356         numBSPBrushes = leaf->numBSPLeafBrushes;
3357         for( i = 0; i < numBSPBrushes; i++ )
3358         {
3359                 /* get parts */
3360                 b = brushes[ i ];
3361                 if( b > maxOpaqueBrush )
3362                         continue;
3363                 brush = &bspBrushes[ b ];
3364                 if( !(opaqueBrushes[ b >> 3 ] & (1 << (b & 7))) )
3365                         continue;
3366                 
3367                 /* check point against all planes */
3368                 inside = qtrue;
3369                 for( j = 0; j < brush->numSides && inside; j++ )
3370                 {
3371                         plane = &bspPlanes[ bspBrushSides[ brush->firstSide + j ].planeNum ];
3372                         dot = DotProduct( point, plane->normal );
3373                         dot -= plane->dist;
3374                         if( dot > epsilon )
3375                                 inside = qfalse;
3376                 }
3377                 
3378                 /* if inside, return bogus cluster */
3379                 if( inside )
3380                         return -1 - b;
3381         }
3382         
3383         /* if the point made it this far, it's not inside any opaque brushes */
3384         return cluster;
3385 }
3386
3387
3388
3389 /*
3390 ClusterForPointExtFilter() - ydnar
3391 adds cluster checking against a list of known valid clusters
3392 */
3393
3394 int ClusterForPointExtFilter( vec3_t point, float epsilon, int numClusters, int *clusters )
3395 {
3396         int             i, cluster;
3397         
3398         
3399         /* get cluster for point */
3400         cluster = ClusterForPointExt( point, epsilon );
3401         
3402         /* check if filtering is necessary */
3403         if( cluster < 0 || numClusters <= 0 || clusters == NULL )
3404                 return cluster;
3405         
3406         /* filter */
3407         for( i = 0; i < numClusters; i++ )
3408         {
3409                 if( cluster == clusters[ i ] || ClusterVisible( cluster, clusters[ i ] ) )
3410                         return cluster;
3411         }
3412         
3413         /* failed */
3414         return -1;
3415 }
3416
3417
3418
3419 /*
3420 ShaderForPointInLeaf() - ydnar
3421 checks a point against all brushes in a leaf, returning the shader of the brush
3422 also sets the cumulative surface and content flags for the brush hit
3423 */
3424
3425 int ShaderForPointInLeaf( vec3_t point, int leafNum, float epsilon, int wantContentFlags, int wantSurfaceFlags, int *contentFlags, int *surfaceFlags )
3426 {
3427         int                             i, j;
3428         float                   dot;
3429         qboolean                inside;
3430         int                             *brushes, numBSPBrushes;
3431         bspLeaf_t                       *leaf;
3432         bspBrush_t              *brush;
3433         bspBrushSide_t  *side;
3434         bspPlane_t              *plane;
3435         bspShader_t             *shader;
3436         int                             allSurfaceFlags, allContentFlags;
3437
3438         
3439         /* clear things out first */
3440         *surfaceFlags = 0;
3441         *contentFlags = 0;
3442         
3443         /* get leaf */
3444         if( leafNum < 0 )
3445                 return -1;
3446         leaf = &bspLeafs[ leafNum ];
3447         
3448         /* transparent leaf, so check point against all brushes in the leaf */
3449         brushes = &bspLeafBrushes[ leaf->firstBSPLeafBrush ];
3450         numBSPBrushes = leaf->numBSPLeafBrushes;
3451         for( i = 0; i < numBSPBrushes; i++ )
3452         {
3453                 /* get parts */
3454                 brush = &bspBrushes[ brushes[ i ] ];
3455                 
3456                 /* check point against all planes */
3457                 inside = qtrue;
3458                 allSurfaceFlags = 0;
3459                 allContentFlags = 0;
3460                 for( j = 0; j < brush->numSides && inside; j++ )
3461                 {
3462                         side = &bspBrushSides[ brush->firstSide + j ];
3463                         plane = &bspPlanes[ side->planeNum ];
3464                         dot = DotProduct( point, plane->normal );
3465                         dot -= plane->dist;
3466                         if( dot > epsilon )
3467                                 inside = qfalse;
3468                         else
3469                         {
3470                                 shader = &bspShaders[ side->shaderNum ];
3471                                 allSurfaceFlags |= shader->surfaceFlags;
3472                                 allContentFlags |= shader->contentFlags;
3473                         }
3474                 }
3475                 
3476                 /* handle if inside */
3477                 if( inside )
3478                 {
3479                         /* if there are desired flags, check for same and continue if they aren't matched */
3480                         if( wantContentFlags && !(wantContentFlags & allContentFlags) )
3481                                 continue;
3482                         if( wantSurfaceFlags && !(wantSurfaceFlags & allSurfaceFlags) )
3483                                 continue;
3484                         
3485                         /* store the cumulative flags and return the brush shader (which is mostly useless) */
3486                         *surfaceFlags = allSurfaceFlags;
3487                         *contentFlags = allContentFlags;
3488                         return brush->shaderNum;
3489                 }
3490         }
3491         
3492         /* if the point made it this far, it's not inside any brushes */
3493         return -1;
3494 }
3495
3496
3497
3498 /*
3499 ChopBounds()
3500 chops a bounding box by the plane defined by origin and normal
3501 returns qfalse if the bounds is entirely clipped away
3502
3503 this is not exactly the fastest way to do this...
3504 */
3505
3506 qboolean ChopBounds( vec3_t mins, vec3_t maxs, vec3_t origin, vec3_t normal )
3507 {
3508         /* FIXME: rewrite this so it doesn't use bloody brushes */
3509         return qtrue;
3510 }
3511
3512
3513
3514 /*
3515 SetupEnvelopes()
3516 calculates each light's effective envelope,
3517 taking into account brightness, type, and pvs.
3518 */
3519
3520 #define LIGHT_EPSILON   0.125f
3521 #define LIGHT_NUDGE             2.0f
3522
3523 void SetupEnvelopes( qboolean forGrid, qboolean fastFlag )
3524 {
3525         int                     i, x, y, z, x1, y1, z1;
3526         light_t         *light, *light2, **owner;
3527         bspLeaf_t       *leaf;
3528         vec3_t          origin, dir, mins, maxs;
3529         float           radius, intensity;
3530         light_t         *buckets[ 256 ];
3531         
3532         
3533         /* early out for weird cases where there are no lights */
3534         if( lights == NULL )
3535                 return;
3536         
3537         /* note it */
3538         Sys_FPrintf( SYS_VRB, "--- SetupEnvelopes%s ---\n", fastFlag ? " (fast)" : "" );
3539         
3540         /* count lights */
3541         numLights = 0;
3542         numCulledLights = 0;
3543         owner = &lights;
3544         while( *owner != NULL )
3545         {
3546                 /* get light */
3547                 light = *owner;
3548                 
3549                 /* handle negative lights */
3550                 if( light->photons < 0.0f || light->add < 0.0f )
3551                 {
3552                         light->photons *= -1.0f;
3553                         light->add *= -1.0f;
3554                         light->flags |= LIGHT_NEGATIVE;
3555                 }
3556                 
3557                 /* sunlight? */
3558                 if( light->type == EMIT_SUN )
3559                 {
3560                         /* special cased */
3561                         light->cluster = 0;
3562                         light->envelope = MAX_WORLD_COORD * 8.0f;
3563                         VectorSet( light->mins, MIN_WORLD_COORD * 8.0f, MIN_WORLD_COORD * 8.0f, MIN_WORLD_COORD * 8.0f );
3564                         VectorSet( light->maxs, MAX_WORLD_COORD * 8.0f, MAX_WORLD_COORD * 8.0f, MAX_WORLD_COORD * 8.0f );
3565                 }
3566                 
3567                 /* everything else */
3568                 else
3569                 {
3570                         /* get pvs cluster for light */
3571                         light->cluster = ClusterForPointExt( light->origin, LIGHT_EPSILON );
3572                         
3573                         /* invalid cluster? */
3574                         if( light->cluster < 0 )
3575                         {
3576                                 /* nudge the sample point around a bit */
3577                                 for( x = 0; x < 4; x++ )
3578                                 {
3579                                         /* two's complement 0, 1, -1, 2, -2, etc */
3580                                         x1 = ((x >> 1) ^ (x & 1 ? -1 : 0)) + (x & 1);
3581                                         
3582                                         for( y = 0; y < 4; y++ )
3583                                         {
3584                                                 y1 = ((y >> 1) ^ (y & 1 ? -1 : 0)) + (y & 1);
3585                                                 
3586                                                 for( z = 0; z < 4; z++ )
3587                                                 {
3588                                                         z1 = ((z >> 1) ^ (z & 1 ? -1 : 0)) + (z & 1);
3589                                                         
3590                                                         /* nudge origin */
3591                                                         origin[ 0 ] = light->origin[ 0 ] + (LIGHT_NUDGE * x1);
3592                                                         origin[ 1 ] = light->origin[ 1 ] + (LIGHT_NUDGE * y1);
3593                                                         origin[ 2 ] = light->origin[ 2 ] + (LIGHT_NUDGE * z1);
3594                                                         
3595                                                         /* try at nudged origin */
3596                                                         light->cluster = ClusterForPointExt( origin, LIGHT_EPSILON );
3597                                                         if( light->cluster < 0 )
3598                                                                 continue;
3599                                                                         
3600                                                         /* set origin */
3601                                                         VectorCopy( origin, light->origin );
3602                                                 }
3603                                         }
3604                                 }
3605                         }
3606                         
3607                         /* only calculate for lights in pvs and outside of opaque brushes */
3608                         if( light->cluster >= 0 )
3609                         {
3610                                 /* set light fast flag */
3611                                 if( fastFlag )
3612                                         light->flags |= LIGHT_FAST_TEMP;
3613                                 else
3614                                         light->flags &= ~LIGHT_FAST_TEMP;
3615                                 if( light->si && light->si->noFast )
3616                                         light->flags &= ~(LIGHT_FAST | LIGHT_FAST_TEMP);
3617                                 
3618                                 /* clear light envelope */
3619                                 light->envelope = 0;
3620                                 
3621                                 /* handle area lights */
3622                                 if( exactPointToPolygon && light->type == EMIT_AREA && light->w != NULL )
3623                                 {
3624                                         /* ugly hack to calculate extent for area lights, but only done once */
3625                                         VectorScale( light->normal, -1.0f, dir );
3626                                         for( radius = 100.0f; radius < 130000.0f && light->envelope == 0; radius += 10.0f )
3627                                         {
3628                                                 float   factor;
3629                                                 
3630                                                 VectorMA( light->origin, radius, light->normal, origin );
3631                                                 factor = PointToPolygonFormFactor( origin, dir, light->w );
3632                                                 if( factor < 0.0f )
3633                                                         factor *= -1.0f;
3634                                                 if( (factor * light->add) <= light->falloffTolerance )
3635                                                         light->envelope = radius;
3636                                         }
3637                                         
3638                                         /* check for fast mode */
3639                                         if( !(light->flags & LIGHT_FAST) && !(light->flags & LIGHT_FAST_TEMP) )
3640                                                 light->envelope = MAX_WORLD_COORD * 8.0f;
3641                                         intensity = light->photons; /* hopefully not used */
3642                                 }
3643                                 else
3644                                 {
3645                                         radius = 0.0f;
3646                                         intensity = light->photons;
3647                                 }
3648                                 
3649                                 /* other calcs */
3650                                 if( light->envelope <= 0.0f )
3651                                 {
3652                                         /* solve distance for non-distance lights */
3653                                         if( !(light->flags & LIGHT_ATTEN_DISTANCE) )
3654                                                 light->envelope = MAX_WORLD_COORD * 8.0f;
3655                                         
3656                                         /* solve distance for linear lights */
3657                                         else if( (light->flags & LIGHT_ATTEN_LINEAR ) )
3658                                                 //% light->envelope = ((intensity / light->falloffTolerance) * linearScale - 1 + radius) / light->fade;
3659                                                 light->envelope = ((intensity * linearScale) - light->falloffTolerance) / light->fade;
3660
3661                                                 /*
3662                                                 add = angle * light->photons * linearScale - (dist * light->fade);
3663                                                 T = (light->photons * linearScale) - (dist * light->fade);
3664                                                 T + (dist * light->fade) = (light->photons * linearScale);
3665                                                 dist * light->fade = (light->photons * linearScale) - T;
3666                                                 dist = ((light->photons * linearScale) - T) / light->fade;
3667                                                 */
3668                                         
3669                                         /* solve for inverse square falloff */
3670                                         else
3671                                                 light->envelope = sqrt( intensity / light->falloffTolerance ) + radius;
3672                                                 
3673                                                 /*
3674                                                 add = light->photons / (dist * dist);
3675                                                 T = light->photons / (dist * dist);
3676                                                 T * (dist * dist) = light->photons;
3677                                                 dist = sqrt( light->photons / T );
3678                                                 */
3679                                 }
3680                                 
3681                                 /* chop radius against pvs */
3682                                 {
3683                                         /* clear bounds */
3684                                         ClearBounds( mins, maxs );
3685                                         
3686                                         /* check all leaves */
3687                                         for( i = 0; i < numBSPLeafs; i++ )
3688                                         {
3689                                                 /* get test leaf */
3690                                                 leaf = &bspLeafs[ i ];
3691                                                 
3692                                                 /* in pvs? */
3693                                                 if( leaf->cluster < 0 )
3694                                                         continue;
3695                                                 if( ClusterVisible( light->cluster, leaf->cluster ) == qfalse ) /* ydnar: thanks Arnout for exposing my stupid error (this never failed before) */
3696                                                         continue;
3697                                                 
3698                                                 /* add this leafs bbox to the bounds */
3699                                                 VectorCopy( leaf->mins, origin );
3700                                                 AddPointToBounds( origin, mins, maxs );
3701                                                 VectorCopy( leaf->maxs, origin );
3702                                                 AddPointToBounds( origin, mins, maxs );
3703                                         }
3704                                         
3705                                         /* test to see if bounds encompass light */
3706                                         for( i = 0; i < 3; i++ )
3707                                         {
3708                                                 if( mins[ i ] > light->origin[ i ] || maxs[ i ] < light->origin[ i ] )
3709                                                 {
3710                                                         //% Sys_Printf( "WARNING: Light PVS bounds (%.0f, %.0f, %.0f) -> (%.0f, %.0f, %.0f)\ndo not encompass light %d (%f, %f, %f)\n",
3711                                                         //%     mins[ 0 ], mins[ 1 ], mins[ 2 ],
3712                                                         //%     maxs[ 0 ], maxs[ 1 ], maxs[ 2 ],
3713                                                         //%     numLights, light->origin[ 0 ], light->origin[ 1 ], light->origin[ 2 ] );
3714                                                         AddPointToBounds( light->origin, mins, maxs );
3715                                                 }
3716                                         }
3717                                         
3718                                         /* chop the bounds by a plane for area lights and spotlights */
3719                                         if( light->type == EMIT_AREA || light->type == EMIT_SPOT )
3720                                                 ChopBounds( mins, maxs, light->origin, light->normal );
3721                                         
3722                                         /* copy bounds */
3723                                         VectorCopy( mins, light->mins );
3724                                         VectorCopy( maxs, light->maxs );
3725                                         
3726                                         /* reflect bounds around light origin */
3727                                         //%     VectorMA( light->origin, -1.0f, origin, origin );
3728                                         VectorScale( light->origin, 2, origin );
3729                                         VectorSubtract( origin, maxs, origin );
3730                                         AddPointToBounds( origin, mins, maxs );
3731                                         //%     VectorMA( light->origin, -1.0f, mins, origin );
3732                                         VectorScale( light->origin, 2, origin );
3733                                         VectorSubtract( origin, mins, origin );
3734                                         AddPointToBounds( origin, mins, maxs );
3735                                          
3736                                         /* calculate spherical bounds */
3737                                         VectorSubtract( maxs, light->origin, dir );
3738                                         radius = (float) VectorLength( dir );
3739                                         
3740                                         /* if this radius is smaller than the envelope, then set the envelope to it */
3741                                         if( radius < light->envelope )
3742                                         {
3743                                                 light->envelope = radius;
3744                                                 //%     Sys_FPrintf( SYS_VRB, "PVS Cull (%d): culled\n", numLights );
3745                                         }
3746                                         //%     else
3747                                         //%             Sys_FPrintf( SYS_VRB, "PVS Cull (%d): failed (%8.0f > %8.0f)\n", numLights, radius, light->envelope );
3748                                 }
3749                                 
3750                                 /* add grid/surface only check */
3751                                 if( forGrid )
3752                                 {
3753                                         if( !(light->flags & LIGHT_GRID) )
3754                                                 light->envelope = 0.0f;
3755                                 }
3756                                 else
3757                                 {
3758                                         if( !(light->flags & LIGHT_SURFACES) )
3759                                                 light->envelope = 0.0f;
3760                                 }
3761                         }
3762                         
3763                         /* culled? */
3764                         if( light->cluster < 0 || light->envelope <= 0.0f )
3765                         {
3766                                 /* debug code */
3767                                 //%     Sys_Printf( "Culling light: Cluster: %d Envelope: %f\n", light->cluster, light->envelope );
3768                                 
3769                                 /* delete the light */
3770                                 numCulledLights++;
3771                                 *owner = light->next;
3772                                 if( light->w != NULL )
3773                                         free( light->w );
3774                                 free( light );
3775                                 continue;
3776                         }
3777                 }
3778                 
3779                 /* square envelope */
3780                 light->envelope2 = (light->envelope * light->envelope);
3781                 
3782                 /* increment light count */
3783                 numLights++;
3784                 
3785                 /* set next light */
3786                 owner = &((**owner).next);
3787         }
3788         
3789         /* bucket sort lights by style */
3790         memset( buckets, 0, sizeof( buckets ) );
3791         light2 = NULL;
3792         for( light = lights; light != NULL; light = light2 )
3793         {
3794                 /* get next light */
3795                 light2 = light->next;
3796                 
3797                 /* filter into correct bucket */
3798                 light->next = buckets[ light->style ];
3799                 buckets[ light->style ] = light;
3800                 
3801                 /* if any styled light is present, automatically set nocollapse */
3802                 if( light->style != LS_NORMAL )
3803                         noCollapse = qtrue;
3804         }
3805         
3806         /* filter back into light list */
3807         lights = NULL;
3808         for( i = 255; i >= 0; i-- )
3809         {
3810                 light2 = NULL;
3811                 for( light = buckets[ i ]; light != NULL; light = light2 )
3812                 {
3813                         light2 = light->next;
3814                         light->next = lights;
3815                         lights = light;
3816                 }
3817         }
3818         
3819         /* emit some statistics */
3820         Sys_Printf( "%9d total lights\n", numLights );
3821         Sys_Printf( "%9d culled lights\n", numCulledLights );
3822 }
3823
3824
3825
3826 /*
3827 CreateTraceLightsForBounds()
3828 creates a list of lights that affect the given bounding box and pvs clusters (bsp leaves)
3829 */
3830
3831 void CreateTraceLightsForBounds( vec3_t mins, vec3_t maxs, vec3_t normal, int numClusters, int *clusters, int flags, trace_t *trace )
3832 {
3833         int                     i;
3834         light_t         *light;
3835         vec3_t          origin, dir, nullVector = { 0.0f, 0.0f, 0.0f };
3836         float           radius, dist, length;
3837         
3838         
3839         /* potential pre-setup  */
3840         if( numLights == 0 )
3841                 SetupEnvelopes( qfalse, fast );
3842         
3843         /* debug code */
3844         //% Sys_Printf( "CTWLFB: (%4.1f %4.1f %4.1f) (%4.1f %4.1f %4.1f)\n", mins[ 0 ], mins[ 1 ], mins[ 2 ], maxs[ 0 ], maxs[ 1 ], maxs[ 2 ] );
3845         
3846         /* allocate the light list */
3847         trace->lights = safe_malloc( sizeof( light_t* ) * (numLights + 1) );
3848         trace->numLights = 0;
3849         
3850         /* calculate spherical bounds */
3851         VectorAdd( mins, maxs, origin );
3852         VectorScale( origin, 0.5f, origin );
3853         VectorSubtract( maxs, origin, dir );
3854         radius = (float) VectorLength( dir );
3855         
3856         /* get length of normal vector */
3857         if( normal != NULL )
3858                 length = VectorLength( normal );
3859         else
3860         {
3861                 normal = nullVector;
3862                 length = 0;
3863         }
3864         
3865         /* test each light and see if it reaches the sphere */
3866         /* note: the attenuation code MUST match LightingAtSample() */
3867         for( light = lights; light; light = light->next )
3868         {
3869                 /* check zero sized envelope */
3870                 if( light->envelope <= 0 )
3871                 {
3872                         lightsEnvelopeCulled++;
3873                         continue;
3874                 }
3875                 
3876                 /* check flags */
3877                 if( !(light->flags & flags) )
3878                         continue;
3879                 
3880                 /* sunlight skips all this nonsense */
3881                 if( light->type != EMIT_SUN )
3882                 {
3883                         /* sun only? */
3884                         if( sunOnly )
3885                                 continue;
3886                         
3887                         /* check against pvs cluster */
3888                         if( numClusters > 0 && clusters != NULL )
3889                         {
3890                                 for( i = 0; i < numClusters; i++ )
3891                                 {
3892                                         if( ClusterVisible( light->cluster, clusters[ i ] ) )
3893                                                 break;
3894                                 }
3895                                 
3896                                 /* fixme! */
3897                                 if( i == numClusters )
3898                                 {
3899                                         lightsClusterCulled++;
3900                                         continue;
3901                                 }
3902                         }
3903                         
3904                         /* if the light's bounding sphere intersects with the bounding sphere then this light needs to be tested */
3905                         VectorSubtract( light->origin, origin, dir );
3906                         dist = VectorLength( dir );
3907                         dist -= light->envelope;
3908                         dist -= radius;
3909                         if( dist > 0 )
3910                         {
3911                                 lightsEnvelopeCulled++;
3912                                 continue;
3913                         }
3914                         
3915                         /* check bounding box against light's pvs envelope (note: this code never eliminated any lights, so disabling it) */
3916                         #if 0
3917                         skip = qfalse;
3918                         for( i = 0; i < 3; i++ )
3919                         {
3920                                 if( mins[ i ] > light->maxs[ i ] || maxs[ i ] < light->mins[ i ] )
3921                                         skip = qtrue;
3922                         }
3923                         if( skip )
3924                         {
3925                                 lightsBoundsCulled++;
3926                                 continue;
3927                         }
3928                         #endif
3929                 }
3930                 
3931                 /* planar surfaces (except twosided surfaces) have a couple more checks */
3932                 if( length > 0.0f && trace->twoSided == qfalse )
3933                 {
3934                         /* lights coplanar with a surface won't light it */
3935                         if( !(light->flags & LIGHT_TWOSIDED) && DotProduct( light->normal, normal ) > 0.999f )
3936                         {
3937                                 lightsPlaneCulled++;
3938                                 continue;
3939                         }
3940                         
3941                         /* check to see if light is behind the plane */
3942                         if( DotProduct( light->origin, normal ) - DotProduct( origin, normal ) < -1.0f )
3943                         {
3944                                 lightsPlaneCulled++;
3945                                 continue;
3946                         }
3947                 }
3948                 
3949                 /* add this light */
3950                 trace->lights[ trace->numLights++ ] = light;
3951         }
3952         
3953         /* make last night null */
3954         trace->lights[ trace->numLights ] = NULL;
3955 }
3956
3957
3958
3959 void FreeTraceLights( trace_t *trace )
3960 {
3961         if( trace->lights != NULL )
3962                 free( trace->lights );
3963 }
3964
3965
3966
3967 /*
3968 CreateTraceLightsForSurface()
3969 creates a list of lights that can potentially affect a drawsurface
3970 */
3971
3972 void CreateTraceLightsForSurface( int num, trace_t *trace )
3973 {
3974         int                                     i;
3975         vec3_t                          mins, maxs, normal;
3976         bspDrawVert_t           *dv;
3977         bspDrawSurface_t        *ds;
3978         surfaceInfo_t           *info;
3979         
3980         
3981         /* dummy check */
3982         if( num < 0 )
3983                 return;
3984         
3985         /* get drawsurface and info */
3986         ds = &bspDrawSurfaces[ num ];
3987         info = &surfaceInfos[ num ];
3988         
3989         /* get the mins/maxs for the dsurf */
3990         ClearBounds( mins, maxs );
3991         VectorCopy( bspDrawVerts[ ds->firstVert ].normal, normal );
3992         for( i = 0; i < ds->numVerts; i++ )
3993         {
3994                 dv = &yDrawVerts[ ds->firstVert + i ];
3995                 AddPointToBounds( dv->xyz, mins, maxs );
3996                 if( !VectorCompare( dv->normal, normal ) )
3997                         VectorClear( normal );
3998         }
3999         
4000         /* create the lights for the bounding box */
4001         CreateTraceLightsForBounds( mins, maxs, normal, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ], LIGHT_SURFACES, trace );
4002 }
4003
4004 /////////////////////////////////////////////////////////////
4005
4006 #define FLOODLIGHT_CONE_ANGLE                   88      /* degrees */
4007 #define FLOODLIGHT_NUM_ANGLE_STEPS              16
4008 #define FLOODLIGHT_NUM_ELEVATION_STEPS  4
4009 #define FLOODLIGHT_NUM_VECTORS                  (FLOODLIGHT_NUM_ANGLE_STEPS * FLOODLIGHT_NUM_ELEVATION_STEPS)
4010
4011 static vec3_t   floodVectors[ FLOODLIGHT_NUM_VECTORS ];
4012 static int              numFloodVectors = 0;
4013
4014 void SetupFloodLight( void )
4015 {
4016         int             i, j;
4017         float   angle, elevation, angleStep, elevationStep;
4018         const char      *value;
4019         double v1,v2,v3,v4,v5,v6;
4020
4021         /* note it */
4022         Sys_FPrintf( SYS_VRB, "--- SetupFloodLight ---\n" );
4023
4024         /* calculate angular steps */
4025         angleStep = DEG2RAD( 360.0f / FLOODLIGHT_NUM_ANGLE_STEPS );
4026         elevationStep = DEG2RAD( FLOODLIGHT_CONE_ANGLE / FLOODLIGHT_NUM_ELEVATION_STEPS );
4027
4028         /* iterate angle */
4029         angle = 0.0f;
4030         for( i = 0, angle = 0.0f; i < FLOODLIGHT_NUM_ANGLE_STEPS; i++, angle += angleStep )
4031         {
4032                 /* iterate elevation */
4033                 for( j = 0, elevation = elevationStep * 0.5f; j < FLOODLIGHT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep )
4034                 {
4035                         floodVectors[ numFloodVectors ][ 0 ] = sin( elevation ) * cos( angle );
4036                         floodVectors[ numFloodVectors ][ 1 ] = sin( elevation ) * sin( angle );
4037                         floodVectors[ numFloodVectors ][ 2 ] = cos( elevation );
4038                         numFloodVectors++;
4039                 }
4040         }
4041
4042         /* emit some statistics */
4043         Sys_FPrintf( SYS_VRB, "%9d numFloodVectors\n", numFloodVectors );
4044
4045       /* floodlight */
4046         value = ValueForKey( &entities[ 0 ], "_floodlight" );
4047
4048         if( value[ 0 ] != '\0' )
4049         {
4050                 v1=v2=v3=0;
4051                 v4=floodlightDistance;
4052                 v5=floodlightIntensity;
4053                 v6=floodlightDirectionScale;
4054
4055                 sscanf( value, "%lf %lf %lf %lf %lf %lf", &v1, &v2, &v3, &v4, &v5, &v6);
4056
4057                 floodlightRGB[0]=v1;
4058                 floodlightRGB[1]=v2;
4059                 floodlightRGB[2]=v3;
4060
4061                 if (VectorLength(floodlightRGB)==0)
4062                 {
4063                         VectorSet(floodlightRGB,240,240,255);
4064                 }
4065
4066                 if (v4<1) v4=1024;
4067                 if (v5<1) v5=128;
4068                 if (v6<0) v6=1;
4069
4070                 floodlightDistance=v4;
4071                 floodlightIntensity=v5;
4072                 floodlightDirectionScale=v6;
4073
4074                 floodlighty = qtrue;
4075                 Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
4076         }
4077         else
4078         {
4079                 VectorSet(floodlightRGB,240,240,255);
4080                 //floodlighty = qtrue;
4081                 //Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
4082         }
4083         VectorNormalize(floodlightRGB,floodlightRGB);
4084 }
4085
4086 /*
4087 FloodLightForSample()
4088 calculates floodlight value for a given sample
4089 once again, kudos to the dirtmapping coder
4090 */
4091
4092 float FloodLightForSample( trace_t *trace , float floodLightDistance, qboolean floodLightLowQuality)
4093 {
4094         int             i;
4095         float   d;
4096         float   contribution;
4097         int     sub = 0;
4098         float   gatherLight, outLight;
4099         vec3_t  normal, worldUp, myUp, myRt, direction, displacement;
4100         float   dd;
4101         int     vecs = 0;
4102  
4103         gatherLight=0;
4104         /* dummy check */
4105         //if( !dirty )
4106         //      return 1.0f;
4107         if( trace == NULL || trace->cluster < 0 )
4108                 return 0.0f;
4109         
4110
4111         /* setup */
4112         dd = floodLightDistance;
4113         VectorCopy( trace->normal, normal );
4114         
4115         /* check if the normal is aligned to the world-up */
4116         if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f && ( normal[ 2 ] == 1.0f || normal[ 2 ] == -1.0f ) )
4117         {
4118                 if( normal[ 2 ] == 1.0f )               
4119                 {
4120                         VectorSet( myRt, 1.0f, 0.0f, 0.0f );
4121                         VectorSet( myUp, 0.0f, 1.0f, 0.0f );
4122                 }
4123                 else if( normal[ 2 ] == -1.0f )
4124                 {
4125                         VectorSet( myRt, -1.0f, 0.0f, 0.0f );
4126                         VectorSet( myUp,  0.0f, 1.0f, 0.0f );
4127                 }
4128         }
4129         else
4130         {
4131                 VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
4132                 CrossProduct( normal, worldUp, myRt );
4133                 VectorNormalize( myRt, myRt );
4134                 CrossProduct( myRt, normal, myUp );
4135                 VectorNormalize( myUp, myUp );
4136         }
4137
4138         /* vortex: optimise floodLightLowQuality a bit */
4139         if ( floodLightLowQuality == qtrue )
4140     {
4141                 /* iterate through ordered vectors */
4142                 for( i = 0; i < numFloodVectors; i++ )
4143                         if (rand()%10 != 0 ) continue;
4144         }
4145         else
4146         {
4147                 /* iterate through ordered vectors */
4148                 for( i = 0; i < numFloodVectors; i++ )
4149                 {
4150                         vecs++;
4151                  
4152                         /* transform vector into tangent space */
4153                         direction[ 0 ] = myRt[ 0 ] * floodVectors[ i ][ 0 ] + myUp[ 0 ] * floodVectors[ i ][ 1 ] + normal[ 0 ] * floodVectors[ i ][ 2 ];
4154                         direction[ 1 ] = myRt[ 1 ] * floodVectors[ i ][ 0 ] + myUp[ 1 ] * floodVectors[ i ][ 1 ] + normal[ 1 ] * floodVectors[ i ][ 2 ];
4155                         direction[ 2 ] = myRt[ 2 ] * floodVectors[ i ][ 0 ] + myUp[ 2 ] * floodVectors[ i ][ 1 ] + normal[ 2 ] * floodVectors[ i ][ 2 ];
4156
4157                         /* set endpoint */
4158                         VectorMA( trace->origin, dd, direction, trace->end );
4159
4160                         //VectorMA( trace->origin, 1, direction, trace->origin );
4161                                 
4162                         SetupTrace( trace );
4163                         /* trace */
4164                         TraceLine( trace );
4165                         contribution=1;
4166
4167                         if ( trace->compileFlags & C_SKY || trace->compileFlags & C_TRANSLUCENT )
4168                         {
4169                                 contribution=1.0f;
4170                         }
4171                         else if ( trace->opaque )
4172                         {
4173                                 VectorSubtract( trace->hit, trace->origin, displacement );
4174                                 d=VectorLength( displacement );
4175
4176                                 // d=trace->distance;            
4177                                 //if (d>256) gatherDirt+=1;
4178                                 contribution=d/dd;
4179                                 if (contribution>1) contribution=1.0f; 
4180                      
4181                                 //gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
4182                         }
4183                  
4184                         gatherLight+=contribution;
4185                 }
4186         }
4187    
4188         /* early out */
4189         if( gatherLight <= 0.0f )
4190                 return 0.0f;
4191         
4192         sub=vecs;
4193
4194         if (sub<1) sub=1;
4195         gatherLight/=(sub);
4196
4197         outLight=gatherLight;
4198         if( outLight > 1.0f )
4199                 outLight = 1.0f;
4200         
4201         /* return to sender */
4202         return outLight;
4203 }
4204
4205 /*
4206 FloodLightRawLightmap
4207 lighttracer style ambient occlusion light hack.
4208 Kudos to the dirtmapping author for most of this source.
4209 VorteX: modified to floodlight up custom surfaces (q3map_floodLight)
4210 VorteX: fixed problems with deluxemapping
4211 */
4212
4213 // floodlight pass on a lightmap
4214 void FloodLightRawLightmapPass( rawLightmap_t *lm , vec3_t lmFloodLightRGB, float lmFloodLightIntensity, float lmFloodLightDistance, qboolean lmFloodLightLowQuality, float floodlightDirectionScale)
4215 {
4216         int                                     i, x, y, *cluster;
4217         float                           *origin, *normal, *floodlight, floodLightAmount;
4218         surfaceInfo_t           *info;
4219         trace_t                         trace;
4220         // int sx, sy;
4221         // float samples, average, *floodlight2;
4222         
4223         memset(&trace,0,sizeof(trace_t));
4224
4225         /* setup trace */
4226         trace.testOcclusion = qtrue;
4227         trace.forceSunlight = qfalse;
4228         trace.twoSided = qtrue;
4229         trace.recvShadows = lm->recvShadows;
4230         trace.numSurfaces = lm->numLightSurfaces;
4231         trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
4232         trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
4233         trace.testAll = qfalse;
4234         trace.distance = 1024;
4235         
4236         /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
4237         //trace.twoSided = qfalse;
4238         for( i = 0; i < trace.numSurfaces; i++ )
4239         {
4240                 /* get surface */
4241                 info = &surfaceInfos[ trace.surfaces[ i ] ];
4242                 
4243                 /* check twosidedness */
4244                 if( info->si->twoSided )
4245                 {
4246                         trace.twoSided = qtrue;
4247                         break;
4248                 }
4249         }
4250         
4251         /* gather floodlight */
4252         for( y = 0; y < lm->sh; y++ )
4253         {
4254                 for( x = 0; x < lm->sw; x++ )
4255                 {
4256                         /* get luxel */
4257                         cluster = SUPER_CLUSTER( x, y );
4258                         origin = SUPER_ORIGIN( x, y );
4259                         normal = SUPER_NORMAL( x, y );
4260                         floodlight = SUPER_FLOODLIGHT( x, y );
4261                         
4262                         /* set default dirt */
4263                         *floodlight = 0.0f;
4264                         
4265                         /* only look at mapped luxels */
4266                         if( *cluster < 0 )
4267                                 continue;
4268                         
4269                         /* copy to trace */
4270                         trace.cluster = *cluster;
4271                         VectorCopy( origin, trace.origin );
4272                         VectorCopy( normal, trace.normal );
4273    
4274                         /* get floodlight */
4275                         floodLightAmount = FloodLightForSample( &trace , lmFloodLightDistance, lmFloodLightLowQuality)*lmFloodLightIntensity;
4276                         
4277                         /* add floodlight */
4278                         floodlight[0] += lmFloodLightRGB[0]*floodLightAmount;
4279                         floodlight[1] += lmFloodLightRGB[1]*floodLightAmount;
4280                         floodlight[2] += lmFloodLightRGB[2]*floodLightAmount;
4281                         floodlight[3] += floodlightDirectionScale;
4282                 }
4283         }
4284         
4285         /* testing no filtering */
4286         return;
4287
4288 #if 0
4289         
4290         /* filter "dirt" */
4291         for( y = 0; y < lm->sh; y++ )
4292         {
4293                 for( x = 0; x < lm->sw; x++ )
4294                 {
4295                         /* get luxel */
4296                         cluster = SUPER_CLUSTER( x, y );
4297                         floodlight = SUPER_FLOODLIGHT(x, y );
4298                         
4299                         /* filter dirt by adjacency to unmapped luxels */
4300                         average = *floodlight;
4301                         samples = 1.0f;
4302                         for( sy = (y - 1); sy <= (y + 1); sy++ )
4303                         {
4304                                 if( sy < 0 || sy >= lm->sh )
4305                                         continue;
4306                                 
4307                                 for( sx = (x - 1); sx <= (x + 1); sx++ )
4308                                 {
4309                                         if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
4310                                                 continue;
4311                                         
4312                                         /* get neighboring luxel */
4313                                         cluster = SUPER_CLUSTER( sx, sy );
4314                                         floodlight2 = SUPER_FLOODLIGHT( sx, sy );
4315                                         if( *cluster < 0 || *floodlight2 <= 0.0f )
4316                                                 continue;
4317                                         
4318                                         /* add it */
4319                                         average += *floodlight2;
4320                                         samples += 1.0f;
4321                                 }
4322                                 
4323                                 /* bail */
4324                                 if( samples <= 0.0f )
4325                                         break;
4326                         }
4327                         
4328                         /* bail */
4329                         if( samples <= 0.0f )
4330                                 continue;
4331                         
4332                         /* scale dirt */
4333                         *floodlight = average / samples;
4334                 }
4335         }
4336 #endif
4337 }
4338
4339 void FloodLightRawLightmap( int rawLightmapNum )
4340 {
4341         rawLightmap_t           *lm;
4342
4343         /* bail if this number exceeds the number of raw lightmaps */
4344         if( rawLightmapNum >= numRawLightmaps )
4345                 return;
4346         /* get lightmap */
4347         lm = &rawLightmaps[ rawLightmapNum ];
4348
4349         /* global pass */
4350         if (floodlighty && floodlightIntensity)
4351                 FloodLightRawLightmapPass(lm, floodlightRGB, floodlightIntensity, floodlightDistance, floodlight_lowquality, floodlightDirectionScale);
4352
4353         /* custom pass */
4354         if (lm->floodlightIntensity)
4355         {
4356                 FloodLightRawLightmapPass(lm, lm->floodlightRGB, lm->floodlightIntensity, lm->floodlightDistance, qfalse, lm->floodlightDirectionScale);
4357                 numSurfacesFloodlighten += 1;
4358         }
4359 }
4360
4361 void FloodlightRawLightmaps()
4362 {
4363         Sys_Printf( "--- FloodlightRawLightmap ---\n" );
4364         numSurfacesFloodlighten = 0;
4365         RunThreadsOnIndividual( numRawLightmaps, qtrue, FloodLightRawLightmap );
4366         Sys_Printf( "%9d custom lightmaps floodlighted\n", numSurfacesFloodlighten );
4367 }
4368
4369 /*
4370 FloodLightIlluminate()
4371 illuminate floodlight into lightmap luxels
4372 */
4373
4374 void FloodlightIlluminateLightmap( rawLightmap_t *lm )
4375 {
4376         float                           *luxel, *floodlight, *deluxel, *normal;
4377         int                                     *cluster;
4378         float                           brightness;
4379         int                                     x, y, lightmapNum;
4380
4381         /* walk lightmaps */
4382         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
4383         {
4384                 /* early out */
4385                 if( lm->superLuxels[ lightmapNum ] == NULL )
4386                         continue;
4387
4388                 /* apply floodlight to each luxel */
4389                 for( y = 0; y < lm->sh; y++ )
4390                 {
4391                         for( x = 0; x < lm->sw; x++ )
4392                         {
4393                                 /* get floodlight */
4394                                 floodlight = SUPER_FLOODLIGHT( x, y );
4395                                 if (!floodlight[0] && !floodlight[1] && !floodlight[2])
4396                                         continue;
4397                                                 
4398                                 /* get cluster */
4399                                 cluster = SUPER_CLUSTER( x, y );
4400
4401                                 /* only process mapped luxels */
4402                                 if( *cluster < 0 )
4403                                         continue;
4404
4405                                 /* get particulars */
4406                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
4407                                 deluxel = SUPER_DELUXEL( x, y );
4408
4409                                 /* add to lightmap */
4410                                 luxel[0]+=floodlight[0];
4411                                 luxel[1]+=floodlight[1];
4412                                 luxel[2]+=floodlight[2];
4413
4414                                 if (luxel[3]==0) luxel[3]=1;
4415
4416                                 /* add to deluxemap */
4417                                 if (deluxemap && floodlight[3] > 0)
4418                                 {
4419                                         vec3_t                          lightvector;
4420
4421                                         normal = SUPER_NORMAL( x, y );
4422                                         brightness = RGBTOGRAY( floodlight ) * ( 1.0f/255.0f ) * floodlight[3];
4423
4424                                         // use AT LEAST this amount of contribution from ambient for the deluxemap, fixes points that receive ZERO light
4425                                         if(brightness < 0.00390625f)
4426                                                 brightness = 0.00390625f;
4427
4428                                         VectorScale( normal, brightness, lightvector );
4429                                         VectorAdd( deluxel, lightvector, deluxel );
4430                                 }
4431                         }
4432                 }
4433         }
4434 }