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