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[ MAX_MAP_SHADERS ];
36 int allocated[ LIGHTMAP_WIDTH ];
39 int c_exactLightmap = 0;
40 int c_planarPatch = 0;
41 int c_nonplanarLightmap = 0;
44 void PrepareNewLightmap( void ) {
45 memset( allocated, 0, sizeof( allocated ) );
53 returns a texture number and the position inside it
56 qboolean AllocLMBlock( int w, int h, int *x, int *y ){
60 best = LIGHTMAP_HEIGHT;
62 for ( i = 0 ; i <= LIGHTMAP_WIDTH - w ; i++ ) {
65 for ( j = 0 ; j < w ; j++ ) {
66 if ( allocated[i + j] >= best ) {
69 if ( allocated[i + j] > best2 ) {
70 best2 = allocated[i + j];
73 if ( j == w ) { // this is a valid spot
79 if ( best + h > LIGHTMAP_HEIGHT ) {
83 for ( i = 0 ; i < w ; i++ ) {
84 allocated[*x + i] = best + h;
93 AllocateLightmapForPatch
96 //#define LIGHTMAP_PATCHSHIFT
98 void AllocateLightmapForPatch( mapDrawSurface_t *ds ){
104 mesh_t mesh, *subdividedMesh, *tempMesh, *newmesh;
105 int widthtable[LIGHTMAP_WIDTH], heighttable[LIGHTMAP_HEIGHT], ssize;
109 mesh.width = ds->patchWidth;
110 mesh.height = ds->patchHeight;
112 newmesh = SubdivideMesh( mesh, 8, 999 );
114 PutMeshOnCurve( *newmesh );
115 tempMesh = RemoveLinearMeshColumnsRows( newmesh );
118 /* get sample size */
119 ssize = ds->sampleSize;
122 #ifdef LIGHTMAP_PATCHSHIFT
123 subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH - 1, widthtable, heighttable );
125 subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH, widthtable, heighttable );
128 w = subdividedMesh->width;
129 h = subdividedMesh->height;
131 #ifdef LIGHTMAP_PATCHSHIFT
136 FreeMesh( subdividedMesh );
138 // allocate the lightmap
139 c_exactLightmap += w * h;
141 if ( !AllocLMBlock( w, h, &x, &y ) ) {
142 PrepareNewLightmap();
143 if ( !AllocLMBlock( w, h, &x, &y ) ) {
144 Error( "Entity %i, brush %i: Lightmap allocation failed",
145 ds->mapBrush->entitynum, ds->mapBrush->brushnum );
149 #ifdef LIGHTMAP_PATCHSHIFT
154 // set the lightmap texture coordinates in the drawVerts
155 ds->lightmapNum = numLightmaps - 1;
156 ds->lightmapWidth = w;
157 ds->lightmapHeight = h;
161 for ( i = 0 ; i < ds->patchWidth ; i++ ) {
162 for ( k = 0 ; k < w ; k++ ) {
163 if ( originalWidths[k] >= i ) {
171 for ( j = 0 ; j < ds->patchHeight ; j++ ) {
172 for ( k = 0 ; k < h ; k++ ) {
173 if ( originalHeights[k] >= j ) {
181 verts[i + j * ds->patchWidth].lightmap[0] = ( s + 0.5 ) / LIGHTMAP_WIDTH;
182 verts[i + j * ds->patchWidth].lightmap[1] = ( t + 0.5 ) / LIGHTMAP_HEIGHT;
190 AllocateLightmapForSurface
194 //#define LIGHTMAP_BLOCK 16
196 void AllocateLightmapForSurface( mapDrawSurface_t *ds ){
197 vec3_t mins, maxs, size, exactSize, delta;
212 if ( ds->type == SURF_META && ds->planar == qfalse ) {
213 Sys_Printf( "NPMS: %3d vertexes, %s\n", ds->numVerts, ds->shaderInfo->shader );
215 else if ( ds->type == SURF_META && ds->planar == qtrue ) {
216 Sys_Printf( "PMS: %3d vertexes, %s\n", ds->numVerts, ds->shaderInfo->shader );
220 /* ydnar: handle planar patches */
221 if ( noPatchFix == qtrue || ( ds->type == SURF_PATCH && ds->planeNum < 0 ) ) {
222 AllocateLightmapForPatch( ds );
226 /* get sample size */
227 ssize = ds->sampleSize;
229 /* bound the surface */
230 ClearBounds( mins, maxs );
232 for ( i = 0 ; i < ds->numVerts ; i++ )
233 AddPointToBounds( verts[i].xyz, mins, maxs );
235 /* round to the lightmap resolution */
236 for ( i = 0; i < 3; i++ )
238 exactSize[i] = maxs[i] - mins[i];
239 mins[i] = ssize * floor( mins[i] / ssize );
240 maxs[i] = ssize * ceil( maxs[i] / ssize );
241 size[i] = ( maxs[i] - mins[i] ) / ssize + 1;
244 /* ydnar: lightmap projection axis is already stored */
245 memset( vecs, 0, sizeof( vecs ) );
247 /* classify the plane (x y or z major) (ydnar: biased to z axis projection) */
248 if ( ds->lightmapAxis[ 2 ] >= ds->lightmapAxis[ 0 ] && ds->lightmapAxis[ 2 ] >= ds->lightmapAxis[ 1 ] ) {
252 vecs[ 0 ][ 0 ] = 1.0 / ssize;
253 vecs[ 1 ][ 1 ] = 1.0 / ssize;
255 else if ( ds->lightmapAxis[ 0 ] >= ds->lightmapAxis[ 1 ] && ds->lightmapAxis[ 0 ] >= ds->lightmapAxis[ 2 ] ) {
259 vecs[ 0 ][ 1 ] = 1.0 / ssize;
260 vecs[ 1 ][ 2 ] = 1.0 / ssize;
267 vecs[ 0 ][ 0 ] = 1.0 / ssize;
268 vecs[ 1 ][ 2 ] = 1.0 / ssize;
271 /* odd check, given projection is now precalculated */
272 if ( ds->lightmapAxis[ axis ] == 0 ) {
273 Error( "Chose a 0 valued axis" );
276 /* clamp to lightmap texture resolution */
277 if ( w > LIGHTMAP_WIDTH ) {
278 VectorScale( vecs[0], (float) LIGHTMAP_WIDTH / w, vecs[0] );
281 if ( h > LIGHTMAP_HEIGHT ) {
282 VectorScale( vecs[1], (float) LIGHTMAP_HEIGHT / h, vecs[1] );
288 if ( ds->planar == qfalse ) {
289 c_nonplanarLightmap += w * h;
291 c_exactLightmap += w * h;
294 if ( !AllocLMBlock( w, h, &x, &y ) ) {
295 PrepareNewLightmap();
296 if ( !AllocLMBlock( w, h, &x, &y ) ) {
297 Error( "Entity %i, brush %i: Lightmap allocation failed",
298 ds->mapBrush->entitynum, ds->mapBrush->brushnum );
302 /* set the lightmap texture coordinates in the drawVerts */
303 ds->lightmapNum = numLightmaps - 1;
304 ds->lightmapWidth = w;
305 ds->lightmapHeight = h;
308 for ( i = 0 ; i < ds->numVerts ; i++ )
310 VectorSubtract( verts[i].xyz, mins, delta );
311 s = DotProduct( delta, vecs[0] ) + x + 0.5;
312 t = DotProduct( delta, vecs[1] ) + y + 0.5;
313 verts[i].lightmap[0] = s / LIGHTMAP_WIDTH;
314 verts[i].lightmap[1] = t / LIGHTMAP_HEIGHT;
317 /* calculate the world coordinates of the lightmap samples */
319 /* construct a plane from the first vert and clear bounding box */
321 /* project mins onto plane to get origin */
322 VectorCopy( ds->lightmapVecs[ 2 ], plane );
323 plane[ 3 ] = DotProduct( ds->verts[ 0 ].xyz, plane );
324 d = DotProduct( mins, plane ) - plane[ 3 ];
327 //% d = DotProduct( mins, plane->normal ) - plane->dist;
328 //% d /= plane->normal[ axis ];
329 VectorCopy( mins, origin );
332 /* project stepped lightmap blocks and subtract to get planevecs */
333 for ( i = 0; i < 2; i++ )
338 len = VectorNormalize( vecs[i], normalized );
339 VectorScale( normalized, ( 1.0 / len ), vecs[i] );
340 d = DotProduct( vecs[i], plane );
342 //%d = DotProduct( vecs[i], plane->normal );
343 //%d /= plane->normal[ axis ];
347 /* store lightmap origin and vectors (fixme: make this work right) */
348 VectorCopy( origin, ds->lightmapOrigin );
349 //% VectorCopy( plane->normal, ds->lightmapVecs[ 2 ] );
351 /* ydnar: lightmap vectors 0 and 1 are used for lod bounds, so don't overwrite */
352 if ( ds->type == SURF_PATCH ) {
356 /* store lightmap vectors */
357 VectorCopy( vecs[ 0 ], ds->lightmapVecs[ 0 ] );
358 VectorCopy( vecs[ 1 ], ds->lightmapVecs[ 1 ] );
360 /* ydnar: print some stats */
361 //Sys_FPrintf( SYS_VRB, "Lightmap block %3d (%3d, %3d) (%3d x %3d) emitted\n", (numLightmaps - 1), x, y, w, h );
370 void AllocateLightmaps( entity_t *e ){
372 mapDrawSurface_t *ds;
377 Sys_FPrintf( SYS_VRB,"--- AllocateLightmaps ---\n" );
380 /* sort all surfaces by shader so common shaders will usually be in the same lightmap */
381 /* ydnar: this is done in two passes, because of an odd bug with lightmapped terrain */
383 for ( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ )
385 /* get surface and early out if possible */
386 ds = &mapDrawSurfs[ i ];
388 if ( si->surfaceFlags & SURF_VERTEXLIT ) {
391 if ( ds->numVerts <= 0 ) {
395 /* ydnar: handle brush faces and patches first */
396 if ( ds->type != SURF_FACE && ds->type != SURF_PATCH ) {
400 /* ydnar: this is unecessary because it should already be set */
401 //% VectorCopy( ds->plane.normal, ds->lightmapVecs[ 2 ] );
403 /* search for this shader */
404 for ( j = 0 ; j < numSortShaders; j++ )
406 if ( ds->shaderInfo == surfsOnShader[ j ]->shaderInfo ) {
407 ds->nextOnShader = surfsOnShader[ j ];
408 surfsOnShader[ j ] = ds;
414 if ( j == numSortShaders ) {
415 if ( numSortShaders >= MAX_MAP_SHADERS ) {
416 Error( "MAX_MAP_SHADERS" );
418 surfsOnShader[ j ] = ds;
419 ds->nextOnShader = NULL;
424 /* second pass, to allocate lightmapped terrain last */
425 for ( i = e->firstDrawSurf; i < numMapDrawSurfs; i++ )
427 /* get surface and early out if possible */
428 ds = &mapDrawSurfs[ i ];
430 if ( si->surfaceFlags & SURF_VERTEXLIT ) {
433 if ( ds->numVerts <= 0 ) {
437 /* ydnar: this only handles metasurfaces and terrain */
438 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 ) {
447 /* search for this shader */
448 for ( j = 0; j < numSortShaders; j++ )
450 if ( ds->shaderInfo == surfsOnShader[ j ]->shaderInfo ) {
451 ds->nextOnShader = surfsOnShader[ j ];
452 surfsOnShader[ j ] = ds;
458 if ( j == numSortShaders ) {
459 if ( numSortShaders >= MAX_MAP_SHADERS ) {
460 Error( "MAX_MAP_SHADERS" );
462 surfsOnShader[ j ] = ds;
463 ds->nextOnShader = NULL;
468 /* tot up shader count */
469 Sys_FPrintf( SYS_VRB, "%9d unique shaders\n", numSortShaders );
471 /* for each shader, allocate lightmaps for each surface */
472 for ( i = 0; i < numSortShaders; i++ )
474 si = surfsOnShader[ i ]->shaderInfo;
475 for ( ds = surfsOnShader[ i ]; ds; ds = ds->nextOnShader )
477 /* ydnar: promoting pointlight above nolightmap */
478 if ( si->surfaceFlags & SURF_POINTLIGHT ) {
479 ds->lightmapNum = -3;
481 else if ( si->surfaceFlags & SURF_NOLIGHTMAP ) {
482 ds->lightmapNum = -1;
485 AllocateLightmapForSurface( ds );
490 /* emit some statistics */
491 Sys_FPrintf( SYS_VRB, "%9d exact lightmap texels\n", c_exactLightmap );
492 Sys_FPrintf( SYS_VRB, "%9d block lightmap texels\n", numLightmaps * LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT );
493 Sys_FPrintf( SYS_VRB, "%9d non-planar or terrain lightmap texels\n", c_nonplanarLightmap );
494 Sys_FPrintf( SYS_VRB, "%9d planar patch lightmaps\n", c_planarPatch );
495 Sys_FPrintf( SYS_VRB, "%9d lightmap textures, size: %d Kbytes\n", numLightmaps, ( numLightmaps * LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 3 ) / 1024 );