2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 Lightmap allocation has to be done after all flood filling and
28 visible surface determination.
33 mapDrawSurface_t **surfsOnShader;
34 int allocatedSurfsOnShader;
37 int allocated[ LIGHTMAP_WIDTH ];
40 int c_exactLightmap = 0;
41 int c_planarPatch = 0;
42 int c_nonplanarLightmap = 0;
45 void PrepareNewLightmap( void ) {
46 memset( allocated, 0, sizeof( allocated ) );
54 returns a texture number and the position inside it
57 qboolean AllocLMBlock (int w, int h, int *x, int *y)
62 best = LIGHTMAP_HEIGHT;
64 for ( i=0 ; i <= LIGHTMAP_WIDTH-w ; i++ ) {
67 for (j=0 ; j<w ; j++) {
68 if (allocated[i+j] >= best) {
71 if (allocated[i+j] > best2) {
72 best2 = allocated[i+j];
75 if (j == w) { // this is a valid spot
81 if (best + h > LIGHTMAP_HEIGHT) {
85 for (i=0 ; i<w ; i++) {
86 allocated[*x + i] = best + h;
95 AllocateLightmapForPatch
98 //#define LIGHTMAP_PATCHSHIFT
100 void AllocateLightmapForPatch( mapDrawSurface_t *ds )
107 mesh_t mesh, *subdividedMesh, *tempMesh, *newmesh;
108 int widthtable[LIGHTMAP_WIDTH], heighttable[LIGHTMAP_HEIGHT], ssize;
112 mesh.width = ds->patchWidth;
113 mesh.height = ds->patchHeight;
115 newmesh = SubdivideMesh( mesh, 8, 999 );
117 PutMeshOnCurve( *newmesh );
118 tempMesh = RemoveLinearMeshColumnsRows( newmesh );
121 /* get sample size */
122 ssize = ds->sampleSize;
125 #ifdef LIGHTMAP_PATCHSHIFT
126 subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH-1, widthtable, heighttable );
128 subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH, widthtable, heighttable );
131 w = subdividedMesh->width;
132 h = subdividedMesh->height;
134 #ifdef LIGHTMAP_PATCHSHIFT
139 FreeMesh(subdividedMesh);
141 // allocate the lightmap
142 c_exactLightmap += w * h;
144 if ( !AllocLMBlock( w, h, &x, &y ) ) {
145 PrepareNewLightmap();
146 if ( !AllocLMBlock( w, h, &x, &y ) )
148 Error("Entity %i, brush %i: Lightmap allocation failed",
149 ds->mapBrush->entitynum, ds->mapBrush->brushnum );
153 #ifdef LIGHTMAP_PATCHSHIFT
158 // set the lightmap texture coordinates in the drawVerts
159 ds->lightmapNum = numLightmaps - 1;
160 ds->lightmapWidth = w;
161 ds->lightmapHeight = h;
165 for ( i = 0 ; i < ds->patchWidth ; i++ ) {
166 for ( k = 0 ; k < w ; k++ ) {
167 if ( originalWidths[k] >= i ) {
174 for ( j = 0 ; j < ds->patchHeight ; j++ ) {
175 for ( k = 0 ; k < h ; k++ ) {
176 if ( originalHeights[k] >= j ) {
183 verts[i + j * ds->patchWidth].lightmap[0] = ( s + 0.5 ) / LIGHTMAP_WIDTH;
184 verts[i + j * ds->patchWidth].lightmap[1] = ( t + 0.5 ) / LIGHTMAP_HEIGHT;
192 AllocateLightmapForSurface
196 //#define LIGHTMAP_BLOCK 16
198 void AllocateLightmapForSurface( mapDrawSurface_t *ds )
200 vec3_t mins, maxs, size, exactSize, delta;
215 if( ds->type == SURF_META && ds->planar == qfalse )
216 Sys_Printf( "NPMS: %3d vertexes, %s\n", ds->numVerts, ds->shaderInfo->shader );
217 else if( ds->type == SURF_META && ds->planar == qtrue )
218 Sys_Printf( "PMS: %3d vertexes, %s\n", ds->numVerts, ds->shaderInfo->shader );
221 /* ydnar: handle planar patches */
222 if( noPatchFix == qtrue || (ds->type == SURF_PATCH && ds->planeNum < 0) )
224 AllocateLightmapForPatch( ds );
228 /* get sample size */
229 ssize = ds->sampleSize;
231 /* bound the surface */
232 ClearBounds( mins, maxs );
234 for ( i = 0 ; i < ds->numVerts ; i++ )
235 AddPointToBounds( verts[i].xyz, mins, maxs );
237 /* round to the lightmap resolution */
238 for( i = 0; i < 3; i++ )
240 exactSize[i] = maxs[i] - mins[i];
241 mins[i] = ssize * floor( mins[i] / ssize );
242 maxs[i] = ssize * ceil( maxs[i] / ssize );
243 size[i] = (maxs[i] - mins[i]) / ssize + 1;
246 /* ydnar: lightmap projection axis is already stored */
247 memset( vecs, 0, sizeof( vecs ) );
249 /* classify the plane (x y or z major) (ydnar: biased to z axis projection) */
250 if( ds->lightmapAxis[ 2 ] >= ds->lightmapAxis[ 0 ] && ds->lightmapAxis[ 2 ] >= ds->lightmapAxis[ 1 ] )
255 vecs[ 0 ][ 0 ] = 1.0 / ssize;
256 vecs[ 1 ][ 1 ] = 1.0 / ssize;
258 else if( ds->lightmapAxis[ 0 ] >= ds->lightmapAxis[ 1 ] && ds->lightmapAxis[ 0 ] >= ds->lightmapAxis[ 2 ] )
263 vecs[ 0 ][ 1 ] = 1.0 / ssize;
264 vecs[ 1 ][ 2 ] = 1.0 / ssize;
271 vecs[ 0 ][ 0 ] = 1.0 / ssize;
272 vecs[ 1 ][ 2 ] = 1.0 / ssize;
275 /* odd check, given projection is now precalculated */
276 if( ds->lightmapAxis[ axis ] == 0 )
277 Error( "Chose a 0 valued axis" );
279 /* clamp to lightmap texture resolution */
280 if( w > LIGHTMAP_WIDTH )
282 VectorScale ( vecs[0], (float) LIGHTMAP_WIDTH / w, vecs[0] );
285 if( h > LIGHTMAP_HEIGHT )
287 VectorScale ( vecs[1], (float) LIGHTMAP_HEIGHT / h, vecs[1] );
293 if( ds->planar == qfalse )
294 c_nonplanarLightmap += w * h;
295 c_exactLightmap += w * h;
298 if( !AllocLMBlock( w, h, &x, &y ) )
300 PrepareNewLightmap();
301 if ( !AllocLMBlock( w, h, &x, &y ) )
303 Error( "Entity %i, brush %i: Lightmap allocation failed",
304 ds->mapBrush->entitynum, ds->mapBrush->brushnum );
308 /* set the lightmap texture coordinates in the drawVerts */
309 ds->lightmapNum = numLightmaps - 1;
310 ds->lightmapWidth = w;
311 ds->lightmapHeight = h;
314 for ( i = 0 ; i < ds->numVerts ; i++ )
316 VectorSubtract( verts[i].xyz, mins, delta );
317 s = DotProduct( delta, vecs[0] ) + x + 0.5;
318 t = DotProduct( delta, vecs[1] ) + y + 0.5;
319 verts[i].lightmap[0] = s / LIGHTMAP_WIDTH;
320 verts[i].lightmap[1] = t / LIGHTMAP_HEIGHT;
323 /* calculate the world coordinates of the lightmap samples */
325 /* construct a plane from the first vert and clear bounding box */
327 /* project mins onto plane to get origin */
328 VectorCopy( ds->lightmapVecs[ 2 ], plane );
329 plane[ 3 ] = DotProduct( ds->verts[ 0 ].xyz, plane );
330 d = DotProduct( mins, plane ) - plane[ 3 ];
333 //% d = DotProduct( mins, plane->normal ) - plane->dist;
334 //% d /= plane->normal[ axis ];
335 VectorCopy( mins, origin );
338 /* project stepped lightmap blocks and subtract to get planevecs */
339 for( i = 0; i < 2; i++ )
344 len = VectorNormalize( vecs[i], normalized );
345 VectorScale( normalized, (1.0/len), vecs[i] );
346 d = DotProduct( vecs[i], plane );
348 //%d = DotProduct( vecs[i], plane->normal );
349 //%d /= plane->normal[ axis ];
353 /* store lightmap origin and vectors (fixme: make this work right) */
354 VectorCopy( origin, ds->lightmapOrigin );
355 //% VectorCopy( plane->normal, ds->lightmapVecs[ 2 ] );
357 /* ydnar: lightmap vectors 0 and 1 are used for lod bounds, so don't overwrite */
358 if( ds->type == SURF_PATCH )
361 /* store lightmap vectors */
362 VectorCopy( vecs[ 0 ], ds->lightmapVecs[ 0 ] );
363 VectorCopy( vecs[ 1 ], ds->lightmapVecs[ 1 ] );
365 /* ydnar: print some stats */
366 //Sys_FPrintf( SYS_VRB, "Lightmap block %3d (%3d, %3d) (%3d x %3d) emitted\n", (numLightmaps - 1), x, y, w, h );
375 void AllocateLightmaps( entity_t *e )
378 mapDrawSurface_t *ds;
383 Sys_FPrintf( SYS_VRB,"--- AllocateLightmaps ---\n" );
386 /* sort all surfaces by shader so common shaders will usually be in the same lightmap */
387 /* ydnar: this is done in two passes, because of an odd bug with lightmapped terrain */
389 for( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ )
391 /* get surface and early out if possible */
392 ds = &mapDrawSurfs[ i ];
394 if( si->surfaceFlags & SURF_VERTEXLIT )
396 if( ds->numVerts <= 0 )
399 /* ydnar: handle brush faces and patches first */
400 if( ds->type != SURF_FACE && ds->type != SURF_PATCH )
403 /* ydnar: this is unecessary because it should already be set */
404 //% VectorCopy( ds->plane.normal, ds->lightmapVecs[ 2 ] );
406 /* search for this shader */
407 for( j = 0 ; j < numSortShaders; j++ )
409 if( ds->shaderInfo == surfsOnShader[ j ]->shaderInfo )
411 ds->nextOnShader = surfsOnShader[ j ];
412 surfsOnShader[ j ] = ds;
418 if( j == numSortShaders )
420 EXPAND_BY_REALLOC(surfsOnShader, numSortShaders, allocatedSurfsOnShader, 1024);
421 surfsOnShader[ j ] = ds;
422 ds->nextOnShader = NULL;
427 /* second pass, to allocate lightmapped terrain last */
428 for( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ )
430 /* get surface and early out if possible */
431 ds = &mapDrawSurfs[ i ];
433 if( si->surfaceFlags & SURF_VERTEXLIT )
435 if( ds->numVerts <= 0 )
438 /* ydnar: this only handles metasurfaces and terrain */
439 if( ds->type != SURF_TERRAIN && ds->type != SURF_META )
442 /* ydnar: a lightmap projection should be pre-stored for anything but excessively curved patches */
443 if( VectorLength( ds->lightmapAxis ) <= 0 )
446 /* search for this shader */
447 for( j = 0; j < numSortShaders; j++ )
449 if( ds->shaderInfo == surfsOnShader[ j ]->shaderInfo )
451 ds->nextOnShader = surfsOnShader[ j ];
452 surfsOnShader[ j ] = ds;
458 if( j == numSortShaders )
460 EXPAND_BY_REALLOC(surfsOnShader, numSortShaders, allocatedSurfsOnShader, 1024);
461 surfsOnShader[ j ] = ds;
462 ds->nextOnShader = NULL;
467 /* tot up shader count */
468 Sys_FPrintf( SYS_VRB, "%9d unique shaders\n", numSortShaders );
470 /* for each shader, allocate lightmaps for each surface */
471 for( i = 0; i < numSortShaders; i++ )
473 si = surfsOnShader[ i ]->shaderInfo;
474 for( ds = surfsOnShader[ i ]; ds; ds = ds->nextOnShader )
476 /* ydnar: promoting pointlight above nolightmap */
477 if( si->surfaceFlags & SURF_POINTLIGHT )
478 ds->lightmapNum = -3;
479 else if( si->surfaceFlags & SURF_NOLIGHTMAP )
480 ds->lightmapNum = -1;
482 AllocateLightmapForSurface( ds );
486 /* emit some statistics */
487 Sys_FPrintf( SYS_VRB, "%9d exact lightmap texels\n", c_exactLightmap );
488 Sys_FPrintf( SYS_VRB, "%9d block lightmap texels\n", numLightmaps * LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT );
489 Sys_FPrintf( SYS_VRB, "%9d non-planar or terrain lightmap texels\n", c_nonplanarLightmap );
490 Sys_FPrintf( SYS_VRB, "%9d planar patch lightmaps\n", c_planarPatch );
491 Sys_FPrintf( SYS_VRB, "%9d lightmap textures, size: %d Kbytes\n", numLightmaps, (numLightmaps * LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 3) / 1024 );