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