]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - tools/quake3/q3map2/lightmaps.c
set eol-style
[xonotic/netradiant.git] / tools / quake3 / q3map2 / lightmaps.c
index c79dfb4038d5a08aba26e8921e6a06c22a6a8491..62977ddfab7b6e65d08a0f4d21dca141d7fa770c 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
-#include "qbsp.h"\r
-\r
-\r
-/*\r
-\r
-  Lightmap allocation has to be done after all flood filling and\r
-  visible surface determination.\r
-\r
-*/\r
-\r
-int                                    numSortShaders;\r
-mapDrawSurface_t       *surfsOnShader[ MAX_MAP_SHADERS ];\r
-\r
-\r
-int            allocated[ LIGHTMAP_WIDTH ];\r
-\r
-int            numLightmaps = 1;\r
-int            c_exactLightmap = 0;\r
-int            c_planarPatch = 0;\r
-int            c_nonplanarLightmap = 0;\r
-\r
-\r
-void PrepareNewLightmap( void ) {\r
-       memset( allocated, 0, sizeof( allocated ) );\r
-       numLightmaps++;\r
-}\r
-\r
-/*\r
-===============\r
-AllocLMBlock\r
-\r
-returns a texture number and the position inside it\r
-===============\r
-*/\r
-qboolean AllocLMBlock (int w, int h, int *x, int *y)\r
-{\r
-       int             i, j;\r
-       int             best, best2;\r
-\r
-       best = LIGHTMAP_HEIGHT;\r
-\r
-       for ( i=0 ; i <= LIGHTMAP_WIDTH-w ; i++ ) {\r
-               best2 = 0;\r
-\r
-               for (j=0 ; j<w ; j++) {\r
-                       if (allocated[i+j] >= best) {\r
-                               break;\r
-                       }\r
-                       if (allocated[i+j] > best2) {\r
-                               best2 = allocated[i+j];\r
-                       }\r
-               }\r
-               if (j == w)     {       // this is a valid spot\r
-                       *x = i;\r
-                       *y = best = best2;\r
-               }\r
-       }\r
-\r
-       if (best + h > LIGHTMAP_HEIGHT) {\r
-               return qfalse;\r
-       }\r
-\r
-       for (i=0 ; i<w ; i++) {\r
-               allocated[*x + i] = best + h;\r
-       }\r
-\r
-       return qtrue;\r
-}\r
-\r
-\r
-/*\r
-===================\r
-AllocateLightmapForPatch\r
-===================\r
-*/\r
-//#define LIGHTMAP_PATCHSHIFT\r
-\r
-void AllocateLightmapForPatch( mapDrawSurface_t *ds )\r
-{\r
-       int                     i, j, k;\r
-       drawVert_t      *verts;\r
-       int                     w, h;\r
-       int                     x, y;\r
-       float           s, t;\r
-       mesh_t          mesh, *subdividedMesh, *tempMesh, *newmesh;\r
-       int                     widthtable[LIGHTMAP_WIDTH], heighttable[LIGHTMAP_HEIGHT], ssize;\r
-\r
-       verts = ds->verts;\r
-\r
-       mesh.width = ds->patchWidth;\r
-       mesh.height = ds->patchHeight;\r
-       mesh.verts = verts;\r
-       newmesh = SubdivideMesh( mesh, 8, 999 );\r
-\r
-       PutMeshOnCurve( *newmesh );\r
-       tempMesh = RemoveLinearMeshColumnsRows( newmesh );\r
-       FreeMesh(newmesh);\r
-       \r
-       /* get sample size */\r
-       ssize = ds->sampleSize;\r
-       \r
-       \r
-#ifdef LIGHTMAP_PATCHSHIFT\r
-       subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH-1, widthtable, heighttable );\r
-#else\r
-       subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH, widthtable, heighttable );\r
-#endif\r
-\r
-       w = subdividedMesh->width;\r
-       h = subdividedMesh->height;\r
-\r
-#ifdef LIGHTMAP_PATCHSHIFT\r
-       w++;\r
-       h++;\r
-#endif\r
-\r
-       FreeMesh(subdividedMesh);\r
-\r
-       // allocate the lightmap\r
-       c_exactLightmap += w * h;\r
-\r
-       if ( !AllocLMBlock( w, h, &x, &y ) ) {\r
-               PrepareNewLightmap();\r
-               if ( !AllocLMBlock( w, h, &x, &y ) )\r
-               {\r
-                       Error("Entity %i, brush %i: Lightmap allocation failed", \r
-                               ds->mapBrush->entitynum, ds->mapBrush->brushnum );\r
-               }\r
-       }\r
-\r
-#ifdef LIGHTMAP_PATCHSHIFT\r
-       w--;\r
-       h--;\r
-#endif\r
-\r
-       // set the lightmap texture coordinates in the drawVerts\r
-       ds->lightmapNum = numLightmaps - 1;\r
-       ds->lightmapWidth = w;\r
-       ds->lightmapHeight = h;\r
-       ds->lightmapX = x;\r
-       ds->lightmapY = y;\r
-\r
-       for ( i = 0 ; i < ds->patchWidth ; i++ ) {\r
-               for ( k = 0 ; k < w ; k++ ) {\r
-                       if ( originalWidths[k] >= i ) {\r
-                               break;\r
-                       }\r
-               }\r
-               if (k >= w)\r
-                       k = w-1;\r
-               s = x + k;\r
-               for ( j = 0 ; j < ds->patchHeight ; j++ ) {\r
-                       for ( k = 0 ; k < h ; k++ ) {\r
-                               if ( originalHeights[k] >= j ) {\r
-                                       break;\r
-                               }\r
-                       }\r
-                       if (k >= h)\r
-                               k = h-1;\r
-                       t = y + k;\r
-                       verts[i + j * ds->patchWidth].lightmap[0] = ( s + 0.5 ) / LIGHTMAP_WIDTH;\r
-                       verts[i + j * ds->patchWidth].lightmap[1] = ( t + 0.5 ) / LIGHTMAP_HEIGHT;\r
-               }\r
-       }\r
-}\r
-\r
-\r
-/*\r
-===================\r
-AllocateLightmapForSurface\r
-===================\r
-*/\r
-\r
-//#define      LIGHTMAP_BLOCK  16\r
-\r
-void AllocateLightmapForSurface( mapDrawSurface_t *ds )\r
-{\r
-       vec3_t          mins, maxs, size, exactSize, delta;\r
-       int                     i;\r
-       drawVert_t      *verts;\r
-       int                     w, h;\r
-       int                     x, y, ssize;\r
-       int                     axis;\r
-       vec3_t          vecs[ 2 ];\r
-       float           s, t;\r
-       vec3_t          origin;\r
-       vec4_t          plane;\r
-       float           d;\r
-       \r
-       \r
-       /* debug code */\r
-       #if 0\r
-               if( ds->type == SURF_META && ds->planar == qfalse )\r
-                       Sys_Printf( "NPMS: %3d vertexes, %s\n", ds->numVerts, ds->shaderInfo->shader );\r
-               else if( ds->type == SURF_META && ds->planar == qtrue )\r
-                       Sys_Printf( "PMS:  %3d vertexes, %s\n", ds->numVerts, ds->shaderInfo->shader );\r
-       #endif\r
-       \r
-       /* ydnar: handle planar patches */\r
-       if( noPatchFix == qtrue || (ds->type == SURF_PATCH && ds->planeNum < 0) )\r
-       {\r
-               AllocateLightmapForPatch( ds );\r
-               return;\r
-       }\r
-       \r
-       /* get sample size */\r
-       ssize = ds->sampleSize;\r
-       \r
-       /* bound the surface */\r
-       ClearBounds( mins, maxs );\r
-       verts = ds->verts;\r
-       for ( i = 0 ; i < ds->numVerts ; i++ )\r
-               AddPointToBounds( verts[i].xyz, mins, maxs );\r
-       \r
-       /* round to the lightmap resolution */\r
-       for( i = 0; i < 3; i++ )\r
-       {\r
-               exactSize[i] = maxs[i] - mins[i];\r
-               mins[i] = ssize * floor( mins[i] / ssize );\r
-               maxs[i] = ssize * ceil( maxs[i] / ssize );\r
-               size[i] = (maxs[i] - mins[i]) / ssize + 1;\r
-       }\r
-       \r
-       /* ydnar: lightmap projection axis is already stored */\r
-       memset( vecs, 0, sizeof( vecs ) );\r
-       \r
-       /* classify the plane (x y or z major) (ydnar: biased to z axis projection) */\r
-       if( ds->lightmapAxis[ 2 ] >= ds->lightmapAxis[ 0 ] && ds->lightmapAxis[ 2 ] >= ds->lightmapAxis[ 1 ] )\r
-       {\r
-               w = size[ 0 ];\r
-               h = size[ 1 ];\r
-               axis = 2;\r
-               vecs[ 0 ][ 0 ] = 1.0 / ssize;\r
-               vecs[ 1 ][ 1 ] = 1.0 / ssize;\r
-       }\r
-       else if( ds->lightmapAxis[ 0 ] >= ds->lightmapAxis[ 1 ] && ds->lightmapAxis[ 0 ] >= ds->lightmapAxis[ 2 ] )\r
-       {\r
-               w = size[ 1 ];\r
-               h = size[ 2 ];\r
-               axis = 0;\r
-               vecs[ 0 ][ 1 ] = 1.0 / ssize;\r
-               vecs[ 1 ][ 2 ] = 1.0 / ssize;\r
-       }\r
-       else\r
-       {\r
-               w = size[ 0 ];\r
-               h = size[ 2 ];\r
-               axis = 1;\r
-               vecs[ 0 ][ 0 ] = 1.0 / ssize;\r
-               vecs[ 1 ][ 2 ] = 1.0 / ssize;\r
-       }\r
-       \r
-       /* odd check, given projection is now precalculated */\r
-       if( ds->lightmapAxis[ axis ] == 0 )\r
-               Error( "Chose a 0 valued axis" );\r
-       \r
-       /* clamp to lightmap texture resolution */\r
-       if( w > LIGHTMAP_WIDTH )\r
-       {\r
-               VectorScale ( vecs[0], (float) LIGHTMAP_WIDTH / w, vecs[0] );\r
-               w = LIGHTMAP_WIDTH;\r
-       }\r
-       if( h > LIGHTMAP_HEIGHT )\r
-       {\r
-               VectorScale ( vecs[1], (float) LIGHTMAP_HEIGHT / h, vecs[1] );\r
-               h = LIGHTMAP_HEIGHT;\r
-       }\r
-       \r
-       \r
-       /* ydnar */\r
-       if( ds->planar == qfalse )\r
-               c_nonplanarLightmap += w * h;\r
-       c_exactLightmap += w * h;\r
-       \r
-       \r
-       if( !AllocLMBlock( w, h, &x, &y ) )\r
-       {\r
-               PrepareNewLightmap();\r
-               if ( !AllocLMBlock( w, h, &x, &y ) )\r
-               {\r
-                       Error( "Entity %i, brush %i: Lightmap allocation failed", \r
-                               ds->mapBrush->entitynum, ds->mapBrush->brushnum );\r
-               }\r
-       }\r
-\r
-       /* set the lightmap texture coordinates in the drawVerts */\r
-       ds->lightmapNum = numLightmaps - 1;\r
-       ds->lightmapWidth = w;\r
-       ds->lightmapHeight = h;\r
-       ds->lightmapX = x;\r
-       ds->lightmapY = y;\r
-       for ( i = 0 ; i < ds->numVerts ; i++ )\r
-       {\r
-               VectorSubtract( verts[i].xyz, mins, delta );\r
-               s = DotProduct( delta, vecs[0] ) + x + 0.5;\r
-               t = DotProduct( delta, vecs[1] ) + y + 0.5;\r
-               verts[i].lightmap[0] = s / LIGHTMAP_WIDTH;\r
-               verts[i].lightmap[1] = t / LIGHTMAP_HEIGHT;\r
-       }\r
-\r
-       /* calculate the world coordinates of the lightmap samples */\r
-       \r
-       /* construct a plane from the first vert and clear bounding box */\r
-       \r
-       /* project mins onto plane to get origin */\r
-       VectorCopy( ds->lightmapVecs[ 2 ], plane );\r
-       plane[ 3 ] = DotProduct( ds->verts[ 0 ].xyz, plane );\r
-       d = DotProduct( mins, plane ) - plane[ 3 ];\r
-       d /= plane[ axis ];\r
-       \r
-       //% d = DotProduct( mins, plane->normal ) - plane->dist;\r
-       //% d /= plane->normal[ axis ];\r
-       VectorCopy( mins, origin );\r
-       origin[ axis ] -= d;\r
-\r
-       /* project stepped lightmap blocks and subtract to get planevecs */\r
-       for( i = 0; i < 2; i++ )\r
-       {\r
-               vec3_t  normalized;\r
-               float   len;\r
-\r
-               len = VectorNormalize( vecs[i], normalized );\r
-               VectorScale( normalized, (1.0/len), vecs[i] );\r
-               d = DotProduct( vecs[i], plane );\r
-               d /= plane[ axis ];\r
-               //%d = DotProduct( vecs[i], plane->normal );\r
-               //%d /= plane->normal[ axis ];\r
-               vecs[i][axis] -= d;\r
-       }\r
-       \r
-       /* store lightmap origin and vectors (fixme: make this work right) */\r
-       VectorCopy( origin, ds->lightmapOrigin );\r
-       //% VectorCopy( plane->normal, ds->lightmapVecs[ 2 ] );\r
-       \r
-       /* ydnar: lightmap vectors 0 and 1 are used for lod bounds, so don't overwrite */\r
-       if( ds->type == SURF_PATCH )\r
-               c_planarPatch++;\r
-       \r
-       /* store lightmap vectors */\r
-       VectorCopy( vecs[ 0 ], ds->lightmapVecs[ 0 ] );\r
-       VectorCopy( vecs[ 1 ], ds->lightmapVecs[ 1 ] );\r
-       \r
-       /* ydnar: print some stats */\r
-       //Sys_FPrintf( SYS_VRB, "Lightmap block %3d (%3d, %3d) (%3d x %3d) emitted\n", (numLightmaps - 1), x, y, w, h );\r
-}\r
-\r
-\r
-/*\r
-===================\r
-AllocateLightmaps\r
-===================\r
-*/\r
-void AllocateLightmaps( entity_t *e )\r
-{\r
-       int                                     i, j;\r
-       mapDrawSurface_t        *ds;\r
-       shaderInfo_t            *si;\r
-       \r
-       \r
-       /* note it */\r
-       Sys_FPrintf( SYS_VRB,"--- AllocateLightmaps ---\n" );\r
-       \r
-       \r
-       /* sort all surfaces by shader so common shaders will usually be in the same lightmap */\r
-       /* ydnar: this is done in two passes, because of an odd bug with lightmapped terrain */\r
-       numSortShaders = 0;\r
-       for( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ )\r
-       {\r
-               /* get surface and early out if possible */\r
-               ds = &mapDrawSurfs[ i ];\r
-               si = ds->shaderInfo;\r
-               if( si->surfaceFlags & SURF_VERTEXLIT )\r
-                       continue;\r
-               if( ds->numVerts <= 0 )\r
-                       continue;\r
-               \r
-               /* ydnar: handle brush faces and patches first */\r
-               if( ds->type != SURF_FACE && ds->type != SURF_PATCH )\r
-                       continue;\r
-               \r
-               /* ydnar: this is unecessary because it should already be set */\r
-               //% VectorCopy( ds->plane.normal, ds->lightmapVecs[ 2 ] );\r
-\r
-               /* search for this shader */\r
-               for( j = 0 ; j < numSortShaders; j++ )\r
-               {\r
-                       if( ds->shaderInfo == surfsOnShader[ j ]->shaderInfo )\r
-                       {\r
-                               ds->nextOnShader = surfsOnShader[ j ];\r
-                               surfsOnShader[ j ] = ds;\r
-                               break;\r
-                       }\r
-               } \r
-               \r
-               /* new shader */\r
-               if( j == numSortShaders )\r
-               {\r
-                       if( numSortShaders >= MAX_MAP_SHADERS )\r
-                               Error( "MAX_MAP_SHADERS" );\r
-                       surfsOnShader[ j ] = ds;\r
-                       ds->nextOnShader = NULL;\r
-                       numSortShaders++;\r
-               }\r
-       }\r
-       \r
-       /* second pass, to allocate lightmapped terrain last */\r
-       for( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ )\r
-       {\r
-               /* get surface and early out if possible */\r
-               ds = &mapDrawSurfs[ i ];\r
-               si = ds->shaderInfo;\r
-               if( si->surfaceFlags & SURF_VERTEXLIT )\r
-                       continue;\r
-               if( ds->numVerts <= 0 )\r
-                       continue;\r
-               \r
-               /* ydnar: this only handles metasurfaces and terrain */\r
-               if( ds->type != SURF_TERRAIN && ds->type != SURF_META )\r
-                       continue;\r
-               \r
-               /* ydnar: a lightmap projection should be pre-stored for anything but excessively curved patches */\r
-               if( VectorLength( ds->lightmapAxis ) <= 0 )\r
-                       continue;\r
-               \r
-               /* search for this shader */\r
-               for( j = 0; j < numSortShaders; j++ )\r
-               {\r
-                       if( ds->shaderInfo == surfsOnShader[ j ]->shaderInfo )\r
-                       {\r
-                               ds->nextOnShader = surfsOnShader[ j ];\r
-                               surfsOnShader[ j ] = ds;\r
-                               break;\r
-                       }\r
-               }\r
-               \r
-               /* new shader */\r
-               if( j == numSortShaders )\r
-               {\r
-                       if( numSortShaders >= MAX_MAP_SHADERS )\r
-                               Error( "MAX_MAP_SHADERS" );\r
-                       surfsOnShader[ j ] = ds;\r
-                       ds->nextOnShader = NULL;\r
-                       numSortShaders++;\r
-               }\r
-       }\r
-       \r
-       /* tot up shader count */\r
-       Sys_FPrintf( SYS_VRB, "%9d unique shaders\n", numSortShaders );\r
-       \r
-       /* for each shader, allocate lightmaps for each surface */\r
-       for( i = 0; i < numSortShaders; i++ )\r
-       {\r
-               si = surfsOnShader[ i ]->shaderInfo;\r
-               for( ds = surfsOnShader[ i ]; ds; ds = ds->nextOnShader )\r
-               {\r
-                       /* ydnar: promoting pointlight above nolightmap */\r
-                       if( si->surfaceFlags & SURF_POINTLIGHT )\r
-                               ds->lightmapNum = -3;\r
-                       else if( si->surfaceFlags & SURF_NOLIGHTMAP )\r
-                               ds->lightmapNum = -1;\r
-                       else\r
-                               AllocateLightmapForSurface( ds );\r
-               }\r
-       }\r
-       \r
-       /* emit some statistics */\r
-       Sys_FPrintf( SYS_VRB, "%9d exact lightmap texels\n", c_exactLightmap );\r
-       Sys_FPrintf( SYS_VRB, "%9d block lightmap texels\n", numLightmaps * LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT );\r
-       Sys_FPrintf( SYS_VRB, "%9d non-planar or terrain lightmap texels\n", c_nonplanarLightmap );\r
-       Sys_FPrintf( SYS_VRB, "%9d planar patch lightmaps\n", c_planarPatch );\r
-       Sys_FPrintf( SYS_VRB, "%9d lightmap textures, size: %d Kbytes\n", numLightmaps, (numLightmaps * LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 3) / 1024 );\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
+*/
+
+#include "qbsp.h"
+
+
+/*
+
+  Lightmap allocation has to be done after all flood filling and
+  visible surface determination.
+
+*/
+
+int                                    numSortShaders;
+mapDrawSurface_t       *surfsOnShader[ MAX_MAP_SHADERS ];
+
+
+int            allocated[ LIGHTMAP_WIDTH ];
+
+int            numLightmaps = 1;
+int            c_exactLightmap = 0;
+int            c_planarPatch = 0;
+int            c_nonplanarLightmap = 0;
+
+
+void PrepareNewLightmap( void ) {
+       memset( allocated, 0, sizeof( allocated ) );
+       numLightmaps++;
+}
+
+/*
+===============
+AllocLMBlock
+
+returns a texture number and the position inside it
+===============
+*/
+qboolean AllocLMBlock (int w, int h, int *x, int *y)
+{
+       int             i, j;
+       int             best, best2;
+
+       best = LIGHTMAP_HEIGHT;
+
+       for ( i=0 ; i <= LIGHTMAP_WIDTH-w ; i++ ) {
+               best2 = 0;
+
+               for (j=0 ; j<w ; j++) {
+                       if (allocated[i+j] >= best) {
+                               break;
+                       }
+                       if (allocated[i+j] > best2) {
+                               best2 = allocated[i+j];
+                       }
+               }
+               if (j == w)     {       // this is a valid spot
+                       *x = i;
+                       *y = best = best2;
+               }
+       }
+
+       if (best + h > LIGHTMAP_HEIGHT) {
+               return qfalse;
+       }
+
+       for (i=0 ; i<w ; i++) {
+               allocated[*x + i] = best + h;
+       }
+
+       return qtrue;
+}
+
+
+/*
+===================
+AllocateLightmapForPatch
+===================
+*/
+//#define LIGHTMAP_PATCHSHIFT
+
+void AllocateLightmapForPatch( mapDrawSurface_t *ds )
+{
+       int                     i, j, k;
+       drawVert_t      *verts;
+       int                     w, h;
+       int                     x, y;
+       float           s, t;
+       mesh_t          mesh, *subdividedMesh, *tempMesh, *newmesh;
+       int                     widthtable[LIGHTMAP_WIDTH], heighttable[LIGHTMAP_HEIGHT], ssize;
+
+       verts = ds->verts;
+
+       mesh.width = ds->patchWidth;
+       mesh.height = ds->patchHeight;
+       mesh.verts = verts;
+       newmesh = SubdivideMesh( mesh, 8, 999 );
+
+       PutMeshOnCurve( *newmesh );
+       tempMesh = RemoveLinearMeshColumnsRows( newmesh );
+       FreeMesh(newmesh);
+       
+       /* get sample size */
+       ssize = ds->sampleSize;
+       
+       
+#ifdef LIGHTMAP_PATCHSHIFT
+       subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH-1, widthtable, heighttable );
+#else
+       subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH, widthtable, heighttable );
+#endif
+
+       w = subdividedMesh->width;
+       h = subdividedMesh->height;
+
+#ifdef LIGHTMAP_PATCHSHIFT
+       w++;
+       h++;
+#endif
+
+       FreeMesh(subdividedMesh);
+
+       // allocate the lightmap
+       c_exactLightmap += w * h;
+
+       if ( !AllocLMBlock( w, h, &x, &y ) ) {
+               PrepareNewLightmap();
+               if ( !AllocLMBlock( w, h, &x, &y ) )
+               {
+                       Error("Entity %i, brush %i: Lightmap allocation failed", 
+                               ds->mapBrush->entitynum, ds->mapBrush->brushnum );
+               }
+       }
+
+#ifdef LIGHTMAP_PATCHSHIFT
+       w--;
+       h--;
+#endif
+
+       // set the lightmap texture coordinates in the drawVerts
+       ds->lightmapNum = numLightmaps - 1;
+       ds->lightmapWidth = w;
+       ds->lightmapHeight = h;
+       ds->lightmapX = x;
+       ds->lightmapY = y;
+
+       for ( i = 0 ; i < ds->patchWidth ; i++ ) {
+               for ( k = 0 ; k < w ; k++ ) {
+                       if ( originalWidths[k] >= i ) {
+                               break;
+                       }
+               }
+               if (k >= w)
+                       k = w-1;
+               s = x + k;
+               for ( j = 0 ; j < ds->patchHeight ; j++ ) {
+                       for ( k = 0 ; k < h ; k++ ) {
+                               if ( originalHeights[k] >= j ) {
+                                       break;
+                               }
+                       }
+                       if (k >= h)
+                               k = h-1;
+                       t = y + k;
+                       verts[i + j * ds->patchWidth].lightmap[0] = ( s + 0.5 ) / LIGHTMAP_WIDTH;
+                       verts[i + j * ds->patchWidth].lightmap[1] = ( t + 0.5 ) / LIGHTMAP_HEIGHT;
+               }
+       }
+}
+
+
+/*
+===================
+AllocateLightmapForSurface
+===================
+*/
+
+//#define      LIGHTMAP_BLOCK  16
+
+void AllocateLightmapForSurface( mapDrawSurface_t *ds )
+{
+       vec3_t          mins, maxs, size, exactSize, delta;
+       int                     i;
+       drawVert_t      *verts;
+       int                     w, h;
+       int                     x, y, ssize;
+       int                     axis;
+       vec3_t          vecs[ 2 ];
+       float           s, t;
+       vec3_t          origin;
+       vec4_t          plane;
+       float           d;
+       
+       
+       /* debug code */
+       #if 0
+               if( ds->type == SURF_META && ds->planar == qfalse )
+                       Sys_Printf( "NPMS: %3d vertexes, %s\n", ds->numVerts, ds->shaderInfo->shader );
+               else if( ds->type == SURF_META && ds->planar == qtrue )
+                       Sys_Printf( "PMS:  %3d vertexes, %s\n", ds->numVerts, ds->shaderInfo->shader );
+       #endif
+       
+       /* ydnar: handle planar patches */
+       if( noPatchFix == qtrue || (ds->type == SURF_PATCH && ds->planeNum < 0) )
+       {
+               AllocateLightmapForPatch( ds );
+               return;
+       }
+       
+       /* get sample size */
+       ssize = ds->sampleSize;
+       
+       /* bound the surface */
+       ClearBounds( mins, maxs );
+       verts = ds->verts;
+       for ( i = 0 ; i < ds->numVerts ; i++ )
+               AddPointToBounds( verts[i].xyz, mins, maxs );
+       
+       /* round to the lightmap resolution */
+       for( i = 0; i < 3; i++ )
+       {
+               exactSize[i] = maxs[i] - mins[i];
+               mins[i] = ssize * floor( mins[i] / ssize );
+               maxs[i] = ssize * ceil( maxs[i] / ssize );
+               size[i] = (maxs[i] - mins[i]) / ssize + 1;
+       }
+       
+       /* ydnar: lightmap projection axis is already stored */
+       memset( vecs, 0, sizeof( vecs ) );
+       
+       /* classify the plane (x y or z major) (ydnar: biased to z axis projection) */
+       if( ds->lightmapAxis[ 2 ] >= ds->lightmapAxis[ 0 ] && ds->lightmapAxis[ 2 ] >= ds->lightmapAxis[ 1 ] )
+       {
+               w = size[ 0 ];
+               h = size[ 1 ];
+               axis = 2;
+               vecs[ 0 ][ 0 ] = 1.0 / ssize;
+               vecs[ 1 ][ 1 ] = 1.0 / ssize;
+       }
+       else if( ds->lightmapAxis[ 0 ] >= ds->lightmapAxis[ 1 ] && ds->lightmapAxis[ 0 ] >= ds->lightmapAxis[ 2 ] )
+       {
+               w = size[ 1 ];
+               h = size[ 2 ];
+               axis = 0;
+               vecs[ 0 ][ 1 ] = 1.0 / ssize;
+               vecs[ 1 ][ 2 ] = 1.0 / ssize;
+       }
+       else
+       {
+               w = size[ 0 ];
+               h = size[ 2 ];
+               axis = 1;
+               vecs[ 0 ][ 0 ] = 1.0 / ssize;
+               vecs[ 1 ][ 2 ] = 1.0 / ssize;
+       }
+       
+       /* odd check, given projection is now precalculated */
+       if( ds->lightmapAxis[ axis ] == 0 )
+               Error( "Chose a 0 valued axis" );
+       
+       /* clamp to lightmap texture resolution */
+       if( w > LIGHTMAP_WIDTH )
+       {
+               VectorScale ( vecs[0], (float) LIGHTMAP_WIDTH / w, vecs[0] );
+               w = LIGHTMAP_WIDTH;
+       }
+       if( h > LIGHTMAP_HEIGHT )
+       {
+               VectorScale ( vecs[1], (float) LIGHTMAP_HEIGHT / h, vecs[1] );
+               h = LIGHTMAP_HEIGHT;
+       }
+       
+       
+       /* ydnar */
+       if( ds->planar == qfalse )
+               c_nonplanarLightmap += w * h;
+       c_exactLightmap += w * h;
+       
+       
+       if( !AllocLMBlock( w, h, &x, &y ) )
+       {
+               PrepareNewLightmap();
+               if ( !AllocLMBlock( w, h, &x, &y ) )
+               {
+                       Error( "Entity %i, brush %i: Lightmap allocation failed", 
+                               ds->mapBrush->entitynum, ds->mapBrush->brushnum );
+               }
+       }
+
+       /* set the lightmap texture coordinates in the drawVerts */
+       ds->lightmapNum = numLightmaps - 1;
+       ds->lightmapWidth = w;
+       ds->lightmapHeight = h;
+       ds->lightmapX = x;
+       ds->lightmapY = y;
+       for ( i = 0 ; i < ds->numVerts ; i++ )
+       {
+               VectorSubtract( verts[i].xyz, mins, delta );
+               s = DotProduct( delta, vecs[0] ) + x + 0.5;
+               t = DotProduct( delta, vecs[1] ) + y + 0.5;
+               verts[i].lightmap[0] = s / LIGHTMAP_WIDTH;
+               verts[i].lightmap[1] = t / LIGHTMAP_HEIGHT;
+       }
+
+       /* calculate the world coordinates of the lightmap samples */
+       
+       /* construct a plane from the first vert and clear bounding box */
+       
+       /* project mins onto plane to get origin */
+       VectorCopy( ds->lightmapVecs[ 2 ], plane );
+       plane[ 3 ] = DotProduct( ds->verts[ 0 ].xyz, plane );
+       d = DotProduct( mins, plane ) - plane[ 3 ];
+       d /= plane[ axis ];
+       
+       //% d = DotProduct( mins, plane->normal ) - plane->dist;
+       //% d /= plane->normal[ axis ];
+       VectorCopy( mins, origin );
+       origin[ axis ] -= d;
+
+       /* project stepped lightmap blocks and subtract to get planevecs */
+       for( i = 0; i < 2; i++ )
+       {
+               vec3_t  normalized;
+               float   len;
+
+               len = VectorNormalize( vecs[i], normalized );
+               VectorScale( normalized, (1.0/len), vecs[i] );
+               d = DotProduct( vecs[i], plane );
+               d /= plane[ axis ];
+               //%d = DotProduct( vecs[i], plane->normal );
+               //%d /= plane->normal[ axis ];
+               vecs[i][axis] -= d;
+       }
+       
+       /* store lightmap origin and vectors (fixme: make this work right) */
+       VectorCopy( origin, ds->lightmapOrigin );
+       //% VectorCopy( plane->normal, ds->lightmapVecs[ 2 ] );
+       
+       /* ydnar: lightmap vectors 0 and 1 are used for lod bounds, so don't overwrite */
+       if( ds->type == SURF_PATCH )
+               c_planarPatch++;
+       
+       /* store lightmap vectors */
+       VectorCopy( vecs[ 0 ], ds->lightmapVecs[ 0 ] );
+       VectorCopy( vecs[ 1 ], ds->lightmapVecs[ 1 ] );
+       
+       /* ydnar: print some stats */
+       //Sys_FPrintf( SYS_VRB, "Lightmap block %3d (%3d, %3d) (%3d x %3d) emitted\n", (numLightmaps - 1), x, y, w, h );
+}
+
+
+/*
+===================
+AllocateLightmaps
+===================
+*/
+void AllocateLightmaps( entity_t *e )
+{
+       int                                     i, j;
+       mapDrawSurface_t        *ds;
+       shaderInfo_t            *si;
+       
+       
+       /* note it */
+       Sys_FPrintf( SYS_VRB,"--- AllocateLightmaps ---\n" );
+       
+       
+       /* sort all surfaces by shader so common shaders will usually be in the same lightmap */
+       /* ydnar: this is done in two passes, because of an odd bug with lightmapped terrain */
+       numSortShaders = 0;
+       for( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ )
+       {
+               /* get surface and early out if possible */
+               ds = &mapDrawSurfs[ i ];
+               si = ds->shaderInfo;
+               if( si->surfaceFlags & SURF_VERTEXLIT )
+                       continue;
+               if( ds->numVerts <= 0 )
+                       continue;
+               
+               /* ydnar: handle brush faces and patches first */
+               if( ds->type != SURF_FACE && ds->type != SURF_PATCH )
+                       continue;
+               
+               /* ydnar: this is unecessary because it should already be set */
+               //% VectorCopy( ds->plane.normal, ds->lightmapVecs[ 2 ] );
+
+               /* search for this shader */
+               for( j = 0 ; j < numSortShaders; j++ )
+               {
+                       if( ds->shaderInfo == surfsOnShader[ j ]->shaderInfo )
+                       {
+                               ds->nextOnShader = surfsOnShader[ j ];
+                               surfsOnShader[ j ] = ds;
+                               break;
+                       }
+               } 
+               
+               /* new shader */
+               if( j == numSortShaders )
+               {
+                       if( numSortShaders >= MAX_MAP_SHADERS )
+                               Error( "MAX_MAP_SHADERS" );
+                       surfsOnShader[ j ] = ds;
+                       ds->nextOnShader = NULL;
+                       numSortShaders++;
+               }
+       }
+       
+       /* second pass, to allocate lightmapped terrain last */
+       for( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ )
+       {
+               /* get surface and early out if possible */
+               ds = &mapDrawSurfs[ i ];
+               si = ds->shaderInfo;
+               if( si->surfaceFlags & SURF_VERTEXLIT )
+                       continue;
+               if( ds->numVerts <= 0 )
+                       continue;
+               
+               /* ydnar: this only handles metasurfaces and terrain */
+               if( ds->type != SURF_TERRAIN && ds->type != SURF_META )
+                       continue;
+               
+               /* ydnar: a lightmap projection should be pre-stored for anything but excessively curved patches */
+               if( VectorLength( ds->lightmapAxis ) <= 0 )
+                       continue;
+               
+               /* search for this shader */
+               for( j = 0; j < numSortShaders; j++ )
+               {
+                       if( ds->shaderInfo == surfsOnShader[ j ]->shaderInfo )
+                       {
+                               ds->nextOnShader = surfsOnShader[ j ];
+                               surfsOnShader[ j ] = ds;
+                               break;
+                       }
+               }
+               
+               /* new shader */
+               if( j == numSortShaders )
+               {
+                       if( numSortShaders >= MAX_MAP_SHADERS )
+                               Error( "MAX_MAP_SHADERS" );
+                       surfsOnShader[ j ] = ds;
+                       ds->nextOnShader = NULL;
+                       numSortShaders++;
+               }
+       }
+       
+       /* tot up shader count */
+       Sys_FPrintf( SYS_VRB, "%9d unique shaders\n", numSortShaders );
+       
+       /* for each shader, allocate lightmaps for each surface */
+       for( i = 0; i < numSortShaders; i++ )
+       {
+               si = surfsOnShader[ i ]->shaderInfo;
+               for( ds = surfsOnShader[ i ]; ds; ds = ds->nextOnShader )
+               {
+                       /* ydnar: promoting pointlight above nolightmap */
+                       if( si->surfaceFlags & SURF_POINTLIGHT )
+                               ds->lightmapNum = -3;
+                       else if( si->surfaceFlags & SURF_NOLIGHTMAP )
+                               ds->lightmapNum = -1;
+                       else
+                               AllocateLightmapForSurface( ds );
+               }
+       }
+       
+       /* emit some statistics */
+       Sys_FPrintf( SYS_VRB, "%9d exact lightmap texels\n", c_exactLightmap );
+       Sys_FPrintf( SYS_VRB, "%9d block lightmap texels\n", numLightmaps * LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT );
+       Sys_FPrintf( SYS_VRB, "%9d non-planar or terrain lightmap texels\n", c_nonplanarLightmap );
+       Sys_FPrintf( SYS_VRB, "%9d planar patch lightmaps\n", c_planarPatch );
+       Sys_FPrintf( SYS_VRB, "%9d lightmap textures, size: %d Kbytes\n", numLightmaps, (numLightmaps * LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 3) / 1024 );
+}
+
+
+