]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - tools/quake3/q3map2/lightmaps_ydnar.c
revert "allocate bigger first"
[xonotic/netradiant.git] / tools / quake3 / q3map2 / lightmaps_ydnar.c
index 22b6e376073eb150b045fda3d9b7a42465c2af66..462331f1ad79ebdef34173719157122209db6f18 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 LIGHTMAPS_YDNAR_C\r
-\r
-\r
-\r
-/* dependencies */\r
-#include "q3map2.h"\r
-\r
-\r
-\r
-\r
-/* -------------------------------------------------------------------------------\r
-\r
-this file contains code that doe lightmap allocation and projection that\r
-runs in the -light phase.\r
-\r
-this is handled here rather than in the bsp phase for a few reasons--\r
-surfaces are no longer necessarily convex polygons, patches may or may not be\r
-planar or have lightmaps projected directly onto control points.\r
-\r
-also, this allows lightmaps to be calculated before being allocated and stored\r
-in the bsp. lightmaps that have little high-frequency information are candidates\r
-for having their resolutions scaled down.\r
-\r
-------------------------------------------------------------------------------- */\r
-\r
-/*\r
-WriteTGA24()\r
-based on WriteTGA() from imagelib.c\r
-*/\r
-\r
-void WriteTGA24( char *filename, byte *data, int width, int height, qboolean flip )\r
-{\r
-       int             i, c;\r
-       byte    *buffer, *in;\r
-       FILE    *file;\r
-       \r
-       \r
-       /* allocate a buffer and set it up */\r
-       buffer = safe_malloc( width * height * 3 + 18 );\r
-       memset( buffer, 0, 18 );\r
-       buffer[ 2 ] = 2;\r
-       buffer[ 12 ] = width & 255;\r
-       buffer[ 13 ] = width >> 8;\r
-       buffer[ 14 ] = height & 255;\r
-       buffer[ 15 ] = height >> 8;\r
-       buffer[ 16 ] = 24;\r
-\r
-       /* swap rgb to bgr */\r
-       c = (width * height * 3) + 18;\r
-       for( i = 18; i < c; i += 3 )\r
-       {\r
-               buffer[ i ] = data[ i - 18 + 2 ];               /* blue */\r
-               buffer[ i + 1 ] = data[ i - 18 + 1 ];   /* green */\r
-               buffer[ i + 2 ] = data[ i - 18 + 0 ];   /* red */\r
-       }\r
-       \r
-       /* write it and free the buffer */\r
-       file = fopen( filename, "wb" );\r
-       if( file == NULL )\r
-               Error( "Unable to open %s for writing", filename );\r
-       \r
-       /* flip vertically? */\r
-       if( flip )\r
-       {\r
-               fwrite( buffer, 1, 18, file );\r
-               for( in = buffer + ((height - 1) * width * 3) + 18; in >= buffer; in -= (width * 3) )\r
-                       fwrite( in, 1, (width * 3), file );\r
-       }\r
-       else\r
-               fwrite( buffer, 1, c, file );\r
-       \r
-       /* close the file */\r
-       fclose( file );\r
-       free( buffer );\r
-}\r
-\r
-\r
-\r
-/*\r
-ExportLightmaps()\r
-exports the lightmaps as a list of numbered tga images\r
-*/\r
-\r
-void ExportLightmaps( void )\r
-{\r
-       int                     i;\r
-       char            dirname[ 1024 ], filename[ 1024 ];\r
-       byte            *lightmap;\r
-       \r
-       \r
-       /* note it */\r
-       Sys_FPrintf( SYS_VRB, "--- ExportLightmaps ---\n");\r
-       \r
-       /* do some path mangling */\r
-       strcpy( dirname, source );\r
-       StripExtension( dirname );\r
-       \r
-       /* sanity check */\r
-       if( bspLightBytes == NULL )\r
-       {\r
-               Sys_Printf( "WARNING: No BSP lightmap data\n" );\r
-               return;\r
-       }\r
-       \r
-       /* make a directory for the lightmaps */\r
-       Q_mkdir( dirname );\r
-       \r
-       /* iterate through the lightmaps */\r
-       for( i = 0, lightmap = bspLightBytes; lightmap < (bspLightBytes + numBSPLightBytes); i++, lightmap += (LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 3) )\r
-       {\r
-               /* write a tga image out */\r
-               sprintf( filename, "%s/lightmap_%04d.tga", dirname, i );\r
-               Sys_Printf( "Writing %s\n", filename );\r
-               WriteTGA24( filename, lightmap, LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT, qfalse );\r
-       }\r
-}\r
-\r
-\r
-\r
-/*\r
-ExportLightmapsMain()\r
-exports the lightmaps as a list of numbered tga images\r
-*/\r
-\r
-int ExportLightmapsMain( int argc, char **argv )\r
-{\r
-       /* arg checking */\r
-       if( argc < 1 )\r
-       {\r
-               Sys_Printf( "Usage: q3map -export [-v] <mapname>\n" );\r
-               return 0;\r
-       }\r
-       \r
-       /* do some path mangling */\r
-       strcpy( source, ExpandArg( argv[ argc - 1 ] ) );\r
-       StripExtension( source );\r
-       DefaultExtension( source, ".bsp" );\r
-       \r
-       /* load the bsp */\r
-       Sys_Printf( "Loading %s\n", source );\r
-       LoadBSPFile( source );\r
-       \r
-       /* export the lightmaps */\r
-       ExportLightmaps();\r
-       \r
-       /* return to sender */\r
-       return 0;\r
-}\r
-\r
-\r
-\r
-/*\r
-ImportLightmapsMain()\r
-imports the lightmaps from a list of numbered tga images\r
-*/\r
-\r
-int ImportLightmapsMain( int argc, char **argv )\r
-{\r
-       int                     i, x, y, len, width, height;\r
-       char            dirname[ 1024 ], filename[ 1024 ];\r
-       byte            *lightmap, *buffer, *pixels, *in, *out;\r
-       \r
-       \r
-       /* arg checking */\r
-       if( argc < 1 )\r
-       {\r
-               Sys_Printf( "Usage: q3map -import [-v] <mapname>\n" );\r
-               return 0;\r
-       }\r
-       \r
-       /* do some path mangling */\r
-       strcpy( source, ExpandArg( argv[ argc - 1 ] ) );\r
-       StripExtension( source );\r
-       DefaultExtension( source, ".bsp" );\r
-       \r
-       /* load the bsp */\r
-       Sys_Printf( "Loading %s\n", source );\r
-       LoadBSPFile( source );\r
-       \r
-       /* note it */\r
-       Sys_FPrintf( SYS_VRB, "--- ImportLightmaps ---\n");\r
-       \r
-       /* do some path mangling */\r
-       strcpy( dirname, source );\r
-       StripExtension( dirname );\r
-       \r
-       /* sanity check */\r
-       if( bspLightBytes == NULL )\r
-               Error( "No lightmap data" );\r
-       \r
-       /* make a directory for the lightmaps */\r
-       Q_mkdir( dirname );\r
-       \r
-       /* iterate through the lightmaps */\r
-       for( i = 0, lightmap = bspLightBytes; lightmap < (bspLightBytes + numBSPLightBytes); i++, lightmap += (LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 3) )\r
-       {\r
-               /* read a tga image */\r
-               sprintf( filename, "%s/lightmap_%04d.tga", dirname, i );\r
-               Sys_Printf( "Loading %s\n", filename );\r
-               buffer = NULL;\r
-               len = vfsLoadFile( filename, (void*) &buffer, -1 );\r
-               if( len < 0 )\r
-               {\r
-                       Sys_Printf( "WARNING: Unable to load image %s\n", filename );\r
-                       continue;\r
-               }\r
-               \r
-               /* parse file into an image */\r
-               pixels = NULL;\r
-               LoadTGABuffer( buffer, &pixels, &width, &height );\r
-               free( buffer );\r
-               \r
-               /* sanity check it */\r
-               if( pixels == NULL )\r
-               {\r
-                       Sys_Printf( "WARNING: Unable to load image %s\n", filename );\r
-                       continue;\r
-               }\r
-               if( width != LIGHTMAP_WIDTH || height != LIGHTMAP_HEIGHT )\r
-                       Sys_Printf( "WARNING: Image %s is not the right size (%d, %d) != (%d, %d)\n",\r
-                               filename, width, height, LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT );\r
-               \r
-               /* copy the pixels */\r
-               in = pixels;\r
-               for( y = 1; y <= LIGHTMAP_HEIGHT; y++ )\r
-               {\r
-                       out = lightmap + ((LIGHTMAP_HEIGHT - y) * LIGHTMAP_WIDTH * 3);\r
-                       for( x = 0; x < LIGHTMAP_WIDTH; x++, in += 4, out += 3 )\r
-                               VectorCopy( in, out );\r
-               }\r
-               \r
-               /* free the image */\r
-               free( pixels );\r
-       }\r
-       \r
-       /* write the bsp */\r
-       Sys_Printf( "writing %s\n", source );\r
-       WriteBSPFile( source );\r
-       \r
-       /* return to sender */\r
-       return 0;\r
-}\r
-\r
-\r
-\r
-/* -------------------------------------------------------------------------------\r
-\r
-this section deals with projecting a lightmap onto a raw drawsurface\r
-\r
-------------------------------------------------------------------------------- */\r
-\r
-/*\r
-CompareLightSurface()\r
-compare function for qsort()\r
-*/\r
-\r
-static int CompareLightSurface( const void *a, const void *b )\r
-{\r
-       shaderInfo_t    *asi, *bsi;\r
-       \r
-       \r
-       /* get shaders */\r
-       asi = surfaceInfos[ *((int*) a) ].si;\r
-       bsi = surfaceInfos[ *((int*) b) ].si;\r
-       \r
-       /* dummy check */\r
-       if( asi == NULL )\r
-               return -1;\r
-       if( bsi == NULL )\r
-               return 1;\r
-       \r
-       /* compare shader names */\r
-       return strcmp( asi->shader, bsi->shader );\r
-}\r
-\r
-\r
-\r
-/*\r
-FinishRawLightmap()\r
-allocates a raw lightmap's necessary buffers\r
-*/\r
-\r
-void FinishRawLightmap( rawLightmap_t *lm )\r
-{\r
-       int                                     i, j, c, size, *sc;\r
-       float                           is;\r
-       surfaceInfo_t           *info;\r
-       \r
-       \r
-       /* sort light surfaces by shader name */\r
-       qsort( &lightSurfaces[ lm->firstLightSurface ], lm->numLightSurfaces, sizeof( int ), CompareLightSurface );\r
-       \r
-       /* count clusters */\r
-       lm->numLightClusters = 0;\r
-       for( i = 0; i < lm->numLightSurfaces; i++ )\r
-       {\r
-               /* get surface info */\r
-               info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + i ] ];\r
-               \r
-               /* add surface clusters */\r
-               lm->numLightClusters += info->numSurfaceClusters;\r
-       }\r
-       \r
-       /* allocate buffer for clusters and copy */\r
-       lm->lightClusters = safe_malloc( lm->numLightClusters * sizeof( *lm->lightClusters ) );\r
-       c = 0;\r
-       for( i = 0; i < lm->numLightSurfaces; i++ )\r
-       {\r
-               /* get surface info */\r
-               info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + i ] ];\r
-               \r
-               /* add surface clusters */\r
-               for( j = 0; j < info->numSurfaceClusters; j++ )\r
-                       lm->lightClusters[ c++ ] = surfaceClusters[ info->firstSurfaceCluster + j ];\r
-       }\r
-       \r
-       /* set styles */\r
-       lm->styles[ 0 ] = LS_NORMAL;\r
-       for( i = 1; i < MAX_LIGHTMAPS; i++ )\r
-               lm->styles[ i ] = LS_NONE;\r
-       \r
-       /* set supersampling size */\r
-       lm->sw = lm->w * superSample;\r
-       lm->sh = lm->h * superSample;\r
-       \r
-       /* add to super luxel count */\r
-       numRawSuperLuxels += (lm->sw * lm->sh);\r
-       \r
-       /* manipulate origin/vecs for supersampling */\r
-       if( superSample > 1 && lm->vecs != NULL )\r
-       {\r
-               /* calc inverse supersample */\r
-               is = 1.0f / superSample;\r
-               \r
-               /* scale the vectors and shift the origin */\r
-               #if 1\r
-                       /* new code that works for arbitrary supersampling values */\r
-                       VectorMA( lm->origin, -0.5, lm->vecs[ 0 ], lm->origin );\r
-                       VectorMA( lm->origin, -0.5, lm->vecs[ 1 ], lm->origin );\r
-                       VectorScale( lm->vecs[ 0 ], is, lm->vecs[ 0 ] );\r
-                       VectorScale( lm->vecs[ 1 ], is, lm->vecs[ 1 ] );\r
-                       VectorMA( lm->origin, is, lm->vecs[ 0 ], lm->origin );\r
-                       VectorMA( lm->origin, is, lm->vecs[ 1 ], lm->origin );\r
-               #else\r
-                       /* old code that only worked with a value of 2 */\r
-                       VectorScale( lm->vecs[ 0 ], is, lm->vecs[ 0 ] );\r
-                       VectorScale( lm->vecs[ 1 ], is, lm->vecs[ 1 ] );\r
-                       VectorMA( lm->origin, -is, lm->vecs[ 0 ], lm->origin );\r
-                       VectorMA( lm->origin, -is, lm->vecs[ 1 ], lm->origin );\r
-               #endif\r
-       }\r
-       \r
-       /* allocate bsp lightmap storage */\r
-       size = lm->w * lm->h * BSP_LUXEL_SIZE * sizeof( float );\r
-       if( lm->bspLuxels[ 0 ] == NULL )\r
-               lm->bspLuxels[ 0 ] = safe_malloc( size );\r
-       memset( lm->bspLuxels[ 0 ], 0, size );\r
-       \r
-       /* allocate radiosity lightmap storage */\r
-       if( bounce )\r
-       {\r
-               size = lm->w * lm->h * RAD_LUXEL_SIZE * sizeof( float );\r
-               if( lm->radLuxels[ 0 ] == NULL )\r
-                       lm->radLuxels[ 0 ] = safe_malloc( size );\r
-               memset( lm->radLuxels[ 0 ], 0, size );\r
-       }\r
-       \r
-       /* allocate sampling lightmap storage */\r
-       size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );\r
-       if( lm->superLuxels[ 0 ] == NULL )\r
-               lm->superLuxels[ 0 ] = safe_malloc( size );\r
-       memset( lm->superLuxels[ 0 ], 0, size );\r
-       \r
-       /* allocate origin map storage */\r
-       size = lm->sw * lm->sh * SUPER_ORIGIN_SIZE * sizeof( float );\r
-       if( lm->superOrigins == NULL )\r
-               lm->superOrigins = safe_malloc( size );\r
-       memset( lm->superOrigins, 0, size );\r
-       \r
-       /* allocate normal map storage */\r
-       size = lm->sw * lm->sh * SUPER_NORMAL_SIZE * sizeof( float );\r
-       if( lm->superNormals == NULL )\r
-               lm->superNormals = safe_malloc( size );\r
-       memset( lm->superNormals, 0, size );\r
-       \r
-       /* allocate cluster map storage */\r
-       size = lm->sw * lm->sh * sizeof( int );\r
-       if( lm->superClusters == NULL )\r
-               lm->superClusters = safe_malloc( size );\r
-       size = lm->sw * lm->sh;\r
-       sc = lm->superClusters;\r
-       for( i = 0; i < size; i++ )\r
-               (*sc++) = CLUSTER_UNMAPPED;\r
-       \r
-       /* deluxemap allocation */\r
-       if( deluxemap )\r
-       {\r
-               /* allocate sampling deluxel storage */\r
-               size = lm->sw * lm->sh * SUPER_DELUXEL_SIZE * sizeof( float );\r
-               if( lm->superDeluxels == NULL )\r
-                       lm->superDeluxels = safe_malloc( size );\r
-               memset( lm->superDeluxels, 0, size );\r
-               \r
-               /* allocate bsp deluxel storage */\r
-               size = lm->w * lm->h * BSP_DELUXEL_SIZE * sizeof( float );\r
-               if( lm->bspDeluxels == NULL )\r
-                       lm->bspDeluxels = safe_malloc( size );\r
-               memset( lm->bspDeluxels, 0, size );\r
-       }\r
-       \r
-       /* add to count */\r
-       numLuxels += (lm->sw * lm->sh);\r
-}\r
-\r
-\r
-\r
-/*\r
-AddPatchToRawLightmap()\r
-projects a lightmap for a patch surface\r
-since lightmap calculation for surfaces is now handled in a general way (light_ydnar.c),\r
-it is no longer necessary for patch verts to fall exactly on a lightmap sample\r
-based on AllocateLightmapForPatch()\r
-*/\r
-\r
-qboolean AddPatchToRawLightmap( int num, rawLightmap_t *lm )\r
-{\r
-       bspDrawSurface_t        *ds;\r
-       surfaceInfo_t           *info;\r
-       int                                     x, y;\r
-       bspDrawVert_t           *verts, *a, *b;\r
-       vec3_t                          delta;\r
-       mesh_t                          src, *subdivided, *mesh;\r
-       float                           sBasis, tBasis, s, t;\r
-       float                           length, widthTable[ MAX_EXPANDED_AXIS ], heightTable[ MAX_EXPANDED_AXIS ];\r
-       \r
-       \r
-       /* patches finish a raw lightmap */\r
-       lm->finished = qtrue;\r
-       \r
-       /* get surface and info  */\r
-       ds = &bspDrawSurfaces[ num ];\r
-       info = &surfaceInfos[ num ];\r
-       \r
-       /* make a temporary 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
-       /* find the longest distance on each row/column */\r
-       verts = mesh->verts;\r
-       memset( widthTable, 0, sizeof( widthTable ) );\r
-       memset( heightTable, 0, sizeof( heightTable ) );\r
-       for( y = 0; y < mesh->height; y++ )\r
-       {\r
-               for( x = 0; x < mesh->width; x++ )\r
-               {\r
-                       /* get width */\r
-                       if( x + 1 < mesh->width )\r
-                       {\r
-                               a = &verts[ (y * mesh->width) + x ];\r
-                               b = &verts[ (y * mesh->width) + x + 1 ];\r
-                               VectorSubtract( a->xyz, b->xyz, delta );\r
-                               length = VectorLength( delta );\r
-                               if( length > widthTable[ x ] )\r
-                                       widthTable[ x ] = length;\r
-                       }\r
-                       \r
-                       /* get height */\r
-                       if( y + 1 < mesh->height )\r
-                       {\r
-                               a = &verts[ (y * mesh->width) + x ];\r
-                               b = &verts[ ((y + 1) * mesh->width) + x ];\r
-                               VectorSubtract( a->xyz, b->xyz, delta );\r
-                               length = VectorLength( delta );\r
-                               if( length > heightTable[ y ] )\r
-                                       heightTable[ y ] = length;\r
-                       }\r
-               }\r
-       }\r
-       \r
-       /* determine lightmap width */\r
-       length = 0;\r
-       for( x = 0; x < (mesh->width - 1); x++ )\r
-               length += widthTable[ x ];\r
-       lm->w = ceil( length / lm->sampleSize ) + 1;\r
-       if( lm->w < ds->patchWidth )\r
-               lm->w = ds->patchWidth;\r
-       if( lm->w > lm->customWidth )\r
-               lm->w = lm->customWidth;\r
-       sBasis = (float) (lm->w - 1) / (float) (ds->patchWidth - 1);\r
-       \r
-       /* determine lightmap height */\r
-       length = 0;\r
-       for( y = 0; y < (mesh->height - 1); y++ )\r
-               length += heightTable[ y ];\r
-       lm->h = ceil( length / lm->sampleSize ) + 1;\r
-       if( lm->h < ds->patchHeight )\r
-               lm->h = ds->patchHeight;\r
-       if( lm->h > lm->customHeight )\r
-               lm->h = lm->customHeight;\r
-       tBasis = (float) (lm->h - 1) / (float) (ds->patchHeight - 1);\r
-       \r
-       /* free the temporary mesh */\r
-       FreeMesh( mesh );\r
-       \r
-       /* set the lightmap texture coordinates in yDrawVerts */\r
-       lm->wrap[ 0 ] = qtrue;\r
-       lm->wrap[ 1 ] = qtrue;\r
-       verts = &yDrawVerts[ ds->firstVert ];\r
-       for( y = 0; y < ds->patchHeight; y++ )\r
-       {\r
-               t = (tBasis * y) + 0.5f;\r
-               for( x = 0; x < ds->patchWidth; x++ )\r
-               {\r
-                       s = (sBasis * x) + 0.5f;\r
-                       verts[ (y * ds->patchWidth) + x ].lightmap[ 0 ][ 0 ] = s * superSample;\r
-                       verts[ (y * ds->patchWidth) + x ].lightmap[ 0 ][ 1 ] = t * superSample;\r
-                       \r
-                       if( y == 0 && !VectorCompare( verts[ x ].xyz, verts[ ((ds->patchHeight - 1) * ds->patchWidth) + x ].xyz ) )\r
-                               lm->wrap[ 1 ] = qfalse;\r
-               }\r
-               \r
-               if( !VectorCompare( verts[ (y * ds->patchWidth) ].xyz, verts[ (y * ds->patchWidth) + (ds->patchWidth - 1) ].xyz ) )\r
-                       lm->wrap[ 0 ] = qfalse;\r
-       }\r
-       \r
-       /* debug code: */\r
-       //%     Sys_Printf( "wrap S: %d wrap T: %d\n", lm->wrap[ 0 ], lm->wrap[ 1 ] );\r
-       //% if( lm->w > (ds->lightmapWidth & 0xFF) || lm->h > (ds->lightmapHeight & 0xFF) )\r
-       //%             Sys_Printf( "Patch lightmap: (%3d %3d) > (%3d, %3d)\n", lm->w, lm->h, ds->lightmapWidth & 0xFF, ds->lightmapHeight & 0xFF );\r
-       //% ds->lightmapWidth = lm->w | (ds->lightmapWidth & 0xFFFF0000);\r
-       //% ds->lightmapHeight = lm->h | (ds->lightmapHeight & 0xFFFF0000);\r
-       \r
-       /* add to counts */\r
-       numPatchesLightmapped++;\r
-       \r
-       /* return */\r
-       return qtrue;\r
-}\r
-\r
-\r
-\r
-/*\r
-AddSurfaceToRawLightmap()\r
-projects a lightmap for a surface\r
-based on AllocateLightmapForSurface()\r
-*/\r
-\r
-qboolean AddSurfaceToRawLightmap( int num, rawLightmap_t *lm )\r
-{\r
-       bspDrawSurface_t        *ds, *ds2;\r
-       surfaceInfo_t           *info, *info2;\r
-       int                                     num2, n, i, axisNum;\r
-       float                           s, t, d, len, sampleSize;\r
-       vec3_t                          mins, maxs, origin, faxis, size, exactSize, delta, normalized, vecs[ 2 ];\r
-       vec4_t                          plane;\r
-       bspDrawVert_t           *verts;\r
-       \r
-       \r
-       /* get surface and info  */\r
-       ds = &bspDrawSurfaces[ num ];\r
-       info = &surfaceInfos[ num ];\r
-       \r
-       /* add the surface to the raw lightmap */\r
-       lightSurfaces[ numLightSurfaces++ ] = num;\r
-       lm->numLightSurfaces++;\r
-       \r
-       /* does this raw lightmap already have any surfaces? */\r
-       if( lm->numLightSurfaces > 1 )\r
-       {\r
-               /* surface and raw lightmap must have the same lightmap projection axis */\r
-               if( VectorCompare( info->axis, lm->axis ) == qfalse )\r
-                       return qfalse;\r
-               \r
-               /* match identical attributes */\r
-               if( info->sampleSize != lm->sampleSize ||\r
-                       info->entityNum != lm->entityNum ||\r
-                       info->recvShadows != lm->recvShadows ||\r
-                       info->si->lmCustomWidth != lm->customWidth ||\r
-                       info->si->lmCustomHeight != lm->customHeight ||\r
-                       info->si->lmGamma != lm->gamma ||\r
-                       info->si->lmFilterRadius != lm->filterRadius ||\r
-                       info->si->splotchFix != lm->splotchFix )\r
-                       return qfalse;\r
-               \r
-               /* surface bounds must intersect with raw lightmap bounds */\r
-               for( i = 0; i < 3; i++ )\r
-               {\r
-                       if( info->mins[ i ] > lm->maxs[ i ] )\r
-                               return qfalse;\r
-                       if( info->maxs[ i ] < lm->mins[ i ] )\r
-                               return qfalse;\r
-               }\r
-               \r
-               /* plane check (fixme: allow merging of nonplanars) */\r
-               if( info->si->lmMergable == qfalse )\r
-               {\r
-                       if( info->plane == NULL || lm->plane == NULL )\r
-                               return qfalse;\r
-                       \r
-                       /* compare planes */\r
-                       for( i = 0; i < 4; i++ )\r
-                               if( fabs( info->plane[ i ] - lm->plane[ i ] ) > EQUAL_EPSILON )\r
-                                       return qfalse;\r
-               }\r
-               \r
-               /* debug code hacking */\r
-               //%     if( lm->numLightSurfaces > 1 )\r
-               //%             return qfalse;\r
-       }\r
-       \r
-       /* set plane */\r
-       if( info->plane == NULL )\r
-               lm->plane = NULL;\r
-       \r
-       /* add surface to lightmap bounds */\r
-       AddPointToBounds( info->mins, lm->mins, lm->maxs );\r
-       AddPointToBounds( info->maxs, lm->mins, lm->maxs );\r
-       \r
-       /* check to see if this is a non-planar patch */\r
-       if( ds->surfaceType == MST_PATCH &&\r
-               lm->axis[ 0 ] == 0.0f && lm->axis[ 1 ] == 0.0f && lm->axis[ 2 ] == 0.0f )\r
-               return AddPatchToRawLightmap( num, lm );\r
-       \r
-       /* start with initially requested sample size */\r
-       sampleSize = lm->sampleSize;\r
-       \r
-       /* round to the lightmap resolution */\r
-       for( i = 0; i < 3; i++ )\r
-       {\r
-               exactSize[ i ] = lm->maxs[ i ] - lm->mins[ i ];\r
-               mins[ i ] = sampleSize * floor( lm->mins[ i ] / sampleSize );\r
-               maxs[ i ] = sampleSize * ceil( lm->maxs[ i ] / sampleSize );\r
-               size[ i ] = (maxs[ i ] - mins[ i ]) / sampleSize + 1.0f;\r
-               \r
-               /* hack (god this sucks) */\r
-               if( size[ i ] > lm->customWidth || size[ i ] > lm->customHeight )\r
-               {\r
-                       i = -1;\r
-                       sampleSize += 1.0f;\r
-               }\r
-       }\r
-       \r
-       /* set actual sample size */\r
-       lm->actualSampleSize = sampleSize;\r
-       \r
-       /* fixme: copy rounded mins/maxes to lightmap record? */\r
-       if( lm->plane == NULL )\r
-       {\r
-               VectorCopy( mins, lm->mins );\r
-               VectorCopy( maxs, lm->maxs );\r
-               VectorCopy( mins, origin );\r
-       }\r
-       \r
-       /* set lightmap origin */\r
-       VectorCopy( lm->mins, origin );\r
-       \r
-       /* make absolute axis */\r
-       faxis[ 0 ] = fabs( lm->axis[ 0 ] );\r
-       faxis[ 1 ] = fabs( lm->axis[ 1 ] );\r
-       faxis[ 2 ] = fabs( lm->axis[ 2 ] );\r
-       \r
-       /* clear out lightmap vectors */\r
-       memset( vecs, 0, sizeof( vecs ) );\r
-       \r
-       /* classify the plane (x y or z major) (ydnar: biased to z axis projection) */\r
-       if( faxis[ 2 ] >= faxis[ 0 ] && faxis[ 2 ] >= faxis[ 1 ] )\r
-       {\r
-               axisNum = 2;\r
-               lm->w = size[ 0 ];\r
-               lm->h = size[ 1 ];\r
-               vecs[ 0 ][ 0 ] = 1.0f / sampleSize;\r
-               vecs[ 1 ][ 1 ] = 1.0f / sampleSize;\r
-       }\r
-       else if( faxis[ 0 ] >= faxis[ 1 ] && faxis[ 0 ] >= faxis[ 2 ] )\r
-       {\r
-               axisNum = 0;\r
-               lm->w = size[ 1 ];\r
-               lm->h = size[ 2 ];\r
-               vecs[ 0 ][ 1 ] = 1.0f / sampleSize;\r
-               vecs[ 1 ][ 2 ] = 1.0f / sampleSize;\r
-       }\r
-       else\r
-       {\r
-               axisNum = 1;\r
-               lm->w = size[ 0 ];\r
-               lm->h = size[ 2 ];\r
-               vecs[ 0 ][ 0 ] = 1.0f / sampleSize;\r
-               vecs[ 1 ][ 2 ] = 1.0f / sampleSize;\r
-       }\r
-       \r
-       /* check for bogus axis */\r
-       if( faxis[ axisNum ] == 0.0f )\r
-       {\r
-               Sys_Printf( "WARNING: ProjectSurfaceLightmap: Chose a 0 valued axis\n" );\r
-               lm->w = lm->h = 0;\r
-               return qfalse;\r
-       }\r
-       \r
-       /* store the axis number in the lightmap */\r
-       lm->axisNum = axisNum;\r
-       \r
-       /* walk the list of surfaces on this raw lightmap */\r
-       for( n = 0; n < lm->numLightSurfaces; n++ )\r
-       {\r
-               /* get surface */\r
-               num2 = lightSurfaces[ lm->firstLightSurface + n ];\r
-               ds2 = &bspDrawSurfaces[ num2 ];\r
-               info2 = &surfaceInfos[ num2 ];\r
-               verts = &yDrawVerts[ ds2->firstVert ];\r
-               \r
-               /* set the lightmap texture coordinates in yDrawVerts in [0, superSample * lm->customWidth] space */\r
-               for( i = 0; i < ds2->numVerts; i++ )\r
-               {\r
-                       VectorSubtract( verts[ i ].xyz, origin, delta );\r
-                       s = DotProduct( delta, vecs[ 0 ] ) + 0.5f;\r
-                       t = DotProduct( delta, vecs[ 1 ] ) + 0.5f;\r
-                       verts[ i ].lightmap[ 0 ][ 0 ] = s * superSample;\r
-                       verts[ i ].lightmap[ 0 ][ 1 ] = t * superSample;\r
-                       \r
-                       if( s > (float) lm->w || t > (float) lm->h )\r
-                       {\r
-                               Sys_FPrintf( SYS_VRB, "WARNING: Lightmap texture coords out of range: S %1.4f > %3d || T %1.4f > %3d\n",\r
-                                       s, lm->w, t, lm->h );\r
-                       }\r
-               }\r
-       }\r
-       \r
-       /* get first drawsurface */\r
-       num2 = lightSurfaces[ lm->firstLightSurface ];\r
-       ds2 = &bspDrawSurfaces[ num2 ];\r
-       info2 = &surfaceInfos[ num2 ];\r
-       verts = &yDrawVerts[ ds2->firstVert ];\r
-       \r
-       /* calculate lightmap origin */\r
-       if( VectorLength( ds2->lightmapVecs[ 2 ] ) )\r
-               VectorCopy( ds2->lightmapVecs[ 2 ], plane );\r
-       else\r
-               VectorCopy( lm->axis, plane );\r
-       plane[ 3 ] = DotProduct( verts[ 0 ].xyz, plane );\r
-       \r
-       VectorCopy( origin, lm->origin );\r
-       d = DotProduct( lm->origin, plane ) - plane[ 3 ];\r
-       d /= plane[ axisNum ];\r
-       lm->origin[ axisNum ] -= d;\r
-       \r
-       /* legacy support */\r
-       VectorCopy( lm->origin, ds->lightmapOrigin );\r
-       \r
-       /* for planar surfaces, create lightmap vectors for st->xyz conversion */\r
-       if( VectorLength( ds->lightmapVecs[ 2 ] ) || 1 )        /* ydnar: can't remember what exactly i was thinking here... */\r
-       {\r
-               /* allocate space for the vectors */\r
-               lm->vecs = safe_malloc( 3 * sizeof( vec3_t ) );\r
-               memset( lm->vecs, 0, 3 * sizeof( vec3_t ) );\r
-               VectorCopy( ds->lightmapVecs[ 2 ], lm->vecs[ 2 ] );\r
-               \r
-               /* project stepped lightmap blocks and subtract to get planevecs */\r
-               for( i = 0; i < 2; i++ )\r
-               {\r
-                       len = VectorNormalize( vecs[ i ], normalized );\r
-                       VectorScale( normalized, (1.0 / len), lm->vecs[ i ] );\r
-                       d = DotProduct( lm->vecs[ i ], plane );\r
-                       d /= plane[ axisNum ];\r
-                       lm->vecs[ i ][ axisNum ] -= d;\r
-               }\r
-       }\r
-       else\r
-       {\r
-               /* lightmap vectors are useless on a non-planar surface */\r
-               lm->vecs = NULL;\r
-       }\r
-       \r
-       /* add to counts */\r
-       if( ds->surfaceType == MST_PATCH )\r
-       {\r
-               numPatchesLightmapped++;\r
-               if( lm->plane != NULL )\r
-                       numPlanarPatchesLightmapped++;\r
-       }\r
-       else\r
-       {\r
-               if( lm->plane != NULL )\r
-                       numPlanarsLightmapped++;\r
-               else\r
-                       numNonPlanarsLightmapped++;\r
-       }\r
-       \r
-       /* return */\r
-       return qtrue;\r
-}\r
-\r
-\r
-\r
-/*\r
-CompareSurfaceInfo()\r
-compare function for qsort()\r
-*/\r
-\r
-static int CompareSurfaceInfo( const void *a, const void *b )\r
-{\r
-       surfaceInfo_t   *aInfo, *bInfo;\r
-       int                             i;\r
-       \r
-\r
-       /* get surface info */\r
-       aInfo = &surfaceInfos[ *((int*) a) ];\r
-       bInfo = &surfaceInfos[ *((int*) b) ];\r
-       \r
-       /* model first */\r
-       if( aInfo->model < bInfo->model )\r
-               return 1;\r
-       else if( aInfo->model > bInfo->model )\r
-               return -1;\r
-       \r
-       /* then lightmap status */\r
-       if( aInfo->hasLightmap < bInfo->hasLightmap )\r
-               return 1;\r
-       else if( aInfo->hasLightmap > bInfo->hasLightmap )\r
-               return -1;\r
-       \r
-       /* then lightmap sample size */\r
-       if( aInfo->sampleSize < bInfo->sampleSize )\r
-               return 1;\r
-       else if( aInfo->sampleSize > bInfo->sampleSize )\r
-               return -1;\r
-       \r
-       /* then lightmap axis */\r
-       for( i = 0; i < 3; i++ )\r
-       {\r
-               if( aInfo->axis[ i ] < bInfo->axis[ i ] )\r
-                       return 1;\r
-               else if( aInfo->axis[ i ] > bInfo->axis[ i ] )\r
-                       return -1;\r
-       }\r
-       \r
-       /* then plane */\r
-       if( aInfo->plane == NULL && bInfo->plane != NULL )\r
-               return 1;\r
-       else if( aInfo->plane != NULL && bInfo->plane == NULL )\r
-               return -1;\r
-       else if( aInfo->plane != NULL && bInfo->plane != NULL )\r
-       {\r
-               for( i = 0; i < 4; i++ )\r
-               {\r
-                       if( aInfo->plane[ i ] < bInfo->plane[ i ] )\r
-                               return 1;\r
-                       else if( aInfo->plane[ i ] > bInfo->plane[ i ] )\r
-                               return -1;\r
-               }\r
-       }\r
-       \r
-       /* then position in world */\r
-       for( i = 0; i < 3; i++ )\r
-       {\r
-               if( aInfo->mins[ i ] < bInfo->mins[ i ] )\r
-                       return 1;\r
-               else if( aInfo->mins[ i ] > bInfo->mins[ i ] )\r
-                       return -1;\r
-       }\r
-       \r
-       /* these are functionally identical (this should almost never happen) */\r
-       return 0;\r
-}\r
-\r
-\r
-\r
-/*\r
-SetupSurfaceLightmaps()\r
-allocates lightmaps for every surface in the bsp that needs one\r
-this depends on yDrawVerts being allocated\r
-*/\r
-\r
-void SetupSurfaceLightmaps( void )\r
-{\r
-       int                                     i, j, k, s,num, num2;\r
-       bspModel_t                      *model;\r
-       bspLeaf_t                       *leaf;\r
-       bspDrawSurface_t        *ds, *ds2;\r
-       surfaceInfo_t           *info, *info2;\r
-       rawLightmap_t           *lm;\r
-       qboolean                        added;\r
-       vec3_t                          mapSize, entityOrigin;\r
-       \r
-       \r
-       /* note it */\r
-       Sys_FPrintf( SYS_VRB, "--- SetupSurfaceLightmaps ---\n");\r
-       \r
-       /* determine supersample amount */\r
-       if( superSample < 1 )\r
-               superSample = 1;\r
-       else if( superSample > 8 )\r
-       {\r
-               Sys_Printf( "WARNING: Insane supersampling amount (%d) detected.\n", superSample );\r
-               superSample = 8;\r
-       }\r
-       \r
-       /* clear map bounds */\r
-       ClearBounds( mapMins, mapMaxs );\r
-       \r
-       /* allocate a list of surface clusters */\r
-       numSurfaceClusters = 0;\r
-       maxSurfaceClusters = numBSPLeafSurfaces;\r
-       surfaceClusters = safe_malloc( maxSurfaceClusters * sizeof( *surfaceClusters ) );\r
-       memset( surfaceClusters, 0, maxSurfaceClusters * sizeof( *surfaceClusters ) );\r
-       \r
-       /* allocate a list for per-surface info */\r
-       surfaceInfos = safe_malloc( numBSPDrawSurfaces * sizeof( *surfaceInfos ) );\r
-       memset( surfaceInfos, 0, numBSPDrawSurfaces * sizeof( *surfaceInfos ) );\r
-       for( i = 0; i < numBSPDrawSurfaces; i++ )\r
-               surfaceInfos[ i ].childSurfaceNum = -1;\r
-       \r
-       /* allocate a list of surface indexes to be sorted */\r
-       sortSurfaces = safe_malloc( numBSPDrawSurfaces * sizeof( int ) );\r
-       memset( sortSurfaces, 0, numBSPDrawSurfaces * sizeof( int ) );\r
-       \r
-       /* walk each model in the bsp */\r
-       for( i = 0; i < numBSPModels; i++ )\r
-       {\r
-               /* get model */\r
-               model = &bspModels[ i ];\r
-               \r
-               /* walk the list of surfaces in this model and fill out the info structs */\r
-               for( j = 0; j < model->numBSPSurfaces; j++ )\r
-               {\r
-                       /* make surface index */\r
-                       num = model->firstBSPSurface + j;\r
-                       \r
-                       /* copy index to sort list */\r
-                       sortSurfaces[ num ] = num;\r
-                       \r
-                       /* get surface and info */\r
-                       ds = &bspDrawSurfaces[ num ];\r
-                       info = &surfaceInfos[ num ];\r
-                       \r
-                       /* set entity origin */\r
-                       if( ds->numVerts > 0 )\r
-                               VectorSubtract( yDrawVerts[ ds->firstVert ].xyz, bspDrawVerts[ ds->firstVert ].xyz, entityOrigin );\r
-                       else\r
-                               VectorClear( entityOrigin );\r
-                       \r
-                       /* basic setup */\r
-                       info->model = model;\r
-                       info->lm = NULL;\r
-                       info->plane = NULL;\r
-                       info->firstSurfaceCluster = numSurfaceClusters;\r
-                       \r
-                       /* get extra data */\r
-                       info->si = GetSurfaceExtraShaderInfo( num );\r
-                       if( info->si == NULL )\r
-                               info->si = ShaderInfoForShader( bspShaders[ ds->shaderNum ].shader );\r
-                       info->parentSurfaceNum = GetSurfaceExtraParentSurfaceNum( num );\r
-                       info->entityNum = GetSurfaceExtraEntityNum( num );\r
-                       info->castShadows = GetSurfaceExtraCastShadows( num );\r
-                       info->recvShadows = GetSurfaceExtraRecvShadows( num );\r
-                       info->sampleSize = GetSurfaceExtraSampleSize( num );\r
-                       info->longestCurve = GetSurfaceExtraLongestCurve( num );\r
-                       info->patchIterations = IterationsForCurve( info->longestCurve, patchSubdivisions );\r
-                       GetSurfaceExtraLightmapAxis( num, info->axis );\r
-                       \r
-                       /* mark parent */\r
-                       if( info->parentSurfaceNum >= 0 )\r
-                               surfaceInfos[ info->parentSurfaceNum ].childSurfaceNum = j;\r
-                       \r
-                       /* determine surface bounds */\r
-                       ClearBounds( info->mins, info->maxs );\r
-                       for( k = 0; k < ds->numVerts; k++ )\r
-                       {\r
-                               AddPointToBounds( yDrawVerts[ ds->firstVert + k ].xyz, mapMins, mapMaxs );\r
-                               AddPointToBounds( yDrawVerts[ ds->firstVert + k ].xyz, info->mins, info->maxs );\r
-                       }\r
-                       \r
-                       /* find all the bsp clusters the surface falls into */\r
-                       for( k = 0; k < numBSPLeafs; k++ )\r
-                       {\r
-                               /* get leaf */\r
-                               leaf = &bspLeafs[ k ];\r
-                               \r
-                               /* test bbox */\r
-                               if( leaf->mins[ 0 ] > info->maxs[ 0 ] || leaf->maxs[ 0 ] < info->mins[ 0 ] ||\r
-                                       leaf->mins[ 1 ] > info->maxs[ 1 ] || leaf->maxs[ 1 ] < info->mins[ 1 ] ||\r
-                                       leaf->mins[ 2 ] > info->maxs[ 2 ] || leaf->maxs[ 2 ] < info->mins[ 2 ] )\r
-                                       continue;\r
-                               \r
-                               /* test leaf surfaces */\r
-                               for( s = 0; s < leaf->numBSPLeafSurfaces; s++ )\r
-                               {\r
-                                       if( bspLeafSurfaces[ leaf->firstBSPLeafSurface + s ] == num )\r
-                                       {\r
-                                               if( numSurfaceClusters >= maxSurfaceClusters )\r
-                                                       Error( "maxSurfaceClusters exceeded" );\r
-                                               surfaceClusters[ numSurfaceClusters ] = leaf->cluster;\r
-                                               numSurfaceClusters++;\r
-                                               info->numSurfaceClusters++;\r
-                                       }\r
-                               }\r
-                       }\r
-                       \r
-                       /* determine if surface is planar */\r
-                       if( VectorLength( ds->lightmapVecs[ 2 ] ) > 0.0f )\r
-                       {\r
-                               /* make a plane */\r
-                               info->plane = safe_malloc( 4 * sizeof( float ) );\r
-                               VectorCopy( ds->lightmapVecs[ 2 ], info->plane );\r
-                               info->plane[ 3 ] = DotProduct( yDrawVerts[ ds->firstVert ].xyz, info->plane );\r
-                       }\r
-                       \r
-                       /* determine if surface requires a lightmap */\r
-                       if( ds->surfaceType == MST_TRIANGLE_SOUP ||\r
-                               ds->surfaceType == MST_FOLIAGE ||\r
-                               (info->si->compileFlags & C_VERTEXLIT) )\r
-                               numSurfsVertexLit++;\r
-                       else\r
-                       {\r
-                               numSurfsLightmapped++;\r
-                               info->hasLightmap = qtrue;\r
-                       }\r
-               }\r
-       }\r
-       \r
-       /* find longest map distance */\r
-       VectorSubtract( mapMaxs, mapMins, mapSize );\r
-       maxMapDistance = VectorLength( mapSize );\r
-       \r
-       /* sort the surfaces info list */\r
-       qsort( sortSurfaces, numBSPDrawSurfaces, sizeof( int ), CompareSurfaceInfo );\r
-       \r
-       /* allocate a list of surfaces that would go into raw lightmaps */\r
-       numLightSurfaces = 0;\r
-       lightSurfaces = safe_malloc( numSurfsLightmapped * sizeof( int ) );\r
-       memset( lightSurfaces, 0, numSurfsLightmapped * sizeof( int ) );\r
-       \r
-       /* allocate a list of raw lightmaps */\r
-       numRawSuperLuxels = 0;\r
-       numRawLightmaps = 0;\r
-       rawLightmaps = safe_malloc( numSurfsLightmapped * sizeof( *rawLightmaps ) );\r
-       memset( rawLightmaps, 0, numSurfsLightmapped * sizeof( *rawLightmaps ) );\r
-       \r
-       /* walk the list of sorted surfaces */\r
-       for( i = 0; i < numBSPDrawSurfaces; i++ )\r
-       {\r
-               /* get info and attempt early out */\r
-               num = sortSurfaces[ i ];\r
-               ds = &bspDrawSurfaces[ num ];\r
-               info = &surfaceInfos[ num ];\r
-               if( info->hasLightmap == qfalse || info->lm != NULL || info->parentSurfaceNum >= 0 )\r
-                       continue;\r
-               \r
-               /* allocate a new raw lightmap */\r
-               lm = &rawLightmaps[ numRawLightmaps ];\r
-               numRawLightmaps++;\r
-               \r
-               /* set it up */\r
-               lm->splotchFix = info->si->splotchFix;\r
-               lm->firstLightSurface = numLightSurfaces;\r
-               lm->numLightSurfaces = 0;\r
-               lm->sampleSize = info->sampleSize;\r
-               lm->actualSampleSize = info->sampleSize;\r
-               lm->entityNum = info->entityNum;\r
-               lm->recvShadows = info->recvShadows;\r
-               lm->gamma = info->si->lmGamma;\r
-               lm->filterRadius = info->si->lmFilterRadius;\r
-               VectorCopy( info->axis, lm->axis );\r
-               lm->plane = info->plane;        \r
-               VectorCopy( info->mins, lm->mins );\r
-               VectorCopy( info->maxs, lm->maxs );\r
-               \r
-               lm->customWidth = info->si->lmCustomWidth;\r
-               lm->customHeight = info->si->lmCustomHeight;\r
-               \r
-               /* add the surface to the raw lightmap */\r
-               AddSurfaceToRawLightmap( num, lm );\r
-               info->lm = lm;\r
-               \r
-               /* do an exhaustive merge */\r
-               added = qtrue;\r
-               while( added )\r
-               {\r
-                       /* walk the list of surfaces again */\r
-                       added = qfalse;\r
-                       for( j = i + 1; j < numBSPDrawSurfaces && lm->finished == qfalse; j++ )\r
-                       {\r
-                               /* get info and attempt early out */\r
-                               num2 = sortSurfaces[ j ];\r
-                               ds2 = &bspDrawSurfaces[ num2 ];\r
-                               info2 = &surfaceInfos[ num2 ];\r
-                               if( info2->hasLightmap == qfalse || info2->lm != NULL )\r
-                                       continue;\r
-                               \r
-                               /* add the surface to the raw lightmap */\r
-                               if( AddSurfaceToRawLightmap( num2, lm ) )\r
-                               {\r
-                                       info2->lm = lm;\r
-                                       added = qtrue;\r
-                               }\r
-                               else\r
-                               {\r
-                                       /* back up one */\r
-                                       lm->numLightSurfaces--;\r
-                                       numLightSurfaces--;\r
-                               }\r
-                       }\r
-               }\r
-               \r
-               /* finish the lightmap and allocate the various buffers */\r
-               FinishRawLightmap( lm );\r
-       }\r
-       \r
-       /* allocate vertex luxel storage */\r
-       for( k = 0; k < MAX_LIGHTMAPS; k++ )\r
-       {\r
-               vertexLuxels[ k ] = safe_malloc( numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) ); \r
-               memset( vertexLuxels[ k ], 0, numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );\r
-               radVertexLuxels[ k ] = safe_malloc( numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );\r
-               memset( radVertexLuxels[ k ], 0, numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );\r
-       }\r
-       \r
-       /* emit some stats */\r
-       Sys_FPrintf( SYS_VRB, "%9d surfaces\n", numBSPDrawSurfaces );\r
-       Sys_FPrintf( SYS_VRB, "%9d raw lightmaps\n", numRawLightmaps );\r
-       Sys_FPrintf( SYS_VRB, "%9d surfaces vertex lit\n", numSurfsVertexLit );\r
-       Sys_FPrintf( SYS_VRB, "%9d surfaces lightmapped\n", numSurfsLightmapped );\r
-       Sys_FPrintf( SYS_VRB, "%9d planar surfaces lightmapped\n", numPlanarsLightmapped );\r
-       Sys_FPrintf( SYS_VRB, "%9d non-planar surfaces lightmapped\n", numNonPlanarsLightmapped );\r
-       Sys_FPrintf( SYS_VRB, "%9d patches lightmapped\n", numPatchesLightmapped );\r
-       Sys_FPrintf( SYS_VRB, "%9d planar patches lightmapped\n", numPlanarPatchesLightmapped );\r
-}\r
-\r
-\r
-\r
-/*\r
-StitchSurfaceLightmaps()\r
-stitches lightmap edges\r
-2002-11-20 update: use this func only for stitching nonplanar patch lightmap seams\r
-*/\r
-\r
-#define MAX_STITCH_CANDIDATES  32\r
-#define MAX_STITCH_LUXELS              64\r
-\r
-void StitchSurfaceLightmaps( void )\r
-{\r
-       int                             i, j, x, y, x2, y2, *cluster, *cluster2,\r
-                                       numStitched, numCandidates, numLuxels, f, fOld, start;\r
-       rawLightmap_t   *lm, *a, *b, *c[ MAX_STITCH_CANDIDATES ];\r
-       float                   *luxel, *luxel2, *origin, *origin2, *normal, *normal2, \r
-                                       sampleSize, average[ 3 ], totalColor, ootc, *luxels[ MAX_STITCH_LUXELS ];\r
-       \r
-       \r
-       /* disabled for now */\r
-       return;\r
-       \r
-       /* note it */\r
-       Sys_Printf( "--- StitchSurfaceLightmaps ---\n");\r
-\r
-       /* init pacifier */\r
-       fOld = -1;\r
-       start = I_FloatTime();\r
-       \r
-       /* walk the list of raw lightmaps */\r
-       numStitched = 0;\r
-       for( i = 0; i < numRawLightmaps; i++ )\r
-       {\r
-               /* print pacifier */\r
-               f = 10 * i / numRawLightmaps;\r
-               if( f != fOld )\r
-               {\r
-                       fOld = f;\r
-                       Sys_Printf( "%i...", f );\r
-               }\r
-               \r
-               /* get lightmap a */\r
-               a = &rawLightmaps[ i ];\r
-               \r
-               /* walk rest of lightmaps */\r
-               numCandidates = 0;\r
-               for( j = i + 1; j < numRawLightmaps && numCandidates < MAX_STITCH_CANDIDATES; j++ )\r
-               {\r
-                       /* get lightmap b */\r
-                       b = &rawLightmaps[ j ];\r
-                       \r
-                       /* test bounding box */\r
-                       if( a->mins[ 0 ] > b->maxs[ 0 ] || a->maxs[ 0 ] < b->mins[ 0 ] ||\r
-                               a->mins[ 1 ] > b->maxs[ 1 ] || a->maxs[ 1 ] < b->mins[ 1 ] ||\r
-                               a->mins[ 2 ] > b->maxs[ 2 ] || a->maxs[ 2 ] < b->mins[ 2 ] )\r
-                               continue;\r
-                       \r
-                       /* add candidate */\r
-                       c[ numCandidates++ ] = b;\r
-               }\r
-               \r
-               /* walk luxels */\r
-               for( y = 0; y < a->sh; y++ )\r
-               {\r
-                       for( x = 0; x < a->sw; x++ )\r
-                       {\r
-                               /* ignore unmapped/unlit luxels */\r
-                               lm = a;\r
-                               cluster = SUPER_CLUSTER( x, y );\r
-                               if( *cluster == CLUSTER_UNMAPPED )\r
-                                       continue;\r
-                               luxel = SUPER_LUXEL( 0, x, y );\r
-                               if( luxel[ 3 ] <= 0.0f )\r
-                                       continue;\r
-                               \r
-                               /* get particulars */\r
-                               origin = SUPER_ORIGIN( x, y );\r
-                               normal = SUPER_NORMAL( x, y );\r
-                               \r
-                               /* walk candidate list */\r
-                               for( j = 0; j < numCandidates; j++ )\r
-                               {\r
-                                       /* get candidate */\r
-                                       b = c[ j ];\r
-                                       lm = b;\r
-                                       \r
-                                       /* set samplesize to the smaller of the pair */\r
-                                       sampleSize = 0.5f * (a->actualSampleSize < b->actualSampleSize ? a->actualSampleSize : b->actualSampleSize);\r
-                                       \r
-                                       /* test bounding box */\r
-                                       if( origin[ 0 ] < (b->mins[ 0 ] - sampleSize) || (origin[ 0 ] > b->maxs[ 0 ] + sampleSize) ||\r
-                                               origin[ 1 ] < (b->mins[ 1 ] - sampleSize) || (origin[ 1 ] > b->maxs[ 1 ] + sampleSize) ||\r
-                                               origin[ 2 ] < (b->mins[ 2 ] - sampleSize) || (origin[ 2 ] > b->maxs[ 2 ] + sampleSize) )\r
-                                               continue;\r
-                                       \r
-                                       /* walk candidate luxels */\r
-                                       VectorClear( average );\r
-                                       numLuxels = 0;\r
-                                       totalColor = 0.0f;\r
-                                       for( y2 = 0; y2 < b->sh && numLuxels < MAX_STITCH_LUXELS; y2++ )\r
-                                       {\r
-                                               for( x2 = 0; x2 < b->sw && numLuxels < MAX_STITCH_LUXELS; x2++ )\r
-                                               {\r
-                                                       /* ignore same luxels */\r
-                                                       if( a == b && abs( x - x2 ) <= 1 && abs( y - y2 ) <= 1 )\r
-                                                               continue;\r
-                                                       \r
-                                                       /* ignore unmapped/unlit luxels */\r
-                                                       cluster2 = SUPER_CLUSTER( x2, y2 );\r
-                                                       if( *cluster2 == CLUSTER_UNMAPPED )\r
-                                                               continue;\r
-                                                       luxel2 = SUPER_LUXEL( 0, x2, y2 );\r
-                                                       if( luxel2[ 3 ] <= 0.0f )\r
-                                                               continue;\r
-                                                       \r
-                                                       /* get particulars */\r
-                                                       origin2 = SUPER_ORIGIN( x2, y2 );\r
-                                                       normal2 = SUPER_NORMAL( x2, y2 );\r
-                                                       \r
-                                                       /* test normal */\r
-                                                       if( DotProduct( normal, normal2 ) < 0.5f )\r
-                                                               continue;\r
-                                                       \r
-                                                       /* test bounds */\r
-                                                       if( fabs( origin[ 0 ] - origin2[ 0 ] ) > sampleSize ||\r
-                                                               fabs( origin[ 1 ] - origin2[ 1 ] ) > sampleSize ||\r
-                                                               fabs( origin[ 2 ] - origin2[ 2 ] ) > sampleSize )\r
-                                                               continue;\r
-                                                       \r
-                                                       /* add luxel */\r
-                                                       //%     VectorSet( luxel2, 255, 0, 255 );\r
-                                                       luxels[ numLuxels++ ] = luxel2;\r
-                                                       VectorAdd( average, luxel2, average );\r
-                                                       totalColor += luxel2[ 3 ];\r
-                                               }\r
-                                       }\r
-                                       \r
-                                       /* early out */\r
-                                       if( numLuxels == 0 )\r
-                                               continue;\r
-                                       \r
-                                       /* scale average */\r
-                                       ootc = 1.0f / totalColor;\r
-                                       VectorScale( average, ootc, luxel );\r
-                                       luxel[ 3 ] = 1.0f;\r
-                                       numStitched++;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       \r
-       /* emit statistics */\r
-       Sys_Printf( " (%i)\n", (int) (I_FloatTime() - start) );\r
-       Sys_FPrintf( SYS_VRB, "%9d luxels stitched\n", numStitched );\r
-}\r
-\r
-\r
-\r
-/*\r
-CompareBSPLuxels()\r
-compares two surface lightmaps' bsp luxels, ignoring occluded luxels\r
-*/\r
-\r
-#define LUXEL_TOLERANCE                0.0025\r
-#define LUXEL_COLOR_FRAC       0.001302083     /* 1 / 3 / 256 */\r
-\r
-static qboolean CompareBSPLuxels( rawLightmap_t *a, int aNum, rawLightmap_t *b, int bNum )\r
-{\r
-       rawLightmap_t   *lm;\r
-       int                             x, y;\r
-       double                  delta, total, rd, gd, bd;\r
-       float                   *aLuxel, *bLuxel;\r
-       \r
-       \r
-       /* styled lightmaps will never be collapsed to non-styled lightmaps when there is _minlight */\r
-       if( (minLight[ 0 ] || minLight[ 1 ] || minLight[ 2 ]) &&\r
-               ((aNum == 0 && bNum != 0) || (aNum != 0 && bNum == 0)) )\r
-               return qfalse;\r
-       \r
-       /* compare */\r
-       if( a->w != b->w || a->h != b->h ||\r
-               a->customWidth != b->customWidth || a->customHeight != b->customHeight ||\r
-               a->gamma != b->gamma ||\r
-               a->bspLuxels[ aNum ] == NULL || b->bspLuxels[ bNum ] == NULL )\r
-               return qfalse;\r
-       \r
-       /* compare luxels */\r
-       delta = 0.0;\r
-       total = 0.0;\r
-       for( y = 0; y < a->h; y++ )\r
-       {\r
-               for( x = 0; x < a->w; x++ )\r
-               {\r
-                       /* increment total */\r
-                       total += 1.0;\r
-                       \r
-                       /* get luxels */\r
-                       lm = a; aLuxel = BSP_LUXEL( aNum, x, y );\r
-                       lm = b; bLuxel = BSP_LUXEL( bNum, x, y );\r
-                       \r
-                       /* ignore unused luxels */\r
-                       if( aLuxel[ 0 ] < 0 || bLuxel[ 0 ] < 0 )\r
-                               continue;\r
-                       \r
-                       /* get deltas */\r
-                       rd = fabs( aLuxel[ 0 ] - bLuxel[ 0 ] );\r
-                       gd = fabs( aLuxel[ 1 ] - bLuxel[ 1 ] );\r
-                       bd = fabs( aLuxel[ 2 ] - bLuxel[ 2 ] );\r
-                       \r
-                       /* 2003-09-27: compare individual luxels */\r
-                       if( rd > 3.0 || gd > 3.0 || bd > 3.0 )\r
-                               return qfalse;\r
-                       \r
-                       /* compare (fixme: take into account perceptual differences) */\r
-                       delta += rd * LUXEL_COLOR_FRAC;\r
-                       delta += gd * LUXEL_COLOR_FRAC;\r
-                       delta += bd * LUXEL_COLOR_FRAC;\r
-                       \r
-                       /* is the change too high? */\r
-                       if( total > 0.0 && ((delta / total) > LUXEL_TOLERANCE) )\r
-                               return qfalse;\r
-               }\r
-       }\r
-       \r
-       /* made it this far, they must be identical (or close enough) */\r
-       return qtrue;\r
-}\r
-\r
-\r
-\r
-/*\r
-MergeBSPLuxels()\r
-merges two surface lightmaps' bsp luxels, overwriting occluded luxels\r
-*/\r
-\r
-static void MergeBSPLuxels( rawLightmap_t *a, int aNum, rawLightmap_t *b, int bNum )\r
-{\r
-       rawLightmap_t   *lm;\r
-       int                             x, y;\r
-       float                   luxel[ 3 ], *aLuxel, *bLuxel;\r
-       \r
-       \r
-       /* compare */\r
-       if( a->w != b->w || a->h != b->h ||\r
-               a->customWidth != b->customWidth || a->customHeight != b->customHeight ||\r
-               a->gamma != b->gamma ||\r
-               a->bspLuxels[ aNum ] == NULL || b->bspLuxels[ bNum ] == NULL )\r
-               return;\r
-       \r
-       /* merge luxels */\r
-       for( y = 0; y < a->h; y++ )\r
-       {\r
-               for( x = 0; x < a->w; x++ )\r
-               {\r
-                       /* get luxels */\r
-                       lm = a; aLuxel = BSP_LUXEL( aNum, x, y );\r
-                       lm = b; bLuxel = BSP_LUXEL( bNum, x, y );\r
-                       \r
-                       /* handle occlusion mismatch */\r
-                       if( aLuxel[ 0 ] < 0.0f )\r
-                               VectorCopy( bLuxel, aLuxel );\r
-                       else if( bLuxel[ 0 ] < 0.0f )\r
-                               VectorCopy( aLuxel, bLuxel );\r
-                       else\r
-                       {\r
-                               /* average */\r
-                               VectorAdd( aLuxel, bLuxel, luxel );\r
-                               VectorScale( luxel, 0.5f, luxel );\r
-                               \r
-                               /* debugging code */\r
-                               //%     luxel[ 2 ] += 64.0f;\r
-                               \r
-                               /* copy to both */\r
-                               VectorCopy( luxel, aLuxel );\r
-                               VectorCopy( luxel, bLuxel );\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-\r
-\r
-/*\r
-ApproximateLuxel()\r
-determines if a single luxel is can be approximated with the interpolated vertex rgba\r
-*/\r
-\r
-static qboolean ApproximateLuxel( rawLightmap_t *lm, bspDrawVert_t *dv )\r
-{\r
-       int             i, x, y, d, lightmapNum;\r
-       float   *luxel;\r
-       vec3_t  color, vertexColor;\r
-       byte    cb[ 4 ], vcb[ 4 ];\r
-       \r
-       \r
-       /* find luxel xy coords */\r
-       x = dv->lightmap[ 0 ][ 0 ] / superSample;\r
-       y = dv->lightmap[ 0 ][ 1 ] / superSample;\r
-       if( x < 0 )\r
-               x = 0;\r
-       else if( x >= lm->w )\r
-               x = lm->w - 1;\r
-       if( y < 0 )\r
-               y = 0;\r
-       else if( y >= lm->h )\r
-               y = lm->h - 1;\r
-       \r
-       /* walk list */\r
-       for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )\r
-       {\r
-               /* early out */\r
-               if( lm->styles[ lightmapNum ] == LS_NONE )\r
-                       continue;\r
-               \r
-               /* get luxel */\r
-               luxel = BSP_LUXEL( lightmapNum, x, y );\r
-               \r
-               /* ignore occluded luxels */\r
-               if( luxel[ 0 ] < 0.0f || luxel[ 1 ] < 0.0f || luxel[ 2 ] < 0.0f )\r
-                       return qtrue;\r
-               \r
-               /* copy, set min color and compare */\r
-               VectorCopy( luxel, color );\r
-               VectorCopy( dv->color[ 0 ], vertexColor );\r
-\r
-               /* styles are not affected by minlight */\r
-               if( lightmapNum == 0 )\r
-               {\r
-                       for( i = 0; i < 3; i++ )\r
-                       {\r
-                               /* set min color */\r
-                               if( color[ i ] < minLight[ i ] )\r
-                                       color[ i ] = minLight[ i ];\r
-                               if( vertexColor[ i ] < minLight[ i ] )  /* note NOT minVertexLight */\r
-                                       vertexColor[ i ] = minLight[ i ];\r
-                       }\r
-               }\r
-               \r
-               /* set to bytes */\r
-               ColorToBytes( color, cb, 1.0f );\r
-               ColorToBytes( vertexColor, vcb, 1.0f );\r
-               \r
-               /* compare */\r
-               for( i = 0; i < 3; i++ )\r
-               {\r
-                       d = cb[ i ] - vcb[ i ];\r
-                       if( d < 0 )\r
-                               d *= -1;\r
-                       if( d > approximateTolerance )\r
-                               return qfalse;\r
-               }\r
-       }\r
-       \r
-       /* close enough for the girls i date */\r
-       return qtrue;\r
-}\r
-\r
-\r
-\r
-/*\r
-ApproximateTriangle()\r
-determines if a single triangle can be approximated with vertex rgba\r
-*/\r
-\r
-static qboolean ApproximateTriangle_r( rawLightmap_t *lm, bspDrawVert_t *dv[ 3 ] )\r
-{\r
-       bspDrawVert_t   mid, *dv2[ 3 ];\r
-       int                             max;\r
-       \r
-       \r
-       /* approximate the vertexes */\r
-       if( ApproximateLuxel( lm, dv[ 0 ] ) == qfalse )\r
-               return qfalse;\r
-       if( ApproximateLuxel( lm, dv[ 1 ] ) == qfalse )\r
-               return qfalse;\r
-       if( ApproximateLuxel( lm, dv[ 2 ] ) == qfalse )\r
-               return qfalse;\r
-       \r
-       /* subdivide calc */\r
-       {\r
-               int                     i;\r
-               float           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
-                       dx = dv[ i ]->lightmap[ 0 ][ 0 ] - dv[ (i + 1) % 3 ]->lightmap[ 0 ][ 0 ];\r
-                       dy = dv[ i ]->lightmap[ 0 ][ 1 ] - dv[ (i + 1) % 3 ]->lightmap[ 0 ][ 1 ];\r
-                       dist = sqrt( (dx * dx) + (dy * dy) );\r
-                       if( dist > maxDist )\r
-                       {\r
-                               maxDist = dist;\r
-                               max = i;\r
-                       }\r
-               }\r
-               \r
-               /* try to early out */\r
-               if( i < 0 || maxDist < subdivideThreshold )\r
-                       return qtrue;\r
-       }\r
-\r
-       /* split the longest edge and map it */\r
-       LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid );\r
-       if( ApproximateLuxel( lm, &mid ) == qfalse )\r
-               return qfalse;\r
-       \r
-       /* recurse to first triangle */\r
-       VectorCopy( dv, dv2 );\r
-       dv2[ max ] = &mid;\r
-       if( ApproximateTriangle_r( lm, dv2 ) == qfalse )\r
-               return qfalse;\r
-       \r
-       /* recurse to second triangle */\r
-       VectorCopy( dv, dv2 );\r
-       dv2[ (max + 1) % 3 ] = &mid;\r
-       return ApproximateTriangle_r( lm, dv2 );\r
-}\r
-\r
-\r
-\r
-/*\r
-ApproximateLightmap()\r
-determines if a raw lightmap can be approximated sufficiently with vertex colors\r
-*/\r
-\r
-static qboolean ApproximateLightmap( rawLightmap_t *lm )\r
-{\r
-       int                                     n, num, i, x, y, pw[ 5 ], r;\r
-       bspDrawSurface_t        *ds;\r
-       surfaceInfo_t           *info;\r
-       mesh_t                          src, *subdivided, *mesh;\r
-       bspDrawVert_t           *verts, *dv[ 3 ];\r
-       qboolean                        approximated;\r
-       \r
-       \r
-       /* approximating? */\r
-       if( approximateTolerance <= 0 )\r
-               return qfalse;\r
-       \r
-       /* test for jmonroe */\r
-       #if 0\r
-               /* don't approx lightmaps with styled twins */\r
-               if( lm->numStyledTwins > 0 )\r
-                       return qfalse;\r
-               \r
-               /* don't approx lightmaps with styles */\r
-               for( i = 1; i < MAX_LIGHTMAPS; i++ )\r
-               {\r
-                       if( lm->styles[ i ] != LS_NONE )\r
-                               return qfalse;\r
-               }\r
-       #endif\r
-       \r
-       /* assume reduced until shadow detail is found */\r
-       approximated = qtrue;\r
-       \r
-       /* walk the list of surfaces on this raw lightmap */\r
-       for( n = 0; n < lm->numLightSurfaces; n++ )\r
-       {\r
-               /* get surface */\r
-               num = lightSurfaces[ lm->firstLightSurface + n ];\r
-               ds = &bspDrawSurfaces[ num ];\r
-               info = &surfaceInfos[ num ];\r
-               \r
-               /* bail if lightmap doesn't match up */\r
-               if( info->lm != lm )\r
-                       continue;\r
-               \r
-               /* assume reduced initially */\r
-               info->approximated = qtrue;\r
-               \r
-               /* assume that surfaces whose bounding boxes is smaller than 2x samplesize will be forced to vertex */\r
-               if( (info->maxs[ 0 ] - info->mins[ 0 ]) <= (2.0f * info->sampleSize) &&\r
-                       (info->maxs[ 1 ] - info->mins[ 1 ]) <= (2.0f * info->sampleSize) &&\r
-                       (info->maxs[ 2 ] - info->mins[ 2 ]) <= (2.0f * info->sampleSize) )\r
-               {\r
-                       numSurfsVertexForced++;\r
-                       continue;\r
-               }\r
-               \r
-               /* handle the triangles */\r
-               switch( ds->surfaceType )\r
-               {\r
-                       case MST_PLANAR:\r
-                               /* get verts */\r
-                               verts = yDrawVerts + ds->firstVert;\r
-                               \r
-                               /* map the triangles */\r
-                               for( i = 0; i < ds->numIndexes && info->approximated; 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
-                                       info->approximated = ApproximateTriangle_r( lm, dv );\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
-                               /* map the mesh quads */\r
-                               for( y = 0; y < (mesh->height - 1) && info->approximated; y++ )\r
-                               {\r
-                                       for( x = 0; x < (mesh->width - 1) && info->approximated; 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
-                                               info->approximated = ApproximateTriangle_r( lm, dv );\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
-                                               if( info->approximated )\r
-                                                       info->approximated = ApproximateTriangle_r( lm, dv );\r
-                                       }\r
-                               }\r
-                               \r
-                               /* free the mesh */\r
-                               FreeMesh( mesh );\r
-                               break;\r
-                       \r
-                       default:\r
-                               break;\r
-               }\r
-               \r
-               /* reduced? */\r
-               if( info->approximated == qfalse )\r
-                       approximated = qfalse;\r
-               else\r
-                       numSurfsVertexApproximated++;\r
-       }\r
-       \r
-       /* return */\r
-       return approximated;\r
-}\r
-\r
-\r
-\r
-/*\r
-TestOutLightmapStamp()\r
-tests a stamp on a given lightmap for validity\r
-*/\r
-\r
-static qboolean TestOutLightmapStamp( rawLightmap_t *lm, int lightmapNum, outLightmap_t *olm, int x, int y )\r
-{\r
-       int                     sx, sy, ox, oy, offset;\r
-       float           *luxel;\r
-\r
-       \r
-       /* bounds check */\r
-       if( x < 0 || y < 0 || (x + lm->w) > olm->customWidth || (y + lm->h) > olm->customHeight )\r
-               return qfalse;\r
-       \r
-       /* test the stamp */\r
-       for( sy = 0; sy < lm->h; sy++ )\r
-       {\r
-               for( sx = 0; sx < lm->w; sx++ )\r
-               {\r
-                       /* get luxel */\r
-                       luxel = BSP_LUXEL( lightmapNum, sx, sy );\r
-                       if( luxel[ 0 ] < 0.0f )\r
-                               continue;\r
-                       \r
-                       /* get bsp lightmap coords and test */\r
-                       ox = x + sx;\r
-                       oy = y + sy;\r
-                       offset = (oy * olm->customWidth) + ox;\r
-                       if( olm->lightBits[ offset >> 3 ] & (1 << (offset & 7)) )\r
-                               return qfalse;\r
-               }\r
-       }\r
-       \r
-       /* stamp is empty */\r
-       return qtrue;\r
-}\r
-\r
-\r
-\r
-/*\r
-SetupOutLightmap()\r
-sets up an output lightmap\r
-*/\r
-\r
-static void SetupOutLightmap( rawLightmap_t *lm, outLightmap_t *olm )\r
-{\r
-       /* dummy check */\r
-       if( lm == NULL || olm == NULL )\r
-               return;\r
-       \r
-       /* is this a "normal" bsp-stored lightmap? */\r
-       if( (lm->customWidth == LIGHTMAP_WIDTH && lm->customHeight == LIGHTMAP_HEIGHT) || externalLightmaps )\r
-       {\r
-               olm->lightmapNum = numBSPLightmaps;\r
-               numBSPLightmaps++;\r
-               \r
-               /* lightmaps are interleaved with light direction maps */\r
-               if( deluxemap )\r
-                       numBSPLightmaps++;\r
-       }\r
-       else\r
-               olm->lightmapNum = -3;\r
-       \r
-       /* set external lightmap number */\r
-       olm->extLightmapNum = -1;\r
-       \r
-       /* set it up */\r
-       olm->numLightmaps = 0;\r
-       olm->customWidth = lm->customWidth;\r
-       olm->customHeight = lm->customHeight;\r
-       olm->freeLuxels = olm->customWidth * olm->customHeight;\r
-       olm->numShaders = 0;\r
-       \r
-       /* allocate buffers */\r
-       olm->lightBits = safe_malloc( (olm->customWidth * olm->customHeight / 8) + 8 );\r
-       memset( olm->lightBits, 0, (olm->customWidth * olm->customHeight / 8) + 8 );\r
-       olm->bspLightBytes = safe_malloc( olm->customWidth * olm->customHeight * 3 );\r
-       memset( olm->bspLightBytes, 0, olm->customWidth * olm->customHeight * 3 );\r
-       if( deluxemap )\r
-       {\r
-               olm->bspDirBytes = safe_malloc( olm->customWidth * olm->customHeight * 3 );\r
-               memset( olm->bspDirBytes, 0, olm->customWidth * olm->customHeight * 3 );\r
-       }\r
-}\r
-\r
-\r
-\r
-/*\r
-FindOutLightmaps()\r
-for a given surface lightmap, find output lightmap pages and positions for it\r
-*/\r
-\r
-static void FindOutLightmaps( rawLightmap_t *lm )\r
-{\r
-       int                                     i, j, lightmapNum, xMax, yMax, x, y, sx, sy, ox, oy, offset, temp;\r
-       outLightmap_t           *olm;\r
-       surfaceInfo_t           *info;\r
-       float                           *luxel, *deluxel;\r
-       vec3_t                          color, direction;\r
-       byte                            *pixel;\r
-       qboolean                        ok;\r
-       \r
-       \r
-       /* set default lightmap number (-3 = LIGHTMAP_BY_VERTEX) */\r
-       for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )\r
-               lm->outLightmapNums[ lightmapNum ] = -3;\r
-               \r
-       /* can this lightmap be approximated with vertex color? */\r
-       if( ApproximateLightmap( lm ) )\r
-               return;\r
-       \r
-       /* walk list */\r
-       for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )\r
-       {\r
-               /* early out */\r
-               if( lm->styles[ lightmapNum ] == LS_NONE )\r
-                       continue;\r
-               \r
-               /* don't store twinned lightmaps */\r
-               if( lm->twins[ lightmapNum ] != NULL )\r
-                       continue;\r
-               \r
-               /* if this is a styled lightmap, try some normalized locations first */\r
-               ok = qfalse;\r
-               if( lightmapNum > 0 && outLightmaps != NULL )\r
-               {\r
-                       /* loop twice */\r
-                       for( j = 0; j < 2; j++ )\r
-                       {\r
-                               /* try identical position */\r
-                               for( i = 0; i < numOutLightmaps; i++ )\r
-                               {\r
-                                       /* get the output lightmap */\r
-                                       olm = &outLightmaps[ i ];\r
-                                       \r
-                                       /* simple early out test */\r
-                                       if( olm->freeLuxels < lm->used )\r
-                                               continue;\r
-                                       \r
-                                       /* don't store non-custom raw lightmaps on custom bsp lightmaps */\r
-                                       if( olm->customWidth != lm->customWidth ||\r
-                                               olm->customHeight != lm->customHeight )\r
-                                               continue;\r
-                                       \r
-                                       /* try identical */\r
-                                       if( j == 0 )\r
-                                       {\r
-                                               x = lm->lightmapX[ 0 ];\r
-                                               y = lm->lightmapY[ 0 ];\r
-                                               ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );\r
-                                       }\r
-                                       \r
-                                       /* try shifting */\r
-                                       else\r
-                                       {\r
-                                               for( sy = -1; sy <= 1; sy++ )\r
-                                               {\r
-                                                       for( sx = -1; sx <= 1; sx++ )\r
-                                                       {\r
-                                                               x = lm->lightmapX[ 0 ] + sx * (olm->customWidth >> 1);  //%     lm->w;\r
-                                                               y = lm->lightmapY[ 0 ] + sy * (olm->customHeight >> 1); //%     lm->h;\r
-                                                               ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );\r
-\r
-                                                               if( ok )\r
-                                                                       break;\r
-                                                       }\r
-                                                       \r
-                                                       if( ok )\r
-                                                               break;\r
-                                               }\r
-                                       }\r
-                                       \r
-                                       if( ok )\r
-                                               break;\r
-                               }\r
-                               \r
-                               if( ok )\r
-                                       break;\r
-                       }\r
-               }\r
-               \r
-               /* try normal placement algorithm */\r
-               if( ok == qfalse )\r
-               {\r
-                       /* reset origin */\r
-                       x = 0;\r
-                       y = 0;\r
-                       \r
-                       /* walk the list of lightmap pages */\r
-                       for( i = 0; i < numOutLightmaps; i++ )\r
-                       {\r
-                               /* get the output lightmap */\r
-                               olm = &outLightmaps[ i ];\r
-                               \r
-                               /* simple early out test */\r
-                               if( olm->freeLuxels < lm->used )\r
-                                       continue;\r
-                               \r
-                               /* don't store non-custom raw lightmaps on custom bsp lightmaps */\r
-                               if( olm->customWidth != lm->customWidth ||\r
-                                       olm->customHeight != lm->customHeight )\r
-                                       continue;\r
-                               \r
-                               /* set maxs */\r
-                               xMax = (olm->customWidth - lm->w) + 1;\r
-                               yMax = (olm->customHeight - lm->h) + 1;\r
-                               \r
-                               /* walk the origin around the lightmap */\r
-                               for( y = 0; y < yMax; y++ )\r
-                               {\r
-                                       for( x = 0; x < xMax; x++ )\r
-                                       {\r
-                                               /* find a fine tract of lauhnd */\r
-                                               ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );\r
-                                               \r
-                                               if( ok )\r
-                                                       break;\r
-                                       }\r
-                                       \r
-                                       if( ok )\r
-                                               break;\r
-                               }\r
-                               \r
-                               if( ok )\r
-                                       break;\r
-                               \r
-                               /* reset x and y */\r
-                               x = 0;\r
-                               y = 0;\r
-                       }\r
-               }\r
-               \r
-               /* no match? */\r
-               if( ok == qfalse )\r
-               {\r
-                       /* allocate two new output lightmaps */\r
-                       numOutLightmaps += 2;\r
-                       olm = safe_malloc( numOutLightmaps * sizeof( outLightmap_t ) );\r
-                       if( outLightmaps != NULL && numOutLightmaps > 2 )\r
-                       {\r
-                               memcpy( olm, outLightmaps, (numOutLightmaps - 2) * sizeof( outLightmap_t ) );\r
-                               free( outLightmaps );\r
-                       }\r
-                       outLightmaps = olm;\r
-                       \r
-                       /* initialize both out lightmaps */\r
-                       SetupOutLightmap( lm, &outLightmaps[ numOutLightmaps - 2 ] );\r
-                       SetupOutLightmap( lm, &outLightmaps[ numOutLightmaps - 1 ] );\r
-                       \r
-                       /* set out lightmap */\r
-                       i = numOutLightmaps - 2;\r
-                       olm = &outLightmaps[ i ];\r
-                       \r
-                       /* set stamp xy origin to the first surface lightmap */\r
-                       if( lightmapNum > 0 )\r
-                       {\r
-                               x = lm->lightmapX[ 0 ];\r
-                               y = lm->lightmapY[ 0 ];\r
-                       }\r
-               }\r
-               \r
-               /* if this is a style-using lightmap, it must be exported */\r
-               if( lightmapNum > 0 )\r
-                       olm->extLightmapNum = 0;\r
-               \r
-               /* add the surface lightmap to the bsp lightmap */\r
-               lm->outLightmapNums[ lightmapNum ] = i;\r
-               lm->lightmapX[ lightmapNum ] = x;\r
-               lm->lightmapY[ lightmapNum ] = y;\r
-               olm->numLightmaps++;\r
-               \r
-               /* add shaders */\r
-               for( i = 0; i < lm->numLightSurfaces; i++ )\r
-               {\r
-                       /* get surface info */\r
-                       info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + i ] ];\r
-                       \r
-                       /* test for shader */\r
-                       for( j = 0; j < olm->numShaders; j++ )\r
-                       {\r
-                               if( olm->shaders[ j ] == info->si )\r
-                                       break;\r
-                       }\r
-                       \r
-                       /* if it doesn't exist, add it */\r
-                       if( j >= olm->numShaders && olm->numShaders < MAX_LIGHTMAP_SHADERS )\r
-                       {\r
-                               olm->shaders[ olm->numShaders ] = info->si;\r
-                               olm->numShaders++;\r
-                               numLightmapShaders++;\r
-                       }\r
-               }\r
-               \r
-               /* mark the bits used */\r
-               for( y = 0; y < lm->h; y++ )\r
-               {\r
-                       for( x = 0; x < lm->w; x++ )\r
-                       {\r
-                               /* get luxel */\r
-                               luxel = BSP_LUXEL( lightmapNum, x, y );\r
-                               deluxel = BSP_DELUXEL( x, y );\r
-                               if( luxel[ 0 ] < 0.0f )\r
-                                       continue;\r
-                               \r
-                               /* set minimum light */\r
-                               VectorCopy( luxel, color );\r
-\r
-                               /* styles are not affected by minlight */\r
-                               if( lightmapNum == 0 )\r
-                               {\r
-                                       for( i = 0; i < 3; i++ )\r
-                                       {\r
-                                               if( color[ i ] < minLight[ i ] )\r
-                                                       color[ i ] = minLight[ i ];\r
-                                       }\r
-                               }\r
-                               \r
-                               /* get bsp lightmap coords  */\r
-                               ox = x + lm->lightmapX[ lightmapNum ];\r
-                               oy = y + lm->lightmapY[ lightmapNum ];\r
-                               offset = (oy * olm->customWidth) + ox;\r
-                               \r
-                               /* flag pixel as used */\r
-                               olm->lightBits[ offset >> 3 ] |= (1 << (offset & 7));\r
-                               olm->freeLuxels--;\r
-                               \r
-                               /* store color */\r
-                               pixel = olm->bspLightBytes + (((oy * olm->customWidth) + ox) * 3);\r
-                               ColorToBytes( color, pixel, lm->gamma );\r
-                               \r
-                               /* store direction */\r
-                               if( deluxemap )\r
-                               {\r
-                                       /* normalize average light direction */\r
-                                       if( VectorNormalize( deluxel, direction ) )\r
-                                       {\r
-                                               /* encode [-1,1] in [0,255] */\r
-                                               pixel = olm->bspDirBytes + (((oy * olm->customWidth) + ox) * 3);\r
-                                               for( i = 0; i < 3; i++ )\r
-                                               {\r
-                                                       temp = (direction[ i ] + 1.0f) * 127.5f;\r
-                                                       if( temp < 0 )\r
-                                                               pixel[ i ] = 0;\r
-                                                       else if( temp > 255 )\r
-                                                               pixel[ i ] = 255;\r
-                                                       else\r
-                                                               pixel[ i ] = temp;\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-}\r
-\r
-\r
-\r
-/*\r
-CompareRawLightmap()\r
-compare function for qsort()\r
-*/\r
-\r
-static int CompareRawLightmap( const void *a, const void *b )\r
-{\r
-       rawLightmap_t   *alm, *blm;\r
-       surfaceInfo_t   *aInfo, *bInfo;\r
-       int                             i, min, diff;\r
-       \r
-       \r
-       /* get lightmaps */\r
-       alm = &rawLightmaps[ *((int*) a) ];\r
-       blm = &rawLightmaps[ *((int*) b) ];\r
-       \r
-       /* get min number of surfaces */\r
-       min = (alm->numLightSurfaces < blm->numLightSurfaces ? alm->numLightSurfaces : blm->numLightSurfaces);\r
-       \r
-       /* iterate */\r
-       for( i = 0; i < min; i++ )\r
-       {\r
-               /* get surface info */\r
-               aInfo = &surfaceInfos[ lightSurfaces[ alm->firstLightSurface + i ] ];\r
-               bInfo = &surfaceInfos[ lightSurfaces[ blm->firstLightSurface + i ] ];\r
-               \r
-               /* compare shader names */\r
-               diff = strcmp( aInfo->si->shader, bInfo->si->shader );\r
-               if( diff != 0 )\r
-                       return diff;\r
-       }\r
-\r
-       /* test style count */\r
-       diff = 0;\r
-       for( i = 0; i < MAX_LIGHTMAPS; i++ )\r
-               diff += blm->styles[ i ] - alm->styles[ i ];\r
-       if( diff )\r
-               return diff;\r
-       \r
-       /* compare size */\r
-       diff = (blm->w * blm->h) - (alm->w * alm->h);\r
-       if( diff != 0 )\r
-               return diff;\r
-       \r
-       /* must be equivalent */\r
-       return 0;\r
-}\r
-\r
-\r
-\r
-/*\r
-StoreSurfaceLightmaps()\r
-stores the surface lightmaps into the bsp as byte rgb triplets\r
-*/\r
-\r
-void StoreSurfaceLightmaps( void )\r
-{\r
-       int                                     i, j, k, x, y, lx, ly, sx, sy, *cluster, mappedSamples;\r
-       int                                     style, size, lightmapNum, lightmapNum2;\r
-       float                           *normal, *luxel, *bspLuxel, *bspLuxel2, *radLuxel, samples, occludedSamples;\r
-       vec3_t                          sample, occludedSample, dirSample;\r
-       float                           *deluxel, *bspDeluxel, *bspDeluxel2;\r
-       byte                            *lb;\r
-       int                                     numUsed, numTwins, numTwinLuxels, numStored;\r
-       float                           lmx, lmy, efficiency;\r
-       vec3_t                          color;\r
-       bspDrawSurface_t        *ds, *parent, dsTemp;\r
-       surfaceInfo_t           *info;\r
-       rawLightmap_t           *lm, *lm2;\r
-       outLightmap_t           *olm;\r
-       bspDrawVert_t           *dv, *ydv, *dvParent;\r
-       char                            dirname[ 1024 ], filename[ 1024 ];\r
-       shaderInfo_t            *csi;\r
-       char                            lightmapName[ 128 ];\r
-       char                            *rgbGenValues[ 256 ];\r
-       char                            *alphaGenValues[ 256 ];\r
-       \r
-       \r
-       /* note it */\r
-       Sys_Printf( "--- StoreSurfaceLightmaps ---\n");\r
-       \r
-       /* setup */\r
-       strcpy( dirname, source );\r
-       StripExtension( dirname );\r
-       memset( rgbGenValues, 0, sizeof( rgbGenValues ) );\r
-       memset( alphaGenValues, 0, sizeof( alphaGenValues ) );\r
-       \r
-       /* -----------------------------------------------------------------\r
-          average the sampled luxels into the bsp luxels\r
-          ----------------------------------------------------------------- */\r
-       \r
-       /* note it */\r
-       Sys_FPrintf( SYS_VRB, "Subsampling..." );\r
-       \r
-       /* walk the list of raw lightmaps */\r
-       numUsed = 0;\r
-       numTwins = 0;\r
-       numTwinLuxels = 0;\r
-       for( i = 0; i < numRawLightmaps; i++ )\r
-       {\r
-               /* get lightmap */\r
-               lm = &rawLightmaps[ i ];\r
-               \r
-               /* walk individual lightmaps */\r
-               for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )\r
-               {\r
-                       /* early outs */\r
-                       if( lm->superLuxels[ lightmapNum ] == NULL )\r
-                               continue;\r
-                       \r
-                       /* allocate bsp luxel storage */\r
-                       if( lm->bspLuxels[ lightmapNum ] == NULL )\r
-                       {\r
-                               size = lm->w * lm->h * BSP_LUXEL_SIZE * sizeof( float );\r
-                               lm->bspLuxels[ lightmapNum ] = safe_malloc( size );\r
-                               memset( lm->bspLuxels[ lightmapNum ], 0, size );\r
-                       }\r
-\r
-                       /* allocate radiosity lightmap storage */\r
-                       if( bounce )\r
-                       {\r
-                               size = lm->w * lm->h * RAD_LUXEL_SIZE * sizeof( float );\r
-                               if( lm->radLuxels[ lightmapNum ] == NULL )\r
-                                       lm->radLuxels[ lightmapNum ] = safe_malloc( size );\r
-                               memset( lm->radLuxels[ lightmapNum ], 0, size );\r
-                       }\r
-                       \r
-                       /* average supersampled luxels */\r
-                       for( y = 0; y < lm->h; y++ )\r
-                       {\r
-                               for( x = 0; x < lm->w; x++ )\r
-                               {\r
-                                       /* subsample */\r
-                                       samples = 0.0f;\r
-                                       occludedSamples = 0.0f;\r
-                                       mappedSamples = 0;\r
-                                       VectorClear( sample );\r
-                                       VectorClear( occludedSample );\r
-                                       VectorClear( dirSample );\r
-                                       for( ly = 0; ly < superSample; ly++ )\r
-                                       {\r
-                                               for( lx = 0; lx < superSample; lx++ )\r
-                                               {\r
-                                                       /* sample luxel */\r
-                                                       sx = x * superSample + lx;\r
-                                                       sy = y * superSample + ly;\r
-                                                       luxel = SUPER_LUXEL( lightmapNum, sx, sy );\r
-                                                       deluxel = SUPER_DELUXEL( sx, sy );\r
-                                                       normal = SUPER_NORMAL( sx, sy );\r
-                                                       cluster = SUPER_CLUSTER( sx, sy );\r
-                                                       \r
-                                                       /* sample deluxemap */\r
-                                                       if( deluxemap && lightmapNum == 0 )\r
-                                                               VectorAdd( dirSample, deluxel, dirSample );\r
-                                                       \r
-                                                       /* keep track of used/occluded samples */\r
-                                                       if( *cluster != CLUSTER_UNMAPPED )\r
-                                                               mappedSamples++;\r
-                                                       \r
-                                                       /* handle lightmap border? */\r
-                                                       if( lightmapBorder && (sx == 0 || sx == (lm->sw - 1) || sy == 0 || sy == (lm->sh - 1) ) && luxel[ 3 ] > 0.0f )\r
-                                                       {\r
-                                                               VectorSet( sample, 255.0f, 0.0f, 0.0f );\r
-                                                               samples += 1.0f;\r
-                                                       }\r
-                                                       \r
-                                                       /* handle debug */\r
-                                                       else if( debug && *cluster < 0 )\r
-                                                       {\r
-                                                               if( *cluster == CLUSTER_UNMAPPED )\r
-                                                                       VectorSet( luxel, 255, 204, 0 );\r
-                                                               else if( *cluster == CLUSTER_OCCLUDED )\r
-                                                                       VectorSet( luxel, 255, 0, 255 );\r
-                                                               else if( *cluster == CLUSTER_FLOODED )\r
-                                                                       VectorSet( luxel, 0, 32, 255 );\r
-                                                               VectorAdd( occludedSample, luxel, occludedSample );\r
-                                                               occludedSamples += 1.0f;\r
-                                                       }\r
-                                                       \r
-                                                       /* normal luxel handling */\r
-                                                       else if( luxel[ 3 ] > 0.0f )\r
-                                                       {\r
-                                                               /* handle lit or flooded luxels */\r
-                                                               if( *cluster > 0 || *cluster == CLUSTER_FLOODED )\r
-                                                               {\r
-                                                                       VectorAdd( sample, luxel, sample );\r
-                                                                       samples += luxel[ 3 ];\r
-                                                               }\r
-                                                               \r
-                                                               /* handle occluded or unmapped luxels */\r
-                                                               else\r
-                                                               {\r
-                                                                       VectorAdd( occludedSample, luxel, occludedSample );\r
-                                                                       occludedSamples += luxel[ 3 ];\r
-                                                               }\r
-                                                               \r
-                                                               /* handle style debugging */\r
-                                                               if( debug && lightmapNum > 0 && x < 2 && y < 2 )\r
-                                                               {\r
-                                                                       VectorCopy( debugColors[ 0 ], sample );\r
-                                                                       samples = 1;\r
-                                                               }\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                                       \r
-                                       /* only use occluded samples if necessary */\r
-                                       if( samples <= 0.0f )\r
-                                       {\r
-                                               VectorCopy( occludedSample, sample );\r
-                                               samples = occludedSamples;\r
-                                       }\r
-                                       \r
-                                       /* get luxels */\r
-                                       luxel = SUPER_LUXEL( lightmapNum, x, y );\r
-                                       deluxel = SUPER_DELUXEL( x, y );\r
-                                       \r
-                                       /* store light direction */\r
-                                       if( deluxemap && lightmapNum == 0 )\r
-                                               VectorCopy( dirSample, deluxel );\r
-                                       \r
-                                       /* store the sample back in super luxels */\r
-                                       if( samples > 0.01f )\r
-                                       {\r
-                                               VectorScale( sample, (1.0f / samples), luxel );\r
-                                               luxel[ 3 ] = 1.0f;\r
-                                       }\r
-                                       \r
-                                       /* if any samples were mapped in any way, store ambient color */\r
-                                       else if( mappedSamples > 0 )\r
-                                       {\r
-                                               if( lightmapNum == 0 )\r
-                                                       VectorCopy( ambientColor, luxel );\r
-                                               else\r
-                                                       VectorClear( luxel );\r
-                                               luxel[ 3 ] = 1.0f;\r
-                                       }\r
-                                       \r
-                                       /* store a bogus value to be fixed later */     \r
-                                       else\r
-                                       {\r
-                                               VectorClear( luxel );\r
-                                               luxel[ 3 ] = -1.0f;\r
-                                       }\r
-                               }\r
-                       }\r
-                       \r
-                       /* clean up and store into bsp luxels */\r
-                       lm->used = 0;\r
-                       for( y = 0; y < lm->h; y++ )\r
-                       {\r
-                               for( x = 0; x < lm->w; x++ )\r
-                               {\r
-                                       /* get luxels */\r
-                                       luxel = SUPER_LUXEL( lightmapNum, x, y );\r
-                                       deluxel = SUPER_DELUXEL( x, y );\r
-                                       \r
-                                       /* copy light direction */\r
-                                       if( deluxemap && lightmapNum == 0 )\r
-                                               VectorCopy( deluxel, dirSample );\r
-                                       \r
-                                       /* is this a valid sample? */\r
-                                       if( luxel[ 3 ] > 0.0f )\r
-                                       {\r
-                                               VectorCopy( luxel, sample );\r
-                                               samples = luxel[ 3 ];\r
-                                               numUsed++;\r
-                                               lm->used++;\r
-                                               \r
-                                               /* fix negative samples */\r
-                                               for( j = 0; j < 3; j++ )\r
-                                               {\r
-                                                       if( sample[ j ] < 0.0f )\r
-                                                               sample[ j ] = 0.0f;\r
-                                               }\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               /* nick an average value from the neighbors */\r
-                                               VectorClear( sample );\r
-                                               VectorClear( dirSample );\r
-                                               samples = 0.0f;\r
-                                               \r
-                                               /* fixme: why is this disabled?? */\r
-                                               for( sy = (y - 1); sy <= (y + 1); sy++ )\r
-                                               {\r
-                                                       if( sy < 0 || sy >= lm->h )\r
-                                                               continue;\r
-                                                       \r
-                                                       for( sx = (x - 1); sx <= (x + 1); sx++ )\r
-                                                       {\r
-                                                               if( sx < 0 || sx >= lm->w || (sx == x && sy == y) )\r
-                                                                       continue;\r
-                                                               \r
-                                                               /* get neighbor's particulars */\r
-                                                               luxel = SUPER_LUXEL( lightmapNum, sx, sy );\r
-                                                               if( luxel[ 3 ] < 0.0f )\r
-                                                                       continue;\r
-                                                               VectorAdd( sample, luxel, sample );\r
-                                                               samples += luxel[ 3 ];\r
-                                                       }\r
-                                               }\r
-                                               \r
-                                               /* no samples? */\r
-                                               if( samples == 0.0f )\r
-                                               {\r
-                                                       VectorSet( sample, -1.0f, -1.0f, -1.0f );\r
-                                                       samples = 1.0f;\r
-                                               }\r
-                                               else\r
-                                               {\r
-                                                       numUsed++;\r
-                                                       lm->used++;\r
-                                                       \r
-                                                       /* fix negative samples */\r
-                                                       for( j = 0; j < 3; j++ )\r
-                                                       {\r
-                                                               if( sample[ j ] < 0.0f )\r
-                                                                       sample[ j ] = 0.0f;\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                                       \r
-                                       /* scale the sample */\r
-                                       VectorScale( sample, (1.0f / samples), sample );\r
-                                       \r
-                                       /* store the sample in the radiosity luxels */\r
-                                       if( bounce > 0 )\r
-                                       {\r
-                                               radLuxel = RAD_LUXEL( lightmapNum, x, y );\r
-                                               VectorCopy( sample, radLuxel );\r
-                                               \r
-                                               /* if only storing bounced light, early out here */\r
-                                               if( bounceOnly && !bouncing )\r
-                                                       continue;\r
-                                       }\r
-                                       \r
-                                       /* store the sample in the bsp luxels */\r
-                                       bspLuxel = BSP_LUXEL( lightmapNum, x, y );\r
-                                       bspDeluxel = BSP_DELUXEL( x, y );\r
-                                       \r
-                                       VectorAdd( bspLuxel, sample, bspLuxel );\r
-                                       if( deluxemap && lightmapNum == 0 )\r
-                                               VectorAdd( bspDeluxel, dirSample, bspDeluxel );\r
-                               }\r
-                       }\r
-                       \r
-                       /* wrap bsp luxels if necessary */\r
-                       if( lm->wrap[ 0 ] )\r
-                       {\r
-                               for( y = 0; y < lm->h; y++ )\r
-                               {\r
-                                       bspLuxel = BSP_LUXEL( lightmapNum, 0, y );\r
-                                       bspLuxel2 = BSP_LUXEL( lightmapNum, lm->w - 1, y );\r
-                                       VectorAdd( bspLuxel, bspLuxel2, bspLuxel );\r
-                                       VectorScale( bspLuxel, 0.5f, bspLuxel );\r
-                                       VectorCopy( bspLuxel, bspLuxel2 );\r
-                                       if( deluxemap && lightmapNum == 0 )\r
-                                       {\r
-                                               bspDeluxel = BSP_DELUXEL( 0, y );\r
-                                               bspDeluxel2 = BSP_DELUXEL( lm->w - 1, y );\r
-                                               VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel );\r
-                                               VectorScale( bspDeluxel, 0.5f, bspDeluxel );\r
-                                               VectorCopy( bspDeluxel, bspDeluxel2 );\r
-                                       }\r
-                               }\r
-                       }\r
-                       if( lm->wrap[ 1 ] )\r
-                       {\r
-                               for( x = 0; x < lm->w; x++ )\r
-                               {\r
-                                       bspLuxel = BSP_LUXEL( lightmapNum, x, 0 );\r
-                                       bspLuxel2 = BSP_LUXEL( lightmapNum, x, lm->h - 1 );\r
-                                       VectorAdd( bspLuxel, bspLuxel2, bspLuxel );\r
-                                       VectorScale( bspLuxel, 0.5f, bspLuxel );\r
-                                       VectorCopy( bspLuxel, bspLuxel2 );\r
-                                       if( deluxemap && lightmapNum == 0 )\r
-                                       {\r
-                                               bspDeluxel = BSP_DELUXEL( x, 0 );\r
-                                               bspDeluxel2 = BSP_DELUXEL( x, lm->h - 1 );\r
-                                               VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel );\r
-                                               VectorScale( bspDeluxel, 0.5f, bspDeluxel );\r
-                                               VectorCopy( bspDeluxel, bspDeluxel2 );\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       \r
-       /* -----------------------------------------------------------------\r
-          collapse non-unique lightmaps\r
-          ----------------------------------------------------------------- */\r
-       \r
-       if( noCollapse == qfalse && deluxemap == qfalse )\r
-       {\r
-               /* note it */\r
-               Sys_FPrintf( SYS_VRB, "collapsing..." );\r
-               \r
-               /* set all twin refs to null */\r
-               for( i = 0; i < numRawLightmaps; i++ )\r
-               {\r
-                       for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )\r
-                       {\r
-                               rawLightmaps[ i ].twins[ lightmapNum ] = NULL;\r
-                               rawLightmaps[ i ].twinNums[ lightmapNum ] = -1;\r
-                               rawLightmaps[ i ].numStyledTwins = 0;\r
-                       }\r
-               }\r
-               \r
-               /* walk the list of raw lightmaps */\r
-               for( i = 0; i < numRawLightmaps; i++ )\r
-               {\r
-                       /* get lightmap */\r
-                       lm = &rawLightmaps[ i ];\r
-                       \r
-                       /* walk lightmaps */\r
-                       for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )\r
-                       {\r
-                               /* early outs */\r
-                               if( lm->bspLuxels[ lightmapNum ] == NULL ||\r
-                                       lm->twins[ lightmapNum ] != NULL )\r
-                                       continue;\r
-                               \r
-                               /* find all lightmaps that are virtually identical to this one */\r
-                               for( j = i + 1; j < numRawLightmaps; j++ )\r
-                               {\r
-                                       /* get lightmap */\r
-                                       lm2 = &rawLightmaps[ j ];\r
-                                       \r
-                                       /* walk lightmaps */\r
-                                       for( lightmapNum2 = 0; lightmapNum2 < MAX_LIGHTMAPS; lightmapNum2++ )\r
-                                       {\r
-                                               /* early outs */\r
-                                               if( lm2->bspLuxels[ lightmapNum2 ] == NULL ||\r
-                                                       lm2->twins[ lightmapNum2 ] != NULL )\r
-                                                       continue;\r
-                                               \r
-                                               /* compare them */\r
-                                               if( CompareBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ) )\r
-                                               {\r
-                                                       /* merge and set twin */\r
-                                                       MergeBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 );\r
-                                                       lm2->twins[ lightmapNum2 ] = lm;\r
-                                                       lm2->twinNums[ lightmapNum2 ] = lightmapNum;\r
-                                                       numTwins++;\r
-                                                       numTwinLuxels += (lm->w * lm->h);\r
-                                                       \r
-                                                       /* count styled twins */\r
-                                                       if( lightmapNum > 0 )\r
-                                                               lm->numStyledTwins++;\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       \r
-       /* -----------------------------------------------------------------\r
-          sort raw lightmaps by shader\r
-          ----------------------------------------------------------------- */\r
-       \r
-       /* note it */\r
-       Sys_FPrintf( SYS_VRB, "sorting..." );\r
-       \r
-       /* allocate a new sorted list */\r
-       if( sortLightmaps == NULL )\r
-               sortLightmaps = safe_malloc( numRawLightmaps * sizeof( int ) );\r
-       \r
-       /* fill it out and sort it */\r
-       for( i = 0; i < numRawLightmaps; i++ )\r
-               sortLightmaps[ i ] = i;\r
-       qsort( sortLightmaps, numRawLightmaps, sizeof( int ), CompareRawLightmap );\r
-       \r
-       /* -----------------------------------------------------------------\r
-          allocate output lightmaps\r
-          ----------------------------------------------------------------- */\r
-       \r
-       /* note it */\r
-       Sys_FPrintf( SYS_VRB, "allocating..." );\r
-       \r
-       /* kill all existing output lightmaps */\r
-       if( outLightmaps != NULL )\r
-       {\r
-               for( i = 0; i < numOutLightmaps; i++ )\r
-               {\r
-                       free( outLightmaps[ i ].lightBits );\r
-                       free( outLightmaps[ i ].bspLightBytes );\r
-               }\r
-               free( outLightmaps );\r
-               outLightmaps = NULL;\r
-       }\r
-       \r
-       numLightmapShaders = 0;\r
-       numOutLightmaps = 0;\r
-       numBSPLightmaps = 0;\r
-       numExtLightmaps = 0;\r
-       \r
-       /* find output lightmap */\r
-       for( i = 0; i < numRawLightmaps; i++ )\r
-       {\r
-               lm = &rawLightmaps[ sortLightmaps[ i ] ];\r
-               FindOutLightmaps( lm );\r
-       }\r
-       \r
-       /* set output numbers in twinned lightmaps */\r
-       for( i = 0; i < numRawLightmaps; i++ )\r
-       {\r
-               /* get lightmap */\r
-               lm = &rawLightmaps[ sortLightmaps[ i ] ];\r
-               \r
-               /* walk lightmaps */\r
-               for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )\r
-               {\r
-                       /* get twin */\r
-                       lm2 = lm->twins[ lightmapNum ];\r
-                       if( lm2 == NULL )\r
-                               continue;\r
-                       lightmapNum2 = lm->twinNums[ lightmapNum ];\r
-                       \r
-                       /* find output lightmap from twin */\r
-                       lm->outLightmapNums[ lightmapNum ] = lm2->outLightmapNums[ lightmapNum2 ];\r
-                       lm->lightmapX[ lightmapNum ] = lm2->lightmapX[ lightmapNum2 ];\r
-                       lm->lightmapY[ lightmapNum ] = lm2->lightmapY[ lightmapNum2 ];\r
-               }\r
-       }\r
-       \r
-       /* -----------------------------------------------------------------\r
-          store output lightmaps\r
-          ----------------------------------------------------------------- */\r
-       \r
-       /* note it */\r
-       Sys_FPrintf( SYS_VRB, "storing..." );\r
-       \r
-       /* count the bsp lightmaps and allocate space */\r
-       if( bspLightBytes != NULL )\r
-               free( bspLightBytes );\r
-       if( numBSPLightmaps == 0 || externalLightmaps )\r
-       {\r
-               numBSPLightBytes = 0;\r
-               bspLightBytes = NULL;\r
-       }\r
-       else\r
-       {\r
-               numBSPLightBytes = (numBSPLightmaps * LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 3);\r
-               bspLightBytes = safe_malloc( numBSPLightBytes );\r
-               memset( bspLightBytes, 0, numBSPLightBytes );\r
-       }\r
-       \r
-       /* walk the list of output lightmaps */\r
-       for( i = 0; i < numOutLightmaps; i++ )\r
-       {\r
-               /* get output lightmap */\r
-               olm = &outLightmaps[ i ];\r
-               \r
-               /* is this a valid bsp lightmap? */\r
-               if( olm->lightmapNum >= 0 && !externalLightmaps )\r
-               {\r
-                       /* copy lighting data */\r
-                       lb = bspLightBytes + (olm->lightmapNum * LIGHTMAP_HEIGHT * LIGHTMAP_WIDTH * 3);\r
-                       memcpy( lb, olm->bspLightBytes, LIGHTMAP_HEIGHT * LIGHTMAP_WIDTH * 3 );\r
-                       \r
-                       /* copy direction data */\r
-                       if( deluxemap )\r
-                       {\r
-                               lb = bspLightBytes + ((olm->lightmapNum + 1) * LIGHTMAP_HEIGHT * LIGHTMAP_WIDTH * 3);\r
-                               memcpy( lb, olm->bspDirBytes, LIGHTMAP_HEIGHT * LIGHTMAP_WIDTH * 3 );\r
-                       }\r
-               }\r
-               \r
-               /* external lightmap? */\r
-               if( olm->lightmapNum < 0 || olm->extLightmapNum >= 0 || externalLightmaps )\r
-               {\r
-                       /* make a directory for the lightmaps */\r
-                       Q_mkdir( dirname );\r
-                       \r
-                       /* set external lightmap number */\r
-                       olm->extLightmapNum = numExtLightmaps;\r
-                       \r
-                       /* write lightmap */\r
-                       sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );\r
-                       Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );\r
-                       WriteTGA24( filename, olm->bspLightBytes, olm->customWidth, olm->customHeight, qtrue );\r
-                       numExtLightmaps++;\r
-                       \r
-                       /* write deluxemap */\r
-                       if( deluxemap )\r
-                       {\r
-                               sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );\r
-                               Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );\r
-                               WriteTGA24( filename, olm->bspDirBytes, olm->customWidth, olm->customHeight, qtrue );\r
-                               numExtLightmaps++;\r
-                               \r
-                               if( debugDeluxemap )\r
-                                       olm->extLightmapNum++;\r
-                       }\r
-               }\r
-       }\r
-       \r
-       if( numExtLightmaps > 0 )\r
-               Sys_FPrintf( SYS_VRB, "\n" );\r
-       \r
-       /* delete unused external lightmaps */\r
-       for( i = numExtLightmaps; i; i++ )\r
-       {\r
-               /* determine if file exists */\r
-               sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, i );\r
-               if( !FileExists( filename ) )\r
-                       break;\r
-               \r
-               /* delete it */\r
-               remove( filename );\r
-       }\r
-       \r
-       /* -----------------------------------------------------------------\r
-          project the lightmaps onto the bsp surfaces\r
-          ----------------------------------------------------------------- */\r
-       \r
-       /* note it */\r
-       Sys_FPrintf( SYS_VRB, "projecting..." );\r
-       \r
-       /* walk the list of surfaces */\r
-       for( i = 0; i < numBSPDrawSurfaces; i++ )\r
-       {\r
-               /* get the surface and info */\r
-               ds = &bspDrawSurfaces[ i ];\r
-               info = &surfaceInfos[ i ];\r
-               lm = info->lm;\r
-               olm = NULL;\r
-               \r
-               /* handle surfaces with identical parent */\r
-               if( info->parentSurfaceNum >= 0 )\r
-               {\r
-                       /* preserve original data and get parent */\r
-                       parent = &bspDrawSurfaces[ info->parentSurfaceNum ];\r
-                       memcpy( &dsTemp, ds, sizeof( *ds ) );\r
-                       \r
-                       /* overwrite child with parent data */\r
-                       memcpy( ds, parent, sizeof( *ds ) );\r
-                       \r
-                       /* restore key parts */\r
-                       ds->fogNum = dsTemp.fogNum;\r
-                       ds->firstVert = dsTemp.firstVert;\r
-                       ds->firstIndex = dsTemp.firstIndex;\r
-                       memcpy( ds->lightmapVecs, dsTemp.lightmapVecs, sizeof( dsTemp.lightmapVecs ) );\r
-                       \r
-                       /* set vertex data */\r
-                       dv = &bspDrawVerts[ ds->firstVert ];\r
-                       dvParent = &bspDrawVerts[ parent->firstVert ];\r
-                       for( j = 0; j < ds->numVerts; j++ )\r
-                       {\r
-                               memcpy( dv[ j ].lightmap, dvParent[ j ].lightmap, sizeof( dv[ j ].lightmap ) );\r
-                               memcpy( dv[ j ].color, dvParent[ j ].color, sizeof( dv[ j ].color ) );\r
-                       }\r
-                       \r
-                       /* skip the rest */\r
-                       continue;\r
-               }\r
-               \r
-               /* handle vertex lit or approximated surfaces */\r
-               else if( lm == NULL || lm->outLightmapNums[ 0 ] < 0 )\r
-               {\r
-                       for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )\r
-                       {\r
-                               ds->lightmapNum[ lightmapNum ] = -3;\r
-                               ds->lightmapStyles[ lightmapNum ] = ds->vertexStyles[ lightmapNum ];\r
-                       }\r
-               }\r
-               \r
-               /* handle lightmapped surfaces */\r
-               else\r
-               {\r
-                       /* walk lightmaps */\r
-                       for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )\r
-                       {\r
-                               /* set style */\r
-                               ds->lightmapStyles[ lightmapNum ] = lm->styles[ lightmapNum ];\r
-                               \r
-                               /* handle unused style */\r
-                               if( lm->styles[ lightmapNum ] == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 )\r
-                               {\r
-                                       ds->lightmapNum[ lightmapNum ] = -3;\r
-                                       continue;\r
-                               }\r
-                               \r
-                               /* get output lightmap */\r
-                               olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];\r
-                               \r
-                               /* set bsp lightmap number */\r
-                               ds->lightmapNum[ lightmapNum ] = olm->lightmapNum;\r
-                               \r
-                               /* deluxemap debugging makes the deluxemap visible */\r
-                               if( deluxemap && debugDeluxemap && lightmapNum == 0 )\r
-                                       ds->lightmapNum[ lightmapNum ]++;\r
-                               \r
-                               /* calc lightmap origin in texture space */\r
-                               lmx = (float) lm->lightmapX[ lightmapNum ] / (float) olm->customWidth;\r
-                               lmy = (float) lm->lightmapY[ lightmapNum ] / (float) olm->customHeight;\r
-                               \r
-                               /* calc lightmap st coords and store lighting values */\r
-                               dv = &bspDrawVerts[ ds->firstVert ];\r
-                               ydv = &yDrawVerts[ ds->firstVert ];\r
-                               for( j = 0; j < ds->numVerts; j++ )\r
-                               {\r
-                                       dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + (ydv[ j ].lightmap[ 0 ][ 0 ] / (superSample * olm->customWidth));\r
-                                       dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + (ydv[ j ].lightmap[ 0 ][ 1 ] / (superSample * olm->customHeight));\r
-                               }\r
-                       }\r
-               }\r
-               \r
-               /* store vertex colors */\r
-               dv = &bspDrawVerts[ ds->firstVert ];\r
-               for( j = 0; j < ds->numVerts; j++ )\r
-               {\r
-                       /* walk lightmaps */\r
-                       for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )\r
-                       {\r
-                               /* handle unused style */\r
-                               if( ds->vertexStyles[ lightmapNum ] == LS_NONE )\r
-                                       VectorClear( color );\r
-                               else\r
-                               {\r
-                                       /* get vertex color */\r
-                                       luxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + j );\r
-                                       VectorCopy( luxel, color );\r
-                                       \r
-                                       /* set minimum light */\r
-                                       if( lightmapNum == 0 )\r
-                                       {\r
-                                               for( k = 0; k < 3; k++ )\r
-                                                       if( color[ k ] < minVertexLight[ k ] )\r
-                                                               color[ k ] = minVertexLight[ k ];\r
-                                       }\r
-                               }\r
-                               \r
-                               /* store to bytes */\r
-                               ColorToBytes( color, dv[ j ].color[ lightmapNum ], info->si->vertexScale );\r
-                       }\r
-               }\r
-               \r
-               /* surfaces with styled lightmaps and a style marker get a custom generated shader (fixme: make this work with external lightmaps) */\r
-               if( olm != NULL && lm != NULL && lm->styles[ 1 ] != LS_NONE && game->load != LoadRBSPFile )     //%     info->si->styleMarker > 0 )\r
-               {\r
-                       qboolean        dfEqual;\r
-                       char            key[ 32 ], styleStage[ 512 ], styleStages[ 4096 ], rgbGen[ 128 ], alphaGen[ 128 ];\r
-                       \r
-                       \r
-                       /* setup */\r
-                       sprintf( styleStages, "\n\t// Q3Map2 custom lightstyle stage(s)\n" );\r
-                       dv = &bspDrawVerts[ ds->firstVert ];\r
-                       \r
-                       /* depthFunc equal? */\r
-                       if( info->si->styleMarker == 2 || info->si->implicitMap == IM_MASKED )\r
-                               dfEqual = qtrue;\r
-                       else\r
-                               dfEqual = qfalse;\r
-                       \r
-                       /* generate stages for styled lightmaps */\r
-                       for( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )\r
-                       {\r
-                               /* early out */\r
-                               style = lm->styles[ lightmapNum ];\r
-                               if( style == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 )\r
-                                       continue;\r
-                               \r
-                               /* get output lightmap */\r
-                               olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];\r
-                               \r
-                               /* lightmap name */\r
-                               if( lm->outLightmapNums[ lightmapNum ] == lm->outLightmapNums[ 0 ] )\r
-                                       strcpy( lightmapName, "$lightmap" );\r
-                               else\r
-                                       sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );\r
-                               \r
-                               /* get rgbgen string */\r
-                               if( rgbGenValues[ style ] == NULL )\r
-                               {\r
-                                       sprintf( key, "_style%drgbgen", style );\r
-                                       rgbGenValues[ style ] = (char*) ValueForKey( &entities[ 0 ], key );\r
-                                       if( rgbGenValues[ style ][ 0 ] == '\0' )\r
-                                               rgbGenValues[ style ] = "wave noise 0.5 1 0 5.37";\r
-                               }\r
-                               rgbGen[ 0 ] = '\0';\r
-                               if( rgbGenValues[ style ][ 0 ] != '\0' )\r
-                                       sprintf( rgbGen, "\t\trgbGen %s // style %d\n", rgbGenValues[ style ], style );\r
-                               else\r
-                                       rgbGen[ 0 ] = '\0';\r
-                               \r
-                               /* get alphagen string */\r
-                               if( alphaGenValues[ style ] == NULL )\r
-                               {\r
-                                       sprintf( key, "_style%dalphagen", style );\r
-                                       alphaGenValues[ style ] = (char*) ValueForKey( &entities[ 0 ], key );\r
-                               }\r
-                               if( alphaGenValues[ style ][ 0 ] != '\0' )\r
-                                       sprintf( alphaGen, "\t\talphaGen %s // style %d\n", alphaGenValues[ style ], style );\r
-                               else\r
-                                       alphaGen[ 0 ] = '\0';\r
-                               \r
-                               /* calculate st offset */\r
-                               lmx = dv[ 0 ].lightmap[ lightmapNum ][ 0 ] - dv[ 0 ].lightmap[ 0 ][ 0 ];\r
-                               lmy = dv[ 0 ].lightmap[ lightmapNum ][ 1 ] - dv[ 0 ].lightmap[ 0 ][ 1 ];\r
-                               \r
-                               /* create additional stage */\r
-                               if( lmx == 0.0f && lmy == 0.0f )\r
-                               {\r
-                                       sprintf( styleStage,    "\t{\n"\r
-                                                                                       "\t\tmap %s\n"                                                                          /* lightmap */\r
-                                                                                       "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"\r
-                                                                                       "%s"                                                                                            /* depthFunc equal */\r
-                                                                                       "%s"                                                                                            /* rgbGen */\r
-                                                                                       "%s"                                                                                            /* alphaGen */\r
-                                                                                       "\t\ttcGen lightmap\n"\r
-                                                                                       "\t}\n",\r
-                                               lightmapName,\r
-                                               (dfEqual ? "\t\tdepthFunc equal\n" : ""),\r
-                                               rgbGen,\r
-                                               alphaGen );\r
-                               }\r
-                               else\r
-                               {\r
-                                       sprintf( styleStage,    "\t{\n"\r
-                                                                                       "\t\tmap %s\n"                                                                          /* lightmap */\r
-                                                                                       "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"\r
-                                                                                       "%s"                                                                                            /* depthFunc equal */\r
-                                                                                       "%s"                                                                                            /* rgbGen */\r
-                                                                                       "%s"                                                                                            /* alphaGen */\r
-                                                                                       "\t\ttcGen lightmap\n"\r
-                                                                                       "\t\ttcMod transform 1 0 0 1 %1.5f %1.5f\n"                     /* st offset */\r
-                                                                                       "\t}\n",\r
-                                               lightmapName,\r
-                                               (dfEqual ? "\t\tdepthFunc equal\n" : ""),\r
-                                               rgbGen,\r
-                                               alphaGen,\r
-                                               lmx, lmy );\r
-                                       \r
-                               }\r
-                               \r
-                               /* concatenate */\r
-                               strcat( styleStages, styleStage );\r
-                       }\r
-                       \r
-                       /* create custom shader */\r
-                       if( info->si->styleMarker == 2 )\r
-                               csi = CustomShader( info->si, "q3map_styleMarker2", styleStages );\r
-                       else\r
-                               csi = CustomShader( info->si, "q3map_styleMarker", styleStages );\r
-                       \r
-                       /* emit remap command */\r
-                       //%     EmitVertexRemapShader( csi->shader, info->si->shader );\r
-                       \r
-                       /* store it */\r
-                       //%     Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );\r
-                       ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );\r
-                       //%     Sys_Printf( ")\n" );\r
-               }\r
-               \r
-               /* devise a custom shader for this surface (fixme: make this work with light styles) */\r
-               else if( olm != NULL && lm != NULL && !externalLightmaps &&\r
-                       (olm->customWidth != LIGHTMAP_WIDTH || olm->customHeight != LIGHTMAP_HEIGHT) )\r
-               {\r
-                       /* get output lightmap */\r
-                       olm = &outLightmaps[ lm->outLightmapNums[ 0 ] ];\r
-                       \r
-                       /* do some name mangling */\r
-                       sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );\r
-                       \r
-                       /* create custom shader */\r
-                       csi = CustomShader( info->si, "$lightmap", lightmapName );\r
-                       \r
-                       /* store it */\r
-                       //%     Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );\r
-                       ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );\r
-                       //%     Sys_Printf( ")\n" );\r
-               }\r
-               \r
-               /* use the normal plain-jane shader */\r
-               else\r
-                       ds->shaderNum = EmitShader( info->si->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );\r
-       }\r
-       \r
-       /* finish */\r
-       Sys_FPrintf( SYS_VRB, "done.\n" );\r
-       \r
-       /* calc num stored */\r
-       numStored = numBSPLightBytes / 3;\r
-       efficiency = (numStored <= 0)\r
-               ? 0\r
-               : (float) numUsed / (float) numStored;\r
-       \r
-       /* print stats */\r
-       Sys_Printf( "%9d luxels used\n", numUsed );\r
-       Sys_Printf( "%9d luxels stored (%3.2f percent efficiency)\n", numStored, efficiency * 100.0f );\r
-       Sys_Printf( "%9d identical surface lightmaps, using %d luxels\n", numTwins, numTwinLuxels );\r
-       Sys_Printf( "%9d vertex forced surfaces\n", numSurfsVertexForced );\r
-       Sys_Printf( "%9d vertex approximated surfaces\n", numSurfsVertexApproximated );\r
-       Sys_Printf( "%9d BSP lightmaps\n", numBSPLightmaps );\r
-       Sys_Printf( "%9d total lightmaps\n", numOutLightmaps );\r
-       Sys_Printf( "%9d unique lightmap/shader combinations\n", numLightmapShaders );\r
-       \r
-       /* write map shader file */\r
-       WriteMapShaderFile();\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 LIGHTMAPS_YDNAR_C
+
+
+
+/* dependencies */
+#include "q3map2.h"
+
+
+
+
+/* -------------------------------------------------------------------------------
+
+   this file contains code that doe lightmap allocation and projection that
+   runs in the -light phase.
+
+   this is handled here rather than in the bsp phase for a few reasons--
+   surfaces are no longer necessarily convex polygons, patches may or may not be
+   planar or have lightmaps projected directly onto control points.
+
+   also, this allows lightmaps to be calculated before being allocated and stored
+   in the bsp. lightmaps that have little high-frequency information are candidates
+   for having their resolutions scaled down.
+
+   ------------------------------------------------------------------------------- */
+
+/*
+   WriteTGA24()
+   based on WriteTGA() from imagelib.c
+ */
+
+void WriteTGA24( char *filename, byte *data, int width, int height, qboolean flip ){
+       int i, c;
+       byte    *buffer, *in;
+       FILE    *file;
+
+
+       /* allocate a buffer and set it up */
+       buffer = safe_malloc( width * height * 3 + 18 );
+       memset( buffer, 0, 18 );
+       buffer[ 2 ] = 2;
+       buffer[ 12 ] = width & 255;
+       buffer[ 13 ] = width >> 8;
+       buffer[ 14 ] = height & 255;
+       buffer[ 15 ] = height >> 8;
+       buffer[ 16 ] = 24;
+
+       /* swap rgb to bgr */
+       c = ( width * height * 3 ) + 18;
+       for ( i = 18; i < c; i += 3 )
+       {
+               buffer[ i ] = data[ i - 18 + 2 ];       /* blue */
+               buffer[ i + 1 ] = data[ i - 18 + 1 ];   /* green */
+               buffer[ i + 2 ] = data[ i - 18 + 0 ];   /* red */
+       }
+
+       /* write it and free the buffer */
+       file = fopen( filename, "wb" );
+       if ( file == NULL ) {
+               Error( "Unable to open %s for writing", filename );
+       }
+
+       /* flip vertically? */
+       if ( flip ) {
+               fwrite( buffer, 1, 18, file );
+               for ( in = buffer + ( ( height - 1 ) * width * 3 ) + 18; in >= buffer; in -= ( width * 3 ) )
+                       fwrite( in, 1, ( width * 3 ), file );
+       }
+       else{
+               fwrite( buffer, 1, c, file );
+       }
+
+       /* close the file */
+       fclose( file );
+       free( buffer );
+}
+
+
+
+/*
+   ExportLightmaps()
+   exports the lightmaps as a list of numbered tga images
+ */
+
+void ExportLightmaps( void ){
+       int i;
+       char dirname[ 1024 ], filename[ 1024 ];
+       byte        *lightmap;
+
+
+       /* note it */
+       Sys_FPrintf( SYS_VRB, "--- ExportLightmaps ---\n" );
+
+       /* do some path mangling */
+       strcpy( dirname, source );
+       StripExtension( dirname );
+
+       /* sanity check */
+       if ( bspLightBytes == NULL ) {
+               Sys_Printf( "WARNING: No BSP lightmap data\n" );
+               return;
+       }
+
+       /* make a directory for the lightmaps */
+       Q_mkdir( dirname );
+
+       /* iterate through the lightmaps */
+       for ( i = 0, lightmap = bspLightBytes; lightmap < ( bspLightBytes + numBSPLightBytes ); i++, lightmap += ( game->lightmapSize * game->lightmapSize * 3 ) )
+       {
+               /* write a tga image out */
+               sprintf( filename, "%s/lightmap_%04d.tga", dirname, i );
+               Sys_Printf( "Writing %s\n", filename );
+               WriteTGA24( filename, lightmap, game->lightmapSize, game->lightmapSize, qfalse );
+       }
+}
+
+
+
+/*
+   ExportLightmapsMain()
+   exports the lightmaps as a list of numbered tga images
+ */
+
+int ExportLightmapsMain( int argc, char **argv ){
+       /* arg checking */
+       if ( argc < 1 ) {
+               Sys_Printf( "Usage: q3map -export [-v] <mapname>\n" );
+               return 0;
+       }
+
+       /* do some path mangling */
+       strcpy( source, ExpandArg( argv[ argc - 1 ] ) );
+       StripExtension( source );
+       DefaultExtension( source, ".bsp" );
+
+       /* load the bsp */
+       Sys_Printf( "Loading %s\n", source );
+       LoadBSPFile( source );
+
+       /* export the lightmaps */
+       ExportLightmaps();
+
+       /* return to sender */
+       return 0;
+}
+
+
+
+/*
+   ImportLightmapsMain()
+   imports the lightmaps from a list of numbered tga images
+ */
+
+int ImportLightmapsMain( int argc, char **argv ){
+       int i, x, y, len, width, height;
+       char dirname[ 1024 ], filename[ 1024 ];
+       byte        *lightmap, *buffer, *pixels, *in, *out;
+
+
+       /* arg checking */
+       if ( argc < 1 ) {
+               Sys_Printf( "Usage: q3map -import [-v] <mapname>\n" );
+               return 0;
+       }
+
+       /* do some path mangling */
+       strcpy( source, ExpandArg( argv[ argc - 1 ] ) );
+       StripExtension( source );
+       DefaultExtension( source, ".bsp" );
+
+       /* load the bsp */
+       Sys_Printf( "Loading %s\n", source );
+       LoadBSPFile( source );
+
+       /* note it */
+       Sys_FPrintf( SYS_VRB, "--- ImportLightmaps ---\n" );
+
+       /* do some path mangling */
+       strcpy( dirname, source );
+       StripExtension( dirname );
+
+       /* sanity check */
+       if ( bspLightBytes == NULL ) {
+               Error( "No lightmap data" );
+       }
+
+       /* make a directory for the lightmaps */
+       Q_mkdir( dirname );
+
+       /* iterate through the lightmaps */
+       for ( i = 0, lightmap = bspLightBytes; lightmap < ( bspLightBytes + numBSPLightBytes ); i++, lightmap += ( game->lightmapSize * game->lightmapSize * 3 ) )
+       {
+               /* read a tga image */
+               sprintf( filename, "%s/lightmap_%04d.tga", dirname, i );
+               Sys_Printf( "Loading %s\n", filename );
+               buffer = NULL;
+               len = vfsLoadFile( filename, (void*) &buffer, -1 );
+               if ( len < 0 ) {
+                       Sys_Printf( "WARNING: Unable to load image %s\n", filename );
+                       continue;
+               }
+
+               /* parse file into an image */
+               pixels = NULL;
+               LoadTGABuffer( buffer, buffer + len, &pixels, &width, &height );
+               free( buffer );
+
+               /* sanity check it */
+               if ( pixels == NULL ) {
+                       Sys_Printf( "WARNING: Unable to load image %s\n", filename );
+                       continue;
+               }
+               if ( width != game->lightmapSize || height != game->lightmapSize ) {
+                       Sys_Printf( "WARNING: Image %s is not the right size (%d, %d) != (%d, %d)\n",
+                                               filename, width, height, game->lightmapSize, game->lightmapSize );
+               }
+
+               /* copy the pixels */
+               in = pixels;
+               for ( y = 1; y <= game->lightmapSize; y++ )
+               {
+                       out = lightmap + ( ( game->lightmapSize - y ) * game->lightmapSize * 3 );
+                       for ( x = 0; x < game->lightmapSize; x++, in += 4, out += 3 )
+                               VectorCopy( in, out );
+               }
+
+               /* free the image */
+               free( pixels );
+       }
+
+       /* write the bsp */
+       Sys_Printf( "writing %s\n", source );
+       WriteBSPFile( source );
+
+       /* return to sender */
+       return 0;
+}
+
+
+
+/* -------------------------------------------------------------------------------
+
+   this section deals with projecting a lightmap onto a raw drawsurface
+
+   ------------------------------------------------------------------------------- */
+
+/*
+   CompareLightSurface()
+   compare function for qsort()
+ */
+
+static int CompareLightSurface( const void *a, const void *b ){
+       shaderInfo_t    *asi, *bsi;
+
+
+       /* get shaders */
+       asi = surfaceInfos[ *( (const int*) a ) ].si;
+       bsi = surfaceInfos[ *( (const int*) b ) ].si;
+
+       /* dummy check */
+       if ( asi == NULL ) {
+               return -1;
+       }
+       if ( bsi == NULL ) {
+               return 1;
+       }
+
+       /* compare shader names */
+       return strcmp( asi->shader, bsi->shader );
+}
+
+
+
+/*
+   FinishRawLightmap()
+   allocates a raw lightmap's necessary buffers
+ */
+
+void FinishRawLightmap( rawLightmap_t *lm ){
+       int i, j, c, size, *sc;
+       float is;
+       surfaceInfo_t       *info;
+
+
+       /* sort light surfaces by shader name */
+       qsort( &lightSurfaces[ lm->firstLightSurface ], lm->numLightSurfaces, sizeof( int ), CompareLightSurface );
+
+       /* count clusters */
+       lm->numLightClusters = 0;
+       for ( i = 0; i < lm->numLightSurfaces; i++ )
+       {
+               /* get surface info */
+               info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + i ] ];
+
+               /* add surface clusters */
+               lm->numLightClusters += info->numSurfaceClusters;
+       }
+
+       /* allocate buffer for clusters and copy */
+       lm->lightClusters = safe_malloc( lm->numLightClusters * sizeof( *lm->lightClusters ) );
+       c = 0;
+       for ( i = 0; i < lm->numLightSurfaces; i++ )
+       {
+               /* get surface info */
+               info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + i ] ];
+
+               /* add surface clusters */
+               for ( j = 0; j < info->numSurfaceClusters; j++ )
+                       lm->lightClusters[ c++ ] = surfaceClusters[ info->firstSurfaceCluster + j ];
+       }
+
+       /* set styles */
+       lm->styles[ 0 ] = LS_NORMAL;
+       for ( i = 1; i < MAX_LIGHTMAPS; i++ )
+               lm->styles[ i ] = LS_NONE;
+
+       /* set supersampling size */
+       lm->sw = lm->w * superSample;
+       lm->sh = lm->h * superSample;
+
+       /* add to super luxel count */
+       numRawSuperLuxels += ( lm->sw * lm->sh );
+
+       /* manipulate origin/vecs for supersampling */
+       if ( superSample > 1 && lm->vecs != NULL ) {
+               /* calc inverse supersample */
+               is = 1.0f / superSample;
+
+               /* scale the vectors and shift the origin */
+               #if 1
+               /* new code that works for arbitrary supersampling values */
+               VectorMA( lm->origin, -0.5, lm->vecs[ 0 ], lm->origin );
+               VectorMA( lm->origin, -0.5, lm->vecs[ 1 ], lm->origin );
+               VectorScale( lm->vecs[ 0 ], is, lm->vecs[ 0 ] );
+               VectorScale( lm->vecs[ 1 ], is, lm->vecs[ 1 ] );
+               VectorMA( lm->origin, is, lm->vecs[ 0 ], lm->origin );
+               VectorMA( lm->origin, is, lm->vecs[ 1 ], lm->origin );
+               #else
+               /* old code that only worked with a value of 2 */
+               VectorScale( lm->vecs[ 0 ], is, lm->vecs[ 0 ] );
+               VectorScale( lm->vecs[ 1 ], is, lm->vecs[ 1 ] );
+               VectorMA( lm->origin, -is, lm->vecs[ 0 ], lm->origin );
+               VectorMA( lm->origin, -is, lm->vecs[ 1 ], lm->origin );
+               #endif
+       }
+
+       /* allocate bsp lightmap storage */
+       size = lm->w * lm->h * BSP_LUXEL_SIZE * sizeof( float );
+       if ( lm->bspLuxels[ 0 ] == NULL ) {
+               lm->bspLuxels[ 0 ] = safe_malloc( size );
+       }
+       memset( lm->bspLuxels[ 0 ], 0, size );
+
+       /* allocate radiosity lightmap storage */
+       if ( bounce ) {
+               size = lm->w * lm->h * RAD_LUXEL_SIZE * sizeof( float );
+               if ( lm->radLuxels[ 0 ] == NULL ) {
+                       lm->radLuxels[ 0 ] = safe_malloc( size );
+               }
+               memset( lm->radLuxels[ 0 ], 0, size );
+       }
+
+       /* allocate sampling lightmap storage */
+       size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
+       if ( lm->superLuxels[ 0 ] == NULL ) {
+               lm->superLuxels[ 0 ] = safe_malloc( size );
+       }
+       memset( lm->superLuxels[ 0 ], 0, size );
+
+       /* allocate origin map storage */
+       size = lm->sw * lm->sh * SUPER_ORIGIN_SIZE * sizeof( float );
+       if ( lm->superOrigins == NULL ) {
+               lm->superOrigins = safe_malloc( size );
+       }
+       memset( lm->superOrigins, 0, size );
+
+       /* allocate normal map storage */
+       size = lm->sw * lm->sh * SUPER_NORMAL_SIZE * sizeof( float );
+       if ( lm->superNormals == NULL ) {
+               lm->superNormals = safe_malloc( size );
+       }
+       memset( lm->superNormals, 0, size );
+
+       /* allocate floodlight map storage */
+       size = lm->sw * lm->sh * SUPER_FLOODLIGHT_SIZE * sizeof( float );
+       if ( lm->superFloodLight == NULL ) {
+               lm->superFloodLight = safe_malloc( size );
+       }
+       memset( lm->superFloodLight, 0, size );
+
+       /* allocate cluster map storage */
+       size = lm->sw * lm->sh * sizeof( int );
+       if ( lm->superClusters == NULL ) {
+               lm->superClusters = safe_malloc( size );
+       }
+       size = lm->sw * lm->sh;
+       sc = lm->superClusters;
+       for ( i = 0; i < size; i++ )
+               ( *sc++ ) = CLUSTER_UNMAPPED;
+
+       /* deluxemap allocation */
+       if ( deluxemap ) {
+               /* allocate sampling deluxel storage */
+               size = lm->sw * lm->sh * SUPER_DELUXEL_SIZE * sizeof( float );
+               if ( lm->superDeluxels == NULL ) {
+                       lm->superDeluxels = safe_malloc( size );
+               }
+               memset( lm->superDeluxels, 0, size );
+
+               /* allocate bsp deluxel storage */
+               size = lm->w * lm->h * BSP_DELUXEL_SIZE * sizeof( float );
+               if ( lm->bspDeluxels == NULL ) {
+                       lm->bspDeluxels = safe_malloc( size );
+               }
+               memset( lm->bspDeluxels, 0, size );
+       }
+
+       /* add to count */
+       numLuxels += ( lm->sw * lm->sh );
+}
+
+
+
+/*
+   AddPatchToRawLightmap()
+   projects a lightmap for a patch surface
+   since lightmap calculation for surfaces is now handled in a general way (light_ydnar.c),
+   it is no longer necessary for patch verts to fall exactly on a lightmap sample
+   based on AllocateLightmapForPatch()
+ */
+
+qboolean AddPatchToRawLightmap( int num, rawLightmap_t *lm ){
+       bspDrawSurface_t    *ds;
+       surfaceInfo_t       *info;
+       int x, y;
+       bspDrawVert_t       *verts, *a, *b;
+       vec3_t delta;
+       mesh_t src, *subdivided, *mesh;
+       float sBasis, tBasis, s, t;
+       float length, widthTable[ MAX_EXPANDED_AXIS ], heightTable[ MAX_EXPANDED_AXIS ];
+
+
+       /* patches finish a raw lightmap */
+       lm->finished = qtrue;
+
+       /* get surface and info  */
+       ds = &bspDrawSurfaces[ num ];
+       info = &surfaceInfos[ num ];
+
+       /* make a temporary 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 );
+
+       /* find the longest distance on each row/column */
+       verts = mesh->verts;
+       memset( widthTable, 0, sizeof( widthTable ) );
+       memset( heightTable, 0, sizeof( heightTable ) );
+       for ( y = 0; y < mesh->height; y++ )
+       {
+               for ( x = 0; x < mesh->width; x++ )
+               {
+                       /* get width */
+                       if ( x + 1 < mesh->width ) {
+                               a = &verts[ ( y * mesh->width ) + x ];
+                               b = &verts[ ( y * mesh->width ) + x + 1 ];
+                               VectorSubtract( a->xyz, b->xyz, delta );
+                               length = VectorLength( delta );
+                               if ( length > widthTable[ x ] ) {
+                                       widthTable[ x ] = length;
+                               }
+                       }
+
+                       /* get height */
+                       if ( y + 1 < mesh->height ) {
+                               a = &verts[ ( y * mesh->width ) + x ];
+                               b = &verts[ ( ( y + 1 ) * mesh->width ) + x ];
+                               VectorSubtract( a->xyz, b->xyz, delta );
+                               length = VectorLength( delta );
+                               if ( length > heightTable[ y ] ) {
+                                       heightTable[ y ] = length;
+                               }
+                       }
+               }
+       }
+
+       /* determine lightmap width */
+       length = 0;
+       for ( x = 0; x < ( mesh->width - 1 ); x++ )
+               length += widthTable[ x ];
+       lm->w = ceil( length / lm->sampleSize ) + 1;
+       if ( lm->w < ds->patchWidth ) {
+               lm->w = ds->patchWidth;
+       }
+       if ( lm->w > lm->customWidth ) {
+               lm->w = lm->customWidth;
+       }
+       sBasis = (float) ( lm->w - 1 ) / (float) ( ds->patchWidth - 1 );
+
+       /* determine lightmap height */
+       length = 0;
+       for ( y = 0; y < ( mesh->height - 1 ); y++ )
+               length += heightTable[ y ];
+       lm->h = ceil( length / lm->sampleSize ) + 1;
+       if ( lm->h < ds->patchHeight ) {
+               lm->h = ds->patchHeight;
+       }
+       if ( lm->h > lm->customHeight ) {
+               lm->h = lm->customHeight;
+       }
+       tBasis = (float) ( lm->h - 1 ) / (float) ( ds->patchHeight - 1 );
+
+       /* free the temporary mesh */
+       FreeMesh( mesh );
+
+       /* set the lightmap texture coordinates in yDrawVerts */
+       lm->wrap[ 0 ] = qtrue;
+       lm->wrap[ 1 ] = qtrue;
+       verts = &yDrawVerts[ ds->firstVert ];
+       for ( y = 0; y < ds->patchHeight; y++ )
+       {
+               t = ( tBasis * y ) + 0.5f;
+               for ( x = 0; x < ds->patchWidth; x++ )
+               {
+                       s = ( sBasis * x ) + 0.5f;
+                       verts[ ( y * ds->patchWidth ) + x ].lightmap[ 0 ][ 0 ] = s * superSample;
+                       verts[ ( y * ds->patchWidth ) + x ].lightmap[ 0 ][ 1 ] = t * superSample;
+
+                       if ( y == 0 && !VectorCompare( verts[ x ].xyz, verts[ ( ( ds->patchHeight - 1 ) * ds->patchWidth ) + x ].xyz ) ) {
+                               lm->wrap[ 1 ] = qfalse;
+                       }
+               }
+
+               if ( !VectorCompare( verts[ ( y * ds->patchWidth ) ].xyz, verts[ ( y * ds->patchWidth ) + ( ds->patchWidth - 1 ) ].xyz ) ) {
+                       lm->wrap[ 0 ] = qfalse;
+               }
+       }
+
+       /* debug code: */
+       //%     Sys_Printf( "wrap S: %d wrap T: %d\n", lm->wrap[ 0 ], lm->wrap[ 1 ] );
+       //% if( lm->w > (ds->lightmapWidth & 0xFF) || lm->h > (ds->lightmapHeight & 0xFF) )
+       //%             Sys_Printf( "Patch lightmap: (%3d %3d) > (%3d, %3d)\n", lm->w, lm->h, ds->lightmapWidth & 0xFF, ds->lightmapHeight & 0xFF );
+       //% ds->lightmapWidth = lm->w | (ds->lightmapWidth & 0xFFFF0000);
+       //% ds->lightmapHeight = lm->h | (ds->lightmapHeight & 0xFFFF0000);
+
+       /* add to counts */
+       numPatchesLightmapped++;
+
+       /* return */
+       return qtrue;
+}
+
+
+
+/*
+   AddSurfaceToRawLightmap()
+   projects a lightmap for a surface
+   based on AllocateLightmapForSurface()
+ */
+
+qboolean AddSurfaceToRawLightmap( int num, rawLightmap_t *lm ){
+       bspDrawSurface_t    *ds, *ds2;
+       surfaceInfo_t       *info;
+       int num2, n, i, axisNum;
+       float s, t, d, len, sampleSize;
+       vec3_t mins, maxs, origin, faxis, size, delta, normalized, vecs[ 2 ];
+       vec4_t plane;
+       bspDrawVert_t       *verts;
+
+
+       /* get surface and info  */
+       ds = &bspDrawSurfaces[ num ];
+       info = &surfaceInfos[ num ];
+
+       /* add the surface to the raw lightmap */
+       lightSurfaces[ numLightSurfaces++ ] = num;
+       lm->numLightSurfaces++;
+
+       /* does this raw lightmap already have any surfaces? */
+       if ( lm->numLightSurfaces > 1 ) {
+               /* surface and raw lightmap must have the same lightmap projection axis */
+               if ( VectorCompare( info->axis, lm->axis ) == qfalse ) {
+                       return qfalse;
+               }
+
+               /* match identical attributes */
+               if ( info->sampleSize != lm->sampleSize ||
+                        info->entityNum != lm->entityNum ||
+                        info->recvShadows != lm->recvShadows ||
+                        info->si->lmCustomWidth != lm->customWidth ||
+                        info->si->lmCustomHeight != lm->customHeight ||
+                        info->si->lmBrightness != lm->brightness ||
+                        info->si->lmFilterRadius != lm->filterRadius ||
+                        info->si->splotchFix != lm->splotchFix ) {
+                       return qfalse;
+               }
+
+               /* surface bounds must intersect with raw lightmap bounds */
+               for ( i = 0; i < 3; i++ )
+               {
+                       if ( info->mins[ i ] > lm->maxs[ i ] ) {
+                               return qfalse;
+                       }
+                       if ( info->maxs[ i ] < lm->mins[ i ] ) {
+                               return qfalse;
+                       }
+               }
+
+               /* plane check (fixme: allow merging of nonplanars) */
+               if ( info->si->lmMergable == qfalse ) {
+                       if ( info->plane == NULL || lm->plane == NULL ) {
+                               return qfalse;
+                       }
+
+                       /* compare planes */
+                       for ( i = 0; i < 4; i++ )
+                               if ( fabs( info->plane[ i ] - lm->plane[ i ] ) > EQUAL_EPSILON ) {
+                                       return qfalse;
+                               }
+               }
+
+               /* debug code hacking */
+               //%     if( lm->numLightSurfaces > 1 )
+               //%             return qfalse;
+       }
+
+       /* set plane */
+       if ( info->plane == NULL ) {
+               lm->plane = NULL;
+       }
+
+       /* add surface to lightmap bounds */
+       AddPointToBounds( info->mins, lm->mins, lm->maxs );
+       AddPointToBounds( info->maxs, lm->mins, lm->maxs );
+
+       /* check to see if this is a non-planar patch */
+       if ( ds->surfaceType == MST_PATCH &&
+                lm->axis[ 0 ] == 0.0f && lm->axis[ 1 ] == 0.0f && lm->axis[ 2 ] == 0.0f ) {
+               return AddPatchToRawLightmap( num, lm );
+       }
+
+       /* start with initially requested sample size */
+       sampleSize = lm->sampleSize;
+
+       /* round to the lightmap resolution */
+       for ( i = 0; i < 3; i++ )
+       {
+               mins[ i ] = sampleSize * floor( lm->mins[ i ] / sampleSize );
+               maxs[ i ] = sampleSize * ceil( lm->maxs[ i ] / sampleSize );
+               size[ i ] = ( maxs[ i ] - mins[ i ] ) / sampleSize + 1.0f;
+
+               /* hack (god this sucks) */
+               if ( size[ i ] > lm->customWidth || size[ i ] > lm->customHeight  || ( lmLimitSize && size[i] > lmLimitSize ) ) {
+                       i = -1;
+                       sampleSize += 1.0f;
+               }
+       }
+
+       if ( sampleSize != lm->sampleSize && lmLimitSize == 0 ) {
+               Sys_FPrintf( SYS_VRB,"WARNING: surface at (%6.0f %6.0f %6.0f) (%6.0f %6.0f %6.0f) too large for desired samplesize/lightmapsize/lightmapscale combination, increased samplesize from %d to %d\n",
+                                        info->mins[0],
+                                        info->mins[1],
+                                        info->mins[2],
+                                        info->maxs[0],
+                                        info->maxs[1],
+                                        info->maxs[2],
+                                        lm->sampleSize,
+                                        (int) sampleSize );
+       }
+
+       /* set actual sample size */
+       lm->actualSampleSize = sampleSize;
+
+       /* fixme: copy rounded mins/maxes to lightmap record? */
+       if ( lm->plane == NULL ) {
+               VectorCopy( mins, lm->mins );
+               VectorCopy( maxs, lm->maxs );
+               VectorCopy( mins, origin );
+       }
+
+       /* set lightmap origin */
+       VectorCopy( lm->mins, origin );
+
+       /* make absolute axis */
+       faxis[ 0 ] = fabs( lm->axis[ 0 ] );
+       faxis[ 1 ] = fabs( lm->axis[ 1 ] );
+       faxis[ 2 ] = fabs( lm->axis[ 2 ] );
+
+       /* clear out lightmap vectors */
+       memset( vecs, 0, sizeof( vecs ) );
+
+       /* classify the plane (x y or z major) (ydnar: biased to z axis projection) */
+       if ( faxis[ 2 ] >= faxis[ 0 ] && faxis[ 2 ] >= faxis[ 1 ] ) {
+               axisNum = 2;
+               lm->w = size[ 0 ];
+               lm->h = size[ 1 ];
+               vecs[ 0 ][ 0 ] = 1.0f / sampleSize;
+               vecs[ 1 ][ 1 ] = 1.0f / sampleSize;
+       }
+       else if ( faxis[ 0 ] >= faxis[ 1 ] && faxis[ 0 ] >= faxis[ 2 ] ) {
+               axisNum = 0;
+               lm->w = size[ 1 ];
+               lm->h = size[ 2 ];
+               vecs[ 0 ][ 1 ] = 1.0f / sampleSize;
+               vecs[ 1 ][ 2 ] = 1.0f / sampleSize;
+       }
+       else
+       {
+               axisNum = 1;
+               lm->w = size[ 0 ];
+               lm->h = size[ 2 ];
+               vecs[ 0 ][ 0 ] = 1.0f / sampleSize;
+               vecs[ 1 ][ 2 ] = 1.0f / sampleSize;
+       }
+
+       /* check for bogus axis */
+       if ( faxis[ axisNum ] == 0.0f ) {
+               Sys_Printf( "WARNING: ProjectSurfaceLightmap: Chose a 0 valued axis\n" );
+               lm->w = lm->h = 0;
+               return qfalse;
+       }
+
+       /* store the axis number in the lightmap */
+       lm->axisNum = axisNum;
+
+       /* walk the list of surfaces on this raw lightmap */
+       for ( n = 0; n < lm->numLightSurfaces; n++ )
+       {
+               /* get surface */
+               num2 = lightSurfaces[ lm->firstLightSurface + n ];
+               ds2 = &bspDrawSurfaces[ num2 ];
+               verts = &yDrawVerts[ ds2->firstVert ];
+
+               /* set the lightmap texture coordinates in yDrawVerts in [0, superSample * lm->customWidth] space */
+               for ( i = 0; i < ds2->numVerts; i++ )
+               {
+                       VectorSubtract( verts[ i ].xyz, origin, delta );
+                       s = DotProduct( delta, vecs[ 0 ] ) + 0.5f;
+                       t = DotProduct( delta, vecs[ 1 ] ) + 0.5f;
+                       verts[ i ].lightmap[ 0 ][ 0 ] = s * superSample;
+                       verts[ i ].lightmap[ 0 ][ 1 ] = t * superSample;
+
+                       if ( s > (float) lm->w || t > (float) lm->h ) {
+                               Sys_FPrintf( SYS_VRB, "WARNING: Lightmap texture coords out of range: S %1.4f > %3d || T %1.4f > %3d\n",
+                                                        s, lm->w, t, lm->h );
+                       }
+               }
+       }
+
+       /* get first drawsurface */
+       num2 = lightSurfaces[ lm->firstLightSurface ];
+       ds2 = &bspDrawSurfaces[ num2 ];
+       verts = &yDrawVerts[ ds2->firstVert ];
+
+       /* calculate lightmap origin */
+       if ( VectorLength( ds2->lightmapVecs[ 2 ] ) ) {
+               VectorCopy( ds2->lightmapVecs[ 2 ], plane );
+       }
+       else{
+               VectorCopy( lm->axis, plane );
+       }
+       plane[ 3 ] = DotProduct( verts[ 0 ].xyz, plane );
+
+       VectorCopy( origin, lm->origin );
+       d = DotProduct( lm->origin, plane ) - plane[ 3 ];
+       d /= plane[ axisNum ];
+       lm->origin[ axisNum ] -= d;
+
+       /* legacy support */
+       VectorCopy( lm->origin, ds->lightmapOrigin );
+
+       /* for planar surfaces, create lightmap vectors for st->xyz conversion */
+       if ( VectorLength( ds->lightmapVecs[ 2 ] ) || 1 ) {  /* ydnar: can't remember what exactly i was thinking here... */
+               /* allocate space for the vectors */
+               lm->vecs = safe_malloc( 3 * sizeof( vec3_t ) );
+               memset( lm->vecs, 0, 3 * sizeof( vec3_t ) );
+               VectorCopy( ds->lightmapVecs[ 2 ], lm->vecs[ 2 ] );
+
+               /* project stepped lightmap blocks and subtract to get planevecs */
+               for ( i = 0; i < 2; i++ )
+               {
+                       len = VectorNormalize( vecs[ i ], normalized );
+                       VectorScale( normalized, ( 1.0 / len ), lm->vecs[ i ] );
+                       d = DotProduct( lm->vecs[ i ], plane );
+                       d /= plane[ axisNum ];
+                       lm->vecs[ i ][ axisNum ] -= d;
+               }
+       }
+       else
+       {
+               /* lightmap vectors are useless on a non-planar surface */
+               lm->vecs = NULL;
+       }
+
+       /* add to counts */
+       if ( ds->surfaceType == MST_PATCH ) {
+               numPatchesLightmapped++;
+               if ( lm->plane != NULL ) {
+                       numPlanarPatchesLightmapped++;
+               }
+       }
+       else
+       {
+               if ( lm->plane != NULL ) {
+                       numPlanarsLightmapped++;
+               }
+               else{
+                       numNonPlanarsLightmapped++;
+               }
+       }
+
+       /* return */
+       return qtrue;
+}
+
+
+
+/*
+   CompareSurfaceInfo()
+   compare function for qsort()
+ */
+
+static int CompareSurfaceInfo( const void *a, const void *b ){
+       surfaceInfo_t   *aInfo, *bInfo;
+       int i;
+
+
+       /* get surface info */
+       aInfo = &surfaceInfos[ *( (const int*) a ) ];
+       bInfo = &surfaceInfos[ *( (const int*) b ) ];
+
+       /* model first */
+       if ( aInfo->modelindex < bInfo->modelindex ) {
+               return 1;
+       }
+       else if ( aInfo->modelindex > bInfo->modelindex ) {
+               return -1;
+       }
+
+       /* then lightmap status */
+       if ( aInfo->hasLightmap < bInfo->hasLightmap ) {
+               return 1;
+       }
+       else if ( aInfo->hasLightmap > bInfo->hasLightmap ) {
+               return -1;
+       }
+
+       /* 27: then shader! */
+       if ( aInfo->si < bInfo->si ) {
+               return 1;
+       }
+       else if ( aInfo->si > bInfo->si ) {
+               return -1;
+       }
+
+
+       /* then lightmap sample size */
+       if ( aInfo->sampleSize < bInfo->sampleSize ) {
+               return 1;
+       }
+       else if ( aInfo->sampleSize > bInfo->sampleSize ) {
+               return -1;
+       }
+
+       /* then lightmap axis */
+       for ( i = 0; i < 3; i++ )
+       {
+               if ( aInfo->axis[ i ] < bInfo->axis[ i ] ) {
+                       return 1;
+               }
+               else if ( aInfo->axis[ i ] > bInfo->axis[ i ] ) {
+                       return -1;
+               }
+       }
+
+       /* then plane */
+       if ( aInfo->plane == NULL && bInfo->plane != NULL ) {
+               return 1;
+       }
+       else if ( aInfo->plane != NULL && bInfo->plane == NULL ) {
+               return -1;
+       }
+       else if ( aInfo->plane != NULL && bInfo->plane != NULL ) {
+               for ( i = 0; i < 4; i++ )
+               {
+                       if ( aInfo->plane[ i ] < bInfo->plane[ i ] ) {
+                               return 1;
+                       }
+                       else if ( aInfo->plane[ i ] > bInfo->plane[ i ] ) {
+                               return -1;
+                       }
+               }
+       }
+
+       /* then position in world */
+       for ( i = 0; i < 3; i++ )
+       {
+               if ( aInfo->mins[ i ] < bInfo->mins[ i ] ) {
+                       return 1;
+               }
+               else if ( aInfo->mins[ i ] > bInfo->mins[ i ] ) {
+                       return -1;
+               }
+       }
+
+       /* these are functionally identical (this should almost never happen) */
+       return 0;
+}
+
+
+
+/*
+   SetupSurfaceLightmaps()
+   allocates lightmaps for every surface in the bsp that needs one
+   this depends on yDrawVerts being allocated
+ */
+
+void SetupSurfaceLightmaps( void ){
+       int i, j, k, s,num, num2;
+       bspModel_t          *model;
+       bspLeaf_t           *leaf;
+       bspDrawSurface_t    *ds;
+       surfaceInfo_t       *info, *info2;
+       rawLightmap_t       *lm;
+       qboolean added;
+       vec3_t mapSize, entityOrigin;
+
+
+       /* note it */
+       Sys_FPrintf( SYS_VRB, "--- SetupSurfaceLightmaps ---\n" );
+
+       /* determine supersample amount */
+       if ( superSample < 1 ) {
+               superSample = 1;
+       }
+       else if ( superSample > 8 ) {
+               Sys_Printf( "WARNING: Insane supersampling amount (%d) detected.\n", superSample );
+               superSample = 8;
+       }
+
+       /* clear map bounds */
+       ClearBounds( mapMins, mapMaxs );
+
+       /* allocate a list of surface clusters */
+       numSurfaceClusters = 0;
+       maxSurfaceClusters = numBSPLeafSurfaces;
+       surfaceClusters = safe_malloc( maxSurfaceClusters * sizeof( *surfaceClusters ) );
+       memset( surfaceClusters, 0, maxSurfaceClusters * sizeof( *surfaceClusters ) );
+
+       /* allocate a list for per-surface info */
+       surfaceInfos = safe_malloc( numBSPDrawSurfaces * sizeof( *surfaceInfos ) );
+       memset( surfaceInfos, 0, numBSPDrawSurfaces * sizeof( *surfaceInfos ) );
+       for ( i = 0; i < numBSPDrawSurfaces; i++ )
+               surfaceInfos[ i ].childSurfaceNum = -1;
+
+       /* allocate a list of surface indexes to be sorted */
+       sortSurfaces = safe_malloc( numBSPDrawSurfaces * sizeof( int ) );
+       memset( sortSurfaces, 0, numBSPDrawSurfaces * sizeof( int ) );
+
+       /* walk each model in the bsp */
+       for ( i = 0; i < numBSPModels; i++ )
+       {
+               /* get model */
+               model = &bspModels[ i ];
+
+               /* walk the list of surfaces in this model and fill out the info structs */
+               for ( j = 0; j < model->numBSPSurfaces; j++ )
+               {
+                       /* make surface index */
+                       num = model->firstBSPSurface + j;
+
+                       /* copy index to sort list */
+                       sortSurfaces[ num ] = num;
+
+                       /* get surface and info */
+                       ds = &bspDrawSurfaces[ num ];
+                       info = &surfaceInfos[ num ];
+
+                       /* set entity origin */
+                       if ( ds->numVerts > 0 ) {
+                               VectorSubtract( yDrawVerts[ ds->firstVert ].xyz, bspDrawVerts[ ds->firstVert ].xyz, entityOrigin );
+                       }
+                       else{
+                               VectorClear( entityOrigin );
+                       }
+
+                       /* basic setup */
+                       info->modelindex = i;
+                       info->lm = NULL;
+                       info->plane = NULL;
+                       info->firstSurfaceCluster = numSurfaceClusters;
+
+                       /* get extra data */
+                       info->si = GetSurfaceExtraShaderInfo( num );
+                       if ( info->si == NULL ) {
+                               info->si = ShaderInfoForShader( bspShaders[ ds->shaderNum ].shader );
+                       }
+                       info->parentSurfaceNum = GetSurfaceExtraParentSurfaceNum( num );
+                       info->entityNum = GetSurfaceExtraEntityNum( num );
+                       info->castShadows = GetSurfaceExtraCastShadows( num );
+                       info->recvShadows = GetSurfaceExtraRecvShadows( num );
+                       info->sampleSize = GetSurfaceExtraSampleSize( num );
+                       info->longestCurve = GetSurfaceExtraLongestCurve( num );
+                       info->patchIterations = IterationsForCurve( info->longestCurve, patchSubdivisions );
+                       GetSurfaceExtraLightmapAxis( num, info->axis );
+
+                       /* mark parent */
+                       if ( info->parentSurfaceNum >= 0 ) {
+                               surfaceInfos[ info->parentSurfaceNum ].childSurfaceNum = j;
+                       }
+
+                       /* determine surface bounds */
+                       ClearBounds( info->mins, info->maxs );
+                       for ( k = 0; k < ds->numVerts; k++ )
+                       {
+                               AddPointToBounds( yDrawVerts[ ds->firstVert + k ].xyz, mapMins, mapMaxs );
+                               AddPointToBounds( yDrawVerts[ ds->firstVert + k ].xyz, info->mins, info->maxs );
+                       }
+
+                       /* find all the bsp clusters the surface falls into */
+                       for ( k = 0; k < numBSPLeafs; k++ )
+                       {
+                               /* get leaf */
+                               leaf = &bspLeafs[ k ];
+
+                               /* test bbox */
+                               if ( leaf->mins[ 0 ] > info->maxs[ 0 ] || leaf->maxs[ 0 ] < info->mins[ 0 ] ||
+                                        leaf->mins[ 1 ] > info->maxs[ 1 ] || leaf->maxs[ 1 ] < info->mins[ 1 ] ||
+                                        leaf->mins[ 2 ] > info->maxs[ 2 ] || leaf->maxs[ 2 ] < info->mins[ 2 ] ) {
+                                       continue;
+                               }
+
+                               /* test leaf surfaces */
+                               for ( s = 0; s < leaf->numBSPLeafSurfaces; s++ )
+                               {
+                                       if ( bspLeafSurfaces[ leaf->firstBSPLeafSurface + s ] == num ) {
+                                               if ( numSurfaceClusters >= maxSurfaceClusters ) {
+                                                       Error( "maxSurfaceClusters exceeded" );
+                                               }
+                                               surfaceClusters[ numSurfaceClusters ] = leaf->cluster;
+                                               numSurfaceClusters++;
+                                               info->numSurfaceClusters++;
+                                       }
+                               }
+                       }
+
+                       /* determine if surface is planar */
+                       if ( VectorLength( ds->lightmapVecs[ 2 ] ) > 0.0f ) {
+                               /* make a plane */
+                               info->plane = safe_malloc( 4 * sizeof( float ) );
+                               VectorCopy( ds->lightmapVecs[ 2 ], info->plane );
+                               info->plane[ 3 ] = DotProduct( yDrawVerts[ ds->firstVert ].xyz, info->plane );
+                       }
+
+                       /* determine if surface requires a lightmap */
+                       if ( ds->surfaceType == MST_TRIANGLE_SOUP ||
+                                ds->surfaceType == MST_FOLIAGE ||
+                                ( info->si->compileFlags & C_VERTEXLIT ) ) {
+                               numSurfsVertexLit++;
+                       }
+                       else
+                       {
+                               numSurfsLightmapped++;
+                               info->hasLightmap = qtrue;
+                       }
+               }
+       }
+
+       /* find longest map distance */
+       VectorSubtract( mapMaxs, mapMins, mapSize );
+       maxMapDistance = VectorLength( mapSize );
+
+       /* sort the surfaces info list */
+       qsort( sortSurfaces, numBSPDrawSurfaces, sizeof( int ), CompareSurfaceInfo );
+
+       /* allocate a list of surfaces that would go into raw lightmaps */
+       numLightSurfaces = 0;
+       lightSurfaces = safe_malloc( numSurfsLightmapped * sizeof( int ) );
+       memset( lightSurfaces, 0, numSurfsLightmapped * sizeof( int ) );
+
+       /* allocate a list of raw lightmaps */
+       numRawSuperLuxels = 0;
+       numRawLightmaps = 0;
+       rawLightmaps = safe_malloc( numSurfsLightmapped * sizeof( *rawLightmaps ) );
+       memset( rawLightmaps, 0, numSurfsLightmapped * sizeof( *rawLightmaps ) );
+
+       /* walk the list of sorted surfaces */
+       for ( i = 0; i < numBSPDrawSurfaces; i++ )
+       {
+               /* get info and attempt early out */
+               num = sortSurfaces[ i ];
+               ds = &bspDrawSurfaces[ num ];
+               info = &surfaceInfos[ num ];
+               if ( info->hasLightmap == qfalse || info->lm != NULL || info->parentSurfaceNum >= 0 ) {
+                       continue;
+               }
+
+               /* allocate a new raw lightmap */
+               lm = &rawLightmaps[ numRawLightmaps ];
+               numRawLightmaps++;
+
+               /* set it up */
+               lm->splotchFix = info->si->splotchFix;
+               lm->firstLightSurface = numLightSurfaces;
+               lm->numLightSurfaces = 0;
+               /* vortex: multiply lightmap sample size by -samplescale */
+               if ( sampleScale > 0 ) {
+                       lm->sampleSize = info->sampleSize * sampleScale;
+               }
+               else{
+                       lm->sampleSize = info->sampleSize;
+               }
+               lm->actualSampleSize = lm->sampleSize;
+               lm->entityNum = info->entityNum;
+               lm->recvShadows = info->recvShadows;
+               lm->brightness = info->si->lmBrightness;
+               lm->filterRadius = info->si->lmFilterRadius;
+               VectorCopy( info->si->floodlightRGB, lm->floodlightRGB );
+               lm->floodlightDistance = info->si->floodlightDistance;
+               lm->floodlightIntensity = info->si->floodlightIntensity;
+               lm->floodlightDirectionScale = info->si->floodlightDirectionScale;
+               VectorCopy( info->axis, lm->axis );
+               lm->plane = info->plane;
+               VectorCopy( info->mins, lm->mins );
+               VectorCopy( info->maxs, lm->maxs );
+
+               lm->customWidth = info->si->lmCustomWidth;
+               lm->customHeight = info->si->lmCustomHeight;
+
+               /* add the surface to the raw lightmap */
+               AddSurfaceToRawLightmap( num, lm );
+               info->lm = lm;
+
+               /* do an exhaustive merge */
+               added = qtrue;
+               while ( added )
+               {
+                       /* walk the list of surfaces again */
+                       added = qfalse;
+                       for ( j = i + 1; j < numBSPDrawSurfaces && lm->finished == qfalse; j++ )
+                       {
+                               /* get info and attempt early out */
+                               num2 = sortSurfaces[ j ];
+                               info2 = &surfaceInfos[ num2 ];
+                               if ( info2->hasLightmap == qfalse || info2->lm != NULL ) {
+                                       continue;
+                               }
+
+                               /* add the surface to the raw lightmap */
+                               if ( AddSurfaceToRawLightmap( num2, lm ) ) {
+                                       info2->lm = lm;
+                                       added = qtrue;
+                               }
+                               else
+                               {
+                                       /* back up one */
+                                       lm->numLightSurfaces--;
+                                       numLightSurfaces--;
+                               }
+                       }
+               }
+
+               /* finish the lightmap and allocate the various buffers */
+               FinishRawLightmap( lm );
+       }
+
+       /* allocate vertex luxel storage */
+       for ( k = 0; k < MAX_LIGHTMAPS; k++ )
+       {
+               vertexLuxels[ k ] = safe_malloc( numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
+               memset( vertexLuxels[ k ], 0, numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
+               radVertexLuxels[ k ] = safe_malloc( numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
+               memset( radVertexLuxels[ k ], 0, numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
+       }
+
+       /* emit some stats */
+       Sys_FPrintf( SYS_VRB, "%9d surfaces\n", numBSPDrawSurfaces );
+       Sys_FPrintf( SYS_VRB, "%9d raw lightmaps\n", numRawLightmaps );
+       Sys_FPrintf( SYS_VRB, "%9d surfaces vertex lit\n", numSurfsVertexLit );
+       Sys_FPrintf( SYS_VRB, "%9d surfaces lightmapped\n", numSurfsLightmapped );
+       Sys_FPrintf( SYS_VRB, "%9d planar surfaces lightmapped\n", numPlanarsLightmapped );
+       Sys_FPrintf( SYS_VRB, "%9d non-planar surfaces lightmapped\n", numNonPlanarsLightmapped );
+       Sys_FPrintf( SYS_VRB, "%9d patches lightmapped\n", numPatchesLightmapped );
+       Sys_FPrintf( SYS_VRB, "%9d planar patches lightmapped\n", numPlanarPatchesLightmapped );
+}
+
+
+
+/*
+   StitchSurfaceLightmaps()
+   stitches lightmap edges
+   2002-11-20 update: use this func only for stitching nonplanar patch lightmap seams
+ */
+
+#define MAX_STITCH_CANDIDATES   32
+#define MAX_STITCH_LUXELS       64
+
+void StitchSurfaceLightmaps( void ){
+       int i, j, x, y, x2, y2, *cluster, *cluster2,
+               numStitched, numCandidates, numLuxels, f, fOld, start;
+       rawLightmap_t   *lm, *a, *b, *c[ MAX_STITCH_CANDIDATES ];
+       float           *luxel, *luxel2, *origin, *origin2, *normal, *normal2,
+                                        sampleSize, average[ 3 ], totalColor, ootc;
+
+
+       /* disabled for now */
+       return;
+
+       /* note it */
+       Sys_Printf( "--- StitchSurfaceLightmaps ---\n" );
+
+       /* init pacifier */
+       fOld = -1;
+       start = I_FloatTime();
+
+       /* walk the list of raw lightmaps */
+       numStitched = 0;
+       for ( i = 0; i < numRawLightmaps; i++ )
+       {
+               /* print pacifier */
+               f = 10 * i / numRawLightmaps;
+               if ( f != fOld ) {
+                       fOld = f;
+                       Sys_Printf( "%i...", f );
+               }
+
+               /* get lightmap a */
+               a = &rawLightmaps[ i ];
+
+               /* walk rest of lightmaps */
+               numCandidates = 0;
+               for ( j = i + 1; j < numRawLightmaps && numCandidates < MAX_STITCH_CANDIDATES; j++ )
+               {
+                       /* get lightmap b */
+                       b = &rawLightmaps[ j ];
+
+                       /* test bounding box */
+                       if ( a->mins[ 0 ] > b->maxs[ 0 ] || a->maxs[ 0 ] < b->mins[ 0 ] ||
+                                a->mins[ 1 ] > b->maxs[ 1 ] || a->maxs[ 1 ] < b->mins[ 1 ] ||
+                                a->mins[ 2 ] > b->maxs[ 2 ] || a->maxs[ 2 ] < b->mins[ 2 ] ) {
+                               continue;
+                       }
+
+                       /* add candidate */
+                       c[ numCandidates++ ] = b;
+               }
+
+               /* walk luxels */
+               for ( y = 0; y < a->sh; y++ )
+               {
+                       for ( x = 0; x < a->sw; x++ )
+                       {
+                               /* ignore unmapped/unlit luxels */
+                               lm = a;
+                               cluster = SUPER_CLUSTER( x, y );
+                               if ( *cluster == CLUSTER_UNMAPPED ) {
+                                       continue;
+                               }
+                               luxel = SUPER_LUXEL( 0, x, y );
+                               if ( luxel[ 3 ] <= 0.0f ) {
+                                       continue;
+                               }
+
+                               /* get particulars */
+                               origin = SUPER_ORIGIN( x, y );
+                               normal = SUPER_NORMAL( x, y );
+
+                               /* walk candidate list */
+                               for ( j = 0; j < numCandidates; j++ )
+                               {
+                                       /* get candidate */
+                                       b = c[ j ];
+                                       lm = b;
+
+                                       /* set samplesize to the smaller of the pair */
+                                       sampleSize = 0.5f * ( a->actualSampleSize < b->actualSampleSize ? a->actualSampleSize : b->actualSampleSize );
+
+                                       /* test bounding box */
+                                       if ( origin[ 0 ] < ( b->mins[ 0 ] - sampleSize ) || ( origin[ 0 ] > b->maxs[ 0 ] + sampleSize ) ||
+                                                origin[ 1 ] < ( b->mins[ 1 ] - sampleSize ) || ( origin[ 1 ] > b->maxs[ 1 ] + sampleSize ) ||
+                                                origin[ 2 ] < ( b->mins[ 2 ] - sampleSize ) || ( origin[ 2 ] > b->maxs[ 2 ] + sampleSize ) ) {
+                                               continue;
+                                       }
+
+                                       /* walk candidate luxels */
+                                       VectorClear( average );
+                                       numLuxels = 0;
+                                       totalColor = 0.0f;
+                                       for ( y2 = 0; y2 < b->sh && numLuxels < MAX_STITCH_LUXELS; y2++ )
+                                       {
+                                               for ( x2 = 0; x2 < b->sw && numLuxels < MAX_STITCH_LUXELS; x2++ )
+                                               {
+                                                       /* ignore same luxels */
+                                                       if ( a == b && abs( x - x2 ) <= 1 && abs( y - y2 ) <= 1 ) {
+                                                               continue;
+                                                       }
+
+                                                       /* ignore unmapped/unlit luxels */
+                                                       cluster2 = SUPER_CLUSTER( x2, y2 );
+                                                       if ( *cluster2 == CLUSTER_UNMAPPED ) {
+                                                               continue;
+                                                       }
+                                                       luxel2 = SUPER_LUXEL( 0, x2, y2 );
+                                                       if ( luxel2[ 3 ] <= 0.0f ) {
+                                                               continue;
+                                                       }
+
+                                                       /* get particulars */
+                                                       origin2 = SUPER_ORIGIN( x2, y2 );
+                                                       normal2 = SUPER_NORMAL( x2, y2 );
+
+                                                       /* test normal */
+                                                       if ( DotProduct( normal, normal2 ) < 0.5f ) {
+                                                               continue;
+                                                       }
+
+                                                       /* test bounds */
+                                                       if ( fabs( origin[ 0 ] - origin2[ 0 ] ) > sampleSize ||
+                                                                fabs( origin[ 1 ] - origin2[ 1 ] ) > sampleSize ||
+                                                                fabs( origin[ 2 ] - origin2[ 2 ] ) > sampleSize ) {
+                                                               continue;
+                                                       }
+
+                                                       /* add luxel */
+                                                       //%     VectorSet( luxel2, 255, 0, 255 );
+                                                       VectorAdd( average, luxel2, average );
+                                                       totalColor += luxel2[ 3 ];
+                                               }
+                                       }
+
+                                       /* early out */
+                                       if ( numLuxels == 0 ) {
+                                               continue;
+                                       }
+
+                                       /* scale average */
+                                       ootc = 1.0f / totalColor;
+                                       VectorScale( average, ootc, luxel );
+                                       luxel[ 3 ] = 1.0f;
+                                       numStitched++;
+                               }
+                       }
+               }
+       }
+
+       /* emit statistics */
+       Sys_Printf( " (%i)\n", (int) ( I_FloatTime() - start ) );
+       Sys_FPrintf( SYS_VRB, "%9d luxels stitched\n", numStitched );
+}
+
+
+
+/*
+   CompareBSPLuxels()
+   compares two surface lightmaps' bsp luxels, ignoring occluded luxels
+ */
+
+#define SOLID_EPSILON       0.0625
+#define LUXEL_TOLERANCE     0.0025
+#define LUXEL_COLOR_FRAC    0.001302083 /* 1 / 3 / 256 */
+
+static qboolean CompareBSPLuxels( rawLightmap_t *a, int aNum, rawLightmap_t *b, int bNum ){
+       rawLightmap_t   *lm;
+       int x, y;
+       double delta, total, rd, gd, bd;
+       float           *aLuxel, *bLuxel;
+
+
+       /* styled lightmaps will never be collapsed to non-styled lightmaps when there is _minlight */
+       if ( ( minLight[ 0 ] || minLight[ 1 ] || minLight[ 2 ] ) &&
+                ( ( aNum == 0 && bNum != 0 ) || ( aNum != 0 && bNum == 0 ) ) ) {
+               return qfalse;
+       }
+
+       /* basic tests */
+       if ( a->customWidth != b->customWidth || a->customHeight != b->customHeight ||
+                a->brightness != b->brightness ||
+                a->solid[ aNum ] != b->solid[ bNum ] ||
+                a->bspLuxels[ aNum ] == NULL || b->bspLuxels[ bNum ] == NULL ) {
+               return qfalse;
+       }
+
+       /* compare solid color lightmaps */
+       if ( a->solid[ aNum ] && b->solid[ bNum ] ) {
+               /* get deltas */
+               rd = fabs( a->solidColor[ aNum ][ 0 ] - b->solidColor[ bNum ][ 0 ] );
+               gd = fabs( a->solidColor[ aNum ][ 1 ] - b->solidColor[ bNum ][ 1 ] );
+               bd = fabs( a->solidColor[ aNum ][ 2 ] - b->solidColor[ bNum ][ 2 ] );
+
+               /* compare color */
+               if ( rd > SOLID_EPSILON || gd > SOLID_EPSILON || bd > SOLID_EPSILON ) {
+                       return qfalse;
+               }
+
+               /* okay */
+               return qtrue;
+       }
+
+       /* compare nonsolid lightmaps */
+       if ( a->w != b->w || a->h != b->h ) {
+               return qfalse;
+       }
+
+       /* compare luxels */
+       delta = 0.0;
+       total = 0.0;
+       for ( y = 0; y < a->h; y++ )
+       {
+               for ( x = 0; x < a->w; x++ )
+               {
+                       /* increment total */
+                       total += 1.0;
+
+                       /* get luxels */
+                       lm = a; aLuxel = BSP_LUXEL( aNum, x, y );
+                       lm = b; bLuxel = BSP_LUXEL( bNum, x, y );
+
+                       /* ignore unused luxels */
+                       if ( aLuxel[ 0 ] < 0 || bLuxel[ 0 ] < 0 ) {
+                               continue;
+                       }
+
+                       /* get deltas */
+                       rd = fabs( aLuxel[ 0 ] - bLuxel[ 0 ] );
+                       gd = fabs( aLuxel[ 1 ] - bLuxel[ 1 ] );
+                       bd = fabs( aLuxel[ 2 ] - bLuxel[ 2 ] );
+
+                       /* 2003-09-27: compare individual luxels */
+                       if ( rd > 3.0 || gd > 3.0 || bd > 3.0 ) {
+                               return qfalse;
+                       }
+
+                       /* compare (fixme: take into account perceptual differences) */
+                       delta += rd * LUXEL_COLOR_FRAC;
+                       delta += gd * LUXEL_COLOR_FRAC;
+                       delta += bd * LUXEL_COLOR_FRAC;
+
+                       /* is the change too high? */
+                       if ( total > 0.0 && ( ( delta / total ) > LUXEL_TOLERANCE ) ) {
+                               return qfalse;
+                       }
+               }
+       }
+
+       /* made it this far, they must be identical (or close enough) */
+       return qtrue;
+}
+
+
+
+/*
+   MergeBSPLuxels()
+   merges two surface lightmaps' bsp luxels, overwriting occluded luxels
+ */
+
+static qboolean MergeBSPLuxels( rawLightmap_t *a, int aNum, rawLightmap_t *b, int bNum ){
+       rawLightmap_t   *lm;
+       int x, y;
+       float luxel[ 3 ], *aLuxel, *bLuxel;
+
+
+       /* basic tests */
+       if ( a->customWidth != b->customWidth || a->customHeight != b->customHeight ||
+                a->brightness != b->brightness ||
+                a->solid[ aNum ] != b->solid[ bNum ] ||
+                a->bspLuxels[ aNum ] == NULL || b->bspLuxels[ bNum ] == NULL ) {
+               return qfalse;
+       }
+
+       /* compare solid lightmaps */
+       if ( a->solid[ aNum ] && b->solid[ bNum ] ) {
+               /* average */
+               VectorAdd( a->solidColor[ aNum ], b->solidColor[ bNum ], luxel );
+               VectorScale( luxel, 0.5f, luxel );
+
+               /* copy to both */
+               VectorCopy( luxel, a->solidColor[ aNum ] );
+               VectorCopy( luxel, b->solidColor[ bNum ] );
+
+               /* return to sender */
+               return qtrue;
+       }
+
+       /* compare nonsolid lightmaps */
+       if ( a->w != b->w || a->h != b->h ) {
+               return qfalse;
+       }
+
+       /* merge luxels */
+       for ( y = 0; y < a->h; y++ )
+       {
+               for ( x = 0; x < a->w; x++ )
+               {
+                       /* get luxels */
+                       lm = a; aLuxel = BSP_LUXEL( aNum, x, y );
+                       lm = b; bLuxel = BSP_LUXEL( bNum, x, y );
+
+                       /* handle occlusion mismatch */
+                       if ( aLuxel[ 0 ] < 0.0f ) {
+                               VectorCopy( bLuxel, aLuxel );
+                       }
+                       else if ( bLuxel[ 0 ] < 0.0f ) {
+                               VectorCopy( aLuxel, bLuxel );
+                       }
+                       else
+                       {
+                               /* average */
+                               VectorAdd( aLuxel, bLuxel, luxel );
+                               VectorScale( luxel, 0.5f, luxel );
+
+                               /* debugging code */
+                               //%     luxel[ 2 ] += 64.0f;
+
+                               /* copy to both */
+                               VectorCopy( luxel, aLuxel );
+                               VectorCopy( luxel, bLuxel );
+                       }
+               }
+       }
+
+       /* done */
+       return qtrue;
+}
+
+
+
+/*
+   ApproximateLuxel()
+   determines if a single luxel is can be approximated with the interpolated vertex rgba
+ */
+
+static qboolean ApproximateLuxel( rawLightmap_t *lm, bspDrawVert_t *dv ){
+       int i, x, y, d, lightmapNum;
+       float   *luxel;
+       vec3_t color, vertexColor;
+       byte cb[ 4 ], vcb[ 4 ];
+
+
+       /* find luxel xy coords */
+       x = dv->lightmap[ 0 ][ 0 ] / superSample;
+       y = dv->lightmap[ 0 ][ 1 ] / superSample;
+       if ( x < 0 ) {
+               x = 0;
+       }
+       else if ( x >= lm->w ) {
+               x = lm->w - 1;
+       }
+       if ( y < 0 ) {
+               y = 0;
+       }
+       else if ( y >= lm->h ) {
+               y = lm->h - 1;
+       }
+
+       /* walk list */
+       for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+       {
+               /* early out */
+               if ( lm->styles[ lightmapNum ] == LS_NONE ) {
+                       continue;
+               }
+
+               /* get luxel */
+               luxel = BSP_LUXEL( lightmapNum, x, y );
+
+               /* ignore occluded luxels */
+               if ( luxel[ 0 ] < 0.0f || luxel[ 1 ] < 0.0f || luxel[ 2 ] < 0.0f ) {
+                       return qtrue;
+               }
+
+               /* copy, set min color and compare */
+               VectorCopy( luxel, color );
+               VectorCopy( dv->color[ 0 ], vertexColor );
+
+               /* styles are not affected by minlight */
+               if ( lightmapNum == 0 ) {
+                       for ( i = 0; i < 3; i++ )
+                       {
+                               /* set min color */
+                               if ( color[ i ] < minLight[ i ] ) {
+                                       color[ i ] = minLight[ i ];
+                               }
+                               if ( vertexColor[ i ] < minLight[ i ] ) { /* note NOT minVertexLight */
+                                       vertexColor[ i ] = minLight[ i ];
+                               }
+                       }
+               }
+
+               /* set to bytes */
+               ColorToBytes( color, cb, 1.0f );
+               ColorToBytes( vertexColor, vcb, 1.0f );
+
+               /* compare */
+               for ( i = 0; i < 3; i++ )
+               {
+                       d = cb[ i ] - vcb[ i ];
+                       if ( d < 0 ) {
+                               d *= -1;
+                       }
+                       if ( d > approximateTolerance ) {
+                               return qfalse;
+                       }
+               }
+       }
+
+       /* close enough for the girls i date */
+       return qtrue;
+}
+
+
+
+/*
+   ApproximateTriangle()
+   determines if a single triangle can be approximated with vertex rgba
+ */
+
+static qboolean ApproximateTriangle_r( rawLightmap_t *lm, bspDrawVert_t *dv[ 3 ] ){
+       bspDrawVert_t mid, *dv2[ 3 ];
+       int max;
+
+
+       /* approximate the vertexes */
+       if ( ApproximateLuxel( lm, dv[ 0 ] ) == qfalse ) {
+               return qfalse;
+       }
+       if ( ApproximateLuxel( lm, dv[ 1 ] ) == qfalse ) {
+               return qfalse;
+       }
+       if ( ApproximateLuxel( lm, dv[ 2 ] ) == qfalse ) {
+               return qfalse;
+       }
+
+       /* subdivide calc */
+       {
+               int i;
+               float dx, dy, dist, maxDist;
+
+
+               /* find the longest edge and split it */
+               max = -1;
+               maxDist = 0;
+               for ( i = 0; i < 3; i++ )
+               {
+                       dx = dv[ i ]->lightmap[ 0 ][ 0 ] - dv[ ( i + 1 ) % 3 ]->lightmap[ 0 ][ 0 ];
+                       dy = dv[ i ]->lightmap[ 0 ][ 1 ] - dv[ ( i + 1 ) % 3 ]->lightmap[ 0 ][ 1 ];
+                       dist = sqrt( ( dx * dx ) + ( dy * dy ) );
+                       if ( dist > maxDist ) {
+                               maxDist = dist;
+                               max = i;
+                       }
+               }
+
+               /* try to early out */
+               if ( i < 0 || maxDist < subdivideThreshold ) {
+                       return qtrue;
+               }
+       }
+
+       /* split the longest edge and map it */
+       LerpDrawVert( dv[ max ], dv[ ( max + 1 ) % 3 ], &mid );
+       if ( ApproximateLuxel( lm, &mid ) == qfalse ) {
+               return qfalse;
+       }
+
+       /* recurse to first triangle */
+       VectorCopy( dv, dv2 );
+       dv2[ max ] = &mid;
+       if ( ApproximateTriangle_r( lm, dv2 ) == qfalse ) {
+               return qfalse;
+       }
+
+       /* recurse to second triangle */
+       VectorCopy( dv, dv2 );
+       dv2[ ( max + 1 ) % 3 ] = &mid;
+       return ApproximateTriangle_r( lm, dv2 );
+}
+
+
+
+/*
+   ApproximateLightmap()
+   determines if a raw lightmap can be approximated sufficiently with vertex colors
+ */
+
+static qboolean ApproximateLightmap( rawLightmap_t *lm ){
+       int n, num, i, x, y, pw[ 5 ], r;
+       bspDrawSurface_t    *ds;
+       surfaceInfo_t       *info;
+       mesh_t src, *subdivided, *mesh;
+       bspDrawVert_t       *verts, *dv[ 3 ];
+       qboolean approximated;
+
+
+       /* approximating? */
+       if ( approximateTolerance <= 0 ) {
+               return qfalse;
+       }
+
+       /* test for jmonroe */
+       #if 0
+       /* don't approx lightmaps with styled twins */
+       if ( lm->numStyledTwins > 0 ) {
+               return qfalse;
+       }
+
+       /* don't approx lightmaps with styles */
+       for ( i = 1; i < MAX_LIGHTMAPS; i++ )
+       {
+               if ( lm->styles[ i ] != LS_NONE ) {
+                       return qfalse;
+               }
+       }
+       #endif
+
+       /* assume reduced until shadow detail is found */
+       approximated = qtrue;
+
+       /* walk the list of surfaces on this raw lightmap */
+       for ( n = 0; n < lm->numLightSurfaces; n++ )
+       {
+               /* get surface */
+               num = lightSurfaces[ lm->firstLightSurface + n ];
+               ds = &bspDrawSurfaces[ num ];
+               info = &surfaceInfos[ num ];
+
+               /* assume not-reduced initially */
+               info->approximated = qfalse;
+
+               /* bail if lightmap doesn't match up */
+               if ( info->lm != lm ) {
+                       continue;
+               }
+
+               /* bail if not vertex lit */
+               if ( info->si->noVertexLight ) {
+                       continue;
+               }
+
+               /* assume that surfaces whose bounding boxes is smaller than 2x samplesize will be forced to vertex */
+               if ( ( info->maxs[ 0 ] - info->mins[ 0 ] ) <= ( 2.0f * info->sampleSize ) &&
+                        ( info->maxs[ 1 ] - info->mins[ 1 ] ) <= ( 2.0f * info->sampleSize ) &&
+                        ( info->maxs[ 2 ] - info->mins[ 2 ] ) <= ( 2.0f * info->sampleSize ) ) {
+                       info->approximated = qtrue;
+                       numSurfsVertexForced++;
+                       continue;
+               }
+
+               /* handle the triangles */
+               switch ( ds->surfaceType )
+               {
+               case MST_PLANAR:
+                       /* get verts */
+                       verts = yDrawVerts + ds->firstVert;
+
+                       /* map the triangles */
+                       info->approximated = qtrue;
+                       for ( i = 0; i < ds->numIndexes && info->approximated; 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 ] ];
+                               info->approximated = ApproximateTriangle_r( lm, dv );
+                       }
+                       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;
+
+                       /* map the mesh quads */
+                       info->approximated = qtrue;
+                       for ( y = 0; y < ( mesh->height - 1 ) && info->approximated; y++ )
+                       {
+                               for ( x = 0; x < ( mesh->width - 1 ) && info->approximated; 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 ] ];
+                                       info->approximated = ApproximateTriangle_r( lm, dv );
+
+                                       /* get drawverts and map second triangle */
+                                       dv[ 0 ] = &verts[ pw[ r + 0 ] ];
+                                       dv[ 1 ] = &verts[ pw[ r + 2 ] ];
+                                       dv[ 2 ] = &verts[ pw[ r + 3 ] ];
+                                       if ( info->approximated ) {
+                                               info->approximated = ApproximateTriangle_r( lm, dv );
+                                       }
+                               }
+                       }
+
+                       /* free the mesh */
+                       FreeMesh( mesh );
+                       break;
+
+               default:
+                       break;
+               }
+
+               /* reduced? */
+               if ( info->approximated == qfalse ) {
+                       approximated = qfalse;
+               }
+               else{
+                       numSurfsVertexApproximated++;
+               }
+       }
+
+       /* return */
+       return approximated;
+}
+
+
+
+/*
+   TestOutLightmapStamp()
+   tests a stamp on a given lightmap for validity
+ */
+
+static qboolean TestOutLightmapStamp( rawLightmap_t *lm, int lightmapNum, outLightmap_t *olm, int x, int y ){
+       int sx, sy, ox, oy, offset;
+       float       *luxel;
+
+
+       /* bounds check */
+       if ( x < 0 || y < 0 || ( x + lm->w ) > olm->customWidth || ( y + lm->h ) > olm->customHeight ) {
+               return qfalse;
+       }
+
+       /* solid lightmaps test a 1x1 stamp */
+       if ( lm->solid[ lightmapNum ] ) {
+               offset = ( y * olm->customWidth ) + x;
+               if ( olm->lightBits[ offset >> 3 ] & ( 1 << ( offset & 7 ) ) ) {
+                       return qfalse;
+               }
+               return qtrue;
+       }
+
+       /* test the stamp */
+       for ( sy = 0; sy < lm->h; sy++ )
+       {
+               for ( sx = 0; sx < lm->w; sx++ )
+               {
+                       /* get luxel */
+                       luxel = BSP_LUXEL( lightmapNum, sx, sy );
+                       if ( luxel[ 0 ] < 0.0f ) {
+                               continue;
+                       }
+
+                       /* get bsp lightmap coords and test */
+                       ox = x + sx;
+                       oy = y + sy;
+                       offset = ( oy * olm->customWidth ) + ox;
+                       if ( olm->lightBits[ offset >> 3 ] & ( 1 << ( offset & 7 ) ) ) {
+                               return qfalse;
+                       }
+               }
+       }
+
+       /* stamp is empty */
+       return qtrue;
+}
+
+
+
+/*
+   SetupOutLightmap()
+   sets up an output lightmap
+ */
+
+static void SetupOutLightmap( rawLightmap_t *lm, outLightmap_t *olm ){
+       /* dummy check */
+       if ( lm == NULL || olm == NULL ) {
+               return;
+       }
+
+       /* is this a "normal" bsp-stored lightmap? */
+       if ( ( lm->customWidth == game->lightmapSize && lm->customHeight == game->lightmapSize ) || externalLightmaps ) {
+               olm->lightmapNum = numBSPLightmaps;
+               numBSPLightmaps++;
+
+               /* lightmaps are interleaved with light direction maps */
+               if ( deluxemap ) {
+                       numBSPLightmaps++;
+               }
+       }
+       else{
+               olm->lightmapNum = -3;
+       }
+
+       /* set external lightmap number */
+       olm->extLightmapNum = -1;
+
+       /* set it up */
+       olm->numLightmaps = 0;
+       olm->customWidth = lm->customWidth;
+       olm->customHeight = lm->customHeight;
+       olm->freeLuxels = olm->customWidth * olm->customHeight;
+       olm->numShaders = 0;
+
+       /* allocate buffers */
+       olm->lightBits = safe_malloc( ( olm->customWidth * olm->customHeight / 8 ) + 8 );
+       memset( olm->lightBits, 0, ( olm->customWidth * olm->customHeight / 8 ) + 8 );
+       olm->bspLightBytes = safe_malloc( olm->customWidth * olm->customHeight * 3 );
+       memset( olm->bspLightBytes, 0, olm->customWidth * olm->customHeight * 3 );
+       if ( deluxemap ) {
+               olm->bspDirBytes = safe_malloc( olm->customWidth * olm->customHeight * 3 );
+               memset( olm->bspDirBytes, 0, olm->customWidth * olm->customHeight * 3 );
+       }
+}
+
+
+
+/*
+   FindOutLightmaps()
+   for a given surface lightmap, find output lightmap pages and positions for it
+ */
+
+#define LIGHTMAP_RESERVE_COUNT 1
+static void FindOutLightmaps( rawLightmap_t *lm, qboolean fastAllocate ){
+       int i, j, k, lightmapNum, xMax, yMax, x = -1, y = -1, sx, sy, ox, oy, offset;
+       outLightmap_t       *olm;
+       surfaceInfo_t       *info;
+       float               *luxel, *deluxel;
+       vec3_t color, direction;
+       byte                *pixel;
+       qboolean ok;
+       int xIncrement, yIncrement;
+
+
+       /* set default lightmap number (-3 = LIGHTMAP_BY_VERTEX) */
+       for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+               lm->outLightmapNums[ lightmapNum ] = -3;
+
+       /* can this lightmap be approximated with vertex color? */
+       if ( ApproximateLightmap( lm ) ) {
+               return;
+       }
+
+       /* walk list */
+       for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+       {
+               /* early out */
+               if ( lm->styles[ lightmapNum ] == LS_NONE ) {
+                       continue;
+               }
+
+               /* don't store twinned lightmaps */
+               if ( lm->twins[ lightmapNum ] != NULL ) {
+                       continue;
+               }
+
+               /* if this is a styled lightmap, try some normalized locations first */
+               ok = qfalse;
+               if ( lightmapNum > 0 && outLightmaps != NULL ) {
+                       /* loop twice */
+                       for ( j = 0; j < 2; j++ )
+                       {
+                               /* try identical position */
+                               for ( i = 0; i < numOutLightmaps; i++ )
+                               {
+                                       /* get the output lightmap */
+                                       olm = &outLightmaps[ i ];
+
+                                       /* simple early out test */
+                                       if ( olm->freeLuxels < lm->used ) {
+                                               continue;
+                                       }
+
+                                       /* don't store non-custom raw lightmaps on custom bsp lightmaps */
+                                       if ( olm->customWidth != lm->customWidth ||
+                                                olm->customHeight != lm->customHeight ) {
+                                               continue;
+                                       }
+
+                                       /* try identical */
+                                       if ( j == 0 ) {
+                                               x = lm->lightmapX[ 0 ];
+                                               y = lm->lightmapY[ 0 ];
+                                               ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );
+                                       }
+
+                                       /* try shifting */
+                                       else
+                                       {
+                                               for ( sy = -1; sy <= 1; sy++ )
+                                               {
+                                                       for ( sx = -1; sx <= 1; sx++ )
+                                                       {
+                                                               x = lm->lightmapX[ 0 ] + sx * ( olm->customWidth >> 1 );  //%   lm->w;
+                                                               y = lm->lightmapY[ 0 ] + sy * ( olm->customHeight >> 1 ); //%   lm->h;
+                                                               ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );
+
+                                                               if ( ok ) {
+                                                                       break;
+                                                               }
+                                                       }
+
+                                                       if ( ok ) {
+                                                               break;
+                                                       }
+                                               }
+                                       }
+
+                                       if ( ok ) {
+                                               break;
+                                       }
+                               }
+
+                               if ( ok ) {
+                                       break;
+                               }
+                       }
+               }
+
+               /* try normal placement algorithm */
+               if ( ok == qfalse ) {
+                       /* reset origin */
+                       x = 0;
+                       y = 0;
+
+                       /* walk the list of lightmap pages */
+                       if ( lightmapSearchBlockSize <= 0 || numOutLightmaps < LIGHTMAP_RESERVE_COUNT ) {
+                               i = 0;
+                       }
+                       else{
+                               i = ( ( numOutLightmaps - LIGHTMAP_RESERVE_COUNT ) / lightmapSearchBlockSize ) * lightmapSearchBlockSize;
+                       }
+                       for ( ; i < numOutLightmaps; i++ )
+                       {
+                               /* get the output lightmap */
+                               olm = &outLightmaps[ i ];
+
+                               /* simple early out test */
+                               if ( olm->freeLuxels < lm->used ) {
+                                       continue;
+                               }
+
+                               /* if fast allocation, skip lightmap files that are more than 90% complete */
+                               if ( fastAllocate == qtrue ) {
+                                       if (olm->freeLuxels < (olm->customWidth * olm->customHeight) / 10) {
+                                               continue;
+                                       }
+                               }
+
+                               /* don't store non-custom raw lightmaps on custom bsp lightmaps */
+                               if ( olm->customWidth != lm->customWidth ||
+                                        olm->customHeight != lm->customHeight ) {
+                                       continue;
+                               }
+
+                               /* set maxs */
+                               if ( lm->solid[ lightmapNum ] ) {
+                                       xMax = olm->customWidth;
+                                       yMax = olm->customHeight;
+                               }
+                               else
+                               {
+                                       xMax = ( olm->customWidth - lm->w ) + 1;
+                                       yMax = ( olm->customHeight - lm->h ) + 1;
+                               }
+
+                               /* if fast allocation, do not test allocation on every pixels, especially for large lightmaps */
+                               if ( fastAllocate == qtrue ) {
+                                       xIncrement = MAX(1, lm->w / 15);
+                                       yIncrement = MAX(1, lm->h / 15);
+                               }
+                               else {
+                                       xIncrement = 1;
+                                       yIncrement = 1;
+                               }
+
+                               /* walk the origin around the lightmap */
+                               for ( y = 0; y < yMax; y += yIncrement )
+                               {
+                                       for ( x = 0; x < xMax; x += xIncrement )
+                                       {
+                                               /* find a fine tract of lauhnd */
+                                               ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );
+
+                                               if ( ok ) {
+                                                       break;
+                                               }
+                                       }
+
+                                       if ( ok ) {
+                                               break;
+                                       }
+                               }
+
+                               if ( ok ) {
+                                       break;
+                               }
+
+                               /* reset x and y */
+                               x = 0;
+                               y = 0;
+                       }
+               }
+
+               /* no match? */
+               if ( ok == qfalse ) {
+                       /* allocate LIGHTMAP_RESERVE_COUNT new output lightmaps */
+                       numOutLightmaps += LIGHTMAP_RESERVE_COUNT;
+                       olm = safe_malloc( numOutLightmaps * sizeof( outLightmap_t ) );
+                       if ( outLightmaps != NULL && numOutLightmaps > LIGHTMAP_RESERVE_COUNT ) {
+                               memcpy( olm, outLightmaps, ( numOutLightmaps - LIGHTMAP_RESERVE_COUNT ) * sizeof( outLightmap_t ) );
+                               free( outLightmaps );
+                       }
+                       outLightmaps = olm;
+
+                       /* initialize both out lightmaps */
+                       for ( k = numOutLightmaps - LIGHTMAP_RESERVE_COUNT; k < numOutLightmaps; ++k )
+                               SetupOutLightmap( lm, &outLightmaps[ k ] );
+
+                       /* set out lightmap */
+                       i = numOutLightmaps - LIGHTMAP_RESERVE_COUNT;
+                       olm = &outLightmaps[ i ];
+
+                       /* set stamp xy origin to the first surface lightmap */
+                       if ( lightmapNum > 0 ) {
+                               x = lm->lightmapX[ 0 ];
+                               y = lm->lightmapY[ 0 ];
+                       }
+               }
+
+               /* if this is a style-using lightmap, it must be exported */
+               if ( lightmapNum > 0 && game->load != LoadRBSPFile ) {
+                       olm->extLightmapNum = 0;
+               }
+
+               /* add the surface lightmap to the bsp lightmap */
+               lm->outLightmapNums[ lightmapNum ] = i;
+               lm->lightmapX[ lightmapNum ] = x;
+               lm->lightmapY[ lightmapNum ] = y;
+               olm->numLightmaps++;
+
+               /* add shaders */
+               for ( i = 0; i < lm->numLightSurfaces; i++ )
+               {
+                       /* get surface info */
+                       info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + i ] ];
+
+                       /* test for shader */
+                       for ( j = 0; j < olm->numShaders; j++ )
+                       {
+                               if ( olm->shaders[ j ] == info->si ) {
+                                       break;
+                               }
+                       }
+
+                       /* if it doesn't exist, add it */
+                       if ( j >= olm->numShaders && olm->numShaders < MAX_LIGHTMAP_SHADERS ) {
+                               olm->shaders[ olm->numShaders ] = info->si;
+                               olm->numShaders++;
+                               numLightmapShaders++;
+                       }
+               }
+
+               /* set maxs */
+               if ( lm->solid[ lightmapNum ] ) {
+                       xMax = 1;
+                       yMax = 1;
+               }
+               else
+               {
+                       xMax = lm->w;
+                       yMax = lm->h;
+               }
+
+               /* mark the bits used */
+               for ( y = 0; y < yMax; y++ )
+               {
+                       for ( x = 0; x < xMax; x++ )
+                       {
+                               /* get luxel */
+                               luxel = BSP_LUXEL( lightmapNum, x, y );
+                               deluxel = BSP_DELUXEL( x, y );
+                               if ( luxel[ 0 ] < 0.0f && !lm->solid[ lightmapNum ] ) {
+                                       continue;
+                               }
+
+                               /* set minimum light */
+                               if ( lm->solid[ lightmapNum ] ) {
+                                       if ( debug ) {
+                                               VectorSet( color, 255.0f, 0.0f, 0.0f );
+                                       }
+                                       else{
+                                               VectorCopy( lm->solidColor[ lightmapNum ], color );
+                                       }
+                               }
+                               else{
+                                       VectorCopy( luxel, color );
+                               }
+
+                               /* styles are not affected by minlight */
+                               if ( lightmapNum == 0 ) {
+                                       for ( i = 0; i < 3; i++ )
+                                       {
+                                               if ( color[ i ] < minLight[ i ] ) {
+                                                       color[ i ] = minLight[ i ];
+                                               }
+                                       }
+                               }
+
+                               /* get bsp lightmap coords  */
+                               ox = x + lm->lightmapX[ lightmapNum ];
+                               oy = y + lm->lightmapY[ lightmapNum ];
+                               offset = ( oy * olm->customWidth ) + ox;
+
+                               /* flag pixel as used */
+                               olm->lightBits[ offset >> 3 ] |= ( 1 << ( offset & 7 ) );
+                               olm->freeLuxels--;
+
+                               /* store color */
+                               pixel = olm->bspLightBytes + ( ( ( oy * olm->customWidth ) + ox ) * 3 );
+                               ColorToBytes( color, pixel, lm->brightness );
+
+                               /* store direction */
+                               if ( deluxemap ) {
+                                       /* normalize average light direction */
+                                       pixel = olm->bspDirBytes + ( ( ( oy * olm->customWidth ) + ox ) * 3 );
+                                       VectorScale( deluxel, 1000.0f, direction );
+                                       VectorNormalize( direction, direction );
+                                       VectorScale( direction, 127.5f, direction );
+                                       for ( i = 0; i < 3; i++ )
+                                               pixel[ i ] = (byte)( 127.5f + direction[ i ] );
+                               }
+                       }
+               }
+       }
+}
+
+
+
+/*
+   CompareRawLightmap()
+   compare function for qsort()
+ */
+
+static int CompareRawLightmap( const void *a, const void *b ){
+       rawLightmap_t   *alm, *blm;
+       surfaceInfo_t   *aInfo, *bInfo;
+       int i, min, diff;
+
+
+       /* get lightmaps */
+       alm = &rawLightmaps[ *( (const int*) a ) ];
+       blm = &rawLightmaps[ *( (const int*) b ) ];
+
+       /* get min number of surfaces */
+       min = ( alm->numLightSurfaces < blm->numLightSurfaces ? alm->numLightSurfaces : blm->numLightSurfaces );
+
+       /* iterate */
+       for ( i = 0; i < min; i++ )
+       {
+               /* get surface info */
+               aInfo = &surfaceInfos[ lightSurfaces[ alm->firstLightSurface + i ] ];
+               bInfo = &surfaceInfos[ lightSurfaces[ blm->firstLightSurface + i ] ];
+
+               /* compare shader names */
+               diff = strcmp( aInfo->si->shader, bInfo->si->shader );
+               if ( diff != 0 ) {
+                       return diff;
+               }
+       }
+
+       /* test style count */
+       diff = 0;
+       for ( i = 0; i < MAX_LIGHTMAPS; i++ )
+               diff += blm->styles[ i ] - alm->styles[ i ];
+       if ( diff ) {
+               return diff;
+       }
+
+       /* compare size */
+       diff = ( blm->w * blm->h ) - ( alm->w * alm->h );
+       if ( diff != 0 ) {
+               return diff;
+       }
+
+       /* must be equivalent */
+       return 0;
+}
+
+void FillOutLightmap( outLightmap_t *olm ){
+       int x, y;
+       int ofs;
+       vec3_t dir_sum, light_sum;
+       int cnt, filled;
+       byte *lightBitsNew = NULL;
+       byte *lightBytesNew = NULL;
+       byte *dirBytesNew = NULL;
+
+       lightBitsNew = safe_malloc( ( olm->customWidth * olm->customHeight + 8 ) / 8 );
+       lightBytesNew = safe_malloc( olm->customWidth * olm->customHeight * 3 );
+       if ( deluxemap ) {
+               dirBytesNew = safe_malloc( olm->customWidth * olm->customHeight * 3 );
+       }
+
+       /*
+          memset(olm->lightBits, 0, (olm->customWidth * olm->customHeight + 8) / 8);
+           olm->lightBits[0] |= 1;
+           olm->lightBits[(10 * olm->customWidth + 30) >> 3] |= 1 << ((10 * olm->customWidth + 30) & 7);
+          memset(olm->bspLightBytes, 0, olm->customWidth * olm->customHeight * 3);
+           olm->bspLightBytes[0] = 255;
+           olm->bspLightBytes[(10 * olm->customWidth + 30) * 3 + 2] = 255;
+        */
+
+       memcpy( lightBitsNew, olm->lightBits, ( olm->customWidth * olm->customHeight + 8 ) / 8 );
+       memcpy( lightBytesNew, olm->bspLightBytes, olm->customWidth * olm->customHeight * 3 );
+       if ( deluxemap ) {
+               memcpy( dirBytesNew, olm->bspDirBytes, olm->customWidth * olm->customHeight * 3 );
+       }
+
+       for (;; )
+       {
+               filled = 0;
+               for ( y = 0; y < olm->customHeight; ++y )
+               {
+                       for ( x = 0; x < olm->customWidth; ++x )
+                       {
+                               ofs = y * olm->customWidth + x;
+                               if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
+                                       continue;
+                               }
+                               cnt = 0;
+                               VectorClear( dir_sum );
+                               VectorClear( light_sum );
+
+                               /* try all four neighbors */
+                               ofs = ( ( y + olm->customHeight - 1 ) % olm->customHeight ) * olm->customWidth + x;
+                               if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
+                                       ++cnt;
+                                       VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
+                                       if ( deluxemap ) {
+                                               VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
+                                       }
+                               }
+
+                               ofs = ( ( y + 1 ) % olm->customHeight ) * olm->customWidth + x;
+                               if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
+                                       ++cnt;
+                                       VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
+                                       if ( deluxemap ) {
+                                               VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
+                                       }
+                               }
+
+                               ofs = y * olm->customWidth + ( x + olm->customWidth - 1 ) % olm->customWidth;
+                               if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
+                                       ++cnt;
+                                       VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
+                                       if ( deluxemap ) {
+                                               VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
+                                       }
+                               }
+
+                               ofs = y * olm->customWidth + ( x + 1 ) % olm->customWidth;
+                               if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
+                                       ++cnt;
+                                       VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
+                                       if ( deluxemap ) {
+                                               VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
+                                       }
+                               }
+
+                               if ( cnt ) {
+                                       ++filled;
+                                       ofs = y * olm->customWidth + x;
+                                       lightBitsNew[ofs >> 3] |= ( 1 << ( ofs & 7 ) );
+                                       VectorScale( light_sum, 1.0 / cnt, lightBytesNew + ofs * 3 );
+                                       if ( deluxemap ) {
+                                               VectorScale( dir_sum, 1.0 / cnt, dirBytesNew + ofs * 3 );
+                                       }
+                               }
+                       }
+               }
+
+               if ( !filled ) {
+                       break;
+               }
+
+               memcpy( olm->lightBits, lightBitsNew, ( olm->customWidth * olm->customHeight + 8 ) / 8 );
+               memcpy( olm->bspLightBytes, lightBytesNew, olm->customWidth * olm->customHeight * 3 );
+               if ( deluxemap ) {
+                       memcpy( olm->bspDirBytes, dirBytesNew, olm->customWidth * olm->customHeight * 3 );
+               }
+       }
+
+       free( lightBitsNew );
+       free( lightBytesNew );
+       if ( deluxemap ) {
+               free( dirBytesNew );
+       }
+}
+
+/*
+   StoreSurfaceLightmaps()
+   stores the surface lightmaps into the bsp as byte rgb triplets
+ */
+
+void StoreSurfaceLightmaps( qboolean fastAllocate ){
+       int i, j, k, x, y, lx, ly, sx, sy, *cluster, mappedSamples;
+       int style, size, lightmapNum, lightmapNum2;
+       float               *normal, *luxel, *bspLuxel, *bspLuxel2, *radLuxel, samples, occludedSamples;
+       vec3_t sample, occludedSample, dirSample, colorMins, colorMaxs;
+       float               *deluxel, *bspDeluxel, *bspDeluxel2;
+       byte                *lb;
+       int numUsed, numTwins, numTwinLuxels, numStored;
+       float lmx, lmy, efficiency;
+       vec3_t color;
+       bspDrawSurface_t    *ds, *parent, dsTemp;
+       surfaceInfo_t       *info;
+       rawLightmap_t       *lm, *lm2;
+       outLightmap_t       *olm;
+       bspDrawVert_t       *dv, *ydv, *dvParent;
+       char dirname[ 1024 ], filename[ 1024 ];
+       shaderInfo_t        *csi;
+       char lightmapName[ 128 ];
+       const char              *rgbGenValues[ 256 ];
+       const char              *alphaGenValues[ 256 ];
+
+
+       /* note it */
+       Sys_Printf( "--- StoreSurfaceLightmaps ---\n" );
+
+       /* setup */
+       if ( lmCustomDir ) {
+               strcpy( dirname, lmCustomDir );
+       }
+       else
+       {
+               strcpy( dirname, source );
+               StripExtension( dirname );
+       }
+       memset( rgbGenValues, 0, sizeof( rgbGenValues ) );
+       memset( alphaGenValues, 0, sizeof( alphaGenValues ) );
+
+       /* -----------------------------------------------------------------
+          average the sampled luxels into the bsp luxels
+          ----------------------------------------------------------------- */
+
+       /* note it */
+       Sys_Printf( "Subsampling..." );
+
+       /* walk the list of raw lightmaps */
+       numUsed = 0;
+       numTwins = 0;
+       numTwinLuxels = 0;
+       numSolidLightmaps = 0;
+       for ( i = 0; i < numRawLightmaps; i++ )
+       {
+               /* get lightmap */
+               lm = &rawLightmaps[ i ];
+
+               /* walk individual lightmaps */
+               for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+               {
+                       /* early outs */
+                       if ( lm->superLuxels[ lightmapNum ] == NULL ) {
+                               continue;
+                       }
+
+                       /* allocate bsp luxel storage */
+                       if ( lm->bspLuxels[ lightmapNum ] == NULL ) {
+                               size = lm->w * lm->h * BSP_LUXEL_SIZE * sizeof( float );
+                               lm->bspLuxels[ lightmapNum ] = safe_malloc( size );
+                               memset( lm->bspLuxels[ lightmapNum ], 0, size );
+                       }
+
+                       /* allocate radiosity lightmap storage */
+                       if ( bounce ) {
+                               size = lm->w * lm->h * RAD_LUXEL_SIZE * sizeof( float );
+                               if ( lm->radLuxels[ lightmapNum ] == NULL ) {
+                                       lm->radLuxels[ lightmapNum ] = safe_malloc( size );
+                               }
+                               memset( lm->radLuxels[ lightmapNum ], 0, size );
+                       }
+
+                       /* average supersampled luxels */
+                       for ( y = 0; y < lm->h; y++ )
+                       {
+                               for ( x = 0; x < lm->w; x++ )
+                               {
+                                       /* subsample */
+                                       samples = 0.0f;
+                                       occludedSamples = 0.0f;
+                                       mappedSamples = 0;
+                                       VectorClear( sample );
+                                       VectorClear( occludedSample );
+                                       VectorClear( dirSample );
+                                       for ( ly = 0; ly < superSample; ly++ )
+                                       {
+                                               for ( lx = 0; lx < superSample; lx++ )
+                                               {
+                                                       /* sample luxel */
+                                                       sx = x * superSample + lx;
+                                                       sy = y * superSample + ly;
+                                                       luxel = SUPER_LUXEL( lightmapNum, sx, sy );
+                                                       deluxel = SUPER_DELUXEL( sx, sy );
+                                                       normal = SUPER_NORMAL( sx, sy );
+                                                       cluster = SUPER_CLUSTER( sx, sy );
+
+                                                       /* sample deluxemap */
+                                                       if ( deluxemap && lightmapNum == 0 ) {
+                                                               VectorAdd( dirSample, deluxel, dirSample );
+                                                       }
+
+                                                       /* keep track of used/occluded samples */
+                                                       if ( *cluster != CLUSTER_UNMAPPED ) {
+                                                               mappedSamples++;
+                                                       }
+
+                                                       /* handle lightmap border? */
+                                                       if ( lightmapBorder && ( sx == 0 || sx == ( lm->sw - 1 ) || sy == 0 || sy == ( lm->sh - 1 ) ) && luxel[ 3 ] > 0.0f ) {
+                                                               VectorSet( sample, 255.0f, 0.0f, 0.0f );
+                                                               samples += 1.0f;
+                                                       }
+
+                                                       /* handle debug */
+                                                       else if ( debug && *cluster < 0 ) {
+                                                               if ( *cluster == CLUSTER_UNMAPPED ) {
+                                                                       VectorSet( luxel, 255, 204, 0 );
+                                                               }
+                                                               else if ( *cluster == CLUSTER_OCCLUDED ) {
+                                                                       VectorSet( luxel, 255, 0, 255 );
+                                                               }
+                                                               else if ( *cluster == CLUSTER_FLOODED ) {
+                                                                       VectorSet( luxel, 0, 32, 255 );
+                                                               }
+                                                               VectorAdd( occludedSample, luxel, occludedSample );
+                                                               occludedSamples += 1.0f;
+                                                       }
+
+                                                       /* normal luxel handling */
+                                                       else if ( luxel[ 3 ] > 0.0f ) {
+                                                               /* handle lit or flooded luxels */
+                                                               if ( *cluster > 0 || *cluster == CLUSTER_FLOODED ) {
+                                                                       VectorAdd( sample, luxel, sample );
+                                                                       samples += luxel[ 3 ];
+                                                               }
+
+                                                               /* handle occluded or unmapped luxels */
+                                                               else
+                                                               {
+                                                                       VectorAdd( occludedSample, luxel, occludedSample );
+                                                                       occludedSamples += luxel[ 3 ];
+                                                               }
+
+                                                               /* handle style debugging */
+                                                               if ( debug && lightmapNum > 0 && x < 2 && y < 2 ) {
+                                                                       VectorCopy( debugColors[ 0 ], sample );
+                                                                       samples = 1;
+                                                               }
+                                                       }
+                                               }
+                                       }
+
+                                       /* only use occluded samples if necessary */
+                                       if ( samples <= 0.0f ) {
+                                               VectorCopy( occludedSample, sample );
+                                               samples = occludedSamples;
+                                       }
+
+                                       /* get luxels */
+                                       luxel = SUPER_LUXEL( lightmapNum, x, y );
+                                       deluxel = SUPER_DELUXEL( x, y );
+
+                                       /* store light direction */
+                                       if ( deluxemap && lightmapNum == 0 ) {
+                                               VectorCopy( dirSample, deluxel );
+                                       }
+
+                                       /* store the sample back in super luxels */
+                                       if ( samples > 0.01f ) {
+                                               VectorScale( sample, ( 1.0f / samples ), luxel );
+                                               luxel[ 3 ] = 1.0f;
+                                       }
+
+                                       /* if any samples were mapped in any way, store ambient color */
+                                       else if ( mappedSamples > 0 ) {
+                                               if ( lightmapNum == 0 ) {
+                                                       VectorCopy( ambientColor, luxel );
+                                               }
+                                               else{
+                                                       VectorClear( luxel );
+                                               }
+                                               luxel[ 3 ] = 1.0f;
+                                       }
+
+                                       /* store a bogus value to be fixed later */
+                                       else
+                                       {
+                                               VectorClear( luxel );
+                                               luxel[ 3 ] = -1.0f;
+                                       }
+                               }
+                       }
+
+                       /* setup */
+                       lm->used = 0;
+                       ClearBounds( colorMins, colorMaxs );
+
+                       /* clean up and store into bsp luxels */
+                       for ( y = 0; y < lm->h; y++ )
+                       {
+                               for ( x = 0; x < lm->w; x++ )
+                               {
+                                       /* get luxels */
+                                       luxel = SUPER_LUXEL( lightmapNum, x, y );
+                                       deluxel = SUPER_DELUXEL( x, y );
+
+                                       /* copy light direction */
+                                       if ( deluxemap && lightmapNum == 0 ) {
+                                               VectorCopy( deluxel, dirSample );
+                                       }
+
+                                       /* is this a valid sample? */
+                                       if ( luxel[ 3 ] > 0.0f ) {
+                                               VectorCopy( luxel, sample );
+                                               samples = luxel[ 3 ];
+                                               numUsed++;
+                                               lm->used++;
+
+                                               /* fix negative samples */
+                                               for ( j = 0; j < 3; j++ )
+                                               {
+                                                       if ( sample[ j ] < 0.0f ) {
+                                                               sample[ j ] = 0.0f;
+                                                       }
+                                               }
+                                       }
+                                       else
+                                       {
+                                               /* nick an average value from the neighbors */
+                                               VectorClear( sample );
+                                               VectorClear( dirSample );
+                                               samples = 0.0f;
+
+                                               /* fixme: why is this disabled?? */
+                                               for ( sy = ( y - 1 ); sy <= ( y + 1 ); sy++ )
+                                               {
+                                                       if ( sy < 0 || sy >= lm->h ) {
+                                                               continue;
+                                                       }
+
+                                                       for ( sx = ( x - 1 ); sx <= ( x + 1 ); sx++ )
+                                                       {
+                                                               if ( sx < 0 || sx >= lm->w || ( sx == x && sy == y ) ) {
+                                                                       continue;
+                                                               }
+
+                                                               /* get neighbor's particulars */
+                                                               luxel = SUPER_LUXEL( lightmapNum, sx, sy );
+                                                               if ( luxel[ 3 ] < 0.0f ) {
+                                                                       continue;
+                                                               }
+                                                               VectorAdd( sample, luxel, sample );
+                                                               samples += luxel[ 3 ];
+                                                       }
+                                               }
+
+                                               /* no samples? */
+                                               if ( samples == 0.0f ) {
+                                                       VectorSet( sample, -1.0f, -1.0f, -1.0f );
+                                                       samples = 1.0f;
+                                               }
+                                               else
+                                               {
+                                                       numUsed++;
+                                                       lm->used++;
+
+                                                       /* fix negative samples */
+                                                       for ( j = 0; j < 3; j++ )
+                                                       {
+                                                               if ( sample[ j ] < 0.0f ) {
+                                                                       sample[ j ] = 0.0f;
+                                                               }
+                                                       }
+                                               }
+                                       }
+
+                                       /* scale the sample */
+                                       VectorScale( sample, ( 1.0f / samples ), sample );
+
+                                       /* store the sample in the radiosity luxels */
+                                       if ( bounce > 0 ) {
+                                               radLuxel = RAD_LUXEL( lightmapNum, x, y );
+                                               VectorCopy( sample, radLuxel );
+
+                                               /* if only storing bounced light, early out here */
+                                               if ( bounceOnly && !bouncing ) {
+                                                       continue;
+                                               }
+                                       }
+
+                                       /* store the sample in the bsp luxels */
+                                       bspLuxel = BSP_LUXEL( lightmapNum, x, y );
+                                       bspDeluxel = BSP_DELUXEL( x, y );
+
+                                       VectorAdd( bspLuxel, sample, bspLuxel );
+                                       if ( deluxemap && lightmapNum == 0 ) {
+                                               VectorAdd( bspDeluxel, dirSample, bspDeluxel );
+                                       }
+
+                                       /* add color to bounds for solid checking */
+                                       if ( samples > 0.0f ) {
+                                               AddPointToBounds( bspLuxel, colorMins, colorMaxs );
+                                       }
+                               }
+                       }
+
+                       /* set solid color */
+                       lm->solid[ lightmapNum ] = qfalse;
+                       VectorAdd( colorMins, colorMaxs, lm->solidColor[ lightmapNum ] );
+                       VectorScale( lm->solidColor[ lightmapNum ], 0.5f, lm->solidColor[ lightmapNum ] );
+
+                       /* nocollapse prevents solid lightmaps */
+                       if ( noCollapse == qfalse ) {
+                               /* check solid color */
+                               VectorSubtract( colorMaxs, colorMins, sample );
+                               if ( ( sample[ 0 ] <= SOLID_EPSILON && sample[ 1 ] <= SOLID_EPSILON && sample[ 2 ] <= SOLID_EPSILON ) ||
+                                        ( lm->w <= 2 && lm->h <= 2 ) ) { /* small lightmaps get forced to solid color */
+                                       /* set to solid */
+                                       VectorCopy( colorMins, lm->solidColor[ lightmapNum ] );
+                                       lm->solid[ lightmapNum ] = qtrue;
+                                       numSolidLightmaps++;
+                               }
+
+                               /* if all lightmaps aren't solid, then none of them are solid */
+                               if ( lm->solid[ lightmapNum ] != lm->solid[ 0 ] ) {
+                                       for ( y = 0; y < MAX_LIGHTMAPS; y++ )
+                                       {
+                                               if ( lm->solid[ y ] ) {
+                                                       numSolidLightmaps--;
+                                               }
+                                               lm->solid[ y ] = qfalse;
+                                       }
+                               }
+                       }
+
+                       /* wrap bsp luxels if necessary */
+                       if ( lm->wrap[ 0 ] ) {
+                               for ( y = 0; y < lm->h; y++ )
+                               {
+                                       bspLuxel = BSP_LUXEL( lightmapNum, 0, y );
+                                       bspLuxel2 = BSP_LUXEL( lightmapNum, lm->w - 1, y );
+                                       VectorAdd( bspLuxel, bspLuxel2, bspLuxel );
+                                       VectorScale( bspLuxel, 0.5f, bspLuxel );
+                                       VectorCopy( bspLuxel, bspLuxel2 );
+                                       if ( deluxemap && lightmapNum == 0 ) {
+                                               bspDeluxel = BSP_DELUXEL( 0, y );
+                                               bspDeluxel2 = BSP_DELUXEL( lm->w - 1, y );
+                                               VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel );
+                                               VectorScale( bspDeluxel, 0.5f, bspDeluxel );
+                                               VectorCopy( bspDeluxel, bspDeluxel2 );
+                                       }
+                               }
+                       }
+                       if ( lm->wrap[ 1 ] ) {
+                               for ( x = 0; x < lm->w; x++ )
+                               {
+                                       bspLuxel = BSP_LUXEL( lightmapNum, x, 0 );
+                                       bspLuxel2 = BSP_LUXEL( lightmapNum, x, lm->h - 1 );
+                                       VectorAdd( bspLuxel, bspLuxel2, bspLuxel );
+                                       VectorScale( bspLuxel, 0.5f, bspLuxel );
+                                       VectorCopy( bspLuxel, bspLuxel2 );
+                                       if ( deluxemap && lightmapNum == 0 ) {
+                                               bspDeluxel = BSP_DELUXEL( x, 0 );
+                                               bspDeluxel2 = BSP_DELUXEL( x, lm->h - 1 );
+                                               VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel );
+                                               VectorScale( bspDeluxel, 0.5f, bspDeluxel );
+                                               VectorCopy( bspDeluxel, bspDeluxel2 );
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* -----------------------------------------------------------------
+          convert modelspace deluxemaps to tangentspace
+          ----------------------------------------------------------------- */
+       /* note it */
+       if ( !bouncing ) {
+               if ( deluxemap && deluxemode == 1 ) {
+                       vec3_t worldUp, myNormal, myTangent, myBinormal;
+                       float dist;
+
+                       Sys_Printf( "converting..." );
+
+                       for ( i = 0; i < numRawLightmaps; i++ )
+                       {
+                               /* get lightmap */
+                               lm = &rawLightmaps[ i ];
+
+                               /* walk lightmap samples */
+                               for ( y = 0; y < lm->sh; y++ )
+                               {
+                                       for ( x = 0; x < lm->sw; x++ )
+                                       {
+                                               /* get normal and deluxel */
+                                               normal = SUPER_NORMAL( x, y );
+                                               cluster = SUPER_CLUSTER( x, y );
+                                               bspDeluxel = BSP_DELUXEL( x, y );
+                                               deluxel = SUPER_DELUXEL( x, y );
+
+                                               /* get normal */
+                                               VectorSet( myNormal, normal[0], normal[1], normal[2] );
+
+                                               /* get tangent vectors */
+                                               if ( myNormal[ 0 ] == 0.0f && myNormal[ 1 ] == 0.0f ) {
+                                                       if ( myNormal[ 2 ] == 1.0f ) {
+                                                               VectorSet( myTangent, 1.0f, 0.0f, 0.0f );
+                                                               VectorSet( myBinormal, 0.0f, 1.0f, 0.0f );
+                                                       }
+                                                       else if ( myNormal[ 2 ] == -1.0f ) {
+                                                               VectorSet( myTangent, -1.0f, 0.0f, 0.0f );
+                                                               VectorSet( myBinormal,  0.0f, 1.0f, 0.0f );
+                                                       }
+                                               }
+                                               else
+                                               {
+                                                       VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
+                                                       CrossProduct( myNormal, worldUp, myTangent );
+                                                       VectorNormalize( myTangent, myTangent );
+                                                       CrossProduct( myTangent, myNormal, myBinormal );
+                                                       VectorNormalize( myBinormal, myBinormal );
+                                               }
+
+                                               /* project onto plane */
+                                               dist = -DotProduct( myTangent, myNormal );
+                                               VectorMA( myTangent, dist, myNormal, myTangent );
+                                               dist = -DotProduct( myBinormal, myNormal );
+                                               VectorMA( myBinormal, dist, myNormal, myBinormal );
+
+                                               /* renormalize */
+                                               VectorNormalize( myTangent, myTangent );
+                                               VectorNormalize( myBinormal, myBinormal );
+
+                                               /* convert modelspace deluxel to tangentspace */
+                                               dirSample[0] = bspDeluxel[0];
+                                               dirSample[1] = bspDeluxel[1];
+                                               dirSample[2] = bspDeluxel[2];
+                                               VectorNormalize( dirSample, dirSample );
+
+                                               /* fix tangents to world matrix */
+                                               if ( myNormal[0] > 0 || myNormal[1] < 0 || myNormal[2] < 0 ) {
+                                                       VectorNegate( myTangent, myTangent );
+                                               }
+
+                                               /* build tangentspace vectors */
+                                               bspDeluxel[0] = DotProduct( dirSample, myTangent );
+                                               bspDeluxel[1] = DotProduct( dirSample, myBinormal );
+                                               bspDeluxel[2] = DotProduct( dirSample, myNormal );
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* -----------------------------------------------------------------
+          blend lightmaps
+          ----------------------------------------------------------------- */
+
+#ifdef sdfsdfwq312323
+       /* note it */
+       Sys_Printf( "blending..." );
+
+       for ( i = 0; i < numRawLightmaps; i++ )
+       {
+               vec3_t myColor;
+               float myBrightness;
+
+               /* get lightmap */
+               lm = &rawLightmaps[ i ];
+
+               /* walk individual lightmaps */
+               for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+               {
+                       /* early outs */
+                       if ( lm->superLuxels[ lightmapNum ] == NULL ) {
+                               continue;
+                       }
+
+                       /* walk lightmap samples */
+                       for ( y = 0; y < lm->sh; y++ )
+                       {
+                               for ( x = 0; x < lm->sw; x++ )
+                               {
+                                       /* get luxel */
+                                       bspLuxel = BSP_LUXEL( lightmapNum, x, y );
+
+                                       /* get color */
+                                       VectorNormalize( bspLuxel, myColor );
+                                       myBrightness = VectorLength( bspLuxel );
+                                       myBrightness *= ( 1 / 127.0f );
+                                       myBrightness = myBrightness * myBrightness;
+                                       myBrightness *= 127.0f;
+                                       VectorScale( myColor, myBrightness, bspLuxel );
+                               }
+                       }
+               }
+       }
+#endif
+
+       /* -----------------------------------------------------------------
+          collapse non-unique lightmaps
+          ----------------------------------------------------------------- */
+
+       if ( noCollapse == qfalse && deluxemap == qfalse ) {
+               /* note it */
+               Sys_Printf( "collapsing..." );
+
+               /* set all twin refs to null */
+               for ( i = 0; i < numRawLightmaps; i++ )
+               {
+                       for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+                       {
+                               rawLightmaps[ i ].twins[ lightmapNum ] = NULL;
+                               rawLightmaps[ i ].twinNums[ lightmapNum ] = -1;
+                               rawLightmaps[ i ].numStyledTwins = 0;
+                       }
+               }
+
+               /* walk the list of raw lightmaps */
+               for ( i = 0; i < numRawLightmaps; i++ )
+               {
+                       /* get lightmap */
+                       lm = &rawLightmaps[ i ];
+
+                       /* walk lightmaps */
+                       for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+                       {
+                               /* early outs */
+                               if ( lm->bspLuxels[ lightmapNum ] == NULL ||
+                                        lm->twins[ lightmapNum ] != NULL ) {
+                                       continue;
+                               }
+
+                               /* find all lightmaps that are virtually identical to this one */
+                               for ( j = i + 1; j < numRawLightmaps; j++ )
+                               {
+                                       /* get lightmap */
+                                       lm2 = &rawLightmaps[ j ];
+
+                                       /* walk lightmaps */
+                                       for ( lightmapNum2 = 0; lightmapNum2 < MAX_LIGHTMAPS; lightmapNum2++ )
+                                       {
+                                               /* early outs */
+                                               if ( lm2->bspLuxels[ lightmapNum2 ] == NULL ||
+                                                        lm2->twins[ lightmapNum2 ] != NULL ) {
+                                                       continue;
+                                               }
+
+                                               /* compare them */
+                                               if ( CompareBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ) ) {
+                                                       /* merge and set twin */
+                                                       if ( MergeBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ) ) {
+                                                               lm2->twins[ lightmapNum2 ] = lm;
+                                                               lm2->twinNums[ lightmapNum2 ] = lightmapNum;
+                                                               numTwins++;
+                                                               numTwinLuxels += ( lm->w * lm->h );
+
+                                                               /* count styled twins */
+                                                               if ( lightmapNum > 0 ) {
+                                                                       lm->numStyledTwins++;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* -----------------------------------------------------------------
+          sort raw lightmaps by shader
+          ----------------------------------------------------------------- */
+
+       /* note it */
+       Sys_Printf( "sorting..." );
+
+       /* allocate a new sorted list */
+       if ( sortLightmaps == NULL ) {
+               sortLightmaps = safe_malloc( numRawLightmaps * sizeof( int ) );
+       }
+
+       /* fill it out and sort it */
+       for ( i = 0; i < numRawLightmaps; i++ )
+               sortLightmaps[ i ] = i;
+       qsort( sortLightmaps, numRawLightmaps, sizeof( int ), CompareRawLightmap );
+
+       /* -----------------------------------------------------------------
+          allocate output lightmaps
+          ----------------------------------------------------------------- */
+
+       /* note it */
+       Sys_Printf( "allocating..." );
+
+       /* kill all existing output lightmaps */
+       if ( outLightmaps != NULL ) {
+               for ( i = 0; i < numOutLightmaps; i++ )
+               {
+                       free( outLightmaps[ i ].lightBits );
+                       free( outLightmaps[ i ].bspLightBytes );
+               }
+               free( outLightmaps );
+               outLightmaps = NULL;
+       }
+
+       numLightmapShaders = 0;
+       numOutLightmaps = 0;
+       numBSPLightmaps = 0;
+       numExtLightmaps = 0;
+
+       /* find output lightmap */
+       for ( i = 0; i < numRawLightmaps; i++ )
+       {
+               lm = &rawLightmaps[ sortLightmaps[ i ] ];
+               FindOutLightmaps( lm, fastAllocate );
+       }
+
+       /* set output numbers in twinned lightmaps */
+       for ( i = 0; i < numRawLightmaps; i++ )
+       {
+               /* get lightmap */
+               lm = &rawLightmaps[ sortLightmaps[ i ] ];
+
+               /* walk lightmaps */
+               for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+               {
+                       /* get twin */
+                       lm2 = lm->twins[ lightmapNum ];
+                       if ( lm2 == NULL ) {
+                               continue;
+                       }
+                       lightmapNum2 = lm->twinNums[ lightmapNum ];
+
+                       /* find output lightmap from twin */
+                       lm->outLightmapNums[ lightmapNum ] = lm2->outLightmapNums[ lightmapNum2 ];
+                       lm->lightmapX[ lightmapNum ] = lm2->lightmapX[ lightmapNum2 ];
+                       lm->lightmapY[ lightmapNum ] = lm2->lightmapY[ lightmapNum2 ];
+               }
+       }
+
+       /* -----------------------------------------------------------------
+          store output lightmaps
+          ----------------------------------------------------------------- */
+
+       /* note it */
+       Sys_Printf( "storing..." );
+
+       /* count the bsp lightmaps and allocate space */
+       if ( bspLightBytes != NULL ) {
+               free( bspLightBytes );
+       }
+       if ( numBSPLightmaps == 0 || externalLightmaps ) {
+               numBSPLightBytes = 0;
+               bspLightBytes = NULL;
+       }
+       else
+       {
+               numBSPLightBytes = ( numBSPLightmaps * game->lightmapSize * game->lightmapSize * 3 );
+               bspLightBytes = safe_malloc( numBSPLightBytes );
+               memset( bspLightBytes, 0, numBSPLightBytes );
+       }
+
+       /* walk the list of output lightmaps */
+       for ( i = 0; i < numOutLightmaps; i++ )
+       {
+               /* get output lightmap */
+               olm = &outLightmaps[ i ];
+
+               /* fill output lightmap */
+               if ( lightmapFill ) {
+                       FillOutLightmap( olm );
+               }
+
+               /* is this a valid bsp lightmap? */
+               if ( olm->lightmapNum >= 0 && !externalLightmaps ) {
+                       /* copy lighting data */
+                       lb = bspLightBytes + ( olm->lightmapNum * game->lightmapSize * game->lightmapSize * 3 );
+                       memcpy( lb, olm->bspLightBytes, game->lightmapSize * game->lightmapSize * 3 );
+
+                       /* copy direction data */
+                       if ( deluxemap ) {
+                               lb = bspLightBytes + ( ( olm->lightmapNum + 1 ) * game->lightmapSize * game->lightmapSize * 3 );
+                               memcpy( lb, olm->bspDirBytes, game->lightmapSize * game->lightmapSize * 3 );
+                       }
+               }
+
+               /* external lightmap? */
+               if ( olm->lightmapNum < 0 || olm->extLightmapNum >= 0 || externalLightmaps ) {
+                       /* make a directory for the lightmaps */
+                       Q_mkdir( dirname );
+
+                       /* set external lightmap number */
+                       olm->extLightmapNum = numExtLightmaps;
+
+                       /* write lightmap */
+                       sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
+                       Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
+                       WriteTGA24( filename, olm->bspLightBytes, olm->customWidth, olm->customHeight, qtrue );
+                       numExtLightmaps++;
+
+                       /* write deluxemap */
+                       if ( deluxemap ) {
+                               sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
+                               Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
+                               WriteTGA24( filename, olm->bspDirBytes, olm->customWidth, olm->customHeight, qtrue );
+                               numExtLightmaps++;
+
+                               if ( debugDeluxemap ) {
+                                       olm->extLightmapNum++;
+                               }
+                       }
+               }
+       }
+
+       if ( numExtLightmaps > 0 ) {
+               Sys_Printf( "\n" );
+       }
+
+       /* delete unused external lightmaps */
+       for ( i = numExtLightmaps; i; i++ )
+       {
+               /* determine if file exists */
+               sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, i );
+               if ( !FileExists( filename ) ) {
+                       break;
+               }
+
+               /* delete it */
+               remove( filename );
+       }
+
+       /* -----------------------------------------------------------------
+          project the lightmaps onto the bsp surfaces
+          ----------------------------------------------------------------- */
+
+       /* note it */
+       Sys_Printf( "projecting..." );
+
+       /* walk the list of surfaces */
+       for ( i = 0; i < numBSPDrawSurfaces; i++ )
+       {
+               /* get the surface and info */
+               ds = &bspDrawSurfaces[ i ];
+               info = &surfaceInfos[ i ];
+               lm = info->lm;
+               olm = NULL;
+
+               /* handle surfaces with identical parent */
+               if ( info->parentSurfaceNum >= 0 ) {
+                       /* preserve original data and get parent */
+                       parent = &bspDrawSurfaces[ info->parentSurfaceNum ];
+                       memcpy( &dsTemp, ds, sizeof( *ds ) );
+
+                       /* overwrite child with parent data */
+                       memcpy( ds, parent, sizeof( *ds ) );
+
+                       /* restore key parts */
+                       ds->fogNum = dsTemp.fogNum;
+                       ds->firstVert = dsTemp.firstVert;
+                       ds->firstIndex = dsTemp.firstIndex;
+                       memcpy( ds->lightmapVecs, dsTemp.lightmapVecs, sizeof( dsTemp.lightmapVecs ) );
+
+                       /* set vertex data */
+                       dv = &bspDrawVerts[ ds->firstVert ];
+                       dvParent = &bspDrawVerts[ parent->firstVert ];
+                       for ( j = 0; j < ds->numVerts; j++ )
+                       {
+                               memcpy( dv[ j ].lightmap, dvParent[ j ].lightmap, sizeof( dv[ j ].lightmap ) );
+                               memcpy( dv[ j ].color, dvParent[ j ].color, sizeof( dv[ j ].color ) );
+                       }
+
+                       /* skip the rest */
+                       continue;
+               }
+
+               /* handle vertex lit or approximated surfaces */
+               else if ( lm == NULL || lm->outLightmapNums[ 0 ] < 0 ) {
+                       for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+                       {
+                               ds->lightmapNum[ lightmapNum ] = -3;
+                               ds->lightmapStyles[ lightmapNum ] = ds->vertexStyles[ lightmapNum ];
+                       }
+               }
+
+               /* handle lightmapped surfaces */
+               else
+               {
+                       /* walk lightmaps */
+                       for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+                       {
+                               /* set style */
+                               ds->lightmapStyles[ lightmapNum ] = lm->styles[ lightmapNum ];
+
+                               /* handle unused style */
+                               if ( lm->styles[ lightmapNum ] == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 ) {
+                                       ds->lightmapNum[ lightmapNum ] = -3;
+                                       continue;
+                               }
+
+                               /* get output lightmap */
+                               olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
+
+                               /* set bsp lightmap number */
+                               ds->lightmapNum[ lightmapNum ] = olm->lightmapNum;
+
+                               /* deluxemap debugging makes the deluxemap visible */
+                               if ( deluxemap && debugDeluxemap && lightmapNum == 0 ) {
+                                       ds->lightmapNum[ lightmapNum ]++;
+                               }
+
+                               /* calc lightmap origin in texture space */
+                               lmx = (float) lm->lightmapX[ lightmapNum ] / (float) olm->customWidth;
+                               lmy = (float) lm->lightmapY[ lightmapNum ] / (float) olm->customHeight;
+
+                               /* calc lightmap st coords */
+                               dv = &bspDrawVerts[ ds->firstVert ];
+                               ydv = &yDrawVerts[ ds->firstVert ];
+                               for ( j = 0; j < ds->numVerts; j++ )
+                               {
+                                       if ( lm->solid[ lightmapNum ] ) {
+                                               dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + ( 0.5f / (float) olm->customWidth );
+                                               dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + ( 0.5f / (float) olm->customWidth );
+                                       }
+                                       else
+                                       {
+                                               dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + ( ydv[ j ].lightmap[ 0 ][ 0 ] / ( superSample * olm->customWidth ) );
+                                               dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + ( ydv[ j ].lightmap[ 0 ][ 1 ] / ( superSample * olm->customHeight ) );
+                                       }
+                               }
+                       }
+               }
+
+               /* store vertex colors */
+               dv = &bspDrawVerts[ ds->firstVert ];
+               for ( j = 0; j < ds->numVerts; j++ )
+               {
+                       /* walk lightmaps */
+                       for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+                       {
+                               /* handle unused style */
+                               if ( ds->vertexStyles[ lightmapNum ] == LS_NONE ) {
+                                       VectorClear( color );
+                               }
+                               else
+                               {
+                                       /* get vertex color */
+                                       luxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + j );
+                                       VectorCopy( luxel, color );
+
+                                       /* set minimum light */
+                                       if ( lightmapNum == 0 ) {
+                                               for ( k = 0; k < 3; k++ )
+                                                       if ( color[ k ] < minVertexLight[ k ] ) {
+                                                               color[ k ] = minVertexLight[ k ];
+                                                       }
+                                       }
+                               }
+
+                               /* store to bytes */
+                               if ( !info->si->noVertexLight ) {
+                                       ColorToBytes( color, dv[ j ].color[ lightmapNum ], info->si->vertexScale );
+                               }
+                       }
+               }
+
+               /* surfaces with styled lightmaps and a style marker get a custom generated shader (fixme: make this work with external lightmaps) */
+               if ( olm != NULL && lm != NULL && lm->styles[ 1 ] != LS_NONE && game->load != LoadRBSPFile ) { //%      info->si->styleMarker > 0 )
+                       qboolean dfEqual;
+                       char key[ 32 ], styleStage[ 512 ], styleStages[ 4096 ], rgbGen[ 128 ], alphaGen[ 128 ];
+
+
+                       /* setup */
+                       sprintf( styleStages, "\n\t// Q3Map2 custom lightstyle stage(s)\n" );
+                       dv = &bspDrawVerts[ ds->firstVert ];
+
+                       /* depthFunc equal? */
+                       if ( info->si->styleMarker == 2 || info->si->implicitMap == IM_MASKED ) {
+                               dfEqual = qtrue;
+                       }
+                       else{
+                               dfEqual = qfalse;
+                       }
+
+                       /* generate stages for styled lightmaps */
+                       for ( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+                       {
+                               /* early out */
+                               style = lm->styles[ lightmapNum ];
+                               if ( style == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 ) {
+                                       continue;
+                               }
+
+                               /* get output lightmap */
+                               olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
+
+                               /* lightmap name */
+                               if ( lm->outLightmapNums[ lightmapNum ] == lm->outLightmapNums[ 0 ] ) {
+                                       strcpy( lightmapName, "$lightmap" );
+                               }
+                               else{
+                                       sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
+                               }
+
+                               /* get rgbgen string */
+                               if ( rgbGenValues[ style ] == NULL ) {
+                                       sprintf( key, "_style%drgbgen", style );
+                                       rgbGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
+                                       if ( rgbGenValues[ style ][ 0 ] == '\0' ) {
+                                               rgbGenValues[ style ] = "wave noise 0.5 1 0 5.37";
+                                       }
+                               }
+                               rgbGen[ 0 ] = '\0';
+                               if ( rgbGenValues[ style ][ 0 ] != '\0' ) {
+                                       sprintf( rgbGen, "\t\trgbGen %s // style %d\n", rgbGenValues[ style ], style );
+                               }
+                               else{
+                                       rgbGen[ 0 ] = '\0';
+                               }
+
+                               /* get alphagen string */
+                               if ( alphaGenValues[ style ] == NULL ) {
+                                       sprintf( key, "_style%dalphagen", style );
+                                       alphaGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
+                               }
+                               if ( alphaGenValues[ style ][ 0 ] != '\0' ) {
+                                       sprintf( alphaGen, "\t\talphaGen %s // style %d\n", alphaGenValues[ style ], style );
+                               }
+                               else{
+                                       alphaGen[ 0 ] = '\0';
+                               }
+
+                               /* calculate st offset */
+                               lmx = dv[ 0 ].lightmap[ lightmapNum ][ 0 ] - dv[ 0 ].lightmap[ 0 ][ 0 ];
+                               lmy = dv[ 0 ].lightmap[ lightmapNum ][ 1 ] - dv[ 0 ].lightmap[ 0 ][ 1 ];
+
+                               /* create additional stage */
+                               if ( lmx == 0.0f && lmy == 0.0f ) {
+                                       sprintf( styleStage,    "\t{\n"
+                                                                                       "\t\tmap %s\n"                                      /* lightmap */
+                                                                                       "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
+                                                                                       "%s"                                                /* depthFunc equal */
+                                                                                       "%s"                                                /* rgbGen */
+                                                                                       "%s"                                                /* alphaGen */
+                                                                                       "\t\ttcGen lightmap\n"
+                                                                                       "\t}\n",
+                                                        lightmapName,
+                                                        ( dfEqual ? "\t\tdepthFunc equal\n" : "" ),
+                                                        rgbGen,
+                                                        alphaGen );
+                               }
+                               else
+                               {
+                                       sprintf( styleStage,    "\t{\n"
+                                                                                       "\t\tmap %s\n"                                      /* lightmap */
+                                                                                       "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
+                                                                                       "%s"                                                /* depthFunc equal */
+                                                                                       "%s"                                                /* rgbGen */
+                                                                                       "%s"                                                /* alphaGen */
+                                                                                       "\t\ttcGen lightmap\n"
+                                                                                       "\t\ttcMod transform 1 0 0 1 %1.5f %1.5f\n"         /* st offset */
+                                                                                       "\t}\n",
+                                                        lightmapName,
+                                                        ( dfEqual ? "\t\tdepthFunc equal\n" : "" ),
+                                                        rgbGen,
+                                                        alphaGen,
+                                                        lmx, lmy );
+
+                               }
+
+                               /* concatenate */
+                               strcat( styleStages, styleStage );
+                       }
+
+                       /* create custom shader */
+                       if ( info->si->styleMarker == 2 ) {
+                               csi = CustomShader( info->si, "q3map_styleMarker2", styleStages );
+                       }
+                       else{
+                               csi = CustomShader( info->si, "q3map_styleMarker", styleStages );
+                       }
+
+                       /* emit remap command */
+                       //%     EmitVertexRemapShader( csi->shader, info->si->shader );
+
+                       /* store it */
+                       //%     Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
+                       ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
+                       //%     Sys_Printf( ")\n" );
+               }
+
+               /* devise a custom shader for this surface (fixme: make this work with light styles) */
+               else if ( olm != NULL && lm != NULL && !externalLightmaps &&
+                                 ( olm->customWidth != game->lightmapSize || olm->customHeight != game->lightmapSize ) ) {
+                       /* get output lightmap */
+                       olm = &outLightmaps[ lm->outLightmapNums[ 0 ] ];
+
+                       /* do some name mangling */
+                       sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
+
+                       /* create custom shader */
+                       csi = CustomShader( info->si, "$lightmap", lightmapName );
+
+                       /* store it */
+                       //%     Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
+                       ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
+                       //%     Sys_Printf( ")\n" );
+               }
+
+               /* use the normal plain-jane shader */
+               else{
+                       ds->shaderNum = EmitShader( info->si->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
+               }
+       }
+
+       /* finish */
+       Sys_Printf( "done.\n" );
+
+       /* calc num stored */
+       numStored = numBSPLightBytes / 3;
+       efficiency = ( numStored <= 0 )
+                                ? 0
+                                : (float) numUsed / (float) numStored;
+
+       /* print stats */
+       Sys_Printf( "%9d luxels used\n", numUsed );
+       Sys_Printf( "%9d luxels stored (%3.2f percent efficiency)\n", numStored, efficiency * 100.0f );
+       Sys_Printf( "%9d solid surface lightmaps\n", numSolidLightmaps );
+       Sys_Printf( "%9d identical surface lightmaps, using %d luxels\n", numTwins, numTwinLuxels );
+       Sys_Printf( "%9d vertex forced surfaces\n", numSurfsVertexForced );
+       Sys_Printf( "%9d vertex approximated surfaces\n", numSurfsVertexApproximated );
+       Sys_Printf( "%9d BSP lightmaps\n", numBSPLightmaps );
+       Sys_Printf( "%9d total lightmaps\n", numOutLightmaps );
+       Sys_Printf( "%9d unique lightmap/shader combinations\n", numLightmapShaders );
+
+       /* write map shader file */
+       WriteMapShaderFile();
+}