]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - tools/quake3/q3map2/light_ydnar.c
eol style
[xonotic/netradiant.git] / tools / quake3 / q3map2 / light_ydnar.c
index 33be2071be8871fd9ec7a7c0e03de678815ce793..6a2921563040b411a38909a476e48419a5abc590 100644 (file)
-/*\r
-Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
-For a list of contributors, see the accompanying CONTRIBUTORS file.\r
-\r
-This file is part of GtkRadiant.\r
-\r
-GtkRadiant is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-GtkRadiant is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with GtkRadiant; if not, write to the Free Software\r
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-\r
-----------------------------------------------------------------------------------\r
-\r
-This code has been altered significantly from its original form, to support\r
-several games based on the Quake III Arena engine, in the form of "Q3Map2."\r
-\r
-------------------------------------------------------------------------------- */\r
-\r
-\r
-\r
-/* marker */\r
-#define LIGHT_YDNAR_C\r
-\r
-\r
-\r
-/* dependencies */\r
-#include "q3map2.h"\r
-\r
-\r
-\r
-\r
-/*\r
-ColorToBytes()\r
-ydnar: moved to here 2001-02-04\r
-*/\r
-\r
-void ColorToBytes( const float *color, byte *colorBytes, float scale )\r
-{\r
-       float   max;\r
-       vec3_t  sample;\r
-       \r
-       \r
-       /* ydnar: scaling necessary for simulating r_overbrightBits on external lightmaps */\r
-       if( scale <= 0.0f )\r
-               scale = 1.0f;\r
-       \r
-       /* make a local copy */\r
-       VectorScale( color, scale, sample );\r
-       \r
-       /* handle negative light */\r
-       if( sample[ 0 ] < 0.0f )\r
-               sample[ 0 ] = 0.0f;\r
-       if( sample[ 1 ] < 0.0f )\r
-               sample[ 1 ] = 0.0f;\r
-       if( sample[ 2 ] < 0.0f )\r
-               sample[ 2 ] = 0.0f;\r
-       \r
-       /* clamp with color normalization */\r
-       max = sample[ 0 ];\r
-       if( sample[ 1 ] > max )\r
-               max = sample[ 1 ];\r
-       if( sample[ 2 ] > max )\r
-               max = sample[ 2 ];\r
-       if( max > 255.0f )\r
-               VectorScale( sample, (255.0f / max), sample );\r
-       \r
-       /* store it off */\r
-       colorBytes[ 0 ] = sample[ 0 ];\r
-       colorBytes[ 1 ] = sample[ 1 ];\r
-       colorBytes[ 2 ] = sample[ 2 ];\r
-}\r
-\r
-\r
-\r
-/* -------------------------------------------------------------------------------\r
-\r
-this section deals with phong shading (normal interpolation across brush faces)\r
-\r
-------------------------------------------------------------------------------- */\r
-\r
-/*\r
-SmoothNormals()\r
-smooths together coincident vertex normals across the bsp\r
-*/\r
-\r
-#define MAX_SAMPLES                            256\r
-#define THETA_EPSILON                  0.000001\r
-#define EQUAL_NORMAL_EPSILON   0.01\r
-\r
-void SmoothNormals( void )\r
-{\r
-       int                                     i, j, k, f, cs, numVerts, numVotes, fOld, start;\r
-       float                           shadeAngle, defaultShadeAngle, maxShadeAngle, dot, testAngle;\r
-       bspDrawSurface_t        *ds;\r
-       shaderInfo_t            *si;\r
-       float                           *shadeAngles;\r
-       byte                            *smoothed;\r
-       vec3_t                          average, diff;\r
-       int                                     indexes[ MAX_SAMPLES ];\r
-       vec3_t                          votes[ MAX_SAMPLES ];\r
-       \r
-       \r
-       /* allocate shade angle table */\r
-       shadeAngles = safe_malloc( numBSPDrawVerts * sizeof( float ) );\r
-       memset( shadeAngles, 0, numBSPDrawVerts * sizeof( float ) );\r
-       \r
-       /* allocate smoothed table */\r
-       cs = (numBSPDrawVerts / 8) + 1;\r
-       smoothed = safe_malloc( cs );\r
-       memset( smoothed, 0, cs );\r
-       \r
-       /* set default shade angle */\r
-       defaultShadeAngle = DEG2RAD( shadeAngleDegrees );\r
-       maxShadeAngle = 0;\r
-       \r
-       /* run through every surface and flag verts belonging to non-lightmapped surfaces\r
-          and set per-vertex smoothing angle */\r
-       for( i = 0; i < numBSPDrawSurfaces; i++ )\r
-       {\r
-               /* get drawsurf */\r
-               ds = &bspDrawSurfaces[ i ];\r
-               \r
-               /* get shader for shade angle */\r
-               si = surfaceInfos[ i ].si;\r
-               if( si->shadeAngleDegrees )\r
-                       shadeAngle = DEG2RAD( si->shadeAngleDegrees );\r
-               else\r
-                       shadeAngle = defaultShadeAngle;\r
-               if( shadeAngle > maxShadeAngle )\r
-                       maxShadeAngle = shadeAngle;\r
-               \r
-               /* flag its verts */\r
-               for( j = 0; j < ds->numVerts; j++ )\r
-               {\r
-                       f = ds->firstVert + j;\r
-                       shadeAngles[ f ] = shadeAngle;\r
-                       if( ds->surfaceType == MST_TRIANGLE_SOUP )\r
-                               smoothed[ f >> 3 ] |= (1 << (f & 7));\r
-               }\r
-               \r
-               /* ydnar: optional force-to-trisoup */\r
-               if( trisoup && ds->surfaceType == MST_PLANAR )\r
-               {\r
-                       ds->surfaceType = MST_TRIANGLE_SOUP;\r
-                       ds->lightmapNum[ 0 ] = -3;\r
-               }\r
-       }\r
-       \r
-       /* bail if no surfaces have a shade angle */\r
-       if( maxShadeAngle == 0 )\r
-       {\r
-               free( shadeAngles );\r
-               free( smoothed );\r
-               return;\r
-       }\r
-       \r
-       /* init pacifier */\r
-       fOld = -1;\r
-       start = I_FloatTime();\r
-       \r
-       /* go through the list of vertexes */\r
-       for( i = 0; i < numBSPDrawVerts; i++ )\r
-       {\r
-               /* print pacifier */\r
-               f = 10 * i / numBSPDrawVerts;\r
-               if( f != fOld )\r
-               {\r
-                       fOld = f;\r
-                       Sys_Printf( "%i...", f );\r
-               }\r
-               \r
-               /* already smoothed? */\r
-               if( smoothed[ i >> 3 ] & (1 << (i & 7)) )\r
-                       continue;\r
-               \r
-               /* clear */\r
-               VectorClear( average );\r
-               numVerts = 0;\r
-               numVotes = 0;\r
-               \r
-               /* build a table of coincident vertexes */\r
-               for( j = i; j < numBSPDrawVerts && numVerts < MAX_SAMPLES; j++ )\r
-               {\r
-                       /* already smoothed? */\r
-                       if( smoothed[ j >> 3 ] & (1 << (j & 7)) )\r
-                               continue;\r
-                       \r
-                       /* test vertexes */\r
-                       if( VectorCompare( yDrawVerts[ i ].xyz, yDrawVerts[ j ].xyz ) == qfalse )\r
-                               continue;\r
-                       \r
-                       /* use smallest shade angle */\r
-                       shadeAngle = (shadeAngles[ i ] < shadeAngles[ j ] ? shadeAngles[ i ] : shadeAngles[ j ]);\r
-                       \r
-                       /* check shade angle */\r
-                       dot = DotProduct( bspDrawVerts[ i ].normal, bspDrawVerts[ j ].normal );\r
-                       if( dot > 1.0 )\r
-                               dot = 1.0;\r
-                       else if( dot < -1.0 )\r
-                               dot = -1.0;\r
-                       testAngle = acos( dot ) + THETA_EPSILON;\r
-                       if( testAngle >= shadeAngle )\r
-                       {\r
-                               //Sys_Printf( "F(%3.3f >= %3.3f) ", RAD2DEG( testAngle ), RAD2DEG( shadeAngle ) );\r
-                               continue;\r
-                       }\r
-                       //Sys_Printf( "P(%3.3f < %3.3f) ", RAD2DEG( testAngle ), RAD2DEG( shadeAngle ) );\r
-                       \r
-                       /* add to the list */\r
-                       indexes[ numVerts++ ] = j;\r
-                       \r
-                       /* flag vertex */\r
-                       smoothed[ j >> 3 ] |= (1 << (j & 7));\r
-                       \r
-                       /* see if this normal has already been voted */\r
-                       for( k = 0; k < numVotes; k++ )\r
-                       {\r
-                               VectorSubtract( bspDrawVerts[ j ].normal, votes[ k ], diff );\r
-                               if( fabs( diff[ 0 ] ) < EQUAL_NORMAL_EPSILON &&\r
-                                       fabs( diff[ 1 ] ) < EQUAL_NORMAL_EPSILON &&\r
-                                       fabs( diff[ 2 ] ) < EQUAL_NORMAL_EPSILON )\r
-                                       break;\r
-                       }\r
-                       \r
-                       /* add a new vote? */\r
-                       if( k == numVotes && numVotes < MAX_SAMPLES )\r
-                       {\r
-                               VectorAdd( average, bspDrawVerts[ j ].normal, average );\r
-                               VectorCopy( bspDrawVerts[ j ].normal, votes[ numVotes ] );\r
-                               numVotes++;\r
-                       }\r
-               }\r
-               \r
-               /* don't average for less than 2 verts */\r
-               if( numVerts < 2 )\r
-                       continue;\r
-               \r
-               /* average normal */\r
-               if( VectorNormalize( average, average ) > 0 )\r
-               {\r
-                       /* smooth */\r
-                       for( j = 0; j < numVerts; j++ )\r
-                               VectorCopy( average, yDrawVerts[ indexes[ j ] ].normal );\r
-               }\r
-       }\r
-       \r
-       /* free the tables */\r
-       free( shadeAngles );\r
-       free( smoothed );\r
-       \r
-       /* print time */\r
-       Sys_Printf( " (%i)\n", (int) (I_FloatTime() - start) );\r
-}\r
-\r
-\r
-\r
-/* -------------------------------------------------------------------------------\r
-\r
-this section deals with phong shaded lightmap tracing\r
-\r
-------------------------------------------------------------------------------- */\r
-\r
-/* 9th rewrite (recursive subdivision of a lightmap triangle) */\r
-\r
-/*\r
-CalcTangentVectors()\r
-calculates the st tangent vectors for normalmapping\r
-*/\r
-\r
-static qboolean CalcTangentVectors( int numVerts, bspDrawVert_t **dv, vec3_t *stv, vec3_t *ttv )\r
-{\r
-       int                     i;\r
-       float           bb, s, t;\r
-       vec3_t          bary;\r
-       \r
-       \r
-       /* calculate barycentric basis for the triangle */\r
-       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 ]);\r
-       if( fabs( bb ) < 0.00000001f )\r
-               return qfalse;\r
-       \r
-       /* do each vertex */\r
-       for( i = 0; i < numVerts; i++ )\r
-       {\r
-               /* calculate s tangent vector */\r
-               s = dv[ i ]->st[ 0 ] + 10.0f;\r
-               t = dv[ i ]->st[ 1 ];\r
-               bary[ 0 ] = ((dv[ 1 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t) - (dv[ 2 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t)) / bb;\r
-               bary[ 1 ] = ((dv[ 2 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t) - (dv[ 0 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t)) / bb;\r
-               bary[ 2 ] = ((dv[ 0 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t) - (dv[ 1 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t)) / bb;\r
-               \r
-               stv[ i ][ 0 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 0 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 0 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 0 ];\r
-               stv[ i ][ 1 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 1 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 1 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 1 ];\r
-               stv[ i ][ 2 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 2 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 2 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 2 ];\r
-               \r
-               VectorSubtract( stv[ i ], dv[ i ]->xyz, stv[ i ] );\r
-               VectorNormalize( stv[ i ], stv[ i ] );\r
-               \r
-               /* calculate t tangent vector */\r
-               s = dv[ i ]->st[ 0 ];\r
-               t = dv[ i ]->st[ 1 ] + 10.0f;\r
-               bary[ 0 ] = ((dv[ 1 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t) - (dv[ 2 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t)) / bb;\r
-               bary[ 1 ] = ((dv[ 2 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t) - (dv[ 0 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t)) / bb;\r
-               bary[ 2 ] = ((dv[ 0 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t) - (dv[ 1 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t)) / bb;\r
-               \r
-               ttv[ i ][ 0 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 0 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 0 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 0 ];\r
-               ttv[ i ][ 1 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 1 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 1 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 1 ];\r
-               ttv[ i ][ 2 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 2 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 2 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 2 ];\r
-               \r
-               VectorSubtract( ttv[ i ], dv[ i ]->xyz, ttv[ i ] );\r
-               VectorNormalize( ttv[ i ], ttv[ i ] );\r
-               \r
-               /* debug code */\r
-               //%     Sys_FPrintf( SYS_VRB, "%d S: (%f %f %f) T: (%f %f %f)\n", i,\r
-               //%             stv[ i ][ 0 ], stv[ i ][ 1 ], stv[ i ][ 2 ], ttv[ i ][ 0 ], ttv[ i ][ 1 ], ttv[ i ][ 2 ] );\r
-       }\r
-       \r
-       /* return to caller */\r
-       return qtrue;\r
-}\r
-\r
-\r
-\r
-\r
-/*\r
-PerturbNormal()\r
-perterbs the normal by the shader's normalmap in tangent space\r
-*/\r
-\r
-static void PerturbNormal( bspDrawVert_t *dv, shaderInfo_t *si, vec3_t pNormal, vec3_t stv[ 3 ], vec3_t ttv[ 3 ] )\r
-{\r
-       int                     i;\r
-       vec4_t          bump;\r
-       \r
-       \r
-       /* passthrough */\r
-       VectorCopy( dv->normal, pNormal );\r
-       \r
-       /* sample normalmap */\r
-       if( RadSampleImage( si->normalImage->pixels, si->normalImage->width, si->normalImage->height, dv->st, bump ) == qfalse )\r
-               return;\r
-       \r
-       /* remap sampled normal from [0,255] to [-1,-1] */\r
-       for( i = 0; i < 3; i++ )\r
-               bump[ i ] = (bump[ i ] - 127.0f) * (1.0f / 127.5f);\r
-       \r
-       /* scale tangent vectors and add to original normal */\r
-       VectorMA( dv->normal, bump[ 0 ], stv[ 0 ], pNormal );\r
-       VectorMA( pNormal, bump[ 1 ], ttv[ 0 ], pNormal );\r
-       VectorMA( pNormal, bump[ 2 ], dv->normal, pNormal );\r
-       \r
-       /* renormalize and return */\r
-       VectorNormalize( pNormal, pNormal );\r
-}\r
-\r
-\r
-\r
-/*\r
-MapSingleLuxel()\r
-maps a luxel for triangle bv at\r
-*/\r
-\r
-#define NUDGE                  0.5f\r
-#define BOGUS_NUDGE            -99999.0f\r
-\r
-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 ] )\r
-{\r
-       int                             i, x, y, numClusters, *clusters, pointCluster, *cluster;\r
-       float                   *luxel, *origin, *normal, d, lightmapSampleOffset;\r
-       shaderInfo_t    *si;\r
-       vec3_t                  pNormal;\r
-       vec3_t                  vecs[ 3 ];\r
-       vec3_t                  nudged;\r
-       float                   *nudge;\r
-       static float    nudges[][ 2 ] =\r
-                                       {\r
-                                               //%{ 0, 0 },            /* try center first */\r
-                                               { -NUDGE, 0 },          /* left */\r
-                                               { NUDGE, 0 },           /* right */\r
-                                               { 0, NUDGE },           /* up */\r
-                                               { 0, -NUDGE },          /* down */\r
-                                               { -NUDGE, NUDGE },      /* left/up */\r
-                                               { NUDGE, -NUDGE },      /* right/down */\r
-                                               { NUDGE, NUDGE },       /* right/up */\r
-                                               { -NUDGE, -NUDGE },     /* left/down */\r
-                                               { BOGUS_NUDGE, BOGUS_NUDGE }\r
-                                       };\r
-       \r
-       \r
-       /* find luxel xy coords (fixme: subtract 0.5?) */\r
-       x = dv->lightmap[ 0 ][ 0 ];\r
-       y = dv->lightmap[ 0 ][ 1 ];\r
-       if( x < 0 )\r
-               x = 0;\r
-       else if( x >= lm->sw )\r
-               x = lm->sw - 1;\r
-       if( y < 0 )\r
-               y = 0;\r
-       else if( y >= lm->sh )\r
-               y = lm->sh - 1;\r
-       \r
-       /* set shader and cluster list */\r
-       if( info != NULL )\r
-       {\r
-               si = info->si;\r
-               numClusters = info->numSurfaceClusters;\r
-               clusters = &surfaceClusters[ info->firstSurfaceCluster ];\r
-       }\r
-       else\r
-       {\r
-               si = NULL;\r
-               numClusters = 0;\r
-               clusters = NULL;\r
-       }\r
-       \r
-       /* get luxel, origin, cluster, and normal */\r
-       luxel = SUPER_LUXEL( 0, x, y );\r
-       origin = SUPER_ORIGIN( x, y );\r
-       normal = SUPER_NORMAL( x, y );\r
-       cluster = SUPER_CLUSTER( x, y );\r
-       \r
-       /* don't attempt to remap occluded luxels for planar surfaces */\r
-       if( (*cluster) == CLUSTER_OCCLUDED && lm->plane != NULL )\r
-               return (*cluster);\r
-       \r
-       /* only average the normal for premapped luxels */\r
-       else if( (*cluster) >= 0 )\r
-       {\r
-               /* do bumpmap calculations */\r
-               if( stv != NULL )\r
-                       PerturbNormal( dv, si, pNormal, stv, ttv );\r
-               else\r
-                       VectorCopy( dv->normal, pNormal );\r
-               \r
-               /* add the additional normal data */\r
-               VectorAdd( normal, pNormal, normal );\r
-               luxel[ 3 ] += 1.0f;\r
-               return (*cluster);\r
-       }\r
-       \r
-       /* otherwise, unmapped luxels (*cluster == CLUSTER_UNMAPPED) will have their full attributes calculated */\r
-       \r
-       /* get origin */\r
-       \r
-       /* axial lightmap projection */\r
-       if( lm->vecs != NULL )\r
-       {\r
-               /* calculate an origin for the sample from the lightmap vectors */\r
-               VectorCopy( lm->origin, origin );\r
-               for( i = 0; i < 3; i++ )\r
-               {\r
-                       /* add unless it's the axis, which is taken care of later */\r
-                       if( i == lm->axisNum )\r
-                               continue;\r
-                       origin[ i ] += (x * lm->vecs[ 0 ][ i ]) + (y * lm->vecs[ 1 ][ i ]);\r
-               }\r
-               \r
-               /* project the origin onto the plane */\r
-               d = DotProduct( origin, plane ) - plane[ 3 ];\r
-               d /= plane[ lm->axisNum ];\r
-               origin[ lm->axisNum ] -= d;\r
-       }\r
-       \r
-       /* non axial lightmap projection (explicit xyz) */\r
-       else\r
-               VectorCopy( dv->xyz, origin );\r
-       \r
-       /* planar surfaces have precalculated lightmap vectors for nudging */\r
-       if( lm->plane != NULL )\r
-       {\r
-               VectorCopy( lm->vecs[ 0 ], vecs[ 0 ] );\r
-               VectorCopy( lm->vecs[ 1 ], vecs[ 1 ] );\r
-               VectorCopy( lm->plane, vecs[ 2 ] );\r
-       }\r
-       \r
-       /* non-planar surfaces must calculate them */\r
-       else\r
-       {\r
-               if( plane != NULL )\r
-                       VectorCopy( plane, vecs[ 2 ] );\r
-               else\r
-                       VectorCopy( dv->normal, vecs[ 2 ] );\r
-               MakeNormalVectors( vecs[ 2 ], vecs[ 0 ], vecs[ 1 ] );\r
-       }\r
-       \r
-       /* push the origin off the surface a bit */\r
-       if( si != NULL )\r
-               lightmapSampleOffset = si->lightmapSampleOffset;\r
-       else\r
-               lightmapSampleOffset = DEFAULT_LIGHTMAP_SAMPLE_OFFSET;\r
-       if( lm->axisNum < 0 )\r
-               VectorMA( origin, lightmapSampleOffset, vecs[ 2 ], origin );\r
-       else if( vecs[ 2 ][ lm->axisNum ] < 0.0f )\r
-               origin[ lm->axisNum ] -= lightmapSampleOffset;\r
-       else\r
-               origin[ lm->axisNum ] += lightmapSampleOffset;\r
-       \r
-       /* get cluster */\r
-       pointCluster = ClusterForPointExtFilter( origin, LUXEL_EPSILON, numClusters, clusters );\r
-       \r
-       /* another retarded hack, storing nudge count in luxel[ 1 ] */\r
-       luxel[ 1 ] = 0.0f;      \r
-       \r
-       /* point in solid? */\r
-       if( pointCluster < 0 )\r
-       {\r
-               /* nudge the the location around */\r
-               nudge = nudges[ 0 ];\r
-               while( nudge[ 0 ] > BOGUS_NUDGE && pointCluster < 0 )\r
-               {\r
-                       /* nudge the vector around a bit */\r
-                       for( i = 0; i < 3; i++ )\r
-                       {\r
-                               /* set nudged point*/\r
-                               nudged[ i ] = origin[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);\r
-                       }\r
-                       nudge += 2;\r
-                       \r
-                       /* get pvs cluster */\r
-                       pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); //% + 0.625 );\r
-                       if( pointCluster >= 0 ) \r
-                               VectorCopy( nudged, origin );\r
-                       luxel[ 1 ] += 1.0f;\r
-               }\r
-       }\r
-       \r
-       /* as a last resort, if still in solid, try drawvert origin offset by normal */\r
-       if( pointCluster < 0 && si != NULL )\r
-       {\r
-               VectorMA( dv->xyz, lightmapSampleOffset, dv->normal, nudged );\r
-               pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters );\r
-               if( pointCluster >= 0 )\r
-                       VectorCopy( nudged, origin );\r
-               luxel[ 1 ] += 1.0f;\r
-       }\r
-       \r
-       /* valid? */\r
-       if( pointCluster < 0 )\r
-       {\r
-               (*cluster) = CLUSTER_OCCLUDED;\r
-               VectorClear( origin );\r
-               VectorClear( normal );\r
-               numLuxelsOccluded++;\r
-               return (*cluster);\r
-       }\r
-       \r
-       /* debug code */\r
-       //%     Sys_Printf( "%f %f %f\n", origin[ 0 ], origin[ 1 ], origin[ 2 ] );\r
-       \r
-       /* do bumpmap calculations */\r
-       if( stv )\r
-               PerturbNormal( dv, si, pNormal, stv, ttv );\r
-       else\r
-               VectorCopy( dv->normal, pNormal );\r
-       \r
-       /* store the cluster and normal */\r
-       (*cluster) = pointCluster;\r
-       VectorCopy( pNormal, normal );\r
-       \r
-       /* store explicit mapping pass and implicit mapping pass */\r
-       luxel[ 0 ] = pass;\r
-       luxel[ 3 ] = 1.0f;\r
-       \r
-       /* add to count */\r
-       numLuxelsMapped++;\r
-       \r
-       /* return ok */\r
-       return (*cluster);\r
-}\r
-\r
-\r
-\r
-/*\r
-MapTriangle_r()\r
-recursively subdivides a triangle until its edges are shorter\r
-than the distance between two luxels (thanks jc :)\r
-*/\r
-\r
-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 ] )\r
-{\r
-       bspDrawVert_t   mid, *dv2[ 3 ];\r
-       int                             max;\r
-       \r
-       \r
-       /* map the vertexes */\r
-       #if 0\r
-       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );\r
-       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );\r
-       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );\r
-       #endif\r
-       \r
-       /* subdivide calc */\r
-       {\r
-               int                     i;\r
-               float           *a, *b, dx, dy, dist, maxDist;\r
-               \r
-               \r
-               /* find the longest edge and split it */\r
-               max = -1;\r
-               maxDist = 0;\r
-               for( i = 0; i < 3; i++ )\r
-               {\r
-                       /* get verts */\r
-                       a = dv[ i ]->lightmap[ 0 ];\r
-                       b = dv[ (i + 1) % 3 ]->lightmap[ 0 ];\r
-                       \r
-                       /* get dists */\r
-                       dx = a[ 0 ] - b[ 0 ];\r
-                       dy = a[ 1 ] - b[ 1 ];\r
-                       dist = (dx * dx) + (dy * dy);   //% sqrt( (dx * dx) + (dy * dy) );\r
-                       \r
-                       /* longer? */\r
-                       if( dist > maxDist )\r
-                       {\r
-                               maxDist = dist;\r
-                               max = i;\r
-                       }\r
-               }\r
-               \r
-               /* try to early out */\r
-               if( max < 0 || maxDist <= subdivideThreshold )  /* ydnar: was i < 0 instead of max < 0 (?) */\r
-                       return;\r
-       }\r
-       \r
-       /* split the longest edge and map it */\r
-       LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid );\r
-       MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv );\r
-       \r
-       /* push the point up a little bit to account for fp creep (fixme: revisit this) */\r
-       //%     VectorMA( mid.xyz, 2.0f, mid.normal, mid.xyz );\r
-       \r
-       /* recurse to first triangle */\r
-       VectorCopy( dv, dv2 );\r
-       dv2[ max ] = &mid;\r
-       MapTriangle_r( lm, info, dv2, plane, stv, ttv );\r
-       \r
-       /* recurse to second triangle */\r
-       VectorCopy( dv, dv2 );\r
-       dv2[ (max + 1) % 3 ] = &mid;\r
-       MapTriangle_r( lm, info, dv2, plane, stv, ttv );\r
-}\r
-\r
-\r
-\r
-/*\r
-MapTriangle()\r
-seed function for MapTriangle_r()\r
-requires a cw ordered triangle\r
-*/\r
-\r
-static qboolean MapTriangle( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 3 ], qboolean mapNonAxial )\r
-{\r
-       int                             i;\r
-       vec4_t                  plane;\r
-       vec3_t                  *stv, *ttv, stvStatic[ 3 ], ttvStatic[ 3 ];\r
-       \r
-       \r
-       /* get plane if possible */\r
-       if( lm->plane != NULL )\r
-       {\r
-               VectorCopy( lm->plane, plane );\r
-               plane[ 3 ] = lm->plane[ 3 ];\r
-       }\r
-       \r
-       /* otherwise make one from the points */\r
-       else if( PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) == qfalse )\r
-               return qfalse;\r
-       \r
-       /* check to see if we need to calculate texture->world tangent vectors */\r
-       if( info->si->normalImage != NULL && CalcTangentVectors( 3, dv, stvStatic, ttvStatic ) )\r
-       {\r
-               stv = stvStatic;\r
-               ttv = ttvStatic;\r
-       }\r
-       else\r
-       {\r
-               stv = NULL;\r
-               ttv = NULL;\r
-       }\r
-       \r
-       /* map the vertexes */\r
-       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );\r
-       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );\r
-       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );\r
-       \r
-       /* 2002-11-20: prefer axial triangle edges */\r
-       if( mapNonAxial )\r
-       {\r
-               /* subdivide the triangle */\r
-               MapTriangle_r( lm, info, dv, plane, stv, ttv );\r
-               return qtrue;\r
-       }\r
-       \r
-       for( i = 0; i < 3; i++ )\r
-       {\r
-               float                   *a, *b;\r
-               bspDrawVert_t   *dv2[ 3 ];\r
-               \r
-               \r
-               /* get verts */\r
-               a = dv[ i ]->lightmap[ 0 ];\r
-               b = dv[ (i + 1) % 3 ]->lightmap[ 0 ];\r
-               \r
-               /* make degenerate triangles for mapping edges */\r
-               if( fabs( a[ 0 ] - b[ 0 ] ) < 0.01f || fabs( a[ 1 ] - b[ 1 ] ) < 0.01f )\r
-               {\r
-                       dv2[ 0 ] = dv[ i ];\r
-                       dv2[ 1 ] = dv[ (i + 1) % 3 ];\r
-                       dv2[ 2 ] = dv[ (i + 1) % 3 ];\r
-                       \r
-                       /* map the degenerate triangle */\r
-                       MapTriangle_r( lm, info, dv2, plane, stv, ttv );\r
-               }\r
-       }\r
-       \r
-       return qtrue;\r
-}\r
-\r
-\r
-\r
-/*\r
-MapQuad_r()\r
-recursively subdivides a quad until its edges are shorter\r
-than the distance between two luxels\r
-*/\r
-\r
-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 ] )\r
-{\r
-       bspDrawVert_t   mid[ 2 ], *dv2[ 4 ];\r
-       int                             max;\r
-       \r
-       \r
-       /* subdivide calc */\r
-       {\r
-               int                     i;\r
-               float           *a, *b, dx, dy, dist, maxDist;\r
-               \r
-               \r
-               /* find the longest edge and split it */\r
-               max = -1;\r
-               maxDist = 0;\r
-               for( i = 0; i < 4; i++ )\r
-               {\r
-                       /* get verts */\r
-                       a = dv[ i ]->lightmap[ 0 ];\r
-                       b = dv[ (i + 1) % 4 ]->lightmap[ 0 ];\r
-                       \r
-                       /* get dists */\r
-                       dx = a[ 0 ] - b[ 0 ];\r
-                       dy = a[ 1 ] - b[ 1 ];\r
-                       dist = (dx * dx) + (dy * dy);   //% sqrt( (dx * dx) + (dy * dy) );\r
-                       \r
-                       /* longer? */\r
-                       if( dist > maxDist )\r
-                       {\r
-                               maxDist = dist;\r
-                               max = i;\r
-                       }\r
-               }\r
-               \r
-               /* try to early out */\r
-               if( max < 0 || maxDist <= subdivideThreshold )\r
-                       return;\r
-       }\r
-       \r
-       /* we only care about even/odd edges */\r
-       max &= 1;\r
-       \r
-       /* split the longest edges */\r
-       LerpDrawVert( dv[ max ], dv[ (max + 1) % 4 ], &mid[ 0 ] );\r
-       LerpDrawVert( dv[ max + 2 ], dv[ (max + 3) % 4 ], &mid[ 1 ] );\r
-       \r
-       /* map the vertexes */\r
-       MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv );\r
-       MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv );\r
-       \r
-       /* 0 and 2 */\r
-       if( max == 0 )\r
-       {\r
-               /* recurse to first quad */\r
-               dv2[ 0 ] = dv[ 0 ];\r
-               dv2[ 1 ] = &mid[ 0 ];\r
-               dv2[ 2 ] = &mid[ 1 ];\r
-               dv2[ 3 ] = dv[ 3 ];\r
-               MapQuad_r( lm, info, dv2, plane, stv, ttv );\r
-               \r
-               /* recurse to second quad */\r
-               dv2[ 0 ] = &mid[ 0 ];\r
-               dv2[ 1 ] = dv[ 1 ];\r
-               dv2[ 2 ] = dv[ 2 ];\r
-               dv2[ 3 ] = &mid[ 1 ];\r
-               MapQuad_r( lm, info, dv2, plane, stv, ttv );\r
-       }\r
-       \r
-       /* 1 and 3 */\r
-       else\r
-       {\r
-               /* recurse to first quad */\r
-               dv2[ 0 ] = dv[ 0 ];\r
-               dv2[ 1 ] = dv[ 1 ];\r
-               dv2[ 2 ] = &mid[ 0 ];\r
-               dv2[ 3 ] = &mid[ 1 ];\r
-               MapQuad_r( lm, info, dv2, plane, stv, ttv );\r
-               \r
-               /* recurse to second quad */\r
-               dv2[ 0 ] = &mid[ 1 ];\r
-               dv2[ 1 ] = &mid[ 0 ];\r
-               dv2[ 2 ] = dv[ 2 ];\r
-               dv2[ 3 ] = dv[ 3 ];\r
-               MapQuad_r( lm, info, dv2, plane, stv, ttv );\r
-       }\r
-}\r
-\r
-\r
-\r
-/*\r
-MapQuad()\r
-seed function for MapQuad_r()\r
-requires a cw ordered triangle quad\r
-*/\r
-\r
-#define QUAD_PLANAR_EPSILON            0.5f\r
-\r
-static qboolean MapQuad( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 4 ] )\r
-{\r
-       float                   dist;\r
-       vec4_t                  plane;\r
-       vec3_t                  *stv, *ttv, stvStatic[ 4 ], ttvStatic[ 4 ];\r
-       \r
-       \r
-       /* get plane if possible */\r
-       if( lm->plane != NULL )\r
-       {\r
-               VectorCopy( lm->plane, plane );\r
-               plane[ 3 ] = lm->plane[ 3 ];\r
-       }\r
-       \r
-       /* otherwise make one from the points */\r
-       else if( PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) == qfalse )\r
-               return qfalse;\r
-       \r
-       /* 4th point must fall on the plane */\r
-       dist = DotProduct( plane, dv[ 3 ]->xyz ) - plane[ 3 ];\r
-       if( fabs( dist ) > QUAD_PLANAR_EPSILON )\r
-               return qfalse;\r
-       \r
-       /* check to see if we need to calculate texture->world tangent vectors */\r
-       if( info->si->normalImage != NULL && CalcTangentVectors( 4, dv, stvStatic, ttvStatic ) )\r
-       {\r
-               stv = stvStatic;\r
-               ttv = ttvStatic;\r
-       }\r
-       else\r
-       {\r
-               stv = NULL;\r
-               ttv = NULL;\r
-       }\r
-       \r
-       /* map the vertexes */\r
-       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );\r
-       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );\r
-       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );\r
-       MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv );\r
-       \r
-       /* subdivide the quad */\r
-       MapQuad_r( lm, info, dv, plane, stv, ttv );\r
-       return qtrue;\r
-}\r
-\r
-\r
-\r
-/*\r
-MapRawLightmap()\r
-maps the locations, normals, and pvs clusters for a raw lightmap\r
-*/\r
-\r
-#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)\r
-\r
-void MapRawLightmap( int rawLightmapNum )\r
-{\r
-       int                                     n, num, i, x, y, sx, sy, pw[ 5 ], r, *cluster, mapNonAxial;\r
-       float                           *luxel, *origin, *normal, samples, radius, pass;\r
-       rawLightmap_t           *lm;\r
-       bspDrawSurface_t        *ds;\r
-       surfaceInfo_t           *info;\r
-       mesh_t                          src, *subdivided, *mesh;\r
-       bspDrawVert_t           *verts, *dv[ 4 ], fake;\r
-       \r
-       \r
-       /* bail if this number exceeds the number of raw lightmaps */\r
-       if( rawLightmapNum >= numRawLightmaps )\r
-               return;\r
-       \r
-       /* get lightmap */\r
-       lm = &rawLightmaps[ rawLightmapNum ];\r
-       \r
-       /* -----------------------------------------------------------------\r
-          map referenced surfaces onto the raw lightmap\r
-          ----------------------------------------------------------------- */\r
-       \r
-       /* walk the list of surfaces on this raw lightmap */\r
-       for( n = 0; n < lm->numLightSurfaces; n++ )\r
-       {\r
-               /* with > 1 surface per raw lightmap, clear occluded */\r
-               if( n > 0 )\r
-               {\r
-                       for( y = 0; y < lm->sh; y++ )\r
-                       {\r
-                               for( x = 0; x < lm->sw; x++ )\r
-                               {\r
-                                       /* get cluster */\r
-                                       cluster = SUPER_CLUSTER( x, y );\r
-                                       if( *cluster < 0 )\r
-                                               *cluster = CLUSTER_UNMAPPED;\r
-                               }\r
-                       }\r
-               }\r
-               \r
-               /* get surface */\r
-               num = lightSurfaces[ lm->firstLightSurface + n ];\r
-               ds = &bspDrawSurfaces[ num ];\r
-               info = &surfaceInfos[ num ];\r
-               \r
-               /* bail if no lightmap to calculate */\r
-               if( info->lm != lm )\r
-               {\r
-                       Sys_Printf( "!" );\r
-                       continue;\r
-               }\r
-               \r
-               /* map the surface onto the lightmap origin/cluster/normal buffers */\r
-               switch( ds->surfaceType )\r
-               {\r
-                       case MST_PLANAR:\r
-                               /* get verts */\r
-                               verts = yDrawVerts + ds->firstVert;\r
-                               \r
-                               /* map the triangles */\r
-                               for( mapNonAxial = 0; mapNonAxial < 2; mapNonAxial++ )\r
-                               {\r
-                                       for( i = 0; i < ds->numIndexes; i += 3 )\r
-                                       {\r
-                                               dv[ 0 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i ] ];\r
-                                               dv[ 1 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 1 ] ];\r
-                                               dv[ 2 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 2 ] ];\r
-                                               MapTriangle( lm, info, dv, mapNonAxial );\r
-                                       }\r
-                               }\r
-                               break;\r
-                       \r
-                       case MST_PATCH:\r
-                               /* make a mesh from the drawsurf */ \r
-                               src.width = ds->patchWidth;\r
-                               src.height = ds->patchHeight;\r
-                               src.verts = &yDrawVerts[ ds->firstVert ];\r
-                               //%     subdivided = SubdivideMesh( src, 8, 512 );\r
-                               subdivided = SubdivideMesh2( src, info->patchIterations );\r
-                               \r
-                               /* fit it to the curve and remove colinear verts on rows/columns */\r
-                               PutMeshOnCurve( *subdivided );\r
-                               mesh = RemoveLinearMeshColumnsRows( subdivided );\r
-                               FreeMesh( subdivided );\r
-                               \r
-                               /* get verts */\r
-                               verts = mesh->verts;\r
-                               \r
-                               /* debug code */\r
-                               #if 0\r
-                                       if( lm->plane )\r
-                                       {\r
-                                               Sys_Printf( "Planar patch: [%1.3f %1.3f %1.3f] [%1.3f %1.3f %1.3f] [%1.3f %1.3f %1.3f]\n",\r
-                                                       lm->plane[ 0 ], lm->plane[ 1 ], lm->plane[ 2 ],\r
-                                                       lm->vecs[ 0 ][ 0 ], lm->vecs[ 0 ][ 1 ], lm->vecs[ 0 ][ 2 ],\r
-                                                       lm->vecs[ 1 ][ 0 ], lm->vecs[ 1 ][ 1 ], lm->vecs[ 1 ][ 2 ] );\r
-                                       }\r
-                               #endif\r
-                               \r
-                               /* map the mesh quads */\r
-                               #if 0\r
-\r
-                               for( mapNonAxial = 0; mapNonAxial < 2; mapNonAxial++ )\r
-                               {\r
-                                       for( y = 0; y < (mesh->height - 1); y++ )\r
-                                       {\r
-                                               for( x = 0; x < (mesh->width - 1); x++ )\r
-                                               {\r
-                                                       /* set indexes */\r
-                                                       pw[ 0 ] = x + (y * mesh->width);\r
-                                                       pw[ 1 ] = x + ((y + 1) * mesh->width);\r
-                                                       pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);\r
-                                                       pw[ 3 ] = x + 1 + (y * mesh->width);\r
-                                                       pw[ 4 ] = x + (y * mesh->width);        /* same as pw[ 0 ] */\r
-                                                       \r
-                                                       /* set radix */\r
-                                                       r = (x + y) & 1;\r
-                                                       \r
-                                                       /* get drawverts and map first triangle */\r
-                                                       dv[ 0 ] = &verts[ pw[ r + 0 ] ];\r
-                                                       dv[ 1 ] = &verts[ pw[ r + 1 ] ];\r
-                                                       dv[ 2 ] = &verts[ pw[ r + 2 ] ];\r
-                                                       MapTriangle( lm, info, dv, mapNonAxial );\r
-                                                       \r
-                                                       /* get drawverts and map second triangle */\r
-                                                       dv[ 0 ] = &verts[ pw[ r + 0 ] ];\r
-                                                       dv[ 1 ] = &verts[ pw[ r + 2 ] ];\r
-                                                       dv[ 2 ] = &verts[ pw[ r + 3 ] ];\r
-                                                       MapTriangle( lm, info, dv, mapNonAxial );\r
-                                               }\r
-                                       }\r
-                               }\r
-                               \r
-                               #else\r
-                               \r
-                               for( y = 0; y < (mesh->height - 1); y++ )\r
-                               {\r
-                                       for( x = 0; x < (mesh->width - 1); x++ )\r
-                                       {\r
-                                               /* set indexes */\r
-                                               pw[ 0 ] = x + (y * mesh->width);\r
-                                               pw[ 1 ] = x + ((y + 1) * mesh->width);\r
-                                               pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);\r
-                                               pw[ 3 ] = x + 1 + (y * mesh->width);\r
-                                               pw[ 4 ] = pw[ 0 ];\r
-                                               \r
-                                               /* set radix */\r
-                                               r = (x + y) & 1;\r
-                                               \r
-                                               /* attempt to map quad first */\r
-                                               dv[ 0 ] = &verts[ pw[ r + 0 ] ];\r
-                                               dv[ 1 ] = &verts[ pw[ r + 1 ] ];\r
-                                               dv[ 2 ] = &verts[ pw[ r + 2 ] ];\r
-                                               dv[ 3 ] = &verts[ pw[ r + 3 ] ];\r
-                                               if( MapQuad( lm, info, dv ) )\r
-                                                       continue;\r
-                                               \r
-                                               /* get drawverts and map first triangle */\r
-                                               MapTriangle( lm, info, dv, mapNonAxial );\r
-                                               \r
-                                               /* get drawverts and map second triangle */\r
-                                               dv[ 1 ] = &verts[ pw[ r + 2 ] ];\r
-                                               dv[ 2 ] = &verts[ pw[ r + 3 ] ];\r
-                                               MapTriangle( lm, info, dv, mapNonAxial );\r
-                                       }\r
-                               }\r
-                               \r
-                               #endif\r
-                               \r
-                               /* free the mesh */\r
-                               FreeMesh( mesh );\r
-                               break;\r
-                       \r
-                       default:\r
-                               break;\r
-               }\r
-       }\r
-       \r
-       /* -----------------------------------------------------------------\r
-          average and clean up luxel normals\r
-          ----------------------------------------------------------------- */\r
-       \r
-       /* walk the luxels */\r
-       for( y = 0; y < lm->sh; y++ )\r
-       {\r
-               for( x = 0; x < lm->sw; x++ )\r
-               {\r
-                       /* get luxel */\r
-                       luxel = SUPER_LUXEL( 0, x, y );\r
-                       normal = SUPER_NORMAL( x, y );\r
-                       cluster = SUPER_CLUSTER( x, y );\r
-\r
-                       /* only look at mapped luxels */\r
-                       if( *cluster < 0 )\r
-                               continue;\r
-                       \r
-                       /* the normal data could be the sum of multiple samples */\r
-                       if( luxel[ 3 ] > 1.0f )\r
-                               VectorNormalize( normal, normal );\r
-                       \r
-                       /* mark this luxel as having only one normal */\r
-                       luxel[ 3 ] = 1.0f;\r
-               }\r
-       }\r
-       \r
-       /* non-planar surfaces stop here */\r
-       if( lm->plane == NULL )\r
-               return;\r
-       \r
-       /* -----------------------------------------------------------------\r
-          map occluded or unuxed luxels\r
-          ----------------------------------------------------------------- */\r
-       \r
-       /* walk the luxels */\r
-       radius = floor( superSample / 2 );\r
-       radius = radius > 0 ? radius : 1.0f;\r
-       radius += 1.0f;\r
-       for( pass = 2.0f; pass <= radius; pass += 1.0f )\r
-       {\r
-               for( y = 0; y < lm->sh; y++ )\r
-               {\r
-                       for( x = 0; x < lm->sw; x++ )\r
-                       {\r
-                               /* get luxel */\r
-                               luxel = SUPER_LUXEL( 0, x, y );\r
-                               normal = SUPER_NORMAL( x, y );\r
-                               cluster = SUPER_CLUSTER( x, y );\r
-                               \r
-                               /* only look at unmapped luxels */\r
-                               if( *cluster != CLUSTER_UNMAPPED )\r
-                                       continue;\r
-                               \r
-                               /* divine a normal and origin from neighboring luxels */\r
-                               VectorClear( fake.xyz );\r
-                               VectorClear( fake.normal );\r
-                               fake.lightmap[ 0 ][ 0 ] = x;    //% 0.0001 + x;\r
-                               fake.lightmap[ 0 ][ 1 ] = y;    //% 0.0001 + y;\r
-                               samples = 0.0f;\r
-                               for( sy = (y - 1); sy <= (y + 1); sy++ )\r
-                               {\r
-                                       if( sy < 0 || sy >= lm->sh )\r
-                                               continue;\r
-                                       \r
-                                       for( sx = (x - 1); sx <= (x + 1); sx++ )\r
-                                       {\r
-                                               if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )\r
-                                                       continue;\r
-                                               \r
-                                               /* get neighboring luxel */\r
-                                               luxel = SUPER_LUXEL( 0, sx, sy );\r
-                                               origin = SUPER_ORIGIN( sx, sy );\r
-                                               normal = SUPER_NORMAL( sx, sy );\r
-                                               cluster = SUPER_CLUSTER( sx, sy );\r
-                                               \r
-                                               /* only consider luxels mapped in previous passes */\r
-                                               if( *cluster < 0 || luxel[ 0 ] >= pass )\r
-                                                       continue;\r
-                                               \r
-                                               /* add its distinctiveness to our own */\r
-                                               VectorAdd( fake.xyz, origin, fake.xyz );\r
-                                               VectorAdd( fake.normal, normal, fake.normal );\r
-                                               samples += luxel[ 3 ];\r
-                                       }\r
-                               }\r
-                               \r
-                               /* any samples? */\r
-                               if( samples == 0.0f )\r
-                                       continue;\r
-                               \r
-                               /* average */\r
-                               VectorDivide( fake.xyz, samples, fake.xyz );\r
-                               //%     VectorDivide( fake.normal, samples, fake.normal );\r
-                               if( VectorNormalize( fake.normal, fake.normal ) == 0.0f )\r
-                                       continue;\r
-                               \r
-                               /* map the fake vert */\r
-                               MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL );\r
-                       }\r
-               }\r
-       }\r
-       \r
-       /* -----------------------------------------------------------------\r
-          average and clean up luxel normals\r
-          ----------------------------------------------------------------- */\r
-       \r
-       /* walk the luxels */\r
-       for( y = 0; y < lm->sh; y++ )\r
-       {\r
-               for( x = 0; x < lm->sw; x++ )\r
-               {\r
-                       /* get luxel */\r
-                       luxel = SUPER_LUXEL( 0, x, y );\r
-                       normal = SUPER_NORMAL( x, y );\r
-                       cluster = SUPER_CLUSTER( x, y );\r
-                       \r
-                       /* only look at mapped luxels */\r
-                       if( *cluster < 0 )\r
-                               continue;\r
-                       \r
-                       /* the normal data could be the sum of multiple samples */\r
-                       if( luxel[ 3 ] > 1.0f )\r
-                               VectorNormalize( normal, normal );\r
-                       \r
-                       /* mark this luxel as having only one normal */\r
-                       luxel[ 3 ] = 1.0f;\r
-               }\r
-       }\r
-       \r
-       /* debug code */\r
-       #if 0\r
-               Sys_Printf( "\n" );\r
-               for( y = 0; y < lm->sh; y++ )\r
-               {\r
-                       for( x = 0; x < lm->sw; x++ )\r
-                       {\r
-                               vec3_t  mins, maxs;\r
-                               \r
-\r
-                               cluster = SUPER_CLUSTER( x, y );\r
-                               origin = SUPER_ORIGIN( x, y );\r
-                               normal = SUPER_NORMAL( x, y );\r
-                               luxel = SUPER_LUXEL( x, y );\r
-                               \r
-                               if( *cluster < 0 )\r
-                                       continue;\r
-                               \r
-                               /* check if within the bounding boxes of all surfaces referenced */\r
-                               ClearBounds( mins, maxs );\r
-                               for( n = 0; n < lm->numLightSurfaces; n++ )\r
-                               {\r
-                                       int TOL;\r
-                                       info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + n ] ];\r
-                                       TOL = info->sampleSize + 2;\r
-                                       AddPointToBounds( info->mins, mins, maxs );\r
-                                       AddPointToBounds( info->maxs, mins, maxs );\r
-                                       if( origin[ 0 ] > (info->mins[ 0 ] - TOL) && origin[ 0 ] < (info->maxs[ 0 ] + TOL) &&\r
-                                               origin[ 1 ] > (info->mins[ 1 ] - TOL) && origin[ 1 ] < (info->maxs[ 1 ] + TOL) &&\r
-                                               origin[ 2 ] > (info->mins[ 2 ] - TOL) && origin[ 2 ] < (info->maxs[ 2 ] + TOL) )\r
-                                               break;\r
-                               }\r
-                               \r
-                               /* inside? */\r
-                               if( n < lm->numLightSurfaces )\r
-                                       continue;\r
-                               \r
-                               /* report bogus origin */\r
-                               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",\r
-                                       rawLightmapNum, x, y, *cluster,\r
-                                       origin[ 0 ], origin[ 1 ], origin[ 2 ],\r
-                                       mins[ 0 ], mins[ 1 ], mins[ 2 ],\r
-                                       maxs[ 0 ], maxs[ 1 ], maxs[ 2 ],\r
-                                       luxel[ 3 ] );\r
-                       }\r
-               }\r
-       #endif\r
-}\r
-\r
-\r
-\r
-/*\r
-SubmapRawLuxel()\r
-calculates the pvs cluster, origin, normal of a sub-luxel\r
-*/\r
-\r
-static qboolean SubmapRawLuxel( rawLightmap_t *lm, int x, int y, float bx, float by, int *sampleCluster, vec3_t sampleOrigin, vec3_t sampleNormal )\r
-{\r
-       int                     i, *cluster, *cluster2;\r
-       float           *origin, *origin2, *normal;     //%     , *normal2;\r
-       vec3_t          originVecs[ 2 ];                        //%     , normalVecs[ 2 ];\r
-       \r
-       \r
-       /* calulate x vector */\r
-       if( (x < (lm->sw - 1) && bx >= 0.0f) || (x == 0 && bx <= 0.0f) )\r
-       {\r
-               cluster = SUPER_CLUSTER( x, y );\r
-               origin = SUPER_ORIGIN( x, y );\r
-               //%     normal = SUPER_NORMAL( x, y );\r
-               cluster2 = SUPER_CLUSTER( x + 1, y );\r
-               origin2 = *cluster2 < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x + 1, y );\r
-               //%     normal2 = *cluster2 < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x + 1, y );\r
-       }\r
-       else if( (x > 0 && bx <= 0.0f) || (x == (lm->sw - 1) && bx >= 0.0f) )\r
-       {\r
-               cluster = SUPER_CLUSTER( x - 1, y );\r
-               origin = *cluster < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x - 1, y );\r
-               //%     normal = *cluster < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x - 1, y );\r
-               cluster2 = SUPER_CLUSTER( x, y );\r
-               origin2 = SUPER_ORIGIN( x, y );\r
-               //%     normal2 = SUPER_NORMAL( x, y );\r
-       }\r
-       else\r
-               Sys_Printf( "WARNING: Spurious lightmap S vector\n" );\r
-       \r
-       VectorSubtract( origin2, origin, originVecs[ 0 ] );\r
-       //%     VectorSubtract( normal2, normal, normalVecs[ 0 ] );\r
-       \r
-       /* calulate y vector */\r
-       if( (y < (lm->sh - 1) && bx >= 0.0f) || (y == 0 && bx <= 0.0f) )\r
-       {\r
-               cluster = SUPER_CLUSTER( x, y );\r
-               origin = SUPER_ORIGIN( x, y );\r
-               //%     normal = SUPER_NORMAL( x, y );\r
-               cluster2 = SUPER_CLUSTER( x, y + 1 );\r
-               origin2 = *cluster2 < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x, y + 1 );\r
-               //%     normal2 = *cluster2 < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x, y + 1 );\r
-       }\r
-       else if( (y > 0 && bx <= 0.0f) || (y == (lm->sh - 1) && bx >= 0.0f) )\r
-       {\r
-               cluster = SUPER_CLUSTER( x, y - 1 );\r
-               origin = *cluster < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x, y - 1 );\r
-               //%     normal = *cluster < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x, y - 1 );\r
-               cluster2 = SUPER_CLUSTER( x, y );\r
-               origin2 = SUPER_ORIGIN( x, y );\r
-               //%     normal2 = SUPER_NORMAL( x, y );\r
-       }\r
-       else\r
-               Sys_Printf( "WARNING: Spurious lightmap T vector\n" );\r
-       \r
-       VectorSubtract( origin2, origin, originVecs[ 1 ] );\r
-       //%     VectorSubtract( normal2, normal, normalVecs[ 1 ] );\r
-       \r
-       /* calculate new origin */\r
-       //%     VectorMA( origin, bx, originVecs[ 0 ], sampleOrigin );\r
-       //%     VectorMA( sampleOrigin, by, originVecs[ 1 ], sampleOrigin );\r
-       for( i = 0; i < 3; i++ )\r
-               sampleOrigin[ i ] = sampleOrigin[ i ] + (bx * originVecs[ 0 ][ i ]) + (by * originVecs[ 1 ][ i ]);\r
-       \r
-       /* get cluster */\r
-       *sampleCluster = ClusterForPointExtFilter( sampleOrigin, (LUXEL_EPSILON * 2), lm->numLightClusters, lm->lightClusters );\r
-       if( *sampleCluster < 0 )\r
-               return qfalse;\r
-       \r
-       /* calculate new normal */\r
-       //%     VectorMA( normal, bx, normalVecs[ 0 ], sampleNormal );\r
-       //%     VectorMA( sampleNormal, by, normalVecs[ 1 ], sampleNormal );\r
-       //%     if( VectorNormalize( sampleNormal, sampleNormal ) <= 0.0f )\r
-       //%             return qfalse;\r
-       normal = SUPER_NORMAL( x, y );\r
-       VectorCopy( normal, sampleNormal );\r
-       \r
-       /* return ok */\r
-       return qtrue;\r
-}\r
-\r
-\r
-/*\r
-SubsampleRawLuxel_r()\r
-recursively subsamples a luxel until its color gradient is low enough or subsampling limit is reached\r
-*/\r
-\r
-void SubsampleRawLuxel_r( rawLightmap_t *lm, trace_t *trace, vec3_t sampleOrigin, int x, int y, float bias, float *lightLuxel )\r
-{\r
-       int                     b, samples, mapped, lighted;\r
-       int                     cluster[ 4 ];\r
-       vec4_t          luxel[ 4 ];\r
-       vec3_t          origin[ 4 ], normal[ 4 ];\r
-       float           biasDirs[ 4 ][ 2 ] = { { -1.0f, -1.0f }, { 1.0f, -1.0f }, { -1.0f, 1.0f }, { 1.0f, 1.0f } };\r
-       vec3_t          color, total;\r
-       \r
-       \r
-       /* limit check */\r
-       if( lightLuxel[ 3 ] >= lightSamples )\r
-               return;\r
-       \r
-       /* setup */\r
-       VectorClear( total );\r
-       mapped = 0;\r
-       lighted = 0;\r
-       \r
-       /* make 2x2 subsample stamp */\r
-       for( b = 0; b < 4; b++ )\r
-       {\r
-               /* set origin */\r
-               VectorCopy( sampleOrigin, origin[ b ] );\r
-               \r
-               /* calculate position */\r
-               if( !SubmapRawLuxel( lm, x, y, (bias * biasDirs[ b ][ 0 ]), (bias * biasDirs[ b ][ 1 ]), &cluster[ b ], origin[ b ], normal[ b ] ) )\r
-               {\r
-                       cluster[ b ] = -1;\r
-                       continue;\r
-               }\r
-               mapped++;\r
-               \r
-               /* increment sample count */\r
-               luxel[ b ][ 3 ] = lightLuxel[ 3 ] + 1.0f;\r
-               \r
-               /* setup trace */\r
-               trace->cluster = *cluster;\r
-               VectorCopy( origin[ b ], trace->origin );\r
-               VectorCopy( normal[ b ], trace->normal );\r
-               \r
-               /* sample light */\r
-               //%     LightContributionToSample( light, cluster[ b ], origin[ b ], normal[ b ], luxel[ b ], qtrue, qfalse, lm->numLightSurfaces, &lightSurfaces[ lm->firstLightSurface ] );\r
-               LightContributionToSample( trace );\r
-               \r
-               /* add to totals (fixme: make contrast function) */\r
-               VectorCopy( trace->color, luxel[ b ] );\r
-               VectorAdd( total, trace->color, total );\r
-               if( (luxel[ b ][ 0 ] + luxel[ b ][ 1 ] + luxel[ b ][ 2 ]) > 0.0f )\r
-                       lighted++;\r
-       }\r
-       \r
-       /* subsample further? */\r
-       if( (lightLuxel[ 3 ] + 1.0f) < lightSamples &&\r
-               (total[ 0 ] > 4.0f || total[ 1 ] > 4.0f || total[ 2 ] > 4.0f) &&\r
-               lighted != 0 && lighted != mapped )\r
-       {\r
-               for( b = 0; b < 4; b++ )\r
-               {\r
-                       if( cluster[ b ] < 0 )\r
-                               continue;\r
-                       SubsampleRawLuxel_r( lm, trace, origin[ b ], x, y, (bias * 0.25f), luxel[ b ] );\r
-               }\r
-       }\r
-       \r
-       /* average */\r
-       //%     VectorClear( color );\r
-       //%     samples = 0;\r
-       VectorCopy( lightLuxel, color );\r
-       samples = 1;\r
-       for( b = 0; b < 4; b++ )\r
-       {\r
-               if( cluster[ b ] < 0 )\r
-                       continue;\r
-               VectorAdd( color, luxel[ b ], color );\r
-               samples++;\r
-       }\r
-       \r
-       /* add to luxel */\r
-       if( samples > 0 )\r
-       {\r
-               /* average */\r
-               color[ 0 ] /= samples;\r
-               color[ 1 ] /= samples;\r
-               color[ 2 ] /= samples;\r
-               \r
-               /* add to color */\r
-               VectorCopy( color, lightLuxel );\r
-               lightLuxel[ 3 ] += 1.0f;\r
-       }\r
-}\r
-\r
-\r
-\r
-/*\r
-IlluminateRawLightmap()\r
-illuminates the luxels\r
-*/\r
-\r
-#define LIGHT_LUXEL( x, y )            (lightLuxels + ((((y) * lm->sw) + (x)) * SUPER_LUXEL_SIZE))\r
-\r
-void IlluminateRawLightmap( int rawLightmapNum )\r
-{\r
-       int                                     i, t, x, y, sx, sy, size, llSize, luxelFilterRadius, lightmapNum;\r
-       int                                     *cluster, *cluster2, mapped, lighted, totalLighted;\r
-       rawLightmap_t           *lm;\r
-       surfaceInfo_t           *info;\r
-       qboolean                        filterColor, filterDir;\r
-       float                           brightness;\r
-       float                           *origin, *normal, *luxel, *luxel2, *deluxel, *deluxel2;\r
-       float                           *lightLuxels, *lightLuxel, samples, filterRadius, weight;\r
-       vec3_t                          color, averageColor, averageDir, total, temp, temp2;\r
-       float                           tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };\r
-       trace_t                         trace;\r
-       \r
-       \r
-       /* bail if this number exceeds the number of raw lightmaps */\r
-       if( rawLightmapNum >= numRawLightmaps )\r
-               return;\r
-       \r
-       /* get lightmap */\r
-       lm = &rawLightmaps[ rawLightmapNum ];\r
-       \r
-       /* setup trace */\r
-       trace.testOcclusion = !noTrace;\r
-       trace.forceSunlight = qfalse;\r
-       trace.recvShadows = lm->recvShadows;\r
-       trace.numSurfaces = lm->numLightSurfaces;\r
-       trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];\r
-       trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;\r
-       \r
-       /* twosided lighting (may or may not be a good idea for lightmapped stuff) */\r
-       trace.twoSided = qfalse;\r
-       for( i = 0; i < trace.numSurfaces; i++ )\r
-       {\r
-               /* get surface */\r
-               info = &surfaceInfos[ trace.surfaces[ i ] ];\r
-               \r
-               /* check twosidedness */\r
-               if( info->si->twoSided )\r
-               {\r
-                       trace.twoSided = qtrue;\r
-                       break;\r
-               }\r
-       }\r
-       \r
-       /* create a culled light list for this raw lightmap */\r
-       CreateTraceLightsForBounds( lm->mins, lm->maxs, lm->plane, lm->numLightClusters, lm->lightClusters, LIGHT_SURFACES, &trace );\r
-       \r
-       /* -----------------------------------------------------------------\r
-          fill pass\r
-          ----------------------------------------------------------------- */\r
-       \r
-       /* test debugging state */\r
-       if( debugSurfaces || debugAxis || debugCluster || debugOrigin || normalmap )\r
-       {\r
-               /* debug fill the luxels */\r
-               for( y = 0; y < lm->sh; y++ )\r
-               {\r
-                       for( x = 0; x < lm->sw; x++ )\r
-                       {\r
-                               /* get cluster */\r
-                               cluster = SUPER_CLUSTER( x, y );\r
-\r
-                               /* only fill mapped luxels */\r
-                               if( *cluster < 0 )\r
-                                       continue;\r
-                               \r
-                               /* get particulars */\r
-                               luxel = SUPER_LUXEL( 0, x, y );\r
-                               origin = SUPER_ORIGIN( x, y );\r
-                               normal = SUPER_NORMAL( x, y );\r
-                               \r
-                               /* color the luxel with raw lightmap num? */\r
-                               if( debugSurfaces )\r
-                                       VectorCopy( debugColors[ rawLightmapNum % 12 ], luxel );\r
-                               \r
-                               /* color the luxel with lightmap axis? */\r
-                               else if( debugAxis )\r
-                               {\r
-                                       luxel[ 0 ] = (lm->axis[ 0 ] + 1.0f) * 127.5f;\r
-                                       luxel[ 1 ] = (lm->axis[ 1 ] + 1.0f) * 127.5f;\r
-                                       luxel[ 2 ] = (lm->axis[ 2 ] + 1.0f) * 127.5f;\r
-                               }\r
-                               \r
-                               /* color the luxel with luxel cluster? */\r
-                               else if( debugCluster )\r
-                                       VectorCopy( debugColors[ *cluster % 12 ], luxel );\r
-                               \r
-                               /* color the luxel with luxel origin? */\r
-                               else if( debugOrigin )\r
-                               {\r
-                                       VectorSubtract( lm->maxs, lm->mins, temp );\r
-                                       VectorScale( temp, (1.0f / 255.0f), temp );\r
-                                       VectorSubtract( origin, lm->mins, temp2 );\r
-                                       luxel[ 0 ] = lm->mins[ 0 ] + (temp[ 0 ] * temp2[ 0 ]);\r
-                                       luxel[ 1 ] = lm->mins[ 1 ] + (temp[ 1 ] * temp2[ 1 ]);\r
-                                       luxel[ 2 ] = lm->mins[ 2 ] + (temp[ 2 ] * temp2[ 2 ]);\r
-                               }\r
-                               \r
-                               /* color the luxel with the normal */\r
-                               else if( normalmap )\r
-                               {\r
-                                       luxel[ 0 ] = (normal[ 0 ] + 1.0f) * 127.5f;\r
-                                       luxel[ 1 ] = (normal[ 1 ] + 1.0f) * 127.5f;\r
-                                       luxel[ 2 ] = (normal[ 2 ] + 1.0f) * 127.5f;\r
-                               }\r
-                               \r
-                               /* add to counts */\r
-                               numLuxelsIlluminated++;\r
-                               luxel[ 3 ] = 1.0f;\r
-                       }\r
-               }\r
-       }\r
-       else\r
-       {\r
-               /* allocate temporary per-light luxel storage */\r
-               llSize = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );\r
-               lightLuxels = safe_malloc( llSize );\r
-               \r
-               /* clear luxels */\r
-               //%     memset( lm->superLuxels[ 0 ], 0, llSize );\r
-               \r
-               /* set ambient color */\r
-               for( y = 0; y < lm->sh; y++ )\r
-               {\r
-                       for( x = 0; x < lm->sw; x++ )\r
-                       {\r
-                               /* get cluster */\r
-                               cluster = SUPER_CLUSTER( x, y );\r
-                               luxel = SUPER_LUXEL( 0, x, y );\r
-                               normal = SUPER_NORMAL( x, y );\r
-                               deluxel = SUPER_DELUXEL( x, y );\r
-                               \r
-                               /* blacken unmapped clusters */\r
-                               if( *cluster < 0 )\r
-                                       VectorClear( luxel );\r
-                               \r
-                               /* set ambient */\r
-                               else\r
-                               {\r
-                                       VectorCopy( ambientColor, luxel );\r
-                                       if( deluxemap )\r
-                                               VectorScale( normal, 0.00390625f, deluxel );\r
-                                       luxel[ 3 ] = 1.0f;\r
-                               }\r
-                       }\r
-               }\r
-               \r
-               /* clear styled lightmaps */\r
-               size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );\r
-               for( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )\r
-               {\r
-                       if( lm->superLuxels[ lightmapNum ] != NULL )\r
-                               memset( lm->superLuxels[ lightmapNum ], 0, size );\r
-               }\r
-               \r
-               /* debugging code */\r
-               //%     if( trace.numLights <= 0 )\r
-               //%             Sys_Printf( "Lightmap %9d: 0 lights, axis: %.2f, %.2f, %.2f\n", rawLightmapNum, lm->axis[ 0 ], lm->axis[ 1 ], lm->axis[ 2 ] );\r
-               \r
-               /* walk light list */\r
-               for( i = 0; i < trace.numLights; i++ )\r
-               {\r
-                       /* setup trace */\r
-                       trace.light = trace.lights[ i ];\r
-                       \r
-                       /* style check */\r
-                       for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )\r
-                       {\r
-                               if( lm->styles[ lightmapNum ] == trace.light->style ||\r
-                                       lm->styles[ lightmapNum ] == LS_NONE )\r
-                                       break;\r
-                       }\r
-                       \r
-                       /* max of MAX_LIGHTMAPS (4) styles allowed to hit a surface/lightmap */\r
-                       if( lightmapNum >= MAX_LIGHTMAPS )\r
-                       {\r
-                               Sys_Printf( "WARNING: Hit per-surface style limit (%d)\n", MAX_LIGHTMAPS );\r
-                               continue;\r
-                       }\r
-                       \r
-                       /* setup */\r
-                       memset( lightLuxels, 0, llSize );\r
-                       totalLighted = 0;\r
-                       \r
-                       /* initial pass, one sample per luxel */\r
-                       for( y = 0; y < lm->sh; y++ )\r
-                       {\r
-                               for( x = 0; x < lm->sw; x++ )\r
-                               {\r
-                                       /* get cluster */\r
-                                       cluster = SUPER_CLUSTER( x, y );\r
-                                       if( *cluster < 0 )\r
-                                               continue;\r
-                                       \r
-                                       /* get particulars */\r
-                                       lightLuxel = LIGHT_LUXEL( x, y );\r
-                                       deluxel = SUPER_DELUXEL( x, y );\r
-                                       origin = SUPER_ORIGIN( x, y );\r
-                                       normal = SUPER_NORMAL( x, y );\r
-                                       \r
-                                       /* set contribution count */\r
-                                       lightLuxel[ 3 ] = 1.0f;\r
-                                       \r
-                                       /* setup trace */\r
-                                       trace.cluster = *cluster;\r
-                                       VectorCopy( origin, trace.origin );\r
-                                       VectorCopy( normal, trace.normal );\r
-                                       \r
-                                       /* get light for this sample */\r
-                                       LightContributionToSample( &trace );\r
-                                       VectorCopy( trace.color, lightLuxel );\r
-                                       \r
-                                       /* add to count */\r
-                                       if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )\r
-                                               totalLighted++;\r
-                                       \r
-                                       /* add to light direction map (fixme: use luxel normal as starting point for deluxel?) */\r
-                                       if( deluxemap )\r
-                                       {\r
-                                               /* color to grayscale (photoshop rgb weighting) */\r
-                                               brightness = trace.color[ 0 ] * 0.3f + trace.color[ 1 ] * 0.59f + trace.color[ 2 ] * 0.11f;\r
-                                               brightness *= (1.0 / 255.0);\r
-                                               VectorScale( trace.direction, brightness, trace.direction );\r
-                                               VectorAdd( deluxel, trace.direction, deluxel );\r
-                                       }\r
-                               }\r
-                       }\r
-                       \r
-                       /* don't even bother with everything else if nothing was lit */\r
-                       if( totalLighted == 0 )\r
-                               continue;\r
-                       \r
-                       /* determine filter radius */\r
-                       filterRadius = lm->filterRadius > trace.light->filterRadius\r
-                               ? lm->filterRadius\r
-                               : trace.light->filterRadius;\r
-                       if( filterRadius < 0.0f )\r
-                               filterRadius = 0.0f;\r
-                       \r
-                       /* set luxel filter radius */\r
-                       luxelFilterRadius = superSample * filterRadius / lm->sampleSize;\r
-                       if( luxelFilterRadius == 0 && (filterRadius > 0.0f || filter) )\r
-                               luxelFilterRadius = 1;\r
-                       \r
-                       /* secondary pass, adaptive supersampling (fixme: use a contrast function to determine if subsampling is necessary) */\r
-                       /* 2003-09-27: changed it so filtering disamples supersampling, as it would waste time */\r
-                       if( lightSamples > 1 && luxelFilterRadius == 0 )\r
-                       {\r
-                               /* walk luxels */\r
-                               for( y = 0; y < (lm->sh - 1); y++ )\r
-                               {\r
-                                       for( x = 0; x < (lm->sw - 1); x++ )\r
-                                       {\r
-                                               /* setup */\r
-                                               mapped = 0;\r
-                                               lighted = 0;\r
-                                               VectorClear( total );\r
-                                               \r
-                                               /* test 2x2 stamp */\r
-                                               for( t = 0; t < 4; t++ )\r
-                                               {\r
-                                                       /* set sample coords */\r
-                                                       sx = x + tests[ t ][ 0 ];\r
-                                                       sy = y + tests[ t ][ 1 ];\r
-                                                       \r
-                                                       /* get cluster */\r
-                                                       cluster = SUPER_CLUSTER( sx, sy );\r
-                                                       if( *cluster < 0 )\r
-                                                               continue;\r
-                                                       mapped++;\r
-                                                       \r
-                                                       /* get luxel */\r
-                                                       lightLuxel = LIGHT_LUXEL( sx, sy );\r
-                                                       VectorAdd( total, lightLuxel, total );\r
-                                                       if( (lightLuxel[ 0 ] + lightLuxel[ 1 ] + lightLuxel[ 2 ]) > 0.0f )\r
-                                                               lighted++;\r
-                                               }\r
-                                               \r
-                                               /* if total color is under a certain amount, then don't bother subsampling */\r
-                                               if( total[ 0 ] <= 4.0f && total[ 1 ] <= 4.0f && total[ 2 ] <= 4.0f )\r
-                                                       continue;\r
-                                               \r
-                                               /* if all 4 pixels are either in shadow or light, then don't subsample */\r
-                                               if( lighted != 0 && lighted != mapped )\r
-                                               {\r
-                                                       for( t = 0; t < 4; t++ )\r
-                                                       {\r
-                                                               /* set sample coords */\r
-                                                               sx = x + tests[ t ][ 0 ];\r
-                                                               sy = y + tests[ t ][ 1 ];\r
-                                                               \r
-                                                               /* get luxel */\r
-                                                               cluster = SUPER_CLUSTER( sx, sy );\r
-                                                               if( *cluster < 0 )\r
-                                                                       continue;\r
-                                                               lightLuxel = LIGHT_LUXEL( sx, sy );\r
-                                                               origin = SUPER_ORIGIN( sx, sy );\r
-                                                               \r
-                                                               /* only subsample shadowed luxels */\r
-                                                               //%     if( (lightLuxel[ 0 ] + lightLuxel[ 1 ] + lightLuxel[ 2 ]) <= 0.0f )\r
-                                                               //%             continue;\r
-                                                               \r
-                                                               /* subsample it */\r
-                                                               SubsampleRawLuxel_r( lm, &trace, origin, sx, sy, 0.25f, lightLuxel );\r
-                                                               \r
-                                                               /* debug code to colorize subsampled areas to yellow */\r
-                                                               //%     luxel = SUPER_LUXEL( lightmapNum, sx, sy );\r
-                                                               //%     VectorSet( luxel, 255, 204, 0 );\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-                       \r
-                       /* allocate sampling lightmap storage */\r
-                       if( lm->superLuxels[ lightmapNum ] == NULL )\r
-                       {\r
-                               /* allocate sampling lightmap storage */\r
-                               size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );\r
-                               lm->superLuxels[ lightmapNum ] = safe_malloc( size );\r
-                               memset( lm->superLuxels[ lightmapNum ], 0, size );\r
-                       }\r
-                       \r
-                       /* set style */\r
-                       if( lightmapNum > 0 )\r
-                       {\r
-                               lm->styles[ lightmapNum ] = trace.light->style;\r
-                               //%     Sys_Printf( "Surface %6d has lightstyle %d\n", rawLightmapNum, trace.light->style );\r
-                       }\r
-                       \r
-                       /* copy to permanent luxels */\r
-                       for( y = 0; y < lm->sh; y++ )\r
-                       {\r
-                               for( x = 0; x < lm->sw; x++ )\r
-                               {\r
-                                       /* get cluster and origin */\r
-                                       cluster = SUPER_CLUSTER( x, y );\r
-                                       if( *cluster < 0 )\r
-                                               continue;\r
-                                       origin = SUPER_ORIGIN( x, y );\r
-                                       \r
-                                       /* filter? */\r
-                                       if( luxelFilterRadius )\r
-                                       {\r
-                                               /* setup */\r
-                                               VectorClear( averageColor );\r
-                                               samples = 0.0f;\r
-                                               \r
-                                               /* cheaper distance-based filtering */\r
-                                               for( sy = (y - luxelFilterRadius); sy <= (y + luxelFilterRadius); sy++ )\r
-                                               {\r
-                                                       if( sy < 0 || sy >= lm->sh )\r
-                                                               continue;\r
-                                                       \r
-                                                       for( sx = (x - luxelFilterRadius); sx <= (x + luxelFilterRadius); sx++ )\r
-                                                       {\r
-                                                               if( sx < 0 || sx >= lm->sw )\r
-                                                                       continue;\r
-                                                               \r
-                                                               /* get particulars */\r
-                                                               cluster = SUPER_CLUSTER( sx, sy );\r
-                                                               if( *cluster < 0 )\r
-                                                                       continue;\r
-                                                               lightLuxel = LIGHT_LUXEL( sx, sy );\r
-                                                               \r
-                                                               /* create weight */\r
-                                                               weight = (abs( sx - x ) == luxelFilterRadius ? 0.5f : 1.0f);\r
-                                                               weight *= (abs( sy - y ) == luxelFilterRadius ? 0.5f : 1.0f);\r
-                                                               \r
-                                                               /* scale luxel by filter weight */\r
-                                                               VectorScale( lightLuxel, weight, color );\r
-                                                               VectorAdd( averageColor, color, averageColor );\r
-                                                               samples += weight;\r
-                                                       }\r
-                                               }\r
-                                               \r
-                                               /* any samples? */\r
-                                               if( samples <= 0.0f     )\r
-                                                       continue;\r
-                                               \r
-                                               /* scale into luxel */\r
-                                               luxel = SUPER_LUXEL( lightmapNum, x, y );\r
-                                               luxel[ 3 ] = 1.0f;\r
-                                               \r
-                                               /* handle negative light */\r
-                                               if( trace.light->flags & LIGHT_NEGATIVE )\r
-                                               { \r
-                                                       luxel[ 0 ] -= averageColor[ 0 ] / samples;\r
-                                                       luxel[ 1 ] -= averageColor[ 1 ] / samples;\r
-                                                       luxel[ 2 ] -= averageColor[ 2 ] / samples;\r
-                                               }\r
-                                               \r
-                                               /* handle normal light */\r
-                                               else\r
-                                               { \r
-                                                       luxel[ 0 ] += averageColor[ 0 ] / samples;\r
-                                                       luxel[ 1 ] += averageColor[ 1 ] / samples;\r
-                                                       luxel[ 2 ] += averageColor[ 2 ] / samples;\r
-                                               }\r
-                                       }\r
-                                       \r
-                                       /* single sample */\r
-                                       else\r
-                                       {\r
-                                               /* get particulars */\r
-                                               lightLuxel = LIGHT_LUXEL( x, y );\r
-                                               luxel = SUPER_LUXEL( lightmapNum, x, y );\r
-                                               \r
-                                               /* handle negative light */\r
-                                               if( trace.light->flags & LIGHT_NEGATIVE )\r
-                                                       VectorScale( averageColor, -1.0f, averageColor );\r
-\r
-                                               /* add color */\r
-                                               luxel[ 3 ] = 1.0f;\r
-                                               \r
-                                               /* handle negative light */\r
-                                               if( trace.light->flags & LIGHT_NEGATIVE )\r
-                                                       VectorSubtract( luxel, lightLuxel, luxel );\r
-                                               \r
-                                               /* handle normal light */\r
-                                               else\r
-                                                       VectorAdd( luxel, lightLuxel, luxel );\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-               \r
-               /* free temporary luxels */\r
-               free( lightLuxels );\r
-       }\r
-       \r
-       /* free light list */\r
-       FreeTraceLights( &trace );\r
-       \r
-       /* -----------------------------------------------------------------\r
-          filter pass\r
-          ----------------------------------------------------------------- */\r
-       \r
-       /* walk lightmaps */\r
-       for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )\r
-       {\r
-               /* early out */\r
-               if( lm->superLuxels[ lightmapNum ] == NULL )\r
-                       continue;\r
-               \r
-               /* average occluded luxels from neighbors */\r
-               for( y = 0; y < lm->sh; y++ )\r
-               {\r
-                       for( x = 0; x < lm->sw; x++ )\r
-                       {\r
-                               /* get particulars */\r
-                               cluster = SUPER_CLUSTER( x, y );\r
-                               luxel = SUPER_LUXEL( lightmapNum, x, y );\r
-                               deluxel = SUPER_DELUXEL( x, y );\r
-                               normal = SUPER_NORMAL( x, y );\r
-                               \r
-                               /* determine if filtering is necessary */\r
-                               filterColor = qfalse;\r
-                               filterDir = qfalse;\r
-                               if( *cluster < 0 ||\r
-                                       (lm->splotchFix && (luxel[ 0 ] <= ambientColor[ 0 ] || luxel[ 1 ] <= ambientColor[ 1 ] || luxel[ 2 ] <= ambientColor[ 2 ])) )\r
-                                       filterColor = qtrue;\r
-                               if( deluxemap && lightmapNum == 0 && (*cluster < 0 || filter) )\r
-                                       filterDir = qtrue;\r
-                               \r
-                               if( !filterColor && !filterDir )\r
-                                       continue;\r
-                               \r
-                               /* choose seed amount */\r
-                               VectorClear( averageColor );\r
-                               VectorClear( averageDir );\r
-                               samples = 0;\r
-                               \r
-                               /* walk 3x3 matrix */\r
-                               for( sy = (y - 1); sy <= (y + 1); sy++ )\r
-                               {\r
-                                       if( sy < 0 || sy >= lm->sh )\r
-                                               continue;\r
-                                       \r
-                                       for( sx = (x - 1); sx <= (x + 1); sx++ )\r
-                                       {\r
-                                               if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )\r
-                                                       continue;\r
-                                               \r
-                                               /* get neighbor's particulars */\r
-                                               cluster2 = SUPER_CLUSTER( sx, sy );\r
-                                               luxel2 = SUPER_LUXEL( lightmapNum, sx, sy );\r
-                                               deluxel2 = SUPER_DELUXEL( sx, sy );\r
-                                               \r
-                                               /* ignore unmapped/unlit luxels */\r
-                                               if( *cluster2 < 0 || luxel2[ 3 ] == 0.0f ||\r
-                                                       (lm->splotchFix && VectorCompare( luxel2, ambientColor )) )\r
-                                                       continue;\r
-                                               \r
-                                               /* add its distinctiveness to our own */\r
-                                               VectorAdd( averageColor, luxel2, averageColor );\r
-                                               samples += luxel2[ 3 ];\r
-                                               if( filterDir )\r
-                                                       VectorAdd( averageDir, deluxel2, averageDir );\r
-                                       }\r
-                               }\r
-                               \r
-                               /* fall through */\r
-                               if( samples == 0.0f )\r
-                                       continue;\r
-                               \r
-                               /* average it */\r
-                               if( filterColor )\r
-                               {\r
-                                       VectorDivide( averageColor, samples, luxel );\r
-                                       luxel[ 3 ] = 1.0f;\r
-                               }\r
-                               if( filterDir )\r
-                                       VectorDivide( averageDir, samples, deluxel );\r
-                               \r
-                               /* set cluster to -3 */\r
-                               if( *cluster < 0 )\r
-                                       *cluster = CLUSTER_FLOODED;\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-\r
-\r
-/*\r
-IlluminateVertexes()\r
-light the surface vertexes\r
-*/\r
-\r
-#define VERTEX_NUDGE   2.0f\r
-\r
-void IlluminateVertexes( int num )\r
-{\r
-       int                                     i, x, y, z, x1, y1, z1, sx, sy, radius, maxRadius, *cluster;\r
-       int                                     lightmapNum;\r
-       float                           samples, *vertLuxel, *radVertLuxel, *luxel;\r
-       vec3_t                          origin, temp, temp2, colors[ MAX_LIGHTMAPS ];\r
-       bspDrawSurface_t        *ds;\r
-       surfaceInfo_t           *info;\r
-       rawLightmap_t           *lm;\r
-       bspDrawVert_t           *verts;\r
-       trace_t                         trace;\r
-       \r
-       \r
-       /* der... */\r
-       if( noVertexLighting )\r
-               return;\r
-       \r
-       /* get surface, info, and raw lightmap */\r
-       ds = &bspDrawSurfaces[ num ];\r
-       info = &surfaceInfos[ num ];\r
-       lm = info->lm;\r
-       \r
-       /* -----------------------------------------------------------------\r
-          illuminate the vertexes\r
-          ----------------------------------------------------------------- */\r
-       \r
-       /* calculate vertex lighting for surfaces without lightmaps */\r
-       if( lm == NULL )\r
-       {\r
-               /* setup trace */\r
-               trace.testOcclusion = !noTrace;\r
-               trace.forceSunlight = info->si->forceSunlight;\r
-               trace.recvShadows = info->recvShadows;\r
-               trace.numSurfaces = 1;\r
-               trace.surfaces = &num;\r
-               trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;\r
-               \r
-               /* twosided lighting */\r
-               trace.twoSided = info->si->twoSided;\r
-               \r
-               /* make light list for this surface */\r
-               CreateTraceLightsForSurface( num, &trace );\r
-               \r
-               /* walk the surface verts */\r
-               verts = yDrawVerts + ds->firstVert;\r
-               for( i = 0; i < ds->numVerts; i++ )\r
-               {\r
-                       /* get vertex luxel */\r
-                       radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );\r
-                       \r
-                       /* color the luxel with raw lightmap num? */\r
-                       if( debugSurfaces )\r
-                               VectorCopy( debugColors[ num % 12 ], radVertLuxel );\r
-                       \r
-                       /* color the luxel with luxel origin? */\r
-                       else if( debugOrigin )\r
-                       {\r
-                               VectorSubtract( info->maxs, info->mins, temp );\r
-                               VectorScale( temp, (1.0f / 255.0f), temp );\r
-                               VectorSubtract( origin, lm->mins, temp2 );\r
-                               radVertLuxel[ 0 ] = info->mins[ 0 ] + (temp[ 0 ] * temp2[ 0 ]);\r
-                               radVertLuxel[ 1 ] = info->mins[ 1 ] + (temp[ 1 ] * temp2[ 1 ]);\r
-                               radVertLuxel[ 2 ] = info->mins[ 2 ] + (temp[ 2 ] * temp2[ 2 ]);\r
-                       }\r
-                       \r
-                       /* color the luxel with the normal */\r
-                       else if( normalmap )\r
-                       {\r
-                               radVertLuxel[ 0 ] = (verts[ i ].normal[ 0 ] + 1.0f) * 127.5f;\r
-                               radVertLuxel[ 1 ] = (verts[ i ].normal[ 1 ] + 1.0f) * 127.5f;\r
-                               radVertLuxel[ 2 ] = (verts[ i ].normal[ 2 ] + 1.0f) * 127.5f;\r
-                       }\r
-                       \r
-                       /* illuminate the vertex */\r
-                       else\r
-                       {\r
-                               /* clear vertex luxel */\r
-                               VectorCopy( ambientColor, radVertLuxel );\r
-                               \r
-                               /* try at initial origin */\r
-                               trace.cluster = ClusterForPointExtFilter( verts[ i ].xyz, VERTEX_EPSILON, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ] );\r
-                               if( trace.cluster >= 0 )\r
-                               {\r
-                                       /* setup trace */\r
-                                       VectorCopy( verts[ i ].xyz, trace.origin );\r
-                                       VectorCopy( verts[ i ].normal, trace.normal );\r
-                                       \r
-                                       /* trace */\r
-                                       LightingAtSample( &trace, ds->vertexStyles, colors );\r
-                                       \r
-                                       /* store */\r
-                                       for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )\r
-                                       {\r
-                                               radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );\r
-                                               VectorCopy( colors[ lightmapNum ], radVertLuxel );\r
-                                       }\r
-                               }\r
-                               \r
-                               /* is this sample bright enough? */\r
-                               if( radVertLuxel[ 0 ] <= ambientColor[ 0 ] &&\r
-                                       radVertLuxel[ 1 ] <= ambientColor[ 1 ] &&\r
-                                       radVertLuxel[ 2 ] <= ambientColor[ 2 ] )\r
-                               {\r
-                                       /* nudge the sample point around a bit */\r
-                                       for( x = 0; x < 4; x++ )\r
-                                       {\r
-                                               /* two's complement 0, 1, -1, 2, -2, etc */\r
-                                               x1 = ((x >> 1) ^ (x & 1 ? -1 : 0)) + (x & 1);\r
-                                               \r
-                                               for( y = 0; y < 4; y++ )\r
-                                               {\r
-                                                       y1 = ((y >> 1) ^ (y & 1 ? -1 : 0)) + (y & 1);\r
-                                                       \r
-                                                       for( z = 0; z < 4; z++ )\r
-                                                       {\r
-                                                               z1 = ((z >> 1) ^ (z & 1 ? -1 : 0)) + (z & 1);\r
-                                                               \r
-                                                               /* nudge origin */\r
-                                                               trace.origin[ 0 ] = verts[ i ].xyz[ 0 ] + (VERTEX_NUDGE * x1);\r
-                                                               trace.origin[ 1 ] = verts[ i ].xyz[ 1 ] + (VERTEX_NUDGE * y1);\r
-                                                               trace.origin[ 2 ] = verts[ i ].xyz[ 2 ] + (VERTEX_NUDGE * z1);\r
-                                                               \r
-                                                               /* try at nudged origin */\r
-                                                               trace.cluster = ClusterForPointExtFilter( origin, VERTEX_EPSILON, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ] );\r
-                                                               if( trace.cluster < 0 )\r
-                                                                       continue;\r
-                                                                                                                       \r
-                                                               /* trace */\r
-                                                               LightingAtSample( &trace, ds->vertexStyles, colors );\r
-                                                               \r
-                                                               /* store */\r
-                                                               for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )\r
-                                                               {\r
-                                                                       radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );\r
-                                                                       VectorCopy( colors[ lightmapNum ], radVertLuxel );\r
-                                                               }\r
-                                                               \r
-                                                               /* bright enough? */\r
-                                                               radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );\r
-                                                               if( radVertLuxel[ 0 ] > ambientColor[ 0 ] ||\r
-                                                                       radVertLuxel[ 1 ] > ambientColor[ 1 ] ||\r
-                                                                       radVertLuxel[ 2 ] > ambientColor[ 2 ] )\r
-                                                                       x = y = z = 1000;\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-                       \r
-                       /* another happy customer */\r
-                       numVertsIlluminated++;\r
-                       \r
-                       /* store it */\r
-                       for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )\r
-                       {\r
-                               /* get luxels */\r
-                               vertLuxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + i );\r
-                               radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );\r
-                               \r
-                               /* store */\r
-                               if( bouncing || bounce == 0 || !bounceOnly )\r
-                                       VectorAdd( vertLuxel, radVertLuxel, vertLuxel );\r
-                               ColorToBytes( vertLuxel, verts[ i ].color[ lightmapNum ], info->si->vertexScale );\r
-                       }\r
-               }\r
-               \r
-               /* free light list */\r
-               FreeTraceLights( &trace );\r
-               \r
-               /* return to sender */\r
-               return;\r
-       }\r
-       \r
-       /* -----------------------------------------------------------------\r
-          reconstitute vertex lighting from the luxels\r
-          ----------------------------------------------------------------- */\r
-       \r
-       /* set styles from lightmap */\r
-       for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )\r
-               ds->vertexStyles[ lightmapNum ] = lm->styles[ lightmapNum ];\r
-       \r
-       /* get max search radius */\r
-       maxRadius = lm->sw;\r
-       maxRadius = maxRadius > lm->sh ? maxRadius : lm->sh;\r
-       \r
-       /* walk the surface verts */\r
-       verts = yDrawVerts + ds->firstVert;\r
-       for( i = 0; i < ds->numVerts; i++ )\r
-       {\r
-               /* do each lightmap */\r
-               for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )\r
-               {\r
-                       /* early out */\r
-                       if( lm->superLuxels[ lightmapNum ] == NULL )\r
-                               continue;\r
-                       \r
-                       /* get luxel coords */\r
-                       x = verts[ i ].lightmap[ lightmapNum ][ 0 ];\r
-                       y = verts[ i ].lightmap[ lightmapNum ][ 1 ];\r
-                       if( x < 0 )\r
-                               x = 0;\r
-                       else if( x >= lm->sw )\r
-                               x = lm->sw - 1;\r
-                       if( y < 0 )\r
-                               y = 0;\r
-                       else if( y >= lm->sh )\r
-                               y = lm->sh - 1;\r
-                       \r
-                       /* get vertex luxels */\r
-                       vertLuxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + i );\r
-                       radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );\r
-                       \r
-                       /* color the luxel with the normal? */\r
-                       if( normalmap )\r
-                       {\r
-                               radVertLuxel[ 0 ] = (verts[ i ].normal[ 0 ] + 1.0f) * 127.5f;\r
-                               radVertLuxel[ 1 ] = (verts[ i ].normal[ 1 ] + 1.0f) * 127.5f;\r
-                               radVertLuxel[ 2 ] = (verts[ i ].normal[ 2 ] + 1.0f) * 127.5f;\r
-                       }\r
-                       \r
-                       /* color the luxel with surface num? */\r
-                       else if( debugSurfaces )\r
-                               VectorCopy( debugColors[ num % 12 ], radVertLuxel );\r
-                       \r
-                       /* divine color from the superluxels */\r
-                       else\r
-                       {\r
-                               /* increasing radius */\r
-                               VectorClear( radVertLuxel );\r
-                               samples = 0.0f;\r
-                               for( radius = 0; radius < maxRadius && samples <= 0.0f; radius++ )\r
-                               {\r
-                                       /* sample within radius */\r
-                                       for( sy = (y - radius); sy <= (y + radius); sy++ )\r
-                                       {\r
-                                               if( sy < 0 || sy >= lm->sh )\r
-                                                       continue;\r
-                                               \r
-                                               for( sx = (x - radius); sx <= (x + radius); sx++ )\r
-                                               {\r
-                                                       if( sx < 0 || sx >= lm->sw )\r
-                                                               continue;\r
-                                                       \r
-                                                       /* get luxel particulars */\r
-                                                       luxel = SUPER_LUXEL( lightmapNum, sx, sy );\r
-                                                       cluster = SUPER_CLUSTER( sx, sy );\r
-                                                       if( *cluster < 0 )\r
-                                                               continue;\r
-                                                       \r
-                                                       /* testing: must be brigher than ambient color */\r
-                                                       //%     if( luxel[ 0 ] <= ambientColor[ 0 ] || luxel[ 1 ] <= ambientColor[ 1 ] || luxel[ 2 ] <= ambientColor[ 2 ] )\r
-                                                       //%             continue;\r
-                                                       \r
-                                                       /* add its distinctiveness to our own */\r
-                                                       VectorAdd( radVertLuxel, luxel, radVertLuxel );\r
-                                                       samples += luxel[ 3 ];\r
-                                               }\r
-                                       }\r
-                               }\r
-                               \r
-                               /* any color? */\r
-                               if( samples > 0.0f )\r
-                                       VectorDivide( radVertLuxel, samples, radVertLuxel );\r
-                               else\r
-                                       VectorCopy( ambientColor, radVertLuxel );\r
-                       }\r
-                       \r
-                       /* store into floating point storage */\r
-                       VectorAdd( vertLuxel, radVertLuxel, vertLuxel );\r
-                       numVertsIlluminated++;\r
-                       \r
-                       /* store into bytes (for vertex approximation) */\r
-                       ColorToBytes( vertLuxel, verts[ i ].color[ lightmapNum ], 1.0f );\r
-               }\r
-       }\r
-}\r
-\r
-\r
-\r
-/* -------------------------------------------------------------------------------\r
-\r
-light optimization (-fast)\r
-\r
-creates a list of lights that will affect a surface and stores it in tw\r
-this is to optimize surface lighting by culling out as many of the\r
-lights in the world as possible from further calculation\r
-\r
-------------------------------------------------------------------------------- */\r
-\r
-/*\r
-SetupBrushes()\r
-determines opaque brushes in the world and find sky shaders for sunlight calculations\r
-*/\r
-\r
-void SetupBrushes( void )\r
-{\r
-       int                             i, j, b, compileFlags;\r
-       qboolean                inside;\r
-       bspBrush_t              *brush;\r
-       bspBrushSide_t  *side;\r
-       bspShader_t             *shader;\r
-       shaderInfo_t    *si;\r
-       \r
-       \r
-       /* note it */\r
-       Sys_FPrintf( SYS_VRB, "--- SetupBrushes ---\n" );\r
-       \r
-       /* allocate */\r
-       if( opaqueBrushes == NULL )\r
-               opaqueBrushes = safe_malloc( numBSPBrushes / 8 + 1 );\r
-       \r
-       /* clear */\r
-       memset( opaqueBrushes, 0, numBSPBrushes / 8 + 1 );\r
-       numOpaqueBrushes = 0;\r
-       \r
-       /* walk the list of worldspawn brushes */\r
-       for( i = 0; i < bspModels[ 0 ].numBSPBrushes; i++ )\r
-       {\r
-               /* get brush */\r
-               b = bspModels[ 0 ].firstBSPBrush + i;\r
-               brush = &bspBrushes[ b ];\r
-               \r
-               /* check all sides */\r
-               inside = qtrue;\r
-               compileFlags = 0;\r
-               for( j = 0; j < brush->numSides && inside; j++ )\r
-               {\r
-                       /* do bsp shader calculations */\r
-                       side = &bspBrushSides[ brush->firstSide + j ];\r
-                       shader = &bspShaders[ side->shaderNum ];\r
-                       \r
-                       /* get shader info */\r
-                       si = ShaderInfoForShader( shader->shader );\r
-                       if( si == NULL )\r
-                               continue;\r
-                       \r
-                       /* or together compile flags */\r
-                       compileFlags |= si->compileFlags;\r
-               }\r
-               \r
-               /* determine if this brush is opaque to light */\r
-               if( !(compileFlags & C_TRANSLUCENT) )\r
-               {\r
-                       opaqueBrushes[ b >> 3 ] |= (1 << (b & 7));\r
-                       numOpaqueBrushes++;\r
-                       maxOpaqueBrush = i;\r
-               }\r
-       }\r
-       \r
-       /* emit some statistics */\r
-       Sys_FPrintf( SYS_VRB, "%9d opaque brushes\n", numOpaqueBrushes );\r
-}\r
-\r
-\r
-\r
-/*\r
-ClusterVisible()\r
-determines if two clusters are visible to each other using the PVS\r
-*/\r
-\r
-qboolean ClusterVisible( int a, int b )\r
-{\r
-       int                     portalClusters, leafBytes;\r
-       byte            *pvs;\r
-       \r
-       \r
-       /* dummy check */\r
-       if( a < 0 || b < 0 )\r
-               return qfalse;\r
-       \r
-       /* early out */\r
-       if( a == b )\r
-               return qtrue;\r
-       \r
-       /* not vised? */\r
-       if( numBSPVisBytes <=8 )\r
-               return qtrue;\r
-       \r
-       /* get pvs data */\r
-       portalClusters = ((int *) bspVisBytes)[ 0 ];\r
-       leafBytes = ((int*) bspVisBytes)[ 1 ];\r
-       pvs = bspVisBytes + VIS_HEADER_SIZE + (a * leafBytes);\r
-       \r
-       /* check */\r
-       if( (pvs[ b >> 3 ] & (1 << (b & 7))) )\r
-               return qtrue;\r
-       return qfalse;\r
-}\r
-\r
-\r
-\r
-/*\r
-PointInLeafNum_r()\r
-borrowed from vlight.c\r
-*/\r
-\r
-int    PointInLeafNum_r( vec3_t point, int nodenum )\r
-{\r
-       int                     leafnum;\r
-       vec_t           dist;\r
-       bspNode_t               *node;\r
-       bspPlane_t      *plane;\r
-       \r
-       \r
-       while( nodenum >= 0 )\r
-       {\r
-               node = &bspNodes[ nodenum ];\r
-               plane = &bspPlanes[ node->planeNum ];\r
-               dist = DotProduct( point, plane->normal ) - plane->dist;\r
-               if( dist > 0.1 )\r
-                       nodenum = node->children[ 0 ];\r
-               else if( dist < -0.1 )\r
-                       nodenum = node->children[ 1 ];\r
-               else\r
-               {\r
-                       leafnum = PointInLeafNum_r( point, node->children[ 0 ] );\r
-                       if( bspLeafs[ leafnum ].cluster != -1 )\r
-                               return leafnum;\r
-                       nodenum = node->children[ 1 ];\r
-               }\r
-       }\r
-       \r
-       leafnum = -nodenum - 1;\r
-       return leafnum;\r
-}\r
-\r
-\r
-\r
-/*\r
-PointInLeafnum()\r
-borrowed from vlight.c\r
-*/\r
-\r
-int    PointInLeafNum( vec3_t point )\r
-{\r
-       return PointInLeafNum_r( point, 0 );\r
-}\r
-\r
-\r
-\r
-/*\r
-ClusterVisibleToPoint() - ydnar\r
-returns qtrue if point can "see" cluster\r
-*/\r
-\r
-qboolean ClusterVisibleToPoint( vec3_t point, int cluster )\r
-{\r
-       int             pointCluster;\r
-       \r
-\r
-       /* get leafNum for point */\r
-       pointCluster = ClusterForPoint( point );\r
-       if( pointCluster < 0 )\r
-               return qfalse;\r
-       \r
-       /* check pvs */\r
-       return ClusterVisible( pointCluster, cluster );\r
-}\r
-\r
-\r
-\r
-/*\r
-ClusterForPoint() - ydnar\r
-returns the pvs cluster for point\r
-*/\r
-\r
-int ClusterForPoint( vec3_t point )\r
-{\r
-       int             leafNum;\r
-       \r
-\r
-       /* get leafNum for point */\r
-       leafNum = PointInLeafNum( point );\r
-       if( leafNum < 0 )\r
-               return -1;\r
-       \r
-       /* return the cluster */\r
-       return bspLeafs[ leafNum ].cluster;\r
-}\r
-\r
-\r
-\r
-/*\r
-ClusterForPointExt() - ydnar\r
-also takes brushes into account for occlusion testing\r
-*/\r
-\r
-int ClusterForPointExt( vec3_t point, float epsilon )\r
-{\r
-       int                             i, j, b, leafNum, cluster;\r
-       float                   dot;\r
-       qboolean                inside;\r
-       int                             *brushes, numBSPBrushes;\r
-       bspLeaf_t               *leaf;\r
-       bspBrush_t              *brush;\r
-       bspPlane_t              *plane;\r
-       \r
-       \r
-       /* get leaf for point */\r
-       leafNum = PointInLeafNum( point );\r
-       if( leafNum < 0 )\r
-               return -1;\r
-       leaf = &bspLeafs[ leafNum ];\r
-       \r
-       /* get the cluster */\r
-       cluster = leaf->cluster;\r
-       if( cluster < 0 )\r
-               return -1;\r
-       \r
-       /* transparent leaf, so check point against all brushes in the leaf */\r
-       brushes = &bspLeafBrushes[ leaf->firstBSPLeafBrush ];\r
-       numBSPBrushes = leaf->numBSPLeafBrushes;\r
-       for( i = 0; i < numBSPBrushes; i++ )\r
-       {\r
-               /* get parts */\r
-               b = brushes[ i ];\r
-               if( b > maxOpaqueBrush )\r
-                       continue;\r
-               brush = &bspBrushes[ b ];\r
-               if( !(opaqueBrushes[ b >> 3 ] & (1 << (b & 7))) )\r
-                       continue;\r
-               \r
-               /* check point against all planes */\r
-               inside = qtrue;\r
-               for( j = 0; j < brush->numSides && inside; j++ )\r
-               {\r
-                       plane = &bspPlanes[ bspBrushSides[ brush->firstSide + j ].planeNum ];\r
-                       dot = DotProduct( point, plane->normal );\r
-                       dot -= plane->dist;\r
-                       if( dot > epsilon )\r
-                               inside = qfalse;\r
-               }\r
-               \r
-               /* if inside, return bogus cluster */\r
-               if( inside )\r
-                       return -1 - b;\r
-       }\r
-       \r
-       /* if the point made it this far, it's not inside any opaque brushes */\r
-       return cluster;\r
-}\r
-\r
-\r
-\r
-/*\r
-ClusterForPointExtFilter() - ydnar\r
-adds cluster checking against a list of known valid clusters\r
-*/\r
-\r
-int ClusterForPointExtFilter( vec3_t point, float epsilon, int numClusters, int *clusters )\r
-{\r
-       int             i, cluster;\r
-       \r
-       \r
-       /* get cluster for point */\r
-       cluster = ClusterForPointExt( point, epsilon );\r
-       \r
-       /* check if filtering is necessary */\r
-       if( cluster < 0 || numClusters <= 0 || clusters == NULL )\r
-               return cluster;\r
-       \r
-       /* filter */\r
-       for( i = 0; i < numClusters; i++ )\r
-       {\r
-               if( cluster == clusters[ i ] || ClusterVisible( cluster, clusters[ i ] ) )\r
-                       return cluster;\r
-       }\r
-       \r
-       /* failed */\r
-       return -1;\r
-}\r
-\r
-\r
-\r
-/*\r
-ShaderForPointInLeaf() - ydnar\r
-checks a point against all brushes in a leaf, returning the shader of the brush\r
-also sets the cumulative surface and content flags for the brush hit\r
-*/\r
-\r
-int ShaderForPointInLeaf( vec3_t point, int leafNum, float epsilon, int wantContentFlags, int wantSurfaceFlags, int *contentFlags, int *surfaceFlags )\r
-{\r
-       int                             i, j;\r
-       float                   dot;\r
-       qboolean                inside;\r
-       int                             *brushes, numBSPBrushes;\r
-       bspLeaf_t                       *leaf;\r
-       bspBrush_t              *brush;\r
-       bspBrushSide_t  *side;\r
-       bspPlane_t              *plane;\r
-       bspShader_t             *shader;\r
-       int                             allSurfaceFlags, allContentFlags;\r
-\r
-       \r
-       /* clear things out first */\r
-       *surfaceFlags = 0;\r
-       *contentFlags = 0;\r
-       \r
-       /* get leaf */\r
-       if( leafNum < 0 )\r
-               return -1;\r
-       leaf = &bspLeafs[ leafNum ];\r
-       \r
-       /* transparent leaf, so check point against all brushes in the leaf */\r
-       brushes = &bspLeafBrushes[ leaf->firstBSPLeafBrush ];\r
-       numBSPBrushes = leaf->numBSPLeafBrushes;\r
-       for( i = 0; i < numBSPBrushes; i++ )\r
-       {\r
-               /* get parts */\r
-               brush = &bspBrushes[ brushes[ i ] ];\r
-               \r
-               /* check point against all planes */\r
-               inside = qtrue;\r
-               allSurfaceFlags = 0;\r
-               allContentFlags = 0;\r
-               for( j = 0; j < brush->numSides && inside; j++ )\r
-               {\r
-                       side = &bspBrushSides[ brush->firstSide + j ];\r
-                       plane = &bspPlanes[ side->planeNum ];\r
-                       dot = DotProduct( point, plane->normal );\r
-                       dot -= plane->dist;\r
-                       if( dot > epsilon )\r
-                               inside = qfalse;\r
-                       else\r
-                       {\r
-                               shader = &bspShaders[ side->shaderNum ];\r
-                               allSurfaceFlags |= shader->surfaceFlags;\r
-                               allContentFlags |= shader->contentFlags;\r
-                       }\r
-               }\r
-               \r
-               /* handle if inside */\r
-               if( inside )\r
-               {\r
-                       /* if there are desired flags, check for same and continue if they aren't matched */\r
-                       if( wantContentFlags && !(wantContentFlags & allContentFlags) )\r
-                               continue;\r
-                       if( wantSurfaceFlags && !(wantSurfaceFlags & allSurfaceFlags) )\r
-                               continue;\r
-                       \r
-                       /* store the cumulative flags and return the brush shader (which is mostly useless) */\r
-                       *surfaceFlags = allSurfaceFlags;\r
-                       *contentFlags = allContentFlags;\r
-                       return brush->shaderNum;\r
-               }\r
-       }\r
-       \r
-       /* if the point made it this far, it's not inside any brushes */\r
-       return -1;\r
-}\r
-\r
-\r
-\r
-/*\r
-ChopBounds()\r
-chops a bounding box by the plane defined by origin and normal\r
-returns qfalse if the bounds is entirely clipped away\r
-\r
-this is not exactly the fastest way to do this...\r
-*/\r
-\r
-qboolean ChopBounds( vec3_t mins, vec3_t maxs, vec3_t origin, vec3_t normal )\r
-{\r
-       /* FIXME: rewrite this so it doesn't use bloody brushes */\r
-       return qtrue;\r
-}\r
-\r
-\r
-\r
-/*\r
-SetupEnvelopes()\r
-calculates each light's effective envelope,\r
-taking into account brightness, type, and pvs.\r
-*/\r
-\r
-#define LIGHT_EPSILON  0.125f\r
-#define LIGHT_NUDGE            2.0f\r
-\r
-void SetupEnvelopes( qboolean forGrid, qboolean fastFlag )\r
-{\r
-       int                     i, x, y, z, x1, y1, z1;\r
-       light_t         *light, *light2, **owner;\r
-       bspLeaf_t       *leaf;\r
-       vec3_t          origin, dir, mins, maxs, nullVector = { 0, 0, 0 };\r
-       float           radius, intensity;\r
-       light_t         *buckets[ 256 ];\r
-       \r
-       \r
-       /* early out for weird cases where there are no lights */\r
-       if( lights == NULL )\r
-               return;\r
-       \r
-       /* note it */\r
-       Sys_FPrintf( SYS_VRB, "--- SetupEnvelopes%s ---\n", fastFlag ? " (fast)" : "" );\r
-       \r
-       /* count lights */\r
-       numLights = 0;\r
-       numCulledLights = 0;\r
-       owner = &lights;\r
-       while( *owner != NULL )\r
-       {\r
-               /* get light */\r
-               light = *owner;\r
-               \r
-               /* handle negative lights */\r
-               if( light->photons < 0.0f || light->add < 0.0f )\r
-               {\r
-                       light->photons *= -1.0f;\r
-                       light->add *= -1.0f;\r
-                       light->flags |= LIGHT_NEGATIVE;\r
-               }\r
-               \r
-               /* sunlight? */\r
-               if( light->type == EMIT_SUN )\r
-               {\r
-                       /* special cased */\r
-                       light->cluster = 0;\r
-                       light->envelope = MAX_WORLD_COORD * 8.0f;\r
-                       VectorSet( light->mins, MIN_WORLD_COORD * 8.0f, MIN_WORLD_COORD * 8.0f, MIN_WORLD_COORD * 8.0f );\r
-                       VectorSet( light->maxs, MAX_WORLD_COORD * 8.0f, MAX_WORLD_COORD * 8.0f, MAX_WORLD_COORD * 8.0f );\r
-               }\r
-               \r
-               /* everything else */\r
-               else\r
-               {\r
-                       /* get pvs cluster for light */\r
-                       light->cluster = ClusterForPointExt( light->origin, LIGHT_EPSILON );\r
-                       \r
-                       /* invalid cluster? */\r
-                       if( light->cluster < 0 )\r
-                       {\r
-                               /* nudge the sample point around a bit */\r
-                               for( x = 0; x < 4; x++ )\r
-                               {\r
-                                       /* two's complement 0, 1, -1, 2, -2, etc */\r
-                                       x1 = ((x >> 1) ^ (x & 1 ? -1 : 0)) + (x & 1);\r
-                                       \r
-                                       for( y = 0; y < 4; y++ )\r
-                                       {\r
-                                               y1 = ((y >> 1) ^ (y & 1 ? -1 : 0)) + (y & 1);\r
-                                               \r
-                                               for( z = 0; z < 4; z++ )\r
-                                               {\r
-                                                       z1 = ((z >> 1) ^ (z & 1 ? -1 : 0)) + (z & 1);\r
-                                                       \r
-                                                       /* nudge origin */\r
-                                                       origin[ 0 ] = light->origin[ 0 ] + (LIGHT_NUDGE * x1);\r
-                                                       origin[ 1 ] = light->origin[ 1 ] + (LIGHT_NUDGE * y1);\r
-                                                       origin[ 2 ] = light->origin[ 2 ] + (LIGHT_NUDGE * z1);\r
-                                                       \r
-                                                       /* try at nudged origin */\r
-                                                       light->cluster = ClusterForPointExt( origin, LIGHT_EPSILON );\r
-                                                       if( light->cluster < 0 )\r
-                                                               continue;\r
-                                                                       \r
-                                                       /* set origin */\r
-                                                       VectorCopy( origin, light->origin );\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-                       \r
-                       /* only calculate for lights in pvs and outside of opaque brushes */\r
-                       if( light->cluster >= 0 )\r
-                       {\r
-                               /* set light fast flag */\r
-                               if( fastFlag )\r
-                                       light->flags |= LIGHT_FAST_TEMP;\r
-                               else\r
-                                       light->flags &= ~LIGHT_FAST_TEMP;\r
-                               if( light->si && light->si->noFast )\r
-                                       light->flags &= ~(LIGHT_FAST | LIGHT_FAST_TEMP);\r
-                               \r
-                               /* clear light envelope */\r
-                               light->envelope = 0;\r
-                               \r
-                               /* handle area lights */\r
-                               if( exactPointToPolygon && light->type == EMIT_AREA && light->w != NULL )\r
-                               {\r
-                                       /* ugly hack to calculate extent for area lights, but only done once */\r
-                                       VectorScale( light->normal, -1.0f, dir );\r
-                                       for( radius = 100.0f; radius < 130000.0f && light->envelope == 0; radius += 10.0f )\r
-                                       {\r
-                                               float   factor;\r
-                                               \r
-                                               VectorMA( light->origin, radius, light->normal, origin );\r
-                                               factor = PointToPolygonFormFactor( origin, dir, light->w );\r
-                                               if( factor < 0.0f )\r
-                                                       factor *= -1.0f;\r
-                                               if( (factor * light->add) <= light->falloffTolerance )\r
-                                                       light->envelope = radius;\r
-                                       }\r
-                                       \r
-                                       /* check for fast mode */\r
-                                       if( !(light->flags & LIGHT_FAST) && !(light->flags & LIGHT_FAST_TEMP) )\r
-                                               light->envelope = MAX_WORLD_COORD * 8.0f;\r
-                               }\r
-                               else\r
-                               {\r
-                                       radius = 0.0f;\r
-                                       intensity = light->photons;\r
-                               }\r
-                               \r
-                               /* other calcs */\r
-                               if( light->envelope <= 0.0f )\r
-                               {\r
-                                       /* solve distance for non-distance lights */\r
-                                       if( !(light->flags & LIGHT_ATTEN_DISTANCE) )\r
-                                               light->envelope = MAX_WORLD_COORD * 8.0f;\r
-                                       \r
-                                       /* solve distance for linear lights */\r
-                                       else if( (light->flags & LIGHT_ATTEN_LINEAR ) )\r
-                                               //% light->envelope = ((intensity / light->falloffTolerance) * linearScale - 1 + radius) / light->fade;\r
-                                               light->envelope = ((intensity * linearScale) - light->falloffTolerance) / light->fade;\r
-\r
-                                               /*\r
-                                               add = angle * light->photons * linearScale - (dist * light->fade);\r
-                                               T = (light->photons * linearScale) - (dist * light->fade);\r
-                                               T + (dist * light->fade) = (light->photons * linearScale);\r
-                                               dist * light->fade = (light->photons * linearScale) - T;\r
-                                               dist = ((light->photons * linearScale) - T) / light->fade;\r
-                                               */\r
-                                       \r
-                                       /* solve for inverse square falloff */\r
-                                       else\r
-                                               light->envelope = sqrt( intensity / light->falloffTolerance ) + radius;\r
-                                               \r
-                                               /*\r
-                                               add = light->photons / (dist * dist);\r
-                                               T = light->photons / (dist * dist);\r
-                                               T * (dist * dist) = light->photons;\r
-                                               dist = sqrt( light->photons / T );\r
-                                               */\r
-                               }\r
-                               \r
-                               /* chop radius against pvs */\r
-                               {\r
-                                       /* clear bounds */\r
-                                       ClearBounds( mins, maxs );\r
-                                       \r
-                                       /* check all leaves */\r
-                                       for( i = 0; i < numBSPLeafs; i++ )\r
-                                       {\r
-                                               /* get test leaf */\r
-                                               leaf = &bspLeafs[ i ];\r
-                                               \r
-                                               /* in pvs? */\r
-                                               if( leaf->cluster < 0 )\r
-                                                       continue;\r
-                                               if( ClusterVisible( light->cluster, leaf->cluster ) == qfalse ) /* ydnar: thanks Arnout for exposing my stupid error (this never failed before) */\r
-                                                       continue;\r
-                                               \r
-                                               /* add this leafs bbox to the bounds */\r
-                                               VectorCopy( leaf->mins, origin );\r
-                                               AddPointToBounds( origin, mins, maxs );\r
-                                               VectorCopy( leaf->maxs, origin );\r
-                                               AddPointToBounds( origin, mins, maxs );\r
-                                       }\r
-                                       \r
-                                       /* test to see if bounds encompass light */\r
-                                       for( i = 0; i < 3; i++ )\r
-                                       {\r
-                                               if( mins[ i ] > light->origin[ i ] || maxs[ i ] < light->origin[ i ] )\r
-                                               {\r
-                                                       //% Sys_Printf( "WARNING: Light PVS bounds (%.0f, %.0f, %.0f) -> (%.0f, %.0f, %.0f)\ndo not encompass light %d (%f, %f, %f)\n",\r
-                                                       //%     mins[ 0 ], mins[ 1 ], mins[ 2 ],\r
-                                                       //%     maxs[ 0 ], maxs[ 1 ], maxs[ 2 ],\r
-                                                       //%     numLights, light->origin[ 0 ], light->origin[ 1 ], light->origin[ 2 ] );\r
-                                                       AddPointToBounds( light->origin, mins, maxs );\r
-                                               }\r
-                                       }\r
-                                       \r
-                                       /* chop the bounds by a plane for area lights and spotlights */\r
-                                       if( light->type == EMIT_AREA || light->type == EMIT_SPOT )\r
-                                               ChopBounds( mins, maxs, light->origin, light->normal );\r
-                                       \r
-                                       /* copy bounds */\r
-                                       VectorCopy( mins, light->mins );\r
-                                       VectorCopy( maxs, light->maxs );\r
-                                       \r
-                                       /* reflect bounds around light origin */\r
-                                       //%     VectorMA( light->origin, -1.0f, origin, origin );\r
-                                       VectorScale( light->origin, 2, origin );\r
-                                       VectorSubtract( origin, maxs, origin );\r
-                                       AddPointToBounds( origin, mins, maxs );\r
-                                       //%     VectorMA( light->origin, -1.0f, mins, origin );\r
-                                       VectorScale( light->origin, 2, origin );\r
-                                       VectorSubtract( origin, mins, origin );\r
-                                       AddPointToBounds( origin, mins, maxs );\r
-                                        \r
-                                       /* calculate spherical bounds */\r
-                                       VectorSubtract( maxs, light->origin, dir );\r
-                                       radius = (float) VectorLength( dir );\r
-                                       \r
-                                       /* if this radius is smaller than the envelope, then set the envelope to it */\r
-                                       if( radius < light->envelope )\r
-                                       {\r
-                                               light->envelope = radius;\r
-                                               //%     Sys_FPrintf( SYS_VRB, "PVS Cull (%d): culled\n", numLights );\r
-                                       }\r
-                                       //%     else\r
-                                       //%             Sys_FPrintf( SYS_VRB, "PVS Cull (%d): failed (%8.0f > %8.0f)\n", numLights, radius, light->envelope );\r
-                               }\r
-                               \r
-                               /* add grid/surface only check */\r
-                               if( forGrid )\r
-                               {\r
-                                       if( !(light->flags & LIGHT_GRID) )\r
-                                               light->envelope = 0.0f;\r
-                               }\r
-                               else\r
-                               {\r
-                                       if( !(light->flags & LIGHT_SURFACES) )\r
-                                               light->envelope = 0.0f;\r
-                               }\r
-                       }\r
-                       \r
-                       /* culled? */\r
-                       if( light->cluster < 0 || light->envelope <= 0.0f )\r
-                       {\r
-                               /* debug code */\r
-                               //%     Sys_Printf( "Culling light: Cluster: %d Envelope: %f\n", light->cluster, light->envelope );\r
-                               \r
-                               /* delete the light */\r
-                               numCulledLights++;\r
-                               *owner = light->next;\r
-                               if( light->w != NULL )\r
-                                       free( light->w );\r
-                               free( light );\r
-                               continue;\r
-                       }\r
-               }\r
-               \r
-               /* square envelope */\r
-               light->envelope2 = (light->envelope * light->envelope);\r
-               \r
-               /* increment light count */\r
-               numLights++;\r
-               \r
-               /* set next light */\r
-               owner = &((**owner).next);\r
-       }\r
-       \r
-       /* bucket sort lights by style */\r
-       memset( buckets, 0, sizeof( buckets ) );\r
-       light2 = NULL;\r
-       for( light = lights; light != NULL; light = light2 )\r
-       {\r
-               /* get next light */\r
-               light2 = light->next;\r
-               \r
-               /* filter into correct bucket */\r
-               light->next = buckets[ light->style ];\r
-               buckets[ light->style ] = light;\r
-       }\r
-       \r
-       /* filter back into light list */\r
-       lights = NULL;\r
-       for( i = 255; i >= 0; i-- )\r
-       {\r
-               light2 = NULL;\r
-               for( light = buckets[ i ]; light != NULL; light = light2 )\r
-               {\r
-                       light2 = light->next;\r
-                       light->next = lights;\r
-                       lights = light;\r
-               }\r
-       }\r
-       \r
-       /* emit some statistics */\r
-       Sys_Printf( "%9d total lights\n", numLights );\r
-       Sys_Printf( "%9d culled lights\n", numCulledLights );\r
-}\r
-\r
-\r
-\r
-/*\r
-CreateTraceLightsForBounds()\r
-creates a list of lights that affect the given bounding box and pvs clusters (bsp leaves)\r
-*/\r
-\r
-void CreateTraceLightsForBounds( vec3_t mins, vec3_t maxs, vec3_t normal, int numClusters, int *clusters, int flags, trace_t *trace )\r
-{\r
-       int                     i;\r
-       light_t         *light;\r
-       vec3_t          origin, dir, nullVector = { 0.0f, 0.0f, 0.0f };\r
-       float           radius, dist, length;\r
-       \r
-       \r
-       /* potential pre-setup  */\r
-       if( numLights == 0 )\r
-               SetupEnvelopes( qfalse, fast );\r
-       \r
-       /* debug code */\r
-       //% Sys_Printf( "CTWLFB: (%4.1f %4.1f %4.1f) (%4.1f %4.1f %4.1f)\n", mins[ 0 ], mins[ 1 ], mins[ 2 ], maxs[ 0 ], maxs[ 1 ], maxs[ 2 ] );\r
-       \r
-       /* allocate the light list */\r
-       trace->lights = safe_malloc( sizeof( light_t* ) * (numLights + 1) );\r
-       trace->numLights = 0;\r
-       \r
-       /* calculate spherical bounds */\r
-       VectorAdd( mins, maxs, origin );\r
-       VectorScale( origin, 0.5f, origin );\r
-       VectorSubtract( maxs, origin, dir );\r
-       radius = (float) VectorLength( dir );\r
-       \r
-       /* get length of normal vector */\r
-       if( normal != NULL )\r
-               length = VectorLength( normal );\r
-       else\r
-       {\r
-               normal = nullVector;\r
-               length = 0;\r
-       }\r
-       \r
-       /* test each light and see if it reaches the sphere */\r
-       /* note: the attenuation code MUST match LightingAtSample() */\r
-       for( light = lights; light; light = light->next )\r
-       {\r
-               /* check zero sized envelope */\r
-               if( light->envelope <= 0 )\r
-               {\r
-                       lightsEnvelopeCulled++;\r
-                       continue;\r
-               }\r
-               \r
-               /* check flags */\r
-               if( !(light->flags & flags) )\r
-                       continue;\r
-               \r
-               /* sunlight skips all this nonsense */\r
-               if( light->type != EMIT_SUN )\r
-               {\r
-                       /* sun only? */\r
-                       if( sunOnly )\r
-                               continue;\r
-                       \r
-                       /* check against pvs cluster */\r
-                       if( numClusters > 0 && clusters != NULL )\r
-                       {\r
-                               for( i = 0; i < numClusters; i++ )\r
-                               {\r
-                                       if( ClusterVisible( light->cluster, clusters[ i ] ) )\r
-                                               break;\r
-                               }\r
-                               \r
-                               /* fixme! */\r
-                               if( i == numClusters )\r
-                               {\r
-                                       lightsClusterCulled++;\r
-                                       continue;\r
-                               }\r
-                       }\r
-                       \r
-                       /* if the light's bounding sphere intersects with the bounding sphere then this light needs to be tested */\r
-                       VectorSubtract( light->origin, origin, dir );\r
-                       dist = VectorLength( dir );\r
-                       dist -= light->envelope;\r
-                       dist -= radius;\r
-                       if( dist > 0 )\r
-                       {\r
-                               lightsEnvelopeCulled++;\r
-                               continue;\r
-                       }\r
-                       \r
-                       /* check bounding box against light's pvs envelope (note: this code never eliminated any lights, so disabling it) */\r
-                       #if 0\r
-                       skip = qfalse;\r
-                       for( i = 0; i < 3; i++ )\r
-                       {\r
-                               if( mins[ i ] > light->maxs[ i ] || maxs[ i ] < light->mins[ i ] )\r
-                                       skip = qtrue;\r
-                       }\r
-                       if( skip )\r
-                       {\r
-                               lightsBoundsCulled++;\r
-                               continue;\r
-                       }\r
-                       #endif\r
-               }\r
-               \r
-               /* planar surfaces (except twosided surfaces) have a couple more checks */\r
-               if( length > 0.0f && trace->twoSided == qfalse )\r
-               {\r
-                       /* lights coplanar with a surface won't light it */\r
-                       if( !(light->flags & LIGHT_TWOSIDED) && DotProduct( light->normal, normal ) > 0.999f )\r
-                       {\r
-                               lightsPlaneCulled++;\r
-                               continue;\r
-                       }\r
-                       \r
-                       /* check to see if light is behind the plane */\r
-                       if( DotProduct( light->origin, normal ) - DotProduct( origin, normal ) < -1.0f )\r
-                       {\r
-                               lightsPlaneCulled++;\r
-                               continue;\r
-                       }\r
-               }\r
-               \r
-               /* add this light */\r
-               trace->lights[ trace->numLights++ ] = light;\r
-       }\r
-       \r
-       /* make last night null */\r
-       trace->lights[ trace->numLights ] = NULL;\r
-}\r
-\r
-\r
-\r
-void FreeTraceLights( trace_t *trace )\r
-{\r
-       if( trace->lights != NULL )\r
-               free( trace->lights );\r
-}\r
-\r
-\r
-\r
-/*\r
-CreateTraceLightsForSurface()\r
-creates a list of lights that can potentially affect a drawsurface\r
-*/\r
-\r
-void CreateTraceLightsForSurface( int num, trace_t *trace )\r
-{\r
-       int                                     i;\r
-       vec3_t                          mins, maxs, normal;\r
-       bspDrawVert_t           *dv;\r
-       bspDrawSurface_t        *ds;\r
-       surfaceInfo_t           *info;\r
-       \r
-       \r
-       /* dummy check */\r
-       if( num < 0 )\r
-               return;\r
-       \r
-       /* get drawsurface and info */\r
-       ds = &bspDrawSurfaces[ num ];\r
-       info = &surfaceInfos[ num ];\r
-       \r
-       /* get the mins/maxs for the dsurf */\r
-       ClearBounds( mins, maxs );\r
-       VectorCopy( bspDrawVerts[ ds->firstVert ].normal, normal );\r
-       for( i = 0; i < ds->numVerts; i++ )\r
-       {\r
-               dv = &yDrawVerts[ ds->firstVert + i ];\r
-               AddPointToBounds( dv->xyz, mins, maxs );\r
-               if( !VectorCompare( dv->normal, normal ) )\r
-                       VectorClear( normal );\r
-       }\r
-       \r
-       /* create the lights for the bounding box */\r
-       CreateTraceLightsForBounds( mins, maxs, normal, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ], LIGHT_SURFACES, trace );\r
-}\r
-\r
-\r
-\r
-\r
-\r
+/*
+Copyright (C) 1999-2007 id Software, Inc. and contributors.
+For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+This file is part of GtkRadiant.
+
+GtkRadiant is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+GtkRadiant is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GtkRadiant; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+----------------------------------------------------------------------------------
+
+This code has been altered significantly from its original form, to support
+several games based on the Quake III Arena engine, in the form of "Q3Map2."
+
+------------------------------------------------------------------------------- */
+
+
+
+/* marker */
+#define LIGHT_YDNAR_C
+
+
+
+/* dependencies */
+#include "q3map2.h"
+
+
+
+
+/*
+ColorToBytes()
+ydnar: moved to here 2001-02-04
+*/
+
+void ColorToBytes( const float *color, byte *colorBytes, float scale )
+{
+       float   max;
+       vec3_t  sample;
+       
+       
+       /* ydnar: scaling necessary for simulating r_overbrightBits on external lightmaps */
+       if( scale <= 0.0f )
+               scale = 1.0f;
+       
+       /* make a local copy */
+       VectorScale( color, scale, sample );
+       
+       /* handle negative light */
+       if( sample[ 0 ] < 0.0f )
+               sample[ 0 ] = 0.0f;
+       if( sample[ 1 ] < 0.0f )
+               sample[ 1 ] = 0.0f;
+       if( sample[ 2 ] < 0.0f )
+               sample[ 2 ] = 0.0f;
+       
+       /* clamp with color normalization */
+       max = sample[ 0 ];
+       if( sample[ 1 ] > max )
+               max = sample[ 1 ];
+       if( sample[ 2 ] > max )
+               max = sample[ 2 ];
+       if( max > 255.0f )
+               VectorScale( sample, (255.0f / max), sample );
+       
+       /* store it off */
+       colorBytes[ 0 ] = sample[ 0 ];
+       colorBytes[ 1 ] = sample[ 1 ];
+       colorBytes[ 2 ] = sample[ 2 ];
+}
+
+
+
+/* -------------------------------------------------------------------------------
+
+this section deals with phong shading (normal interpolation across brush faces)
+
+------------------------------------------------------------------------------- */
+
+/*
+SmoothNormals()
+smooths together coincident vertex normals across the bsp
+*/
+
+#define MAX_SAMPLES                            256
+#define THETA_EPSILON                  0.000001
+#define EQUAL_NORMAL_EPSILON   0.01
+
+void SmoothNormals( void )
+{
+       int                                     i, j, k, f, cs, numVerts, numVotes, fOld, start;
+       float                           shadeAngle, defaultShadeAngle, maxShadeAngle, dot, testAngle;
+       bspDrawSurface_t        *ds;
+       shaderInfo_t            *si;
+       float                           *shadeAngles;
+       byte                            *smoothed;
+       vec3_t                          average, diff;
+       int                                     indexes[ MAX_SAMPLES ];
+       vec3_t                          votes[ MAX_SAMPLES ];
+       
+       
+       /* allocate shade angle table */
+       shadeAngles = safe_malloc( numBSPDrawVerts * sizeof( float ) );
+       memset( shadeAngles, 0, numBSPDrawVerts * sizeof( float ) );
+       
+       /* allocate smoothed table */
+       cs = (numBSPDrawVerts / 8) + 1;
+       smoothed = safe_malloc( cs );
+       memset( smoothed, 0, cs );
+       
+       /* set default shade angle */
+       defaultShadeAngle = DEG2RAD( shadeAngleDegrees );
+       maxShadeAngle = 0;
+       
+       /* run through every surface and flag verts belonging to non-lightmapped surfaces
+          and set per-vertex smoothing angle */
+       for( i = 0; i < numBSPDrawSurfaces; i++ )
+       {
+               /* get drawsurf */
+               ds = &bspDrawSurfaces[ i ];
+               
+               /* get shader for shade angle */
+               si = surfaceInfos[ i ].si;
+               if( si->shadeAngleDegrees )
+                       shadeAngle = DEG2RAD( si->shadeAngleDegrees );
+               else
+                       shadeAngle = defaultShadeAngle;
+               if( shadeAngle > maxShadeAngle )
+                       maxShadeAngle = shadeAngle;
+               
+               /* flag its verts */
+               for( j = 0; j < ds->numVerts; j++ )
+               {
+                       f = ds->firstVert + j;
+                       shadeAngles[ f ] = shadeAngle;
+                       if( ds->surfaceType == MST_TRIANGLE_SOUP )
+                               smoothed[ f >> 3 ] |= (1 << (f & 7));
+               }
+               
+               /* ydnar: optional force-to-trisoup */
+               if( trisoup && ds->surfaceType == MST_PLANAR )
+               {
+                       ds->surfaceType = MST_TRIANGLE_SOUP;
+                       ds->lightmapNum[ 0 ] = -3;
+               }
+       }
+       
+       /* bail if no surfaces have a shade angle */
+       if( maxShadeAngle == 0 )
+       {
+               free( shadeAngles );
+               free( smoothed );
+               return;
+       }
+       
+       /* init pacifier */
+       fOld = -1;
+       start = I_FloatTime();
+       
+       /* go through the list of vertexes */
+       for( i = 0; i < numBSPDrawVerts; i++ )
+       {
+               /* print pacifier */
+               f = 10 * i / numBSPDrawVerts;
+               if( f != fOld )
+               {
+                       fOld = f;
+                       Sys_Printf( "%i...", f );
+               }
+               
+               /* already smoothed? */
+               if( smoothed[ i >> 3 ] & (1 << (i & 7)) )
+                       continue;
+               
+               /* clear */
+               VectorClear( average );
+               numVerts = 0;
+               numVotes = 0;
+               
+               /* build a table of coincident vertexes */
+               for( j = i; j < numBSPDrawVerts && numVerts < MAX_SAMPLES; j++ )
+               {
+                       /* already smoothed? */
+                       if( smoothed[ j >> 3 ] & (1 << (j & 7)) )
+                               continue;
+                       
+                       /* test vertexes */
+                       if( VectorCompare( yDrawVerts[ i ].xyz, yDrawVerts[ j ].xyz ) == qfalse )
+                               continue;
+                       
+                       /* use smallest shade angle */
+                       shadeAngle = (shadeAngles[ i ] < shadeAngles[ j ] ? shadeAngles[ i ] : shadeAngles[ j ]);
+                       
+                       /* check shade angle */
+                       dot = DotProduct( bspDrawVerts[ i ].normal, bspDrawVerts[ j ].normal );
+                       if( dot > 1.0 )
+                               dot = 1.0;
+                       else if( dot < -1.0 )
+                               dot = -1.0;
+                       testAngle = acos( dot ) + THETA_EPSILON;
+                       if( testAngle >= shadeAngle )
+                       {
+                               //Sys_Printf( "F(%3.3f >= %3.3f) ", RAD2DEG( testAngle ), RAD2DEG( shadeAngle ) );
+                               continue;
+                       }
+                       //Sys_Printf( "P(%3.3f < %3.3f) ", RAD2DEG( testAngle ), RAD2DEG( shadeAngle ) );
+                       
+                       /* add to the list */
+                       indexes[ numVerts++ ] = j;
+                       
+                       /* flag vertex */
+                       smoothed[ j >> 3 ] |= (1 << (j & 7));
+                       
+                       /* see if this normal has already been voted */
+                       for( k = 0; k < numVotes; k++ )
+                       {
+                               VectorSubtract( bspDrawVerts[ j ].normal, votes[ k ], diff );
+                               if( fabs( diff[ 0 ] ) < EQUAL_NORMAL_EPSILON &&
+                                       fabs( diff[ 1 ] ) < EQUAL_NORMAL_EPSILON &&
+                                       fabs( diff[ 2 ] ) < EQUAL_NORMAL_EPSILON )
+                                       break;
+                       }
+                       
+                       /* add a new vote? */
+                       if( k == numVotes && numVotes < MAX_SAMPLES )
+                       {
+                               VectorAdd( average, bspDrawVerts[ j ].normal, average );
+                               VectorCopy( bspDrawVerts[ j ].normal, votes[ numVotes ] );
+                               numVotes++;
+                       }
+               }
+               
+               /* don't average for less than 2 verts */
+               if( numVerts < 2 )
+                       continue;
+               
+               /* average normal */
+               if( VectorNormalize( average, average ) > 0 )
+               {
+                       /* smooth */
+                       for( j = 0; j < numVerts; j++ )
+                               VectorCopy( average, yDrawVerts[ indexes[ j ] ].normal );
+               }
+       }
+       
+       /* free the tables */
+       free( shadeAngles );
+       free( smoothed );
+       
+       /* print time */
+       Sys_Printf( " (%i)\n", (int) (I_FloatTime() - start) );
+}
+
+
+
+/* -------------------------------------------------------------------------------
+
+this section deals with phong shaded lightmap tracing
+
+------------------------------------------------------------------------------- */
+
+/* 9th rewrite (recursive subdivision of a lightmap triangle) */
+
+/*
+CalcTangentVectors()
+calculates the st tangent vectors for normalmapping
+*/
+
+static qboolean CalcTangentVectors( int numVerts, bspDrawVert_t **dv, vec3_t *stv, vec3_t *ttv )
+{
+       int                     i;
+       float           bb, s, t;
+       vec3_t          bary;
+       
+       
+       /* calculate barycentric basis for the triangle */
+       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 ]);
+       if( fabs( bb ) < 0.00000001f )
+               return qfalse;
+       
+       /* do each vertex */
+       for( i = 0; i < numVerts; i++ )
+       {
+               /* calculate s tangent vector */
+               s = dv[ i ]->st[ 0 ] + 10.0f;
+               t = dv[ i ]->st[ 1 ];
+               bary[ 0 ] = ((dv[ 1 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t) - (dv[ 2 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t)) / bb;
+               bary[ 1 ] = ((dv[ 2 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t) - (dv[ 0 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t)) / bb;
+               bary[ 2 ] = ((dv[ 0 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t) - (dv[ 1 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t)) / bb;
+               
+               stv[ i ][ 0 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 0 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 0 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 0 ];
+               stv[ i ][ 1 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 1 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 1 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 1 ];
+               stv[ i ][ 2 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 2 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 2 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 2 ];
+               
+               VectorSubtract( stv[ i ], dv[ i ]->xyz, stv[ i ] );
+               VectorNormalize( stv[ i ], stv[ i ] );
+               
+               /* calculate t tangent vector */
+               s = dv[ i ]->st[ 0 ];
+               t = dv[ i ]->st[ 1 ] + 10.0f;
+               bary[ 0 ] = ((dv[ 1 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t) - (dv[ 2 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t)) / bb;
+               bary[ 1 ] = ((dv[ 2 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t) - (dv[ 0 ]->st[ 0 ] - s) * (dv[ 2 ]->st[ 1 ] - t)) / bb;
+               bary[ 2 ] = ((dv[ 0 ]->st[ 0 ] - s) * (dv[ 1 ]->st[ 1 ] - t) - (dv[ 1 ]->st[ 0 ] - s) * (dv[ 0 ]->st[ 1 ] - t)) / bb;
+               
+               ttv[ i ][ 0 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 0 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 0 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 0 ];
+               ttv[ i ][ 1 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 1 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 1 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 1 ];
+               ttv[ i ][ 2 ] = bary[ 0 ] * dv[ 0 ]->xyz[ 2 ] + bary[ 1 ] * dv[ 1 ]->xyz[ 2 ] + bary[ 2 ] * dv[ 2 ]->xyz[ 2 ];
+               
+               VectorSubtract( ttv[ i ], dv[ i ]->xyz, ttv[ i ] );
+               VectorNormalize( ttv[ i ], ttv[ i ] );
+               
+               /* debug code */
+               //%     Sys_FPrintf( SYS_VRB, "%d S: (%f %f %f) T: (%f %f %f)\n", i,
+               //%             stv[ i ][ 0 ], stv[ i ][ 1 ], stv[ i ][ 2 ], ttv[ i ][ 0 ], ttv[ i ][ 1 ], ttv[ i ][ 2 ] );
+       }
+       
+       /* return to caller */
+       return qtrue;
+}
+
+
+
+
+/*
+PerturbNormal()
+perterbs the normal by the shader's normalmap in tangent space
+*/
+
+static void PerturbNormal( bspDrawVert_t *dv, shaderInfo_t *si, vec3_t pNormal, vec3_t stv[ 3 ], vec3_t ttv[ 3 ] )
+{
+       int                     i;
+       vec4_t          bump;
+       
+       
+       /* passthrough */
+       VectorCopy( dv->normal, pNormal );
+       
+       /* sample normalmap */
+       if( RadSampleImage( si->normalImage->pixels, si->normalImage->width, si->normalImage->height, dv->st, bump ) == qfalse )
+               return;
+       
+       /* remap sampled normal from [0,255] to [-1,-1] */
+       for( i = 0; i < 3; i++ )
+               bump[ i ] = (bump[ i ] - 127.0f) * (1.0f / 127.5f);
+       
+       /* scale tangent vectors and add to original normal */
+       VectorMA( dv->normal, bump[ 0 ], stv[ 0 ], pNormal );
+       VectorMA( pNormal, bump[ 1 ], ttv[ 0 ], pNormal );
+       VectorMA( pNormal, bump[ 2 ], dv->normal, pNormal );
+       
+       /* renormalize and return */
+       VectorNormalize( pNormal, pNormal );
+}
+
+
+
+/*
+MapSingleLuxel()
+maps a luxel for triangle bv at
+*/
+
+#define NUDGE                  0.5f
+#define BOGUS_NUDGE            -99999.0f
+
+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 ] )
+{
+       int                             i, x, y, numClusters, *clusters, pointCluster, *cluster;
+       float                   *luxel, *origin, *normal, d, lightmapSampleOffset;
+       shaderInfo_t    *si;
+       vec3_t                  pNormal;
+       vec3_t                  vecs[ 3 ];
+       vec3_t                  nudged;
+       float                   *nudge;
+       static float    nudges[][ 2 ] =
+                                       {
+                                               //%{ 0, 0 },            /* try center first */
+                                               { -NUDGE, 0 },          /* left */
+                                               { NUDGE, 0 },           /* right */
+                                               { 0, NUDGE },           /* up */
+                                               { 0, -NUDGE },          /* down */
+                                               { -NUDGE, NUDGE },      /* left/up */
+                                               { NUDGE, -NUDGE },      /* right/down */
+                                               { NUDGE, NUDGE },       /* right/up */
+                                               { -NUDGE, -NUDGE },     /* left/down */
+                                               { BOGUS_NUDGE, BOGUS_NUDGE }
+                                       };
+       
+       
+       /* find luxel xy coords (fixme: subtract 0.5?) */
+       x = dv->lightmap[ 0 ][ 0 ];
+       y = dv->lightmap[ 0 ][ 1 ];
+       if( x < 0 )
+               x = 0;
+       else if( x >= lm->sw )
+               x = lm->sw - 1;
+       if( y < 0 )
+               y = 0;
+       else if( y >= lm->sh )
+               y = lm->sh - 1;
+       
+       /* set shader and cluster list */
+       if( info != NULL )
+       {
+               si = info->si;
+               numClusters = info->numSurfaceClusters;
+               clusters = &surfaceClusters[ info->firstSurfaceCluster ];
+       }
+       else
+       {
+               si = NULL;
+               numClusters = 0;
+               clusters = NULL;
+       }
+       
+       /* get luxel, origin, cluster, and normal */
+       luxel = SUPER_LUXEL( 0, x, y );
+       origin = SUPER_ORIGIN( x, y );
+       normal = SUPER_NORMAL( x, y );
+       cluster = SUPER_CLUSTER( x, y );
+       
+       /* don't attempt to remap occluded luxels for planar surfaces */
+       if( (*cluster) == CLUSTER_OCCLUDED && lm->plane != NULL )
+               return (*cluster);
+       
+       /* only average the normal for premapped luxels */
+       else if( (*cluster) >= 0 )
+       {
+               /* do bumpmap calculations */
+               if( stv != NULL )
+                       PerturbNormal( dv, si, pNormal, stv, ttv );
+               else
+                       VectorCopy( dv->normal, pNormal );
+               
+               /* add the additional normal data */
+               VectorAdd( normal, pNormal, normal );
+               luxel[ 3 ] += 1.0f;
+               return (*cluster);
+       }
+       
+       /* otherwise, unmapped luxels (*cluster == CLUSTER_UNMAPPED) will have their full attributes calculated */
+       
+       /* get origin */
+       
+       /* axial lightmap projection */
+       if( lm->vecs != NULL )
+       {
+               /* calculate an origin for the sample from the lightmap vectors */
+               VectorCopy( lm->origin, origin );
+               for( i = 0; i < 3; i++ )
+               {
+                       /* add unless it's the axis, which is taken care of later */
+                       if( i == lm->axisNum )
+                               continue;
+                       origin[ i ] += (x * lm->vecs[ 0 ][ i ]) + (y * lm->vecs[ 1 ][ i ]);
+               }
+               
+               /* project the origin onto the plane */
+               d = DotProduct( origin, plane ) - plane[ 3 ];
+               d /= plane[ lm->axisNum ];
+               origin[ lm->axisNum ] -= d;
+       }
+       
+       /* non axial lightmap projection (explicit xyz) */
+       else
+               VectorCopy( dv->xyz, origin );
+       
+       /* planar surfaces have precalculated lightmap vectors for nudging */
+       if( lm->plane != NULL )
+       {
+               VectorCopy( lm->vecs[ 0 ], vecs[ 0 ] );
+               VectorCopy( lm->vecs[ 1 ], vecs[ 1 ] );
+               VectorCopy( lm->plane, vecs[ 2 ] );
+       }
+       
+       /* non-planar surfaces must calculate them */
+       else
+       {
+               if( plane != NULL )
+                       VectorCopy( plane, vecs[ 2 ] );
+               else
+                       VectorCopy( dv->normal, vecs[ 2 ] );
+               MakeNormalVectors( vecs[ 2 ], vecs[ 0 ], vecs[ 1 ] );
+       }
+       
+       /* push the origin off the surface a bit */
+       if( si != NULL )
+               lightmapSampleOffset = si->lightmapSampleOffset;
+       else
+               lightmapSampleOffset = DEFAULT_LIGHTMAP_SAMPLE_OFFSET;
+       if( lm->axisNum < 0 )
+               VectorMA( origin, lightmapSampleOffset, vecs[ 2 ], origin );
+       else if( vecs[ 2 ][ lm->axisNum ] < 0.0f )
+               origin[ lm->axisNum ] -= lightmapSampleOffset;
+       else
+               origin[ lm->axisNum ] += lightmapSampleOffset;
+       
+       /* get cluster */
+       pointCluster = ClusterForPointExtFilter( origin, LUXEL_EPSILON, numClusters, clusters );
+       
+       /* another retarded hack, storing nudge count in luxel[ 1 ] */
+       luxel[ 1 ] = 0.0f;      
+       
+       /* point in solid? */
+       if( pointCluster < 0 )
+       {
+               /* nudge the the location around */
+               nudge = nudges[ 0 ];
+               while( nudge[ 0 ] > BOGUS_NUDGE && pointCluster < 0 )
+               {
+                       /* nudge the vector around a bit */
+                       for( i = 0; i < 3; i++ )
+                       {
+                               /* set nudged point*/
+                               nudged[ i ] = origin[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
+                       }
+                       nudge += 2;
+                       
+                       /* get pvs cluster */
+                       pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); //% + 0.625 );
+                       if( pointCluster >= 0 ) 
+                               VectorCopy( nudged, origin );
+                       luxel[ 1 ] += 1.0f;
+               }
+       }
+       
+       /* as a last resort, if still in solid, try drawvert origin offset by normal */
+       if( pointCluster < 0 && si != NULL )
+       {
+               VectorMA( dv->xyz, lightmapSampleOffset, dv->normal, nudged );
+               pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters );
+               if( pointCluster >= 0 )
+                       VectorCopy( nudged, origin );
+               luxel[ 1 ] += 1.0f;
+       }
+       
+       /* valid? */
+       if( pointCluster < 0 )
+       {
+               (*cluster) = CLUSTER_OCCLUDED;
+               VectorClear( origin );
+               VectorClear( normal );
+               numLuxelsOccluded++;
+               return (*cluster);
+       }
+       
+       /* debug code */
+       //%     Sys_Printf( "%f %f %f\n", origin[ 0 ], origin[ 1 ], origin[ 2 ] );
+       
+       /* do bumpmap calculations */
+       if( stv )
+               PerturbNormal( dv, si, pNormal, stv, ttv );
+       else
+               VectorCopy( dv->normal, pNormal );
+       
+       /* store the cluster and normal */
+       (*cluster) = pointCluster;
+       VectorCopy( pNormal, normal );
+       
+       /* store explicit mapping pass and implicit mapping pass */
+       luxel[ 0 ] = pass;
+       luxel[ 3 ] = 1.0f;
+       
+       /* add to count */
+       numLuxelsMapped++;
+       
+       /* return ok */
+       return (*cluster);
+}
+
+
+
+/*
+MapTriangle_r()
+recursively subdivides a triangle until its edges are shorter
+than the distance between two luxels (thanks jc :)
+*/
+
+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 ] )
+{
+       bspDrawVert_t   mid, *dv2[ 3 ];
+       int                             max;
+       
+       
+       /* map the vertexes */
+       #if 0
+       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
+       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
+       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
+       #endif
+       
+       /* subdivide calc */
+       {
+               int                     i;
+               float           *a, *b, dx, dy, dist, maxDist;
+               
+               
+               /* find the longest edge and split it */
+               max = -1;
+               maxDist = 0;
+               for( i = 0; i < 3; i++ )
+               {
+                       /* get verts */
+                       a = dv[ i ]->lightmap[ 0 ];
+                       b = dv[ (i + 1) % 3 ]->lightmap[ 0 ];
+                       
+                       /* get dists */
+                       dx = a[ 0 ] - b[ 0 ];
+                       dy = a[ 1 ] - b[ 1 ];
+                       dist = (dx * dx) + (dy * dy);   //% sqrt( (dx * dx) + (dy * dy) );
+                       
+                       /* longer? */
+                       if( dist > maxDist )
+                       {
+                               maxDist = dist;
+                               max = i;
+                       }
+               }
+               
+               /* try to early out */
+               if( max < 0 || maxDist <= subdivideThreshold )  /* ydnar: was i < 0 instead of max < 0 (?) */
+                       return;
+       }
+       
+       /* split the longest edge and map it */
+       LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid );
+       MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv );
+       
+       /* push the point up a little bit to account for fp creep (fixme: revisit this) */
+       //%     VectorMA( mid.xyz, 2.0f, mid.normal, mid.xyz );
+       
+       /* recurse to first triangle */
+       VectorCopy( dv, dv2 );
+       dv2[ max ] = &mid;
+       MapTriangle_r( lm, info, dv2, plane, stv, ttv );
+       
+       /* recurse to second triangle */
+       VectorCopy( dv, dv2 );
+       dv2[ (max + 1) % 3 ] = &mid;
+       MapTriangle_r( lm, info, dv2, plane, stv, ttv );
+}
+
+
+
+/*
+MapTriangle()
+seed function for MapTriangle_r()
+requires a cw ordered triangle
+*/
+
+static qboolean MapTriangle( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 3 ], qboolean mapNonAxial )
+{
+       int                             i;
+       vec4_t                  plane;
+       vec3_t                  *stv, *ttv, stvStatic[ 3 ], ttvStatic[ 3 ];
+       
+       
+       /* get plane if possible */
+       if( lm->plane != NULL )
+       {
+               VectorCopy( lm->plane, plane );
+               plane[ 3 ] = lm->plane[ 3 ];
+       }
+       
+       /* otherwise make one from the points */
+       else if( PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) == qfalse )
+               return qfalse;
+       
+       /* check to see if we need to calculate texture->world tangent vectors */
+       if( info->si->normalImage != NULL && CalcTangentVectors( 3, dv, stvStatic, ttvStatic ) )
+       {
+               stv = stvStatic;
+               ttv = ttvStatic;
+       }
+       else
+       {
+               stv = NULL;
+               ttv = NULL;
+       }
+       
+       /* map the vertexes */
+       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
+       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
+       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
+       
+       /* 2002-11-20: prefer axial triangle edges */
+       if( mapNonAxial )
+       {
+               /* subdivide the triangle */
+               MapTriangle_r( lm, info, dv, plane, stv, ttv );
+               return qtrue;
+       }
+       
+       for( i = 0; i < 3; i++ )
+       {
+               float                   *a, *b;
+               bspDrawVert_t   *dv2[ 3 ];
+               
+               
+               /* get verts */
+               a = dv[ i ]->lightmap[ 0 ];
+               b = dv[ (i + 1) % 3 ]->lightmap[ 0 ];
+               
+               /* make degenerate triangles for mapping edges */
+               if( fabs( a[ 0 ] - b[ 0 ] ) < 0.01f || fabs( a[ 1 ] - b[ 1 ] ) < 0.01f )
+               {
+                       dv2[ 0 ] = dv[ i ];
+                       dv2[ 1 ] = dv[ (i + 1) % 3 ];
+                       dv2[ 2 ] = dv[ (i + 1) % 3 ];
+                       
+                       /* map the degenerate triangle */
+                       MapTriangle_r( lm, info, dv2, plane, stv, ttv );
+               }
+       }
+       
+       return qtrue;
+}
+
+
+
+/*
+MapQuad_r()
+recursively subdivides a quad until its edges are shorter
+than the distance between two luxels
+*/
+
+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 ] )
+{
+       bspDrawVert_t   mid[ 2 ], *dv2[ 4 ];
+       int                             max;
+       
+       
+       /* subdivide calc */
+       {
+               int                     i;
+               float           *a, *b, dx, dy, dist, maxDist;
+               
+               
+               /* find the longest edge and split it */
+               max = -1;
+               maxDist = 0;
+               for( i = 0; i < 4; i++ )
+               {
+                       /* get verts */
+                       a = dv[ i ]->lightmap[ 0 ];
+                       b = dv[ (i + 1) % 4 ]->lightmap[ 0 ];
+                       
+                       /* get dists */
+                       dx = a[ 0 ] - b[ 0 ];
+                       dy = a[ 1 ] - b[ 1 ];
+                       dist = (dx * dx) + (dy * dy);   //% sqrt( (dx * dx) + (dy * dy) );
+                       
+                       /* longer? */
+                       if( dist > maxDist )
+                       {
+                               maxDist = dist;
+                               max = i;
+                       }
+               }
+               
+               /* try to early out */
+               if( max < 0 || maxDist <= subdivideThreshold )
+                       return;
+       }
+       
+       /* we only care about even/odd edges */
+       max &= 1;
+       
+       /* split the longest edges */
+       LerpDrawVert( dv[ max ], dv[ (max + 1) % 4 ], &mid[ 0 ] );
+       LerpDrawVert( dv[ max + 2 ], dv[ (max + 3) % 4 ], &mid[ 1 ] );
+       
+       /* map the vertexes */
+       MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv );
+       MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv );
+       
+       /* 0 and 2 */
+       if( max == 0 )
+       {
+               /* recurse to first quad */
+               dv2[ 0 ] = dv[ 0 ];
+               dv2[ 1 ] = &mid[ 0 ];
+               dv2[ 2 ] = &mid[ 1 ];
+               dv2[ 3 ] = dv[ 3 ];
+               MapQuad_r( lm, info, dv2, plane, stv, ttv );
+               
+               /* recurse to second quad */
+               dv2[ 0 ] = &mid[ 0 ];
+               dv2[ 1 ] = dv[ 1 ];
+               dv2[ 2 ] = dv[ 2 ];
+               dv2[ 3 ] = &mid[ 1 ];
+               MapQuad_r( lm, info, dv2, plane, stv, ttv );
+       }
+       
+       /* 1 and 3 */
+       else
+       {
+               /* recurse to first quad */
+               dv2[ 0 ] = dv[ 0 ];
+               dv2[ 1 ] = dv[ 1 ];
+               dv2[ 2 ] = &mid[ 0 ];
+               dv2[ 3 ] = &mid[ 1 ];
+               MapQuad_r( lm, info, dv2, plane, stv, ttv );
+               
+               /* recurse to second quad */
+               dv2[ 0 ] = &mid[ 1 ];
+               dv2[ 1 ] = &mid[ 0 ];
+               dv2[ 2 ] = dv[ 2 ];
+               dv2[ 3 ] = dv[ 3 ];
+               MapQuad_r( lm, info, dv2, plane, stv, ttv );
+       }
+}
+
+
+
+/*
+MapQuad()
+seed function for MapQuad_r()
+requires a cw ordered triangle quad
+*/
+
+#define QUAD_PLANAR_EPSILON            0.5f
+
+static qboolean MapQuad( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 4 ] )
+{
+       float                   dist;
+       vec4_t                  plane;
+       vec3_t                  *stv, *ttv, stvStatic[ 4 ], ttvStatic[ 4 ];
+       
+       
+       /* get plane if possible */
+       if( lm->plane != NULL )
+       {
+               VectorCopy( lm->plane, plane );
+               plane[ 3 ] = lm->plane[ 3 ];
+       }
+       
+       /* otherwise make one from the points */
+       else if( PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) == qfalse )
+               return qfalse;
+       
+       /* 4th point must fall on the plane */
+       dist = DotProduct( plane, dv[ 3 ]->xyz ) - plane[ 3 ];
+       if( fabs( dist ) > QUAD_PLANAR_EPSILON )
+               return qfalse;
+       
+       /* check to see if we need to calculate texture->world tangent vectors */
+       if( info->si->normalImage != NULL && CalcTangentVectors( 4, dv, stvStatic, ttvStatic ) )
+       {
+               stv = stvStatic;
+               ttv = ttvStatic;
+       }
+       else
+       {
+               stv = NULL;
+               ttv = NULL;
+       }
+       
+       /* map the vertexes */
+       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
+       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
+       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
+       MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv );
+       
+       /* subdivide the quad */
+       MapQuad_r( lm, info, dv, plane, stv, ttv );
+       return qtrue;
+}
+
+
+
+/*
+MapRawLightmap()
+maps the locations, normals, and pvs clusters for a raw lightmap
+*/
+
+#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)
+
+void MapRawLightmap( int rawLightmapNum )
+{
+       int                                     n, num, i, x, y, sx, sy, pw[ 5 ], r, *cluster, mapNonAxial;
+       float                           *luxel, *origin, *normal, samples, radius, pass;
+       rawLightmap_t           *lm;
+       bspDrawSurface_t        *ds;
+       surfaceInfo_t           *info;
+       mesh_t                          src, *subdivided, *mesh;
+       bspDrawVert_t           *verts, *dv[ 4 ], fake;
+       
+       
+       /* bail if this number exceeds the number of raw lightmaps */
+       if( rawLightmapNum >= numRawLightmaps )
+               return;
+       
+       /* get lightmap */
+       lm = &rawLightmaps[ rawLightmapNum ];
+       
+       /* -----------------------------------------------------------------
+          map referenced surfaces onto the raw lightmap
+          ----------------------------------------------------------------- */
+       
+       /* walk the list of surfaces on this raw lightmap */
+       for( n = 0; n < lm->numLightSurfaces; n++ )
+       {
+               /* with > 1 surface per raw lightmap, clear occluded */
+               if( n > 0 )
+               {
+                       for( y = 0; y < lm->sh; y++ )
+                       {
+                               for( x = 0; x < lm->sw; x++ )
+                               {
+                                       /* get cluster */
+                                       cluster = SUPER_CLUSTER( x, y );
+                                       if( *cluster < 0 )
+                                               *cluster = CLUSTER_UNMAPPED;
+                               }
+                       }
+               }
+               
+               /* get surface */
+               num = lightSurfaces[ lm->firstLightSurface + n ];
+               ds = &bspDrawSurfaces[ num ];
+               info = &surfaceInfos[ num ];
+               
+               /* bail if no lightmap to calculate */
+               if( info->lm != lm )
+               {
+                       Sys_Printf( "!" );
+                       continue;
+               }
+               
+               /* map the surface onto the lightmap origin/cluster/normal buffers */
+               switch( ds->surfaceType )
+               {
+                       case MST_PLANAR:
+                               /* get verts */
+                               verts = yDrawVerts + ds->firstVert;
+                               
+                               /* map the triangles */
+                               for( mapNonAxial = 0; mapNonAxial < 2; mapNonAxial++ )
+                               {
+                                       for( i = 0; i < ds->numIndexes; i += 3 )
+                                       {
+                                               dv[ 0 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i ] ];
+                                               dv[ 1 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 1 ] ];
+                                               dv[ 2 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 2 ] ];
+                                               MapTriangle( lm, info, dv, mapNonAxial );
+                                       }
+                               }
+                               break;
+                       
+                       case MST_PATCH:
+                               /* make a mesh from the drawsurf */ 
+                               src.width = ds->patchWidth;
+                               src.height = ds->patchHeight;
+                               src.verts = &yDrawVerts[ ds->firstVert ];
+                               //%     subdivided = SubdivideMesh( src, 8, 512 );
+                               subdivided = SubdivideMesh2( src, info->patchIterations );
+                               
+                               /* fit it to the curve and remove colinear verts on rows/columns */
+                               PutMeshOnCurve( *subdivided );
+                               mesh = RemoveLinearMeshColumnsRows( subdivided );
+                               FreeMesh( subdivided );
+                               
+                               /* get verts */
+                               verts = mesh->verts;
+                               
+                               /* debug code */
+                               #if 0
+                                       if( lm->plane )
+                                       {
+                                               Sys_Printf( "Planar patch: [%1.3f %1.3f %1.3f] [%1.3f %1.3f %1.3f] [%1.3f %1.3f %1.3f]\n",
+                                                       lm->plane[ 0 ], lm->plane[ 1 ], lm->plane[ 2 ],
+                                                       lm->vecs[ 0 ][ 0 ], lm->vecs[ 0 ][ 1 ], lm->vecs[ 0 ][ 2 ],
+                                                       lm->vecs[ 1 ][ 0 ], lm->vecs[ 1 ][ 1 ], lm->vecs[ 1 ][ 2 ] );
+                                       }
+                               #endif
+                               
+                               /* map the mesh quads */
+                               #if 0
+
+                               for( mapNonAxial = 0; mapNonAxial < 2; mapNonAxial++ )
+                               {
+                                       for( y = 0; y < (mesh->height - 1); y++ )
+                                       {
+                                               for( x = 0; x < (mesh->width - 1); x++ )
+                                               {
+                                                       /* set indexes */
+                                                       pw[ 0 ] = x + (y * mesh->width);
+                                                       pw[ 1 ] = x + ((y + 1) * mesh->width);
+                                                       pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
+                                                       pw[ 3 ] = x + 1 + (y * mesh->width);
+                                                       pw[ 4 ] = x + (y * mesh->width);        /* same as pw[ 0 ] */
+                                                       
+                                                       /* set radix */
+                                                       r = (x + y) & 1;
+                                                       
+                                                       /* get drawverts and map first triangle */
+                                                       dv[ 0 ] = &verts[ pw[ r + 0 ] ];
+                                                       dv[ 1 ] = &verts[ pw[ r + 1 ] ];
+                                                       dv[ 2 ] = &verts[ pw[ r + 2 ] ];
+                                                       MapTriangle( lm, info, dv, mapNonAxial );
+                                                       
+                                                       /* get drawverts and map second triangle */
+                                                       dv[ 0 ] = &verts[ pw[ r + 0 ] ];
+                                                       dv[ 1 ] = &verts[ pw[ r + 2 ] ];
+                                                       dv[ 2 ] = &verts[ pw[ r + 3 ] ];
+                                                       MapTriangle( lm, info, dv, mapNonAxial );
+                                               }
+                                       }
+                               }
+                               
+                               #else
+                               
+                               for( y = 0; y < (mesh->height - 1); y++ )
+                               {
+                                       for( x = 0; x < (mesh->width - 1); x++ )
+                                       {
+                                               /* set indexes */
+                                               pw[ 0 ] = x + (y * mesh->width);
+                                               pw[ 1 ] = x + ((y + 1) * mesh->width);
+                                               pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
+                                               pw[ 3 ] = x + 1 + (y * mesh->width);
+                                               pw[ 4 ] = pw[ 0 ];
+                                               
+                                               /* set radix */
+                                               r = (x + y) & 1;
+                                               
+                                               /* attempt to map quad first */
+                                               dv[ 0 ] = &verts[ pw[ r + 0 ] ];
+                                               dv[ 1 ] = &verts[ pw[ r + 1 ] ];
+                                               dv[ 2 ] = &verts[ pw[ r + 2 ] ];
+                                               dv[ 3 ] = &verts[ pw[ r + 3 ] ];
+                                               if( MapQuad( lm, info, dv ) )
+                                                       continue;
+                                               
+                                               /* get drawverts and map first triangle */
+                                               MapTriangle( lm, info, dv, mapNonAxial );
+                                               
+                                               /* get drawverts and map second triangle */
+                                               dv[ 1 ] = &verts[ pw[ r + 2 ] ];
+                                               dv[ 2 ] = &verts[ pw[ r + 3 ] ];
+                                               MapTriangle( lm, info, dv, mapNonAxial );
+                                       }
+                               }
+                               
+                               #endif
+                               
+                               /* free the mesh */
+                               FreeMesh( mesh );
+                               break;
+                       
+                       default:
+                               break;
+               }
+       }
+       
+       /* -----------------------------------------------------------------
+          average and clean up luxel normals
+          ----------------------------------------------------------------- */
+       
+       /* walk the luxels */
+       for( y = 0; y < lm->sh; y++ )
+       {
+               for( x = 0; x < lm->sw; x++ )
+               {
+                       /* get luxel */
+                       luxel = SUPER_LUXEL( 0, x, y );
+                       normal = SUPER_NORMAL( x, y );
+                       cluster = SUPER_CLUSTER( x, y );
+
+                       /* only look at mapped luxels */
+                       if( *cluster < 0 )
+                               continue;
+                       
+                       /* the normal data could be the sum of multiple samples */
+                       if( luxel[ 3 ] > 1.0f )
+                               VectorNormalize( normal, normal );
+                       
+                       /* mark this luxel as having only one normal */
+                       luxel[ 3 ] = 1.0f;
+               }
+       }
+       
+       /* non-planar surfaces stop here */
+       if( lm->plane == NULL )
+               return;
+       
+       /* -----------------------------------------------------------------
+          map occluded or unuxed luxels
+          ----------------------------------------------------------------- */
+       
+       /* walk the luxels */
+       radius = floor( superSample / 2 );
+       radius = radius > 0 ? radius : 1.0f;
+       radius += 1.0f;
+       for( pass = 2.0f; pass <= radius; pass += 1.0f )
+       {
+               for( y = 0; y < lm->sh; y++ )
+               {
+                       for( x = 0; x < lm->sw; x++ )
+                       {
+                               /* get luxel */
+                               luxel = SUPER_LUXEL( 0, x, y );
+                               normal = SUPER_NORMAL( x, y );
+                               cluster = SUPER_CLUSTER( x, y );
+                               
+                               /* only look at unmapped luxels */
+                               if( *cluster != CLUSTER_UNMAPPED )
+                                       continue;
+                               
+                               /* divine a normal and origin from neighboring luxels */
+                               VectorClear( fake.xyz );
+                               VectorClear( fake.normal );
+                               fake.lightmap[ 0 ][ 0 ] = x;    //% 0.0001 + x;
+                               fake.lightmap[ 0 ][ 1 ] = y;    //% 0.0001 + y;
+                               samples = 0.0f;
+                               for( sy = (y - 1); sy <= (y + 1); sy++ )
+                               {
+                                       if( sy < 0 || sy >= lm->sh )
+                                               continue;
+                                       
+                                       for( sx = (x - 1); sx <= (x + 1); sx++ )
+                                       {
+                                               if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
+                                                       continue;
+                                               
+                                               /* get neighboring luxel */
+                                               luxel = SUPER_LUXEL( 0, sx, sy );
+                                               origin = SUPER_ORIGIN( sx, sy );
+                                               normal = SUPER_NORMAL( sx, sy );
+                                               cluster = SUPER_CLUSTER( sx, sy );
+                                               
+                                               /* only consider luxels mapped in previous passes */
+                                               if( *cluster < 0 || luxel[ 0 ] >= pass )
+                                                       continue;
+                                               
+                                               /* add its distinctiveness to our own */
+                                               VectorAdd( fake.xyz, origin, fake.xyz );
+                                               VectorAdd( fake.normal, normal, fake.normal );
+                                               samples += luxel[ 3 ];
+                                       }
+                               }
+                               
+                               /* any samples? */
+                               if( samples == 0.0f )
+                                       continue;
+                               
+                               /* average */
+                               VectorDivide( fake.xyz, samples, fake.xyz );
+                               //%     VectorDivide( fake.normal, samples, fake.normal );
+                               if( VectorNormalize( fake.normal, fake.normal ) == 0.0f )
+                                       continue;
+                               
+                               /* map the fake vert */
+                               MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL );
+                       }
+               }
+       }
+       
+       /* -----------------------------------------------------------------
+          average and clean up luxel normals
+          ----------------------------------------------------------------- */
+       
+       /* walk the luxels */
+       for( y = 0; y < lm->sh; y++ )
+       {
+               for( x = 0; x < lm->sw; x++ )
+               {
+                       /* get luxel */
+                       luxel = SUPER_LUXEL( 0, x, y );
+                       normal = SUPER_NORMAL( x, y );
+                       cluster = SUPER_CLUSTER( x, y );
+                       
+                       /* only look at mapped luxels */
+                       if( *cluster < 0 )
+                               continue;
+                       
+                       /* the normal data could be the sum of multiple samples */
+                       if( luxel[ 3 ] > 1.0f )
+                               VectorNormalize( normal, normal );
+                       
+                       /* mark this luxel as having only one normal */
+                       luxel[ 3 ] = 1.0f;
+               }
+       }
+       
+       /* debug code */
+       #if 0
+               Sys_Printf( "\n" );
+               for( y = 0; y < lm->sh; y++ )
+               {
+                       for( x = 0; x < lm->sw; x++ )
+                       {
+                               vec3_t  mins, maxs;
+                               
+
+                               cluster = SUPER_CLUSTER( x, y );
+                               origin = SUPER_ORIGIN( x, y );
+                               normal = SUPER_NORMAL( x, y );
+                               luxel = SUPER_LUXEL( x, y );
+                               
+                               if( *cluster < 0 )
+                                       continue;
+                               
+                               /* check if within the bounding boxes of all surfaces referenced */
+                               ClearBounds( mins, maxs );
+                               for( n = 0; n < lm->numLightSurfaces; n++ )
+                               {
+                                       int TOL;
+                                       info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + n ] ];
+                                       TOL = info->sampleSize + 2;
+                                       AddPointToBounds( info->mins, mins, maxs );
+                                       AddPointToBounds( info->maxs, mins, maxs );
+                                       if( origin[ 0 ] > (info->mins[ 0 ] - TOL) && origin[ 0 ] < (info->maxs[ 0 ] + TOL) &&
+                                               origin[ 1 ] > (info->mins[ 1 ] - TOL) && origin[ 1 ] < (info->maxs[ 1 ] + TOL) &&
+                                               origin[ 2 ] > (info->mins[ 2 ] - TOL) && origin[ 2 ] < (info->maxs[ 2 ] + TOL) )
+                                               break;
+                               }
+                               
+                               /* inside? */
+                               if( n < lm->numLightSurfaces )
+                                       continue;
+                               
+                               /* report bogus origin */
+                               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",
+                                       rawLightmapNum, x, y, *cluster,
+                                       origin[ 0 ], origin[ 1 ], origin[ 2 ],
+                                       mins[ 0 ], mins[ 1 ], mins[ 2 ],
+                                       maxs[ 0 ], maxs[ 1 ], maxs[ 2 ],
+                                       luxel[ 3 ] );
+                       }
+               }
+       #endif
+}
+
+
+
+/*
+SubmapRawLuxel()
+calculates the pvs cluster, origin, normal of a sub-luxel
+*/
+
+static qboolean SubmapRawLuxel( rawLightmap_t *lm, int x, int y, float bx, float by, int *sampleCluster, vec3_t sampleOrigin, vec3_t sampleNormal )
+{
+       int                     i, *cluster, *cluster2;
+       float           *origin, *origin2, *normal;     //%     , *normal2;
+       vec3_t          originVecs[ 2 ];                        //%     , normalVecs[ 2 ];
+       
+       
+       /* calulate x vector */
+       if( (x < (lm->sw - 1) && bx >= 0.0f) || (x == 0 && bx <= 0.0f) )
+       {
+               cluster = SUPER_CLUSTER( x, y );
+               origin = SUPER_ORIGIN( x, y );
+               //%     normal = SUPER_NORMAL( x, y );
+               cluster2 = SUPER_CLUSTER( x + 1, y );
+               origin2 = *cluster2 < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x + 1, y );
+               //%     normal2 = *cluster2 < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x + 1, y );
+       }
+       else if( (x > 0 && bx <= 0.0f) || (x == (lm->sw - 1) && bx >= 0.0f) )
+       {
+               cluster = SUPER_CLUSTER( x - 1, y );
+               origin = *cluster < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x - 1, y );
+               //%     normal = *cluster < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x - 1, y );
+               cluster2 = SUPER_CLUSTER( x, y );
+               origin2 = SUPER_ORIGIN( x, y );
+               //%     normal2 = SUPER_NORMAL( x, y );
+       }
+       else
+               Sys_Printf( "WARNING: Spurious lightmap S vector\n" );
+       
+       VectorSubtract( origin2, origin, originVecs[ 0 ] );
+       //%     VectorSubtract( normal2, normal, normalVecs[ 0 ] );
+       
+       /* calulate y vector */
+       if( (y < (lm->sh - 1) && bx >= 0.0f) || (y == 0 && bx <= 0.0f) )
+       {
+               cluster = SUPER_CLUSTER( x, y );
+               origin = SUPER_ORIGIN( x, y );
+               //%     normal = SUPER_NORMAL( x, y );
+               cluster2 = SUPER_CLUSTER( x, y + 1 );
+               origin2 = *cluster2 < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x, y + 1 );
+               //%     normal2 = *cluster2 < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x, y + 1 );
+       }
+       else if( (y > 0 && bx <= 0.0f) || (y == (lm->sh - 1) && bx >= 0.0f) )
+       {
+               cluster = SUPER_CLUSTER( x, y - 1 );
+               origin = *cluster < 0 ? SUPER_ORIGIN( x, y ) : SUPER_ORIGIN( x, y - 1 );
+               //%     normal = *cluster < 0 ? SUPER_NORMAL( x, y ) : SUPER_NORMAL( x, y - 1 );
+               cluster2 = SUPER_CLUSTER( x, y );
+               origin2 = SUPER_ORIGIN( x, y );
+               //%     normal2 = SUPER_NORMAL( x, y );
+       }
+       else
+               Sys_Printf( "WARNING: Spurious lightmap T vector\n" );
+       
+       VectorSubtract( origin2, origin, originVecs[ 1 ] );
+       //%     VectorSubtract( normal2, normal, normalVecs[ 1 ] );
+       
+       /* calculate new origin */
+       //%     VectorMA( origin, bx, originVecs[ 0 ], sampleOrigin );
+       //%     VectorMA( sampleOrigin, by, originVecs[ 1 ], sampleOrigin );
+       for( i = 0; i < 3; i++ )
+               sampleOrigin[ i ] = sampleOrigin[ i ] + (bx * originVecs[ 0 ][ i ]) + (by * originVecs[ 1 ][ i ]);
+       
+       /* get cluster */
+       *sampleCluster = ClusterForPointExtFilter( sampleOrigin, (LUXEL_EPSILON * 2), lm->numLightClusters, lm->lightClusters );
+       if( *sampleCluster < 0 )
+               return qfalse;
+       
+       /* calculate new normal */
+       //%     VectorMA( normal, bx, normalVecs[ 0 ], sampleNormal );
+       //%     VectorMA( sampleNormal, by, normalVecs[ 1 ], sampleNormal );
+       //%     if( VectorNormalize( sampleNormal, sampleNormal ) <= 0.0f )
+       //%             return qfalse;
+       normal = SUPER_NORMAL( x, y );
+       VectorCopy( normal, sampleNormal );
+       
+       /* return ok */
+       return qtrue;
+}
+
+
+/*
+SubsampleRawLuxel_r()
+recursively subsamples a luxel until its color gradient is low enough or subsampling limit is reached
+*/
+
+void SubsampleRawLuxel_r( rawLightmap_t *lm, trace_t *trace, vec3_t sampleOrigin, int x, int y, float bias, float *lightLuxel )
+{
+       int                     b, samples, mapped, lighted;
+       int                     cluster[ 4 ];
+       vec4_t          luxel[ 4 ];
+       vec3_t          origin[ 4 ], normal[ 4 ];
+       float           biasDirs[ 4 ][ 2 ] = { { -1.0f, -1.0f }, { 1.0f, -1.0f }, { -1.0f, 1.0f }, { 1.0f, 1.0f } };
+       vec3_t          color, total;
+       
+       
+       /* limit check */
+       if( lightLuxel[ 3 ] >= lightSamples )
+               return;
+       
+       /* setup */
+       VectorClear( total );
+       mapped = 0;
+       lighted = 0;
+       
+       /* make 2x2 subsample stamp */
+       for( b = 0; b < 4; b++ )
+       {
+               /* set origin */
+               VectorCopy( sampleOrigin, origin[ b ] );
+               
+               /* calculate position */
+               if( !SubmapRawLuxel( lm, x, y, (bias * biasDirs[ b ][ 0 ]), (bias * biasDirs[ b ][ 1 ]), &cluster[ b ], origin[ b ], normal[ b ] ) )
+               {
+                       cluster[ b ] = -1;
+                       continue;
+               }
+               mapped++;
+               
+               /* increment sample count */
+               luxel[ b ][ 3 ] = lightLuxel[ 3 ] + 1.0f;
+               
+               /* setup trace */
+               trace->cluster = *cluster;
+               VectorCopy( origin[ b ], trace->origin );
+               VectorCopy( normal[ b ], trace->normal );
+               
+               /* sample light */
+               //%     LightContributionToSample( light, cluster[ b ], origin[ b ], normal[ b ], luxel[ b ], qtrue, qfalse, lm->numLightSurfaces, &lightSurfaces[ lm->firstLightSurface ] );
+               LightContributionToSample( trace );
+               
+               /* add to totals (fixme: make contrast function) */
+               VectorCopy( trace->color, luxel[ b ] );
+               VectorAdd( total, trace->color, total );
+               if( (luxel[ b ][ 0 ] + luxel[ b ][ 1 ] + luxel[ b ][ 2 ]) > 0.0f )
+                       lighted++;
+       }
+       
+       /* subsample further? */
+       if( (lightLuxel[ 3 ] + 1.0f) < lightSamples &&
+               (total[ 0 ] > 4.0f || total[ 1 ] > 4.0f || total[ 2 ] > 4.0f) &&
+               lighted != 0 && lighted != mapped )
+       {
+               for( b = 0; b < 4; b++ )
+               {
+                       if( cluster[ b ] < 0 )
+                               continue;
+                       SubsampleRawLuxel_r( lm, trace, origin[ b ], x, y, (bias * 0.25f), luxel[ b ] );
+               }
+       }
+       
+       /* average */
+       //%     VectorClear( color );
+       //%     samples = 0;
+       VectorCopy( lightLuxel, color );
+       samples = 1;
+       for( b = 0; b < 4; b++ )
+       {
+               if( cluster[ b ] < 0 )
+                       continue;
+               VectorAdd( color, luxel[ b ], color );
+               samples++;
+       }
+       
+       /* add to luxel */
+       if( samples > 0 )
+       {
+               /* average */
+               color[ 0 ] /= samples;
+               color[ 1 ] /= samples;
+               color[ 2 ] /= samples;
+               
+               /* add to color */
+               VectorCopy( color, lightLuxel );
+               lightLuxel[ 3 ] += 1.0f;
+       }
+}
+
+
+
+/*
+IlluminateRawLightmap()
+illuminates the luxels
+*/
+
+#define LIGHT_LUXEL( x, y )            (lightLuxels + ((((y) * lm->sw) + (x)) * SUPER_LUXEL_SIZE))
+
+void IlluminateRawLightmap( int rawLightmapNum )
+{
+       int                                     i, t, x, y, sx, sy, size, llSize, luxelFilterRadius, lightmapNum;
+       int                                     *cluster, *cluster2, mapped, lighted, totalLighted;
+       rawLightmap_t           *lm;
+       surfaceInfo_t           *info;
+       qboolean                        filterColor, filterDir;
+       float                           brightness;
+       float                           *origin, *normal, *luxel, *luxel2, *deluxel, *deluxel2;
+       float                           *lightLuxels, *lightLuxel, samples, filterRadius, weight;
+       vec3_t                          color, averageColor, averageDir, total, temp, temp2;
+       float                           tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
+       trace_t                         trace;
+       
+       
+       /* bail if this number exceeds the number of raw lightmaps */
+       if( rawLightmapNum >= numRawLightmaps )
+               return;
+       
+       /* get lightmap */
+       lm = &rawLightmaps[ rawLightmapNum ];
+       
+       /* setup trace */
+       trace.testOcclusion = !noTrace;
+       trace.forceSunlight = qfalse;
+       trace.recvShadows = lm->recvShadows;
+       trace.numSurfaces = lm->numLightSurfaces;
+       trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
+       trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
+       
+       /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
+       trace.twoSided = qfalse;
+       for( i = 0; i < trace.numSurfaces; i++ )
+       {
+               /* get surface */
+               info = &surfaceInfos[ trace.surfaces[ i ] ];
+               
+               /* check twosidedness */
+               if( info->si->twoSided )
+               {
+                       trace.twoSided = qtrue;
+                       break;
+               }
+       }
+       
+       /* create a culled light list for this raw lightmap */
+       CreateTraceLightsForBounds( lm->mins, lm->maxs, lm->plane, lm->numLightClusters, lm->lightClusters, LIGHT_SURFACES, &trace );
+       
+       /* -----------------------------------------------------------------
+          fill pass
+          ----------------------------------------------------------------- */
+       
+       /* test debugging state */
+       if( debugSurfaces || debugAxis || debugCluster || debugOrigin || normalmap )
+       {
+               /* debug fill the luxels */
+               for( y = 0; y < lm->sh; y++ )
+               {
+                       for( x = 0; x < lm->sw; x++ )
+                       {
+                               /* get cluster */
+                               cluster = SUPER_CLUSTER( x, y );
+
+                               /* only fill mapped luxels */
+                               if( *cluster < 0 )
+                                       continue;
+                               
+                               /* get particulars */
+                               luxel = SUPER_LUXEL( 0, x, y );
+                               origin = SUPER_ORIGIN( x, y );
+                               normal = SUPER_NORMAL( x, y );
+                               
+                               /* color the luxel with raw lightmap num? */
+                               if( debugSurfaces )
+                                       VectorCopy( debugColors[ rawLightmapNum % 12 ], luxel );
+                               
+                               /* color the luxel with lightmap axis? */
+                               else if( debugAxis )
+                               {
+                                       luxel[ 0 ] = (lm->axis[ 0 ] + 1.0f) * 127.5f;
+                                       luxel[ 1 ] = (lm->axis[ 1 ] + 1.0f) * 127.5f;
+                                       luxel[ 2 ] = (lm->axis[ 2 ] + 1.0f) * 127.5f;
+                               }
+                               
+                               /* color the luxel with luxel cluster? */
+                               else if( debugCluster )
+                                       VectorCopy( debugColors[ *cluster % 12 ], luxel );
+                               
+                               /* color the luxel with luxel origin? */
+                               else if( debugOrigin )
+                               {
+                                       VectorSubtract( lm->maxs, lm->mins, temp );
+                                       VectorScale( temp, (1.0f / 255.0f), temp );
+                                       VectorSubtract( origin, lm->mins, temp2 );
+                                       luxel[ 0 ] = lm->mins[ 0 ] + (temp[ 0 ] * temp2[ 0 ]);
+                                       luxel[ 1 ] = lm->mins[ 1 ] + (temp[ 1 ] * temp2[ 1 ]);
+                                       luxel[ 2 ] = lm->mins[ 2 ] + (temp[ 2 ] * temp2[ 2 ]);
+                               }
+                               
+                               /* color the luxel with the normal */
+                               else if( normalmap )
+                               {
+                                       luxel[ 0 ] = (normal[ 0 ] + 1.0f) * 127.5f;
+                                       luxel[ 1 ] = (normal[ 1 ] + 1.0f) * 127.5f;
+                                       luxel[ 2 ] = (normal[ 2 ] + 1.0f) * 127.5f;
+                               }
+                               
+                               /* add to counts */
+                               numLuxelsIlluminated++;
+                               luxel[ 3 ] = 1.0f;
+                       }
+               }
+       }
+       else
+       {
+               /* allocate temporary per-light luxel storage */
+               llSize = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
+               lightLuxels = safe_malloc( llSize );
+               
+               /* clear luxels */
+               //%     memset( lm->superLuxels[ 0 ], 0, llSize );
+               
+               /* set ambient color */
+               for( y = 0; y < lm->sh; y++ )
+               {
+                       for( x = 0; x < lm->sw; x++ )
+                       {
+                               /* get cluster */
+                               cluster = SUPER_CLUSTER( x, y );
+                               luxel = SUPER_LUXEL( 0, x, y );
+                               normal = SUPER_NORMAL( x, y );
+                               deluxel = SUPER_DELUXEL( x, y );
+                               
+                               /* blacken unmapped clusters */
+                               if( *cluster < 0 )
+                                       VectorClear( luxel );
+                               
+                               /* set ambient */
+                               else
+                               {
+                                       VectorCopy( ambientColor, luxel );
+                                       if( deluxemap )
+                                               VectorScale( normal, 0.00390625f, deluxel );
+                                       luxel[ 3 ] = 1.0f;
+                               }
+                       }
+               }
+               
+               /* clear styled lightmaps */
+               size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
+               for( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+               {
+                       if( lm->superLuxels[ lightmapNum ] != NULL )
+                               memset( lm->superLuxels[ lightmapNum ], 0, size );
+               }
+               
+               /* debugging code */
+               //%     if( trace.numLights <= 0 )
+               //%             Sys_Printf( "Lightmap %9d: 0 lights, axis: %.2f, %.2f, %.2f\n", rawLightmapNum, lm->axis[ 0 ], lm->axis[ 1 ], lm->axis[ 2 ] );
+               
+               /* walk light list */
+               for( i = 0; i < trace.numLights; i++ )
+               {
+                       /* setup trace */
+                       trace.light = trace.lights[ i ];
+                       
+                       /* style check */
+                       for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+                       {
+                               if( lm->styles[ lightmapNum ] == trace.light->style ||
+                                       lm->styles[ lightmapNum ] == LS_NONE )
+                                       break;
+                       }
+                       
+                       /* max of MAX_LIGHTMAPS (4) styles allowed to hit a surface/lightmap */
+                       if( lightmapNum >= MAX_LIGHTMAPS )
+                       {
+                               Sys_Printf( "WARNING: Hit per-surface style limit (%d)\n", MAX_LIGHTMAPS );
+                               continue;
+                       }
+                       
+                       /* setup */
+                       memset( lightLuxels, 0, llSize );
+                       totalLighted = 0;
+                       
+                       /* initial pass, one sample per luxel */
+                       for( y = 0; y < lm->sh; y++ )
+                       {
+                               for( x = 0; x < lm->sw; x++ )
+                               {
+                                       /* get cluster */
+                                       cluster = SUPER_CLUSTER( x, y );
+                                       if( *cluster < 0 )
+                                               continue;
+                                       
+                                       /* get particulars */
+                                       lightLuxel = LIGHT_LUXEL( x, y );
+                                       deluxel = SUPER_DELUXEL( x, y );
+                                       origin = SUPER_ORIGIN( x, y );
+                                       normal = SUPER_NORMAL( x, y );
+                                       
+                                       /* set contribution count */
+                                       lightLuxel[ 3 ] = 1.0f;
+                                       
+                                       /* setup trace */
+                                       trace.cluster = *cluster;
+                                       VectorCopy( origin, trace.origin );
+                                       VectorCopy( normal, trace.normal );
+                                       
+                                       /* get light for this sample */
+                                       LightContributionToSample( &trace );
+                                       VectorCopy( trace.color, lightLuxel );
+                                       
+                                       /* add to count */
+                                       if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
+                                               totalLighted++;
+                                       
+                                       /* add to light direction map (fixme: use luxel normal as starting point for deluxel?) */
+                                       if( deluxemap )
+                                       {
+                                               /* color to grayscale (photoshop rgb weighting) */
+                                               brightness = trace.color[ 0 ] * 0.3f + trace.color[ 1 ] * 0.59f + trace.color[ 2 ] * 0.11f;
+                                               brightness *= (1.0 / 255.0);
+                                               VectorScale( trace.direction, brightness, trace.direction );
+                                               VectorAdd( deluxel, trace.direction, deluxel );
+                                       }
+                               }
+                       }
+                       
+                       /* don't even bother with everything else if nothing was lit */
+                       if( totalLighted == 0 )
+                               continue;
+                       
+                       /* determine filter radius */
+                       filterRadius = lm->filterRadius > trace.light->filterRadius
+                               ? lm->filterRadius
+                               : trace.light->filterRadius;
+                       if( filterRadius < 0.0f )
+                               filterRadius = 0.0f;
+                       
+                       /* set luxel filter radius */
+                       luxelFilterRadius = superSample * filterRadius / lm->sampleSize;
+                       if( luxelFilterRadius == 0 && (filterRadius > 0.0f || filter) )
+                               luxelFilterRadius = 1;
+                       
+                       /* secondary pass, adaptive supersampling (fixme: use a contrast function to determine if subsampling is necessary) */
+                       /* 2003-09-27: changed it so filtering disamples supersampling, as it would waste time */
+                       if( lightSamples > 1 && luxelFilterRadius == 0 )
+                       {
+                               /* walk luxels */
+                               for( y = 0; y < (lm->sh - 1); y++ )
+                               {
+                                       for( x = 0; x < (lm->sw - 1); x++ )
+                                       {
+                                               /* setup */
+                                               mapped = 0;
+                                               lighted = 0;
+                                               VectorClear( total );
+                                               
+                                               /* test 2x2 stamp */
+                                               for( t = 0; t < 4; t++ )
+                                               {
+                                                       /* set sample coords */
+                                                       sx = x + tests[ t ][ 0 ];
+                                                       sy = y + tests[ t ][ 1 ];
+                                                       
+                                                       /* get cluster */
+                                                       cluster = SUPER_CLUSTER( sx, sy );
+                                                       if( *cluster < 0 )
+                                                               continue;
+                                                       mapped++;
+                                                       
+                                                       /* get luxel */
+                                                       lightLuxel = LIGHT_LUXEL( sx, sy );
+                                                       VectorAdd( total, lightLuxel, total );
+                                                       if( (lightLuxel[ 0 ] + lightLuxel[ 1 ] + lightLuxel[ 2 ]) > 0.0f )
+                                                               lighted++;
+                                               }
+                                               
+                                               /* if total color is under a certain amount, then don't bother subsampling */
+                                               if( total[ 0 ] <= 4.0f && total[ 1 ] <= 4.0f && total[ 2 ] <= 4.0f )
+                                                       continue;
+                                               
+                                               /* if all 4 pixels are either in shadow or light, then don't subsample */
+                                               if( lighted != 0 && lighted != mapped )
+                                               {
+                                                       for( t = 0; t < 4; t++ )
+                                                       {
+                                                               /* set sample coords */
+                                                               sx = x + tests[ t ][ 0 ];
+                                                               sy = y + tests[ t ][ 1 ];
+                                                               
+                                                               /* get luxel */
+                                                               cluster = SUPER_CLUSTER( sx, sy );
+                                                               if( *cluster < 0 )
+                                                                       continue;
+                                                               lightLuxel = LIGHT_LUXEL( sx, sy );
+                                                               origin = SUPER_ORIGIN( sx, sy );
+                                                               
+                                                               /* only subsample shadowed luxels */
+                                                               //%     if( (lightLuxel[ 0 ] + lightLuxel[ 1 ] + lightLuxel[ 2 ]) <= 0.0f )
+                                                               //%             continue;
+                                                               
+                                                               /* subsample it */
+                                                               SubsampleRawLuxel_r( lm, &trace, origin, sx, sy, 0.25f, lightLuxel );
+                                                               
+                                                               /* debug code to colorize subsampled areas to yellow */
+                                                               //%     luxel = SUPER_LUXEL( lightmapNum, sx, sy );
+                                                               //%     VectorSet( luxel, 255, 204, 0 );
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       
+                       /* allocate sampling lightmap storage */
+                       if( lm->superLuxels[ lightmapNum ] == NULL )
+                       {
+                               /* allocate sampling lightmap storage */
+                               size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
+                               lm->superLuxels[ lightmapNum ] = safe_malloc( size );
+                               memset( lm->superLuxels[ lightmapNum ], 0, size );
+                       }
+                       
+                       /* set style */
+                       if( lightmapNum > 0 )
+                       {
+                               lm->styles[ lightmapNum ] = trace.light->style;
+                               //%     Sys_Printf( "Surface %6d has lightstyle %d\n", rawLightmapNum, trace.light->style );
+                       }
+                       
+                       /* copy to permanent luxels */
+                       for( y = 0; y < lm->sh; y++ )
+                       {
+                               for( x = 0; x < lm->sw; x++ )
+                               {
+                                       /* get cluster and origin */
+                                       cluster = SUPER_CLUSTER( x, y );
+                                       if( *cluster < 0 )
+                                               continue;
+                                       origin = SUPER_ORIGIN( x, y );
+                                       
+                                       /* filter? */
+                                       if( luxelFilterRadius )
+                                       {
+                                               /* setup */
+                                               VectorClear( averageColor );
+                                               samples = 0.0f;
+                                               
+                                               /* cheaper distance-based filtering */
+                                               for( sy = (y - luxelFilterRadius); sy <= (y + luxelFilterRadius); sy++ )
+                                               {
+                                                       if( sy < 0 || sy >= lm->sh )
+                                                               continue;
+                                                       
+                                                       for( sx = (x - luxelFilterRadius); sx <= (x + luxelFilterRadius); sx++ )
+                                                       {
+                                                               if( sx < 0 || sx >= lm->sw )
+                                                                       continue;
+                                                               
+                                                               /* get particulars */
+                                                               cluster = SUPER_CLUSTER( sx, sy );
+                                                               if( *cluster < 0 )
+                                                                       continue;
+                                                               lightLuxel = LIGHT_LUXEL( sx, sy );
+                                                               
+                                                               /* create weight */
+                                                               weight = (abs( sx - x ) == luxelFilterRadius ? 0.5f : 1.0f);
+                                                               weight *= (abs( sy - y ) == luxelFilterRadius ? 0.5f : 1.0f);
+                                                               
+                                                               /* scale luxel by filter weight */
+                                                               VectorScale( lightLuxel, weight, color );
+                                                               VectorAdd( averageColor, color, averageColor );
+                                                               samples += weight;
+                                                       }
+                                               }
+                                               
+                                               /* any samples? */
+                                               if( samples <= 0.0f     )
+                                                       continue;
+                                               
+                                               /* scale into luxel */
+                                               luxel = SUPER_LUXEL( lightmapNum, x, y );
+                                               luxel[ 3 ] = 1.0f;
+                                               
+                                               /* handle negative light */
+                                               if( trace.light->flags & LIGHT_NEGATIVE )
+                                               { 
+                                                       luxel[ 0 ] -= averageColor[ 0 ] / samples;
+                                                       luxel[ 1 ] -= averageColor[ 1 ] / samples;
+                                                       luxel[ 2 ] -= averageColor[ 2 ] / samples;
+                                               }
+                                               
+                                               /* handle normal light */
+                                               else
+                                               { 
+                                                       luxel[ 0 ] += averageColor[ 0 ] / samples;
+                                                       luxel[ 1 ] += averageColor[ 1 ] / samples;
+                                                       luxel[ 2 ] += averageColor[ 2 ] / samples;
+                                               }
+                                       }
+                                       
+                                       /* single sample */
+                                       else
+                                       {
+                                               /* get particulars */
+                                               lightLuxel = LIGHT_LUXEL( x, y );
+                                               luxel = SUPER_LUXEL( lightmapNum, x, y );
+                                               
+                                               /* handle negative light */
+                                               if( trace.light->flags & LIGHT_NEGATIVE )
+                                                       VectorScale( averageColor, -1.0f, averageColor );
+
+                                               /* add color */
+                                               luxel[ 3 ] = 1.0f;
+                                               
+                                               /* handle negative light */
+                                               if( trace.light->flags & LIGHT_NEGATIVE )
+                                                       VectorSubtract( luxel, lightLuxel, luxel );
+                                               
+                                               /* handle normal light */
+                                               else
+                                                       VectorAdd( luxel, lightLuxel, luxel );
+                                       }
+                               }
+                       }
+               }
+               
+               /* free temporary luxels */
+               free( lightLuxels );
+       }
+       
+       /* free light list */
+       FreeTraceLights( &trace );
+       
+       /* -----------------------------------------------------------------
+          filter pass
+          ----------------------------------------------------------------- */
+       
+       /* walk lightmaps */
+       for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+       {
+               /* early out */
+               if( lm->superLuxels[ lightmapNum ] == NULL )
+                       continue;
+               
+               /* average occluded luxels from neighbors */
+               for( y = 0; y < lm->sh; y++ )
+               {
+                       for( x = 0; x < lm->sw; x++ )
+                       {
+                               /* get particulars */
+                               cluster = SUPER_CLUSTER( x, y );
+                               luxel = SUPER_LUXEL( lightmapNum, x, y );
+                               deluxel = SUPER_DELUXEL( x, y );
+                               normal = SUPER_NORMAL( x, y );
+                               
+                               /* determine if filtering is necessary */
+                               filterColor = qfalse;
+                               filterDir = qfalse;
+                               if( *cluster < 0 ||
+                                       (lm->splotchFix && (luxel[ 0 ] <= ambientColor[ 0 ] || luxel[ 1 ] <= ambientColor[ 1 ] || luxel[ 2 ] <= ambientColor[ 2 ])) )
+                                       filterColor = qtrue;
+                               if( deluxemap && lightmapNum == 0 && (*cluster < 0 || filter) )
+                                       filterDir = qtrue;
+                               
+                               if( !filterColor && !filterDir )
+                                       continue;
+                               
+                               /* choose seed amount */
+                               VectorClear( averageColor );
+                               VectorClear( averageDir );
+                               samples = 0;
+                               
+                               /* walk 3x3 matrix */
+                               for( sy = (y - 1); sy <= (y + 1); sy++ )
+                               {
+                                       if( sy < 0 || sy >= lm->sh )
+                                               continue;
+                                       
+                                       for( sx = (x - 1); sx <= (x + 1); sx++ )
+                                       {
+                                               if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
+                                                       continue;
+                                               
+                                               /* get neighbor's particulars */
+                                               cluster2 = SUPER_CLUSTER( sx, sy );
+                                               luxel2 = SUPER_LUXEL( lightmapNum, sx, sy );
+                                               deluxel2 = SUPER_DELUXEL( sx, sy );
+                                               
+                                               /* ignore unmapped/unlit luxels */
+                                               if( *cluster2 < 0 || luxel2[ 3 ] == 0.0f ||
+                                                       (lm->splotchFix && VectorCompare( luxel2, ambientColor )) )
+                                                       continue;
+                                               
+                                               /* add its distinctiveness to our own */
+                                               VectorAdd( averageColor, luxel2, averageColor );
+                                               samples += luxel2[ 3 ];
+                                               if( filterDir )
+                                                       VectorAdd( averageDir, deluxel2, averageDir );
+                                       }
+                               }
+                               
+                               /* fall through */
+                               if( samples == 0.0f )
+                                       continue;
+                               
+                               /* average it */
+                               if( filterColor )
+                               {
+                                       VectorDivide( averageColor, samples, luxel );
+                                       luxel[ 3 ] = 1.0f;
+                               }
+                               if( filterDir )
+                                       VectorDivide( averageDir, samples, deluxel );
+                               
+                               /* set cluster to -3 */
+                               if( *cluster < 0 )
+                                       *cluster = CLUSTER_FLOODED;
+                       }
+               }
+       }
+}
+
+
+
+/*
+IlluminateVertexes()
+light the surface vertexes
+*/
+
+#define VERTEX_NUDGE   2.0f
+
+void IlluminateVertexes( int num )
+{
+       int                                     i, x, y, z, x1, y1, z1, sx, sy, radius, maxRadius, *cluster;
+       int                                     lightmapNum;
+       float                           samples, *vertLuxel, *radVertLuxel, *luxel;
+       vec3_t                          origin, temp, temp2, colors[ MAX_LIGHTMAPS ];
+       bspDrawSurface_t        *ds;
+       surfaceInfo_t           *info;
+       rawLightmap_t           *lm;
+       bspDrawVert_t           *verts;
+       trace_t                         trace;
+       
+       
+       /* der... */
+       if( noVertexLighting )
+               return;
+       
+       /* get surface, info, and raw lightmap */
+       ds = &bspDrawSurfaces[ num ];
+       info = &surfaceInfos[ num ];
+       lm = info->lm;
+       
+       /* -----------------------------------------------------------------
+          illuminate the vertexes
+          ----------------------------------------------------------------- */
+       
+       /* calculate vertex lighting for surfaces without lightmaps */
+       if( lm == NULL )
+       {
+               /* setup trace */
+               trace.testOcclusion = !noTrace;
+               trace.forceSunlight = info->si->forceSunlight;
+               trace.recvShadows = info->recvShadows;
+               trace.numSurfaces = 1;
+               trace.surfaces = &num;
+               trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
+               
+               /* twosided lighting */
+               trace.twoSided = info->si->twoSided;
+               
+               /* make light list for this surface */
+               CreateTraceLightsForSurface( num, &trace );
+               
+               /* walk the surface verts */
+               verts = yDrawVerts + ds->firstVert;
+               for( i = 0; i < ds->numVerts; i++ )
+               {
+                       /* get vertex luxel */
+                       radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
+                       
+                       /* color the luxel with raw lightmap num? */
+                       if( debugSurfaces )
+                               VectorCopy( debugColors[ num % 12 ], radVertLuxel );
+                       
+                       /* color the luxel with luxel origin? */
+                       else if( debugOrigin )
+                       {
+                               VectorSubtract( info->maxs, info->mins, temp );
+                               VectorScale( temp, (1.0f / 255.0f), temp );
+                               VectorSubtract( origin, lm->mins, temp2 );
+                               radVertLuxel[ 0 ] = info->mins[ 0 ] + (temp[ 0 ] * temp2[ 0 ]);
+                               radVertLuxel[ 1 ] = info->mins[ 1 ] + (temp[ 1 ] * temp2[ 1 ]);
+                               radVertLuxel[ 2 ] = info->mins[ 2 ] + (temp[ 2 ] * temp2[ 2 ]);
+                       }
+                       
+                       /* color the luxel with the normal */
+                       else if( normalmap )
+                       {
+                               radVertLuxel[ 0 ] = (verts[ i ].normal[ 0 ] + 1.0f) * 127.5f;
+                               radVertLuxel[ 1 ] = (verts[ i ].normal[ 1 ] + 1.0f) * 127.5f;
+                               radVertLuxel[ 2 ] = (verts[ i ].normal[ 2 ] + 1.0f) * 127.5f;
+                       }
+                       
+                       /* illuminate the vertex */
+                       else
+                       {
+                               /* clear vertex luxel */
+                               VectorCopy( ambientColor, radVertLuxel );
+                               
+                               /* try at initial origin */
+                               trace.cluster = ClusterForPointExtFilter( verts[ i ].xyz, VERTEX_EPSILON, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ] );
+                               if( trace.cluster >= 0 )
+                               {
+                                       /* setup trace */
+                                       VectorCopy( verts[ i ].xyz, trace.origin );
+                                       VectorCopy( verts[ i ].normal, trace.normal );
+                                       
+                                       /* trace */
+                                       LightingAtSample( &trace, ds->vertexStyles, colors );
+                                       
+                                       /* store */
+                                       for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+                                       {
+                                               radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
+                                               VectorCopy( colors[ lightmapNum ], radVertLuxel );
+                                       }
+                               }
+                               
+                               /* is this sample bright enough? */
+                               if( radVertLuxel[ 0 ] <= ambientColor[ 0 ] &&
+                                       radVertLuxel[ 1 ] <= ambientColor[ 1 ] &&
+                                       radVertLuxel[ 2 ] <= ambientColor[ 2 ] )
+                               {
+                                       /* nudge the sample point around a bit */
+                                       for( x = 0; x < 4; x++ )
+                                       {
+                                               /* two's complement 0, 1, -1, 2, -2, etc */
+                                               x1 = ((x >> 1) ^ (x & 1 ? -1 : 0)) + (x & 1);
+                                               
+                                               for( y = 0; y < 4; y++ )
+                                               {
+                                                       y1 = ((y >> 1) ^ (y & 1 ? -1 : 0)) + (y & 1);
+                                                       
+                                                       for( z = 0; z < 4; z++ )
+                                                       {
+                                                               z1 = ((z >> 1) ^ (z & 1 ? -1 : 0)) + (z & 1);
+                                                               
+                                                               /* nudge origin */
+                                                               trace.origin[ 0 ] = verts[ i ].xyz[ 0 ] + (VERTEX_NUDGE * x1);
+                                                               trace.origin[ 1 ] = verts[ i ].xyz[ 1 ] + (VERTEX_NUDGE * y1);
+                                                               trace.origin[ 2 ] = verts[ i ].xyz[ 2 ] + (VERTEX_NUDGE * z1);
+                                                               
+                                                               /* try at nudged origin */
+                                                               trace.cluster = ClusterForPointExtFilter( origin, VERTEX_EPSILON, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ] );
+                                                               if( trace.cluster < 0 )
+                                                                       continue;
+                                                                                                                       
+                                                               /* trace */
+                                                               LightingAtSample( &trace, ds->vertexStyles, colors );
+                                                               
+                                                               /* store */
+                                                               for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+                                                               {
+                                                                       radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
+                                                                       VectorCopy( colors[ lightmapNum ], radVertLuxel );
+                                                               }
+                                                               
+                                                               /* bright enough? */
+                                                               radVertLuxel = RAD_VERTEX_LUXEL( 0, ds->firstVert + i );
+                                                               if( radVertLuxel[ 0 ] > ambientColor[ 0 ] ||
+                                                                       radVertLuxel[ 1 ] > ambientColor[ 1 ] ||
+                                                                       radVertLuxel[ 2 ] > ambientColor[ 2 ] )
+                                                                       x = y = z = 1000;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       
+                       /* another happy customer */
+                       numVertsIlluminated++;
+                       
+                       /* store it */
+                       for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+                       {
+                               /* get luxels */
+                               vertLuxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
+                               radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
+                               
+                               /* store */
+                               if( bouncing || bounce == 0 || !bounceOnly )
+                                       VectorAdd( vertLuxel, radVertLuxel, vertLuxel );
+                               ColorToBytes( vertLuxel, verts[ i ].color[ lightmapNum ], info->si->vertexScale );
+                       }
+               }
+               
+               /* free light list */
+               FreeTraceLights( &trace );
+               
+               /* return to sender */
+               return;
+       }
+       
+       /* -----------------------------------------------------------------
+          reconstitute vertex lighting from the luxels
+          ----------------------------------------------------------------- */
+       
+       /* set styles from lightmap */
+       for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+               ds->vertexStyles[ lightmapNum ] = lm->styles[ lightmapNum ];
+       
+       /* get max search radius */
+       maxRadius = lm->sw;
+       maxRadius = maxRadius > lm->sh ? maxRadius : lm->sh;
+       
+       /* walk the surface verts */
+       verts = yDrawVerts + ds->firstVert;
+       for( i = 0; i < ds->numVerts; i++ )
+       {
+               /* do each lightmap */
+               for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+               {
+                       /* early out */
+                       if( lm->superLuxels[ lightmapNum ] == NULL )
+                               continue;
+                       
+                       /* get luxel coords */
+                       x = verts[ i ].lightmap[ lightmapNum ][ 0 ];
+                       y = verts[ i ].lightmap[ lightmapNum ][ 1 ];
+                       if( x < 0 )
+                               x = 0;
+                       else if( x >= lm->sw )
+                               x = lm->sw - 1;
+                       if( y < 0 )
+                               y = 0;
+                       else if( y >= lm->sh )
+                               y = lm->sh - 1;
+                       
+                       /* get vertex luxels */
+                       vertLuxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
+                       radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i );
+                       
+                       /* color the luxel with the normal? */
+                       if( normalmap )
+                       {
+                               radVertLuxel[ 0 ] = (verts[ i ].normal[ 0 ] + 1.0f) * 127.5f;
+                               radVertLuxel[ 1 ] = (verts[ i ].normal[ 1 ] + 1.0f) * 127.5f;
+                               radVertLuxel[ 2 ] = (verts[ i ].normal[ 2 ] + 1.0f) * 127.5f;
+                       }
+                       
+                       /* color the luxel with surface num? */
+                       else if( debugSurfaces )
+                               VectorCopy( debugColors[ num % 12 ], radVertLuxel );
+                       
+                       /* divine color from the superluxels */
+                       else
+                       {
+                               /* increasing radius */
+                               VectorClear( radVertLuxel );
+                               samples = 0.0f;
+                               for( radius = 0; radius < maxRadius && samples <= 0.0f; radius++ )
+                               {
+                                       /* sample within radius */
+                                       for( sy = (y - radius); sy <= (y + radius); sy++ )
+                                       {
+                                               if( sy < 0 || sy >= lm->sh )
+                                                       continue;
+                                               
+                                               for( sx = (x - radius); sx <= (x + radius); sx++ )
+                                               {
+                                                       if( sx < 0 || sx >= lm->sw )
+                                                               continue;
+                                                       
+                                                       /* get luxel particulars */
+                                                       luxel = SUPER_LUXEL( lightmapNum, sx, sy );
+                                                       cluster = SUPER_CLUSTER( sx, sy );
+                                                       if( *cluster < 0 )
+                                                               continue;
+                                                       
+                                                       /* testing: must be brigher than ambient color */
+                                                       //%     if( luxel[ 0 ] <= ambientColor[ 0 ] || luxel[ 1 ] <= ambientColor[ 1 ] || luxel[ 2 ] <= ambientColor[ 2 ] )
+                                                       //%             continue;
+                                                       
+                                                       /* add its distinctiveness to our own */
+                                                       VectorAdd( radVertLuxel, luxel, radVertLuxel );
+                                                       samples += luxel[ 3 ];
+                                               }
+                                       }
+                               }
+                               
+                               /* any color? */
+                               if( samples > 0.0f )
+                                       VectorDivide( radVertLuxel, samples, radVertLuxel );
+                               else
+                                       VectorCopy( ambientColor, radVertLuxel );
+                       }
+                       
+                       /* store into floating point storage */
+                       VectorAdd( vertLuxel, radVertLuxel, vertLuxel );
+                       numVertsIlluminated++;
+                       
+                       /* store into bytes (for vertex approximation) */
+                       ColorToBytes( vertLuxel, verts[ i ].color[ lightmapNum ], 1.0f );
+               }
+       }
+}
+
+
+
+/* -------------------------------------------------------------------------------
+
+light optimization (-fast)
+
+creates a list of lights that will affect a surface and stores it in tw
+this is to optimize surface lighting by culling out as many of the
+lights in the world as possible from further calculation
+
+------------------------------------------------------------------------------- */
+
+/*
+SetupBrushes()
+determines opaque brushes in the world and find sky shaders for sunlight calculations
+*/
+
+void SetupBrushes( void )
+{
+       int                             i, j, b, compileFlags;
+       qboolean                inside;
+       bspBrush_t              *brush;
+       bspBrushSide_t  *side;
+       bspShader_t             *shader;
+       shaderInfo_t    *si;
+       
+       
+       /* note it */
+       Sys_FPrintf( SYS_VRB, "--- SetupBrushes ---\n" );
+       
+       /* allocate */
+       if( opaqueBrushes == NULL )
+               opaqueBrushes = safe_malloc( numBSPBrushes / 8 + 1 );
+       
+       /* clear */
+       memset( opaqueBrushes, 0, numBSPBrushes / 8 + 1 );
+       numOpaqueBrushes = 0;
+       
+       /* walk the list of worldspawn brushes */
+       for( i = 0; i < bspModels[ 0 ].numBSPBrushes; i++ )
+       {
+               /* get brush */
+               b = bspModels[ 0 ].firstBSPBrush + i;
+               brush = &bspBrushes[ b ];
+               
+               /* check all sides */
+               inside = qtrue;
+               compileFlags = 0;
+               for( j = 0; j < brush->numSides && inside; j++ )
+               {
+                       /* do bsp shader calculations */
+                       side = &bspBrushSides[ brush->firstSide + j ];
+                       shader = &bspShaders[ side->shaderNum ];
+                       
+                       /* get shader info */
+                       si = ShaderInfoForShader( shader->shader );
+                       if( si == NULL )
+                               continue;
+                       
+                       /* or together compile flags */
+                       compileFlags |= si->compileFlags;
+               }
+               
+               /* determine if this brush is opaque to light */
+               if( !(compileFlags & C_TRANSLUCENT) )
+               {
+                       opaqueBrushes[ b >> 3 ] |= (1 << (b & 7));
+                       numOpaqueBrushes++;
+                       maxOpaqueBrush = i;
+               }
+       }
+       
+       /* emit some statistics */
+       Sys_FPrintf( SYS_VRB, "%9d opaque brushes\n", numOpaqueBrushes );
+}
+
+
+
+/*
+ClusterVisible()
+determines if two clusters are visible to each other using the PVS
+*/
+
+qboolean ClusterVisible( int a, int b )
+{
+       int                     portalClusters, leafBytes;
+       byte            *pvs;
+       
+       
+       /* dummy check */
+       if( a < 0 || b < 0 )
+               return qfalse;
+       
+       /* early out */
+       if( a == b )
+               return qtrue;
+       
+       /* not vised? */
+       if( numBSPVisBytes <=8 )
+               return qtrue;
+       
+       /* get pvs data */
+       portalClusters = ((int *) bspVisBytes)[ 0 ];
+       leafBytes = ((int*) bspVisBytes)[ 1 ];
+       pvs = bspVisBytes + VIS_HEADER_SIZE + (a * leafBytes);
+       
+       /* check */
+       if( (pvs[ b >> 3 ] & (1 << (b & 7))) )
+               return qtrue;
+       return qfalse;
+}
+
+
+
+/*
+PointInLeafNum_r()
+borrowed from vlight.c
+*/
+
+int    PointInLeafNum_r( vec3_t point, int nodenum )
+{
+       int                     leafnum;
+       vec_t           dist;
+       bspNode_t               *node;
+       bspPlane_t      *plane;
+       
+       
+       while( nodenum >= 0 )
+       {
+               node = &bspNodes[ nodenum ];
+               plane = &bspPlanes[ node->planeNum ];
+               dist = DotProduct( point, plane->normal ) - plane->dist;
+               if( dist > 0.1 )
+                       nodenum = node->children[ 0 ];
+               else if( dist < -0.1 )
+                       nodenum = node->children[ 1 ];
+               else
+               {
+                       leafnum = PointInLeafNum_r( point, node->children[ 0 ] );
+                       if( bspLeafs[ leafnum ].cluster != -1 )
+                               return leafnum;
+                       nodenum = node->children[ 1 ];
+               }
+       }
+       
+       leafnum = -nodenum - 1;
+       return leafnum;
+}
+
+
+
+/*
+PointInLeafnum()
+borrowed from vlight.c
+*/
+
+int    PointInLeafNum( vec3_t point )
+{
+       return PointInLeafNum_r( point, 0 );
+}
+
+
+
+/*
+ClusterVisibleToPoint() - ydnar
+returns qtrue if point can "see" cluster
+*/
+
+qboolean ClusterVisibleToPoint( vec3_t point, int cluster )
+{
+       int             pointCluster;
+       
+
+       /* get leafNum for point */
+       pointCluster = ClusterForPoint( point );
+       if( pointCluster < 0 )
+               return qfalse;
+       
+       /* check pvs */
+       return ClusterVisible( pointCluster, cluster );
+}
+
+
+
+/*
+ClusterForPoint() - ydnar
+returns the pvs cluster for point
+*/
+
+int ClusterForPoint( vec3_t point )
+{
+       int             leafNum;
+       
+
+       /* get leafNum for point */
+       leafNum = PointInLeafNum( point );
+       if( leafNum < 0 )
+               return -1;
+       
+       /* return the cluster */
+       return bspLeafs[ leafNum ].cluster;
+}
+
+
+
+/*
+ClusterForPointExt() - ydnar
+also takes brushes into account for occlusion testing
+*/
+
+int ClusterForPointExt( vec3_t point, float epsilon )
+{
+       int                             i, j, b, leafNum, cluster;
+       float                   dot;
+       qboolean                inside;
+       int                             *brushes, numBSPBrushes;
+       bspLeaf_t               *leaf;
+       bspBrush_t              *brush;
+       bspPlane_t              *plane;
+       
+       
+       /* get leaf for point */
+       leafNum = PointInLeafNum( point );
+       if( leafNum < 0 )
+               return -1;
+       leaf = &bspLeafs[ leafNum ];
+       
+       /* get the cluster */
+       cluster = leaf->cluster;
+       if( cluster < 0 )
+               return -1;
+       
+       /* transparent leaf, so check point against all brushes in the leaf */
+       brushes = &bspLeafBrushes[ leaf->firstBSPLeafBrush ];
+       numBSPBrushes = leaf->numBSPLeafBrushes;
+       for( i = 0; i < numBSPBrushes; i++ )
+       {
+               /* get parts */
+               b = brushes[ i ];
+               if( b > maxOpaqueBrush )
+                       continue;
+               brush = &bspBrushes[ b ];
+               if( !(opaqueBrushes[ b >> 3 ] & (1 << (b & 7))) )
+                       continue;
+               
+               /* check point against all planes */
+               inside = qtrue;
+               for( j = 0; j < brush->numSides && inside; j++ )
+               {
+                       plane = &bspPlanes[ bspBrushSides[ brush->firstSide + j ].planeNum ];
+                       dot = DotProduct( point, plane->normal );
+                       dot -= plane->dist;
+                       if( dot > epsilon )
+                               inside = qfalse;
+               }
+               
+               /* if inside, return bogus cluster */
+               if( inside )
+                       return -1 - b;
+       }
+       
+       /* if the point made it this far, it's not inside any opaque brushes */
+       return cluster;
+}
+
+
+
+/*
+ClusterForPointExtFilter() - ydnar
+adds cluster checking against a list of known valid clusters
+*/
+
+int ClusterForPointExtFilter( vec3_t point, float epsilon, int numClusters, int *clusters )
+{
+       int             i, cluster;
+       
+       
+       /* get cluster for point */
+       cluster = ClusterForPointExt( point, epsilon );
+       
+       /* check if filtering is necessary */
+       if( cluster < 0 || numClusters <= 0 || clusters == NULL )
+               return cluster;
+       
+       /* filter */
+       for( i = 0; i < numClusters; i++ )
+       {
+               if( cluster == clusters[ i ] || ClusterVisible( cluster, clusters[ i ] ) )
+                       return cluster;
+       }
+       
+       /* failed */
+       return -1;
+}
+
+
+
+/*
+ShaderForPointInLeaf() - ydnar
+checks a point against all brushes in a leaf, returning the shader of the brush
+also sets the cumulative surface and content flags for the brush hit
+*/
+
+int ShaderForPointInLeaf( vec3_t point, int leafNum, float epsilon, int wantContentFlags, int wantSurfaceFlags, int *contentFlags, int *surfaceFlags )
+{
+       int                             i, j;
+       float                   dot;
+       qboolean                inside;
+       int                             *brushes, numBSPBrushes;
+       bspLeaf_t                       *leaf;
+       bspBrush_t              *brush;
+       bspBrushSide_t  *side;
+       bspPlane_t              *plane;
+       bspShader_t             *shader;
+       int                             allSurfaceFlags, allContentFlags;
+
+       
+       /* clear things out first */
+       *surfaceFlags = 0;
+       *contentFlags = 0;
+       
+       /* get leaf */
+       if( leafNum < 0 )
+               return -1;
+       leaf = &bspLeafs[ leafNum ];
+       
+       /* transparent leaf, so check point against all brushes in the leaf */
+       brushes = &bspLeafBrushes[ leaf->firstBSPLeafBrush ];
+       numBSPBrushes = leaf->numBSPLeafBrushes;
+       for( i = 0; i < numBSPBrushes; i++ )
+       {
+               /* get parts */
+               brush = &bspBrushes[ brushes[ i ] ];
+               
+               /* check point against all planes */
+               inside = qtrue;
+               allSurfaceFlags = 0;
+               allContentFlags = 0;
+               for( j = 0; j < brush->numSides && inside; j++ )
+               {
+                       side = &bspBrushSides[ brush->firstSide + j ];
+                       plane = &bspPlanes[ side->planeNum ];
+                       dot = DotProduct( point, plane->normal );
+                       dot -= plane->dist;
+                       if( dot > epsilon )
+                               inside = qfalse;
+                       else
+                       {
+                               shader = &bspShaders[ side->shaderNum ];
+                               allSurfaceFlags |= shader->surfaceFlags;
+                               allContentFlags |= shader->contentFlags;
+                       }
+               }
+               
+               /* handle if inside */
+               if( inside )
+               {
+                       /* if there are desired flags, check for same and continue if they aren't matched */
+                       if( wantContentFlags && !(wantContentFlags & allContentFlags) )
+                               continue;
+                       if( wantSurfaceFlags && !(wantSurfaceFlags & allSurfaceFlags) )
+                               continue;
+                       
+                       /* store the cumulative flags and return the brush shader (which is mostly useless) */
+                       *surfaceFlags = allSurfaceFlags;
+                       *contentFlags = allContentFlags;
+                       return brush->shaderNum;
+               }
+       }
+       
+       /* if the point made it this far, it's not inside any brushes */
+       return -1;
+}
+
+
+
+/*
+ChopBounds()
+chops a bounding box by the plane defined by origin and normal
+returns qfalse if the bounds is entirely clipped away
+
+this is not exactly the fastest way to do this...
+*/
+
+qboolean ChopBounds( vec3_t mins, vec3_t maxs, vec3_t origin, vec3_t normal )
+{
+       /* FIXME: rewrite this so it doesn't use bloody brushes */
+       return qtrue;
+}
+
+
+
+/*
+SetupEnvelopes()
+calculates each light's effective envelope,
+taking into account brightness, type, and pvs.
+*/
+
+#define LIGHT_EPSILON  0.125f
+#define LIGHT_NUDGE            2.0f
+
+void SetupEnvelopes( qboolean forGrid, qboolean fastFlag )
+{
+       int                     i, x, y, z, x1, y1, z1;
+       light_t         *light, *light2, **owner;
+       bspLeaf_t       *leaf;
+       vec3_t          origin, dir, mins, maxs, nullVector = { 0, 0, 0 };
+       float           radius, intensity;
+       light_t         *buckets[ 256 ];
+       
+       
+       /* early out for weird cases where there are no lights */
+       if( lights == NULL )
+               return;
+       
+       /* note it */
+       Sys_FPrintf( SYS_VRB, "--- SetupEnvelopes%s ---\n", fastFlag ? " (fast)" : "" );
+       
+       /* count lights */
+       numLights = 0;
+       numCulledLights = 0;
+       owner = &lights;
+       while( *owner != NULL )
+       {
+               /* get light */
+               light = *owner;
+               
+               /* handle negative lights */
+               if( light->photons < 0.0f || light->add < 0.0f )
+               {
+                       light->photons *= -1.0f;
+                       light->add *= -1.0f;
+                       light->flags |= LIGHT_NEGATIVE;
+               }
+               
+               /* sunlight? */
+               if( light->type == EMIT_SUN )
+               {
+                       /* special cased */
+                       light->cluster = 0;
+                       light->envelope = MAX_WORLD_COORD * 8.0f;
+                       VectorSet( light->mins, MIN_WORLD_COORD * 8.0f, MIN_WORLD_COORD * 8.0f, MIN_WORLD_COORD * 8.0f );
+                       VectorSet( light->maxs, MAX_WORLD_COORD * 8.0f, MAX_WORLD_COORD * 8.0f, MAX_WORLD_COORD * 8.0f );
+               }
+               
+               /* everything else */
+               else
+               {
+                       /* get pvs cluster for light */
+                       light->cluster = ClusterForPointExt( light->origin, LIGHT_EPSILON );
+                       
+                       /* invalid cluster? */
+                       if( light->cluster < 0 )
+                       {
+                               /* nudge the sample point around a bit */
+                               for( x = 0; x < 4; x++ )
+                               {
+                                       /* two's complement 0, 1, -1, 2, -2, etc */
+                                       x1 = ((x >> 1) ^ (x & 1 ? -1 : 0)) + (x & 1);
+                                       
+                                       for( y = 0; y < 4; y++ )
+                                       {
+                                               y1 = ((y >> 1) ^ (y & 1 ? -1 : 0)) + (y & 1);
+                                               
+                                               for( z = 0; z < 4; z++ )
+                                               {
+                                                       z1 = ((z >> 1) ^ (z & 1 ? -1 : 0)) + (z & 1);
+                                                       
+                                                       /* nudge origin */
+                                                       origin[ 0 ] = light->origin[ 0 ] + (LIGHT_NUDGE * x1);
+                                                       origin[ 1 ] = light->origin[ 1 ] + (LIGHT_NUDGE * y1);
+                                                       origin[ 2 ] = light->origin[ 2 ] + (LIGHT_NUDGE * z1);
+                                                       
+                                                       /* try at nudged origin */
+                                                       light->cluster = ClusterForPointExt( origin, LIGHT_EPSILON );
+                                                       if( light->cluster < 0 )
+                                                               continue;
+                                                                       
+                                                       /* set origin */
+                                                       VectorCopy( origin, light->origin );
+                                               }
+                                       }
+                               }
+                       }
+                       
+                       /* only calculate for lights in pvs and outside of opaque brushes */
+                       if( light->cluster >= 0 )
+                       {
+                               /* set light fast flag */
+                               if( fastFlag )
+                                       light->flags |= LIGHT_FAST_TEMP;
+                               else
+                                       light->flags &= ~LIGHT_FAST_TEMP;
+                               if( light->si && light->si->noFast )
+                                       light->flags &= ~(LIGHT_FAST | LIGHT_FAST_TEMP);
+                               
+                               /* clear light envelope */
+                               light->envelope = 0;
+                               
+                               /* handle area lights */
+                               if( exactPointToPolygon && light->type == EMIT_AREA && light->w != NULL )
+                               {
+                                       /* ugly hack to calculate extent for area lights, but only done once */
+                                       VectorScale( light->normal, -1.0f, dir );
+                                       for( radius = 100.0f; radius < 130000.0f && light->envelope == 0; radius += 10.0f )
+                                       {
+                                               float   factor;
+                                               
+                                               VectorMA( light->origin, radius, light->normal, origin );
+                                               factor = PointToPolygonFormFactor( origin, dir, light->w );
+                                               if( factor < 0.0f )
+                                                       factor *= -1.0f;
+                                               if( (factor * light->add) <= light->falloffTolerance )
+                                                       light->envelope = radius;
+                                       }
+                                       
+                                       /* check for fast mode */
+                                       if( !(light->flags & LIGHT_FAST) && !(light->flags & LIGHT_FAST_TEMP) )
+                                               light->envelope = MAX_WORLD_COORD * 8.0f;
+                               }
+                               else
+                               {
+                                       radius = 0.0f;
+                                       intensity = light->photons;
+                               }
+                               
+                               /* other calcs */
+                               if( light->envelope <= 0.0f )
+                               {
+                                       /* solve distance for non-distance lights */
+                                       if( !(light->flags & LIGHT_ATTEN_DISTANCE) )
+                                               light->envelope = MAX_WORLD_COORD * 8.0f;
+                                       
+                                       /* solve distance for linear lights */
+                                       else if( (light->flags & LIGHT_ATTEN_LINEAR ) )
+                                               //% light->envelope = ((intensity / light->falloffTolerance) * linearScale - 1 + radius) / light->fade;
+                                               light->envelope = ((intensity * linearScale) - light->falloffTolerance) / light->fade;
+
+                                               /*
+                                               add = angle * light->photons * linearScale - (dist * light->fade);
+                                               T = (light->photons * linearScale) - (dist * light->fade);
+                                               T + (dist * light->fade) = (light->photons * linearScale);
+                                               dist * light->fade = (light->photons * linearScale) - T;
+                                               dist = ((light->photons * linearScale) - T) / light->fade;
+                                               */
+                                       
+                                       /* solve for inverse square falloff */
+                                       else
+                                               light->envelope = sqrt( intensity / light->falloffTolerance ) + radius;
+                                               
+                                               /*
+                                               add = light->photons / (dist * dist);
+                                               T = light->photons / (dist * dist);
+                                               T * (dist * dist) = light->photons;
+                                               dist = sqrt( light->photons / T );
+                                               */
+                               }
+                               
+                               /* chop radius against pvs */
+                               {
+                                       /* clear bounds */
+                                       ClearBounds( mins, maxs );
+                                       
+                                       /* check all leaves */
+                                       for( i = 0; i < numBSPLeafs; i++ )
+                                       {
+                                               /* get test leaf */
+                                               leaf = &bspLeafs[ i ];
+                                               
+                                               /* in pvs? */
+                                               if( leaf->cluster < 0 )
+                                                       continue;
+                                               if( ClusterVisible( light->cluster, leaf->cluster ) == qfalse ) /* ydnar: thanks Arnout for exposing my stupid error (this never failed before) */
+                                                       continue;
+                                               
+                                               /* add this leafs bbox to the bounds */
+                                               VectorCopy( leaf->mins, origin );
+                                               AddPointToBounds( origin, mins, maxs );
+                                               VectorCopy( leaf->maxs, origin );
+                                               AddPointToBounds( origin, mins, maxs );
+                                       }
+                                       
+                                       /* test to see if bounds encompass light */
+                                       for( i = 0; i < 3; i++ )
+                                       {
+                                               if( mins[ i ] > light->origin[ i ] || maxs[ i ] < light->origin[ i ] )
+                                               {
+                                                       //% Sys_Printf( "WARNING: Light PVS bounds (%.0f, %.0f, %.0f) -> (%.0f, %.0f, %.0f)\ndo not encompass light %d (%f, %f, %f)\n",
+                                                       //%     mins[ 0 ], mins[ 1 ], mins[ 2 ],
+                                                       //%     maxs[ 0 ], maxs[ 1 ], maxs[ 2 ],
+                                                       //%     numLights, light->origin[ 0 ], light->origin[ 1 ], light->origin[ 2 ] );
+                                                       AddPointToBounds( light->origin, mins, maxs );
+                                               }
+                                       }
+                                       
+                                       /* chop the bounds by a plane for area lights and spotlights */
+                                       if( light->type == EMIT_AREA || light->type == EMIT_SPOT )
+                                               ChopBounds( mins, maxs, light->origin, light->normal );
+                                       
+                                       /* copy bounds */
+                                       VectorCopy( mins, light->mins );
+                                       VectorCopy( maxs, light->maxs );
+                                       
+                                       /* reflect bounds around light origin */
+                                       //%     VectorMA( light->origin, -1.0f, origin, origin );
+                                       VectorScale( light->origin, 2, origin );
+                                       VectorSubtract( origin, maxs, origin );
+                                       AddPointToBounds( origin, mins, maxs );
+                                       //%     VectorMA( light->origin, -1.0f, mins, origin );
+                                       VectorScale( light->origin, 2, origin );
+                                       VectorSubtract( origin, mins, origin );
+                                       AddPointToBounds( origin, mins, maxs );
+                                        
+                                       /* calculate spherical bounds */
+                                       VectorSubtract( maxs, light->origin, dir );
+                                       radius = (float) VectorLength( dir );
+                                       
+                                       /* if this radius is smaller than the envelope, then set the envelope to it */
+                                       if( radius < light->envelope )
+                                       {
+                                               light->envelope = radius;
+                                               //%     Sys_FPrintf( SYS_VRB, "PVS Cull (%d): culled\n", numLights );
+                                       }
+                                       //%     else
+                                       //%             Sys_FPrintf( SYS_VRB, "PVS Cull (%d): failed (%8.0f > %8.0f)\n", numLights, radius, light->envelope );
+                               }
+                               
+                               /* add grid/surface only check */
+                               if( forGrid )
+                               {
+                                       if( !(light->flags & LIGHT_GRID) )
+                                               light->envelope = 0.0f;
+                               }
+                               else
+                               {
+                                       if( !(light->flags & LIGHT_SURFACES) )
+                                               light->envelope = 0.0f;
+                               }
+                       }
+                       
+                       /* culled? */
+                       if( light->cluster < 0 || light->envelope <= 0.0f )
+                       {
+                               /* debug code */
+                               //%     Sys_Printf( "Culling light: Cluster: %d Envelope: %f\n", light->cluster, light->envelope );
+                               
+                               /* delete the light */
+                               numCulledLights++;
+                               *owner = light->next;
+                               if( light->w != NULL )
+                                       free( light->w );
+                               free( light );
+                               continue;
+                       }
+               }
+               
+               /* square envelope */
+               light->envelope2 = (light->envelope * light->envelope);
+               
+               /* increment light count */
+               numLights++;
+               
+               /* set next light */
+               owner = &((**owner).next);
+       }
+       
+       /* bucket sort lights by style */
+       memset( buckets, 0, sizeof( buckets ) );
+       light2 = NULL;
+       for( light = lights; light != NULL; light = light2 )
+       {
+               /* get next light */
+               light2 = light->next;
+               
+               /* filter into correct bucket */
+               light->next = buckets[ light->style ];
+               buckets[ light->style ] = light;
+       }
+       
+       /* filter back into light list */
+       lights = NULL;
+       for( i = 255; i >= 0; i-- )
+       {
+               light2 = NULL;
+               for( light = buckets[ i ]; light != NULL; light = light2 )
+               {
+                       light2 = light->next;
+                       light->next = lights;
+                       lights = light;
+               }
+       }
+       
+       /* emit some statistics */
+       Sys_Printf( "%9d total lights\n", numLights );
+       Sys_Printf( "%9d culled lights\n", numCulledLights );
+}
+
+
+
+/*
+CreateTraceLightsForBounds()
+creates a list of lights that affect the given bounding box and pvs clusters (bsp leaves)
+*/
+
+void CreateTraceLightsForBounds( vec3_t mins, vec3_t maxs, vec3_t normal, int numClusters, int *clusters, int flags, trace_t *trace )
+{
+       int                     i;
+       light_t         *light;
+       vec3_t          origin, dir, nullVector = { 0.0f, 0.0f, 0.0f };
+       float           radius, dist, length;
+       
+       
+       /* potential pre-setup  */
+       if( numLights == 0 )
+               SetupEnvelopes( qfalse, fast );
+       
+       /* debug code */
+       //% Sys_Printf( "CTWLFB: (%4.1f %4.1f %4.1f) (%4.1f %4.1f %4.1f)\n", mins[ 0 ], mins[ 1 ], mins[ 2 ], maxs[ 0 ], maxs[ 1 ], maxs[ 2 ] );
+       
+       /* allocate the light list */
+       trace->lights = safe_malloc( sizeof( light_t* ) * (numLights + 1) );
+       trace->numLights = 0;
+       
+       /* calculate spherical bounds */
+       VectorAdd( mins, maxs, origin );
+       VectorScale( origin, 0.5f, origin );
+       VectorSubtract( maxs, origin, dir );
+       radius = (float) VectorLength( dir );
+       
+       /* get length of normal vector */
+       if( normal != NULL )
+               length = VectorLength( normal );
+       else
+       {
+               normal = nullVector;
+               length = 0;
+       }
+       
+       /* test each light and see if it reaches the sphere */
+       /* note: the attenuation code MUST match LightingAtSample() */
+       for( light = lights; light; light = light->next )
+       {
+               /* check zero sized envelope */
+               if( light->envelope <= 0 )
+               {
+                       lightsEnvelopeCulled++;
+                       continue;
+               }
+               
+               /* check flags */
+               if( !(light->flags & flags) )
+                       continue;
+               
+               /* sunlight skips all this nonsense */
+               if( light->type != EMIT_SUN )
+               {
+                       /* sun only? */
+                       if( sunOnly )
+                               continue;
+                       
+                       /* check against pvs cluster */
+                       if( numClusters > 0 && clusters != NULL )
+                       {
+                               for( i = 0; i < numClusters; i++ )
+                               {
+                                       if( ClusterVisible( light->cluster, clusters[ i ] ) )
+                                               break;
+                               }
+                               
+                               /* fixme! */
+                               if( i == numClusters )
+                               {
+                                       lightsClusterCulled++;
+                                       continue;
+                               }
+                       }
+                       
+                       /* if the light's bounding sphere intersects with the bounding sphere then this light needs to be tested */
+                       VectorSubtract( light->origin, origin, dir );
+                       dist = VectorLength( dir );
+                       dist -= light->envelope;
+                       dist -= radius;
+                       if( dist > 0 )
+                       {
+                               lightsEnvelopeCulled++;
+                               continue;
+                       }
+                       
+                       /* check bounding box against light's pvs envelope (note: this code never eliminated any lights, so disabling it) */
+                       #if 0
+                       skip = qfalse;
+                       for( i = 0; i < 3; i++ )
+                       {
+                               if( mins[ i ] > light->maxs[ i ] || maxs[ i ] < light->mins[ i ] )
+                                       skip = qtrue;
+                       }
+                       if( skip )
+                       {
+                               lightsBoundsCulled++;
+                               continue;
+                       }
+                       #endif
+               }
+               
+               /* planar surfaces (except twosided surfaces) have a couple more checks */
+               if( length > 0.0f && trace->twoSided == qfalse )
+               {
+                       /* lights coplanar with a surface won't light it */
+                       if( !(light->flags & LIGHT_TWOSIDED) && DotProduct( light->normal, normal ) > 0.999f )
+                       {
+                               lightsPlaneCulled++;
+                               continue;
+                       }
+                       
+                       /* check to see if light is behind the plane */
+                       if( DotProduct( light->origin, normal ) - DotProduct( origin, normal ) < -1.0f )
+                       {
+                               lightsPlaneCulled++;
+                               continue;
+                       }
+               }
+               
+               /* add this light */
+               trace->lights[ trace->numLights++ ] = light;
+       }
+       
+       /* make last night null */
+       trace->lights[ trace->numLights ] = NULL;
+}
+
+
+
+void FreeTraceLights( trace_t *trace )
+{
+       if( trace->lights != NULL )
+               free( trace->lights );
+}
+
+
+
+/*
+CreateTraceLightsForSurface()
+creates a list of lights that can potentially affect a drawsurface
+*/
+
+void CreateTraceLightsForSurface( int num, trace_t *trace )
+{
+       int                                     i;
+       vec3_t                          mins, maxs, normal;
+       bspDrawVert_t           *dv;
+       bspDrawSurface_t        *ds;
+       surfaceInfo_t           *info;
+       
+       
+       /* dummy check */
+       if( num < 0 )
+               return;
+       
+       /* get drawsurface and info */
+       ds = &bspDrawSurfaces[ num ];
+       info = &surfaceInfos[ num ];
+       
+       /* get the mins/maxs for the dsurf */
+       ClearBounds( mins, maxs );
+       VectorCopy( bspDrawVerts[ ds->firstVert ].normal, normal );
+       for( i = 0; i < ds->numVerts; i++ )
+       {
+               dv = &yDrawVerts[ ds->firstVert + i ];
+               AddPointToBounds( dv->xyz, mins, maxs );
+               if( !VectorCompare( dv->normal, normal ) )
+                       VectorClear( normal );
+       }
+       
+       /* create the lights for the bounding box */
+       CreateTraceLightsForBounds( mins, maxs, normal, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ], LIGHT_SURFACES, trace );
+}
+
+
+
+
+