fix -nodeluxenormalize
[divverent/netradiant.git] / tools / quake3 / q3map2 / light_ydnar.c
1 /* -------------------------------------------------------------------------------
2
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
5
6 This file is part of GtkRadiant.
7
8 GtkRadiant is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 GtkRadiant is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GtkRadiant; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21
22 ----------------------------------------------------------------------------------
23
24 This code has been altered significantly from its original form, to support
25 several games based on the Quake III Arena engine, in the form of "Q3Map2."
26
27 ------------------------------------------------------------------------------- */
28
29
30
31 /* marker */
32 #define LIGHT_YDNAR_C
33
34
35
36 /* dependencies */
37 #include "q3map2.h"
38
39
40
41
42 /*
43 ColorToBytes()
44 ydnar: moved to here 2001-02-04
45 */
46
47 void ColorToBytesDeluxe( const float *color, byte *colorBytes, float scale, const float *deluxel, byte *deluxeBytes)
48 {
49         int             i;
50         float   max, gamma;
51         vec3_t  sample, direction;
52         float   inv, dif;
53         float   colorMultiplier;
54         float   temp;
55         
56         
57         /* ydnar: scaling necessary for simulating r_overbrightBits on external lightmaps */
58         if( scale <= 0.0f )
59                 scale = 1.0f;
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                 {
71                         sample[ i ] = 0.0f;
72                         continue;
73                 }
74                 
75                 /* gamma */
76                 sample[ i ] = pow( sample[ i ] / 255.0f, gamma ) * 255.0f;
77         }
78
79         colorMultiplier = 1;
80
81         if (lightmapExposure == 1)
82         {
83                 /* clamp with color normalization */
84                 max = sample[ 0 ];
85                 if( sample[ 1 ] > max )
86                         max = sample[ 1 ];
87                 if( sample[ 2 ] > max )
88                         max = sample[ 2 ];
89                 if(max * colorMultiplier > 255.0f)
90                         colorMultiplier *= 255.0 / max;
91         }
92         else
93         {
94                 if (lightmapExposure==0)
95                         inv = 1.f;
96                 else
97                         inv = 1.f/lightmapExposure;
98                 //Exposure
99
100                 max = sample[ 0 ];
101                 if( sample[ 1 ] > max )
102                         max = sample[ 1 ];
103                 if( sample[ 2 ] > max )
104                         max = sample[ 2 ];
105                 max *= colorMultiplier;
106
107                 dif = (1-  exp(-max * inv) )  *  255;
108
109                 if (max >0)
110                 {
111                         dif = dif / max;
112                 }
113                 else
114                 {
115                         dif = 0;
116                 }
117
118                 colorMultiplier *= dif;
119         }
120
121         /* compensate for ingame overbrighting/bitshifting */
122         VectorScale( sample, (colorMultiplier / lightmapCompensate), sample );
123
124         /* store it off */
125         colorBytes[ 0 ] = sample[ 0 ];
126         colorBytes[ 1 ] = sample[ 1 ];
127         colorBytes[ 2 ] = sample[ 2 ];
128
129                                 
130         /* store direction */
131         if( deluxel )
132         {
133                 if(normalizeDeluxemap)
134                 {
135                         if(!VectorNormalize(deluxel, direction))
136                                 VectorClear(direction);
137                 }
138                 else
139                 {
140                         if(deluxel[3])
141                         {
142                                 VectorScale(deluxel, 1 / deluxel[3], direction);
143                                 // NOTE:
144                                 // if the light was scaled down due to it being too bright...
145                                 // we need to reduce the directionality so ADDING light can't
146                                 // make stuff DARKER!
147                                 if(colorMultiplier < 1)
148                                         VectorScale(direction, colorMultiplier, direction);
149                                 // TODO find out the best renderer equation for this
150                         }
151                         else
152                                 VectorClear(direction);
153                 }
154
155                 /* normalize average light direction */
156                 //if(direction[0] != 0 || direction[1] != 0 || direction[2] != 0)
157                 {
158                         /* encode [-1,1] in [0,255] */
159                         for( i = 0; i < 3; i++ )
160                         {
161                                 temp = (direction[ i ] + 1.0f) * 127.5f;
162                                 if( temp < 0 )
163                                         deluxeBytes[ i ] = 0;
164                                 else if( temp > 255 )
165                                         deluxeBytes[ i ] = 255;
166                                 else
167                                         deluxeBytes[ i ] = temp;
168                         }
169                 }
170         }
171 }
172
173 void ColorToBytes( const float *color, byte *colorBytes, float scale )
174 {
175         ColorToBytesDeluxe(color, colorBytes, scale, NULL, NULL);
176 }
177
178
179
180 /* -------------------------------------------------------------------------------
181
182 this section deals with phong shading (normal interpolation across brush faces)
183
184 ------------------------------------------------------------------------------- */
185
186 /*
187 SmoothNormals()
188 smooths together coincident vertex normals across the bsp
189 */
190
191 #define MAX_SAMPLES                             256
192 #define THETA_EPSILON                   0.000001
193 #define EQUAL_NORMAL_EPSILON    0.01
194
195 void SmoothNormals( void )
196 {
197         int                                     i, j, k, f, cs, numVerts, numVotes, fOld, start;
198         float                           shadeAngle, defaultShadeAngle, maxShadeAngle, dot, testAngle;
199         bspDrawSurface_t        *ds;
200         shaderInfo_t            *si;
201         float                           *shadeAngles;
202         byte                            *smoothed;
203         vec3_t                          average, diff;
204         int                                     indexes[ MAX_SAMPLES ];
205         vec3_t                          votes[ MAX_SAMPLES ];
206         
207         
208         /* allocate shade angle table */
209         shadeAngles = safe_malloc( numBSPDrawVerts * sizeof( float ) );
210         memset( shadeAngles, 0, numBSPDrawVerts * sizeof( float ) );
211         
212         /* allocate smoothed table */
213         cs = (numBSPDrawVerts / 8) + 1;
214         smoothed = safe_malloc( cs );
215         memset( smoothed, 0, cs );
216         
217         /* set default shade angle */
218         defaultShadeAngle = DEG2RAD( shadeAngleDegrees );
219         maxShadeAngle = 0;
220         
221         /* run through every surface and flag verts belonging to non-lightmapped surfaces
222            and set per-vertex smoothing angle */
223         for( i = 0; i < numBSPDrawSurfaces; i++ )
224         {
225                 /* get drawsurf */
226                 ds = &bspDrawSurfaces[ i ];
227                 
228                 /* get shader for shade angle */
229                 si = surfaceInfos[ i ].si;
230                 if( si->shadeAngleDegrees )
231                         shadeAngle = DEG2RAD( si->shadeAngleDegrees );
232                 else
233                         shadeAngle = defaultShadeAngle;
234                 if( shadeAngle > maxShadeAngle )
235                         maxShadeAngle = shadeAngle;
236                 
237                 /* flag its verts */
238                 for( j = 0; j < ds->numVerts; j++ )
239                 {
240                         f = ds->firstVert + j;
241                         shadeAngles[ f ] = shadeAngle;
242                         if( ds->surfaceType == MST_TRIANGLE_SOUP )
243                                 smoothed[ f >> 3 ] |= (1 << (f & 7));
244                 }
245                 
246                 /* ydnar: optional force-to-trisoup */
247                 if( trisoup && ds->surfaceType == MST_PLANAR )
248                 {
249                         ds->surfaceType = MST_TRIANGLE_SOUP;
250                         ds->lightmapNum[ 0 ] = -3;
251                 }
252         }
253         
254         /* bail if no surfaces have a shade angle */
255         if( maxShadeAngle == 0 )
256         {
257                 free( shadeAngles );
258                 free( smoothed );
259                 return;
260         }
261         
262         /* init pacifier */
263         fOld = -1;
264         start = I_FloatTime();
265         
266         /* go through the list of vertexes */
267         for( i = 0; i < numBSPDrawVerts; i++ )
268         {
269                 /* print pacifier */
270                 f = 10 * i / numBSPDrawVerts;
271                 if( f != fOld )
272                 {
273                         fOld = f;
274                         Sys_Printf( "%i...", f );
275                 }
276                 
277                 /* already smoothed? */
278                 if( smoothed[ i >> 3 ] & (1 << (i & 7)) )
279                         continue;
280                 
281                 /* clear */
282                 VectorClear( average );
283                 numVerts = 0;
284                 numVotes = 0;
285                 
286                 /* build a table of coincident vertexes */
287                 for( j = i; j < numBSPDrawVerts && numVerts < MAX_SAMPLES; j++ )
288                 {
289                         /* already smoothed? */
290                         if( smoothed[ j >> 3 ] & (1 << (j & 7)) )
291                                 continue;
292                         
293                         /* test vertexes */
294                         if( VectorCompare( yDrawVerts[ i ].xyz, yDrawVerts[ j ].xyz ) == qfalse )
295                                 continue;
296                         
297                         /* use smallest shade angle */
298                         shadeAngle = (shadeAngles[ i ] < shadeAngles[ j ] ? shadeAngles[ i ] : shadeAngles[ j ]);
299                         
300                         /* check shade angle */
301                         dot = DotProduct( bspDrawVerts[ i ].normal, bspDrawVerts[ j ].normal );
302                         if( dot > 1.0 )
303                                 dot = 1.0;
304                         else if( dot < -1.0 )
305                                 dot = -1.0;
306                         testAngle = acos( dot ) + THETA_EPSILON;
307                         if( testAngle >= shadeAngle )
308                         {
309                                 //Sys_Printf( "F(%3.3f >= %3.3f) ", RAD2DEG( testAngle ), RAD2DEG( shadeAngle ) );
310                                 continue;
311                         }
312                         //Sys_Printf( "P(%3.3f < %3.3f) ", RAD2DEG( testAngle ), RAD2DEG( shadeAngle ) );
313                         
314                         /* add to the list */
315                         indexes[ numVerts++ ] = j;
316                         
317                         /* flag vertex */
318                         smoothed[ j >> 3 ] |= (1 << (j & 7));
319                         
320                         /* see if this normal has already been voted */
321                         for( k = 0; k < numVotes; k++ )
322                         {
323                                 VectorSubtract( bspDrawVerts[ j ].normal, votes[ k ], diff );
324                                 if( fabs( diff[ 0 ] ) < EQUAL_NORMAL_EPSILON &&
325                                         fabs( diff[ 1 ] ) < EQUAL_NORMAL_EPSILON &&
326                                         fabs( diff[ 2 ] ) < EQUAL_NORMAL_EPSILON )
327                                         break;
328                         }
329                         
330                         /* add a new vote? */
331                         if( k == numVotes && numVotes < MAX_SAMPLES )
332                         {
333                                 VectorAdd( average, bspDrawVerts[ j ].normal, average );
334                                 VectorCopy( bspDrawVerts[ j ].normal, votes[ numVotes ] );
335                                 numVotes++;
336                         }
337                 }
338                 
339                 /* don't average for less than 2 verts */
340                 if( numVerts < 2 )
341                         continue;
342                 
343                 /* average normal */
344                 if( VectorNormalize( average, average ) > 0 )
345                 {
346                         /* smooth */
347                         for( j = 0; j < numVerts; j++ )
348                                 VectorCopy( average, yDrawVerts[ indexes[ j ] ].normal );
349                 }
350         }
351         
352         /* free the tables */
353         free( shadeAngles );
354         free( smoothed );
355         
356         /* print time */
357         Sys_Printf( " (%i)\n", (int) (I_FloatTime() - start) );
358 }
359
360
361
362 /* -------------------------------------------------------------------------------
363
364 this section deals with phong shaded lightmap tracing
365
366 ------------------------------------------------------------------------------- */
367
368 /* 9th rewrite (recursive subdivision of a lightmap triangle) */
369
370 /*
371 CalcTangentVectors()
372 calculates the st tangent vectors for normalmapping
373 */
374
375 static qboolean CalcTangentVectors( int numVerts, bspDrawVert_t **dv, vec3_t *stv, vec3_t *ttv )
376 {
377         int                     i;
378         float           bb, s, t;
379         vec3_t          bary;
380         
381         
382         /* calculate barycentric basis for the triangle */
383         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 ]);
384         if( fabs( bb ) < 0.00000001f )
385                 return qfalse;
386         
387         /* do each vertex */
388         for( i = 0; i < numVerts; i++ )
389         {
390                 /* calculate s tangent vector */
391                 s = dv[ i ]->st[ 0 ] + 10.0f;
392                 t = dv[ i ]->st[ 1 ];
393                 bary[ 0 ] = ((dv[ 1 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t) - (dv[ 2 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t)) / bb;
394                 bary[ 1 ] = ((dv[ 2 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t) - (dv[ 0 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t)) / bb;
395                 bary[ 2 ] = ((dv[ 0 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t) - (dv[ 1 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t)) / bb;
396                 
397                 stv[ i ][ 0 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 0 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 0 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 0 ];
398                 stv[ i ][ 1 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 1 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 1 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 1 ];
399                 stv[ i ][ 2 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 2 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 2 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 2 ];
400                 
401                 VectorSubtract( stv[ i ], dv[ i ]->xyz, stv[ i ] );
402                 VectorNormalize( stv[ i ], stv[ i ] );
403                 
404                 /* calculate t tangent vector */
405                 s = dv[ i ]->st[ 0 ];
406                 t = dv[ i ]->st[ 1 ] + 10.0f;
407                 bary[ 0 ] = ((dv[ 1 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t) - (dv[ 2 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t)) / bb;
408                 bary[ 1 ] = ((dv[ 2 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t) - (dv[ 0 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t)) / bb;
409                 bary[ 2 ] = ((dv[ 0 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t) - (dv[ 1 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t)) / bb;
410                 
411                 ttv[ i ][ 0 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 0 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 0 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 0 ];
412                 ttv[ i ][ 1 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 1 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 1 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 1 ];
413                 ttv[ i ][ 2 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 2 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 2 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 2 ];
414                 
415                 VectorSubtract( ttv[ i ], dv[ i ]->xyz, ttv[ i ] );
416                 VectorNormalize( ttv[ i ], ttv[ i ] );
417                 
418                 /* debug code */
419                 //%     Sys_FPrintf( SYS_VRB, "%d S: (%f %f %f) T: (%f %f %f)\n", i,
420                 //%             stv[ i ][ 0 ], stv[ i ][ 1 ], stv[ i ][ 2 ], ttv[ i ][ 0 ], ttv[ i ][ 1 ], ttv[ i ][ 2 ] );
421         }
422         
423         /* return to caller */
424         return qtrue;
425 }
426
427
428
429
430 /*
431 PerturbNormal()
432 perterbs the normal by the shader's normalmap in tangent space
433 */
434
435 static void PerturbNormal( bspDrawVert_t *dv, shaderInfo_t *si, vec3_t pNormal, vec3_t stv[ 3 ], vec3_t ttv[ 3 ] )
436 {
437         int                     i;
438         vec4_t          bump;
439         
440         
441         /* passthrough */
442         VectorCopy( dv->normal, pNormal );
443         
444         /* sample normalmap */
445         if( RadSampleImage( si->normalImage->pixels, si->normalImage->width, si->normalImage->height, dv->st, bump ) == qfalse )
446                 return;
447         
448         /* remap sampled normal from [0,255] to [-1,-1] */
449         for( i = 0; i < 3; i++ )
450                 bump[ i ] = (bump[ i ] - 127.0f) * (1.0f / 127.5f);
451         
452         /* scale tangent vectors and add to original normal */
453         VectorMA( dv->normal, bump[ 0 ], stv[ 0 ], pNormal );
454         VectorMA( pNormal, bump[ 1 ], ttv[ 0 ], pNormal );
455         VectorMA( pNormal, bump[ 2 ], dv->normal, pNormal );
456         
457         /* renormalize and return */
458         VectorNormalize( pNormal, pNormal );
459 }
460
461
462
463 /*
464 MapSingleLuxel()
465 maps a luxel for triangle bv at
466 */
467
468 #define NUDGE                   0.5f
469 #define BOGUS_NUDGE             -99999.0f
470
471 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 ] )
472 {
473         int                             i, x, y, numClusters, *clusters, pointCluster, *cluster;
474         float                   *luxel, *origin, *normal, d, lightmapSampleOffset;
475         shaderInfo_t    *si;
476         vec3_t                  pNormal;
477         vec3_t                  vecs[ 3 ];
478         vec3_t                  nudged;
479         vec3_t                  cverts[ 3 ];
480         vec3_t                  temp;
481         vec4_t                  sideplane, hostplane;
482         vec3_t                  origintwo;
483         int                             j, next;
484         float                   e;
485         float                   *nudge;
486         static float    nudges[][ 2 ] =
487                                         {
488                                                 //%{ 0, 0 },            /* try center first */
489                                                 { -NUDGE, 0 },          /* left */
490                                                 { NUDGE, 0 },           /* right */
491                                                 { 0, NUDGE },           /* up */
492                                                 { 0, -NUDGE },          /* down */
493                                                 { -NUDGE, NUDGE },      /* left/up */
494                                                 { NUDGE, -NUDGE },      /* right/down */
495                                                 { NUDGE, NUDGE },       /* right/up */
496                                                 { -NUDGE, -NUDGE },     /* left/down */
497                                                 { BOGUS_NUDGE, BOGUS_NUDGE }
498                                         };
499         
500         
501         /* find luxel xy coords (fixme: subtract 0.5?) */
502         x = dv->lightmap[ 0 ][ 0 ];
503         y = dv->lightmap[ 0 ][ 1 ];
504         if( x < 0 )
505                 x = 0;
506         else if( x >= lm->sw )
507                 x = lm->sw - 1;
508         if( y < 0 )
509                 y = 0;
510         else if( y >= lm->sh )
511                 y = lm->sh - 1;
512         
513         /* set shader and cluster list */
514         if( info != NULL )
515         {
516                 si = info->si;
517                 numClusters = info->numSurfaceClusters;
518                 clusters = &surfaceClusters[ info->firstSurfaceCluster ];
519         }
520         else
521         {
522                 si = NULL;
523                 numClusters = 0;
524                 clusters = NULL;
525         }
526         
527         /* get luxel, origin, cluster, and normal */
528         luxel = SUPER_LUXEL( 0, x, y );
529         origin = SUPER_ORIGIN( x, y );
530         normal = SUPER_NORMAL( x, y );
531         cluster = SUPER_CLUSTER( x, y );
532         
533         /* don't attempt to remap occluded luxels for planar surfaces */
534         if( (*cluster) == CLUSTER_OCCLUDED && lm->plane != NULL )
535                 return (*cluster);
536         
537         /* only average the normal for premapped luxels */
538         else if( (*cluster) >= 0 )
539         {
540                 /* do bumpmap calculations */
541                 if( stv != NULL )
542                         PerturbNormal( dv, si, pNormal, stv, ttv );
543                 else
544                         VectorCopy( dv->normal, pNormal );
545                 
546                 /* add the additional normal data */
547                 VectorAdd( normal, pNormal, normal );
548                 luxel[ 3 ] += 1.0f;
549                 return (*cluster);
550         }
551         
552         /* otherwise, unmapped luxels (*cluster == CLUSTER_UNMAPPED) will have their full attributes calculated */
553         
554         /* get origin */
555         
556         /* axial lightmap projection */
557         if( lm->vecs != NULL )
558         {
559                 /* calculate an origin for the sample from the lightmap vectors */
560                 VectorCopy( lm->origin, origin );
561                 for( i = 0; i < 3; i++ )
562                 {
563                         /* add unless it's the axis, which is taken care of later */
564                         if( i == lm->axisNum )
565                                 continue;
566                         origin[ i ] += (x * lm->vecs[ 0 ][ i ]) + (y * lm->vecs[ 1 ][ i ]);
567                 }
568                 
569                 /* project the origin onto the plane */
570                 d = DotProduct( origin, plane ) - plane[ 3 ];
571                 d /= plane[ lm->axisNum ];
572                 origin[ lm->axisNum ] -= d;
573         }
574         
575         /* non axial lightmap projection (explicit xyz) */
576         else
577                 VectorCopy( dv->xyz, origin );
578
579         //////////////////////
580         //27's test to make sure samples stay within the triangle boundaries
581         //1) Test the sample origin to see if it lays on the wrong side of any edge (x/y)
582         //2) if it does, nudge it onto the correct side.
583
584         if (worldverts!=NULL && lightmapTriangleCheck)
585         {
586                 for (j=0;j<3;j++)
587                 {
588                         VectorCopy(worldverts[j],cverts[j]);
589                 }
590                 PlaneFromPoints(hostplane,cverts[0],cverts[1],cverts[2]);
591
592                 for (j=0;j<3;j++)
593                 {
594                         for (i=0;i<3;i++)
595                         {
596                                 //build plane using 2 edges and a normal
597                                 next=(i+1)%3;
598
599                                 VectorCopy(cverts[next],temp);
600                                 VectorAdd(temp,hostplane,temp);
601                                 PlaneFromPoints(sideplane,cverts[i],cverts[ next ], temp);
602
603                                 //planetest sample point
604                                 e=DotProduct(origin,sideplane);
605                                 e=e-sideplane[3];
606                                 if (e>0)
607                                 {
608                                         //we're bad.
609                                         //VectorClear(origin);
610                                         //Move the sample point back inside triangle bounds
611                                         origin[0]-=sideplane[0]*(e+1);
612                                         origin[1]-=sideplane[1]*(e+1);
613                                         origin[2]-=sideplane[2]*(e+1);
614 #ifdef DEBUG_27_1
615                                         VectorClear(origin);
616 #endif
617                                 }
618                         }
619                 }
620         }
621
622         ////////////////////////
623         
624         /* planar surfaces have precalculated lightmap vectors for nudging */
625         if( lm->plane != NULL )
626         {
627                 VectorCopy( lm->vecs[ 0 ], vecs[ 0 ] );
628                 VectorCopy( lm->vecs[ 1 ], vecs[ 1 ] );
629                 VectorCopy( lm->plane, vecs[ 2 ] );
630         }
631         
632         /* non-planar surfaces must calculate them */
633         else
634         {
635                 if( plane != NULL )
636                         VectorCopy( plane, vecs[ 2 ] );
637                 else
638                         VectorCopy( dv->normal, vecs[ 2 ] );
639                 MakeNormalVectors( vecs[ 2 ], vecs[ 0 ], vecs[ 1 ] );
640         }
641         
642         /* push the origin off the surface a bit */
643         if( si != NULL )
644                 lightmapSampleOffset = si->lightmapSampleOffset;
645         else
646                 lightmapSampleOffset = DEFAULT_LIGHTMAP_SAMPLE_OFFSET;
647         if( lm->axisNum < 0 )
648                 VectorMA( origin, lightmapSampleOffset, vecs[ 2 ], origin );
649         else if( vecs[ 2 ][ lm->axisNum ] < 0.0f )
650                 origin[ lm->axisNum ] -= lightmapSampleOffset;
651         else
652                 origin[ lm->axisNum ] += lightmapSampleOffset;
653         
654         VectorCopy(origin,origintwo);
655         if(lightmapExtraVisClusterNudge)
656         {
657                 origintwo[0]+=vecs[2][0];
658                 origintwo[1]+=vecs[2][1];
659                 origintwo[2]+=vecs[2][2];
660         }
661
662         /* get cluster */
663         pointCluster = ClusterForPointExtFilter( origintwo, LUXEL_EPSILON, numClusters, clusters );
664         
665         /* another retarded hack, storing nudge count in luxel[ 1 ] */
666         luxel[ 1 ] = 0.0f;      
667         
668         /* point in solid? (except in dark mode) */
669         if( pointCluster < 0 && dark == qfalse )
670         {
671                 /* nudge the the location around */
672                 nudge = nudges[ 0 ];
673                 while( nudge[ 0 ] > BOGUS_NUDGE && pointCluster < 0 )
674                 {
675                         /* nudge the vector around a bit */
676                         for( i = 0; i < 3; i++ )
677                         {
678                                 /* set nudged point*/
679                                 nudged[ i ] = origintwo[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
680                         }
681                         nudge += 2;
682                         
683                         /* get pvs cluster */
684                         pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); //% + 0.625 );
685                         if( pointCluster >= 0 )
686                                 VectorCopy( nudged, origin );
687                         luxel[ 1 ] += 1.0f;
688                 }
689         }
690         
691         /* as a last resort, if still in solid, try drawvert origin offset by normal (except in dark mode) */
692         if( pointCluster < 0 && si != NULL && dark == qfalse )
693         {
694                 VectorMA( dv->xyz, lightmapSampleOffset, dv->normal, nudged );
695                 pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters );
696                 if( pointCluster >= 0 )
697                         VectorCopy( nudged, origin );
698                 luxel[ 1 ] += 1.0f;
699         }
700         
701         /* valid? */
702         if( pointCluster < 0 )
703         {
704                 (*cluster) = CLUSTER_OCCLUDED;
705                 VectorClear( origin );
706                 VectorClear( normal );
707                 numLuxelsOccluded++;
708                 return (*cluster);
709         }
710         
711         /* debug code */
712         //%     Sys_Printf( "%f %f %f\n", origin[ 0 ], origin[ 1 ], origin[ 2 ] );
713         
714         /* do bumpmap calculations */
715         if( stv )
716                 PerturbNormal( dv, si, pNormal, stv, ttv );
717         else
718                 VectorCopy( dv->normal, pNormal );
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 {
745         bspDrawVert_t   mid, *dv2[ 3 ];
746         int                             max;
747         
748         
749         /* map the vertexes */
750         #if 0
751         MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
752         MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
753         MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
754         #endif
755         
756         /* subdivide calc */
757         {
758                 int                     i;
759                 float           *a, *b, dx, dy, dist, maxDist;
760                 
761                 
762                 /* find the longest edge and split it */
763                 max = -1;
764                 maxDist = 0;
765                 for( i = 0; i < 3; i++ )
766                 {
767                         /* get verts */
768                         a = dv[ i ]->lightmap[ 0 ];
769                         b = dv[ (i + 1) % 3 ]->lightmap[ 0 ];
770                         
771                         /* get dists */
772                         dx = a[ 0 ] - b[ 0 ];
773                         dy = a[ 1 ] - b[ 1 ];
774                         dist = (dx * dx) + (dy * dy);   //% sqrt( (dx * dx) + (dy * dy) );
775                         
776                         /* longer? */
777                         if( dist > maxDist )
778                         {
779                                 maxDist = dist;
780                                 max = i;
781                         }
782                 }
783                 
784                 /* try to early out */
785                 if( max < 0 || maxDist <= subdivideThreshold )  /* ydnar: was i < 0 instead of max < 0 (?) */
786                         return;
787         }
788         
789         /* split the longest edge and map it */
790         LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid );
791         MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv, worldverts );
792         
793         /* push the point up a little bit to account for fp creep (fixme: revisit this) */
794         //%     VectorMA( mid.xyz, 2.0f, mid.normal, mid.xyz );
795         
796         /* recurse to first triangle */
797         VectorCopy( dv, dv2 );
798         dv2[ max ] = &mid;
799         MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
800         
801         /* recurse to second triangle */
802         VectorCopy( dv, dv2 );
803         dv2[ (max + 1) % 3 ] = &mid;
804         MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
805 }
806
807
808
809 /*
810 MapTriangle()
811 seed function for MapTriangle_r()
812 requires a cw ordered triangle
813 */
814
815 static qboolean MapTriangle( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 3 ], qboolean mapNonAxial )
816 {
817         int                             i;
818         vec4_t                  plane;
819         vec3_t                  *stv, *ttv, stvStatic[ 3 ], ttvStatic[ 3 ];
820         vec3_t                  worldverts[ 3 ];
821         
822         
823         /* get plane if possible */
824         if( lm->plane != NULL )
825         {
826                 VectorCopy( lm->plane, plane );
827                 plane[ 3 ] = lm->plane[ 3 ];
828         }
829         
830         /* otherwise make one from the points */
831         else if( PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) == qfalse )
832                 return qfalse;
833         
834         /* check to see if we need to calculate texture->world tangent vectors */
835         if( info->si->normalImage != NULL && CalcTangentVectors( 3, dv, stvStatic, ttvStatic ) )
836         {
837                 stv = stvStatic;
838                 ttv = ttvStatic;
839         }
840         else
841         {
842                 stv = NULL;
843                 ttv = NULL;
844         }
845         
846         VectorCopy( dv[ 0 ]->xyz, worldverts[ 0 ] );
847         VectorCopy( dv[ 1 ]->xyz, worldverts[ 1 ] );
848         VectorCopy( dv[ 2 ]->xyz, worldverts[ 2 ] );
849
850         /* map the vertexes */
851         MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, worldverts );
852         MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, worldverts );
853         MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, worldverts );
854         
855         /* 2002-11-20: prefer axial triangle edges */
856         if( mapNonAxial )
857         {
858                 /* subdivide the triangle */
859                 MapTriangle_r( lm, info, dv, plane, stv, ttv, worldverts );
860                 return qtrue;
861         }
862         
863         for( i = 0; i < 3; i++ )
864         {
865                 float                   *a, *b;
866                 bspDrawVert_t   *dv2[ 3 ];
867                 
868                 
869                 /* get verts */
870                 a = dv[ i ]->lightmap[ 0 ];
871                 b = dv[ (i + 1) % 3 ]->lightmap[ 0 ];
872                 
873                 /* make degenerate triangles for mapping edges */
874                 if( fabs( a[ 0 ] - b[ 0 ] ) < 0.01f || fabs( a[ 1 ] - b[ 1 ] ) < 0.01f )
875                 {
876                         dv2[ 0 ] = dv[ i ];
877                         dv2[ 1 ] = dv[ (i + 1) % 3 ];
878                         dv2[ 2 ] = dv[ (i + 1) % 3 ];
879                         
880                         /* map the degenerate triangle */
881                         MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
882                 }
883         }
884         
885         return qtrue;
886 }
887
888
889
890 /*
891 MapQuad_r()
892 recursively subdivides a quad until its edges are shorter
893 than the distance between two luxels
894 */
895
896 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 ] )
897 {
898         bspDrawVert_t   mid[ 2 ], *dv2[ 4 ];
899         int                             max;
900         
901         
902         /* subdivide calc */
903         {
904                 int                     i;
905                 float           *a, *b, dx, dy, dist, maxDist;
906                 
907                 
908                 /* find the longest edge and split it */
909                 max = -1;
910                 maxDist = 0;
911                 for( i = 0; i < 4; i++ )
912                 {
913                         /* get verts */
914                         a = dv[ i ]->lightmap[ 0 ];
915                         b = dv[ (i + 1) % 4 ]->lightmap[ 0 ];
916                         
917                         /* get dists */
918                         dx = a[ 0 ] - b[ 0 ];
919                         dy = a[ 1 ] - b[ 1 ];
920                         dist = (dx * dx) + (dy * dy);   //% sqrt( (dx * dx) + (dy * dy) );
921                         
922                         /* longer? */
923                         if( dist > maxDist )
924                         {
925                                 maxDist = dist;
926                                 max = i;
927                         }
928                 }
929                 
930                 /* try to early out */
931                 if( max < 0 || maxDist <= subdivideThreshold )
932                         return;
933         }
934         
935         /* we only care about even/odd edges */
936         max &= 1;
937         
938         /* split the longest edges */
939         LerpDrawVert( dv[ max ], dv[ (max + 1) % 4 ], &mid[ 0 ] );
940         LerpDrawVert( dv[ max + 2 ], dv[ (max + 3) % 4 ], &mid[ 1 ] );
941         
942         /* map the vertexes */
943         MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv, NULL );
944         MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv, NULL );
945         
946         /* 0 and 2 */
947         if( max == 0 )
948         {
949                 /* recurse to first quad */
950                 dv2[ 0 ] = dv[ 0 ];
951                 dv2[ 1 ] = &mid[ 0 ];
952                 dv2[ 2 ] = &mid[ 1 ];
953                 dv2[ 3 ] = dv[ 3 ];
954                 MapQuad_r( lm, info, dv2, plane, stv, ttv );
955                 
956                 /* recurse to second quad */
957                 dv2[ 0 ] = &mid[ 0 ];
958                 dv2[ 1 ] = dv[ 1 ];
959                 dv2[ 2 ] = dv[ 2 ];
960                 dv2[ 3 ] = &mid[ 1 ];
961                 MapQuad_r( lm, info, dv2, plane, stv, ttv );
962         }
963         
964         /* 1 and 3 */
965         else
966         {
967                 /* recurse to first quad */
968                 dv2[ 0 ] = dv[ 0 ];
969                 dv2[ 1 ] = dv[ 1 ];
970                 dv2[ 2 ] = &mid[ 0 ];
971                 dv2[ 3 ] = &mid[ 1 ];
972                 MapQuad_r( lm, info, dv2, plane, stv, ttv );
973                 
974                 /* recurse to second quad */
975                 dv2[ 0 ] = &mid[ 1 ];
976                 dv2[ 1 ] = &mid[ 0 ];
977                 dv2[ 2 ] = dv[ 2 ];
978                 dv2[ 3 ] = dv[ 3 ];
979                 MapQuad_r( lm, info, dv2, plane, stv, ttv );
980         }
981 }
982
983
984
985 /*
986 MapQuad()
987 seed function for MapQuad_r()
988 requires a cw ordered triangle quad
989 */
990
991 #define QUAD_PLANAR_EPSILON             0.5f
992
993 static qboolean MapQuad( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 4 ] )
994 {
995         float                   dist;
996         vec4_t                  plane;
997         vec3_t                  *stv, *ttv, stvStatic[ 4 ], ttvStatic[ 4 ];
998         
999         
1000         /* get plane if possible */
1001         if( lm->plane != NULL )
1002         {
1003                 VectorCopy( lm->plane, plane );
1004                 plane[ 3 ] = lm->plane[ 3 ];
1005         }
1006         
1007         /* otherwise make one from the points */
1008         else if( PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) == qfalse )
1009                 return qfalse;
1010         
1011         /* 4th point must fall on the plane */
1012         dist = DotProduct( plane, dv[ 3 ]->xyz ) - plane[ 3 ];
1013         if( fabs( dist ) > QUAD_PLANAR_EPSILON )
1014                 return qfalse;
1015         
1016         /* check to see if we need to calculate texture->world tangent vectors */
1017         if( info->si->normalImage != NULL && CalcTangentVectors( 4, dv, stvStatic, ttvStatic ) )
1018         {
1019                 stv = stvStatic;
1020                 ttv = ttvStatic;
1021         }
1022         else
1023         {
1024                 stv = NULL;
1025                 ttv = NULL;
1026         }
1027         
1028         /* map the vertexes */
1029         MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, NULL );
1030         MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, NULL );
1031         MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, NULL );
1032         MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv, NULL );
1033         
1034         /* subdivide the quad */
1035         MapQuad_r( lm, info, dv, plane, stv, ttv );
1036         return qtrue;
1037 }
1038
1039
1040
1041 /*
1042 MapRawLightmap()
1043 maps the locations, normals, and pvs clusters for a raw lightmap
1044 */
1045
1046 #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)
1047
1048 void MapRawLightmap( int rawLightmapNum )
1049 {
1050         int                                     n, num, i, x, y, sx, sy, pw[ 5 ], r, *cluster, mapNonAxial;
1051         float                           *luxel, *origin, *normal, samples, radius, pass;
1052         rawLightmap_t           *lm;
1053         bspDrawSurface_t        *ds;
1054         surfaceInfo_t           *info;
1055         mesh_t                          src, *subdivided, *mesh;
1056         bspDrawVert_t           *verts, *dv[ 4 ], fake;
1057         
1058         
1059         /* bail if this number exceeds the number of raw lightmaps */
1060         if( rawLightmapNum >= numRawLightmaps )
1061                 return;
1062         
1063         /* get lightmap */
1064         lm = &rawLightmaps[ rawLightmapNum ];
1065         
1066         /* -----------------------------------------------------------------
1067            map referenced surfaces onto the raw lightmap
1068            ----------------------------------------------------------------- */
1069         
1070         /* walk the list of surfaces on this raw lightmap */
1071         for( n = 0; n < lm->numLightSurfaces; n++ )
1072         {
1073                 /* with > 1 surface per raw lightmap, clear occluded */
1074                 if( n > 0 )
1075                 {
1076                         for( y = 0; y < lm->sh; y++ )
1077                         {
1078                                 for( x = 0; x < lm->sw; x++ )
1079                                 {
1080                                         /* get cluster */
1081                                         cluster = SUPER_CLUSTER( x, y );
1082                                         if( *cluster < 0 )
1083                                                 *cluster = CLUSTER_UNMAPPED;
1084                                 }
1085                         }
1086                 }
1087                 
1088                 /* get surface */
1089                 num = lightSurfaces[ lm->firstLightSurface + n ];
1090                 ds = &bspDrawSurfaces[ num ];
1091                 info = &surfaceInfos[ num ];
1092                 
1093                 /* bail if no lightmap to calculate */
1094                 if( info->lm != lm )
1095                 {
1096                         Sys_Printf( "!" );
1097                         continue;
1098                 }
1099                 
1100                 /* map the surface onto the lightmap origin/cluster/normal buffers */
1101                 switch( ds->surfaceType )
1102                 {
1103                         case MST_PLANAR:
1104                                 /* get verts */
1105                                 verts = yDrawVerts + ds->firstVert;
1106                                 
1107                                 /* map the triangles */
1108                                 for( mapNonAxial = 0; mapNonAxial < 2; mapNonAxial++ )
1109                                 {
1110                                         for( i = 0; i < ds->numIndexes; i += 3 )
1111                                         {
1112                                                 dv[ 0 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i ] ];
1113                                                 dv[ 1 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 1 ] ];
1114                                                 dv[ 2 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 2 ] ];
1115                                                 MapTriangle( lm, info, dv, mapNonAxial );
1116                                         }
1117                                 }
1118                                 break;
1119                         
1120                         case MST_PATCH:
1121                                 /* make a mesh from the drawsurf */ 
1122                                 src.width = ds->patchWidth;
1123                                 src.height = ds->patchHeight;
1124                                 src.verts = &yDrawVerts[ ds->firstVert ];
1125                                 //%     subdivided = SubdivideMesh( src, 8, 512 );
1126                                 subdivided = SubdivideMesh2( src, info->patchIterations );
1127                                 
1128                                 /* fit it to the curve and remove colinear verts on rows/columns */
1129                                 PutMeshOnCurve( *subdivided );
1130                                 mesh = RemoveLinearMeshColumnsRows( subdivided );
1131                                 FreeMesh( subdivided );
1132                                 
1133                                 /* get verts */
1134                                 verts = mesh->verts;
1135                                 
1136                                 /* debug code */
1137                                 #if 0
1138                                         if( lm->plane )
1139                                         {
1140                                                 Sys_Printf( "Planar patch: [%1.3f %1.3f %1.3f] [%1.3f %1.3f %1.3f] [%1.3f %1.3f %1.3f]\n",
1141                                                         lm->plane[ 0 ], lm->plane[ 1 ], lm->plane[ 2 ],
1142                                                         lm->vecs[ 0 ][ 0 ], lm->vecs[ 0 ][ 1 ], lm->vecs[ 0 ][ 2 ],
1143                                                         lm->vecs[ 1 ][ 0 ], lm->vecs[ 1 ][ 1 ], lm->vecs[ 1 ][ 2 ] );
1144                                         }
1145                                 #endif
1146                                 
1147                                 /* map the mesh quads */
1148                                 #if 0
1149
1150                                 for( mapNonAxial = 0; mapNonAxial < 2; mapNonAxial++ )
1151                                 {
1152                                         for( y = 0; y < (mesh->height - 1); y++ )
1153                                         {
1154                                                 for( x = 0; x < (mesh->width - 1); x++ )
1155                                                 {
1156                                                         /* set indexes */
1157                                                         pw[ 0 ] = x + (y * mesh->width);
1158                                                         pw[ 1 ] = x + ((y + 1) * mesh->width);
1159                                                         pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
1160                                                         pw[ 3 ] = x + 1 + (y * mesh->width);
1161                                                         pw[ 4 ] = x + (y * mesh->width);        /* same as pw[ 0 ] */
1162                                                         
1163                                                         /* set radix */
1164                                                         r = (x + y) & 1;
1165                                                         
1166                                                         /* get drawverts and map first triangle */
1167                                                         dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1168                                                         dv[ 1 ] = &verts[ pw[ r + 1 ] ];
1169                                                         dv[ 2 ] = &verts[ pw[ r + 2 ] ];
1170                                                         MapTriangle( lm, info, dv, mapNonAxial );
1171                                                         
1172                                                         /* get drawverts and map second triangle */
1173                                                         dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1174                                                         dv[ 1 ] = &verts[ pw[ r + 2 ] ];
1175                                                         dv[ 2 ] = &verts[ pw[ r + 3 ] ];
1176                                                         MapTriangle( lm, info, dv, mapNonAxial );
1177                                                 }
1178                                         }
1179                                 }
1180                                 
1181                                 #else
1182                                 
1183                                 for( y = 0; y < (mesh->height - 1); y++ )
1184                                 {
1185                                         for( x = 0; x < (mesh->width - 1); x++ )
1186                                         {
1187                                                 /* set indexes */
1188                                                 pw[ 0 ] = x + (y * mesh->width);
1189                                                 pw[ 1 ] = x + ((y + 1) * mesh->width);
1190                                                 pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
1191                                                 pw[ 3 ] = x + 1 + (y * mesh->width);
1192                                                 pw[ 4 ] = pw[ 0 ];
1193                                                 
1194                                                 /* set radix */
1195                                                 r = (x + y) & 1;
1196                                                 
1197                                                 /* attempt to map quad first */
1198                                                 dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1199                                                 dv[ 1 ] = &verts[ pw[ r + 1 ] ];
1200                                                 dv[ 2 ] = &verts[ pw[ r + 2 ] ];
1201                                                 dv[ 3 ] = &verts[ pw[ r + 3 ] ];
1202                                                 if( MapQuad( lm, info, dv ) )
1203                                                         continue;
1204                                                 
1205                                                 /* get drawverts and map first triangle */
1206                                                 MapTriangle( lm, info, dv, mapNonAxial );
1207                                                 
1208                                                 /* get drawverts and map second triangle */
1209                                                 dv[ 1 ] = &verts[ pw[ r + 2 ] ];
1210                                                 dv[ 2 ] = &verts[ pw[ r + 3 ] ];
1211                                                 MapTriangle( lm, info, dv, mapNonAxial );
1212                                         }
1213                                 }
1214                                 
1215                                 #endif
1216                                 
1217                                 /* free the mesh */
1218                                 FreeMesh( mesh );
1219                                 break;
1220                         
1221                         default:
1222                                 break;
1223                 }
1224         }
1225         
1226         /* -----------------------------------------------------------------
1227            average and clean up luxel normals
1228            ----------------------------------------------------------------- */
1229         
1230         /* walk the luxels */
1231         for( y = 0; y < lm->sh; y++ )
1232         {
1233                 for( x = 0; x < lm->sw; x++ )
1234                 {
1235                         /* get luxel */
1236                         luxel = SUPER_LUXEL( 0, x, y );
1237                         normal = SUPER_NORMAL( x, y );
1238                         cluster = SUPER_CLUSTER( x, y );
1239
1240                         /* only look at mapped luxels */
1241                         if( *cluster < 0 )
1242                                 continue;
1243                         
1244                         /* the normal data could be the sum of multiple samples */
1245                         if( luxel[ 3 ] > 1.0f )
1246                                 VectorNormalize( normal, normal );
1247                         
1248                         /* mark this luxel as having only one normal */
1249                         luxel[ 3 ] = 1.0f;
1250                 }
1251         }
1252         
1253         /* non-planar surfaces stop here */
1254         if( lm->plane == NULL )
1255                 return;
1256         
1257         /* -----------------------------------------------------------------
1258            map occluded or unuxed luxels
1259            ----------------------------------------------------------------- */
1260         
1261         /* walk the luxels */
1262         radius = floor( superSample / 2 );
1263         radius = radius > 0 ? radius : 1.0f;
1264         radius += 1.0f;
1265         for( pass = 2.0f; pass <= radius; pass += 1.0f )
1266         {
1267                 for( y = 0; y < lm->sh; y++ )
1268                 {
1269                         for( x = 0; x < lm->sw; x++ )
1270                         {
1271                                 /* get luxel */
1272                                 luxel = SUPER_LUXEL( 0, x, y );
1273                                 normal = SUPER_NORMAL( x, y );
1274                                 cluster = SUPER_CLUSTER( x, y );
1275                                 
1276                                 /* only look at unmapped luxels */
1277                                 if( *cluster != CLUSTER_UNMAPPED )
1278                                         continue;
1279                                 
1280                                 /* 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                                         for( sx = (x - 1); sx <= (x + 1); sx++ )
1292                                         {
1293                                                 if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
1294                                                         continue;
1295                                                 
1296                                                 /* get neighboring luxel */
1297                                                 luxel = SUPER_LUXEL( 0, sx, sy );
1298                                                 origin = SUPER_ORIGIN( sx, sy );
1299                                                 normal = SUPER_NORMAL( sx, sy );
1300                                                 cluster = SUPER_CLUSTER( sx, sy );
1301                                                 
1302                                                 /* only consider luxels mapped in previous passes */
1303                                                 if( *cluster < 0 || luxel[ 0 ] >= pass )
1304                                                         continue;
1305                                                 
1306                                                 /* add its distinctiveness to our own */
1307                                                 VectorAdd( fake.xyz, origin, fake.xyz );
1308                                                 VectorAdd( fake.normal, normal, fake.normal );
1309                                                 samples += luxel[ 3 ];
1310                                         }
1311                                 }
1312                                 
1313                                 /* any samples? */
1314                                 if( samples == 0.0f )
1315                                         continue;
1316                                 
1317                                 /* average */
1318                                 VectorDivide( fake.xyz, samples, fake.xyz );
1319                                 //%     VectorDivide( fake.normal, samples, fake.normal );
1320                                 if( VectorNormalize( fake.normal, fake.normal ) == 0.0f )
1321                                         continue;
1322                                 
1323                                 /* map the fake vert */
1324                                 MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL, NULL );
1325                         }
1326                 }
1327         }
1328         
1329         /* -----------------------------------------------------------------
1330            average and clean up luxel normals
1331            ----------------------------------------------------------------- */
1332         
1333         /* walk the luxels */
1334         for( y = 0; y < lm->sh; y++ )
1335         {
1336                 for( x = 0; x < lm->sw; x++ )
1337                 {
1338                         /* get luxel */
1339                         luxel = SUPER_LUXEL( 0, x, y );
1340                         normal = SUPER_NORMAL( x, y );
1341                         cluster = SUPER_CLUSTER( x, y );
1342                         
1343                         /* only look at mapped luxels */
1344                         if( *cluster < 0 )
1345                                 continue;
1346                         
1347                         /* the normal data could be the sum of multiple samples */
1348                         if( luxel[ 3 ] > 1.0f )
1349                                 VectorNormalize( normal, normal );
1350                         
1351                         /* mark this luxel as having only one normal */
1352                         luxel[ 3 ] = 1.0f;
1353                 }
1354         }
1355         
1356         /* debug code */
1357         #if 0
1358                 Sys_Printf( "\n" );
1359                 for( y = 0; y < lm->sh; y++ )
1360                 {
1361                         for( x = 0; x < lm->sw; x++ )
1362                         {
1363                                 vec3_t  mins, maxs;
1364                                 
1365
1366                                 cluster = SUPER_CLUSTER( x, y );
1367                                 origin = SUPER_ORIGIN( x, y );
1368                                 normal = SUPER_NORMAL( x, y );
1369                                 luxel = SUPER_LUXEL( x, y );
1370                                 
1371                                 if( *cluster < 0 )
1372                                         continue;
1373                                 
1374                                 /* check if within the bounding boxes of all surfaces referenced */
1375                                 ClearBounds( mins, maxs );
1376                                 for( n = 0; n < lm->numLightSurfaces; n++ )
1377                                 {
1378                                         int TOL;
1379                                         info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + n ] ];
1380                                         TOL = info->sampleSize + 2;
1381                                         AddPointToBounds( info->mins, mins, maxs );
1382                                         AddPointToBounds( info->maxs, mins, maxs );
1383                                         if( origin[ 0 ] > (info->mins[ 0 ] - TOL) && origin[ 0 ] < (info->maxs[ 0 ] + TOL) &&
1384                                                 origin[ 1 ] > (info->mins[ 1 ] - TOL) && origin[ 1 ] < (info->maxs[ 1 ] + TOL) &&
1385                                                 origin[ 2 ] > (info->mins[ 2 ] - TOL) && origin[ 2 ] < (info->maxs[ 2 ] + TOL) )
1386                                                 break;
1387                                 }
1388                                 
1389                                 /* inside? */
1390                                 if( n < lm->numLightSurfaces )
1391                                         continue;
1392                                 
1393                                 /* report bogus origin */
1394                                 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",
1395                                         rawLightmapNum, x, y, *cluster,
1396                                         origin[ 0 ], origin[ 1 ], origin[ 2 ],
1397                                         mins[ 0 ], mins[ 1 ], mins[ 2 ],
1398                                         maxs[ 0 ], maxs[ 1 ], maxs[ 2 ],
1399                                         luxel[ 3 ] );
1400                         }
1401                 }
1402         #endif
1403 }
1404
1405
1406
1407 /*
1408 SetupDirt()
1409 sets up dirtmap (ambient occlusion)
1410 */
1411
1412 #define DIRT_CONE_ANGLE                         88      /* degrees */
1413 #define DIRT_NUM_ANGLE_STEPS            16
1414 #define DIRT_NUM_ELEVATION_STEPS        3
1415 #define DIRT_NUM_VECTORS                        (DIRT_NUM_ANGLE_STEPS * DIRT_NUM_ELEVATION_STEPS)
1416
1417 static vec3_t           dirtVectors[ DIRT_NUM_VECTORS ];
1418 static int                      numDirtVectors = 0;
1419
1420 void SetupDirt( void )
1421 {
1422         int             i, j;
1423         float   angle, elevation, angleStep, elevationStep;
1424         
1425         
1426         /* note it */
1427         Sys_FPrintf( SYS_VRB, "--- SetupDirt ---\n" );
1428         
1429         /* calculate angular steps */
1430         angleStep = DEG2RAD( 360.0f / DIRT_NUM_ANGLE_STEPS );
1431         elevationStep = DEG2RAD( DIRT_CONE_ANGLE / DIRT_NUM_ELEVATION_STEPS );
1432         
1433         /* iterate angle */
1434         angle = 0.0f;
1435         for( i = 0, angle = 0.0f; i < DIRT_NUM_ANGLE_STEPS; i++, angle += angleStep )
1436         {
1437                 /* iterate elevation */
1438                 for( j = 0, elevation = elevationStep * 0.5f; j < DIRT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep )
1439                 {
1440                         dirtVectors[ numDirtVectors ][ 0 ] = sin( elevation ) * cos( angle );
1441                         dirtVectors[ numDirtVectors ][ 1 ] = sin( elevation ) * sin( angle );
1442                         dirtVectors[ numDirtVectors ][ 2 ] = cos( elevation );
1443                         numDirtVectors++;
1444                 }
1445         }
1446         
1447         /* emit some statistics */
1448         Sys_FPrintf( SYS_VRB, "%9d dirtmap vectors\n", numDirtVectors );
1449 }
1450
1451
1452 /*
1453 DirtForSample()
1454 calculates dirt value for a given sample
1455 */
1456
1457 float DirtForSample( trace_t *trace )
1458 {
1459         int             i;
1460         float   gatherDirt, outDirt, angle, elevation, ooDepth;
1461         vec3_t  normal, worldUp, myUp, myRt, temp, direction, displacement;
1462         
1463         
1464         /* dummy check */
1465         if( !dirty )
1466                 return 1.0f;
1467         if( trace == NULL || trace->cluster < 0 )
1468                 return 0.0f;
1469         
1470         /* setup */
1471         gatherDirt = 0.0f;
1472         ooDepth = 1.0f / dirtDepth;
1473         VectorCopy( trace->normal, normal );
1474         
1475         /* check if the normal is aligned to the world-up */
1476         if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f )
1477         {
1478                 if( normal[ 2 ] == 1.0f )               
1479                 {
1480                         VectorSet( myRt, 1.0f, 0.0f, 0.0f );
1481                         VectorSet( myUp, 0.0f, 1.0f, 0.0f );
1482                 }
1483                 else if( normal[ 2 ] == -1.0f )
1484                 {
1485                         VectorSet( myRt, -1.0f, 0.0f, 0.0f );
1486                         VectorSet( myUp,  0.0f, 1.0f, 0.0f );
1487                 }
1488         }
1489         else
1490         {
1491                 VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
1492                 CrossProduct( normal, worldUp, myRt );
1493                 VectorNormalize( myRt, myRt );
1494                 CrossProduct( myRt, normal, myUp );
1495                 VectorNormalize( myUp, myUp );
1496         }
1497         
1498         /* 1 = random mode, 0 (well everything else) = non-random mode */
1499         if( dirtMode == 1 )
1500         {
1501                 /* iterate */
1502                 for( i = 0; i < numDirtVectors; i++ )
1503                 {
1504                         /* get random vector */
1505                         angle = Random() * DEG2RAD( 360.0f );
1506                         elevation = Random() * DEG2RAD( DIRT_CONE_ANGLE );
1507                         temp[ 0 ] = cos( angle ) * sin( elevation );
1508                         temp[ 1 ] = sin( angle ) * sin( elevation );
1509                         temp[ 2 ] = cos( elevation );
1510                         
1511                         /* transform into tangent space */
1512                         direction[ 0 ] = myRt[ 0 ] * temp[ 0 ] + myUp[ 0 ] * temp[ 1 ] + normal[ 0 ] * temp[ 2 ];
1513                         direction[ 1 ] = myRt[ 1 ] * temp[ 0 ] + myUp[ 1 ] * temp[ 1 ] + normal[ 1 ] * temp[ 2 ];
1514                         direction[ 2 ] = myRt[ 2 ] * temp[ 0 ] + myUp[ 2 ] * temp[ 1 ] + normal[ 2 ] * temp[ 2 ];
1515                         
1516                         /* set endpoint */
1517                         VectorMA( trace->origin, dirtDepth, direction, trace->end );
1518                         SetupTrace( trace );
1519                         
1520                         /* trace */
1521                         TraceLine( trace );
1522                         if( trace->opaque )
1523                         {
1524                                 VectorSubtract( trace->hit, trace->origin, displacement );
1525                                 gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1526                         }
1527                 }
1528         }
1529         else
1530         {
1531                 /* iterate through ordered vectors */
1532                 for( i = 0; i < numDirtVectors; i++ )
1533                 {
1534                         /* transform vector into tangent space */
1535                         direction[ 0 ] = myRt[ 0 ] * dirtVectors[ i ][ 0 ] + myUp[ 0 ] * dirtVectors[ i ][ 1 ] + normal[ 0 ] * dirtVectors[ i ][ 2 ];
1536                         direction[ 1 ] = myRt[ 1 ] * dirtVectors[ i ][ 0 ] + myUp[ 1 ] * dirtVectors[ i ][ 1 ] + normal[ 1 ] * dirtVectors[ i ][ 2 ];
1537                         direction[ 2 ] = myRt[ 2 ] * dirtVectors[ i ][ 0 ] + myUp[ 2 ] * dirtVectors[ i ][ 1 ] + normal[ 2 ] * dirtVectors[ i ][ 2 ];
1538                         
1539                         /* set endpoint */
1540                         VectorMA( trace->origin, dirtDepth, direction, trace->end );
1541                         SetupTrace( trace );
1542                         
1543                         /* trace */
1544                         TraceLine( trace );
1545                         if( trace->opaque )
1546                         {
1547                                 VectorSubtract( trace->hit, trace->origin, displacement );
1548                                 gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1549                         }
1550                 }
1551         }
1552         
1553         /* direct ray */
1554         VectorMA( trace->origin, dirtDepth, normal, trace->end );
1555         SetupTrace( trace );
1556         
1557         /* trace */
1558         TraceLine( trace );
1559         if( trace->opaque )
1560         {
1561                 VectorSubtract( trace->hit, trace->origin, displacement );
1562                 gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1563         }
1564         
1565         /* early out */
1566         if( gatherDirt <= 0.0f )
1567                 return 1.0f;
1568         
1569         /* apply gain (does this even do much? heh) */
1570         outDirt = pow( gatherDirt / (numDirtVectors + 1), dirtGain );
1571         if( outDirt > 1.0f )
1572                 outDirt = 1.0f;
1573         
1574         /* apply scale */
1575         outDirt *= dirtScale;
1576         if( outDirt > 1.0f )
1577                 outDirt = 1.0f;
1578         
1579         /* return to sender */
1580         return 1.0f - outDirt;
1581 }
1582
1583
1584
1585 /*
1586 DirtyRawLightmap()
1587 calculates dirty fraction for each luxel
1588 */
1589
1590 void DirtyRawLightmap( int rawLightmapNum )
1591 {
1592         int                                     i, x, y, sx, sy, *cluster;
1593         float                           *origin, *normal, *dirt, *dirt2, average, samples;
1594         rawLightmap_t           *lm;
1595         surfaceInfo_t           *info;
1596         trace_t                         trace;
1597         
1598         
1599         /* bail if this number exceeds the number of raw lightmaps */
1600         if( rawLightmapNum >= numRawLightmaps )
1601                 return;
1602         
1603         /* get lightmap */
1604         lm = &rawLightmaps[ rawLightmapNum ];
1605         
1606         /* setup trace */
1607         trace.testOcclusion = qtrue;
1608         trace.forceSunlight = qfalse;
1609         trace.recvShadows = lm->recvShadows;
1610         trace.numSurfaces = lm->numLightSurfaces;
1611         trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
1612         trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1613         trace.testAll = qfalse;
1614         
1615         /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
1616         trace.twoSided = qfalse;
1617         for( i = 0; i < trace.numSurfaces; i++ )
1618         {
1619                 /* get surface */
1620                 info = &surfaceInfos[ trace.surfaces[ i ] ];
1621                 
1622                 /* check twosidedness */
1623                 if( info->si->twoSided )
1624                 {
1625                         trace.twoSided = qtrue;
1626                         break;
1627                 }
1628         }
1629         
1630         /* gather dirt */
1631         for( y = 0; y < lm->sh; y++ )
1632         {
1633                 for( x = 0; x < lm->sw; x++ )
1634                 {
1635                         /* get luxel */
1636                         cluster = SUPER_CLUSTER( x, y );
1637                         origin = SUPER_ORIGIN( x, y );
1638                         normal = SUPER_NORMAL( x, y );
1639                         dirt = SUPER_DIRT( x, y );
1640                         
1641                         /* set default dirt */
1642                         *dirt = 0.0f;
1643                         
1644                         /* only look at mapped luxels */
1645                         if( *cluster < 0 )
1646                                 continue;
1647                         
1648                         /* copy to trace */
1649                         trace.cluster = *cluster;
1650                         VectorCopy( origin, trace.origin );
1651                         VectorCopy( normal, trace.normal );
1652                         
1653                         /* get dirt */
1654                         *dirt = DirtForSample( &trace );
1655                 }
1656         }
1657         
1658         /* testing no filtering */
1659         //%     return;
1660         
1661         /* filter dirt */
1662         for( y = 0; y < lm->sh; y++ )
1663         {
1664                 for( x = 0; x < lm->sw; x++ )
1665                 {
1666                         /* get luxel */
1667                         cluster = SUPER_CLUSTER( x, y );
1668                         dirt = SUPER_DIRT( x, y );
1669                         
1670                         /* filter dirt by adjacency to unmapped luxels */
1671                         average = *dirt;
1672                         samples = 1.0f;
1673                         for( sy = (y - 1); sy <= (y + 1); sy++ )
1674                         {
1675                                 if( sy < 0 || sy >= lm->sh )
1676                                         continue;
1677                                 
1678                                 for( sx = (x - 1); sx <= (x + 1); sx++ )
1679                                 {
1680                                         if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
1681                                                 continue;
1682                                         
1683                                         /* get neighboring luxel */
1684                                         cluster = SUPER_CLUSTER( sx, sy );
1685                                         dirt2 = SUPER_DIRT( sx, sy );
1686                                         if( *cluster < 0 || *dirt2 <= 0.0f )
1687                                                 continue;
1688                                         
1689                                         /* add it */
1690                                         average += *dirt2;
1691                                         samples += 1.0f;
1692                                 }
1693                                 
1694                                 /* bail */
1695                                 if( samples <= 0.0f )
1696                                         break;
1697                         }
1698                         
1699                         /* bail */
1700                         if( samples <= 0.0f )
1701                                 continue;
1702                         
1703                         /* scale dirt */
1704                         *dirt = average / samples;
1705                 }
1706         }
1707 }
1708
1709
1710
1711 /*
1712 SubmapRawLuxel()
1713 calculates the pvs cluster, origin, normal of a sub-luxel
1714 */
1715
1716 static qboolean SubmapRawLuxel( rawLightmap_t *lm, int x, int y, float bx, float by, int *sampleCluster, vec3_t sampleOrigin, vec3_t sampleNormal )
1717 {
1718         int                     i, *cluster, *cluster2;
1719         float           *origin, *origin2, *normal;     //%     , *normal2;
1720         vec3_t          originVecs[ 2 ];                        //%     , normalVecs[ 2 ];
1721         
1722         
1723         /* calulate x vector */
1724         if( (x < (lm->sw - 1) && bx >= 0.0f) || (x == 0 && bx <= 0.0f) )
1725         {
1726                 cluster = SUPER_CLUSTER( x, y );
1727                 origin = SUPER_ORIGIN( x, y );
1728                 //%     normal = SUPER_NORMAL( x, y );
1729                 cluster2 = SUPER_CLUSTER( x + 1, y );
1730                 origin2 = *cluster2 < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x + 1, y );
1731                 //%     normal2 = *cluster2 < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x + 1, y );
1732         }
1733         else if( (x > 0 && bx <= 0.0f) || (x == (lm->sw - 1) && bx >= 0.0f) )
1734         {
1735                 cluster = SUPER_CLUSTER( x - 1, y );
1736                 origin = *cluster < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x - 1, y );
1737                 //%     normal = *cluster < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x - 1, y );
1738                 cluster2 = SUPER_CLUSTER( x, y );
1739                 origin2 = SUPER_ORIGIN( x, y );
1740                 //%     normal2 = SUPER_NORMAL( x, y );
1741         }
1742         else
1743                 Sys_Printf( "WARNING: Spurious lightmap S vector\n" );
1744         
1745         VectorSubtract( origin2, origin, originVecs[ 0 ] );
1746         //%     VectorSubtract( normal2, normal, normalVecs[ 0 ] );
1747         
1748         /* calulate y vector */
1749         if( (y < (lm->sh - 1) && bx >= 0.0f) || (y == 0 && bx <= 0.0f) )
1750         {
1751                 cluster = SUPER_CLUSTER( x, y );
1752                 origin = SUPER_ORIGIN( x, y );
1753                 //%     normal = SUPER_NORMAL( x, y );
1754                 cluster2 = SUPER_CLUSTER( x, y + 1 );
1755                 origin2 = *cluster2 < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x, y + 1 );
1756                 //%     normal2 = *cluster2 < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x, y + 1 );
1757         }
1758         else if( (y > 0 && bx <= 0.0f) || (y == (lm->sh - 1) && bx >= 0.0f) )
1759         {
1760                 cluster = SUPER_CLUSTER( x, y - 1 );
1761                 origin = *cluster < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x, y - 1 );
1762                 //%     normal = *cluster < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x, y - 1 );
1763                 cluster2 = SUPER_CLUSTER( x, y );
1764                 origin2 = SUPER_ORIGIN( x, y );
1765                 //%     normal2 = SUPER_NORMAL( x, y );
1766         }
1767         else
1768                 Sys_Printf( "WARNING: Spurious lightmap T vector\n" );
1769         
1770         VectorSubtract( origin2, origin, originVecs[ 1 ] );
1771         //%     VectorSubtract( normal2, normal, normalVecs[ 1 ] );
1772         
1773         /* calculate new origin */
1774         //%     VectorMA( origin, bx, originVecs[ 0 ], sampleOrigin );
1775         //%     VectorMA( sampleOrigin, by, originVecs[ 1 ], sampleOrigin );
1776         for( i = 0; i < 3; i++ )
1777                 sampleOrigin[ i ] = sampleOrigin[ i ] + (bx * originVecs[ 0 ][ i ]) + (by * originVecs[ 1 ][ i ]);
1778         
1779         /* get cluster */
1780         *sampleCluster = ClusterForPointExtFilter( sampleOrigin, (LUXEL_EPSILON * 2), lm->numLightClusters, lm->lightClusters );
1781         if( *sampleCluster < 0 )
1782                 return qfalse;
1783         
1784         /* calculate new normal */
1785         //%     VectorMA( normal, bx, normalVecs[ 0 ], sampleNormal );
1786         //%     VectorMA( sampleNormal, by, normalVecs[ 1 ], sampleNormal );
1787         //%     if( VectorNormalize( sampleNormal, sampleNormal ) <= 0.0f )
1788         //%             return qfalse;
1789         normal = SUPER_NORMAL( x, y );
1790         VectorCopy( normal, sampleNormal );
1791         
1792         /* return ok */
1793         return qtrue;
1794 }
1795
1796
1797 /*
1798 SubsampleRawLuxel_r()
1799 recursively subsamples a luxel until its color gradient is low enough or subsampling limit is reached
1800 */
1801
1802 static void SubsampleRawLuxel_r( rawLightmap_t *lm, trace_t *trace, vec3_t sampleOrigin, int x, int y, float bias, float *lightLuxel )
1803 {
1804         int                     b, samples, mapped, lighted;
1805         int                     cluster[ 4 ];
1806         vec4_t          luxel[ 4 ];
1807         vec3_t          origin[ 4 ], normal[ 4 ];
1808         float           biasDirs[ 4 ][ 2 ] = { { -1.0f, -1.0f }, { 1.0f, -1.0f }, { -1.0f, 1.0f }, { 1.0f, 1.0f } };
1809         vec3_t          color, total;
1810         
1811         
1812         /* limit check */
1813         if( lightLuxel[ 3 ] >= lightSamples )
1814                 return;
1815         
1816         /* setup */
1817         VectorClear( total );
1818         mapped = 0;
1819         lighted = 0;
1820         
1821         /* make 2x2 subsample stamp */
1822         for( b = 0; b < 4; b++ )
1823         {
1824                 /* set origin */
1825                 VectorCopy( sampleOrigin, origin[ b ] );
1826                 
1827                 /* calculate position */
1828                 if( !SubmapRawLuxel( lm, x, y, (bias * biasDirs[ b ][ 0 ]), (bias * biasDirs[ b ][ 1 ]), &cluster[ b ], origin[ b ], normal[ b ] ) )
1829                 {
1830                         cluster[ b ] = -1;
1831                         continue;
1832                 }
1833                 mapped++;
1834                 
1835                 /* increment sample count */
1836                 luxel[ b ][ 3 ] = lightLuxel[ 3 ] + 1.0f;
1837                 
1838                 /* setup trace */
1839                 trace->cluster = *cluster;
1840                 VectorCopy( origin[ b ], trace->origin );
1841                 VectorCopy( normal[ b ], trace->normal );
1842                 
1843                 /* sample light */
1844
1845                 LightContributionToSample( trace );
1846                 
1847                 /* add to totals (fixme: make contrast function) */
1848                 VectorCopy( trace->color, luxel[ b ] );
1849                 VectorAdd( total, trace->color, total );
1850                 if( (luxel[ b ][ 0 ] + luxel[ b ][ 1 ] + luxel[ b ][ 2 ]) > 0.0f )
1851                         lighted++;
1852         }
1853         
1854         /* subsample further? */
1855         if( (lightLuxel[ 3 ] + 1.0f) < lightSamples &&
1856                 (total[ 0 ] > 4.0f || total[ 1 ] > 4.0f || total[ 2 ] > 4.0f) &&
1857                 lighted != 0 && lighted != mapped )
1858         {
1859                 for( b = 0; b < 4; b++ )
1860                 {
1861                         if( cluster[ b ] < 0 )
1862                                 continue;
1863                         SubsampleRawLuxel_r( lm, trace, origin[ b ], x, y, (bias * 0.25f), luxel[ b ] );
1864                 }
1865         }
1866         
1867         /* average */
1868         //%     VectorClear( color );
1869         //%     samples = 0;
1870         VectorCopy( lightLuxel, color );
1871         samples = 1;
1872         for( b = 0; b < 4; b++ )
1873         {
1874                 if( cluster[ b ] < 0 )
1875                         continue;
1876                 VectorAdd( color, luxel[ b ], color );
1877                 samples++;
1878         }
1879         
1880         /* add to luxel */
1881         if( samples > 0 )
1882         {
1883                 /* average */
1884                 color[ 0 ] /= samples;
1885                 color[ 1 ] /= samples;
1886                 color[ 2 ] /= samples;
1887                 
1888                 /* add to color */
1889                 VectorCopy( color, lightLuxel );
1890                 lightLuxel[ 3 ] += 1.0f;
1891         }
1892 }
1893
1894
1895
1896 /*
1897 IlluminateRawLightmap()
1898 illuminates the luxels
1899 */
1900
1901 #define STACK_LL_SIZE                   (SUPER_LUXEL_SIZE * 64 * 64)
1902 #define LIGHT_LUXEL( x, y )             (lightLuxels + ((((y) * lm->sw) + (x)) * SUPER_LUXEL_SIZE))
1903
1904 void IlluminateRawLightmap( int rawLightmapNum )
1905 {
1906         int                                     i, t, x, y, sx, sy, size, llSize, luxelFilterRadius, lightmapNum;
1907         int                                     *cluster, *cluster2, mapped, lighted, totalLighted;
1908         rawLightmap_t           *lm;
1909         surfaceInfo_t           *info;
1910         qboolean                        filterColor, filterDir;
1911         float                           brightness;
1912         float                           *origin, *normal, *dirt, *luxel, *luxel2, *deluxel, *deluxel2;
1913         float                           *lightLuxels, *lightLuxel, samples, filterRadius, weight;
1914         vec3_t                          color, averageColor, total, temp, temp2;
1915         float               averageDir[4];
1916         float                           tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
1917         trace_t                         trace;
1918         float                           stackLightLuxels[ STACK_LL_SIZE ];
1919         vec3_t                          flood;
1920         float                           *floodlight;
1921         
1922         
1923         /* bail if this number exceeds the number of raw lightmaps */
1924         if( rawLightmapNum >= numRawLightmaps )
1925                 return;
1926         
1927         /* get lightmap */
1928         lm = &rawLightmaps[ rawLightmapNum ];
1929         
1930         /* setup trace */
1931         trace.testOcclusion = !noTrace;
1932         trace.forceSunlight = qfalse;
1933         trace.recvShadows = lm->recvShadows;
1934         trace.numSurfaces = lm->numLightSurfaces;
1935         trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
1936         trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1937         
1938         /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
1939         trace.twoSided = qfalse;
1940         for( i = 0; i < trace.numSurfaces; i++ )
1941         {
1942                 /* get surface */
1943                 info = &surfaceInfos[ trace.surfaces[ i ] ];
1944                 
1945                 /* check twosidedness */
1946                 if( info->si->twoSided )
1947                 {
1948                         trace.twoSided = qtrue;
1949                         break;
1950                 }
1951         }
1952         
1953         /* create a culled light list for this raw lightmap */
1954         CreateTraceLightsForBounds( lm->mins, lm->maxs, lm->plane, lm->numLightClusters, lm->lightClusters, LIGHT_SURFACES, &trace );
1955         
1956         /* -----------------------------------------------------------------
1957            fill pass
1958            ----------------------------------------------------------------- */
1959         
1960         /* set counts */
1961         numLuxelsIlluminated += (lm->sw * lm->sh);
1962         
1963         /* test debugging state */
1964         if( debugSurfaces || debugAxis || debugCluster || debugOrigin || dirtDebug || normalmap )
1965         {
1966                 /* debug fill the luxels */
1967                 for( y = 0; y < lm->sh; y++ )
1968                 {
1969                         for( x = 0; x < lm->sw; x++ )
1970                         {
1971                                 /* get cluster */
1972                                 cluster = SUPER_CLUSTER( x, y );
1973
1974                                 /* only fill mapped luxels */
1975                                 if( *cluster < 0 )
1976                                         continue;
1977                                 
1978                                 /* get particulars */
1979                                 luxel = SUPER_LUXEL( 0, x, y );
1980                                 origin = SUPER_ORIGIN( x, y );
1981                                 normal = SUPER_NORMAL( x, y );
1982                                 
1983                                 /* color the luxel with raw lightmap num? */
1984                                 if( debugSurfaces )
1985                                         VectorCopy( debugColors[ rawLightmapNum % 12 ], luxel );
1986                                 
1987                                 /* color the luxel with lightmap axis? */
1988                                 else if( debugAxis )
1989                                 {
1990                                         luxel[ 0 ] = (lm->axis[ 0 ] + 1.0f) * 127.5f;
1991                                         luxel[ 1 ] = (lm->axis[ 1 ] + 1.0f) * 127.5f;
1992                                         luxel[ 2 ] = (lm->axis[ 2 ] + 1.0f) * 127.5f;
1993                                 }
1994                                 
1995                                 /* color the luxel with luxel cluster? */
1996                                 else if( debugCluster )
1997                                         VectorCopy( debugColors[ *cluster % 12 ], luxel );
1998                                 
1999                                 /* color the luxel with luxel origin? */
2000                                 else if( debugOrigin )
2001                                 {
2002                                         VectorSubtract( lm->maxs, lm->mins, temp );
2003                                         VectorScale( temp, (1.0f / 255.0f), temp );
2004                                         VectorSubtract( origin, lm->mins, temp2 );
2005                                         luxel[ 0 ] = lm->mins[ 0 ] + (temp[ 0 ] * temp2[ 0 ]);
2006                                         luxel[ 1 ] = lm->mins[ 1 ] + (temp[ 1 ] * temp2[ 1 ]);
2007                                         luxel[ 2 ] = lm->mins[ 2 ] + (temp[ 2 ] * temp2[ 2 ]);
2008                                 }
2009                                 
2010                                 /* color the luxel with the normal */
2011                                 else if( normalmap )
2012                                 {
2013                                         luxel[ 0 ] = (normal[ 0 ] + 1.0f) * 127.5f;
2014                                         luxel[ 1 ] = (normal[ 1 ] + 1.0f) * 127.5f;
2015                                         luxel[ 2 ] = (normal[ 2 ] + 1.0f) * 127.5f;
2016                                 }
2017                                 
2018                                 /* otherwise clear it */
2019                                 else
2020                                         VectorClear( luxel );
2021                                 
2022                                 /* add to counts */
2023                                 luxel[ 3 ] = 1.0f;
2024                         }
2025                 }
2026         }
2027         else
2028         {
2029                 /* allocate temporary per-light luxel storage */
2030                 llSize = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
2031                 if( llSize <= (STACK_LL_SIZE * sizeof( float )) )
2032                         lightLuxels = stackLightLuxels;
2033                 else
2034                         lightLuxels = safe_malloc( llSize );
2035                 
2036                 /* clear luxels */
2037                 //%     memset( lm->superLuxels[ 0 ], 0, llSize );
2038                 
2039                 /* set ambient color */
2040                 for( y = 0; y < lm->sh; y++ )
2041                 {
2042                         for( x = 0; x < lm->sw; x++ )
2043                         {
2044                                 /* get cluster */
2045                                 cluster = SUPER_CLUSTER( x, y );
2046                                 luxel = SUPER_LUXEL( 0, x, y );
2047                                 normal = SUPER_NORMAL( x, y );
2048                                 deluxel = SUPER_DELUXEL( x, y );
2049                                 
2050                                 /* blacken unmapped clusters */
2051                                 if( *cluster < 0 )
2052                                         VectorClear( luxel );
2053                                 
2054                                 /* set ambient */
2055                                 else
2056                                 {
2057                                         VectorCopy( ambientColor, luxel );
2058                                         if( deluxemap )
2059                                         {
2060                                                 VectorScale( normal, 0.00390625f, deluxel );
2061                                                 deluxel[3] = 0.00390625f;
2062                                         }
2063                                         luxel[ 3 ] = 1.0f;
2064                                 }
2065                         }
2066                 }
2067                 
2068                 /* clear styled lightmaps */
2069                 size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
2070                 for( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2071                 {
2072                         if( lm->superLuxels[ lightmapNum ] != NULL )
2073                                 memset( lm->superLuxels[ lightmapNum ], 0, size );
2074                 }
2075                 
2076                 /* debugging code */
2077                 //%     if( trace.numLights <= 0 )
2078                 //%             Sys_Printf( "Lightmap %9d: 0 lights, axis: %.2f, %.2f, %.2f\n", rawLightmapNum, lm->axis[ 0 ], lm->axis[ 1 ], lm->axis[ 2 ] );
2079                 
2080                 /* walk light list */
2081                 for( i = 0; i < trace.numLights; i++ )
2082                 {
2083                         /* setup trace */
2084                         trace.light = trace.lights[ i ];
2085                         
2086                         /* style check */
2087                         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2088                         {
2089                                 if( lm->styles[ lightmapNum ] == trace.light->style ||
2090                                         lm->styles[ lightmapNum ] == LS_NONE )
2091                                         break;
2092                         }
2093                         
2094                         /* max of MAX_LIGHTMAPS (4) styles allowed to hit a surface/lightmap */
2095                         if( lightmapNum >= MAX_LIGHTMAPS )
2096                         {
2097                                 Sys_Printf( "WARNING: Hit per-surface style limit (%d)\n", MAX_LIGHTMAPS );
2098                                 continue;
2099                         }
2100                         
2101                         /* setup */
2102                         memset( lightLuxels, 0, llSize );
2103                         totalLighted = 0;
2104                         
2105                         /* initial pass, one sample per luxel */
2106                         for( y = 0; y < lm->sh; y++ )
2107                         {
2108                                 for( x = 0; x < lm->sw; x++ )
2109                                 {
2110                                         /* get cluster */
2111                                         cluster = SUPER_CLUSTER( x, y );
2112                                         if( *cluster < 0 )
2113                                                 continue;
2114                                         
2115                                         /* get particulars */
2116                                         lightLuxel = LIGHT_LUXEL( x, y );
2117                                         deluxel = SUPER_DELUXEL( x, y );
2118                                         origin = SUPER_ORIGIN( x, y );
2119                                         normal = SUPER_NORMAL( x, y );
2120
2121 #if 0
2122                                         ////////// 27's temp hack for testing edge clipping ////
2123                                         if( origin[0]==0 && origin[1]==0 && origin[2]==0 )
2124                                         {
2125                                                 lightLuxel[ 1 ] = 255;
2126                                                 lightLuxel[ 3 ] = 1.0f;
2127                                                 totalLighted++;
2128                                         }
2129                                         else
2130 #endif
2131                                         {
2132                                                 /* set contribution count */
2133                                                 lightLuxel[ 3 ] = 1.0f;
2134
2135                                                 /* setup trace */
2136                                                 trace.cluster = *cluster;
2137                                                 VectorCopy( origin, trace.origin );
2138                                                 VectorCopy( normal, trace.normal );
2139
2140                                                 /* get light for this sample */
2141                                                 LightContributionToSample( &trace );
2142                                                 VectorCopy( trace.color, lightLuxel );
2143
2144                                                 /* add to count */
2145                                                 if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
2146                                                         totalLighted++;
2147                                         }
2148                                         
2149                                         /* add to light direction map (fixme: use luxel normal as starting point for deluxel?) */
2150                                         if( deluxemap )
2151                                         {
2152                                                 /* color to grayscale (photoshop rgb weighting) */
2153                                                 brightness = trace.color[ 0 ] * 0.3f + trace.color[ 1 ] * 0.59f + trace.color[ 2 ] * 0.11f;
2154                                                 brightness *= (1.0 / 255.0);
2155                                                 if(brightness != 0)
2156                                                 {
2157                                                         VectorScale( trace.direction, brightness, temp );
2158                                                         VectorAdd( deluxel, temp, deluxel );
2159                                                         deluxel[3] += brightness;
2160                                                 }
2161                                         }
2162                                 }
2163                         }
2164                         
2165                         /* don't even bother with everything else if nothing was lit */
2166                         if( totalLighted == 0 )
2167                                 continue;
2168                         
2169                         /* determine filter radius */
2170                         filterRadius = lm->filterRadius > trace.light->filterRadius
2171                                 ? lm->filterRadius
2172                                 : trace.light->filterRadius;
2173                         if( filterRadius < 0.0f )
2174                                 filterRadius = 0.0f;
2175                         
2176                         /* set luxel filter radius */
2177                         luxelFilterRadius = superSample * filterRadius / lm->sampleSize;
2178                         if( luxelFilterRadius == 0 && (filterRadius > 0.0f || filter) )
2179                                 luxelFilterRadius = 1;
2180                         
2181                         /* secondary pass, adaptive supersampling (fixme: use a contrast function to determine if subsampling is necessary) */
2182                         /* 2003-09-27: changed it so filtering disamples supersampling, as it would waste time */
2183                         if( lightSamples > 1 && luxelFilterRadius == 0 )
2184                         {
2185                                 /* walk luxels */
2186                                 for( y = 0; y < (lm->sh - 1); y++ )
2187                                 {
2188                                         for( x = 0; x < (lm->sw - 1); x++ )
2189                                         {
2190                                                 /* setup */
2191                                                 mapped = 0;
2192                                                 lighted = 0;
2193                                                 VectorClear( total );
2194                                                 
2195                                                 /* test 2x2 stamp */
2196                                                 for( t = 0; t < 4; t++ )
2197                                                 {
2198                                                         /* set sample coords */
2199                                                         sx = x + tests[ t ][ 0 ];
2200                                                         sy = y + tests[ t ][ 1 ];
2201                                                         
2202                                                         /* get cluster */
2203                                                         cluster = SUPER_CLUSTER( sx, sy );
2204                                                         if( *cluster < 0 )
2205                                                                 continue;
2206                                                         mapped++;
2207                                                         
2208                                                         /* get luxel */
2209                                                         lightLuxel = LIGHT_LUXEL( sx, sy );
2210                                                         VectorAdd( total, lightLuxel, total );
2211                                                         if( (lightLuxel[ 0 ] + lightLuxel[ 1 ] + lightLuxel[ 2 ]) > 0.0f )
2212                                                                 lighted++;
2213                                                 }
2214                                                 
2215                                                 /* if total color is under a certain amount, then don't bother subsampling */
2216                                                 if( total[ 0 ] <= 4.0f && total[ 1 ] <= 4.0f && total[ 2 ] <= 4.0f )
2217                                                         continue;
2218                                                 
2219                                                 /* if all 4 pixels are either in shadow or light, then don't subsample */
2220                                                 if( lighted != 0 && lighted != mapped )
2221                                                 {
2222                                                         for( t = 0; t < 4; t++ )
2223                                                         {
2224                                                                 /* set sample coords */
2225                                                                 sx = x + tests[ t ][ 0 ];
2226                                                                 sy = y + tests[ t ][ 1 ];
2227                                                                 
2228                                                                 /* get luxel */
2229                                                                 cluster = SUPER_CLUSTER( sx, sy );
2230                                                                 if( *cluster < 0 )
2231                                                                         continue;
2232                                                                 lightLuxel = LIGHT_LUXEL( sx, sy );
2233                                                                 origin = SUPER_ORIGIN( sx, sy );
2234                                                                 
2235                                                                 /* only subsample shadowed luxels */
2236                                                                 //%     if( (lightLuxel[ 0 ] + lightLuxel[ 1 ] + lightLuxel[ 2 ]) <= 0.0f )
2237                                                                 //%             continue;
2238                                                                 
2239                                                                 /* subsample it */
2240                                                                 SubsampleRawLuxel_r( lm, &trace, origin, sx, sy, 0.25f, lightLuxel );
2241                                                                 
2242                                                                 /* debug code to colorize subsampled areas to yellow */
2243                                                                 //%     luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2244                                                                 //%     VectorSet( luxel, 255, 204, 0 );
2245                                                         }
2246                                                 }
2247                                         }
2248                                 }
2249                         }
2250                         
2251                         /* tertiary pass, apply dirt map (ambient occlusion) */
2252                         if( 0 && dirty )
2253                         {
2254                                 /* walk luxels */
2255                                 for( y = 0; y < lm->sh; y++ )
2256                                 {
2257                                         for( x = 0; x < lm->sw; x++ )
2258                                         {
2259                                                 /* get cluster  */
2260                                                 cluster = SUPER_CLUSTER( x, y );
2261                                                 if( *cluster < 0 )
2262                                                         continue;
2263                                                 
2264                                                 /* get particulars */
2265                                                 lightLuxel = LIGHT_LUXEL( x, y );
2266                                                 dirt = SUPER_DIRT( x, y );
2267                                                 
2268                                                 /* scale light value */
2269                                                 VectorScale( lightLuxel, *dirt, lightLuxel );
2270                                         }
2271                                 }
2272                         }
2273                         
2274                         /* allocate sampling lightmap storage */
2275                         if( lm->superLuxels[ lightmapNum ] == NULL )
2276                         {
2277                                 /* allocate sampling lightmap storage */
2278                                 size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
2279                                 lm->superLuxels[ lightmapNum ] = safe_malloc( size );
2280                                 memset( lm->superLuxels[ lightmapNum ], 0, size );
2281                         }
2282                         
2283                         /* set style */
2284                         if( lightmapNum > 0 )
2285                         {
2286                                 lm->styles[ lightmapNum ] = trace.light->style;
2287                                 //%     Sys_Printf( "Surface %6d has lightstyle %d\n", rawLightmapNum, trace.light->style );
2288                         }
2289                         
2290                         /* copy to permanent luxels */
2291                         for( y = 0; y < lm->sh; y++ )
2292                         {
2293                                 for( x = 0; x < lm->sw; x++ )
2294                                 {
2295                                         /* get cluster and origin */
2296                                         cluster = SUPER_CLUSTER( x, y );
2297                                         if( *cluster < 0 )
2298                                                 continue;
2299                                         origin = SUPER_ORIGIN( x, y );
2300                                         
2301                                         /* filter? */
2302                                         if( luxelFilterRadius )
2303                                         {
2304                                                 /* setup */
2305                                                 VectorClear( averageColor );
2306                                                 samples = 0.0f;
2307                                                 
2308                                                 /* cheaper distance-based filtering */
2309                                                 for( sy = (y - luxelFilterRadius); sy <= (y + luxelFilterRadius); sy++ )
2310                                                 {
2311                                                         if( sy < 0 || sy >= lm->sh )
2312                                                                 continue;
2313                                                         
2314                                                         for( sx = (x - luxelFilterRadius); sx <= (x + luxelFilterRadius); sx++ )
2315                                                         {
2316                                                                 if( sx < 0 || sx >= lm->sw )
2317                                                                         continue;
2318                                                                 
2319                                                                 /* get particulars */
2320                                                                 cluster = SUPER_CLUSTER( sx, sy );
2321                                                                 if( *cluster < 0 )
2322                                                                         continue;
2323                                                                 lightLuxel = LIGHT_LUXEL( sx, sy );
2324                                                                 
2325                                                                 /* create weight */
2326                                                                 weight = (abs( sx - x ) == luxelFilterRadius ? 0.5f : 1.0f);
2327                                                                 weight *= (abs( sy - y ) == luxelFilterRadius ? 0.5f : 1.0f);
2328                                                                 
2329                                                                 /* scale luxel by filter weight */
2330                                                                 VectorScale( lightLuxel, weight, color );
2331                                                                 VectorAdd( averageColor, color, averageColor );
2332                                                                 samples += weight;
2333                                                         }
2334                                                 }
2335                                                 
2336                                                 /* any samples? */
2337                                                 if( samples <= 0.0f     )
2338                                                         continue;
2339                                                 
2340                                                 /* scale into luxel */
2341                                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
2342                                                 luxel[ 3 ] = 1.0f;
2343                                                 
2344                                                 /* handle negative light */
2345                                                 if( trace.light->flags & LIGHT_NEGATIVE )
2346                                                 { 
2347                                                         luxel[ 0 ] -= averageColor[ 0 ] / samples;
2348                                                         luxel[ 1 ] -= averageColor[ 1 ] / samples;
2349                                                         luxel[ 2 ] -= averageColor[ 2 ] / samples;
2350                                                 }
2351                                                 
2352                                                 /* handle normal light */
2353                                                 else
2354                                                 { 
2355                                                         luxel[ 0 ] += averageColor[ 0 ] / samples;
2356                                                         luxel[ 1 ] += averageColor[ 1 ] / samples;
2357                                                         luxel[ 2 ] += averageColor[ 2 ] / samples;
2358                                                 }
2359                                         }
2360                                         
2361                                         /* single sample */
2362                                         else
2363                                         {
2364                                                 /* get particulars */
2365                                                 lightLuxel = LIGHT_LUXEL( x, y );
2366                                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
2367                                                 
2368                                                 /* handle negative light */
2369                                                 if( trace.light->flags & LIGHT_NEGATIVE )
2370                                                         VectorScale( averageColor, -1.0f, averageColor );
2371
2372                                                 /* add color */
2373                                                 luxel[ 3 ] = 1.0f;
2374                                                 
2375                                                 /* handle negative light */
2376                                                 if( trace.light->flags & LIGHT_NEGATIVE )
2377                                                         VectorSubtract( luxel, lightLuxel, luxel );
2378                                                 
2379                                                 /* handle normal light */
2380                                                 else
2381                                                         VectorAdd( luxel, lightLuxel, luxel );
2382                                         }
2383                                 }
2384                         }
2385                 }
2386                 
2387                 /* free temporary luxels */
2388                 if( lightLuxels != stackLightLuxels )
2389                         free( lightLuxels );
2390         }
2391         
2392         /* free light list */
2393         FreeTraceLights( &trace );
2394         
2395         /*      -----------------------------------------------------------------
2396                 floodlight pass
2397                 ----------------------------------------------------------------- */
2398
2399         if( floodlighty )
2400         {
2401                 /* walk lightmaps */
2402                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2403                 {
2404                         /* early out */
2405                         if( lm->superLuxels[ lightmapNum ] == NULL )
2406                                 continue;
2407
2408                         /* apply floodlight to each luxel */
2409                         for( y = 0; y < lm->sh; y++ )
2410                         {
2411                                 for( x = 0; x < lm->sw; x++ )
2412                                 {
2413                                         /* get cluster */
2414                                         cluster = SUPER_CLUSTER( x, y );
2415                                         if( *cluster < 0 )
2416                                                 continue;
2417
2418                                         /* get particulars */
2419                                         luxel = SUPER_LUXEL( lightmapNum, x, y );
2420                                         floodlight = SUPER_FLOODLIGHT( x, y );
2421
2422                                         flood[0]=floodlightRGB[0]*floodlightIntensity;
2423                                         flood[1]=floodlightRGB[1]*floodlightIntensity;
2424                                         flood[2]=floodlightRGB[2]*floodlightIntensity;
2425
2426                                         /* scale light value */
2427                                         VectorScale( flood, *floodlight, flood );
2428                                         luxel[0]+=flood[0];
2429                                         luxel[1]+=flood[1];
2430                                         luxel[2]+=flood[2];
2431
2432                                         if (luxel[3]==0) luxel[3]=1;
2433                                 }
2434                         }
2435                 }
2436         }
2437
2438         if (debugnormals)
2439         {
2440                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2441                 {
2442                         /* early out */
2443                         if( lm->superLuxels[ lightmapNum ] == NULL )
2444                                 continue;
2445
2446                         for( y = 0; y < lm->sh; y++ )
2447                         {
2448                                 for( x = 0; x < lm->sw; x++ )
2449                                 {
2450                                         /* get cluster */
2451                                         cluster = SUPER_CLUSTER( x, y );
2452                                         //%     if( *cluster < 0 )
2453                                         //%             continue;
2454
2455                                         /* get particulars */
2456                                         luxel = SUPER_LUXEL( lightmapNum, x, y );
2457                                         normal = SUPER_NORMAL (  x, y );
2458
2459                                         luxel[0]=(normal[0]*127)+127;
2460                                         luxel[1]=(normal[1]*127)+127;
2461                                         luxel[2]=(normal[2]*127)+127;
2462                                 }
2463                         }
2464                 }
2465         }
2466
2467         /*      -----------------------------------------------------------------
2468                 dirt pass
2469                 ----------------------------------------------------------------- */
2470         
2471         if( dirty )
2472         {
2473                 /* walk lightmaps */
2474                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2475                 {
2476                         /* early out */
2477                         if( lm->superLuxels[ lightmapNum ] == NULL )
2478                                 continue;
2479                         
2480                         /* apply dirt to each luxel */
2481                         for( y = 0; y < lm->sh; y++ )
2482                         {
2483                                 for( x = 0; x < lm->sw; x++ )
2484                                 {
2485                                         /* get cluster */
2486                                         cluster = SUPER_CLUSTER( x, y );
2487                                         //%     if( *cluster < 0 ) // TODO why not do this check? These pixels should be zero anyway
2488                                         //%             continue;
2489                                         
2490                                         /* get particulars */
2491                                         luxel = SUPER_LUXEL( lightmapNum, x, y );
2492                                         dirt = SUPER_DIRT( x, y );
2493                                         
2494                                         /* apply dirt */
2495                                         VectorScale( luxel, *dirt, luxel );
2496                                         
2497                                         /* debugging */
2498                                         if( dirtDebug )
2499                                                 VectorSet( luxel, *dirt * 255.0f, *dirt * 255.0f, *dirt * 255.0f );
2500                                 }
2501                         }
2502                 }
2503         }
2504         
2505         /* -----------------------------------------------------------------
2506            filter pass
2507            ----------------------------------------------------------------- */
2508         
2509         /* walk lightmaps */
2510         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2511         {
2512                 /* early out */
2513                 if( lm->superLuxels[ lightmapNum ] == NULL )
2514                         continue;
2515                 
2516                 /* average occluded luxels from neighbors */
2517                 for( y = 0; y < lm->sh; y++ )
2518                 {
2519                         for( x = 0; x < lm->sw; x++ )
2520                         {
2521                                 /* get particulars */
2522                                 cluster = SUPER_CLUSTER( x, y );
2523                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
2524                                 deluxel = SUPER_DELUXEL( x, y );
2525                                 normal = SUPER_NORMAL( x, y );
2526                                 
2527                                 /* determine if filtering is necessary */
2528                                 filterColor = qfalse;
2529                                 filterDir = qfalse;
2530                                 if( *cluster < 0 ||
2531                                         (lm->splotchFix && (luxel[ 0 ] <= ambientColor[ 0 ] || luxel[ 1 ] <= ambientColor[ 1 ] || luxel[ 2 ] <= ambientColor[ 2 ])) )
2532                                         filterColor = qtrue;
2533                                 if( deluxemap && lightmapNum == 0 && (*cluster < 0 || filter) )
2534                                         filterDir = qtrue;
2535                                 
2536                                 if( !filterColor && !filterDir )
2537                                         continue;
2538                                 
2539                                 /* choose seed amount */
2540                                 VectorClear( averageColor );
2541                                 VectorClear( averageDir );
2542                                 averageDir[3] = 0.0f;
2543                                 samples = 0.0f;
2544                                 
2545                                 /* walk 3x3 matrix */
2546                                 for( sy = (y - 1); sy <= (y + 1); sy++ )
2547                                 {
2548                                         if( sy < 0 || sy >= lm->sh )
2549                                                 continue;
2550                                         
2551                                         for( sx = (x - 1); sx <= (x + 1); sx++ )
2552                                         {
2553                                                 if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
2554                                                         continue;
2555                                                 
2556                                                 /* get neighbor's particulars */
2557                                                 cluster2 = SUPER_CLUSTER( sx, sy );
2558                                                 luxel2 = SUPER_LUXEL( lightmapNum, sx, sy );
2559                                                 deluxel2 = SUPER_DELUXEL( sx, sy );
2560                                                 
2561                                                 /* ignore unmapped/unlit luxels */
2562                                                 if( *cluster2 < 0 || luxel2[ 3 ] == 0.0f ||
2563                                                         (lm->splotchFix && VectorCompare( luxel2, ambientColor )) )
2564                                                         continue;
2565                                                 
2566                                                 /* add its distinctiveness to our own */
2567                                                 VectorAdd( averageColor, luxel2, averageColor );
2568                                                 samples += luxel2[ 3 ];
2569                                                 if( filterDir )
2570                                                 {
2571                                                         VectorAdd( averageDir, deluxel2, averageDir );
2572                                                         averageDir[3] += deluxel2[3];
2573                                                 }
2574                                         }
2575                                 }
2576                                 
2577                                 /* fall through */
2578                                 if( samples <= 0.0f )
2579                                         continue;
2580                                 
2581                                 /* dark lightmap seams */
2582                                 if( dark )
2583                                 {
2584                                         if( lightmapNum == 0 )
2585                                                 VectorMA( averageColor, 2.0f, ambientColor, averageColor );
2586                                         samples += 2.0f;
2587                                 }
2588                                 
2589                                 /* average it */
2590                                 if( filterColor )
2591                                 {
2592                                         VectorDivide( averageColor, samples, luxel );
2593                                         luxel[ 3 ] = 1.0f;
2594                                 }
2595                                 if( filterDir )
2596                                 {
2597                                         VectorDivide( averageDir, samples, deluxel );
2598                                         deluxel[3] = averageDir[3] / samples;
2599                                 }
2600                                 
2601                                 /* set cluster to -3 */
2602                                 if( *cluster < 0 )
2603                                         *cluster = CLUSTER_FLOODED;
2604                         }
2605                 }
2606         }
2607
2608
2609 #if 0
2610         // audit pass
2611         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2612         {
2613                 /* early out */
2614                 if( lm->superLuxels[ lightmapNum ] == NULL )
2615                         continue;
2616                 for( y = 0; y < lm->sh; y++ )
2617                         for( x = 0; x < lm->sw; x++ )
2618                         {
2619                                 /* get cluster */
2620                                 cluster = SUPER_CLUSTER( x, y );
2621                                 luxel = SUPER_LUXEL( lightmapNum, x, y );
2622                                 deluxel = SUPER_DELUXEL( x, y );
2623                                 if(!luxel || !deluxel || !cluster)
2624                                 {
2625                                         Sys_FPrintf(SYS_VRB, "WARNING: I got NULL'd.\n");
2626                                         continue;
2627                                 }
2628                                 else if(*cluster < 0)
2629                                 {
2630                                         // unmapped pixel
2631                                         // should have neither deluxemap nor lightmap
2632                                         if(deluxel[3])
2633                                                 Sys_FPrintf(SYS_VRB, "WARNING: I have written deluxe to an unmapped luxel. Sorry.\n");
2634                                 }
2635                                 else
2636                                 {
2637                                         // mapped pixel
2638                                         // should have both deluxemap and lightmap
2639                                         if(deluxel[3])
2640                                                 Sys_FPrintf(SYS_VRB, "WARNING: I forgot to write deluxe to a mapped luxel. Sorry.\n");
2641                                 }
2642                         }
2643         }
2644 #endif
2645 }
2646
2647
2648
2649 /*
2650 IlluminateVertexes()
2651 light the surface vertexes
2652 */
2653
2654 #define VERTEX_NUDGE    4.0f
2655
2656 void IlluminateVertexes( int num )
2657 {
2658         int                                     i, x, y, z, x1, y1, z1, sx, sy, radius, maxRadius, *cluster;
2659         int                                     lightmapNum, numAvg;
2660         float                           samples, *vertLuxel, *radVertLuxel, *luxel, dirt;
2661         vec3_t                          origin, temp, temp2, colors[ MAX_LIGHTMAPS ], avgColors[ MAX_LIGHTMAPS ];
2662         bspDrawSurface_t        *ds;
2663         surfaceInfo_t           *info;
2664         rawLightmap_t           *lm;
2665         bspDrawVert_t           *verts;
2666         trace_t                         trace;
2667         
2668         
2669         /* get surface, info, and raw lightmap */
2670         ds = &bspDrawSurfaces[ num ];
2671         info = &surfaceInfos[ num ];
2672         lm = info->lm;
2673         
2674         /* -----------------------------------------------------------------
2675            illuminate the vertexes
2676            ----------------------------------------------------------------- */
2677         
2678         /* calculate vertex lighting for surfaces without lightmaps */
2679         if( lm == NULL || cpmaHack )
2680         {
2681                 /* setup trace */
2682                 trace.testOcclusion = (cpmaHack && lm != NULL) ? qfalse : !noTrace;
2683                 trace.forceSunlight = info->si->forceSunlight;
2684                 trace.recvShadows = info->recvShadows;
2685                 trace.numSurfaces = 1;
2686                 trace.surfaces = &num;
2687                 trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
2688                 
2689                 /* twosided lighting */
2690                 trace.twoSided = info->si->twoSided;
2691                 
2692                 /* make light list for this surface */
2693                 CreateTraceLightsForSurface( num, &trace );
2694                 
2695                 /* setup */
2696                 verts = yDrawVerts + ds->firstVert;
2697                 numAvg = 0;
2698                 memset( avgColors, 0, sizeof( avgColors ) );
2699                 
2700                 /* walk the surface verts */
2701                 for( i = 0; i < ds->numVerts; i++ )
2702                 {
2703                         /* get vertex luxel */
2704                         radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2705                         
2706                         /* color the luxel with raw lightmap num? */
2707                         if( debugSurfaces )
2708                                 VectorCopy( debugColors[ num % 12 ], radVertLuxel );
2709                         
2710                         /* color the luxel with luxel origin? */
2711                         else if( debugOrigin )
2712                         {
2713                                 VectorSubtract( info->maxs, info->mins, temp );
2714                                 VectorScale( temp, (1.0f / 255.0f), temp );
2715                                 VectorSubtract( origin, lm->mins, temp2 );
2716                                 radVertLuxel[ 0 ] = info->mins[ 0 ] + (temp[ 0 ] * temp2[ 0 ]);
2717                                 radVertLuxel[ 1 ] = info->mins[ 1 ] + (temp[ 1 ] * temp2[ 1 ]);
2718                                 radVertLuxel[ 2 ] = info->mins[ 2 ] + (temp[ 2 ] * temp2[ 2 ]);
2719                         }
2720                         
2721                         /* color the luxel with the normal */
2722                         else if( normalmap )
2723                         {
2724                                 radVertLuxel[ 0 ] = (verts[ i ].normal[ 0 ] + 1.0f) * 127.5f;
2725                                 radVertLuxel[ 1 ] = (verts[ i ].normal[ 1 ] + 1.0f) * 127.5f;
2726                                 radVertLuxel[ 2 ] = (verts[ i ].normal[ 2 ] + 1.0f) * 127.5f;
2727                         }
2728                         
2729                         /* illuminate the vertex */
2730                         else
2731                         {
2732                                 /* clear vertex luxel */
2733                                 VectorSet( radVertLuxel, -1.0f, -1.0f, -1.0f );
2734                                 
2735                                 /* try at initial origin */
2736                                 trace.cluster = ClusterForPointExtFilter( verts[ i ].xyz, VERTEX_EPSILON, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ] );
2737                                 if( trace.cluster >= 0 )
2738                                 {
2739                                         /* setup trace */
2740                                         VectorCopy( verts[ i ].xyz, trace.origin );
2741                                         VectorCopy( verts[ i ].normal, trace.normal );
2742                                         
2743                                         /* r7 dirt */
2744                                         if( dirty )
2745                                                 dirt = DirtForSample( &trace );
2746                                         else
2747                                                 dirt = 1.0f;
2748
2749                                         /* trace */
2750                                         LightingAtSample( &trace, ds->vertexStyles, colors );
2751                                         
2752                                         /* store */
2753                                         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2754                                         {
2755                                                 /* r7 dirt */
2756                                                 VectorScale( colors[ lightmapNum ], dirt, colors[ lightmapNum ] );
2757                                                 
2758                                                 /* store */
2759                                                 radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
2760                                                 VectorCopy( colors[ lightmapNum ], radVertLuxel );
2761                                                 VectorAdd( avgColors[ lightmapNum ], colors[ lightmapNum ], colors[ lightmapNum ] );
2762                                         }
2763                                 }
2764                                 
2765                                 /* is this sample bright enough? */
2766                                 radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2767                                 if( radVertLuxel[ 0 ] <= ambientColor[ 0 ] &&
2768                                         radVertLuxel[ 1 ] <= ambientColor[ 1 ] &&
2769                                         radVertLuxel[ 2 ] <= ambientColor[ 2 ] )
2770                                 {
2771                                         /* nudge the sample point around a bit */
2772                                         for( x = 0; x < 4; x++ )
2773                                         {
2774                                                 /* two's complement 0, 1, -1, 2, -2, etc */
2775                                                 x1 = ((x >> 1) ^ (x & 1 ? -1 : 0)) + (x & 1);
2776                                                 
2777                                                 for( y = 0; y < 4; y++ )
2778                                                 {
2779                                                         y1 = ((y >> 1) ^ (y & 1 ? -1 : 0)) + (y & 1);
2780                                                         
2781                                                         for( z = 0; z < 4; z++ )
2782                                                         {
2783                                                                 z1 = ((z >> 1) ^ (z & 1 ? -1 : 0)) + (z & 1);
2784                                                                 
2785                                                                 /* nudge origin */
2786                                                                 trace.origin[ 0 ] = verts[ i ].xyz[ 0 ] + (VERTEX_NUDGE * x1);
2787                                                                 trace.origin[ 1 ] = verts[ i ].xyz[ 1 ] + (VERTEX_NUDGE * y1);
2788                                                                 trace.origin[ 2 ] = verts[ i ].xyz[ 2 ] + (VERTEX_NUDGE * z1);
2789                                                                 
2790                                                                 /* try at nudged origin */
2791                                                                 trace.cluster = ClusterForPointExtFilter( origin, VERTEX_EPSILON, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ] );
2792                                                                 if( trace.cluster < 0 )
2793                                                                         continue;
2794                                                                                                                         
2795                                                                 /* trace */
2796                                                                 LightingAtSample( &trace, ds->vertexStyles, colors );
2797                                                                 
2798                                                                 /* store */
2799                                                                 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2800                                                                 {
2801                                                                         /* r7 dirt */
2802                                                                         VectorScale( colors[ lightmapNum ], dirt, colors[ lightmapNum ] );
2803                                                                         
2804                                                                         /* store */
2805                                                                         radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
2806                                                                         VectorCopy( colors[ lightmapNum ], radVertLuxel );
2807                                                                 }
2808                                                                 
2809                                                                 /* bright enough? */
2810                                                                 radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2811                                                                 if( radVertLuxel[ 0 ] > ambientColor[ 0 ] ||
2812                                                                         radVertLuxel[ 1 ] > ambientColor[ 1 ] ||
2813                                                                         radVertLuxel[ 2 ] > ambientColor[ 2 ] )
2814                                                                         x = y = z = 1000;
2815                                                         }
2816                                                 }
2817                                         }
2818                                 }
2819                                 
2820                                 /* add to average? */
2821                                 radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2822                                 if( radVertLuxel[ 0 ] > ambientColor[ 0 ] ||
2823                                         radVertLuxel[ 1 ] > ambientColor[ 1 ] ||
2824                                         radVertLuxel[ 2 ] > ambientColor[ 2 ] )
2825                                 {
2826                                         numAvg++;
2827                                         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2828                                         {
2829                                                 radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
2830                                                 VectorAdd( avgColors[ lightmapNum ], radVertLuxel, avgColors[ lightmapNum ] );
2831                                         }
2832                                 }
2833                         }
2834                         
2835                         /* another happy customer */
2836                         numVertsIlluminated++;
2837                 }
2838                 
2839                 /* set average color */
2840                 if( numAvg > 0 )
2841                 {
2842                         for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2843                                 VectorScale( avgColors[ lightmapNum ], (1.0f / numAvg), avgColors[ lightmapNum ] );
2844                 }
2845                 else
2846                 {
2847                         VectorCopy( ambientColor, avgColors[ 0 ] );
2848                 }
2849                 
2850                 /* clean up and store vertex color */
2851                 for( i = 0; i < ds->numVerts; i++ )
2852                 {
2853                         /* get vertex luxel */
2854                         radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
2855                         
2856                         /* store average in occluded vertexes */