]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - tools/quake3/q3map2/lightmaps_ydnar.c
eol style
[xonotic/netradiant.git] / tools / quake3 / q3map2 / lightmaps_ydnar.c
index 22b6e376073eb150b045fda3d9b7a42465c2af66..df1693513fbbca684d09183f4e89bb28da2b6c7a 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 += (LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 3) )
+       {
+               /* write a tga image out */
+               sprintf( filename, "%s/lightmap_%04d.tga", dirname, i );
+               Sys_Printf( "Writing %s\n", filename );
+               WriteTGA24( filename, lightmap, LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT, 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 += (LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 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, &pixels, &width, &height );
+               free( buffer );
+               
+               /* sanity check it */
+               if( pixels == NULL )
+               {
+                       Sys_Printf( "WARNING: Unable to load image %s\n", filename );
+                       continue;
+               }
+               if( width != LIGHTMAP_WIDTH || height != LIGHTMAP_HEIGHT )
+                       Sys_Printf( "WARNING: Image %s is not the right size (%d, %d) != (%d, %d)\n",
+                               filename, width, height, LIGHTMAP_WIDTH, LIGHTMAP_HEIGHT );
+               
+               /* copy the pixels */
+               in = pixels;
+               for( y = 1; y <= LIGHTMAP_HEIGHT; y++ )
+               {
+                       out = lightmap + ((LIGHTMAP_HEIGHT - y) * LIGHTMAP_WIDTH * 3);
+                       for( x = 0; x < LIGHTMAP_WIDTH; 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[ *((int*) a) ].si;
+       bsi = surfaceInfos[ *((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 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, *info2;
+       int                                     num2, n, i, axisNum;
+       float                           s, t, d, len, sampleSize;
+       vec3_t                          mins, maxs, origin, faxis, size, exactSize, 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->lmGamma != lm->gamma ||
+                       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++ )
+       {
+               exactSize[ i ] = lm->maxs[ i ] - lm->mins[ 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 )
+               {
+                       i = -1;
+                       sampleSize += 1.0f;
+               }
+       }
+       
+       /* 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 ];
+               info2 = &surfaceInfos[ 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 ];
+       info2 = &surfaceInfos[ 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[ *((int*) a) ];
+       bInfo = &surfaceInfos[ *((int*) b) ];
+       
+       /* model first */
+       if( aInfo->model < bInfo->model )
+               return 1;
+       else if( aInfo->model > bInfo->model )
+               return -1;
+       
+       /* then lightmap status */
+       if( aInfo->hasLightmap < bInfo->hasLightmap )
+               return 1;
+       else if( aInfo->hasLightmap > bInfo->hasLightmap )
+               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, *ds2;
+       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->model = model;
+                       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;
+               lm->sampleSize = info->sampleSize;
+               lm->actualSampleSize = info->sampleSize;
+               lm->entityNum = info->entityNum;
+               lm->recvShadows = info->recvShadows;
+               lm->gamma = info->si->lmGamma;
+               lm->filterRadius = info->si->lmFilterRadius;
+               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 ];
+                               ds2 = &bspDrawSurfaces[ num2 ];
+                               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, *luxels[ MAX_STITCH_LUXELS ];
+       
+       
+       /* 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 );
+                                                       luxels[ numLuxels++ ] = luxel2;
+                                                       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 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;
+       
+       /* compare */
+       if( a->w != b->w || a->h != b->h ||
+               a->customWidth != b->customWidth || a->customHeight != b->customHeight ||
+               a->gamma != b->gamma ||
+               a->bspLuxels[ aNum ] == NULL || b->bspLuxels[ bNum ] == NULL )
+               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 void MergeBSPLuxels( rawLightmap_t *a, int aNum, rawLightmap_t *b, int bNum )
+{
+       rawLightmap_t   *lm;
+       int                             x, y;
+       float                   luxel[ 3 ], *aLuxel, *bLuxel;
+       
+       
+       /* compare */
+       if( a->w != b->w || a->h != b->h ||
+               a->customWidth != b->customWidth || a->customHeight != b->customHeight ||
+               a->gamma != b->gamma ||
+               a->bspLuxels[ aNum ] == NULL || b->bspLuxels[ bNum ] == NULL )
+               return;
+       
+       /* 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 );
+                       }
+               }
+       }
+}
+
+
+
+/*
+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 ];
+               
+               /* bail if lightmap doesn't match up */
+               if( info->lm != lm )
+                       continue;
+               
+               /* assume reduced initially */
+               info->approximated = qtrue;
+               
+               /* 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) )
+               {
+                       numSurfsVertexForced++;
+                       continue;
+               }
+               
+               /* handle the triangles */
+               switch( ds->surfaceType )
+               {
+                       case MST_PLANAR:
+                               /* get verts */
+                               verts = yDrawVerts + ds->firstVert;
+                               
+                               /* map the triangles */
+                               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 */
+                               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;
+       
+       /* 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 == LIGHTMAP_WIDTH && lm->customHeight == LIGHTMAP_HEIGHT) || 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
+*/
+
+static void FindOutLightmaps( rawLightmap_t *lm )
+{
+       int                                     i, j, lightmapNum, xMax, yMax, x, y, sx, sy, ox, oy, offset, temp;
+       outLightmap_t           *olm;
+       surfaceInfo_t           *info;
+       float                           *luxel, *deluxel;
+       vec3_t                          color, direction;
+       byte                            *pixel;
+       qboolean                        ok;
+       
+       
+       /* 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 */
+                       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;
+                               
+                               /* set maxs */
+                               xMax = (olm->customWidth - lm->w) + 1;
+                               yMax = (olm->customHeight - lm->h) + 1;
+                               
+                               /* walk the origin around the lightmap */
+                               for( y = 0; y < yMax; y++ )
+                               {
+                                       for( x = 0; x < xMax; x++ )
+                                       {
+                                               /* 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 two new output lightmaps */
+                       numOutLightmaps += 2;
+                       olm = safe_malloc( numOutLightmaps * sizeof( outLightmap_t ) );
+                       if( outLightmaps != NULL && numOutLightmaps > 2 )
+                       {
+                               memcpy( olm, outLightmaps, (numOutLightmaps - 2) * sizeof( outLightmap_t ) );
+                               free( outLightmaps );
+                       }
+                       outLightmaps = olm;
+                       
+                       /* initialize both out lightmaps */
+                       SetupOutLightmap( lm, &outLightmaps[ numOutLightmaps - 2 ] );
+                       SetupOutLightmap( lm, &outLightmaps[ numOutLightmaps - 1 ] );
+                       
+                       /* set out lightmap */
+                       i = numOutLightmaps - 2;
+                       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 )
+                       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++;
+                       }
+               }
+               
+               /* mark the bits used */
+               for( y = 0; y < lm->h; y++ )
+               {
+                       for( x = 0; x < lm->w; x++ )
+                       {
+                               /* get luxel */
+                               luxel = BSP_LUXEL( lightmapNum, x, y );
+                               deluxel = BSP_DELUXEL( x, y );
+                               if( luxel[ 0 ] < 0.0f )
+                                       continue;
+                               
+                               /* set minimum light */
+                               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->gamma );
+                               
+                               /* store direction */
+                               if( deluxemap )
+                               {
+                                       /* normalize average light direction */
+                                       if( VectorNormalize( deluxel, direction ) )
+                                       {
+                                               /* encode [-1,1] in [0,255] */
+                                               pixel = olm->bspDirBytes + (((oy * olm->customWidth) + ox) * 3);
+                                               for( i = 0; i < 3; i++ )
+                                               {
+                                                       temp = (direction[ i ] + 1.0f) * 127.5f;
+                                                       if( temp < 0 )
+                                                               pixel[ i ] = 0;
+                                                       else if( temp > 255 )
+                                                               pixel[ i ] = 255;
+                                                       else
+                                                               pixel[ i ] = temp;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+
+
+/*
+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[ *((int*) a) ];
+       blm = &rawLightmaps[ *((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;
+}
+
+
+
+/*
+StoreSurfaceLightmaps()
+stores the surface lightmaps into the bsp as byte rgb triplets
+*/
+
+void StoreSurfaceLightmaps( void )
+{
+       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;
+       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 ];
+       char                            *rgbGenValues[ 256 ];
+       char                            *alphaGenValues[ 256 ];
+       
+       
+       /* note it */
+       Sys_Printf( "--- StoreSurfaceLightmaps ---\n");
+       
+       /* setup */
+       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_FPrintf( SYS_VRB, "Subsampling..." );
+       
+       /* walk the list of raw lightmaps */
+       numUsed = 0;
+       numTwins = 0;
+       numTwinLuxels = 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;
+                                       }
+                               }
+                       }
+                       
+                       /* clean up and store into bsp luxels */
+                       lm->used = 0;
+                       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 );
+                               }
+                       }
+                       
+                       /* 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 );
+                                       }
+                               }
+                       }
+               }
+       }
+       
+       /* -----------------------------------------------------------------
+          collapse non-unique lightmaps
+          ----------------------------------------------------------------- */
+       
+       if( noCollapse == qfalse && deluxemap == qfalse )
+       {
+               /* note it */
+               Sys_FPrintf( SYS_VRB, "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 */
+                                                       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_FPrintf( SYS_VRB, "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_FPrintf( SYS_VRB, "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 );
+       }
+       
+       /* 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_FPrintf( SYS_VRB, "storing..." );
+       
+       /* count the bsp lightmaps and allocate space */
+       if( bspLightBytes != NULL )
+               free( bspLightBytes );
+       if( numBSPLightmaps == 0 || externalLightmaps )
+       {
+               numBSPLightBytes = 0;
+               bspLightBytes = NULL;
+       }
+       else
+       {
+               numBSPLightBytes = (numBSPLightmaps * LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 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 ];
+               
+               /* is this a valid bsp lightmap? */
+               if( olm->lightmapNum >= 0 && !externalLightmaps )
+               {
+                       /* copy lighting data */
+                       lb = bspLightBytes + (olm->lightmapNum * LIGHTMAP_HEIGHT * LIGHTMAP_WIDTH * 3);
+                       memcpy( lb, olm->bspLightBytes, LIGHTMAP_HEIGHT * LIGHTMAP_WIDTH * 3 );
+                       
+                       /* copy direction data */
+                       if( deluxemap )
+                       {
+                               lb = bspLightBytes + ((olm->lightmapNum + 1) * LIGHTMAP_HEIGHT * LIGHTMAP_WIDTH * 3);
+                               memcpy( lb, olm->bspDirBytes, LIGHTMAP_HEIGHT * LIGHTMAP_WIDTH * 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_FPrintf( SYS_VRB, "\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_FPrintf( SYS_VRB, "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 and store lighting values */
+                               dv = &bspDrawVerts[ ds->firstVert ];
+                               ydv = &yDrawVerts[ ds->firstVert ];
+                               for( j = 0; j < ds->numVerts; j++ )
+                               {
+                                       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 */
+                               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 ] = (char*) 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 ] = (char*) 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 != LIGHTMAP_WIDTH || olm->customHeight != LIGHTMAP_HEIGHT) )
+               {
+                       /* 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_FPrintf( SYS_VRB, "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 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();
+}
+
+
+
+