]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/light_ydnar.c
Merge commit 'c92c662abbbbc7ed93f628ad0e0f25e996ab686c' into garux-merge
[xonotic/netradiant.git] / tools / quake3 / q3map2 / light_ydnar.c
1 /* -------------------------------------------------------------------------------
2
3    Copyright (C) 1999-2007 id Software, Inc. and contributors.
4    For a list of contributors, see the accompanying CONTRIBUTORS file.
5
6    This file is part of GtkRadiant.
7
8    GtkRadiant is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    GtkRadiant is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with GtkRadiant; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21
22    ----------------------------------------------------------------------------------
23
24    This code has been altered significantly from its original form, to support
25    several games based on the Quake III Arena engine, in the form of "Q3Map2."
26
27    ------------------------------------------------------------------------------- */
28
29
30
31 /* marker */
32 #define LIGHT_YDNAR_C
33
34
35
36 /* dependencies */
37 #include "q3map2.h"
38
39
40
41
42 /*
43    ColorToBytes()
44    ydnar: moved to here 2001-02-04
45  */
46
47 void ColorToBytes( const float *color, byte *colorBytes, float scale ){
48         int i;
49         float max, gamma;
50         vec3_t sample;
51         float inv, dif;
52
53
54         /* ydnar: scaling necessary for simulating r_overbrightBits on external lightmaps */
55         if ( scale <= 0.0f ) {
56                 scale = 1.0f;
57         }
58         /* globally */
59         scale *= lightmapBrightness;
60
61         /* make a local copy */
62         VectorScale( color, scale, sample );
63
64         /* muck with it */
65         gamma = 1.0f / lightmapGamma;
66         for ( i = 0; i < 3; i++ )
67         {
68                 /* handle negative light */
69                 if ( sample[ i ] < 0.0f ) {
70                         sample[ i ] = 0.0f;
71                         continue;
72                 }
73
74                 /* gamma */
75                 sample[ i ] = pow( sample[ i ] / 255.0f, gamma ) * 255.0f;
76         }
77
78         if ( lightmapExposure == 0 ) {
79                 /* clamp with color normalization */
80                 max = sample[ 0 ];
81                 if ( sample[ 1 ] > max ) {
82                         max = sample[ 1 ];
83                 }
84                 if ( sample[ 2 ] > max ) {
85                         max = sample[ 2 ];
86                 }
87                 if ( max > 255.0f ) {
88                         VectorScale( sample, ( 255.0f / max ), sample );
89                 }
90         }
91         else
92         {
93                 inv = 1.f / lightmapExposure;
94                 //Exposure
95
96                 max = sample[ 0 ];
97                 if ( sample[ 1 ] > max ) {
98                         max = sample[ 1 ];
99                 }
100                 if ( sample[ 2 ] > max ) {
101                         max = sample[ 2 ];
102                 }
103
104                 dif = ( 1 -  exp( -max * inv ) )  *  255;
105
106                 if ( max > 0 ) {
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         /* contrast */
125         if ( lightmapContrast != 1.0f ){
126                 for ( i = 0; i < 3; i++ ){
127                         sample[i] = lightmapContrast * ( sample[i] - 128 ) + 128;
128                         if ( sample[i] < 0 ){
129                                 sample[i] = 0;
130                         }
131                 }
132                 if ( ( sample[0] > 255 ) || ( sample[1] > 255 ) || ( sample[2] > 255 ) ) {
133                         max = sample[0] > sample[1] ? sample[0] : sample[1];
134                         max = max > sample[2] ? max : sample[2];
135                         sample[0] = sample[0] * 255 / max;
136                         sample[1] = sample[1] * 255 / max;
137                         sample[2] = sample[2] * 255 / max;
138                 }
139         }
140
141         /* sRGB lightmaps */
142         if ( lightmapsRGB ) {
143                 sample[0] = floor( Image_sRGBFloatFromLinearFloat( sample[0] * ( 1.0 / 255.0 ) ) * 255.0 + 0.5 );
144                 sample[1] = floor( Image_sRGBFloatFromLinearFloat( sample[1] * ( 1.0 / 255.0 ) ) * 255.0 + 0.5 );
145                 sample[2] = floor( Image_sRGBFloatFromLinearFloat( sample[2] * ( 1.0 / 255.0 ) ) * 255.0 + 0.5 );
146         }
147
148         /* store it off */
149         colorBytes[ 0 ] = sample[ 0 ];
150         colorBytes[ 1 ] = sample[ 1 ];
151         colorBytes[ 2 ] = sample[ 2 ];
152 }
153
154
155
156 /* -------------------------------------------------------------------------------
157
158    this section deals with phong shading (normal interpolation across brush faces)
159
160    ------------------------------------------------------------------------------- */
161
162 /*
163    SmoothNormals()
164    smooths together coincident vertex normals across the bsp
165  */
166
167 #define MAX_SAMPLES             256
168 #define THETA_EPSILON           0.000001
169 #define EQUAL_NORMAL_EPSILON    0.01
170
171 void SmoothNormals( void ){
172         int i, j, k, f, cs, numVerts, numVotes, fOld, start;
173         float shadeAngle, defaultShadeAngle, maxShadeAngle, dot, testAngle;
174         bspDrawSurface_t    *ds;
175         shaderInfo_t        *si;
176         float               *shadeAngles;
177         byte                *smoothed;
178         vec3_t average, diff;
179         int indexes[ MAX_SAMPLES ];
180         vec3_t votes[ MAX_SAMPLES ];
181
182
183         /* allocate shade angle table */
184         shadeAngles = safe_malloc( numBSPDrawVerts * sizeof( float ) );
185         memset( shadeAngles, 0, numBSPDrawVerts * sizeof( float ) );
186
187         /* allocate smoothed table */
188         cs = ( numBSPDrawVerts / 8 ) + 1;
189         smoothed = safe_malloc( cs );
190         memset( smoothed, 0, cs );
191
192         /* set default shade angle */
193         defaultShadeAngle = DEG2RAD( shadeAngleDegrees );
194         maxShadeAngle = 0;
195
196         /* run through every surface and flag verts belonging to non-lightmapped surfaces
197            and set per-vertex smoothing angle */
198         for ( i = 0; i < numBSPDrawSurfaces; i++ )
199         {
200                 /* get drawsurf */
201                 ds = &bspDrawSurfaces[ i ];
202
203                 /* get shader for shade angle */
204                 si = surfaceInfos[ i ].si;
205                 if ( si->shadeAngleDegrees ) {
206                         shadeAngle = DEG2RAD( si->shadeAngleDegrees );
207                 }
208                 else{
209                         shadeAngle = defaultShadeAngle;
210                 }
211                 if ( shadeAngle > maxShadeAngle ) {
212                         maxShadeAngle = shadeAngle;
213                 }
214
215                 /* flag its verts */
216                 for ( j = 0; j < ds->numVerts; j++ )
217                 {
218                         f = ds->firstVert + j;
219                         shadeAngles[ f ] = shadeAngle;
220                         if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
221                                 smoothed[ f >> 3 ] |= ( 1 << ( f & 7 ) );
222                         }
223                 }
224
225                 /* ydnar: optional force-to-trisoup */
226                 if ( trisoup && ds->surfaceType == MST_PLANAR ) {
227                         ds->surfaceType = MST_TRIANGLE_SOUP;
228                         ds->lightmapNum[ 0 ] = -3;
229                 }
230         }
231
232         /* bail if no surfaces have a shade angle */
233         if ( maxShadeAngle == 0 ) {
234                 free( shadeAngles );
235                 free( smoothed );
236                 return;
237         }
238
239         /* init pacifier */
240         fOld = -1;
241         start = I_FloatTime();
242
243         /* go through the list of vertexes */
244         for ( i = 0; i < numBSPDrawVerts; i++ )
245         {
246                 /* print pacifier */
247                 f = 10 * i / numBSPDrawVerts;
248                 if ( f != fOld ) {
249                         fOld = f;
250                         Sys_Printf( "%i...", f );
251                 }
252
253                 /* already smoothed? */
254                 if ( smoothed[ i >> 3 ] & ( 1 << ( i & 7 ) ) ) {
255                         continue;
256                 }
257
258                 /* clear */
259                 VectorClear( average );
260                 numVerts = 0;
261                 numVotes = 0;
262
263                 /* build a table of coincident vertexes */
264                 for ( j = i; j < numBSPDrawVerts && numVerts < MAX_SAMPLES; j++ )
265                 {
266                         /* already smoothed? */
267                         if ( smoothed[ j >> 3 ] & ( 1 << ( j & 7 ) ) ) {
268                                 continue;
269                         }
270
271                         /* test vertexes */
272                         if ( VectorCompare( yDrawVerts[ i ].xyz, yDrawVerts[ j ].xyz ) == qfalse ) {
273                                 continue;
274                         }
275
276                         /* use smallest shade angle */
277                         shadeAngle = ( shadeAngles[ i ] < shadeAngles[ j ] ? shadeAngles[ i ] : shadeAngles[ j ] );
278
279                         /* check shade angle */
280                         dot = DotProduct( bspDrawVerts[ i ].normal, bspDrawVerts[ j ].normal );
281                         if ( dot > 1.0 ) {
282                                 dot = 1.0;
283                         }
284                         else if ( dot < -1.0 ) {
285                                 dot = -1.0;
286                         }
287                         testAngle = acos( dot ) + THETA_EPSILON;
288                         if ( testAngle >= shadeAngle ) {
289                                 //Sys_Printf( "F(%3.3f >= %3.3f) ", RAD2DEG( testAngle ), RAD2DEG( shadeAngle ) );
290                                 continue;
291                         }
292                         //Sys_Printf( "P(%3.3f < %3.3f) ", RAD2DEG( testAngle ), RAD2DEG( shadeAngle ) );
293
294                         /* add to the list */
295                         indexes[ numVerts++ ] = j;
296
297                         /* flag vertex */
298                         smoothed[ j >> 3 ] |= ( 1 << ( j & 7 ) );
299
300                         /* see if this normal has already been voted */
301                         for ( k = 0; k < numVotes; k++ )
302                         {
303                                 VectorSubtract( bspDrawVerts[ j ].normal, votes[ k ], diff );
304                                 if ( fabs( diff[ 0 ] ) < EQUAL_NORMAL_EPSILON &&
305                                          fabs( diff[ 1 ] ) < EQUAL_NORMAL_EPSILON &&
306                                          fabs( diff[ 2 ] ) < EQUAL_NORMAL_EPSILON ) {
307                                         break;
308                                 }
309                         }
310
311                         /* add a new vote? */
312                         if ( k == numVotes && numVotes < MAX_SAMPLES ) {
313                                 VectorAdd( average, bspDrawVerts[ j ].normal, average );
314                                 VectorCopy( bspDrawVerts[ j ].normal, votes[ numVotes ] );
315                                 numVotes++;
316                         }
317                 }
318
319                 /* don't average for less than 2 verts */
320                 if ( numVerts < 2 ) {
321                         continue;
322                 }
323
324                 /* average normal */
325                 if ( VectorNormalize( average, average ) > 0 ) {
326                         /* smooth */
327                         for ( j = 0; j < numVerts; j++ )
328                                 VectorCopy( average, yDrawVerts[ indexes[ j ] ].normal );
329                 }
330         }
331
332         /* free the tables */
333         free( shadeAngles );
334         free( smoothed );
335
336         /* print time */
337         Sys_Printf( " (%i)\n", (int) ( I_FloatTime() - start ) );
338 }
339
340
341
342 /* -------------------------------------------------------------------------------
343
344    this section deals with phong shaded lightmap tracing
345
346    ------------------------------------------------------------------------------- */
347
348 /* 9th rewrite (recursive subdivision of a lightmap triangle) */
349
350 /*
351    CalcTangentVectors()
352    calculates the st tangent vectors for normalmapping
353  */
354
355 static qboolean CalcTangentVectors( int numVerts, bspDrawVert_t **dv, vec3_t *stv, vec3_t *ttv ){
356         int i;
357         float bb, s, t;
358         vec3_t bary;
359
360
361         /* calculate barycentric basis for the triangle */
362         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 ] );
363         if ( fabs( bb ) < 0.00000001f ) {
364                 return qfalse;
365         }
366
367         /* do each vertex */
368         for ( i = 0; i < numVerts; i++ )
369         {
370                 /* calculate s tangent vector */
371                 s = dv[ i ]->st[ 0 ] + 10.0f;
372                 t = dv[ i ]->st[ 1 ];
373                 bary[ 0 ] = ( ( dv[ 1 ]->st[ 0 ] - s ) * ( dv[ 2 ]->st[ 1 ] - t ) - ( dv[ 2 ]->st[ 0 ] - s ) * ( dv[ 1 ]->st[ 1 ] - t ) ) / bb;
374                 bary[ 1 ] = ( ( dv[ 2 ]->st[ 0 ] - s ) * ( dv[ 0 ]->st[ 1 ] - t ) - ( dv[ 0 ]->st[ 0 ] - s ) * ( dv[ 2 ]->st[ 1 ] - t ) ) / bb;
375                 bary[ 2 ] = ( ( dv[ 0 ]->st[ 0 ] - s ) * ( dv[ 1 ]->st[ 1 ] - t ) - ( dv[ 1 ]->st[ 0 ] - s ) * ( dv[ 0 ]->st[ 1 ] - t ) ) / bb;
376
377                 stv[ i ][ 0 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 0 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 0 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 0 ];
378                 stv[ i ][ 1 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 1 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 1 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 1 ];
379                 stv[ i ][ 2 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 2 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 2 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 2 ];
380
381                 VectorSubtract( stv[ i ], dv[ i ]->xyz, stv[ i ] );
382                 VectorNormalize( stv[ i ], stv[ i ] );
383
384                 /* calculate t tangent vector */
385                 s = dv[ i ]->st[ 0 ];
386                 t = dv[ i ]->st[ 1 ] + 10.0f;
387                 bary[ 0 ] = ( ( dv[ 1 ]->st[ 0 ] - s ) * ( dv[ 2 ]->st[ 1 ] - t ) - ( dv[ 2 ]->st[ 0 ] - s ) * ( dv[ 1 ]->st[ 1 ] - t ) ) / bb;
388                 bary[ 1 ] = ( ( dv[ 2 ]->st[ 0 ] - s ) * ( dv[ 0 ]->st[ 1 ] - t ) - ( dv[ 0 ]->st[ 0 ] - s ) * ( dv[ 2 ]->st[ 1 ] - t ) ) / bb;
389                 bary[ 2 ] = ( ( dv[ 0 ]->st[ 0 ] - s ) * ( dv[ 1 ]->st[ 1 ] - t ) - ( dv[ 1 ]->st[ 0 ] - s ) * ( dv[ 0 ]->st[ 1 ] - t ) ) / bb;
390
391                 ttv[ i ][ 0 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 0 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 0 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 0 ];
392                 ttv[ i ][ 1 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 1 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 1 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 1 ];
393                 ttv[ i ][ 2 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 2 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 2 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 2 ];
394
395                 VectorSubtract( ttv[ i ], dv[ i ]->xyz, ttv[ i ] );
396                 VectorNormalize( ttv[ i ], ttv[ i ] );
397
398                 /* debug code */
399                 //%     Sys_FPrintf( SYS_VRB, "%d S: (%f %f %f) T: (%f %f %f)\n", i,
400                 //%             stv[ i ][ 0 ], stv[ i ][ 1 ], stv[ i ][ 2 ], ttv[ i ][ 0 ], ttv[ i ][ 1 ], ttv[ i ][ 2 ] );
401         }
402
403         /* return to caller */
404         return qtrue;
405 }
406
407
408
409
410 /*
411    PerturbNormal()
412    perterbs the normal by the shader's normalmap in tangent space
413  */
414
415 static void PerturbNormal( bspDrawVert_t *dv, shaderInfo_t *si, vec3_t pNormal, vec3_t stv[ 3 ], vec3_t ttv[ 3 ] ){
416         int i;
417         vec4_t bump;
418
419
420         /* passthrough */
421         VectorCopy( dv->normal, pNormal );
422
423         /* sample normalmap */
424         if ( RadSampleImage( si->normalImage->pixels, si->normalImage->width, si->normalImage->height, dv->st, bump ) == qfalse ) {
425                 return;
426         }
427
428         /* remap sampled normal from [0,255] to [-1,-1] */
429         for ( i = 0; i < 3; i++ )
430                 bump[ i ] = ( bump[ i ] - 127.0f ) * ( 1.0f / 127.5f );
431
432         /* scale tangent vectors and add to original normal */
433         VectorMA( dv->normal, bump[ 0 ], stv[ 0 ], pNormal );
434         VectorMA( pNormal, bump[ 1 ], ttv[ 0 ], pNormal );
435         VectorMA( pNormal, bump[ 2 ], dv->normal, pNormal );
436
437         /* renormalize and return */
438         VectorNormalize( pNormal, pNormal );
439 }
440
441
442
443 /*
444    MapSingleLuxel()
445    maps a luxel for triangle bv at
446  */
447
448 #define NUDGE           0.5f
449 #define BOGUS_NUDGE     -99999.0f
450
451 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 ] ){
452         int i, x, y, numClusters, *clusters, pointCluster, *cluster;
453         float           *luxel, *origin, *normal, d, lightmapSampleOffset;
454         shaderInfo_t    *si;
455         vec3_t pNormal;
456         vec3_t vecs[ 3 ];
457         vec3_t nudged;
458         vec3_t cverts[ 3 ];
459         vec3_t temp;
460         vec4_t sideplane, hostplane;
461         vec3_t origintwo;
462         int j, next;
463         float e;
464         float           *nudge;
465         static float nudges[][ 2 ] =
466         {
467                 //%{ 0, 0 },            /* try center first */
468                 { -NUDGE, 0 },                      /* left */
469                 { NUDGE, 0 },                       /* right */
470                 { 0, NUDGE },                       /* up */
471                 { 0, -NUDGE },                      /* down */
472                 { -NUDGE, NUDGE },                  /* left/up */
473                 { NUDGE, -NUDGE },                  /* right/down */
474                 { NUDGE, NUDGE },                   /* right/up */
475                 { -NUDGE, -NUDGE },                 /* left/down */
476                 { BOGUS_NUDGE, BOGUS_NUDGE }
477         };
478
479
480         /* find luxel xy coords (fixme: subtract 0.5?) */
481         x = dv->lightmap[ 0 ][ 0 ];
482         y = dv->lightmap[ 0 ][ 1 ];
483         if ( x < 0 ) {
484                 x = 0;
485         }
486         else if ( x >= lm->sw ) {
487                 x = lm->sw - 1;
488         }
489         if ( y < 0 ) {
490                 y = 0;
491         }
492         else if ( y >= lm->sh ) {
493                 y = lm->sh - 1;
494         }
495
496         /* set shader and cluster list */
497         if ( info != NULL ) {
498                 si = info->si;
499                 numClusters = info->numSurfaceClusters;
500                 clusters = &surfaceClusters[ info->firstSurfaceCluster ];
501         }
502         else
503         {
504                 si = NULL;
505                 numClusters = 0;
506                 clusters = NULL;
507         }
508
509         /* get luxel, origin, cluster, and normal */
510         luxel = SUPER_LUXEL( 0, x, y );
511         origin = SUPER_ORIGIN( x, y );
512         normal = SUPER_NORMAL( x, y );
513         cluster = SUPER_CLUSTER( x, y );
514
515         /* don't attempt to remap occluded luxels for planar surfaces */
516         if ( ( *cluster ) == CLUSTER_OCCLUDED && lm->plane != NULL ) {
517                 return ( *cluster );
518         }
519
520         /* only average the normal for premapped luxels */
521         else if ( ( *cluster ) >= 0 ) {
522                 /* do bumpmap calculations */
523                 if ( stv != NULL ) {
524                         PerturbNormal( dv, si, pNormal, stv, ttv );
525                 }
526                 else{
527                         VectorCopy( dv->normal, pNormal );
528                 }
529
530                 /* add the additional normal data */
531                 VectorAdd( normal, pNormal, normal );
532                 luxel[ 3 ] += 1.0f;
533                 return ( *cluster );
534         }
535
536         /* otherwise, unmapped luxels (*cluster == CLUSTER_UNMAPPED) will have their full attributes calculated */
537
538         /* get origin */
539
540         /* axial lightmap projection */
541         if ( lm->vecs != NULL ) {
542                 /* calculate an origin for the sample from the lightmap vectors */
543                 VectorCopy( lm->origin, origin );
544                 for ( i = 0; i < 3; i++ )
545                 {
546                         /* add unless it's the axis, which is taken care of later */
547                         if ( i == lm->axisNum ) {
548                                 continue;
549                         }
550                         origin[ i ] += ( x * lm->vecs[ 0 ][ i ] ) + ( y * lm->vecs[ 1 ][ i ] );
551                 }
552
553                 /* project the origin onto the plane */
554                 d = DotProduct( origin, plane ) - plane[ 3 ];
555                 d /= plane[ lm->axisNum ];
556                 origin[ lm->axisNum ] -= d;
557         }
558
559         /* non axial lightmap projection (explicit xyz) */
560         else{
561                 VectorCopy( dv->xyz, origin );
562         }
563
564         //////////////////////
565         //27's test to make sure samples stay within the triangle boundaries
566         //1) Test the sample origin to see if it lays on the wrong side of any edge (x/y)
567         //2) if it does, nudge it onto the correct side.
568
569         if ( worldverts != NULL && lightmapTriangleCheck ) {
570                 for ( j = 0; j < 3; j++ )
571                 {
572                         VectorCopy( worldverts[j],cverts[j] );
573                 }
574                 PlaneFromPoints( hostplane,cverts[0],cverts[1],cverts[2] );
575
576                 for ( j = 0; j < 3; j++ )
577                 {
578                         for ( i = 0; i < 3; i++ )
579                         {
580                                 //build plane using 2 edges and a normal
581                                 next = ( i + 1 ) % 3;
582
583                                 VectorCopy( cverts[next],temp );
584                                 VectorAdd( temp,hostplane,temp );
585                                 PlaneFromPoints( sideplane,cverts[i],cverts[ next ], temp );
586
587                                 //planetest sample point
588                                 e = DotProduct( origin,sideplane );
589                                 e = e - sideplane[3];
590                                 if ( e > 0 ) {
591                                         //we're bad.
592                                         //VectorClear(origin);
593                                         //Move the sample point back inside triangle bounds
594                                         origin[0] -= sideplane[0] * ( e + 1 );
595                                         origin[1] -= sideplane[1] * ( e + 1 );
596                                         origin[2] -= sideplane[2] * ( e + 1 );
597 #ifdef DEBUG_27_1
598                                         VectorClear( origin );
599 #endif
600                                 }
601                         }
602                 }
603         }
604
605         ////////////////////////
606
607         /* planar surfaces have precalculated lightmap vectors for nudging */
608         if ( lm->plane != NULL ) {
609                 VectorCopy( lm->vecs[ 0 ], vecs[ 0 ] );
610                 VectorCopy( lm->vecs[ 1 ], vecs[ 1 ] );
611                 VectorCopy( lm->plane, vecs[ 2 ] );
612         }
613
614         /* non-planar surfaces must calculate them */
615         else
616         {
617                 if ( plane != NULL ) {
618                         VectorCopy( plane, vecs[ 2 ] );
619                 }
620                 else{
621                         VectorCopy( dv->normal, vecs[ 2 ] );
622                 }
623                 MakeNormalVectors( vecs[ 2 ], vecs[ 0 ], vecs[ 1 ] );
624         }
625
626         /* push the origin off the surface a bit */
627         if ( si != NULL ) {
628                 lightmapSampleOffset = si->lightmapSampleOffset;
629         }
630         else{
631                 lightmapSampleOffset = DEFAULT_LIGHTMAP_SAMPLE_OFFSET;
632         }
633         if ( lm->axisNum < 0 ) {
634                 VectorMA( origin, lightmapSampleOffset, vecs[ 2 ], origin );
635         }
636         else if ( vecs[ 2 ][ lm->axisNum ] < 0.0f ) {
637                 origin[ lm->axisNum ] -= lightmapSampleOffset;
638         }
639         else{
640                 origin[ lm->axisNum ] += lightmapSampleOffset;
641         }
642
643         VectorCopy( origin,origintwo );
644         if ( lightmapExtraVisClusterNudge ) {
645                 origintwo[0] += vecs[2][0];
646                 origintwo[1] += vecs[2][1];
647                 origintwo[2] += vecs[2][2];
648         }
649
650         /* get cluster */
651         pointCluster = ClusterForPointExtFilter( origintwo, LUXEL_EPSILON, numClusters, clusters );
652
653         /* another retarded hack, storing nudge count in luxel[ 1 ] */
654         luxel[ 1 ] = 0.0f;
655
656         /* point in solid? (except in dark mode) */
657         if ( pointCluster < 0 && dark == qfalse ) {
658                 /* nudge the the location around */
659                 nudge = nudges[ 0 ];
660                 while ( nudge[ 0 ] > BOGUS_NUDGE && pointCluster < 0 )
661                 {
662                         /* nudge the vector around a bit */
663                         for ( i = 0; i < 3; i++ )
664                         {
665                                 /* set nudged point*/
666                                 nudged[ i ] = origintwo[ i ] + ( nudge[ 0 ] * vecs[ 0 ][ i ] ) + ( nudge[ 1 ] * vecs[ 1 ][ i ] );
667                         }
668                         nudge += 2;
669
670                         /* get pvs cluster */
671                         pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); //% + 0.625 );
672                         if ( pointCluster >= 0 ) {
673                                 VectorCopy( nudged, origin );
674                         }
675                         luxel[ 1 ] += 1.0f;
676                 }
677         }
678
679         /* as a last resort, if still in solid, try drawvert origin offset by normal (except in dark mode) */
680         if ( pointCluster < 0 && si != NULL && dark == qfalse ) {
681                 VectorMA( dv->xyz, lightmapSampleOffset, dv->normal, nudged );
682                 pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters );
683                 if ( pointCluster >= 0 ) {
684                         VectorCopy( nudged, origin );
685                 }
686                 luxel[ 1 ] += 1.0f;
687         }
688
689         /* valid? */
690         if ( pointCluster < 0 ) {
691                 ( *cluster ) = CLUSTER_OCCLUDED;
692                 VectorClear( origin );
693                 VectorClear( normal );
694                 numLuxelsOccluded++;
695                 return ( *cluster );
696         }
697
698         /* debug code */
699         //%     Sys_Printf( "%f %f %f\n", origin[ 0 ], origin[ 1 ], origin[ 2 ] );
700
701         /* do bumpmap calculations */
702         if ( stv ) {
703                 PerturbNormal( dv, si, pNormal, stv, ttv );
704         }
705         else{
706                 VectorCopy( dv->normal, pNormal );
707         }
708
709         /* store the cluster and normal */
710         ( *cluster ) = pointCluster;
711         VectorCopy( pNormal, normal );
712
713         /* store explicit mapping pass and implicit mapping pass */
714         luxel[ 0 ] = pass;
715         luxel[ 3 ] = 1.0f;
716
717         /* add to count */
718         numLuxelsMapped++;
719
720         /* return ok */
721         return ( *cluster );
722 }
723
724
725
726 /*
727    MapTriangle_r()
728    recursively subdivides a triangle until its edges are shorter
729    than the distance between two luxels (thanks jc :)
730  */
731
732 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 ] ){
733         bspDrawVert_t mid, *dv2[ 3 ];
734         int max;
735
736
737         /* map the vertexes */
738         #if 0
739         MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
740         MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
741         MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
742         #endif
743
744         /* subdivide calc */
745         {
746                 int i;
747                 float       *a, *b, dx, dy, dist, maxDist;
748
749
750                 /* find the longest edge and split it */
751                 max = -1;
752                 maxDist = 0;
753                 for ( i = 0; i < 3; i++ )
754                 {
755                         /* get verts */
756                         a = dv[ i ]->lightmap[ 0 ];
757                         b = dv[ ( i + 1 ) % 3 ]->lightmap[ 0 ];
758
759                         /* get dists */
760                         dx = a[ 0 ] - b[ 0 ];
761                         dy = a[ 1 ] - b[ 1 ];
762                         dist = ( dx * dx ) + ( dy * dy );   //% sqrt( (dx * dx) + (dy * dy) );
763
764                         /* longer? */
765                         if ( dist > maxDist ) {
766                                 maxDist = dist;
767                                 max = i;
768                         }
769                 }
770
771                 /* try to early out */
772                 if ( max < 0 || maxDist <= subdivideThreshold ) { /* ydnar: was i < 0 instead of max < 0 (?) */
773                         return;
774                 }
775         }
776
777         /* split the longest edge and map it */
778         LerpDrawVert( dv[ max ], dv[ ( max + 1 ) % 3 ], &mid );
779         MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv, worldverts );
780
781         /* push the point up a little bit to account for fp creep (fixme: revisit this) */
782         //%     VectorMA( mid.xyz, 2.0f, mid.normal, mid.xyz );
783
784         /* recurse to first triangle */
785         VectorCopy( dv, dv2 );
786         dv2[ max ] = &mid;
787         MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
788
789         /* recurse to second triangle */
790         VectorCopy( dv, dv2 );
791         dv2[ ( max + 1 ) % 3 ] = &mid;
792         MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
793 }
794
795
796
797 /*
798    MapTriangle()
799    seed function for MapTriangle_r()
800    requires a cw ordered triangle
801  */
802
803 static qboolean MapTriangle( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 3 ], qboolean mapNonAxial ){
804         int i;
805         vec4_t plane;
806         vec3_t          *stv, *ttv, stvStatic[ 3 ], ttvStatic[ 3 ];
807         vec3_t worldverts[ 3 ];
808
809
810         /* get plane if possible */
811         if ( lm->plane != NULL ) {
812                 VectorCopy( lm->plane, plane );
813                 plane[ 3 ] = lm->plane[ 3 ];
814         }
815
816         /* otherwise make one from the points */
817         else if ( PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) == qfalse ) {
818                 return qfalse;
819         }
820
821         /* check to see if we need to calculate texture->world tangent vectors */
822         if ( info->si->normalImage != NULL && CalcTangentVectors( 3, dv, stvStatic, ttvStatic ) ) {
823                 stv = stvStatic;
824                 ttv = ttvStatic;
825         }
826         else
827         {
828                 stv = NULL;
829                 ttv = NULL;
830         }
831
832         VectorCopy( dv[ 0 ]->xyz, worldverts[ 0 ] );
833         VectorCopy( dv[ 1 ]->xyz, worldverts[ 1 ] );
834         VectorCopy( dv[ 2 ]->xyz, worldverts[ 2 ] );
835
836         /* map the vertexes */
837         MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, worldverts );
838         MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, worldverts );
839         MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, worldverts );
840
841         /* 2002-11-20: prefer axial triangle edges */
842         if ( mapNonAxial ) {
843                 /* subdivide the triangle */
844                 MapTriangle_r( lm, info, dv, plane, stv, ttv, worldverts );
845                 return qtrue;
846         }
847
848         for ( i = 0; i < 3; i++ )
849         {
850                 float           *a, *b;
851                 bspDrawVert_t   *dv2[ 3 ];
852
853
854                 /* get verts */
855                 a = dv[ i ]->lightmap[ 0 ];
856                 b = dv[ ( i + 1 ) % 3 ]->lightmap[ 0 ];
857
858                 /* make degenerate triangles for mapping edges */
859                 if ( fabs( a[ 0 ] - b[ 0 ] ) < 0.01f || fabs( a[ 1 ] - b[ 1 ] ) < 0.01f ) {
860                         dv2[ 0 ] = dv[ i ];
861                         dv2[ 1 ] = dv[ ( i + 1 ) % 3 ];
862                         dv2[ 2 ] = dv[ ( i + 1 ) % 3 ];
863
864                         /* map the degenerate triangle */
865                         MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
866                 }
867         }
868
869         return qtrue;
870 }
871
872
873
874 /*
875    MapQuad_r()
876    recursively subdivides a quad until its edges are shorter
877    than the distance between two luxels
878  */
879
880 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 ] ){
881         bspDrawVert_t mid[ 2 ], *dv2[ 4 ];
882         int max;
883
884
885         /* subdivide calc */
886         {
887                 int i;
888                 float       *a, *b, dx, dy, dist, maxDist;
889
890
891                 /* find the longest edge and split it */
892                 max = -1;
893                 maxDist = 0;
894                 for ( i = 0; i < 4; i++ )
895                 {
896                         /* get verts */
897                         a = dv[ i ]->lightmap[ 0 ];
898                         b = dv[ ( i + 1 ) % 4 ]->lightmap[ 0 ];
899
900                         /* get dists */
901                         dx = a[ 0 ] - b[ 0 ];
902                         dy = a[ 1 ] - b[ 1 ];
903                         dist = ( dx * dx ) + ( dy * dy );   //% sqrt( (dx * dx) + (dy * dy) );
904
905                         /* longer? */
906                         if ( dist > maxDist ) {
907                                 maxDist = dist;
908                                 max = i;
909                         }
910                 }
911
912                 /* try to early out */
913                 if ( max < 0 || maxDist <= subdivideThreshold ) {
914                         return;
915                 }
916         }
917
918         /* we only care about even/odd edges */
919         max &= 1;
920
921         /* split the longest edges */
922         LerpDrawVert( dv[ max ], dv[ ( max + 1 ) % 4 ], &mid[ 0 ] );
923         LerpDrawVert( dv[ max + 2 ], dv[ ( max + 3 ) % 4 ], &mid[ 1 ] );
924
925         /* map the vertexes */
926         MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv, NULL );
927         MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv, NULL );
928
929         /* 0 and 2 */
930         if ( max == 0 ) {
931                 /* recurse to first quad */
932                 dv2[ 0 ] = dv[ 0 ];
933                 dv2[ 1 ] = &mid[ 0 ];
934                 dv2[ 2 ] = &mid[ 1 ];
935                 dv2[ 3 ] = dv[ 3 ];
936                 MapQuad_r( lm, info, dv2, plane, stv, ttv );
937
938                 /* recurse to second quad */
939                 dv2[ 0 ] = &mid[ 0 ];
940                 dv2[ 1 ] = dv[ 1 ];
941                 dv2[ 2 ] = dv[ 2 ];
942                 dv2[ 3 ] = &mid[ 1 ];
943                 MapQuad_r( lm, info, dv2, plane, stv, ttv );
944         }
945
946         /* 1 and 3 */
947         else
948         {
949                 /* recurse to first quad */
950                 dv2[ 0 ] = dv[ 0 ];
951                 dv2[ 1 ] = dv[ 1 ];
952                 dv2[ 2 ] = &mid[ 0 ];
953                 dv2[ 3 ] = &mid[ 1 ];
954                 MapQuad_r( lm, info, dv2, plane, stv, ttv );
955
956                 /* recurse to second quad */
957                 dv2[ 0 ] = &mid[ 1 ];
958                 dv2[ 1 ] = &mid[ 0 ];
959                 dv2[ 2 ] = dv[ 2 ];
960                 dv2[ 3 ] = dv[ 3 ];
961                 MapQuad_r( lm, info, dv2, plane, stv, ttv );
962         }
963 }
964
965
966
967 /*
968    MapQuad()
969    seed function for MapQuad_r()
970    requires a cw ordered triangle quad
971  */
972
973 #define QUAD_PLANAR_EPSILON     0.5f
974
975 static qboolean MapQuad( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 4 ] ){
976         float dist;
977         vec4_t plane;
978         vec3_t          *stv, *ttv, stvStatic[ 4 ], ttvStatic[ 4 ];
979
980
981         /* get plane if possible */
982         if ( lm->plane != NULL ) {
983                 VectorCopy( lm->plane, plane );
984                 plane[ 3 ] = lm->plane[ 3 ];
985         }
986
987         /* otherwise make one from the points */
988         else if ( PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) == qfalse ) {
989                 return qfalse;
990         }
991
992         /* 4th point must fall on the plane */
993         dist = DotProduct( plane, dv[ 3 ]->xyz ) - plane[ 3 ];
994         if ( fabs( dist ) > QUAD_PLANAR_EPSILON ) {
995                 return qfalse;
996         }
997
998         /* check to see if we need to calculate texture->world tangent vectors */
999         if ( info->si->normalImage != NULL && CalcTangentVectors( 4, dv, stvStatic, ttvStatic ) ) {
1000                 stv = stvStatic;
1001                 ttv = ttvStatic;
1002         }
1003         else
1004         {
1005                 stv = NULL;
1006                 ttv = NULL;
1007         }
1008
1009         /* map the vertexes */
1010         MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, NULL );
1011         MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, NULL );
1012         MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, NULL );
1013         MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv, NULL );
1014
1015         /* subdivide the quad */
1016         MapQuad_r( lm, info, dv, plane, stv, ttv );
1017         return qtrue;
1018 }
1019
1020
1021
1022 /*
1023    MapRawLightmap()
1024    maps the locations, normals, and pvs clusters for a raw lightmap
1025  */
1026
1027 #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)
1028
1029 void MapRawLightmap( int rawLightmapNum ){
1030         int n, num, i, x, y, sx, sy, pw[ 5 ], r, *cluster, mapNonAxial;
1031         float               *luxel, *origin, *normal, samples, radius, pass;
1032         rawLightmap_t       *lm;
1033         bspDrawSurface_t    *ds;
1034         surfaceInfo_t       *info;
1035         mesh_t src, *subdivided, *mesh;
1036         bspDrawVert_t       *verts, *dv[ 4 ], fake;
1037
1038
1039         /* bail if this number exceeds the number of raw lightmaps */
1040         if ( rawLightmapNum >= numRawLightmaps ) {
1041                 return;
1042         }
1043
1044         /* get lightmap */
1045         lm = &rawLightmaps[ rawLightmapNum ];
1046
1047         /* -----------------------------------------------------------------
1048            map referenced surfaces onto the raw lightmap
1049            ----------------------------------------------------------------- */
1050
1051         /* walk the list of surfaces on this raw lightmap */
1052         for ( n = 0; n < lm->numLightSurfaces; n++ )
1053         {
1054                 /* with > 1 surface per raw lightmap, clear occluded */
1055                 if ( n > 0 ) {
1056                         for ( y = 0; y < lm->sh; y++ )
1057                         {
1058                                 for ( x = 0; x < lm->sw; x++ )
1059                                 {
1060                                         /* get cluster */
1061                                         cluster = SUPER_CLUSTER( x, y );
1062                                         if ( *cluster < 0 ) {
1063                                                 *cluster = CLUSTER_UNMAPPED;
1064                                         }
1065                                 }
1066                         }
1067                 }
1068
1069                 /* get surface */
1070                 num = lightSurfaces[ lm->firstLightSurface + n ];
1071                 ds = &bspDrawSurfaces[ num ];
1072                 info = &surfaceInfos[ num ];
1073
1074                 /* bail if no lightmap to calculate */
1075                 if ( info->lm != lm ) {
1076                         Sys_Printf( "!" );
1077                         continue;
1078                 }
1079
1080                 /* map the surface onto the lightmap origin/cluster/normal buffers */
1081                 switch ( ds->surfaceType )
1082                 {
1083                 case MST_PLANAR:
1084                         /* get verts */
1085                         verts = yDrawVerts + ds->firstVert;
1086
1087                         /* map the triangles */
1088                         for ( mapNonAxial = 0; mapNonAxial < 2; mapNonAxial++ )
1089                         {
1090                                 for ( i = 0; i < ds->numIndexes; i += 3 )
1091                                 {
1092                                         dv[ 0 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i ] ];
1093                                         dv[ 1 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 1 ] ];
1094                                         dv[ 2 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 2 ] ];
1095                                         MapTriangle( lm, info, dv, mapNonAxial );
1096                                 }
1097                         }
1098                         break;
1099
1100                 case MST_PATCH:
1101                         /* make a mesh from the drawsurf */
1102                         src.width = ds->patchWidth;
1103                         src.height = ds->patchHeight;
1104                         src.verts = &yDrawVerts[ ds->firstVert ];
1105                         //%     subdivided = SubdivideMesh( src, 8, 512 );
1106                         subdivided = SubdivideMesh2( src, info->patchIterations );
1107
1108                         /* fit it to the curve and remove colinear verts on rows/columns */
1109                         PutMeshOnCurve( *subdivided );
1110                         mesh = RemoveLinearMeshColumnsRows( subdivided );
1111                         FreeMesh( subdivided );
1112
1113                         /* get verts */
1114                         verts = mesh->verts;
1115
1116                         /* debug code */
1117                                 #if 0
1118                         if ( lm->plane ) {
1119                                 Sys_Printf( "Planar patch: [%1.3f %1.3f %1.3f] [%1.3f %1.3f %1.3f] [%1.3f %1.3f %1.3f]\n",
1120                                                         lm->plane[ 0 ], lm->plane[ 1 ], lm->plane[ 2 ],
1121                                                         lm->vecs[ 0 ][ 0 ], lm->vecs[ 0 ][ 1 ], lm->vecs[ 0 ][ 2 ],
1122                                                         lm->vecs[ 1 ][ 0 ], lm->vecs[ 1 ][ 1 ], lm->vecs[ 1 ][ 2 ] );
1123                         }
1124                                 #endif
1125
1126                         /* map the mesh quads */
1127                                 #if 0
1128
1129                         for ( mapNonAxial = 0; mapNonAxial < 2; mapNonAxial++ )
1130                         {
1131                                 for ( y = 0; y < ( mesh->height - 1 ); y++ )
1132                                 {
1133                                         for ( x = 0; x < ( mesh->width - 1 ); x++ )
1134                                         {
1135                                                 /* set indexes */
1136                                                 pw[ 0 ] = x + ( y * mesh->width );
1137                                                 pw[ 1 ] = x + ( ( y + 1 ) * mesh->width );
1138                                                 pw[ 2 ] = x + 1 + ( ( y + 1 ) * mesh->width );
1139                                                 pw[ 3 ] = x + 1 + ( y * mesh->width );
1140                                                 pw[ 4 ] = x + ( y * mesh->width );      /* same as pw[ 0 ] */
1141
1142                                                 /* set radix */
1143                                                 r = ( x + y ) & 1;
1144
1145                                                 /* get drawverts and map first triangle */
1146                                                 dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1147                                                 dv[ 1 ] = &verts[ pw[ r + 1 ] ];
1148                                                 dv[ 2 ] = &verts[ pw[ r + 2 ] ];
1149                                                 MapTriangle( lm, info, dv, mapNonAxial );
1150
1151                                                 /* get drawverts and map second triangle */
1152                                                 dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1153                                                 dv[ 1 ] = &verts[ pw[ r + 2 ] ];
1154                                                 dv[ 2 ] = &verts[ pw[ r + 3 ] ];
1155                                                 MapTriangle( lm, info, dv, mapNonAxial );
1156                                         }
1157                                 }
1158                         }
1159
1160                                 #else
1161
1162                         for ( y = 0; y < ( mesh->height - 1 ); y++ )
1163                         {
1164                                 for ( x = 0; x < ( mesh->width - 1 ); x++ )
1165                                 {
1166                                         /* set indexes */
1167                                         pw[ 0 ] = x + ( y * mesh->width );
1168                                         pw[ 1 ] = x + ( ( y + 1 ) * mesh->width );
1169                                         pw[ 2 ] = x + 1 + ( ( y + 1 ) * mesh->width );
1170                                         pw[ 3 ] = x + 1 + ( y * mesh->width );
1171                                         pw[ 4 ] = pw[ 0 ];
1172
1173                                         /* set radix */
1174                                         r = ( x + y ) & 1;
1175
1176                                         /* attempt to map quad first */
1177                                         dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1178                                         dv[ 1 ] = &verts[ pw[ r + 1 ] ];
1179                                         dv[ 2 ] = &verts[ pw[ r + 2 ] ];
1180                                         dv[ 3 ] = &verts[ pw[ r + 3 ] ];
1181                                         if ( MapQuad( lm, info, dv ) ) {
1182                                                 continue;
1183                                         }
1184
1185                                         for ( mapNonAxial = 0; mapNonAxial < 2; mapNonAxial++ )
1186                                         {
1187                                                 /* get drawverts and map first triangle */
1188                                                 dv[ 1 ] = &verts[ pw[ r + 1 ] ];
1189                                                 dv[ 2 ] = &verts[ pw[ r + 2 ] ];
1190                                                 MapTriangle( lm, info, dv, mapNonAxial );
1191
1192                                                 /* get drawverts and map second triangle */
1193                                                 dv[ 1 ] = &verts[ pw[ r + 2 ] ];
1194                                                 dv[ 2 ] = &verts[ pw[ r + 3 ] ];
1195                                                 MapTriangle( lm, info, dv, mapNonAxial );
1196                                         }
1197                                 }
1198                         }
1199
1200                                 #endif
1201
1202                         /* free the mesh */
1203                         FreeMesh( mesh );
1204                         break;
1205
1206                 default:
1207                         break;
1208                 }
1209         }
1210
1211         /* -----------------------------------------------------------------
1212            average and clean up luxel normals
1213            ----------------------------------------------------------------- */
1214
1215         /* walk the luxels */
1216         for ( y = 0; y < lm->sh; y++ )
1217         {
1218                 for ( x = 0; x < lm->sw; x++ )
1219                 {
1220                         /* get luxel */
1221                         luxel = SUPER_LUXEL( 0, x, y );
1222                         normal = SUPER_NORMAL( x, y );
1223                         cluster = SUPER_CLUSTER( x, y );
1224
1225                         /* only look at mapped luxels */
1226                         if ( *cluster < 0 ) {
1227                                 continue;
1228                         }
1229
1230                         /* the normal data could be the sum of multiple samples */
1231                         if ( luxel[ 3 ] > 1.0f ) {
1232                                 VectorNormalize( normal, normal );
1233                         }
1234
1235                         /* mark this luxel as having only one normal */
1236                         luxel[ 3 ] = 1.0f;
1237                 }
1238         }
1239
1240         /* non-planar surfaces stop here */
1241         if ( lm->plane == NULL ) {
1242                 return;
1243         }
1244
1245         /* -----------------------------------------------------------------
1246            map occluded or unuxed luxels
1247            ----------------------------------------------------------------- */
1248
1249         /* walk the luxels */
1250         radius = floor( superSample / 2 );
1251         radius = radius > 0 ? radius : 1.0f;
1252         radius += 1.0f;
1253         for ( pass = 2.0f; pass <= radius; pass += 1.0f )
1254         {
1255                 for ( y = 0; y < lm->sh; y++ )
1256                 {
1257                         for ( x = 0; x < lm->sw; x++ )
1258                         {
1259                                 /* get luxel */
1260                                 luxel = SUPER_LUXEL( 0, x, y );
1261                                 normal = SUPER_NORMAL( x, y );
1262                                 cluster = SUPER_CLUSTER( x, y );
1263
1264                                 /* only look at unmapped luxels */
1265                                 if ( *cluster != CLUSTER_UNMAPPED ) {
1266                                         continue;
1267                                 }
1268
1269                                 /* divine a normal and origin from neighboring luxels */
1270                                 VectorClear( fake.xyz );
1271                                 VectorClear( fake.normal );
1272                                 fake.lightmap[ 0 ][ 0 ] = x;    //% 0.0001 + x;
1273                                 fake.lightmap[ 0 ][ 1 ] = y;    //% 0.0001 + y;
1274                                 samples = 0.0f;
1275                                 for ( sy = ( y - 1 ); sy <= ( y + 1 ); sy++ )
1276                                 {
1277                                         if ( sy < 0 || sy >= lm->sh ) {
1278                                                 continue;
1279                                         }
1280
1281                                         for ( sx = ( x - 1 ); sx <= ( x + 1 ); sx++ )
1282                                         {
1283                                                 if ( sx < 0 || sx >= lm->sw || ( sx == x && sy == y ) ) {
1284                                                         continue;
1285                                                 }
1286
1287                                                 /* get neighboring luxel */
1288                                                 luxel = SUPER_LUXEL( 0, sx, sy );
1289                                                 origin = SUPER_ORIGIN( sx, sy );
1290                                                 normal = SUPER_NORMAL( sx, sy );
1291                                                 cluster = SUPER_CLUSTER( sx, sy );
1292
1293                                                 /* only consider luxels mapped in previous passes */
1294                                                 if ( *cluster < 0 || luxel[ 0 ] >= pass ) {
1295                                                         continue;
1296                                                 }
1297
1298                                                 /* add its distinctiveness to our own */
1299                                                 VectorAdd( fake.xyz, origin, fake.xyz );
1300                                                 VectorAdd( fake.normal, normal, fake.normal );
1301                                                 samples += luxel[ 3 ];
1302                                         }
1303                                 }
1304
1305                                 /* any samples? */
1306                                 if ( samples == 0.0f ) {
1307                                         continue;
1308                                 }
1309
1310                                 /* average */
1311                                 VectorDivide( fake.xyz, samples, fake.xyz );
1312                                 //%     VectorDivide( fake.normal, samples, fake.normal );
1313                                 if ( VectorNormalize( fake.normal, fake.normal ) == 0.0f ) {
1314                                         continue;
1315                                 }
1316
1317                                 /* map the fake vert */
1318                                 MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL, NULL );
1319                         }
1320                 }
1321         }
1322
1323         /* -----------------------------------------------------------------
1324            average and clean up luxel normals
1325            ----------------------------------------------------------------- */
1326
1327         /* walk the luxels */
1328         for ( y = 0; y < lm->sh; y++ )
1329         {
1330                 for ( x = 0; x < lm->sw; x++ )
1331                 {
1332                         /* get luxel */
1333                         luxel = SUPER_LUXEL( 0, x, y );
1334                         normal = SUPER_NORMAL( x, y );
1335                         cluster = SUPER_CLUSTER( x, y );
1336
1337                         /* only look at mapped luxels */
1338                         if ( *cluster < 0 ) {
1339                                 continue;
1340                         }
1341
1342                         /* the normal data could be the sum of multiple samples */
1343                         if ( luxel[ 3 ] > 1.0f ) {
1344                                 VectorNormalize( normal, normal );
1345                         }
1346
1347                         /* mark this luxel as having only one normal */
1348                         luxel[ 3 ] = 1.0f;
1349                 }
1350         }
1351
1352         /* debug code */
1353         #if 0
1354         Sys_Printf( "\n" );
1355         for ( y = 0; y < lm->sh; y++ )
1356         {
1357                 for ( x = 0; x < lm->sw; x++ )
1358                 {
1359                         vec3_t mins, maxs;
1360
1361
1362                         cluster = SUPER_CLUSTER( x, y );
1363                         origin = SUPER_ORIGIN( x, y );
1364                         normal = SUPER_NORMAL( x, y );
1365                         luxel = SUPER_LUXEL( x, y );
1366
1367                         if ( *cluster < 0 ) {
1368                                 continue;
1369                         }
1370
1371                         /* check if within the bounding boxes of all surfaces referenced */
1372                         ClearBounds( mins, maxs );
1373                         for ( n = 0; n < lm->numLightSurfaces; n++ )
1374                         {
1375                                 int TOL;
1376                                 info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + n ] ];
1377                                 TOL = info->sampleSize + 2;
1378                                 AddPointToBounds( info->mins, mins, maxs );
1379                                 AddPointToBounds( info->maxs, mins, maxs );
1380                                 if ( origin[ 0 ] > ( info->mins[ 0 ] - TOL ) && origin[ 0 ] < ( info->maxs[ 0 ] + TOL ) &&
1381                                          origin[ 1 ] > ( info->mins[ 1 ] - TOL ) && origin[ 1 ] < ( info->maxs[ 1 ] + TOL ) &&
1382                                          origin[ 2 ] > ( info->mins[ 2 ] - TOL ) && origin[ 2 ] < ( info->maxs[ 2 ] + TOL ) ) {
1383                                         break;
1384                                 }
1385                         }
1386
1387                         /* inside? */
1388                         if ( n < lm->numLightSurfaces ) {
1389                                 continue;
1390                         }
1391
1392                         /* report bogus origin */
1393                         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",
1394                                                 rawLightmapNum, x, y, *cluster,
1395                                                 origin[ 0 ], origin[ 1 ], origin[ 2 ],
1396                                                 mins[ 0 ], mins[ 1 ], mins[ 2 ],
1397                                                 maxs[ 0 ], maxs[ 1 ], maxs[ 2 ],
1398                                                 luxel[ 3 ] );
1399                 }
1400         }
1401         #endif
1402 }
1403
1404
1405
1406 /*
1407    SetupDirt()
1408    sets up dirtmap (ambient occlusion)
1409  */
1410
1411 #define DIRT_CONE_ANGLE             88  /* degrees */
1412 #define DIRT_NUM_ANGLE_STEPS        16
1413 #define DIRT_NUM_ELEVATION_STEPS    3
1414 #define DIRT_NUM_VECTORS            ( DIRT_NUM_ANGLE_STEPS * DIRT_NUM_ELEVATION_STEPS )
1415
1416 static vec3_t dirtVectors[ DIRT_NUM_VECTORS ];
1417 static int numDirtVectors = 0;
1418
1419 void SetupDirt( void ){
1420         int i, j;
1421         float angle, elevation, angleStep, elevationStep;
1422
1423
1424         /* note it */
1425         Sys_FPrintf( SYS_VRB, "--- SetupDirt ---\n" );
1426
1427         /* calculate angular steps */
1428         angleStep = DEG2RAD( 360.0f / DIRT_NUM_ANGLE_STEPS );
1429         elevationStep = DEG2RAD( DIRT_CONE_ANGLE / DIRT_NUM_ELEVATION_STEPS );
1430
1431         /* iterate angle */
1432         angle = 0.0f;
1433         for ( i = 0, angle = 0.0f; i < DIRT_NUM_ANGLE_STEPS; i++, angle += angleStep )
1434         {
1435                 /* iterate elevation */
1436                 for ( j = 0, elevation = elevationStep * 0.5f; j < DIRT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep )
1437                 {
1438                         dirtVectors[ numDirtVectors ][ 0 ] = sin( elevation ) * cos( angle );
1439                         dirtVectors[ numDirtVectors ][ 1 ] = sin( elevation ) * sin( angle );
1440                         dirtVectors[ numDirtVectors ][ 2 ] = cos( elevation );
1441                         numDirtVectors++;
1442                 }
1443         }
1444
1445         /* emit some statistics */
1446         Sys_FPrintf( SYS_VRB, "%9d dirtmap vectors\n", numDirtVectors );
1447 }
1448
1449
1450 /*
1451    DirtForSample()
1452    calculates dirt value for a given sample
1453  */
1454
1455 float DirtForSample( trace_t *trace ){
1456         int i;
1457         float gatherDirt, outDirt, angle, elevation, ooDepth;
1458         vec3_t normal, worldUp, myUp, myRt, temp, direction, displacement;
1459
1460
1461         /* dummy check */
1462         if ( !dirty ) {
1463                 return 1.0f;
1464         }
1465         if ( trace == NULL || trace->cluster < 0 ) {
1466                 return 0.0f;
1467         }
1468
1469         /* setup */
1470         gatherDirt = 0.0f;
1471         ooDepth = 1.0f / dirtDepth;
1472         VectorCopy( trace->normal, normal );
1473
1474         /* check if the normal is aligned to the world-up */
1475         if ( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f && ( normal[ 2 ] == 1.0f || normal[ 2 ] == -1.0f ) ) {
1476                 if ( normal[ 2 ] == 1.0f ) {
1477                         VectorSet( myRt, 1.0f, 0.0f, 0.0f );
1478                         VectorSet( myUp, 0.0f, 1.0f, 0.0f );
1479                 }
1480                 else if ( normal[ 2 ] == -1.0f ) {
1481                         VectorSet( myRt, -1.0f, 0.0f, 0.0f );
1482                         VectorSet( myUp,  0.0f, 1.0f, 0.0f );
1483                 }
1484         }
1485         else
1486         {
1487                 VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
1488                 CrossProduct( normal, worldUp, myRt );
1489                 VectorNormalize( myRt, myRt );
1490                 CrossProduct( myRt, normal, myUp );
1491                 VectorNormalize( myUp, myUp );
1492         }
1493
1494         /* 1 = random mode, 0 (well everything else) = non-random mode */
1495         if ( dirtMode == 1 ) {
1496                 /* iterate */
1497                 for ( i = 0; i < numDirtVectors; i++ )
1498                 {
1499                         /* get random vector */
1500                         angle = Random() * DEG2RAD( 360.0f );
1501                         elevation = Random() * DEG2RAD( DIRT_CONE_ANGLE );
1502                         temp[ 0 ] = cos( angle ) * sin( elevation );
1503                         temp[ 1 ] = sin( angle ) * sin( elevation );
1504                         temp[ 2 ] = cos( elevation );
1505
1506                         /* transform into tangent space */
1507                         direction[ 0 ] = myRt[ 0 ] * temp[ 0 ] + myUp[ 0 ] * temp[ 1 ] + normal[ 0 ] * temp[ 2 ];
1508                         direction[ 1 ] = myRt[ 1 ] * temp[ 0 ] + myUp[ 1 ] * temp[ 1 ] + normal[ 1 ] * temp[ 2 ];
1509                         direction[ 2 ] = myRt[ 2 ] * temp[ 0 ] + myUp[ 2 ] * temp[ 1 ] + normal[ 2 ] * temp[ 2 ];
1510
1511                         /* set endpoint */
1512                         VectorMA( trace->origin, dirtDepth, direction, trace->end );
1513                         SetupTrace( trace );
1514                         VectorSet(trace->color, 1.0f, 1.0f, 1.0f);
1515
1516                         /* trace */
1517                         TraceLine( trace );
1518                         if ( trace->opaque && !( trace->compileFlags & C_SKY ) ) {
1519                                 VectorSubtract( trace->hit, trace->origin, displacement );
1520                                 gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1521                         }
1522                 }
1523         }
1524         else
1525         {
1526                 /* iterate through ordered vectors */
1527                 for ( i = 0; i < numDirtVectors; i++ )
1528                 {
1529                         /* transform vector into tangent space */
1530                         direction[ 0 ] = myRt[ 0 ] * dirtVectors[ i ][ 0 ] + myUp[ 0 ] * dirtVectors[ i ][ 1 ] + normal[ 0 ] * dirtVectors[ i ][ 2 ];
1531                         direction[ 1 ] = myRt[ 1 ] * dirtVectors[ i ][ 0 ] + myUp[ 1 ] * dirtVectors[ i ][ 1 ] + normal[ 1 ] * dirtVectors[ i ][ 2 ];
1532                         direction[ 2 ] = myRt[ 2 ] * dirtVectors[ i ][ 0 ] + myUp[ 2 ] * dirtVectors[ i ][ 1 ] + normal[ 2 ] * dirtVectors[ i ][ 2 ];
1533
1534                         /* set endpoint */
1535                         VectorMA( trace->origin, dirtDepth, direction, trace->end );
1536                         SetupTrace( trace );
1537                         VectorSet(trace->color, 1.0f, 1.0f, 1.0f);
1538
1539                         /* trace */
1540                         TraceLine( trace );
1541                         if ( trace->opaque ) {
1542                                 VectorSubtract( trace->hit, trace->origin, displacement );
1543                                 gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1544                         }
1545                 }
1546         }
1547
1548         /* direct ray */
1549         VectorMA( trace->origin, dirtDepth, normal, trace->end );
1550         SetupTrace( trace );
1551         VectorSet(trace->color, 1.0f, 1.0f, 1.0f);
1552
1553         /* trace */
1554         TraceLine( trace );
1555         if ( trace->opaque ) {
1556                 VectorSubtract( trace->hit, trace->origin, displacement );
1557                 gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1558         }
1559
1560         /* early out */
1561         if ( gatherDirt <= 0.0f ) {
1562                 return 1.0f;
1563         }
1564
1565         /* apply gain (does this even do much? heh) */
1566         outDirt = pow( gatherDirt / ( numDirtVectors + 1 ), dirtGain );
1567         if ( outDirt > 1.0f ) {
1568                 outDirt = 1.0f;
1569         }
1570
1571         /* apply scale */
1572         outDirt *= dirtScale;
1573         if ( outDirt > 1.0f ) {
1574                 outDirt = 1.0f;
1575         }
1576
1577         /* return to sender */
1578         return 1.0f - outDirt;
1579 }
1580
1581
1582
1583 /*
1584    DirtyRawLightmap()
1585    calculates dirty fraction for each luxel
1586  */
1587
1588 void DirtyRawLightmap( int rawLightmapNum ){
1589         int i, x, y, sx, sy, *cluster;
1590         float               *origin, *normal, *dirt, *dirt2, average, samples;
1591         rawLightmap_t       *lm;
1592         surfaceInfo_t       *info;
1593         trace_t trace;
1594         qboolean noDirty;
1595
1596
1597         /* bail if this number exceeds the number of raw lightmaps */
1598         if ( rawLightmapNum >= numRawLightmaps ) {
1599                 return;
1600         }
1601
1602         /* get lightmap */
1603         lm = &rawLightmaps[ rawLightmapNum ];
1604
1605         /* setup trace */
1606         trace.testOcclusion = qtrue;
1607         trace.forceSunlight = qfalse;
1608         trace.recvShadows = lm->recvShadows;
1609         trace.numSurfaces = lm->numLightSurfaces;
1610         trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
1611         trace.inhibitRadius = 0.0f;
1612         trace.testAll = qfalse;
1613
1614         /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
1615         trace.twoSided = qfalse;
1616         for ( i = 0; i < trace.numSurfaces; i++ )
1617         {
1618                 /* get surface */
1619                 info = &surfaceInfos[ trace.surfaces[ i ] ];
1620
1621                 /* check twosidedness */
1622                 if ( info->si->twoSided ) {
1623                         trace.twoSided = qtrue;
1624                         break;
1625                 }
1626         }
1627
1628         noDirty = qfalse;
1629         for ( i = 0; i < trace.numSurfaces; i++ )
1630         {
1631                 /* get surface */
1632                 info = &surfaceInfos[ trace.surfaces[ i ] ];
1633
1634                 /* check twosidedness */
1635                 if ( info->si->noDirty ) {
1636                         noDirty = qtrue;
1637                         break;
1638                 }
1639         }
1640
1641         /* gather dirt */
1642         for ( y = 0; y < lm->sh; y++ )
1643         {
1644                 for ( x = 0; x < lm->sw; x++ )
1645                 {
1646                         /* get luxel */
1647                         cluster = SUPER_CLUSTER( x, y );
1648                         origin = SUPER_ORIGIN( x, y );
1649                         normal = SUPER_NORMAL( x, y );
1650                         dirt = SUPER_DIRT( x, y );
1651
1652                         /* set default dirt */
1653                         *dirt = 0.0f;
1654
1655                         /* only look at mapped luxels */
1656                         if ( *cluster < 0 ) {
1657                                 continue;
1658                         }
1659
1660                         /* don't apply dirty on this surface */
1661                         if ( noDirty ) {
1662                                 *dirt = 1.0f;
1663                                 continue;
1664                         }
1665
1666                         /* copy to trace */
1667                         trace.cluster = *cluster;
1668                         VectorCopy( origin, trace.origin );
1669                         VectorCopy( normal, trace.normal );
1670
1671                         /* get dirt */
1672                         *dirt = DirtForSample( &trace );
1673                 }
1674         }
1675
1676         /* testing no filtering */
1677         //%     return;
1678
1679         /* filter dirt */
1680         for ( y = 0; y < lm->sh; y++ )
1681         {
1682                 for ( x = 0; x < lm->sw; x++ )
1683                 {
1684                         /* get luxel */
1685                         cluster = SUPER_CLUSTER( x, y );
1686                         dirt = SUPER_DIRT( x, y );
1687
1688                         /* filter dirt by adjacency to unmapped luxels */
1689                         average = *dirt;
1690                         samples = 1.0f;
1691                         for ( sy = ( y - 1 ); sy <= ( y + 1 ); sy++ )
1692                         {
1693                                 if ( sy < 0 || sy >= lm->sh ) {
1694                                         continue;
1695                                 }
1696
1697                                 for ( sx = ( x - 1 ); sx <= ( x + 1 ); sx++ )
1698                                 {
1699                                         if ( sx < 0 || sx >= lm->sw || ( sx == x && sy == y ) ) {
1700                                                 continue;
1701                                         }
1702
1703                                         /* get neighboring luxel */
1704                                         cluster = SUPER_CLUSTER( sx, sy );
1705                                         dirt2 = SUPER_DIRT( sx, sy );
1706                                         if ( *cluster < 0 || *dirt2 <= 0.0f ) {
1707                                                 continue;
1708                                         }
1709
1710                                         /* add it */
1711                                         average += *dirt2;
1712                                         samples += 1.0f;
1713                                 }
1714
1715                                 /* bail */
1716                                 if ( samples <= 0.0f ) {
1717                                         break;
1718                                 }
1719                         }
1720
1721                         /* bail */
1722                         if ( samples <= 0.0f ) {
1723                                 continue;
1724                         }
1725
1726                         /* scale dirt */
1727                         *dirt = average / samples;
1728                 }
1729         }
1730 }
1731
1732
1733
1734 /*
1735    SubmapRawLuxel()
1736    calculates the pvs cluster, origin, normal of a sub-luxel
1737  */
1738
1739 static qboolean SubmapRawLuxel( rawLightmap_t *lm, int x, int y, float bx, float by, int *sampleCluster, vec3_t sampleOrigin, vec3_t sampleNormal ){
1740         int i, *cluster, *cluster2;
1741         float       *origin, *origin2, *normal; //%     , *normal2;
1742         vec3_t originVecs[ 2 ];                 //%     , normalVecs[ 2 ];
1743
1744
1745         /* calulate x vector */
1746         if ( ( x < ( lm->sw - 1 ) && bx >= 0.0f ) || ( x == 0 && bx <= 0.0f ) ) {
1747                 cluster = SUPER_CLUSTER( x, y );
1748                 origin = SUPER_ORIGIN( x, y );
1749                 //%     normal = SUPER_NORMAL( x, y );
1750                 cluster2 = SUPER_CLUSTER( x + 1, y );
1751                 origin2 = *cluster2 < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x + 1, y );
1752                 //%     normal2 = *cluster2 < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x + 1, y );
1753         }
1754         else if ( ( x > 0 && bx <= 0.0f ) || ( x == ( lm->sw - 1 ) && bx >= 0.0f ) ) {
1755                 cluster = SUPER_CLUSTER( x - 1, y );
1756                 origin = *cluster < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x - 1, y );
1757                 //%     normal = *cluster < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x - 1, y );
1758                 cluster2 = SUPER_CLUSTER( x, y );
1759                 origin2 = SUPER_ORIGIN( x, y );
1760                 //%     normal2 = SUPER_NORMAL( x, y );
1761         }
1762         else {
1763                 Sys_FPrintf( SYS_WRN, "WARNING: Spurious lightmap S vector\n" );
1764         }
1765
1766         VectorSubtract( origin2, origin, originVecs[ 0 ] );
1767         //%     VectorSubtract( normal2, normal, normalVecs[ 0 ] );
1768
1769         /* calulate y vector */
1770         if ( ( y < ( lm->sh - 1 ) && bx >= 0.0f ) || ( y == 0 && bx <= 0.0f ) ) {
1771                 cluster = SUPER_CLUSTER( x, y );
1772                 origin = SUPER_ORIGIN( x, y );
1773                 //%     normal = SUPER_NORMAL( x, y );
1774                 cluster2 = SUPER_CLUSTER( x, y + 1 );
1775                 origin2 = *cluster2 < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x, y + 1 );
1776                 //%     normal2 = *cluster2 < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x, y + 1 );
1777         }
1778         else if ( ( y > 0 && bx <= 0.0f ) || ( y == ( lm->sh - 1 ) && bx >= 0.0f ) ) {
1779                 cluster = SUPER_CLUSTER( x, y - 1 );
1780                 origin = *cluster < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x, y - 1 );
1781                 //%     normal = *cluster < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x, y - 1 );
1782                 cluster2 = SUPER_CLUSTER( x, y );
1783                 origin2 = SUPER_ORIGIN( x, y );
1784                 //%     normal2 = SUPER_NORMAL( x, y );
1785         }
1786         else{
1787                 Sys_FPrintf( SYS_WRN, "WARNING: Spurious lightmap T vector\n" );
1788         }
1789
1790         VectorSubtract( origin2, origin, originVecs[ 1 ] );
1791
1792         /* calculate new origin */
1793         for ( i = 0; i < 3; i++ )
1794                 sampleOrigin[ i ] = sampleOrigin[ i ] + ( bx * originVecs[ 0 ][ i ] ) + ( by * originVecs[ 1 ][ i ] );
1795
1796         /* get cluster */
1797         *sampleCluster = ClusterForPointExtFilter( sampleOrigin, ( LUXEL_EPSILON * 2 ), lm->numLightClusters, lm->lightClusters );
1798         if ( *sampleCluster < 0 ) {
1799                 return qfalse;
1800         }
1801
1802         /* calculate new normal */
1803         normal = SUPER_NORMAL( x, y );
1804         VectorCopy( normal, sampleNormal );
1805
1806         /* return ok */
1807         return qtrue;
1808 }
1809
1810
1811 /*
1812    SubsampleRawLuxel_r()
1813    recursively subsamples a luxel until its color gradient is low enough or subsampling limit is reached
1814  */
1815
1816 static void SubsampleRawLuxel_r( rawLightmap_t *lm, trace_t *trace, vec3_t sampleOrigin, int x, int y, float bias, float *lightLuxel, float *lightDeluxel ){
1817         int b, samples, mapped, lighted;
1818         int cluster[ 4 ];
1819         vec4_t luxel[ 4 ];
1820         vec3_t deluxel[ 4 ];
1821         vec3_t origin[ 4 ], normal[ 4 ];
1822         float biasDirs[ 4 ][ 2 ] = { { -1.0f, -1.0f }, { 1.0f, -1.0f }, { -1.0f, 1.0f }, { 1.0f, 1.0f } };
1823         vec3_t color, direction = { 0, 0, 0 }, total;
1824
1825
1826         /* limit check */
1827         if ( lightLuxel[ 3 ] >= lightSamples ) {
1828                 return;
1829         }
1830
1831         /* setup */
1832         VectorClear( total );
1833         mapped = 0;
1834         lighted = 0;
1835
1836         /* make 2x2 subsample stamp */
1837         for ( b = 0; b < 4; b++ )
1838         {
1839                 /* set origin */
1840                 VectorCopy( sampleOrigin, origin[ b ] );
1841
1842                 /* calculate position */
1843                 if ( !SubmapRawLuxel( lm, x, y, ( bias * biasDirs[ b ][ 0 ] ), ( bias * biasDirs[ b ][ 1 ] ), &cluster[ b ], origin[ b ], normal[ b ] ) ) {
1844                         cluster[ b ] = -1;
1845                         continue;
1846                 }
1847                 mapped++;
1848
1849                 /* increment sample count */
1850                 luxel[ b ][ 3 ] = lightLuxel[ 3 ] + 1.0f;
1851
1852                 /* setup trace */
1853                 trace->cluster = *cluster;
1854                 VectorCopy( origin[ b ], trace->origin );
1855                 VectorCopy( normal[ b ], trace->normal );
1856
1857                 /* sample light */
1858
1859                 LightContributionToSample( trace );
1860                 if ( trace->forceSubsampling > 1.0f ) {
1861                         /* alphashadow: we subsample as deep as we can */
1862                         ++lighted;
1863                         ++mapped;
1864                         ++mapped;
1865                 }
1866
1867                 /* add to totals (fixme: make contrast function) */
1868                 VectorCopy( trace->color, luxel[ b ] );
1869                 if ( lightDeluxel ) {
1870                         VectorCopy( trace->directionContribution, deluxel[ b ] );
1871                 }
1872                 VectorAdd( total, trace->color, total );
1873                 if ( ( luxel[ b ][ 0 ] + luxel[ b ][ 1 ] + luxel[ b ][ 2 ] ) > 0.0f ) {
1874                         lighted++;
1875                 }
1876         }
1877
1878         /* subsample further? */
1879         if ( ( lightLuxel[ 3 ] + 1.0f ) < lightSamples &&
1880                  ( total[ 0 ] > 4.0f || total[ 1 ] > 4.0f || total[ 2 ] > 4.0f ) &&
1881                  lighted != 0 && lighted != mapped ) {
1882                 for ( b = 0; b < 4; b++ )
1883                 {
1884                         if ( cluster[ b ] < 0 ) {
1885                                 continue;
1886                         }
1887                         SubsampleRawLuxel_r( lm, trace, origin[ b ], x, y, ( bias * 0.5f ), luxel[ b ], lightDeluxel ? deluxel[ b ] : NULL );
1888                 }
1889         }
1890
1891         /* average */
1892         //%     VectorClear( color );
1893         //%     samples = 0;
1894         VectorCopy( lightLuxel, color );
1895         if ( lightDeluxel ) {
1896                 VectorCopy( lightDeluxel, direction );
1897         }
1898         samples = 1;
1899         for ( b = 0; b < 4; b++ )
1900         {
1901                 if ( cluster[ b ] < 0 ) {
1902                         continue;
1903                 }
1904                 VectorAdd( color, luxel[ b ], color );
1905                 if ( lightDeluxel ) {
1906                         VectorAdd( direction, deluxel[ b ], direction );
1907                 }
1908                 samples++;
1909         }
1910
1911         /* add to luxel */
1912         if ( samples > 0 ) {
1913                 /* average */
1914                 color[ 0 ] /= samples;
1915                 color[ 1 ] /= samples;
1916                 color[ 2 ] /= samples;
1917
1918                 /* add to color */
1919                 VectorCopy( color, lightLuxel );
1920                 lightLuxel[ 3 ] += 1.0f;
1921
1922                 if ( lightDeluxel ) {
1923                         direction[ 0 ] /= samples;
1924                         direction[ 1 ] /= samples;
1925                         direction[ 2 ] /= samples;
1926                         VectorCopy( direction, lightDeluxel );
1927                 }
1928         }
1929 }
1930
1931 /* A mostly Gaussian-like bounded random distribution (sigma is expected standard deviation) */
1932 static void GaussLikeRandom( float sigma, float *x, float *y ){
1933         float r;
1934         r = Random() * 2 * Q_PI;
1935         *x = sigma * 2.73861278752581783822 * cos( r );
1936         *y = sigma * 2.73861278752581783822 * sin( r );
1937         r = Random();
1938         r = 1 - sqrt( r );
1939         r = 1 - sqrt( r );
1940         *x *= r;
1941         *y *= r;
1942 }
1943 static void RandomSubsampleRawLuxel( rawLightmap_t *lm, trace_t *trace, vec3_t sampleOrigin, int x, int y, float bias, float *lightLuxel, float *lightDeluxel ){
1944         int b, mapped;
1945         int cluster;
1946         vec3_t origin, normal;
1947         vec3_t total, totaldirection;
1948         float dx, dy;
1949
1950         VectorClear( total );
1951         VectorClear( totaldirection );
1952         mapped = 0;
1953         for ( b = 0; b < lightSamples; ++b )
1954         {
1955                 /* set origin */
1956                 VectorCopy( sampleOrigin, origin );
1957                 GaussLikeRandom( bias, &dx, &dy );
1958
1959                 /* calculate position */
1960                 if ( !SubmapRawLuxel( lm, x, y, dx, dy, &cluster, origin, normal ) ) {
1961                         cluster = -1;
1962                         continue;
1963                 }
1964                 mapped++;
1965
1966                 trace->cluster = cluster;
1967                 VectorCopy( origin, trace->origin );
1968                 VectorCopy( normal, trace->normal );
1969
1970                 LightContributionToSample( trace );
1971                 VectorAdd( total, trace->color, total );
1972                 if ( lightDeluxel ) {
1973                         VectorAdd( totaldirection, trace->directionContribution, totaldirection );
1974                 }
1975         }
1976
1977         /* add to luxel */
1978         if ( mapped > 0 ) {
1979                 /* average */
1980                 lightLuxel[ 0 ] = total[ 0 ] / mapped;
1981                 lightLuxel[ 1 ] = total[ 1 ] / mapped;
1982                 lightLuxel[ 2 ] = total[ 2 ] / mapped;
1983
1984                 if ( lightDeluxel ) {
1985                         lightDeluxel[ 0 ] = totaldirection[ 0 ] / mapped;
1986                         lightDeluxel[ 1 ] = totaldirection[ 1 ] / mapped;
1987                         lightDeluxel[ 2 ] = totaldirection[ 2 ] / mapped;
1988                 }
1989         }
1990 }
1991
1992
1993
1994 /*
1995    IlluminateRawLightmap()
1996    illuminates the luxels
1997  */
1998
1999 #define STACK_LL_SIZE           ( SUPER_LUXEL_SIZE * 64 * 64 )
2000 #define LIGHT_LUXEL( x, y )     ( lightLuxels + ( ( ( ( y ) * lm->sw ) + ( x ) ) * SUPER_LUXEL_SIZE ) )
2001 #define LIGHT_DELUXEL( x, y )       ( lightDeluxels + ( ( ( ( y ) * lm->sw ) + ( x ) ) * SUPER_DELUXEL_SIZE ) )
2002
2003 void IlluminateRawLightmap( int rawLightmapNum ){
2004         int i, t, x, y, sx, sy, size, luxelFilterRadius, lightmapNum;
2005         int                 *cluster, *cluster2, mapped, lighted, totalLighted;
2006         size_t llSize, ldSize;
2007         rawLightmap_t       *lm;
2008         surfaceInfo_t       *info;
2009         qboolean filterColor, filterDir;
2010         float brightness;
2011         float               *origin, *normal, *dirt, *luxel, *luxel2, *deluxel, *deluxel2;
2012         unsigned char           *flag;
2013         float               *lightLuxels, *lightDeluxels, *lightLuxel, *lightDeluxel, samples, filterRadius, weight;
2014         vec3_t color, direction, averageColor, averageDir, total, temp, temp2;
2015         float tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
2016         trace_t trace;
2017         float stackLightLuxels[ STACK_LL_SIZE ];
2018
2019
2020         /* bail if this number exceeds the number of raw lightmaps */
2021         if ( rawLightmapNum >= numRawLightmaps ) {
2022                 return;
2023         }
2024
2025         /* get lightmap */
2026         lm = &rawLightmaps[ rawLightmapNum ];
2027
2028         /* setup trace */
2029         trace.testOcclusion = !noTrace;
2030         trace.forceSunlight = qfalse;
2031         trace.recvShadows = lm->recvShadows;
2032         trace.numSurfaces = lm->numLightSurfaces;
2033         trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
2034         trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
2035
2036         /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
2037         trace.twoSided = qfalse;
2038         for ( i = 0; i < trace.numSurfaces; i++ )
2039         {
2040                 /* get surface */
2041                 info = &surfaceInfos[ trace.surfaces[ i ] ];
2042
2043                 /* check twosidedness */
2044                 if ( info->si->twoSided ) {
2045                         trace.twoSided = qtrue;
2046                         break;
2047                 }
2048         }
2049
2050         /* create a culled light list for this raw lightmap */
2051         CreateTraceLightsForBounds( lm->mins, lm->maxs, lm->plane, lm->numLightClusters, lm->lightClusters, LIGHT_SURFACES, &trace );
2052
2053         /* -----------------------------------------------------------------
2054            fill pass
2055            ----------------------------------------------------------------- */
2056
2057         /* set counts */
2058         numLuxelsIlluminated += ( lm->sw * lm->sh );
2059
2060         /* test debugging state */
2061         if ( debugSurfaces || debugAxis || debugCluster || debugOrigin || dirtDebug || normalmap ) {
2062                 /* debug fill the luxels */
2063                 for ( y = 0; y < lm->sh; y++ )
2064                 {
2065                         for ( x = 0; x < lm->sw; x++ )
2066                         {
2067                                 /* get cluster */
2068                                 cluster = SUPER_CLUSTER( x, y );
2069
2070                                 /* only fill mapped luxels */
2071                                 if ( *cluster < 0 ) {
2072                                         continue;
2073                                 }
2074
2075                                 /* get particulars */
2076                                 luxel = SUPER_LUXEL( 0, x, y );
2077                                 origin = SUPER_ORIGIN( x, y );
2078                                 normal = SUPER_NORMAL( x, y );
2079
2080                                 /* color the luxel with raw lightmap num? */
2081                                 if ( debugSurfaces ) {
2082                                         VectorCopy( debugColors[ rawLightmapNum % 12 ], luxel );
2083                                 }
2084
2085                                 /* color the luxel with lightmap axis? */
2086                                 else if ( debugAxis ) {
2087                                         luxel[ 0 ] = ( lm->axis[ 0 ] + 1.0f ) * 127.5f;
2088                                         luxel[ 1 ] = ( lm->axis[ 1 ] + 1.0f ) * 127.5f;
2089                                         luxel[ 2 ] = ( lm->axis[ 2 ] + 1.0f ) * 127.5f;
2090                                 }
2091
2092                                 /* color the luxel with luxel cluster? */
2093                                 else if ( debugCluster ) {
2094                                         VectorCopy( debugColors[ *cluster % 12 ], luxel );
2095                                 }
2096
2097                                 /* color the luxel with luxel origin? */
2098                                 else if ( debugOrigin ) {
2099                                         VectorSubtract( lm->maxs, lm->mins, temp );
2100                                         VectorScale( temp, ( 1.0f / 255.0f ), temp );
2101                                         VectorSubtract( origin, lm->mins, temp2 );
2102                                         luxel[ 0 ] = lm->mins[ 0 ] + ( temp[ 0 ] * temp2[ 0 ] );
2103                                         luxel[ 1 ] = lm->mins[ 1 ] + ( temp[ 1 ] * temp2[ 1 ] );
2104                                         luxel[ 2 ] = lm->mins[ 2 ] + ( temp[ 2 ] * temp2[ 2 ] );
2105                                 }
2106
2107                                 /* color the luxel with the normal */
2108                                 else if ( normalmap ) {
2109                                         luxel[ 0 ] = ( normal[ 0 ] + 1.0f ) * 127.5f;
2110                                         luxel[ 1 ] = ( normal[ 1 ] + 1.0f ) * 127.5f;
2111                                         luxel[ 2 ] = ( normal[ 2 ] + 1.0f ) * 127.5f;
2112                                 }
2113
2114                                 /* otherwise clear it */
2115                                 else{
2116                                         VectorClear( luxel );
2117                                 }
2118
2119                                 /* add to counts */
2120                                 luxel[ 3 ] = 1.0f;
2121                         }
2122                 }
2123         }
2124         else
2125         {
2126                 /* allocate temporary per-light luxel storage */
2127                 llSize = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
2128                 ldSize = lm->sw * lm->sh * SUPER_DELUXEL_SIZE * sizeof( float );
2129                 if ( llSize <= ( STACK_LL_SIZE * sizeof( float ) ) ) {
2130                         lightLuxels = stackLightLuxels;
2131                 }
2132                 else{
2133                         lightLuxels = safe_malloc( llSize );
2134                 }
2135                 if ( deluxemap ) {
2136                         lightDeluxels = safe_malloc( ldSize );
2137                 }
2138                 else{
2139                         lightDeluxels = NULL;
2140                 }
2141
2142                 /* clear luxels */
2143                 //%     memset( lm->superLuxels[ 0 ], 0, llSize );
2144
2145                 /* set ambient color */
2146                 for ( y = 0; y < lm->sh; y++ )
2147                 {
2148                         for ( x = 0; x < lm->sw; x++ )
2149                         {
2150                                 /* get cluster */
2151                                 cluster = SUPER_CLUSTER( x, y );
2152                                 luxel = SUPER_LUXEL( 0, x, y );
2153                                 normal = SUPER_NORMAL( x, y );
2154                                 deluxel = SUPER_DELUXEL( x, y );
2155
2156                                 /* blacken unmapped clusters */
2157                                 if ( *cluster < 0 ) {
2158                                         VectorClear( luxel );
2159                                 }
2160
2161                                 /* set ambient */
2162                                 else
2163                                 {
2164                                         VectorCopy( ambientColor, luxel );
2165                                         if ( deluxemap ) {
2166                                                 brightness = RGBTOGRAY( ambientColor ) * ( 1.0f / 255.0f );
2167
2168                                                 // use AT LEAST this amount of contribution from ambient for the deluxemap, fixes points that receive ZERO light
2169                                                 if ( brightness < 0.00390625f ) {
2170                                                         brightness = 0.00390625f;
2171                                                 }
2172
2173                                                 VectorScale( normal, brightness, deluxel );
2174                                         }
2175                                         luxel[ 3 ] = 1.0f;
2176                                 }
2177                         }
2178                 }
2179
2180                 /* clear styled lightmaps */
2181                 size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
2182                 for ( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2183                 {
2184                         if ( lm->superLuxels[ lightmapNum ] != NULL ) {
2185                                 memset( lm->superLuxels[ lightmapNum ], 0, size );
2186                         }
2187                 }
2188
2189                 /* debugging code */
2190                 //%     if( trace.numLights <= 0 )
2191                 //%             Sys_Printf( "Lightmap %9d: 0 lights, axis: %.2f, %.2f, %.2f\n", rawLightmapNum, lm->axis[ 0 ], lm->axis[ 1 ], lm->axis[ 2 ] );
2192
2193                 /* walk light list */
2194                 for ( i = 0; i < trace.numLights; i++ )
2195                 {
2196                         /* setup trace */
2197                         trace.light = trace.lights[ i ];
2198
2199                         /* style check */
2200                         for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2201                         {
2202                                 if ( lm->styles[ lightmapNum ] == trace.light->style ||
2203                                          lm->styles[ lightmapNum ] == LS_NONE ) {
2204                                         break;
2205                                 }
2206                         }
2207
2208                         /* max of MAX_LIGHTMAPS (4) styles allowed to hit a surface/lightmap */
2209                         if ( lightmapNum >= MAX_LIGHTMAPS ) {
2210                                 Sys_FPrintf( SYS_WRN, "WARNING: Hit per-surface style limit (%d)\n", MAX_LIGHTMAPS );
2211                                 continue;
2212                         }
2213
2214                         /* setup */
2215                         memset( lightLuxels, 0, llSize );
2216                         if ( deluxemap ) {
2217                                 memset( lightDeluxels, 0, ldSize );
2218                         }
2219                         totalLighted = 0;
2220
2221                         /* determine filter radius */
2222                         filterRadius = lm->filterRadius > trace.light->filterRadius
2223                                                    ? lm->filterRadius
2224                                                    : trace.light->filterRadius;
2225                         if ( filterRadius < 0.0f ) {
2226                                 filterRadius = 0.0f;
2227                         }
2228
2229                         /* set luxel filter radius */
2230                         luxelFilterRadius = lm->sampleSize != 0 ? superSample * filterRadius / lm->sampleSize : 0;
2231                         if ( luxelFilterRadius == 0 && ( filterRadius > 0.0f || filter ) ) {
2232                                 luxelFilterRadius = 1;
2233                         }
2234
2235                         /* allocate sampling flags storage */
2236                         if ( lightSamples > 1 || lightRandomSamples ) {
2237                                 size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( unsigned char );
2238                                 if ( lm->superFlags == NULL ) {
2239                                         lm->superFlags = safe_malloc( size );
2240                                 }
2241                                 memset( (void *) lm->superFlags, 0, size );
2242                         }
2243
2244                         /* initial pass, one sample per luxel */
2245                         for ( y = 0; y < lm->sh; y++ )
2246                         {
2247                                 for ( x = 0; x < lm->sw; x++ )
2248                                 {
2249                                         /* get cluster */
2250                                         cluster = SUPER_CLUSTER( x, y );
2251                                         if ( *cluster < 0 ) {
2252                                                 continue;
2253                                         }
2254
2255                                         /* get particulars */
2256                                         lightLuxel = LIGHT_LUXEL( x, y );
2257                                         lightDeluxel = LIGHT_DELUXEL( x, y );
2258                                         origin = SUPER_ORIGIN( x, y );
2259                                         normal = SUPER_NORMAL( x, y );
2260                                         flag = SUPER_FLAG( x, y );
2261
2262                                         /* set contribution count */
2263                                         lightLuxel[ 3 ] = 1.0f;
2264
2265                                         /* setup trace */
2266                                         trace.cluster = *cluster;
2267                                         VectorCopy( origin, trace.origin );
2268                                         VectorCopy( normal, trace.normal );
2269
2270                                         /* get light for this sample */
2271                                         LightContributionToSample( &trace );
2272                                         VectorCopy( trace.color, lightLuxel );
2273
2274                                         /* add the contribution to the deluxemap */
2275                                         if ( deluxemap ) {
2276                                                 VectorCopy( trace.directionContribution, lightDeluxel );
2277                                         }
2278
2279                                         /* check for evilness */
2280                                         if ( trace.forceSubsampling > 1.0f && ( lightSamples > 1 || lightRandomSamples ) ) {
2281                                                 totalLighted++;
2282                                                 *flag |= FLAG_FORCE_SUBSAMPLING; /* force */
2283                                         }
2284                                         /* add to count */
2285                                         else if ( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] ) {
2286                                                 totalLighted++;
2287                                         }
2288                                 }
2289                         }
2290
2291                         /* don't even bother with everything else if nothing was lit */
2292                         if ( totalLighted == 0 ) {
2293                                 continue;
2294                         }
2295
2296                         /* secondary pass, adaptive supersampling (fixme: use a contrast function to determine if subsampling is necessary) */
2297                         /* 2003-09-27: changed it so filtering disamples supersampling, as it would waste time */
2298                         if ( lightSamples > 1 || lightRandomSamples ) {
2299                                 /* walk luxels */
2300                                 for ( y = 0; y < ( lm->sh - 1 ); y++ )
2301                                 {
2302                                         for ( x = 0; x < ( lm->sw - 1 ); x++ )
2303                                         {
2304                                                 /* setup */
2305                                                 mapped = 0;
2306                                                 lighted = 0;
2307                                                 VectorClear( total );
2308
2309                                                 /* test 2x2 stamp */
2310                                                 for ( t = 0; t < 4; t++ )
2311                                                 {
2312                                                         /* set sample coords */
2313                                                         sx = x + tests[ t ][ 0 ];
2314                                                         sy = y + tests[ t ][ 1 ];
2315
2316                                                         /* get cluster */
2317                                                         cluster = SUPER_CLUSTER( sx, sy );
2318                                                         if ( *cluster < 0 ) {
2319                                                                 continue;
2320                                                         }
2321                                                         mapped++;
2322
2323                                                         /* get luxel */
2324                                                         flag = SUPER_FLAG( sx, sy );
2325                                                         if ( *flag & FLAG_FORCE_SUBSAMPLING ) {
2326                                                                 /* force a lighted/mapped discrepancy so we subsample */
2327                                                                 ++lighted;
2328                                                                 ++mapped;
2329                                                                 ++mapped;
2330                                                         }
2331                                                         lightLuxel = LIGHT_LUXEL( sx, sy );
2332                                                         VectorAdd( total, lightLuxel, total );
2333                                                         if ( ( lightLuxel[ 0 ] + lightLuxel[ 1 ] + lightLuxel[ 2 ] ) > 0.0f ) {
2334                                                                 lighted++;
2335                                                         }
2336                                                 }
2337
2338                                                 /* if total color is under a certain amount, then don't bother subsampling */
2339                                                 if ( total[ 0 ] <= 4.0f && total[ 1 ] <= 4.0f && total[ 2 ] <= 4.0f ) {
2340                                                         continue;
2341                                                 }
2342
2343                                                 /* if all 4 pixels are either in shadow or light, then don't subsample */
2344                                                 if ( lighted != 0 && lighted != mapped ) {
2345                                                         for ( t = 0; t < 4; t++ )
2346                                                         {
2347                                                                 /* set sample coords */
2348                                                                 sx = x + tests[ t ][ 0 ];
2349                                                                 sy = y + tests[ t ][ 1 ];
2350
2351                                                                 /* get luxel */
2352                                                                 cluster = SUPER_CLUSTER( sx, sy );
2353                                                                 if ( *cluster < 0 ) {
2354                                                                         continue;
2355                                                                 }
2356                                                                 flag = SUPER_FLAG( sx, sy );
2357                                                                 if ( *flag & FLAG_ALREADY_SUBSAMPLED ) { // already subsampled
2358                                                                         continue;
2359                                                                 }
2360                                                                 lightLuxel = LIGHT_LUXEL( sx, sy );
2361                                                                 lightDeluxel = LIGHT_DELUXEL( sx, sy );
2362                                                                 origin = SUPER_ORIGIN( sx, sy );
2363
2364                                                                 /* only subsample shadowed luxels */
2365                                                                 //%     if( (lightLuxel[ 0 ] + lightLuxel[ 1 ] + lightLuxel[ 2 ]) <= 0.0f )
2366                                                                 //%             continue;
2367
2368                                                                 /* subsample it */
2369                                                                 if ( lightRandomSamples ) {
2370                                                                         RandomSubsampleRawLuxel( lm, &trace, origin, sx, sy, 0.5f * lightSamplesSearchBoxSize, lightLuxel, deluxemap ? lightDeluxel : NULL );
2371                                                                 }
2372                                                                 else{
2373                                                                         SubsampleRawLuxel_r( lm, &trace, origin, sx, sy, 0.25f * lightSamplesSearchBoxSize, lightLuxel, deluxemap ? lightDeluxel : NULL );
2374                                                                 }
2375
2376                                                                 *flag |= FLAG_ALREADY_SUBSAMPLED;
2377
2378                                                                 /* debug code to colorize subsampled areas to yellow */
2379                                                                 //%     luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2380                                                                 //%     VectorSet( luxel, 255, 204, 0 );
2381                                                         }
2382                                                 }
2383                                         }
2384                                 }
2385                         }
2386
2387                         /* tertiary pass, apply dirt map (ambient occlusion) */
2388                         if ( 0 && dirty ) {
2389                                 /* walk luxels */
2390                                 for ( y = 0; y < lm->sh; y++ )
2391                                 {
2392                                         for ( x = 0; x < lm->sw; x++ )
2393                                         {
2394                                                 /* get cluster  */
2395                                                 cluster = SUPER_CLUSTER( x, y );
2396                                                 if ( *cluster < 0 ) {
2397                                                         continue;
2398                                                 }
2399
2400                                                 /* get particulars */
2401                                                 lightLuxel = LIGHT_LUXEL( x, y );
2402                                                 dirt = SUPER_DIRT( x, y );
2403
2404                                                 /* scale light value */
2405                                                 VectorScale( lightLuxel, *dirt, lightLuxel );
2406                                         }
2407                                 }
2408                         }
2409
2410                         /* allocate sampling lightmap storage */
2411                         if ( lm->superLuxels[ lightmapNum ] == NULL ) {
2412                                 /* allocate sampling lightmap storage */
2413                                 size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
2414                                 lm->superLuxels[ lightmapNum ] = safe_malloc( size );
2415                                 memset( lm->superLuxels[ lightmapNum ], 0, size );
2416                         }
2417
2418                         /* set style */
2419                         if ( lightmapNum > 0 ) {
2420                                 lm->styles[ lightmapNum ] = trace.light->style;
2421                                 //%     Sys_Printf( "Surface %6d has lightstyle %d\n", rawLightmapNum, trace.light->style );
2422                         }
2423
2424                         /* copy to permanent luxels */
2425                         for ( y = 0; y < lm->sh; y++ )
2426                         {
2427                                 for ( x = 0; x < lm->sw; x++ )
2428                                 {
2429                                         /* get cluster and origin */
2430                                         cluster = SUPER_CLUSTER( x, y );
2431                                         if ( *cluster < 0 ) {
2432                                                 continue;
2433                                         }
2434                                         origin = SUPER_ORIGIN( x, y );
2435
2436                                         /* filter? */
2437                                         if ( luxelFilterRadius ) {
2438                                                 /* setup */
2439                                                 VectorClear( averageColor );
2440                                                 VectorClear( averageDir );
2441                                                 samples = 0.0f;
2442
2443                                                 /* cheaper distance-based filtering */
2444                                                 for ( sy = ( y - luxelFilterRadius ); sy <= ( y + luxelFilterRadius ); sy++ )
2445                                                 {
2446                                                         if ( sy < 0 || sy >= lm->sh ) {
2447                                                                 continue;
2448                                                         }
2449
2450                                                         for ( sx = ( x - luxelFilterRadius ); sx <= ( x + luxelFilterRadius ); sx++ )
2451                                                         {
2452                                                                 if ( sx < 0 || sx >= lm->sw ) {
2453                                                                         continue;
2454                                                                 }
2455
2456                                                                 /* get particulars */
2457                                                                 cluster = SUPER_CLUSTER( sx, sy );
2458                                                                 if ( *cluster < 0 ) {
2459                                                                         continue;
2460                                                                 }
2461                                                                 lightLuxel = LIGHT_LUXEL( sx, sy );
2462                                                                 lightDeluxel = LIGHT_DELUXEL( sx, sy );
2463
2464                                                                 /* create weight */
2465                                                                 weight = ( abs( sx - x ) == luxelFilterRadius ? 0.5f : 1.0f );
2466                                                                 weight *= ( abs( sy - y ) == luxelFilterRadius ? 0.5f : 1.0f );
2467
2468                                                                 /* scale luxel by filter weight */
2469                                                                 VectorScale( lightLuxel, weight, color );
2470                                                                 VectorAdd( averageColor, color, averageColor );
2471                                                                 if ( deluxemap ) {
2472                                                                         VectorScale( lightDeluxel, weight, direction );
2473                                                                         VectorAdd( averageDir, direction, averageDir );
2474                                                                 }
2475                                                                 samples += weight;
2476                                                         }
2477                                                 }
2478
2479                                                 /* any samples? */
2480                                                 if ( samples <= 0.0f ) {
2481                                                         continue;
2482                                                 }
2483
2484                                                 /* scale into luxel */
2485                                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
2486                                                 luxel[ 3 ] = 1.0f;
2487
2488                                                 /* handle negative light */
2489                                                 if ( trace.light->flags & LIGHT_NEGATIVE ) {
2490                                                         luxel[ 0 ] -= averageColor[ 0 ] / samples;
2491                                                         luxel[ 1 ] -= averageColor[ 1 ] / samples;
2492                                                         luxel[ 2 ] -= averageColor[ 2 ] / samples;
2493                                                 }
2494
2495                                                 /* handle normal light */
2496                                                 else
2497                                                 {
2498                                                         luxel[ 0 ] += averageColor[ 0 ] / samples;
2499                                                         luxel[ 1 ] += averageColor[ 1 ] / samples;
2500                                                         luxel[ 2 ] += averageColor[ 2 ] / samples;
2501                                                 }
2502
2503                                                 if ( deluxemap ) {
2504                                                         /* scale into luxel */
2505                                                         deluxel = SUPER_DELUXEL( x, y );
2506                                                         deluxel[ 0 ] += averageDir[ 0 ] / samples;
2507                                                         deluxel[ 1 ] += averageDir[ 1 ] / samples;
2508                                                         deluxel[ 2 ] += averageDir[ 2 ] / samples;
2509                                                 }
2510                                         }
2511
2512                                         /* single sample */
2513                                         else
2514                                         {
2515                                                 /* get particulars */
2516                                                 lightLuxel = LIGHT_LUXEL( x, y );
2517                                                 lightDeluxel = LIGHT_DELUXEL( x, y );
2518                                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
2519                                                 deluxel = SUPER_DELUXEL( x, y );
2520
2521                                                 /* handle negative light */
2522                                                 if ( trace.light->flags & LIGHT_NEGATIVE ) {
2523                                                         VectorScale( averageColor, -1.0f, averageColor );
2524                                                 }
2525
2526                                                 /* add color */
2527                                                 luxel[ 3 ] = 1.0f;
2528
2529                                                 /* handle negative light */
2530                                                 if ( trace.light->flags & LIGHT_NEGATIVE ) {
2531                                                         VectorSubtract( luxel, lightLuxel, luxel );
2532                                                 }
2533
2534                                                 /* handle normal light */
2535                                                 else{
2536                                                         VectorAdd( luxel, lightLuxel, luxel );
2537                                                 }
2538
2539                                                 if ( deluxemap ) {
2540                                                         VectorAdd( deluxel, lightDeluxel, deluxel );
2541                                                 }
2542                                         }
2543                                 }
2544                         }
2545                 }
2546
2547                 /* free temporary luxels */
2548                 if ( lightLuxels != stackLightLuxels ) {
2549                         free( lightLuxels );
2550                 }
2551
2552                 if ( deluxemap ) {
2553                         free( lightDeluxels );
2554                 }
2555         }
2556
2557         /* free light list */
2558         FreeTraceLights( &trace );
2559
2560         /* floodlight pass */
2561         if ( floodlighty ) {
2562                 FloodlightIlluminateLightmap( lm );
2563         }
2564
2565         if ( debugnormals ) {
2566                 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2567                 {
2568                         /* early out */
2569                         if ( lm->superLuxels[ lightmapNum ] == NULL ) {
2570                                 continue;
2571                         }
2572
2573                         for ( y = 0; y < lm->sh; y++ )
2574                         {
2575                                 for ( x = 0; x < lm->sw; x++ )
2576                                 {
2577                                         /* get cluster */
2578                                         cluster = SUPER_CLUSTER( x, y );
2579                                         //%     if( *cluster < 0 )
2580                                         //%             continue;
2581
2582                                         /* get particulars */
2583                                         luxel = SUPER_LUXEL( lightmapNum, x, y );
2584                                         normal = SUPER_NORMAL(  x, y );
2585
2586                                         luxel[0] = ( normal[0] * 127 ) + 127;
2587                                         luxel[1] = ( normal[1] * 127 ) + 127;
2588                                         luxel[2] = ( normal[2] * 127 ) + 127;
2589                                 }
2590                         }
2591                 }
2592         }
2593
2594         /*      -----------------------------------------------------------------
2595             dirt pass
2596             ----------------------------------------------------------------- */
2597
2598         if ( dirty ) {
2599                 /* walk lightmaps */
2600                 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2601                 {
2602                         /* early out */
2603                         if ( lm->superLuxels[ lightmapNum ] == NULL ) {
2604                                 continue;
2605                         }
2606
2607                         /* apply dirt to each luxel */
2608                         for ( y = 0; y < lm->sh; y++ )
2609                         {
2610                                 for ( x = 0; x < lm->sw; x++ )
2611                                 {
2612                                         /* get cluster */
2613                                         cluster = SUPER_CLUSTER( x, y );
2614
2615                                         /* get particulars */
2616                                         luxel = SUPER_LUXEL( lightmapNum, x, y );
2617                                         dirt = SUPER_DIRT( x, y );
2618
2619                                         /* apply dirt */
2620                                         VectorScale( luxel, *dirt, luxel );
2621
2622                                         /* debugging */
2623                                         if ( dirtDebug ) {
2624                                                 VectorSet( luxel, *dirt * 255.0f, *dirt * 255.0f, *dirt * 255.0f );
2625                                         }
2626                                 }
2627                         }
2628                 }
2629         }
2630
2631         /* -----------------------------------------------------------------
2632            filter pass
2633            ----------------------------------------------------------------- */
2634
2635         /* walk lightmaps */
2636         for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2637         {
2638                 /* early out */
2639                 if ( lm->superLuxels[ lightmapNum ] == NULL ) {
2640                         continue;
2641                 }
2642
2643                 /* average occluded luxels from neighbors */
2644                 for ( y = 0; y < lm->sh; y++ )
2645                 {
2646                         for ( x = 0; x < lm->sw; x++ )
2647                         {
2648                                 /* get particulars */
2649                                 cluster = SUPER_CLUSTER( x, y );
2650                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
2651                                 deluxel = SUPER_DELUXEL( x, y );
2652                                 normal = SUPER_NORMAL( x, y );
2653
2654                                 /* determine if filtering is necessary */
2655                                 filterColor = qfalse;
2656                                 filterDir = qfalse;
2657                                 if ( *cluster < 0 ||
2658                                          ( lm->splotchFix && ( luxel[ 0 ] <= ambientColor[ 0 ] || luxel[ 1 ] <= ambientColor[ 1 ] || luxel[ 2 ] <= ambientColor[ 2 ] ) ) ) {
2659                                         filterColor = qtrue;
2660                                 }
2661
2662                                 if ( deluxemap && lightmapNum == 0 && ( *cluster < 0 || filter ) ) {
2663                                         filterDir = qtrue;
2664                                 }
2665
2666                                 if ( !filterColor && !filterDir ) {
2667                                         continue;
2668                                 }
2669
2670                                 /* choose seed amount */
2671                                 VectorClear( averageColor );
2672                                 VectorClear( averageDir );
2673                                 samples = 0.0f;
2674
2675                                 /* walk 3x3 matrix */
2676                                 for ( sy = ( y - 1 ); sy <= ( y + 1 ); sy++ )
2677                                 {
2678                                         if ( sy < 0 || sy >= lm->sh ) {
2679                                                 continue;
2680                                         }
2681
2682                                         for ( sx = ( x - 1 ); sx <= ( x + 1 ); sx++ )
2683                                         {
2684                                                 if ( sx < 0 || sx >= lm->sw || ( sx == x && sy == y ) ) {
2685                                                         continue;
2686                                                 }
2687
2688                                                 /* get neighbor's particulars */
2689                                                 cluster2 = SUPER_CLUSTER( sx, sy );
2690                                                 luxel2 = SUPER_LUXEL( lightmapNum, sx, sy );
2691                                                 deluxel2 = SUPER_DELUXEL( sx, sy );
2692
2693                                                 /* ignore unmapped/unlit luxels */
2694                                                 if ( *cluster2 < 0 || luxel2[ 3 ] == 0.0f ||
2695                                                          ( lm->splotchFix && VectorCompare( luxel2, ambientColor ) ) ) {
2696                                                         continue;
2697                                                 }
2698
2699                                                 /* add its distinctiveness to our own */
2700                                                 VectorAdd( averageColor, luxel2, averageColor );
2701                                                 samples += luxel2[ 3 ];
2702                                                 if ( filterDir ) {
2703                                                         VectorAdd( averageDir, deluxel2, averageDir );
2704                                                 }
2705                                         }
2706                                 }
2707
2708                                 /* fall through */
2709                                 if ( samples <= 0.0f ) {
2710                                         continue;
2711                                 }
2712
2713                                 /* dark lightmap seams */
2714                                 if ( dark ) {
2715                                         if ( lightmapNum == 0 ) {
2716                                                 VectorMA( averageColor, 2.0f, ambientColor, averageColor );
2717                                         }
2718                                         samples += 2.0f;
2719                                 }
2720
2721                                 /* average it */
2722                                 if ( filterColor ) {
2723                                         VectorDivide( averageColor, samples, luxel );
2724                                         luxel[ 3 ] = 1.0f;
2725                                 }
2726                                 if ( filterDir ) {
2727                                         VectorDivide( averageDir, samples, deluxel );
2728                                 }
2729
2730                                 /* set cluster to -3 */
2731                                 if ( *cluster < 0 ) {
2732                                         *cluster = CLUSTER_FLOODED;
2733                                 }
2734                         }
2735                 }
2736         }
2737 }
2738
2739
2740
2741 /*
2742    IlluminateVertexes()
2743    light the surface vertexes
2744  */
2745
2746 #define VERTEX_NUDGE    4.0f
2747
2748 void IlluminateVertexes( int num ){
2749         int i, x, y, z, x1, y1, z1, sx, sy, radius, maxRadius, *cluster;
2750         int lightmapNum, numAvg;
2751         float samples, *vertLuxel, *radVertLuxel, *luxel, dirt;
2752         vec3_t origin, temp, temp2, colors[ MAX_LIGHTMAPS ], avgColors[ MAX_LIGHTMAPS ];
2753         bspDrawSurface_t    *ds;
2754         surfaceInfo_t       *info;
2755         rawLightmap_t       *lm;
2756         bspDrawVert_t       *verts;
2757         trace_t trace;
2758         float floodLightAmount;
2759         vec3_t floodColor;
2760
2761
2762         /* get surface, info, and raw lightmap */
2763         ds = &bspDrawSurfaces[ num ];
2764         info = &surfaceInfos[ num ];
2765         lm = info->lm;
2766
2767         /* -----------------------------------------------------------------
2768            illuminate the vertexes
2769            ----------------------------------------------------------------- */
2770
2771         /* calculate vertex lighting for surfaces without lightmaps */
2772         if ( lm == NULL || cpmaHack ) {
2773                 /* setup trace */
2774                 trace.testOcclusion = ( cpmaHack && lm != NULL ) ? qfalse : !noTrace;
2775                 trace.forceSunlight = info->si->forceSunlight;
2776                 trace.recvShadows = info->recvShadows;
2777                 trace.numSurfaces = 1;
2778                 trace.surfaces = &num;
2779                 trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
2780
2781                 /* twosided lighting */
2782                 trace.twoSided = info->si->twoSided;
2783
2784                 /* make light list for this surface */
2785                 CreateTraceLightsForSurface( num, &trace );
2786
2787                 /* setup */
2788                 verts = yDrawVerts + ds->firstVert;
2789                 numAvg = 0;
2790                 memset( avgColors, 0, sizeof( avgColors ) );
2791
2792                 /* walk the surface verts */
2793                 for ( i = 0; i < ds->numVerts; i++ )
2794                 {
2795                         /* get vertex luxel */
2796                         radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2797
2798                         /* color the luxel with raw lightmap num? */
2799                         if ( debugSurfaces ) {
2800                                 VectorCopy( debugColors[ num % 12 ], radVertLuxel );
2801                         }
2802
2803                         /* color the luxel with luxel origin? */
2804                         else if ( debugOrigin ) {
2805                                 VectorSubtract( info->maxs, info->mins, temp );
2806                                 VectorScale( temp, ( 1.0f / 255.0f ), temp );
2807                                 VectorSubtract( origin, lm->mins, temp2 );
2808                                 radVertLuxel[ 0 ] = info->mins[ 0 ] + ( temp[ 0 ] * temp2[ 0 ] );
2809                                 radVertLuxel[ 1 ] = info->mins[ 1 ] + ( temp[ 1 ] * temp2[ 1 ] );
2810                                 radVertLuxel[ 2 ] = info->mins[ 2 ] + ( temp[ 2 ] * temp2[ 2 ] );
2811                         }
2812
2813                         /* color the luxel with the normal */
2814                         else if ( normalmap ) {
2815                                 radVertLuxel[ 0 ] = ( verts[ i ].normal[ 0 ] + 1.0f ) * 127.5f;
2816                                 radVertLuxel[ 1 ] = ( verts[ i ].normal[ 1 ] + 1.0f ) * 127.5f;
2817                                 radVertLuxel[ 2 ] = ( verts[ i ].normal[ 2 ] + 1.0f ) * 127.5f;
2818                         }
2819
2820                         else if ( info->si->noVertexLight ) {
2821                                 VectorSet( radVertLuxel, 127.5f, 127.5f, 127.5f );
2822                         }
2823
2824                         else if ( noVertexLighting > 0 ) {
2825                                 VectorSet( radVertLuxel, 127.5f * noVertexLighting, 127.5f * noVertexLighting, 127.5f * noVertexLighting );
2826                         }
2827
2828                         /* illuminate the vertex */
2829                         else
2830                         {
2831                                 /* clear vertex luxel */
2832                                 VectorSet( radVertLuxel, -1.0f, -1.0f, -1.0f );
2833
2834                                 /* try at initial origin */
2835                                 trace.cluster = ClusterForPointExtFilter( verts[ i ].xyz, VERTEX_EPSILON, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ] );
2836                                 if ( trace.cluster >= 0 ) {
2837                                         /* setup trace */
2838                                         VectorCopy( verts[ i ].xyz, trace.origin );
2839                                         VectorCopy( verts[ i ].normal, trace.normal );
2840
2841                                         /* r7 dirt */
2842                                         if ( dirty && !bouncing ) {
2843                                                 dirt = DirtForSample( &trace );
2844                                         }
2845                                         else{
2846                                                 dirt = 1.0f;
2847                                         }
2848
2849                                         /* jal: floodlight */
2850                                         floodLightAmount = 0.0f;
2851                                         VectorClear( floodColor );
2852                                         if ( floodlighty && !bouncing ) {
2853                                                 floodLightAmount = floodlightIntensity * FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality );
2854                                                 VectorScale( floodlightRGB, floodLightAmount, floodColor );
2855                                         }
2856
2857                                         /* trace */
2858                                         LightingAtSample( &trace, ds->vertexStyles, colors );
2859
2860                                         /* store */
2861                                         for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2862                                         {
2863                                                 /* r7 dirt */
2864                                                 VectorScale( colors[ lightmapNum ], dirt, colors[ lightmapNum ] );
2865
2866                                                 /* jal: floodlight */
2867                                                 VectorAdd( colors[ lightmapNum ], floodColor, colors[ lightmapNum ] );
2868
2869                                                 /* store */
2870                                                 radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
2871                                                 VectorCopy( colors[ lightmapNum ], radVertLuxel );
2872                                                 VectorAdd( avgColors[ lightmapNum ], colors[ lightmapNum ], colors[ lightmapNum ] );
2873                                         }
2874                                 }
2875
2876                                 /* is this sample bright enough? */
2877                                 radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2878                                 if ( radVertLuxel[ 0 ] <= ambientColor[ 0 ] &&
2879                                          radVertLuxel[ 1 ] <= ambientColor[ 1 ] &&
2880                                          radVertLuxel[ 2 ] <= ambientColor[ 2 ] ) {
2881                                         /* nudge the sample point around a bit */
2882                                         for ( x = 0; x < 5; x++ )
2883                                         {
2884                                                 /* two's complement 0, 1, -1, 2, -2, etc */
2885                                                 x1 = ( ( x >> 1 ) ^ ( x & 1 ? -1 : 0 ) ) + ( x & 1 );
2886
2887                                                 for ( y = 0; y < 5; y++ )
2888                                                 {
2889                                                         y1 = ( ( y >> 1 ) ^ ( y & 1 ? -1 : 0 ) ) + ( y & 1 );
2890
2891                                                         for ( z = 0; z < 5; z++ )
2892                                                         {
2893                                                                 z1 = ( ( z >> 1 ) ^ ( z & 1 ? -1 : 0 ) ) + ( z & 1 );
2894
2895                                                                 /* nudge origin */
2896                                                                 trace.origin[ 0 ] = verts[ i ].xyz[ 0 ] + ( VERTEX_NUDGE * x1 );
2897                                                                 trace.origin[ 1 ] = verts[ i ].xyz[ 1 ] + ( VERTEX_NUDGE * y1 );
2898                                                                 trace.origin[ 2 ] = verts[ i ].xyz[ 2 ] + ( VERTEX_NUDGE * z1 );
2899
2900                                                                 /* try at nudged origin */
2901                                                                 trace.cluster = ClusterForPointExtFilter( origin, VERTEX_EPSILON, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ] );
2902                                                                 if ( trace.cluster < 0 ) {
2903                                                                         continue;
2904                                                                 }
2905
2906                                                                 /* r7 dirt */
2907                                                                 if ( dirty && !bouncing ) {
2908                                                                         dirt = DirtForSample( &trace );
2909                                                                 }
2910                                                                 else{
2911                                                                         dirt = 1.0f;
2912                                                                 }
2913
2914                                                                 /* jal: floodlight */
2915                                                                 floodLightAmount = 0.0f;
2916                                                                 VectorClear( floodColor );
2917                                                                 if ( floodlighty && !bouncing ) {
2918                                                                         floodLightAmount = floodlightIntensity * FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality );
2919                                                                         VectorScale( floodlightRGB, floodLightAmount, floodColor );
2920                                                                 }
2921
2922                                                                 /* trace */
2923                                                                 LightingAtSample( &trace, ds->vertexStyles, colors );
2924
2925                                                                 /* store */
2926                                                                 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2927                                                                 {
2928                                                                         /* r7 dirt */
2929                                                                         VectorScale( colors[ lightmapNum ], dirt, colors[ lightmapNum ] );
2930
2931                                                                         /* jal: floodlight */
2932                                                                         VectorAdd( colors[ lightmapNum ], floodColor, colors[ lightmapNum ] );
2933
2934                                                                         /* store */
2935                                                                         radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
2936                                                                         VectorCopy( colors[ lightmapNum ], radVertLuxel );
2937                                                                 }
2938
2939                                                                 /* bright enough? */
2940                                                                 radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2941                                                                 if ( radVertLuxel[ 0 ] > ambientColor[ 0 ] ||
2942                                                                          radVertLuxel[ 1 ] > ambientColor[ 1 ] ||
2943                                                                          radVertLuxel[ 2 ] > ambientColor[ 2 ] ) {
2944                                                                         x = y = z = 1000;
2945                                                                 }
2946                                                         }
2947                                                 }
2948                                         }
2949                                 }
2950
2951                                 /* add to average? */
2952                                 radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2953                                 if ( radVertLuxel[ 0 ] > ambientColor[ 0 ] ||
2954                                          radVertLuxel[ 1 ] > ambientColor[ 1 ] ||
2955                                          radVertLuxel[ 2 ] > ambientColor[ 2 ] ) {
2956                                         numAvg++;
2957                                         for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2958                                         {
2959                                                 radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
2960                                                 VectorAdd( avgColors[ lightmapNum ], radVertLuxel, avgColors[ lightmapNum ] );
2961                                         }
2962                                 }
2963                         }
2964
2965                         /* another happy customer */
2966                         numVertsIlluminated++;
2967                 }
2968
2969                 /* set average color */
2970                 if ( numAvg > 0 ) {
2971                         for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2972                                 VectorScale( avgColors[ lightmapNum ], ( 1.0f / numAvg ), avgColors[ lightmapNum ] );
2973                 }
2974                 else
2975                 {
2976                         VectorCopy( ambientColor, avgColors[ 0 ] );
2977                 }
2978
2979                 /* clean up and store vertex color */
2980                 for ( i = 0; i < ds->numVerts; i++ )
2981                 {
2982                         /* get vertex luxel */
2983                         radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2984
2985                         /* store average in occluded vertexes */
2986                         if ( radVertLuxel[ 0 ] < 0.0f ) {
2987                                 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2988                                 {
2989                                         radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
2990                                         VectorCopy( avgColors[ lightmapNum ], radVertLuxel );
2991
2992                                         /* debug code */
2993                                         //%     VectorSet( radVertLuxel, 255.0f, 0.0f, 0.0f );
2994                                 }
2995                         }
2996
2997                         /* store it */
2998                         for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2999                         {
3000                                 /* get luxels */
3001                                 vertLuxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
3002                                 radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
3003
3004                                 /* store */
3005                                 if ( bouncing || bounce == 0 || !bounceOnly ) {
3006                                         VectorAdd( vertLuxel, radVertLuxel, vertLuxel );
3007                                 }
3008                                 if ( !info->si->noVertexLight ) {
3009                                         ColorToBytes( vertLuxel, verts[ i ].color[ lightmapNum ], info->si->vertexScale );
3010                                 }
3011                         }
3012                 }
3013
3014                 /* free light list */
3015                 FreeTraceLights( &trace );
3016
3017                 /* return to sender */
3018                 return;
3019         }
3020
3021         /* -----------------------------------------------------------------
3022            reconstitute vertex lighting from the luxels
3023            ----------------------------------------------------------------- */
3024
3025         /* set styles from lightmap */
3026         for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3027                 ds->vertexStyles[ lightmapNum ] = lm->styles[ lightmapNum ];
3028
3029         /* get max search radius */
3030         maxRadius = lm->sw;
3031         maxRadius = maxRadius > lm->sh ? maxRadius : lm->sh;
3032
3033         /* walk the surface verts */
3034         verts = yDrawVerts + ds->firstVert;
3035         for ( i = 0; i < ds->numVerts; i++ )
3036         {
3037                 /* do each lightmap */
3038                 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3039                 {
3040                         /* early out */
3041                         if ( lm->superLuxels[ lightmapNum ] == NULL ) {
3042                                 continue;
3043                         }
3044
3045                         /* get luxel coords */
3046                         x = verts[ i ].lightmap[ lightmapNum ][ 0 ];
3047                         y = verts[ i ].lightmap[ lightmapNum ][ 1 ];
3048                         if ( x < 0 ) {
3049                                 x = 0;
3050                         }
3051                         else if ( x >= lm->sw ) {
3052                                 x = lm->sw - 1;
3053                         }
3054                         if ( y < 0 ) {
3055                                 y = 0;
3056                         }
3057                         else if ( y >= lm->sh ) {
3058                                 y = lm->sh - 1;
3059                         }
3060
3061                         /* get vertex luxels */
3062                         vertLuxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
3063                         radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
3064
3065                         /* color the luxel with the normal? */
3066                         if ( normalmap ) {
3067                                 radVertLuxel[ 0 ] = ( verts[ i ].normal[ 0 ] + 1.0f ) * 127.5f;
3068                                 radVertLuxel[ 1 ] = ( verts[ i ].normal[ 1 ] + 1.0f ) * 127.5f;
3069                                 radVertLuxel[ 2 ] = ( verts[ i ].normal[ 2 ] + 1.0f ) * 127.5f;
3070                         }
3071
3072                         /* color the luxel with surface num? */
3073                         else if ( debugSurfaces ) {
3074                                 VectorCopy( debugColors[ num % 12 ], radVertLuxel );
3075                         }
3076
3077                         else if ( info->si->noVertexLight ) {
3078                                 VectorSet( radVertLuxel, 127.5f, 127.5f, 127.5f );
3079                         }
3080
3081                         else if ( noVertexLighting > 0 ) {
3082                                 VectorSet( radVertLuxel, 127.5f * noVertexLighting, 127.5f * noVertexLighting, 127.5f * noVertexLighting );
3083                         }
3084
3085                         /* divine color from the superluxels */
3086                         else
3087                         {
3088                                 /* increasing radius */
3089                                 VectorClear( radVertLuxel );
3090                                 samples = 0.0f;
3091                                 for ( radius = 0; radius < maxRadius && samples <= 0.0f; radius++ )
3092                                 {
3093                                         /* sample within radius */
3094                                         for ( sy = ( y - radius ); sy <= ( y + radius ); sy++ )
3095                                         {
3096                                                 if ( sy < 0 || sy >= lm->sh ) {
3097                                                         continue;
3098                                                 }
3099
3100                                                 for ( sx = ( x - radius ); sx <= ( x + radius ); sx++ )
3101                                                 {
3102                                                         if ( sx < 0 || sx >= lm->sw ) {
3103                                                                 continue;
3104                                                         }
3105
3106                                                         /* get luxel particulars */
3107                                                         luxel = SUPER_LUXEL( lightmapNum, sx, sy );
3108                                                         cluster = SUPER_CLUSTER( sx, sy );
3109                                                         if ( *cluster < 0 ) {
3110                                                                 continue;
3111                                                         }
3112
3113                                                         /* testing: must be brigher than ambient color */
3114                                                         //%     if( luxel[ 0 ] <= ambientColor[ 0 ] || luxel[ 1 ] <= ambientColor[ 1 ] || luxel[ 2 ] <= ambientColor[ 2 ] )
3115                                                         //%             continue;
3116
3117                                                         /* add its distinctiveness to our own */
3118                                                         VectorAdd( radVertLuxel, luxel, radVertLuxel );
3119                                                         samples += luxel[ 3 ];
3120                                                 }
3121                                         }
3122                                 }
3123
3124                                 /* any color? */
3125                                 if ( samples > 0.0f ) {
3126                                         VectorDivide( radVertLuxel, samples, radVertLuxel );
3127                                 }
3128                                 else{
3129                                         VectorCopy( ambientColor, radVertLuxel );
3130                                 }
3131                         }
3132
3133                         /* store into floating point storage */
3134                         VectorAdd( vertLuxel, radVertLuxel, vertLuxel );
3135                         numVertsIlluminated++;
3136
3137                         /* store into bytes (for vertex approximation) */
3138                         if ( !info->si->noVertexLight ) {
3139                                 ColorToBytes( vertLuxel, verts[ i ].color[ lightmapNum ], 1.0f );
3140                         }
3141                 }
3142         }
3143 }
3144
3145
3146
3147 /* -------------------------------------------------------------------------------
3148
3149    light optimization (-fast)
3150
3151    creates a list of lights that will affect a surface and stores it in tw
3152    this is to optimize surface lighting by culling out as many of the
3153    lights in the world as possible from further calculation
3154
3155    ------------------------------------------------------------------------------- */
3156
3157 /*
3158    SetupBrushes()
3159    determines opaque brushes in the world and find sky shaders for sunlight calculations
3160  */
3161
3162 void SetupBrushesFlags( unsigned int mask_any, unsigned int test_any, unsigned int mask_all, unsigned int test_all ){
3163         int i, j, b;
3164         unsigned int compileFlags, allCompileFlags;
3165         bspBrush_t      *brush;
3166         bspBrushSide_t  *side;
3167         bspShader_t     *shader;
3168         shaderInfo_t    *si;
3169
3170
3171         /* note it */
3172         Sys_FPrintf( SYS_VRB, "--- SetupBrushes ---\n" );
3173
3174         /* allocate */
3175         if ( opaqueBrushes == NULL ) {
3176                 opaqueBrushes = safe_malloc( numBSPBrushes / 8 + 1 );
3177         }
3178
3179         /* clear */
3180         memset( opaqueBrushes, 0, numBSPBrushes / 8 + 1 );
3181         numOpaqueBrushes = 0;
3182
3183         /* walk the list of worldspawn brushes */
3184         for ( i = 0; i < bspModels[ 0 ].numBSPBrushes; i++ )
3185         {
3186                 /* get brush */
3187                 b = bspModels[ 0 ].firstBSPBrush + i;
3188                 brush = &bspBrushes[ b ];
3189
3190                 /* check all sides */
3191                 compileFlags = 0;
3192                 allCompileFlags = ~( 0u );
3193                 for ( j = 0; j < brush->numSides; j++ )
3194                 {
3195                         /* do bsp shader calculations */
3196                         side = &bspBrushSides[ brush->firstSide + j ];
3197                         shader = &bspShaders[ side->shaderNum ];
3198
3199                         /* get shader info */
3200                         si = ShaderInfoForShaderNull( shader->shader );
3201                         if ( si == NULL ) {
3202                                 continue;
3203                         }
3204
3205                         /* or together compile flags */
3206                         compileFlags |= si->compileFlags;
3207                         allCompileFlags &= si->compileFlags;
3208                 }
3209
3210                 /* determine if this brush is opaque to light */
3211                 if ( ( compileFlags & mask_any ) == test_any && ( allCompileFlags & mask_all ) == test_all ) {
3212                         opaqueBrushes[ b >> 3 ] |= ( 1 << ( b & 7 ) );
3213                         numOpaqueBrushes++;
3214                         maxOpaqueBrush = i;
3215                 }
3216         }
3217
3218         /* emit some statistics */
3219         Sys_FPrintf( SYS_VRB, "%9d opaque brushes\n", numOpaqueBrushes );
3220 }
3221 void SetupBrushes( void ){
3222         SetupBrushesFlags( C_TRANSLUCENT, 0, 0, 0 );
3223 }
3224
3225
3226
3227 /*
3228    ClusterVisible()
3229    determines if two clusters are visible to each other using the PVS
3230  */
3231
3232 qboolean ClusterVisible( int a, int b ){
3233         int leafBytes;
3234         byte        *pvs;
3235
3236
3237         /* dummy check */
3238         if ( a < 0 || b < 0 ) {
3239                 return qfalse;
3240         }
3241
3242         /* early out */
3243         if ( a == b ) {
3244                 return qtrue;
3245         }
3246
3247         /* not vised? */
3248         if ( numBSPVisBytes <= 8 ) {
3249                 return qtrue;
3250         }
3251
3252         /* get pvs data */
3253         /* portalClusters = ((int *) bspVisBytes)[ 0 ]; */
3254         leafBytes = ( (int*) bspVisBytes )[ 1 ];
3255         pvs = bspVisBytes + VIS_HEADER_SIZE + ( a * leafBytes );
3256
3257         /* check */
3258         if ( ( pvs[ b >> 3 ] & ( 1 << ( b & 7 ) ) ) ) {
3259                 return qtrue;
3260         }
3261         return qfalse;
3262 }
3263
3264
3265
3266 /*
3267    PointInLeafNum_r()
3268    borrowed from vlight.c
3269  */
3270
3271 int PointInLeafNum_r( vec3_t point, int nodenum ){
3272         int leafnum;
3273         vec_t dist;
3274         bspNode_t       *node;
3275         bspPlane_t  *plane;
3276
3277
3278         while ( nodenum >= 0 )
3279         {
3280                 node = &bspNodes[ nodenum ];
3281                 plane = &bspPlanes[ node->planeNum ];
3282                 dist = DotProduct( point, plane->normal ) - plane->dist;
3283                 if ( dist > 0.1 ) {
3284                         nodenum = node->children[ 0 ];
3285                 }
3286                 else if ( dist < -0.1 ) {
3287                         nodenum = node->children[ 1 ];
3288                 }
3289                 else
3290                 {
3291                         leafnum = PointInLeafNum_r( point, node->children[ 0 ] );
3292                         if ( bspLeafs[ leafnum ].cluster != -1 ) {
3293                                 return leafnum;
3294                         }
3295                         nodenum = node->children[ 1 ];
3296                 }
3297         }
3298
3299         leafnum = -nodenum - 1;
3300         return leafnum;
3301 }
3302
3303
3304
3305 /*
3306    PointInLeafnum()
3307    borrowed from vlight.c
3308  */
3309
3310 int PointInLeafNum( vec3_t point ){
3311         return PointInLeafNum_r( point, 0 );
3312 }
3313
3314
3315
3316 /*
3317    ClusterVisibleToPoint() - ydnar
3318    returns qtrue if point can "see" cluster
3319  */
3320
3321 qboolean ClusterVisibleToPoint( vec3_t point, int cluster ){
3322         int pointCluster;
3323
3324
3325         /* get leafNum for point */
3326         pointCluster = ClusterForPoint( point );
3327         if ( pointCluster < 0 ) {
3328                 return qfalse;
3329         }
3330
3331         /* check pvs */
3332         return ClusterVisible( pointCluster, cluster );
3333 }
3334
3335
3336
3337 /*
3338    ClusterForPoint() - ydnar
3339    returns the pvs cluster for point
3340  */
3341
3342 int ClusterForPoint( vec3_t point ){
3343         int leafNum;
3344
3345
3346         /* get leafNum for point */
3347         leafNum = PointInLeafNum( point );
3348         if ( leafNum < 0 ) {
3349                 return -1;
3350         }
3351
3352         /* return the cluster */
3353         return bspLeafs[ leafNum ].cluster;
3354 }
3355
3356
3357
3358 /*
3359    ClusterForPointExt() - ydnar
3360    also takes brushes into account for occlusion testing
3361  */
3362
3363 int ClusterForPointExt( vec3_t point, float epsilon ){
3364         int i, j, b, leafNum, cluster;
3365         float dot;
3366         qboolean inside;
3367         int             *brushes, numBSPBrushes;
3368         bspLeaf_t       *leaf;
3369         bspBrush_t      *brush;
3370         bspPlane_t      *plane;
3371
3372
3373         /* get leaf for point */
3374         leafNum = PointInLeafNum( point );
3375         if ( leafNum < 0 ) {
3376                 return -1;
3377         }
3378         leaf = &bspLeafs[ leafNum ];
3379
3380         /* get the cluster */
3381         cluster = leaf->cluster;
3382         if ( cluster < 0 ) {
3383                 return -1;
3384         }
3385
3386         /* transparent leaf, so check point against all brushes in the leaf */
3387         brushes = &bspLeafBrushes[ leaf->firstBSPLeafBrush ];
3388         numBSPBrushes = leaf->numBSPLeafBrushes;
3389         for ( i = 0; i < numBSPBrushes; i++ )
3390         {
3391                 /* get parts */
3392                 b = brushes[ i ];
3393                 if ( b > maxOpaqueBrush ) {
3394                         continue;
3395                 }
3396                 brush = &bspBrushes[ b ];
3397                 if ( !( opaqueBrushes[ b >> 3 ] & ( 1 << ( b & 7 ) ) ) ) {
3398                         continue;
3399                 }
3400
3401                 /* check point against all planes */
3402                 inside = qtrue;
3403                 for ( j = 0; j < brush->numSides && inside; j++ )
3404                 {
3405                         plane = &bspPlanes[ bspBrushSides[ brush->firstSide + j ].planeNum ];
3406                         dot = DotProduct( point, plane->normal );
3407                         dot -= plane->dist;
3408                         if ( dot > epsilon ) {
3409                                 inside = qfalse;
3410                         }
3411                 }
3412
3413                 /* if inside, return bogus cluster */
3414                 if ( inside ) {
3415                         return -1 - b;
3416                 }
3417         }
3418
3419         /* if the point made it this far, it's not inside any opaque brushes */
3420         return cluster;
3421 }
3422
3423
3424
3425 /*
3426    ClusterForPointExtFilter() - ydnar
3427    adds cluster checking against a list of known valid clusters
3428  */
3429
3430 int ClusterForPointExtFilter( vec3_t point, float epsilon, int numClusters, int *clusters ){
3431         int i, cluster;
3432
3433
3434         /* get cluster for point */
3435         cluster = ClusterForPointExt( point, epsilon );
3436
3437         /* check if filtering is necessary */
3438         if ( cluster < 0 || numClusters <= 0 || clusters == NULL ) {
3439                 return cluster;
3440         }
3441
3442         /* filter */
3443         for ( i = 0; i < numClusters; i++ )
3444         {
3445                 if ( cluster == clusters[ i ] || ClusterVisible( cluster, clusters[ i ] ) ) {
3446                         return cluster;
3447                 }
3448         }
3449
3450         /* failed */
3451         return -1;
3452 }
3453
3454
3455
3456 /*
3457    ShaderForPointInLeaf() - ydnar
3458    checks a point against all brushes in a leaf, returning the shader of the brush
3459    also sets the cumulative surface and content flags for the brush hit
3460  */
3461
3462 int ShaderForPointInLeaf( vec3_t point, int leafNum, float epsilon, int wantContentFlags, int wantSurfaceFlags, int *contentFlags, int *surfaceFlags ){
3463         int i, j;
3464         float dot;
3465         qboolean inside;
3466         int             *brushes, numBSPBrushes;
3467         bspLeaf_t           *leaf;
3468         bspBrush_t      *brush;
3469         bspBrushSide_t  *side;
3470         bspPlane_t      *plane;
3471         bspShader_t     *shader;
3472         int allSurfaceFlags, allContentFlags;
3473
3474
3475         /* clear things out first */
3476         *surfaceFlags = 0;
3477         *contentFlags = 0;
3478
3479         /* get leaf */
3480         if ( leafNum < 0 ) {
3481                 return -1;
3482         }
3483         leaf = &bspLeafs[ leafNum ];
3484
3485         /* transparent leaf, so check point against all brushes in the leaf */
3486         brushes = &bspLeafBrushes[ leaf->firstBSPLeafBrush ];
3487         numBSPBrushes = leaf->numBSPLeafBrushes;
3488         for ( i = 0; i < numBSPBrushes; i++ )
3489         {
3490                 /* get parts */
3491                 brush = &bspBrushes[ brushes[ i ] ];
3492
3493                 /* check point against all planes */
3494                 inside = qtrue;
3495                 allSurfaceFlags = 0;
3496                 allContentFlags = 0;
3497                 for ( j = 0; j < brush->numSides && inside; j++ )
3498                 {
3499                         side = &bspBrushSides[ brush->firstSide + j ];
3500                         plane = &bspPlanes[ side->planeNum ];
3501                         dot = DotProduct( point, plane->normal );
3502                         dot -= plane->dist;
3503                         if ( dot > epsilon ) {
3504                                 inside = qfalse;
3505                         }
3506                         else
3507                         {
3508                                 shader = &bspShaders[ side->shaderNum ];
3509                                 allSurfaceFlags |= shader->surfaceFlags;
3510                                 allContentFlags |= shader->contentFlags;
3511                         }
3512                 }
3513
3514                 /* handle if inside */
3515                 if ( inside ) {
3516                         /* if there are desired flags, check for same and continue if they aren't matched */
3517                         if ( wantContentFlags && !( wantContentFlags & allContentFlags ) ) {
3518                                 continue;
3519                         }
3520                         if ( wantSurfaceFlags && !( wantSurfaceFlags & allSurfaceFlags ) ) {
3521                                 continue;
3522                         }
3523
3524                         /* store the cumulative flags and return the brush shader (which is mostly useless) */
3525                         *surfaceFlags = allSurfaceFlags;
3526                         *contentFlags = allContentFlags;
3527                         return brush->shaderNum;
3528                 }
3529         }
3530
3531         /* if the point made it this far, it's not inside any brushes */
3532         return -1;
3533 }
3534
3535
3536
3537 /*
3538    ChopBounds()
3539    chops a bounding box by the plane defined by origin and normal
3540    returns qfalse if the bounds is entirely clipped away
3541
3542    this is not exactly the fastest way to do this...
3543  */
3544
3545 qboolean ChopBounds( vec3_t mins, vec3_t maxs, vec3_t origin, vec3_t normal ){
3546         /* FIXME: rewrite this so it doesn't use bloody brushes */
3547         return qtrue;
3548 }
3549
3550
3551
3552 /*
3553    SetupEnvelopes()
3554    calculates each light's effective envelope,
3555    taking into account brightness, type, and pvs.
3556  */
3557
3558 #define LIGHT_EPSILON   0.125f
3559 #define LIGHT_NUDGE     2.0f
3560
3561 void SetupEnvelopes( qboolean forGrid, qboolean fastFlag ){
3562         int i, x, y, z, x1, y1, z1;
3563         light_t     *light, *light2, **owner;
3564         bspLeaf_t   *leaf;
3565         vec3_t origin, dir, mins, maxs;
3566         float radius, intensity;
3567         light_t     *buckets[ 256 ];
3568
3569
3570         /* early out for weird cases where there are no lights */
3571         if ( lights == NULL ) {
3572                 return;
3573         }
3574
3575         /* note it */
3576         Sys_FPrintf( SYS_VRB, "--- SetupEnvelopes%s ---\n", fastFlag ? " (fast)" : "" );
3577
3578         /* count lights */
3579         numLights = 0;
3580         numCulledLights = 0;
3581         owner = &lights;
3582         while ( *owner != NULL )
3583         {
3584                 /* get light */
3585                 light = *owner;
3586
3587                 /* handle negative lights */
3588                 if ( light->photons < 0.0f || light->add < 0.0f ) {
3589                         light->photons *= -1.0f;
3590                         light->add *= -1.0f;
3591                         light->flags |= LIGHT_NEGATIVE;
3592                 }
3593
3594                 /* sunlight? */
3595                 if ( light->type == EMIT_SUN ) {
3596                         /* special cased */
3597                         light->cluster = 0;
3598                         light->envelope = MAX_WORLD_COORD * 8.0f;
3599                         VectorSet( light->mins, MIN_WORLD_COORD * 8.0f, MIN_WORLD_COORD * 8.0f, MIN_WORLD_COORD * 8.0f );
3600                         VectorSet( light->maxs, MAX_WORLD_COORD * 8.0f, MAX_WORLD_COORD * 8.0f, MAX_WORLD_COORD * 8.0f );
3601                 }
3602
3603                 /* everything else */
3604                 else
3605                 {
3606                         /* get pvs cluster for light */
3607                         light->cluster = ClusterForPointExt( light->origin, LIGHT_EPSILON );
3608
3609                         /* invalid cluster? */
3610                         if ( light->cluster < 0 ) {
3611                                 /* nudge the sample point around a bit */
3612                                 for ( x = 0; x < 4; x++ )
3613                                 {
3614                                         /* two's complement 0, 1, -1, 2, -2, etc */
3615                                         x1 = ( ( x >> 1 ) ^ ( x & 1 ? -1 : 0 ) ) + ( x & 1 );
3616
3617                                         for ( y = 0; y < 4; y++ )
3618                                         {
3619                                                 y1 = ( ( y >> 1 ) ^ ( y & 1 ? -1 : 0 ) ) + ( y & 1 );
3620
3621                                                 for ( z = 0; z < 4; z++ )
3622                                                 {
3623                                                         z1 = ( ( z >> 1 ) ^ ( z & 1 ? -1 : 0 ) ) + ( z & 1 );
3624
3625                                                         /* nudge origin */
3626                                                         origin[ 0 ] = light->origin[ 0 ] + ( LIGHT_NUDGE * x1 );
3627                                                         origin[ 1 ] = light->origin[ 1 ] + ( LIGHT_NUDGE * y1 );
3628                                                         origin[ 2 ] = light->origin[ 2 ] + ( LIGHT_NUDGE * z1 );
3629
3630                                                         /* try at nudged origin */
3631                                                         light->cluster = ClusterForPointExt( origin, LIGHT_EPSILON );
3632                                                         if ( light->cluster < 0 ) {
3633                                                                 continue;
3634                                                         }
3635
3636                                                         /* set origin */
3637                                                         VectorCopy( origin, light->origin );
3638                                                 }
3639                                         }
3640                                 }
3641                         }
3642
3643                         /* only calculate for lights in pvs and outside of opaque brushes */
3644                         if ( light->cluster >= 0 ) {
3645                                 /* set light fast flag */
3646                                 if ( fastFlag ) {
3647                                         light->flags |= LIGHT_FAST_TEMP;
3648                                 }
3649                                 else{
3650                                         light->flags &= ~LIGHT_FAST_TEMP;
3651                                 }
3652                                 if ( fastpoint && ( light->type != EMIT_AREA ) ) {
3653                                         light->flags |= LIGHT_FAST_TEMP;
3654                                 }
3655                                 if ( light->si && light->si->noFast ) {
3656                                         light->flags &= ~( LIGHT_FAST | LIGHT_FAST_TEMP );
3657                                 }
3658
3659                                 /* clear light envelope */
3660                                 light->envelope = 0;
3661
3662                                 /* handle area lights */
3663                                 if ( exactPointToPolygon && light->type == EMIT_AREA && light->w != NULL ) {
3664                                         light->envelope = MAX_WORLD_COORD * 8.0f;
3665
3666                                         /* check for fast mode */
3667                                         if ( ( light->flags & LIGHT_FAST ) || ( light->flags & LIGHT_FAST_TEMP ) ) {
3668                                                 /* ugly hack to calculate extent for area lights, but only done once */
3669                                                 VectorScale( light->normal, -1.0f, dir );
3670                                                 for ( radius = 100.0f; radius < MAX_WORLD_COORD * 8.0f; radius += 10.0f )
3671                                                 {
3672                                                         float factor;
3673
3674                                                         VectorMA( light->origin, radius, light->normal, origin );
3675                                                         factor = PointToPolygonFormFactor( origin, dir, light->w );
3676                                                         if ( factor < 0.0f ) {
3677                                                                 factor *= -1.0f;
3678                                                         }
3679                                                         if ( ( factor * light->add ) <= light->falloffTolerance ) {
3680                                                                 light->envelope = radius;
3681                                                                 break;
3682                                                         }
3683                                                 }
3684                                         }
3685
3686                                         intensity = light->photons; /* hopefully not used */
3687                                 }
3688                                 else
3689                                 {
3690                                         radius = 0.0f;
3691                                         intensity = light->photons;
3692                                 }
3693
3694                                 /* other calcs */
3695                                 if ( light->envelope <= 0.0f ) {
3696                                         /* solve distance for non-distance lights */
3697                                         if ( !( light->flags & LIGHT_ATTEN_DISTANCE ) ) {
3698                                                 light->envelope = MAX_WORLD_COORD * 8.0f;
3699                                         }
3700
3701                                         else if ( ( light->flags & LIGHT_FAST ) || ( light->flags & LIGHT_FAST_TEMP ) ) {
3702                                                 /* solve distance for linear lights */
3703                                                 if ( ( light->flags & LIGHT_ATTEN_LINEAR ) ) {
3704                                                         light->envelope = ( ( intensity * linearScale ) - light->falloffTolerance ) / light->fade;
3705                                                 }
3706
3707                                                 /*
3708                                                    add = angle * light->photons * linearScale - (dist * light->fade);
3709                                                    T = (light->photons * linearScale) - (dist * light->fade);
3710                                                    T + (dist * light->fade) = (light->photons * linearScale);
3711                                                    dist * light->fade = (light->photons * linearScale) - T;
3712                                                    dist = ((light->photons * linearScale) - T) / light->fade;
3713                                                  */
3714
3715                                                 /* solve for inverse square falloff */
3716                                                 else{
3717                                                         light->envelope = sqrt( intensity / light->falloffTolerance ) + radius;
3718                                                 }
3719
3720                                                 /*
3721                                                    add = light->photons / (dist * dist);
3722                                                    T = light->photons / (dist * dist);
3723                                                    T * (dist * dist) = light->photons;
3724                                                    dist = sqrt( light->photons / T );
3725                                                  */
3726                                         }
3727                                         else
3728                                         {
3729                                                 /* solve distance for linear lights */
3730                                                 if ( ( light->flags & LIGHT_ATTEN_LINEAR ) ) {
3731                                                         light->envelope = ( intensity * linearScale ) / light->fade;
3732                                                 }
3733
3734                                                 /* can't cull these */
3735                                                 else{
3736                                                         light->envelope = MAX_WORLD_COORD * 8.0f;
3737                                                 }
3738                                         }
3739                                 }
3740
3741                                 /* chop radius against pvs */
3742                                 {
3743                                         /* clear bounds */
3744                                         ClearBounds( mins, maxs );
3745
3746                                         /* check all leaves */
3747                                         for ( i = 0; i < numBSPLeafs; i++ )
3748                                         {
3749                                                 /* get test leaf */
3750                                                 leaf = &bspLeafs[ i ];
3751
3752                                                 /* in pvs? */
3753                                                 if ( leaf->cluster < 0 ) {
3754                                                         continue;
3755                                                 }
3756                                                 if ( ClusterVisible( light->cluster, leaf->cluster ) == qfalse ) { /* ydnar: thanks Arnout for exposing my stupid error (this never failed before) */
3757                                                         continue;
3758                                                 }
3759
3760                                                 /* add this leafs bbox to the bounds */
3761                                                 VectorCopy( leaf->mins, origin );
3762                                                 AddPointToBounds( origin, mins, maxs );
3763                                                 VectorCopy( leaf->maxs, origin );
3764                                                 AddPointToBounds( origin, mins, maxs );
3765                                         }
3766
3767                                         /* test to see if bounds encompass light */
3768                                         for ( i = 0; i < 3; i++ )
3769                                         {
3770                                                 if ( mins[ i ] > light->origin[ i ] || maxs[ i ] < light->origin[ i ] ) {
3771                                                         //% Sys_FPrintf( SYS_WRN, "WARNING: Light PVS bounds (%.0f, %.0f, %.0f) -> (%.0f, %.0f, %.0f)\ndo not encompass light %d (%f, %f, %f)\n",
3772                                                         //%     mins[ 0 ], mins[ 1 ], mins[ 2 ],
3773                                                         //%     maxs[ 0 ], maxs[ 1 ], maxs[ 2 ],
3774                                                         //%     numLights, light->origin[ 0 ], light->origin[ 1 ], light->origin[ 2 ] );
3775                                                         AddPointToBounds( light->origin, mins, maxs );
3776                                                 }
3777                                         }
3778
3779                                         /* chop the bounds by a plane for area lights and spotlights */
3780                                         if ( light->type == EMIT_AREA || light->type == EMIT_SPOT ) {
3781                                                 ChopBounds( mins, maxs, light->origin, light->normal );
3782                                         }
3783
3784                                         /* copy bounds */
3785                                         VectorCopy( mins, light->mins );
3786                                         VectorCopy( maxs, light->maxs );
3787
3788                                         /* reflect bounds around light origin */
3789                                         //%     VectorMA( light->origin, -1.0f, origin, origin );
3790                                         VectorScale( light->origin, 2, origin );
3791                                         VectorSubtract( origin, maxs, origin );
3792                                         AddPointToBounds( origin, mins, maxs );
3793                                         //%     VectorMA( light->origin, -1.0f, mins, origin );
3794                                         VectorScale( light->origin, 2, origin );
3795                                         VectorSubtract( origin, mins, origin );
3796                                         AddPointToBounds( origin, mins, maxs );
3797
3798                                         /* calculate spherical bounds */
3799                                         VectorSubtract( maxs, light->origin, dir );
3800                                         radius = (float) VectorLength( dir );
3801
3802                                         /* if this radius is smaller than the envelope, then set the envelope to it */
3803                                         if ( radius < light->envelope ) {
3804                                                 light->envelope = radius;
3805                                                 //%     Sys_FPrintf( SYS_VRB, "PVS Cull (%d): culled\n", numLights );
3806                                         }
3807                                         //%     else
3808                                         //%             Sys_FPrintf( SYS_VRB, "PVS Cull (%d): failed (%8.0f > %8.0f)\n", numLights, radius, light->envelope );
3809                                 }
3810
3811                                 /* add grid/surface only check */
3812                                 if ( forGrid ) {
3813                                         if ( !( light->flags & LIGHT_GRID ) ) {
3814                                                 light->envelope = 0.0f;
3815                                         }
3816                                 }
3817                                 else
3818                                 {
3819                                         if ( !( light->flags & LIGHT_SURFACES ) ) {
3820                                                 light->envelope = 0.0f;
3821                                         }
3822                                 }
3823                         }
3824
3825                         /* culled? */
3826                         if ( light->cluster < 0 || light->envelope <= 0.0f ) {
3827                                 /* debug code */
3828                                 //%     Sys_Printf( "Culling light: Cluster: %d Envelope: %f\n", light->cluster, light->envelope );
3829
3830                                 /* delete the light */
3831                                 numCulledLights++;
3832                                 *owner = light->next;
3833                                 if ( light->w != NULL ) {
3834                                         free( light->w );
3835                                 }
3836                                 free( light );
3837                                 continue;
3838                         }
3839                 }
3840
3841                 /* square envelope */
3842                 light->envelope2 = ( light->envelope * light->envelope );
3843
3844                 /* increment light count */
3845                 numLights++;
3846
3847                 /* set next light */
3848                 owner = &( ( **owner ).next );
3849         }
3850
3851         /* bucket sort lights by style */
3852         memset( buckets, 0, sizeof( buckets ) );
3853         light2 = NULL;
3854         for ( light = lights; light != NULL; light = light2 )
3855         {
3856                 /* get next light */
3857                 light2 = light->next;
3858
3859                 /* filter into correct bucket */
3860                 light->next = buckets[ light->style ];
3861                 buckets[ light->style ] = light;
3862
3863                 /* if any styled light is present, automatically set nocollapse */
3864                 if ( light->style != LS_NORMAL ) {
3865                         noCollapse = qtrue;
3866                 }
3867         }
3868
3869         /* filter back into light list */
3870         lights = NULL;
3871         for ( i = 255; i >= 0; i-- )
3872         {
3873                 light2 = NULL;
3874                 for ( light = buckets[ i ]; light != NULL; light = light2 )
3875                 {
3876                         light2 = light->next;
3877                         light->next = lights;
3878                         lights = light;
3879                 }
3880         }
3881
3882         /* emit some statistics */
3883         Sys_Printf( "%9d total lights\n", numLights );
3884         Sys_Printf( "%9d culled lights\n", numCulledLights );
3885 }
3886
3887
3888
3889 /*
3890    CreateTraceLightsForBounds()
3891    creates a list of lights that affect the given bounding box and pvs clusters (bsp leaves)
3892  */
3893
3894 void CreateTraceLightsForBounds( vec3_t mins, vec3_t maxs, vec3_t normal, int numClusters, int *clusters, int flags, trace_t *trace ){
3895         int i;
3896         light_t     *light;
3897         vec3_t origin, dir, nullVector = { 0.0f, 0.0f, 0.0f };
3898         float radius, dist, length;
3899
3900
3901         /* potential pre-setup  */
3902         if ( numLights == 0 ) {
3903                 SetupEnvelopes( qfalse, fast );
3904         }
3905
3906         /* debug code */
3907         //% 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 ] );
3908
3909         /* allocate the light list */
3910         trace->lights = safe_malloc( sizeof( light_t* ) * ( numLights + 1 ) );
3911         trace->numLights = 0;
3912
3913         /* calculate spherical bounds */
3914         VectorAdd( mins, maxs, origin );
3915         VectorScale( origin, 0.5f, origin );
3916         VectorSubtract( maxs, origin, dir );
3917         radius = (float) VectorLength( dir );
3918
3919         /* get length of normal vector */
3920         if ( normal != NULL ) {
3921                 length = VectorLength( normal );
3922         }
3923         else
3924         {
3925                 normal = nullVector;
3926                 length = 0;
3927         }
3928
3929         /* test each light and see if it reaches the sphere */
3930         /* note: the attenuation code MUST match LightingAtSample() */
3931         for ( light = lights; light; light = light->next )
3932         {
3933                 /* check zero sized envelope */
3934                 if ( light->envelope <= 0 ) {
3935                         lightsEnvelopeCulled++;
3936                         continue;
3937                 }
3938
3939                 /* check flags */
3940                 if ( !( light->flags & flags ) ) {
3941                         continue;
3942                 }
3943
3944                 /* sunlight skips all this nonsense */
3945                 if ( light->type != EMIT_SUN ) {
3946                         /* sun only? */
3947                         if ( sunOnly ) {
3948                                 continue;
3949                         }
3950
3951                         /* check against pvs cluster */
3952                         if ( numClusters > 0 && clusters != NULL ) {
3953                                 for ( i = 0; i < numClusters; i++ )
3954                                 {
3955                                         if ( ClusterVisible( light->cluster, clusters[ i ] ) ) {
3956                                                 break;
3957                                         }
3958                                 }
3959
3960                                 /* fixme! */
3961                                 if ( i == numClusters ) {
3962                                         lightsClusterCulled++;
3963                                         continue;
3964                                 }
3965                         }
3966
3967                         /* if the light's bounding sphere intersects with the bounding sphere then this light needs to be tested */
3968                         VectorSubtract( light->origin, origin, dir );
3969                         dist = VectorLength( dir );
3970                         dist -= light->envelope;
3971                         dist -= radius;
3972                         if ( dist > 0 ) {
3973                                 lightsEnvelopeCulled++;
3974                                 continue;
3975                         }
3976
3977                         /* check bounding box against light's pvs envelope (note: this code never eliminated any lights, so disabling it) */
3978                         #if 0
3979                         skip = qfalse;
3980                         for ( i = 0; i < 3; i++ )
3981                         {
3982                                 if ( mins[ i ] > light->maxs[ i ] || maxs[ i ] < light->mins[ i ] ) {
3983                                         skip = qtrue;
3984                                 }
3985                         }
3986                         if ( skip ) {
3987                                 lightsBoundsCulled++;
3988                                 continue;
3989                         }
3990                         #endif
3991                 }
3992
3993                 /* planar surfaces (except twosided surfaces) have a couple more checks */
3994                 if ( length > 0.0f && trace->twoSided == qfalse ) {
3995                         /* lights coplanar with a surface won't light it */
3996                         if ( !( light->flags & LIGHT_TWOSIDED ) && DotProduct( light->normal, normal ) > 0.999f ) {
3997                                 lightsPlaneCulled++;
3998                                 continue;
3999                         }
4000
4001                         /* check to see if light is behind the plane */
4002                         if ( DotProduct( light->origin, normal ) - DotProduct( origin, normal ) < -1.0f ) {
4003                                 lightsPlaneCulled++;
4004                                 continue;
4005                         }
4006                 }
4007
4008                 /* add this light */
4009                 trace->lights[ trace->numLights++ ] = light;
4010         }
4011
4012         /* make last night null */
4013         trace->lights[ trace->numLights ] = NULL;
4014 }
4015
4016
4017
4018 void FreeTraceLights( trace_t *trace ){
4019         if ( trace->lights != NULL ) {
4020                 free( trace->lights );
4021         }
4022 }
4023
4024
4025
4026 /*
4027    CreateTraceLightsForSurface()
4028    creates a list of lights that can potentially affect a drawsurface
4029  */
4030
4031 void CreateTraceLightsForSurface( int num, trace_t *trace ){
4032         int i;
4033         vec3_t mins, maxs, normal;
4034         bspDrawVert_t       *dv;
4035         bspDrawSurface_t    *ds;
4036         surfaceInfo_t       *info;
4037
4038
4039         /* dummy check */
4040         if ( num < 0 ) {
4041                 return;
4042         }
4043
4044         /* get drawsurface and info */
4045         ds = &bspDrawSurfaces[ num ];
4046         info = &surfaceInfos[ num ];
4047
4048         /* get the mins/maxs for the dsurf */
4049         ClearBounds( mins, maxs );
4050         VectorCopy( bspDrawVerts[ ds->firstVert ].normal, normal );
4051         for ( i = 0; i < ds->numVerts; i++ )
4052         {
4053                 dv = &yDrawVerts[ ds->firstVert + i ];
4054                 AddPointToBounds( dv->xyz, mins, maxs );
4055                 if ( !VectorCompare( dv->normal, normal ) ) {
4056                         VectorClear( normal );
4057                 }
4058         }
4059
4060         /* create the lights for the bounding box */
4061         CreateTraceLightsForBounds( mins, maxs, normal, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ], LIGHT_SURFACES, trace );
4062 }
4063
4064 /////////////////////////////////////////////////////////////
4065
4066 #define FLOODLIGHT_CONE_ANGLE           88  /* degrees */
4067 #define FLOODLIGHT_NUM_ANGLE_STEPS      16
4068 #define FLOODLIGHT_NUM_ELEVATION_STEPS  4
4069 #define FLOODLIGHT_NUM_VECTORS          ( FLOODLIGHT_NUM_ANGLE_STEPS * FLOODLIGHT_NUM_ELEVATION_STEPS )
4070
4071 static vec3_t floodVectors[ FLOODLIGHT_NUM_VECTORS ];
4072 static int numFloodVectors = 0;
4073
4074 void SetupFloodLight( void ){
4075         int i, j;
4076         float angle, elevation, angleStep, elevationStep;
4077         const char  *value;
4078         double v1,v2,v3,v4,v5,v6;
4079
4080         /* note it */
4081         Sys_FPrintf( SYS_VRB, "--- SetupFloodLight ---\n" );
4082
4083         /* calculate angular steps */
4084         angleStep = DEG2RAD( 360.0f / FLOODLIGHT_NUM_ANGLE_STEPS );
4085         elevationStep = DEG2RAD( FLOODLIGHT_CONE_ANGLE / FLOODLIGHT_NUM_ELEVATION_STEPS );
4086
4087         /* iterate angle */
4088         angle = 0.0f;
4089         for ( i = 0, angle = 0.0f; i < FLOODLIGHT_NUM_ANGLE_STEPS; i++, angle += angleStep )
4090         {
4091                 /* iterate elevation */
4092                 for ( j = 0, elevation = elevationStep * 0.5f; j < FLOODLIGHT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep )
4093                 {
4094                         floodVectors[ numFloodVectors ][ 0 ] = sin( elevation ) * cos( angle );
4095                         floodVectors[ numFloodVectors ][ 1 ] = sin( elevation ) * sin( angle );
4096                         floodVectors[ numFloodVectors ][ 2 ] = cos( elevation );
4097                         numFloodVectors++;
4098                 }
4099         }
4100
4101         /* emit some statistics */
4102         Sys_FPrintf( SYS_VRB, "%9d numFloodVectors\n", numFloodVectors );
4103
4104         /* floodlight */
4105         value = ValueForKey( &entities[ 0 ], "_floodlight" );
4106
4107         if ( value[ 0 ] != '\0' ) {
4108                 v1 = v2 = v3 = 0;
4109                 v4 = floodlightDistance;
4110                 v5 = floodlightIntensity;
4111                 v6 = floodlightDirectionScale;
4112
4113                 sscanf( value, "%lf %lf %lf %lf %lf %lf", &v1, &v2, &v3, &v4, &v5, &v6 );
4114
4115                 floodlightRGB[0] = v1;
4116                 floodlightRGB[1] = v2;
4117                 floodlightRGB[2] = v3;
4118
4119                 if ( VectorLength( floodlightRGB ) == 0 ) {
4120                         VectorSet( floodlightRGB,0.94,0.94,1.0 );
4121                 }
4122
4123                 if ( v4 < 1 ) {
4124                         v4 = 1024;
4125                 }
4126                 if ( v5 < 1 ) {
4127                         v5 = 128;
4128                 }
4129                 if ( v6 < 0 ) {
4130                         v6 = 1;
4131                 }
4132
4133                 floodlightDistance = v4;
4134                 floodlightIntensity = v5;
4135                 floodlightDirectionScale = v6;
4136
4137                 floodlighty = qtrue;
4138                 Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
4139         }
4140         else
4141         {
4142                 VectorSet( floodlightRGB,0.94,0.94,1.0 );
4143         }
4144         if ( colorsRGB ) {
4145                 floodlightRGB[0] = Image_LinearFloatFromsRGBFloat( floodlightRGB[0] );
4146                 floodlightRGB[1] = Image_LinearFloatFromsRGBFloat( floodlightRGB[1] );
4147                 floodlightRGB[2] = Image_LinearFloatFromsRGBFloat( floodlightRGB[2] );
4148         }
4149         ColorNormalize( floodlightRGB,floodlightRGB );
4150 }
4151
4152 /*
4153    FloodLightForSample()
4154    calculates floodlight value for a given sample
4155    once again, kudos to the dirtmapping coder
4156  */
4157
4158 float FloodLightForSample( trace_t *trace, float floodLightDistance, qboolean floodLightLowQuality ){
4159         int i;
4160         float d;
4161         float contribution;
4162         int sub = 0;
4163         float gatherLight, outLight;
4164         vec3_t normal, worldUp, myUp, myRt, direction, displacement;
4165         float dd;
4166         int vecs = 0;
4167
4168         gatherLight = 0;
4169         /* dummy check */
4170         //if( !dirty )
4171         //      return 1.0f;
4172         if ( trace == NULL || trace->cluster < 0 ) {
4173                 return 0.0f;
4174         }
4175
4176
4177         /* setup */
4178         dd = floodLightDistance;
4179         VectorCopy( trace->normal, normal );
4180
4181         /* check if the normal is aligned to the world-up */
4182         if ( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f && ( normal[ 2 ] == 1.0f || normal[ 2 ] == -1.0f ) ) {
4183                 if ( normal[ 2 ] == 1.0f ) {
4184                         VectorSet( myRt, 1.0f, 0.0f, 0.0f );
4185                         VectorSet( myUp, 0.0f, 1.0f, 0.0f );
4186                 }
4187                 else if ( normal[ 2 ] == -1.0f ) {
4188                         VectorSet( myRt, -1.0f, 0.0f, 0.0f );
4189                         VectorSet( myUp,  0.0f, 1.0f, 0.0f );
4190                 }
4191         }
4192         else
4193         {
4194                 VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
4195                 CrossProduct( normal, worldUp, myRt );
4196                 VectorNormalize( myRt, myRt );
4197                 CrossProduct( myRt, normal, myUp );
4198                 VectorNormalize( myUp, myUp );
4199         }
4200
4201         /* vortex: optimise floodLightLowQuality a bit */
4202         if ( floodLightLowQuality == qtrue ) {
4203                 /* iterate through ordered vectors */
4204                 for ( i = 0; i < numFloodVectors; i++ )
4205                         if ( rand() % 10 != 0 ) {
4206                                 continue;
4207                         }
4208         }
4209         else
4210         {
4211                 /* iterate through ordered vectors */
4212                 for ( i = 0; i < numFloodVectors; i++ )
4213                 {
4214                         vecs++;
4215
4216                         /* transform vector into tangent space */
4217                         direction[ 0 ] = myRt[ 0 ] * floodVectors[ i ][ 0 ] + myUp[ 0 ] * floodVectors[ i ][ 1 ] + normal[ 0 ] * floodVectors[ i ][ 2 ];
4218                         direction[ 1 ] = myRt[ 1 ] * floodVectors[ i ][ 0 ] + myUp[ 1 ] * floodVectors[ i ][ 1 ] + normal[ 1 ] * floodVectors[ i ][ 2 ];
4219                         direction[ 2 ] = myRt[ 2 ] * floodVectors[ i ][ 0 ] + myUp[ 2 ] * floodVectors[ i ][ 1 ] + normal[ 2 ] * floodVectors[ i ][ 2 ];
4220
4221                         /* set endpoint */
4222                         VectorMA( trace->origin, dd, direction, trace->end );
4223
4224                         //VectorMA( trace->origin, 1, direction, trace->origin );
4225
4226                         SetupTrace( trace );
4227                         VectorSet(trace->color, 1.0f, 1.0f, 1.0f);
4228                         /* trace */
4229                         TraceLine( trace );
4230                         contribution = 1;
4231
4232                         if ( trace->compileFlags & C_SKY || trace->compileFlags & C_TRANSLUCENT ) {
4233                                 contribution = 1.0f;
4234                         }
4235                         else if ( trace->opaque ) {
4236                                 VectorSubtract( trace->hit, trace->origin, displacement );
4237                                 d = VectorLength( displacement );
4238
4239                                 // d=trace->distance;
4240                                 //if (d>256) gatherDirt+=1;
4241                                 contribution = d / dd;
4242                                 if ( contribution > 1 ) {
4243                                         contribution = 1.0f;
4244                                 }
4245
4246                                 //gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
4247                         }
4248
4249                         gatherLight += contribution;
4250                 }
4251         }
4252
4253         /* early out */
4254         if ( gatherLight <= 0.0f ) {
4255                 return 0.0f;
4256         }
4257
4258         sub = vecs;
4259
4260         if ( sub < 1 ) {
4261                 sub = 1;
4262         }
4263         gatherLight /= ( sub );
4264
4265         outLight = gatherLight;
4266         if ( outLight > 1.0f ) {
4267                 outLight = 1.0f;
4268         }
4269
4270         /* return to sender */
4271         return outLight;
4272 }
4273
4274 /*
4275    FloodLightRawLightmap
4276    lighttracer style ambient occlusion light hack.
4277    Kudos to the dirtmapping author for most of this source.
4278    VorteX: modified to floodlight up custom surfaces (q3map_floodLight)
4279    VorteX: fixed problems with deluxemapping
4280  */
4281
4282 // floodlight pass on a lightmap
4283 void FloodLightRawLightmapPass( rawLightmap_t *lm, vec3_t lmFloodLightRGB, float lmFloodLightIntensity, float lmFloodLightDistance, qboolean lmFloodLightLowQuality, float floodlightDirectionScale ){
4284         int i, x, y, *cluster;
4285         float               *origin, *normal, *floodlight, floodLightAmount;
4286         surfaceInfo_t       *info;
4287         trace_t trace;
4288         // int sx, sy;
4289         // float samples, average, *floodlight2;
4290
4291         memset( &trace,0,sizeof( trace_t ) );
4292
4293         /* setup trace */
4294         trace.testOcclusion = qtrue;
4295         trace.forceSunlight = qfalse;
4296         trace.twoSided = qtrue;
4297         trace.recvShadows = lm->recvShadows;
4298         trace.numSurfaces = lm->numLightSurfaces;
4299         trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
4300         trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
4301         trace.testAll = qfalse;
4302         trace.distance = 1024;
4303
4304         /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
4305         //trace.twoSided = qfalse;
4306         for ( i = 0; i < trace.numSurfaces; i++ )
4307         {
4308                 /* get surface */
4309                 info = &surfaceInfos[ trace.surfaces[ i ] ];
4310
4311                 /* check twosidedness */
4312                 if ( info->si->twoSided ) {
4313                         trace.twoSided = qtrue;
4314                         break;
4315                 }
4316         }
4317
4318         /* gather floodlight */
4319         for ( y = 0; y < lm->sh; y++ )
4320         {
4321                 for ( x = 0; x < lm->sw; x++ )
4322                 {
4323                         /* get luxel */
4324                         cluster = SUPER_CLUSTER( x, y );
4325                         origin = SUPER_ORIGIN( x, y );
4326                         normal = SUPER_NORMAL( x, y );
4327                         floodlight = SUPER_FLOODLIGHT( x, y );
4328
4329                         /* set default dirt */
4330                         *floodlight = 0.0f;
4331
4332                         /* only look at mapped luxels */
4333                         if ( *cluster < 0 ) {
4334                                 continue;
4335                         }
4336
4337                         /* copy to trace */
4338                         trace.cluster = *cluster;
4339                         VectorCopy( origin, trace.origin );
4340                         VectorCopy( normal, trace.normal );
4341
4342                         /* get floodlight */
4343                         floodLightAmount = FloodLightForSample( &trace, lmFloodLightDistance, lmFloodLightLowQuality ) * lmFloodLightIntensity;
4344
4345                         /* add floodlight */
4346                         floodlight[0] += lmFloodLightRGB[0] * floodLightAmount;
4347                         floodlight[1] += lmFloodLightRGB[1] * floodLightAmount;
4348                         floodlight[2] += lmFloodLightRGB[2] * floodLightAmount;
4349                         floodlight[3] += floodlightDirectionScale;
4350                 }
4351         }
4352
4353         /* testing no filtering */
4354         return;
4355
4356 #if 0
4357
4358         /* filter "dirt" */
4359         for ( y = 0; y < lm->sh; y++ )
4360         {
4361                 for ( x = 0; x < lm->sw; x++ )
4362                 {
4363                         /* get luxel */
4364                         cluster = SUPER_CLUSTER( x, y );
4365                         floodlight = SUPER_FLOODLIGHT( x, y );
4366
4367                         /* filter dirt by adjacency to unmapped luxels */
4368                         average = *floodlight;
4369                         samples = 1.0f;
4370                         for ( sy = ( y - 1 ); sy <= ( y + 1 ); sy++ )
4371                         {
4372                                 if ( sy < 0 || sy >= lm->sh ) {
4373                                         continue;
4374                                 }
4375
4376                                 for ( sx = ( x - 1 ); sx <= ( x + 1 ); sx++ )
4377                                 {
4378                                         if ( sx < 0 || sx >= lm->sw || ( sx == x && sy == y ) ) {
4379                                                 continue;
4380                                         }
4381
4382                                         /* get neighboring luxel */
4383                                         cluster = SUPER_CLUSTER( sx, sy );
4384                                         floodlight2 = SUPER_FLOODLIGHT( sx, sy );
4385                                         if ( *cluster < 0 || *floodlight2 <= 0.0f ) {
4386                                                 continue;
4387                                         }
4388
4389                                         /* add it */
4390                                         average += *floodlight2;
4391                                         samples += 1.0f;
4392                                 }
4393
4394                                 /* bail */
4395                                 if ( samples <= 0.0f ) {
4396                                         break;
4397                                 }
4398                         }
4399
4400                         /* bail */
4401                         if ( samples <= 0.0f ) {
4402                                 continue;
4403                         }
4404
4405                         /* scale dirt */
4406                         *floodlight = average / samples;
4407                 }
4408         }
4409 #endif
4410 }
4411
4412 void FloodLightRawLightmap( int rawLightmapNum ){
4413         rawLightmap_t       *lm;
4414
4415         /* bail if this number exceeds the number of raw lightmaps */
4416         if ( rawLightmapNum >= numRawLightmaps ) {
4417                 return;
4418         }
4419         /* get lightmap */
4420         lm = &rawLightmaps[ rawLightmapNum ];
4421
4422         /* global pass */
4423         if ( floodlighty && floodlightIntensity ) {
4424                 FloodLightRawLightmapPass( lm, floodlightRGB, floodlightIntensity, floodlightDistance, floodlight_lowquality, floodlightDirectionScale );
4425         }
4426
4427         /* custom pass */
4428         if ( lm->floodlightIntensity ) {
4429                 FloodLightRawLightmapPass( lm, lm->floodlightRGB, lm->floodlightIntensity, lm->floodlightDistance, qfalse, lm->floodlightDirectionScale );
4430                 numSurfacesFloodlighten += 1;
4431         }
4432 }
4433
4434 void FloodlightRawLightmaps(){
4435         Sys_Printf( "--- FloodlightRawLightmap ---\n" );
4436         numSurfacesFloodlighten = 0;
4437         RunThreadsOnIndividual( numRawLightmaps, qtrue, FloodLightRawLightmap );
4438         Sys_Printf( "%9d custom lightmaps floodlighted\n", numSurfacesFloodlighten );
4439 }
4440
4441 /*
4442    FloodLightIlluminate()
4443    illuminate floodlight into lightmap luxels
4444  */
4445
4446 void FloodlightIlluminateLightmap( rawLightmap_t *lm ){
4447         float               *luxel, *floodlight, *deluxel, *normal;
4448         int                 *cluster;
4449         float brightness;
4450         int x, y, lightmapNum;
4451
4452         /* walk lightmaps */
4453         for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
4454         {
4455                 /* early out */
4456                 if ( lm->superLuxels[ lightmapNum ] == NULL ) {
4457                         continue;
4458                 }
4459
4460                 /* apply floodlight to each luxel */
4461                 for ( y = 0; y < lm->sh; y++ )
4462                 {
4463                         for ( x = 0; x < lm->sw; x++ )
4464                         {
4465                                 /* get floodlight */
4466                                 floodlight = SUPER_FLOODLIGHT( x, y );
4467                                 if ( !floodlight[0] && !floodlight[1] && !floodlight[2] ) {
4468                                         continue;
4469                                 }
4470
4471                                 /* get cluster */
4472                                 cluster = SUPER_CLUSTER( x, y );
4473
4474                                 /* only process mapped luxels */
4475                                 if ( *cluster < 0 ) {
4476                                         continue;
4477                                 }
4478
4479                                 /* get particulars */
4480                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
4481                                 deluxel = SUPER_DELUXEL( x, y );
4482
4483                                 /* add to lightmap */
4484                                 luxel[0] += floodlight[0];
4485                                 luxel[1] += floodlight[1];
4486                                 luxel[2] += floodlight[2];
4487
4488                                 if ( luxel[3] == 0 ) {
4489                                         luxel[3] = 1;
4490                                 }
4491
4492                                 /* add to deluxemap */
4493                                 if ( deluxemap && floodlight[3] > 0 ) {
4494                                         vec3_t lightvector;
4495
4496                                         normal = SUPER_NORMAL( x, y );
4497                                         brightness = RGBTOGRAY( floodlight ) * ( 1.0f / 255.0f ) * floodlight[3];
4498
4499                                         // use AT LEAST this amount of contribution from ambient for the deluxemap, fixes points that receive ZERO light
4500                                         if ( brightness < 0.00390625f ) {
4501                                                 brightness = 0.00390625f;
4502                                         }
4503
4504                                         VectorScale( normal, brightness, lightvector );
4505                                         VectorAdd( deluxel, lightvector, deluxel );
4506                                 }
4507                         }
4508                 }
4509         }
4510 }