]> git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/light_ydnar.c
c024dd3eb39fe4597f88b2c7b45b16d507ae0e46
[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[ 4 ];
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         bspBrush_t      *brush;
3176         bspBrushSide_t  *side;
3177         bspShader_t     *shader;
3178         shaderInfo_t    *si;
3179
3180
3181         /* note it */
3182         Sys_FPrintf( SYS_VRB, "--- SetupBrushes ---\n" );
3183
3184         /* allocate */
3185         if ( opaqueBrushes == NULL ) {
3186                 opaqueBrushes = safe_malloc( numBSPBrushes / 8 + 1 );
3187         }
3188
3189         /* clear */
3190         memset( opaqueBrushes, 0, numBSPBrushes / 8 + 1 );
3191         numOpaqueBrushes = 0;
3192
3193         /* walk the list of worldspawn brushes */
3194         for ( i = 0; i < bspModels[ 0 ].numBSPBrushes; i++ )
3195         {
3196                 /* get brush */
3197                 b = bspModels[ 0 ].firstBSPBrush + i;
3198                 brush = &bspBrushes[ b ];
3199
3200                 /* check all sides */
3201                 compileFlags = 0;
3202                 allCompileFlags = ~( 0u );
3203                 for ( j = 0; j < brush->numSides; j++ )
3204                 {
3205                         /* do bsp shader calculations */
3206                         side = &bspBrushSides[ brush->firstSide + j ];
3207                         shader = &bspShaders[ side->shaderNum ];
3208
3209                         /* get shader info */
3210                         si = ShaderInfoForShaderNull( shader->shader );
3211                         if ( si == NULL ) {
3212                                 continue;
3213                         }
3214
3215                         /* or together compile flags */
3216                         compileFlags |= si->compileFlags;
3217                         allCompileFlags &= si->compileFlags;
3218                 }
3219
3220                 /* determine if this brush is opaque to light */
3221                 if ( ( compileFlags & mask_any ) == test_any && ( allCompileFlags & mask_all ) == test_all ) {
3222                         opaqueBrushes[ b >> 3 ] |= ( 1 << ( b & 7 ) );
3223                         numOpaqueBrushes++;
3224                         maxOpaqueBrush = i;
3225                 }
3226         }
3227
3228         /* emit some statistics */
3229         Sys_FPrintf( SYS_VRB, "%9d opaque brushes\n", numOpaqueBrushes );
3230 }
3231 void SetupBrushes( void ){
3232         SetupBrushesFlags( C_TRANSLUCENT, 0, 0, 0 );
3233 }
3234
3235
3236
3237 /*
3238    ClusterVisible()
3239    determines if two clusters are visible to each other using the PVS
3240  */
3241
3242 qboolean ClusterVisible( int a, int b ){
3243         int leafBytes;
3244         byte        *pvs;
3245
3246
3247         /* dummy check */
3248         if ( a < 0 || b < 0 ) {
3249                 return qfalse;
3250         }
3251
3252         /* early out */
3253         if ( a == b ) {
3254                 return qtrue;
3255         }
3256
3257         /* not vised? */
3258         if ( numBSPVisBytes <= 8 ) {
3259                 return qtrue;
3260         }
3261
3262         /* get pvs data */
3263         /* portalClusters = ((int *) bspVisBytes)[ 0 ]; */
3264         leafBytes = ( (int*) bspVisBytes )[ 1 ];
3265         pvs = bspVisBytes + VIS_HEADER_SIZE + ( a * leafBytes );
3266
3267         /* check */
3268         if ( ( pvs[ b >> 3 ] & ( 1 << ( b & 7 ) ) ) ) {
3269                 return qtrue;
3270         }
3271         return qfalse;
3272 }
3273
3274
3275
3276 /*
3277    PointInLeafNum_r()
3278    borrowed from vlight.c
3279  */
3280
3281 int PointInLeafNum_r( vec3_t point, int nodenum ){
3282         int leafnum;
3283         vec_t dist;
3284         bspNode_t       *node;
3285         bspPlane_t  *plane;
3286
3287
3288         while ( nodenum >= 0 )
3289         {
3290                 node = &bspNodes[ nodenum ];
3291                 plane = &bspPlanes[ node->planeNum ];
3292                 dist = DotProduct( point, plane->normal ) - plane->dist;
3293                 if ( dist > 0.1 ) {
3294                         nodenum = node->children[ 0 ];
3295                 }
3296                 else if ( dist < -0.1 ) {
3297                         nodenum = node->children[ 1 ];
3298                 }
3299                 else
3300                 {
3301                         leafnum = PointInLeafNum_r( point, node->children[ 0 ] );
3302                         if ( bspLeafs[ leafnum ].cluster != -1 ) {
3303                                 return leafnum;
3304                         }
3305                         nodenum = node->children[ 1 ];
3306                 }
3307         }
3308
3309         leafnum = -nodenum - 1;
3310         return leafnum;
3311 }
3312
3313
3314
3315 /*
3316    PointInLeafnum()
3317    borrowed from vlight.c
3318  */
3319
3320 int PointInLeafNum( vec3_t point ){
3321         return PointInLeafNum_r( point, 0 );
3322 }
3323
3324
3325
3326 /*
3327    ClusterVisibleToPoint() - ydnar
3328    returns qtrue if point can "see" cluster
3329  */
3330
3331 qboolean ClusterVisibleToPoint( vec3_t point, int cluster ){
3332         int pointCluster;
3333
3334
3335         /* get leafNum for point */
3336         pointCluster = ClusterForPoint( point );
3337         if ( pointCluster < 0 ) {
3338                 return qfalse;
3339         }
3340
3341         /* check pvs */
3342         return ClusterVisible( pointCluster, cluster );
3343 }
3344
3345
3346
3347 /*
3348    ClusterForPoint() - ydnar
3349    returns the pvs cluster for point
3350  */
3351
3352 int ClusterForPoint( vec3_t point ){
3353         int leafNum;
3354
3355
3356         /* get leafNum for point */
3357         leafNum = PointInLeafNum( point );
3358         if ( leafNum < 0 ) {
3359                 return -1;
3360         }
3361
3362         /* return the cluster */
3363         return bspLeafs[ leafNum ].cluster;
3364 }
3365
3366
3367
3368 /*
3369    ClusterForPointExt() - ydnar
3370    also takes brushes into account for occlusion testing
3371  */
3372
3373 int ClusterForPointExt( vec3_t point, float epsilon ){
3374         int i, j, b, leafNum, cluster;
3375         float dot;
3376         qboolean inside;
3377         int             *brushes, numBSPBrushes;
3378         bspLeaf_t       *leaf;
3379         bspBrush_t      *brush;
3380         bspPlane_t      *plane;
3381
3382
3383         /* get leaf for point */
3384         leafNum = PointInLeafNum( point );
3385         if ( leafNum < 0 ) {
3386                 return -1;
3387         }
3388         leaf = &bspLeafs[ leafNum ];
3389
3390         /* get the cluster */
3391         cluster = leaf->cluster;
3392         if ( cluster < 0 ) {
3393                 return -1;
3394         }
3395
3396         /* transparent leaf, so check point against all brushes in the leaf */
3397         brushes = &bspLeafBrushes[ leaf->firstBSPLeafBrush ];
3398         numBSPBrushes = leaf->numBSPLeafBrushes;
3399         for ( i = 0; i < numBSPBrushes; i++ )
3400         {
3401                 /* get parts */
3402                 b = brushes[ i ];
3403                 if ( b > maxOpaqueBrush ) {
3404                         continue;
3405                 }
3406                 brush = &bspBrushes[ b ];
3407                 if ( !( opaqueBrushes[ b >> 3 ] & ( 1 << ( b & 7 ) ) ) ) {
3408                         continue;
3409                 }
3410
3411                 /* check point against all planes */
3412                 inside = qtrue;
3413                 for ( j = 0; j < brush->numSides && inside; j++ )
3414                 {
3415                         plane = &bspPlanes[ bspBrushSides[ brush->firstSide + j ].planeNum ];
3416                         dot = DotProduct( point, plane->normal );
3417                         dot -= plane->dist;
3418                         if ( dot > epsilon ) {
3419                                 inside = qfalse;
3420                         }
3421                 }
3422
3423                 /* if inside, return bogus cluster */
3424                 if ( inside ) {
3425                         return -1 - b;
3426                 }
3427         }
3428
3429         /* if the point made it this far, it's not inside any opaque brushes */
3430         return cluster;
3431 }
3432
3433
3434
3435 /*
3436    ClusterForPointExtFilter() - ydnar
3437    adds cluster checking against a list of known valid clusters
3438  */
3439
3440 int ClusterForPointExtFilter( vec3_t point, float epsilon, int numClusters, int *clusters ){
3441         int i, cluster;
3442
3443
3444         /* get cluster for point */
3445         cluster = ClusterForPointExt( point, epsilon );
3446
3447         /* check if filtering is necessary */
3448         if ( cluster < 0 || numClusters <= 0 || clusters == NULL ) {
3449                 return cluster;
3450         }
3451
3452         /* filter */
3453         for ( i = 0; i < numClusters; i++ )
3454         {
3455                 if ( cluster == clusters[ i ] || ClusterVisible( cluster, clusters[ i ] ) ) {
3456                         return cluster;
3457                 }
3458         }
3459
3460         /* failed */
3461         return -1;
3462 }
3463
3464
3465
3466 /*
3467    ShaderForPointInLeaf() - ydnar
3468    checks a point against all brushes in a leaf, returning the shader of the brush
3469    also sets the cumulative surface and content flags for the brush hit
3470  */
3471
3472 int ShaderForPointInLeaf( vec3_t point, int leafNum, float epsilon, int wantContentFlags, int wantSurfaceFlags, int *contentFlags, int *surfaceFlags ){
3473         int i, j;
3474         float dot;
3475         qboolean inside;
3476         int             *brushes, numBSPBrushes;
3477         bspLeaf_t           *leaf;
3478         bspBrush_t      *brush;
3479         bspBrushSide_t  *side;
3480         bspPlane_t      *plane;
3481         bspShader_t     *shader;
3482         int allSurfaceFlags, allContentFlags;
3483
3484
3485         /* clear things out first */
3486         *surfaceFlags = 0;
3487         *contentFlags = 0;
3488
3489         /* get leaf */
3490         if ( leafNum < 0 ) {
3491                 return -1;
3492         }
3493         leaf = &bspLeafs[ leafNum ];
3494
3495         /* transparent leaf, so check point against all brushes in the leaf */
3496         brushes = &bspLeafBrushes[ leaf->firstBSPLeafBrush ];
3497         numBSPBrushes = leaf->numBSPLeafBrushes;
3498         for ( i = 0; i < numBSPBrushes; i++ )
3499         {
3500                 /* get parts */
3501                 brush = &bspBrushes[ brushes[ i ] ];
3502
3503                 /* check point against all planes */
3504                 inside = qtrue;
3505                 allSurfaceFlags = 0;
3506                 allContentFlags = 0;
3507                 for ( j = 0; j < brush->numSides && inside; j++ )
3508                 {
3509                         side = &bspBrushSides[ brush->firstSide + j ];
3510                         plane = &bspPlanes[ side->planeNum ];
3511                         dot = DotProduct( point, plane->normal );
3512                         dot -= plane->dist;
3513                         if ( dot > epsilon ) {
3514                                 inside = qfalse;
3515                         }
3516                         else
3517                         {
3518                                 shader = &bspShaders[ side->shaderNum ];
3519                                 allSurfaceFlags |= shader->surfaceFlags;
3520                                 allContentFlags |= shader->contentFlags;
3521                         }
3522                 }
3523
3524                 /* handle if inside */
3525                 if ( inside ) {
3526                         /* if there are desired flags, check for same and continue if they aren't matched */
3527                         if ( wantContentFlags && !( wantContentFlags & allContentFlags ) ) {
3528                                 continue;
3529                         }
3530                         if ( wantSurfaceFlags && !( wantSurfaceFlags & allSurfaceFlags ) ) {
3531                                 continue;
3532                         }
3533
3534                         /* store the cumulative flags and return the brush shader (which is mostly useless) */
3535                         *surfaceFlags = allSurfaceFlags;
3536                         *contentFlags = allContentFlags;
3537                         return brush->shaderNum;
3538                 }
3539         }
3540
3541         /* if the point made it this far, it's not inside any brushes */
3542         return -1;
3543 }
3544
3545
3546
3547 /*
3548    ChopBounds()
3549    chops a bounding box by the plane defined by origin and normal
3550    returns qfalse if the bounds is entirely clipped away
3551
3552    this is not exactly the fastest way to do this...
3553  */
3554
3555 qboolean ChopBounds( vec3_t mins, vec3_t maxs, vec3_t origin, vec3_t normal ){
3556         /* FIXME: rewrite this so it doesn't use bloody brushes */
3557         return qtrue;
3558 }
3559
3560
3561
3562 /*
3563    SetupEnvelopes()
3564    calculates each light's effective envelope,
3565    taking into account brightness, type, and pvs.
3566  */
3567
3568 #define LIGHT_EPSILON   0.125f
3569 #define LIGHT_NUDGE     2.0f
3570
3571 void SetupEnvelopes( qboolean forGrid, qboolean fastFlag ){
3572         int i, x, y, z, x1, y1, z1;
3573         light_t     *light, *light2, **owner;
3574         bspLeaf_t   *leaf;
3575         vec3_t origin, dir, mins, maxs;
3576         float radius, intensity;
3577         light_t     *buckets[ 256 ];
3578
3579
3580         /* early out for weird cases where there are no lights */
3581         if ( lights == NULL ) {
3582                 return;
3583         }
3584
3585         /* note it */
3586         Sys_FPrintf( SYS_VRB, "--- SetupEnvelopes%s ---\n", fastFlag ? " (fast)" : "" );
3587
3588         /* count lights */
3589         numLights = 0;
3590         numCulledLights = 0;
3591         owner = &lights;
3592         while ( *owner != NULL )
3593         {
3594                 /* get light */
3595                 light = *owner;
3596
3597                 /* handle negative lights */
3598                 if ( light->photons < 0.0f || light->add < 0.0f ) {
3599                         light->photons *= -1.0f;
3600                         light->add *= -1.0f;
3601                         light->flags |= LIGHT_NEGATIVE;
3602                 }
3603
3604                 /* sunlight? */
3605                 if ( light->type == EMIT_SUN ) {
3606                         /* special cased */
3607                         light->cluster = 0;
3608                         light->envelope = MAX_WORLD_COORD * 8.0f;
3609                         VectorSet( light->mins, MIN_WORLD_COORD * 8.0f, MIN_WORLD_COORD * 8.0f, MIN_WORLD_COORD * 8.0f );
3610                         VectorSet( light->maxs, MAX_WORLD_COORD * 8.0f, MAX_WORLD_COORD * 8.0f, MAX_WORLD_COORD * 8.0f );
3611                 }
3612
3613                 /* everything else */
3614                 else
3615                 {
3616                         /* get pvs cluster for light */
3617                         light->cluster = ClusterForPointExt( light->origin, LIGHT_EPSILON );
3618
3619                         /* invalid cluster? */
3620                         if ( light->cluster < 0 ) {
3621                                 /* nudge the sample point around a bit */
3622                                 for ( x = 0; x < 4; x++ )
3623                                 {
3624                                         /* two's complement 0, 1, -1, 2, -2, etc */
3625                                         x1 = ( ( x >> 1 ) ^ ( x & 1 ? -1 : 0 ) ) + ( x & 1 );
3626
3627                                         for ( y = 0; y < 4; y++ )
3628                                         {
3629                                                 y1 = ( ( y >> 1 ) ^ ( y & 1 ? -1 : 0 ) ) + ( y & 1 );
3630
3631                                                 for ( z = 0; z < 4; z++ )
3632                                                 {
3633                                                         z1 = ( ( z >> 1 ) ^ ( z & 1 ? -1 : 0 ) ) + ( z & 1 );
3634
3635                                                         /* nudge origin */
3636                                                         origin[ 0 ] = light->origin[ 0 ] + ( LIGHT_NUDGE * x1 );
3637                                                         origin[ 1 ] = light->origin[ 1 ] + ( LIGHT_NUDGE * y1 );
3638                                                         origin[ 2 ] = light->origin[ 2 ] + ( LIGHT_NUDGE * z1 );
3639
3640                                                         /* try at nudged origin */
3641                                                         light->cluster = ClusterForPointExt( origin, LIGHT_EPSILON );
3642                                                         if ( light->cluster < 0 ) {
3643                                                                 continue;
3644                                                         }
3645
3646                                                         /* set origin */
3647                                                         VectorCopy( origin, light->origin );
3648                                                 }
3649                                         }
3650                                 }
3651                         }
3652
3653                         /* only calculate for lights in pvs and outside of opaque brushes */
3654                         if ( light->cluster >= 0 ) {
3655                                 /* set light fast flag */
3656                                 if ( fastFlag ) {
3657                                         light->flags |= LIGHT_FAST_TEMP;
3658                                 }
3659                                 else{
3660                                         light->flags &= ~LIGHT_FAST_TEMP;
3661                                 }
3662                                 if ( fastpoint && ( light->type != EMIT_AREA ) ) {
3663                                         light->flags |= LIGHT_FAST_TEMP;
3664                                 }
3665                                 if ( light->si && light->si->noFast ) {
3666                                         light->flags &= ~( LIGHT_FAST | LIGHT_FAST_TEMP );
3667                                 }
3668
3669                                 /* clear light envelope */
3670                                 light->envelope = 0;
3671
3672                                 /* handle area lights */
3673                                 if ( exactPointToPolygon && light->type == EMIT_AREA && light->w != NULL ) {
3674                                         light->envelope = MAX_WORLD_COORD * 8.0f;
3675
3676                                         /* check for fast mode */
3677                                         if ( ( light->flags & LIGHT_FAST ) || ( light->flags & LIGHT_FAST_TEMP ) ) {
3678                                                 /* ugly hack to calculate extent for area lights, but only done once */
3679                                                 VectorScale( light->normal, -1.0f, dir );
3680                                                 for ( radius = 100.0f; radius < MAX_WORLD_COORD * 8.0f; radius += 10.0f )
3681                                                 {
3682                                                         float factor;
3683
3684                                                         VectorMA( light->origin, radius, light->normal, origin );
3685                                                         factor = PointToPolygonFormFactor( origin, dir, light->w );
3686                                                         if ( factor < 0.0f ) {
3687                                                                 factor *= -1.0f;
3688                                                         }
3689                                                         if ( ( factor * light->add ) <= light->falloffTolerance ) {
3690                                                                 light->envelope = radius;
3691                                                                 break;
3692                                                         }
3693                                                 }
3694                                         }
3695
3696                                         intensity = light->photons; /* hopefully not used */
3697                                 }
3698                                 else
3699                                 {
3700                                         radius = 0.0f;
3701                                         intensity = light->photons;
3702                                 }
3703
3704                                 /* other calcs */
3705                                 if ( light->envelope <= 0.0f ) {
3706                                         /* solve distance for non-distance lights */
3707                                         if ( !( light->flags & LIGHT_ATTEN_DISTANCE ) ) {
3708                                                 light->envelope = MAX_WORLD_COORD * 8.0f;
3709                                         }
3710
3711                                         else if ( ( light->flags & LIGHT_FAST ) || ( light->flags & LIGHT_FAST_TEMP ) ) {
3712                                                 /* solve distance for linear lights */
3713                                                 if ( ( light->flags & LIGHT_ATTEN_LINEAR ) ) {
3714                                                         light->envelope = ( ( intensity * linearScale ) - light->falloffTolerance ) / light->fade;
3715                                                 }
3716
3717                                                 /*
3718                                                    add = angle * light->photons * linearScale - (dist * light->fade);
3719                                                    T = (light->photons * linearScale) - (dist * light->fade);
3720                                                    T + (dist * light->fade) = (light->photons * linearScale);
3721                                                    dist * light->fade = (light->photons * linearScale) - T;
3722                                                    dist = ((light->photons * linearScale) - T) / light->fade;
3723                                                  */
3724
3725                                                 /* solve for inverse square falloff */
3726                                                 else{
3727                                                         light->envelope = sqrt( intensity / light->falloffTolerance ) + radius;
3728                                                 }
3729
3730                                                 /*
3731                                                    add = light->photons / (dist * dist);
3732                                                    T = light->photons / (dist * dist);
3733                                                    T * (dist * dist) = light->photons;
3734                                                    dist = sqrt( light->photons / T );
3735                                                  */
3736                                         }
3737                                         else
3738                                         {
3739                                                 /* solve distance for linear lights */
3740                                                 if ( ( light->flags & LIGHT_ATTEN_LINEAR ) ) {
3741                                                         light->envelope = ( intensity * linearScale ) / light->fade;
3742                                                 }
3743
3744                                                 /* can't cull these */
3745                                                 else{
3746                                                         light->envelope = MAX_WORLD_COORD * 8.0f;
3747                                                 }
3748                                         }
3749                                 }
3750
3751                                 /* chop radius against pvs */
3752                                 {
3753                                         /* clear bounds */
3754                                         ClearBounds( mins, maxs );
3755
3756                                         /* check all leaves */
3757                                         for ( i = 0; i < numBSPLeafs; i++ )
3758                                         {
3759                                                 /* get test leaf */
3760                                                 leaf = &bspLeafs[ i ];
3761
3762                                                 /* in pvs? */
3763                                                 if ( leaf->cluster < 0 ) {
3764                                                         continue;
3765                                                 }
3766                                                 if ( ClusterVisible( light->cluster, leaf->cluster ) == qfalse ) { /* ydnar: thanks Arnout for exposing my stupid error (this never failed before) */
3767                                                         continue;
3768                                                 }
3769
3770                                                 /* add this leafs bbox to the bounds */
3771                                                 VectorCopy( leaf->mins, origin );
3772                                                 AddPointToBounds( origin, mins, maxs );
3773                                                 VectorCopy( leaf->maxs, origin );
3774                                                 AddPointToBounds( origin, mins, maxs );
3775                                         }
3776
3777                                         /* test to see if bounds encompass light */
3778                                         for ( i = 0; i < 3; i++ )
3779                                         {
3780                                                 if ( mins[ i ] > light->origin[ i ] || maxs[ i ] < light->origin[ i ] ) {
3781                                                         //% Sys_FPrintf( SYS_WRN, "WARNING: Light PVS bounds (%.0f, %.0f, %.0f) -> (%.0f, %.0f, %.0f)\ndo not encompass light %d (%f, %f, %f)\n",
3782                                                         //%     mins[ 0 ], mins[ 1 ], mins[ 2 ],
3783                                                         //%     maxs[ 0 ], maxs[ 1 ], maxs[ 2 ],
3784                                                         //%     numLights, light->origin[ 0 ], light->origin[ 1 ], light->origin[ 2 ] );
3785                                                         AddPointToBounds( light->origin, mins, maxs );
3786                                                 }
3787                                         }
3788
3789                                         /* chop the bounds by a plane for area lights and spotlights */
3790                                         if ( light->type == EMIT_AREA || light->type == EMIT_SPOT ) {
3791                                                 ChopBounds( mins, maxs, light->origin, light->normal );
3792                                         }
3793
3794                                         /* copy bounds */
3795                                         VectorCopy( mins, light->mins );
3796                                         VectorCopy( maxs, light->maxs );
3797
3798                                         /* reflect bounds around light origin */
3799                                         //%     VectorMA( light->origin, -1.0f, origin, origin );
3800                                         VectorScale( light->origin, 2, origin );
3801                                         VectorSubtract( origin, maxs, origin );
3802                                         AddPointToBounds( origin, mins, maxs );
3803                                         //%     VectorMA( light->origin, -1.0f, mins, origin );
3804                                         VectorScale( light->origin, 2, origin );
3805                                         VectorSubtract( origin, mins, origin );
3806                                         AddPointToBounds( origin, mins, maxs );
3807
3808                                         /* calculate spherical bounds */
3809                                         VectorSubtract( maxs, light->origin, dir );
3810                                         radius = (float) VectorLength( dir );
3811
3812                                         /* if this radius is smaller than the envelope, then set the envelope to it */
3813                                         if ( radius < light->envelope ) {
3814                                                 light->envelope = radius;
3815                                                 //%     Sys_FPrintf( SYS_VRB, "PVS Cull (%d): culled\n", numLights );
3816                                         }
3817                                         //%     else
3818                                         //%             Sys_FPrintf( SYS_VRB, "PVS Cull (%d): failed (%8.0f > %8.0f)\n", numLights, radius, light->envelope );
3819                                 }
3820
3821                                 /* add grid/surface only check */
3822                                 if ( forGrid ) {
3823                                         if ( !( light->flags & LIGHT_GRID ) ) {
3824                                                 light->envelope = 0.0f;
3825                                         }
3826                                 }
3827                                 else
3828                                 {
3829                                         if ( !( light->flags & LIGHT_SURFACES ) ) {
3830                                                 light->envelope = 0.0f;
3831                                         }
3832                                 }
3833                         }
3834
3835                         /* culled? */
3836                         if ( light->cluster < 0 || light->envelope <= 0.0f ) {
3837                                 /* debug code */
3838                                 //%     Sys_Printf( "Culling light: Cluster: %d Envelope: %f\n", light->cluster, light->envelope );
3839
3840                                 /* delete the light */
3841                                 numCulledLights++;
3842                                 *owner = light->next;
3843                                 if ( light->w != NULL ) {
3844                                         free( light->w );
3845                                 }
3846                                 free( light );
3847                                 continue;
3848                         }
3849                 }
3850
3851                 /* square envelope */
3852                 light->envelope2 = ( light->envelope * light->envelope );
3853
3854                 /* increment light count */
3855                 numLights++;
3856
3857                 /* set next light */
3858                 owner = &( ( **owner ).next );
3859         }
3860
3861         /* bucket sort lights by style */
3862         memset( buckets, 0, sizeof( buckets ) );
3863         light2 = NULL;
3864         for ( light = lights; light != NULL; light = light2 )
3865         {
3866                 /* get next light */
3867                 light2 = light->next;
3868
3869                 /* filter into correct bucket */
3870                 light->next = buckets[ light->style ];
3871                 buckets[ light->style ] = light;
3872
3873                 /* if any styled light is present, automatically set nocollapse */
3874                 if ( light->style != LS_NORMAL ) {
3875                         noCollapse = qtrue;
3876                 }
3877         }
3878
3879         /* filter back into light list */
3880         lights = NULL;
3881         for ( i = 255; i >= 0; i-- )
3882         {
3883                 light2 = NULL;
3884                 for ( light = buckets[ i ]; light != NULL; light = light2 )
3885                 {
3886                         light2 = light->next;
3887                         light->next = lights;
3888                         lights = light;
3889                 }
3890         }
3891
3892         /* emit some statistics */
3893         Sys_Printf( "%9d total lights\n", numLights );
3894         Sys_Printf( "%9d culled lights\n", numCulledLights );
3895 }
3896
3897
3898
3899 /*
3900    CreateTraceLightsForBounds()
3901    creates a list of lights that affect the given bounding box and pvs clusters (bsp leaves)
3902  */
3903
3904 void CreateTraceLightsForBounds( vec3_t mins, vec3_t maxs, vec3_t normal, int numClusters, int *clusters, int flags, trace_t *trace ){
3905         int i;
3906         light_t     *light;
3907         vec3_t origin, dir, nullVector = { 0.0f, 0.0f, 0.0f };
3908         float radius, dist, length;
3909
3910
3911         /* potential pre-setup  */
3912         if ( numLights == 0 ) {
3913                 SetupEnvelopes( qfalse, fast );
3914         }
3915
3916         /* debug code */
3917         //% 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 ] );
3918
3919         /* allocate the light list */
3920         trace->lights = safe_malloc( sizeof( light_t* ) * ( numLights + 1 ) );
3921         trace->numLights = 0;
3922
3923         /* calculate spherical bounds */
3924         VectorAdd( mins, maxs, origin );
3925         VectorScale( origin, 0.5f, origin );
3926         VectorSubtract( maxs, origin, dir );
3927         radius = (float) VectorLength( dir );
3928
3929         /* get length of normal vector */
3930         if ( normal != NULL ) {
3931                 length = VectorLength( normal );
3932         }
3933         else
3934         {
3935                 normal = nullVector;
3936                 length = 0;
3937         }
3938
3939         /* test each light and see if it reaches the sphere */
3940         /* note: the attenuation code MUST match LightingAtSample() */
3941         for ( light = lights; light; light = light->next )
3942         {
3943                 /* check zero sized envelope */
3944                 if ( light->envelope <= 0 ) {
3945                         lightsEnvelopeCulled++;
3946                         continue;
3947                 }
3948
3949                 /* check flags */
3950                 if ( !( light->flags & flags ) ) {
3951                         continue;
3952                 }
3953
3954                 /* sunlight skips all this nonsense */
3955                 if ( light->type != EMIT_SUN ) {
3956                         /* sun only? */
3957                         if ( sunOnly ) {
3958                                 continue;
3959                         }
3960
3961                         /* check against pvs cluster */
3962                         if ( numClusters > 0 && clusters != NULL ) {
3963                                 for ( i = 0; i < numClusters; i++ )
3964                                 {
3965                                         if ( ClusterVisible( light->cluster, clusters[ i ] ) ) {
3966                                                 break;
3967                                         }
3968                                 }
3969
3970                                 /* fixme! */
3971                                 if ( i == numClusters ) {
3972                                         lightsClusterCulled++;
3973                                         continue;
3974                                 }
3975                         }
3976
3977                         /* if the light's bounding sphere intersects with the bounding sphere then this light needs to be tested */
3978                         VectorSubtract( light->origin, origin, dir );
3979                         dist = VectorLength( dir );
3980                         dist -= light->envelope;
3981                         dist -= radius;
3982                         if ( dist > 0 ) {
3983                                 lightsEnvelopeCulled++;
3984                                 continue;
3985                         }
3986
3987                         /* check bounding box against light's pvs envelope (note: this code never eliminated any lights, so disabling it) */
3988                         #if 0
3989                         skip = qfalse;
3990                         for ( i = 0; i < 3; i++ )
3991                         {
3992                                 if ( mins[ i ] > light->maxs[ i ] || maxs[ i ] < light->mins[ i ] ) {
3993                                         skip = qtrue;
3994                                 }
3995                         }
3996                         if ( skip ) {
3997                                 lightsBoundsCulled++;
3998                                 continue;
3999                         }
4000                         #endif
4001                 }
4002
4003                 /* planar surfaces (except twosided surfaces) have a couple more checks */
4004                 if ( length > 0.0f && trace->twoSided == qfalse ) {
4005                         /* lights coplanar with a surface won't light it */
4006                         if ( !( light->flags & LIGHT_TWOSIDED ) && DotProduct( light->normal, normal ) > 0.999f ) {
4007                                 lightsPlaneCulled++;
4008                                 continue;
4009                         }
4010
4011                         /* check to see if light is behind the plane */
4012                         if ( DotProduct( light->origin, normal ) - DotProduct( origin, normal ) < -1.0f ) {
4013                                 lightsPlaneCulled++;
4014                                 continue;
4015                         }
4016                 }
4017
4018                 /* add this light */
4019                 trace->lights[ trace->numLights++ ] = light;
4020         }
4021
4022         /* make last night null */
4023         trace->lights[ trace->numLights ] = NULL;
4024 }
4025
4026
4027
4028 void FreeTraceLights( trace_t *trace ){
4029         if ( trace->lights != NULL ) {
4030                 free( trace->lights );
4031         }
4032 }
4033
4034
4035
4036 /*
4037    CreateTraceLightsForSurface()
4038    creates a list of lights that can potentially affect a drawsurface
4039  */
4040
4041 void CreateTraceLightsForSurface( int num, trace_t *trace ){
4042         int i;
4043         vec3_t mins, maxs, normal;
4044         bspDrawVert_t       *dv;
4045         bspDrawSurface_t    *ds;
4046         surfaceInfo_t       *info;
4047
4048
4049         /* dummy check */
4050         if ( num < 0 ) {
4051                 return;
4052         }
4053
4054         /* get drawsurface and info */
4055         ds = &bspDrawSurfaces[ num ];
4056         info = &surfaceInfos[ num ];
4057
4058         /* get the mins/maxs for the dsurf */
4059         ClearBounds( mins, maxs );
4060         VectorCopy( bspDrawVerts[ ds->firstVert ].normal, normal );
4061         for ( i = 0; i < ds->numVerts; i++ )
4062         {
4063                 dv = &yDrawVerts[ ds->firstVert + i ];
4064                 AddPointToBounds( dv->xyz, mins, maxs );
4065                 if ( !VectorCompare( dv->normal, normal ) ) {
4066                         VectorClear( normal );
4067                 }
4068         }
4069
4070         /* create the lights for the bounding box */
4071         CreateTraceLightsForBounds( mins, maxs, normal, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ], LIGHT_SURFACES, trace );
4072 }
4073
4074 /////////////////////////////////////////////////////////////
4075
4076 #define FLOODLIGHT_CONE_ANGLE           88  /* degrees */
4077 #define FLOODLIGHT_NUM_ANGLE_STEPS      16
4078 #define FLOODLIGHT_NUM_ELEVATION_STEPS  4
4079 #define FLOODLIGHT_NUM_VECTORS          ( FLOODLIGHT_NUM_ANGLE_STEPS * FLOODLIGHT_NUM_ELEVATION_STEPS )
4080
4081 static vec3_t floodVectors[ FLOODLIGHT_NUM_VECTORS ];
4082 static int numFloodVectors = 0;
4083
4084 void SetupFloodLight( void ){
4085         int i, j;
4086         float angle, elevation, angleStep, elevationStep;
4087         const char  *value;
4088         double v1,v2,v3,v4,v5,v6;
4089
4090         /* note it */
4091         Sys_FPrintf( SYS_VRB, "--- SetupFloodLight ---\n" );
4092
4093         /* calculate angular steps */
4094         angleStep = DEG2RAD( 360.0f / FLOODLIGHT_NUM_ANGLE_STEPS );
4095         elevationStep = DEG2RAD( FLOODLIGHT_CONE_ANGLE / FLOODLIGHT_NUM_ELEVATION_STEPS );
4096
4097         /* iterate angle */
4098         angle = 0.0f;
4099         for ( i = 0, angle = 0.0f; i < FLOODLIGHT_NUM_ANGLE_STEPS; i++, angle += angleStep )
4100         {
4101                 /* iterate elevation */
4102                 for ( j = 0, elevation = elevationStep * 0.5f; j < FLOODLIGHT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep )
4103                 {
4104                         floodVectors[ numFloodVectors ][ 0 ] = sin( elevation ) * cos( angle );
4105                         floodVectors[ numFloodVectors ][ 1 ] = sin( elevation ) * sin( angle );
4106                         floodVectors[ numFloodVectors ][ 2 ] = cos( elevation );
4107                         numFloodVectors++;
4108                 }
4109         }
4110
4111         /* emit some statistics */
4112         Sys_FPrintf( SYS_VRB, "%9d numFloodVectors\n", numFloodVectors );
4113
4114         /* floodlight */
4115         value = ValueForKey( &entities[ 0 ], "_floodlight" );
4116
4117         if ( value[ 0 ] != '\0' ) {
4118                 v1 = v2 = v3 = 0;
4119                 v4 = floodlightDistance;
4120                 v5 = floodlightIntensity;
4121                 v6 = floodlightDirectionScale;
4122
4123                 sscanf( value, "%lf %lf %lf %lf %lf %lf", &v1, &v2, &v3, &v4, &v5, &v6 );
4124
4125                 floodlightRGB[0] = v1;
4126                 floodlightRGB[1] = v2;
4127                 floodlightRGB[2] = v3;
4128
4129                 if ( VectorLength( floodlightRGB ) == 0 ) {
4130                         VectorSet( floodlightRGB,0.94,0.94,1.0 );
4131                 }
4132
4133                 if ( v4 < 1 ) {
4134                         v4 = 1024;
4135                 }
4136                 if ( v5 < 1 ) {
4137                         v5 = 128;
4138                 }
4139                 if ( v6 < 0 ) {
4140                         v6 = 1;
4141                 }
4142
4143                 floodlightDistance = v4;
4144                 floodlightIntensity = v5;
4145                 floodlightDirectionScale = v6;
4146
4147                 floodlighty = qtrue;
4148                 Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
4149         }
4150         else
4151         {
4152                 VectorSet( floodlightRGB,0.94,0.94,1.0 );
4153         }
4154         if ( colorsRGB ) {
4155                 floodlightRGB[0] = Image_LinearFloatFromsRGBFloat( floodlightRGB[0] );
4156                 floodlightRGB[1] = Image_LinearFloatFromsRGBFloat( floodlightRGB[1] );
4157                 floodlightRGB[2] = Image_LinearFloatFromsRGBFloat( floodlightRGB[2] );
4158         }
4159         ColorNormalize( floodlightRGB,floodlightRGB );
4160 }
4161
4162 /*
4163    FloodLightForSample()
4164    calculates floodlight value for a given sample
4165    once again, kudos to the dirtmapping coder
4166  */
4167
4168 float FloodLightForSample( trace_t *trace, float floodLightDistance, qboolean floodLightLowQuality ){
4169         int i;
4170         float d;
4171         float contribution;
4172         int sub = 0;
4173         float gatherLight, outLight;
4174         vec3_t normal, worldUp, myUp, myRt, direction, displacement;
4175         float dd;
4176         int vecs = 0;
4177
4178         gatherLight = 0;
4179         /* dummy check */
4180         //if( !dirty )
4181         //      return 1.0f;
4182         if ( trace == NULL || trace->cluster < 0 ) {
4183                 return 0.0f;
4184         }
4185
4186
4187         /* setup */
4188         dd = floodLightDistance;
4189         VectorCopy( trace->normal, normal );
4190
4191         /* check if the normal is aligned to the world-up */
4192         if ( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f && ( normal[ 2 ] == 1.0f || normal[ 2 ] == -1.0f ) ) {
4193                 if ( normal[ 2 ] == 1.0f ) {
4194                         VectorSet( myRt, 1.0f, 0.0f, 0.0f );
4195                         VectorSet( myUp, 0.0f, 1.0f, 0.0f );
4196                 }
4197                 else if ( normal[ 2 ] == -1.0f ) {
4198                         VectorSet( myRt, -1.0f, 0.0f, 0.0f );
4199                         VectorSet( myUp,  0.0f, 1.0f, 0.0f );
4200                 }
4201         }
4202         else
4203         {
4204                 VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
4205                 CrossProduct( normal, worldUp, myRt );
4206                 VectorNormalize( myRt, myRt );
4207                 CrossProduct( myRt, normal, myUp );
4208                 VectorNormalize( myUp, myUp );
4209         }
4210
4211         /* vortex: optimise floodLightLowQuality a bit */
4212         if ( floodLightLowQuality == qtrue ) {
4213                 /* iterate through ordered vectors */
4214                 for ( i = 0; i < numFloodVectors; i++ )
4215                         if ( rand() % 10 != 0 ) {
4216                                 continue;
4217                         }
4218         }
4219         else
4220         {
4221                 /* iterate through ordered vectors */
4222                 for ( i = 0; i < numFloodVectors; i++ )
4223                 {
4224                         vecs++;
4225
4226                         /* transform vector into tangent space */
4227                         direction[ 0 ] = myRt[ 0 ] * floodVectors[ i ][ 0 ] + myUp[ 0 ] * floodVectors[ i ][ 1 ] + normal[ 0 ] * floodVectors[ i ][ 2 ];
4228                         direction[ 1 ] = myRt[ 1 ] * floodVectors[ i ][ 0 ] + myUp[ 1 ] * floodVectors[ i ][ 1 ] + normal[ 1 ] * floodVectors[ i ][ 2 ];
4229                         direction[ 2 ] = myRt[ 2 ] * floodVectors[ i ][ 0 ] + myUp[ 2 ] * floodVectors[ i ][ 1 ] + normal[ 2 ] * floodVectors[ i ][ 2 ];
4230
4231                         /* set endpoint */
4232                         VectorMA( trace->origin, dd, direction, trace->end );
4233
4234                         //VectorMA( trace->origin, 1, direction, trace->origin );
4235
4236                         SetupTrace( trace );
4237                         VectorSet(trace->color, 1.0f, 1.0f, 1.0f);
4238                         /* trace */
4239                         TraceLine( trace );
4240                         contribution = 1;
4241
4242                         if ( trace->compileFlags & C_SKY || trace->compileFlags & C_TRANSLUCENT ) {
4243                                 contribution = 1.0f;
4244                         }
4245                         else if ( trace->opaque ) {
4246                                 VectorSubtract( trace->hit, trace->origin, displacement );
4247                                 d = VectorLength( displacement );
4248
4249                                 // d=trace->distance;
4250                                 //if (d>256) gatherDirt+=1;
4251                                 contribution = d / dd;
4252                                 if ( contribution > 1 ) {
4253                                         contribution = 1.0f;
4254                                 }
4255
4256                                 //gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
4257                         }
4258
4259                         gatherLight += contribution;
4260                 }
4261         }
4262
4263         /* early out */
4264         if ( gatherLight <= 0.0f ) {
4265                 return 0.0f;
4266         }
4267
4268         sub = vecs;
4269
4270         if ( sub < 1 ) {
4271                 sub = 1;
4272         }
4273         gatherLight /= ( sub );
4274
4275         outLight = gatherLight;
4276         if ( outLight > 1.0f ) {
4277                 outLight = 1.0f;
4278         }
4279
4280         /* return to sender */
4281         return outLight;
4282 }
4283
4284 /*
4285    FloodLightRawLightmap
4286    lighttracer style ambient occlusion light hack.
4287    Kudos to the dirtmapping author for most of this source.
4288    VorteX: modified to floodlight up custom surfaces (q3map_floodLight)
4289    VorteX: fixed problems with deluxemapping
4290  */
4291
4292 // floodlight pass on a lightmap
4293 void FloodLightRawLightmapPass( rawLightmap_t *lm, vec3_t lmFloodLightRGB, float lmFloodLightIntensity, float lmFloodLightDistance, qboolean lmFloodLightLowQuality, float floodlightDirectionScale ){
4294         int i, x, y, *cluster;
4295         float               *origin, *normal, *floodlight, floodLightAmount;
4296         surfaceInfo_t       *info;
4297         trace_t trace;
4298         // int sx, sy;
4299         // float samples, average, *floodlight2;
4300
4301         memset( &trace,0,sizeof( trace_t ) );
4302
4303         /* setup trace */
4304         trace.testOcclusion = qtrue;
4305         trace.forceSunlight = qfalse;
4306         trace.twoSided = qtrue;
4307         trace.recvShadows = lm->recvShadows;
4308         trace.numSurfaces = lm->numLightSurfaces;
4309         trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
4310         trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
4311         trace.testAll = qfalse;
4312         trace.distance = 1024;
4313
4314         /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
4315         //trace.twoSided = qfalse;
4316         for ( i = 0; i < trace.numSurfaces; i++ )
4317         {
4318                 /* get surface */
4319                 info = &surfaceInfos[ trace.surfaces[ i ] ];
4320
4321                 /* check twosidedness */
4322                 if ( info->si->twoSided ) {
4323                         trace.twoSided = qtrue;
4324                         break;
4325                 }
4326         }
4327
4328         /* gather floodlight */
4329         for ( y = 0; y < lm->sh; y++ )
4330         {
4331                 for ( x = 0; x < lm->sw; x++ )
4332                 {
4333                         /* get luxel */
4334                         cluster = SUPER_CLUSTER( x, y );
4335                         origin = SUPER_ORIGIN( x, y );
4336                         normal = SUPER_NORMAL( x, y );
4337                         floodlight = SUPER_FLOODLIGHT( x, y );
4338
4339                         /* set default dirt */
4340                         *floodlight = 0.0f;
4341
4342                         /* only look at mapped luxels */
4343                         if ( *cluster < 0 ) {
4344                                 continue;
4345                         }
4346
4347                         /* copy to trace */
4348                         trace.cluster = *cluster;
4349                         VectorCopy( origin, trace.origin );
4350                         VectorCopy( normal, trace.normal );
4351
4352                         /* get floodlight */
4353                         floodLightAmount = FloodLightForSample( &trace, lmFloodLightDistance, lmFloodLightLowQuality ) * lmFloodLightIntensity;
4354
4355                         /* add floodlight */
4356                         floodlight[0] += lmFloodLightRGB[0] * floodLightAmount;
4357                         floodlight[1] += lmFloodLightRGB[1] * floodLightAmount;
4358                         floodlight[2] += lmFloodLightRGB[2] * floodLightAmount;
4359                         floodlight[3] += floodlightDirectionScale;
4360                 }
4361         }
4362
4363         /* testing no filtering */
4364         return;
4365
4366 #if 0
4367
4368         /* filter "dirt" */
4369         for ( y = 0; y < lm->sh; y++ )
4370         {
4371                 for ( x = 0; x < lm->sw; x++ )
4372                 {
4373                         /* get luxel */
4374                         cluster = SUPER_CLUSTER( x, y );
4375                         floodlight = SUPER_FLOODLIGHT( x, y );
4376
4377                         /* filter dirt by adjacency to unmapped luxels */
4378                         average = *floodlight;
4379                         samples = 1.0f;
4380                         for ( sy = ( y - 1 ); sy <= ( y + 1 ); sy++ )
4381                         {
4382                                 if ( sy < 0 || sy >= lm->sh ) {
4383                                         continue;
4384                                 }
4385
4386                                 for ( sx = ( x - 1 ); sx <= ( x + 1 ); sx++ )
4387                                 {
4388                                         if ( sx < 0 || sx >= lm->sw || ( sx == x && sy == y ) ) {
4389                                                 continue;
4390                                         }
4391
4392                                         /* get neighboring luxel */
4393                                         cluster = SUPER_CLUSTER( sx, sy );
4394                                         floodlight2 = SUPER_FLOODLIGHT( sx, sy );
4395                                         if ( *cluster < 0 || *floodlight2 <= 0.0f ) {
4396                                                 continue;
4397                                         }
4398
4399                                         /* add it */
4400                                         average += *floodlight2;
4401                                         samples += 1.0f;
4402                                 }
4403
4404                                 /* bail */
4405                                 if ( samples <= 0.0f ) {
4406                                         break;
4407                                 }
4408                         }
4409
4410                         /* bail */
4411                         if ( samples <= 0.0f ) {
4412                                 continue;
4413                         }
4414
4415                         /* scale dirt */
4416                         *floodlight = average / samples;
4417                 }
4418         }
4419 #endif
4420 }
4421
4422 void FloodLightRawLightmap( int rawLightmapNum ){
4423         rawLightmap_t       *lm;
4424
4425         /* bail if this number exceeds the number of raw lightmaps */
4426         if ( rawLightmapNum >= numRawLightmaps ) {
4427                 return;
4428         }
4429         /* get lightmap */
4430         lm = &rawLightmaps[ rawLightmapNum ];
4431
4432         /* global pass */
4433         if ( floodlighty && floodlightIntensity ) {
4434                 FloodLightRawLightmapPass( lm, floodlightRGB, floodlightIntensity, floodlightDistance, floodlight_lowquality, floodlightDirectionScale );
4435         }
4436
4437         /* custom pass */
4438         if ( lm->floodlightIntensity ) {
4439                 FloodLightRawLightmapPass( lm, lm->floodlightRGB, lm->floodlightIntensity, lm->floodlightDistance, qfalse, lm->floodlightDirectionScale );
4440                 numSurfacesFloodlighten += 1;
4441         }
4442 }
4443
4444 void FloodlightRawLightmaps(){
4445         Sys_Printf( "--- FloodlightRawLightmap ---\n" );
4446         numSurfacesFloodlighten = 0;
4447         RunThreadsOnIndividual( numRawLightmaps, qtrue, FloodLightRawLightmap );
4448         Sys_Printf( "%9d custom lightmaps floodlighted\n", numSurfacesFloodlighten );
4449 }
4450
4451 /*
4452    FloodLightIlluminate()
4453    illuminate floodlight into lightmap luxels
4454  */
4455
4456 void FloodlightIlluminateLightmap( rawLightmap_t *lm ){
4457         float               *luxel, *floodlight, *deluxel, *normal;
4458         int                 *cluster;
4459         float brightness;
4460         int x, y, lightmapNum;
4461
4462         /* walk lightmaps */
4463         for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
4464         {
4465                 /* early out */
4466                 if ( lm->superLuxels[ lightmapNum ] == NULL ) {
4467                         continue;
4468                 }
4469
4470                 if( lm->styles[lightmapNum] != LS_NORMAL && lm->styles[lightmapNum] != LS_NONE ) // isStyleLight
4471                         continue;
4472
4473                 /* apply floodlight to each luxel */
4474                 for ( y = 0; y < lm->sh; y++ )
4475                 {
4476                         for ( x = 0; x < lm->sw; x++ )
4477                         {
4478                                 /* get floodlight */
4479                                 floodlight = SUPER_FLOODLIGHT( x, y );
4480                                 if ( !floodlight[0] && !floodlight[1] && !floodlight[2] ) {
4481                                         continue;
4482                                 }
4483
4484                                 /* get cluster */
4485                                 cluster = SUPER_CLUSTER( x, y );
4486
4487                                 /* only process mapped luxels */
4488                                 if ( *cluster < 0 ) {
4489                                         continue;
4490                                 }
4491
4492                                 /* get particulars */
4493                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
4494                                 deluxel = SUPER_DELUXEL( x, y );
4495
4496                                 /* add to lightmap */
4497                                 luxel[0] += floodlight[0];
4498                                 luxel[1] += floodlight[1];
4499                                 luxel[2] += floodlight[2];
4500
4501                                 if ( luxel[3] == 0 ) {
4502                                         luxel[3] = 1;
4503                                 }
4504
4505                                 /* add to deluxemap */
4506                                 if ( deluxemap && floodlight[3] > 0 ) {
4507                                         vec3_t lightvector;
4508
4509                                         normal = SUPER_NORMAL( x, y );
4510                                         brightness = RGBTOGRAY( floodlight ) * ( 1.0f / 255.0f ) * floodlight[3];
4511
4512                                         // use AT LEAST this amount of contribution from ambient for the deluxemap, fixes points that receive ZERO light
4513                                         if ( brightness < 0.00390625f ) {
4514                                                 brightness = 0.00390625f;
4515                                         }
4516
4517                                         VectorScale( normal, brightness, lightvector );
4518                                         VectorAdd( deluxel, lightvector, deluxel );
4519                                 }
4520                         }
4521                 }
4522         }
4523 }