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