1 /* -------------------------------------------------------------------------------
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
6 This file is part of GtkRadiant.
8 GtkRadiant is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 GtkRadiant is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GtkRadiant; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 ----------------------------------------------------------------------------------
24 This code has been altered significantly from its original form, to support
25 several games based on the Quake III Arena engine, in the form of "Q3Map2."
27 ------------------------------------------------------------------------------- */
32 #define LIGHTMAPS_YDNAR_C
42 /* -------------------------------------------------------------------------------
44 this file contains code that doe lightmap allocation and projection that
45 runs in the -light phase.
47 this is handled here rather than in the bsp phase for a few reasons--
48 surfaces are no longer necessarily convex polygons, patches may or may not be
49 planar or have lightmaps projected directly onto control points.
51 also, this allows lightmaps to be calculated before being allocated and stored
52 in the bsp. lightmaps that have little high-frequency information are candidates
53 for having their resolutions scaled down.
55 ------------------------------------------------------------------------------- */
59 based on WriteTGA() from imagelib.c
62 void WriteTGA24( char *filename, byte *data, int width, int height, qboolean flip )
69 /* allocate a buffer and set it up */
70 buffer = safe_malloc( width * height * 3 + 18 );
71 memset( buffer, 0, 18 );
73 buffer[ 12 ] = width & 255;
74 buffer[ 13 ] = width >> 8;
75 buffer[ 14 ] = height & 255;
76 buffer[ 15 ] = height >> 8;
80 c = (width * height * 3) + 18;
81 for( i = 18; i < c; i += 3 )
83 buffer[ i ] = data[ i - 18 + 2 ]; /* blue */
84 buffer[ i + 1 ] = data[ i - 18 + 1 ]; /* green */
85 buffer[ i + 2 ] = data[ i - 18 + 0 ]; /* red */
88 /* write it and free the buffer */
89 file = fopen( filename, "wb" );
91 Error( "Unable to open %s for writing", filename );
93 /* flip vertically? */
96 fwrite( buffer, 1, 18, file );
97 for( in = buffer + ((height - 1) * width * 3) + 18; in >= buffer; in -= (width * 3) )
98 fwrite( in, 1, (width * 3), file );
101 fwrite( buffer, 1, c, file );
112 exports the lightmaps as a list of numbered tga images
115 void ExportLightmaps( void )
118 char dirname[ 1024 ], filename[ 1024 ];
123 Sys_FPrintf( SYS_VRB, "--- ExportLightmaps ---\n");
125 /* do some path mangling */
126 strcpy( dirname, source );
127 StripExtension( dirname );
130 if( bspLightBytes == NULL )
132 Sys_Printf( "WARNING: No BSP lightmap data\n" );
136 /* make a directory for the lightmaps */
139 /* iterate through the lightmaps */
140 for( i = 0, lightmap = bspLightBytes; lightmap < (bspLightBytes + numBSPLightBytes); i++, lightmap += (game->lightmapSize * game->lightmapSize * 3) )
142 /* write a tga image out */
143 sprintf( filename, "%s/lightmap_%04d.tga", dirname, i );
144 Sys_Printf( "Writing %s\n", filename );
145 WriteTGA24( filename, lightmap, game->lightmapSize, game->lightmapSize, qfalse );
152 ExportLightmapsMain()
153 exports the lightmaps as a list of numbered tga images
156 int ExportLightmapsMain( int argc, char **argv )
161 Sys_Printf( "Usage: q3map -export [-v] <mapname>\n" );
165 /* do some path mangling */
166 strcpy( source, ExpandArg( argv[ argc - 1 ] ) );
167 StripExtension( source );
168 DefaultExtension( source, ".bsp" );
171 Sys_Printf( "Loading %s\n", source );
172 LoadBSPFile( source );
174 /* export the lightmaps */
177 /* return to sender */
184 ImportLightmapsMain()
185 imports the lightmaps from a list of numbered tga images
188 int ImportLightmapsMain( int argc, char **argv )
190 int i, x, y, len, width, height;
191 char dirname[ 1024 ], filename[ 1024 ];
192 byte *lightmap, *buffer, *pixels, *in, *out;
198 Sys_Printf( "Usage: q3map -import [-v] <mapname>\n" );
202 /* do some path mangling */
203 strcpy( source, ExpandArg( argv[ argc - 1 ] ) );
204 StripExtension( source );
205 DefaultExtension( source, ".bsp" );
208 Sys_Printf( "Loading %s\n", source );
209 LoadBSPFile( source );
212 Sys_FPrintf( SYS_VRB, "--- ImportLightmaps ---\n");
214 /* do some path mangling */
215 strcpy( dirname, source );
216 StripExtension( dirname );
219 if( bspLightBytes == NULL )
220 Error( "No lightmap data" );
222 /* make a directory for the lightmaps */
225 /* iterate through the lightmaps */
226 for( i = 0, lightmap = bspLightBytes; lightmap < (bspLightBytes + numBSPLightBytes); i++, lightmap += (game->lightmapSize * game->lightmapSize * 3) )
228 /* read a tga image */
229 sprintf( filename, "%s/lightmap_%04d.tga", dirname, i );
230 Sys_Printf( "Loading %s\n", filename );
232 len = vfsLoadFile( filename, (void*) &buffer, -1 );
235 Sys_Printf( "WARNING: Unable to load image %s\n", filename );
239 /* parse file into an image */
241 LoadTGABuffer( buffer, buffer + len, &pixels, &width, &height );
244 /* sanity check it */
247 Sys_Printf( "WARNING: Unable to load image %s\n", filename );
250 if( width != game->lightmapSize || height != game->lightmapSize )
251 Sys_Printf( "WARNING: Image %s is not the right size (%d, %d) != (%d, %d)\n",
252 filename, width, height, game->lightmapSize, game->lightmapSize );
254 /* copy the pixels */
256 for( y = 1; y <= game->lightmapSize; y++ )
258 out = lightmap + ((game->lightmapSize - y) * game->lightmapSize * 3);
259 for( x = 0; x < game->lightmapSize; x++, in += 4, out += 3 )
260 VectorCopy( in, out );
268 Sys_Printf( "writing %s\n", source );
269 WriteBSPFile( source );
271 /* return to sender */
277 /* -------------------------------------------------------------------------------
279 this section deals with projecting a lightmap onto a raw drawsurface
281 ------------------------------------------------------------------------------- */
284 CompareLightSurface()
285 compare function for qsort()
288 static int CompareLightSurface( const void *a, const void *b )
290 shaderInfo_t *asi, *bsi;
294 asi = surfaceInfos[ *((const int*) a) ].si;
295 bsi = surfaceInfos[ *((const int*) b) ].si;
303 /* compare shader names */
304 return strcmp( asi->shader, bsi->shader );
311 allocates a raw lightmap's necessary buffers
314 void FinishRawLightmap( rawLightmap_t *lm )
316 int i, j, c, size, *sc;
321 /* sort light surfaces by shader name */
322 qsort( &lightSurfaces[ lm->firstLightSurface ], lm->numLightSurfaces, sizeof( int ), CompareLightSurface );
325 lm->numLightClusters = 0;
326 for( i = 0; i < lm->numLightSurfaces; i++ )
328 /* get surface info */
329 info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + i ] ];
331 /* add surface clusters */
332 lm->numLightClusters += info->numSurfaceClusters;
335 /* allocate buffer for clusters and copy */
336 lm->lightClusters = safe_malloc( lm->numLightClusters * sizeof( *lm->lightClusters ) );
338 for( i = 0; i < lm->numLightSurfaces; i++ )
340 /* get surface info */
341 info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + i ] ];
343 /* add surface clusters */
344 for( j = 0; j < info->numSurfaceClusters; j++ )
345 lm->lightClusters[ c++ ] = surfaceClusters[ info->firstSurfaceCluster + j ];
349 lm->styles[ 0 ] = LS_NORMAL;
350 for( i = 1; i < MAX_LIGHTMAPS; i++ )
351 lm->styles[ i ] = LS_NONE;
353 /* set supersampling size */
354 lm->sw = lm->w * superSample;
355 lm->sh = lm->h * superSample;
357 /* add to super luxel count */
358 numRawSuperLuxels += (lm->sw * lm->sh);
360 /* manipulate origin/vecs for supersampling */
361 if( superSample > 1 && lm->vecs != NULL )
363 /* calc inverse supersample */
364 is = 1.0f / superSample;
366 /* scale the vectors and shift the origin */
368 /* new code that works for arbitrary supersampling values */
369 VectorMA( lm->origin, -0.5, lm->vecs[ 0 ], lm->origin );
370 VectorMA( lm->origin, -0.5, lm->vecs[ 1 ], lm->origin );
371 VectorScale( lm->vecs[ 0 ], is, lm->vecs[ 0 ] );
372 VectorScale( lm->vecs[ 1 ], is, lm->vecs[ 1 ] );
373 VectorMA( lm->origin, is, lm->vecs[ 0 ], lm->origin );
374 VectorMA( lm->origin, is, lm->vecs[ 1 ], lm->origin );
376 /* old code that only worked with a value of 2 */
377 VectorScale( lm->vecs[ 0 ], is, lm->vecs[ 0 ] );
378 VectorScale( lm->vecs[ 1 ], is, lm->vecs[ 1 ] );
379 VectorMA( lm->origin, -is, lm->vecs[ 0 ], lm->origin );
380 VectorMA( lm->origin, -is, lm->vecs[ 1 ], lm->origin );
384 /* allocate bsp lightmap storage */
385 size = lm->w * lm->h * BSP_LUXEL_SIZE * sizeof( float );
386 if( lm->bspLuxels[ 0 ] == NULL )
387 lm->bspLuxels[ 0 ] = safe_malloc( size );
388 memset( lm->bspLuxels[ 0 ], 0, size );
390 /* allocate radiosity lightmap storage */
393 size = lm->w * lm->h * RAD_LUXEL_SIZE * sizeof( float );
394 if( lm->radLuxels[ 0 ] == NULL )
395 lm->radLuxels[ 0 ] = safe_malloc( size );
396 memset( lm->radLuxels[ 0 ], 0, size );
399 /* allocate sampling lightmap storage */
400 size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
401 if( lm->superLuxels[ 0 ] == NULL )
402 lm->superLuxels[ 0 ] = safe_malloc( size );
403 memset( lm->superLuxels[ 0 ], 0, size );
405 /* allocate origin map storage */
406 size = lm->sw * lm->sh * SUPER_ORIGIN_SIZE * sizeof( float );
407 if( lm->superOrigins == NULL )
408 lm->superOrigins = safe_malloc( size );
409 memset( lm->superOrigins, 0, size );
411 /* allocate normal map storage */
412 size = lm->sw * lm->sh * SUPER_NORMAL_SIZE * sizeof( float );
413 if( lm->superNormals == NULL )
414 lm->superNormals = safe_malloc( size );
415 memset( lm->superNormals, 0, size );
417 /* allocate floodlight map storage */
418 size = lm->sw * lm->sh * SUPER_FLOODLIGHT_SIZE * sizeof( float );
419 if( lm->superFloodLight == NULL )
420 lm->superFloodLight = safe_malloc( size );
421 memset( lm->superFloodLight, 0, size );
423 /* allocate cluster map storage */
424 size = lm->sw * lm->sh * sizeof( int );
425 if( lm->superClusters == NULL )
426 lm->superClusters = safe_malloc( size );
427 size = lm->sw * lm->sh;
428 sc = lm->superClusters;
429 for( i = 0; i < size; i++ )
430 (*sc++) = CLUSTER_UNMAPPED;
432 /* deluxemap allocation */
435 /* allocate sampling deluxel storage */
436 size = lm->sw * lm->sh * SUPER_DELUXEL_SIZE * sizeof( float );
437 if( lm->superDeluxels == NULL )
438 lm->superDeluxels = safe_malloc( size );
439 memset( lm->superDeluxels, 0, size );
441 /* allocate bsp deluxel storage */
442 size = lm->w * lm->h * BSP_DELUXEL_SIZE * sizeof( float );
443 if( lm->bspDeluxels == NULL )
444 lm->bspDeluxels = safe_malloc( size );
445 memset( lm->bspDeluxels, 0, size );
449 numLuxels += (lm->sw * lm->sh);
455 AddPatchToRawLightmap()
456 projects a lightmap for a patch surface
457 since lightmap calculation for surfaces is now handled in a general way (light_ydnar.c),
458 it is no longer necessary for patch verts to fall exactly on a lightmap sample
459 based on AllocateLightmapForPatch()
462 qboolean AddPatchToRawLightmap( int num, rawLightmap_t *lm )
464 bspDrawSurface_t *ds;
467 bspDrawVert_t *verts, *a, *b;
469 mesh_t src, *subdivided, *mesh;
470 float sBasis, tBasis, s, t;
471 float length, widthTable[ MAX_EXPANDED_AXIS ], heightTable[ MAX_EXPANDED_AXIS ];
474 /* patches finish a raw lightmap */
475 lm->finished = qtrue;
477 /* get surface and info */
478 ds = &bspDrawSurfaces[ num ];
479 info = &surfaceInfos[ num ];
481 /* make a temporary mesh from the drawsurf */
482 src.width = ds->patchWidth;
483 src.height = ds->patchHeight;
484 src.verts = &yDrawVerts[ ds->firstVert ];
485 //% subdivided = SubdivideMesh( src, 8, 512 );
486 subdivided = SubdivideMesh2( src, info->patchIterations );
488 /* fit it to the curve and remove colinear verts on rows/columns */
489 PutMeshOnCurve( *subdivided );
490 mesh = RemoveLinearMeshColumnsRows( subdivided );
491 FreeMesh( subdivided );
493 /* find the longest distance on each row/column */
495 memset( widthTable, 0, sizeof( widthTable ) );
496 memset( heightTable, 0, sizeof( heightTable ) );
497 for( y = 0; y < mesh->height; y++ )
499 for( x = 0; x < mesh->width; x++ )
502 if( x + 1 < mesh->width )
504 a = &verts[ (y * mesh->width) + x ];
505 b = &verts[ (y * mesh->width) + x + 1 ];
506 VectorSubtract( a->xyz, b->xyz, delta );
507 length = VectorLength( delta );
508 if( length > widthTable[ x ] )
509 widthTable[ x ] = length;
513 if( y + 1 < mesh->height )
515 a = &verts[ (y * mesh->width) + x ];
516 b = &verts[ ((y + 1) * mesh->width) + x ];
517 VectorSubtract( a->xyz, b->xyz, delta );
518 length = VectorLength( delta );
519 if( length > heightTable[ y ] )
520 heightTable[ y ] = length;
525 /* determine lightmap width */
527 for( x = 0; x < (mesh->width - 1); x++ )
528 length += widthTable[ x ];
529 lm->w = ceil( length / lm->sampleSize ) + 1;
530 if( lm->w < ds->patchWidth )
531 lm->w = ds->patchWidth;
532 if( lm->w > lm->customWidth )
533 lm->w = lm->customWidth;
534 sBasis = (float) (lm->w - 1) / (float) (ds->patchWidth - 1);
536 /* determine lightmap height */
538 for( y = 0; y < (mesh->height - 1); y++ )
539 length += heightTable[ y ];
540 lm->h = ceil( length / lm->sampleSize ) + 1;
541 if( lm->h < ds->patchHeight )
542 lm->h = ds->patchHeight;
543 if( lm->h > lm->customHeight )
544 lm->h = lm->customHeight;
545 tBasis = (float) (lm->h - 1) / (float) (ds->patchHeight - 1);
547 /* free the temporary mesh */
550 /* set the lightmap texture coordinates in yDrawVerts */
551 lm->wrap[ 0 ] = qtrue;
552 lm->wrap[ 1 ] = qtrue;
553 verts = &yDrawVerts[ ds->firstVert ];
554 for( y = 0; y < ds->patchHeight; y++ )
556 t = (tBasis * y) + 0.5f;
557 for( x = 0; x < ds->patchWidth; x++ )
559 s = (sBasis * x) + 0.5f;
560 verts[ (y * ds->patchWidth) + x ].lightmap[ 0 ][ 0 ] = s * superSample;
561 verts[ (y * ds->patchWidth) + x ].lightmap[ 0 ][ 1 ] = t * superSample;
563 if( y == 0 && !VectorCompare( verts[ x ].xyz, verts[ ((ds->patchHeight - 1) * ds->patchWidth) + x ].xyz ) )
564 lm->wrap[ 1 ] = qfalse;
567 if( !VectorCompare( verts[ (y * ds->patchWidth) ].xyz, verts[ (y * ds->patchWidth) + (ds->patchWidth - 1) ].xyz ) )
568 lm->wrap[ 0 ] = qfalse;
572 //% Sys_Printf( "wrap S: %d wrap T: %d\n", lm->wrap[ 0 ], lm->wrap[ 1 ] );
573 //% if( lm->w > (ds->lightmapWidth & 0xFF) || lm->h > (ds->lightmapHeight & 0xFF) )
574 //% Sys_Printf( "Patch lightmap: (%3d %3d) > (%3d, %3d)\n", lm->w, lm->h, ds->lightmapWidth & 0xFF, ds->lightmapHeight & 0xFF );
575 //% ds->lightmapWidth = lm->w | (ds->lightmapWidth & 0xFFFF0000);
576 //% ds->lightmapHeight = lm->h | (ds->lightmapHeight & 0xFFFF0000);
579 numPatchesLightmapped++;
588 AddSurfaceToRawLightmap()
589 projects a lightmap for a surface
590 based on AllocateLightmapForSurface()
593 qboolean AddSurfaceToRawLightmap( int num, rawLightmap_t *lm )
595 bspDrawSurface_t *ds, *ds2;
597 int num2, n, i, axisNum;
598 float s, t, d, len, sampleSize;
599 vec3_t mins, maxs, origin, faxis, size, delta, normalized, vecs[ 2 ];
601 bspDrawVert_t *verts;
604 /* get surface and info */
605 ds = &bspDrawSurfaces[ num ];
606 info = &surfaceInfos[ num ];
608 /* add the surface to the raw lightmap */
609 lightSurfaces[ numLightSurfaces++ ] = num;
610 lm->numLightSurfaces++;
612 /* does this raw lightmap already have any surfaces? */
613 if( lm->numLightSurfaces > 1 )
615 /* surface and raw lightmap must have the same lightmap projection axis */
616 if( VectorCompare( info->axis, lm->axis ) == qfalse )
619 /* match identical attributes */
620 if( info->sampleSize != lm->sampleSize ||
621 info->entityNum != lm->entityNum ||
622 info->recvShadows != lm->recvShadows ||
623 info->si->lmCustomWidth != lm->customWidth ||
624 info->si->lmCustomHeight != lm->customHeight ||
625 info->si->lmBrightness != lm->brightness ||
626 info->si->lmFilterRadius != lm->filterRadius ||
627 info->si->splotchFix != lm->splotchFix )
630 /* surface bounds must intersect with raw lightmap bounds */
631 for( i = 0; i < 3; i++ )
633 if( info->mins[ i ] > lm->maxs[ i ] )
635 if( info->maxs[ i ] < lm->mins[ i ] )
639 /* plane check (fixme: allow merging of nonplanars) */
640 if( info->si->lmMergable == qfalse )
642 if( info->plane == NULL || lm->plane == NULL )
646 for( i = 0; i < 4; i++ )
647 if( fabs( info->plane[ i ] - lm->plane[ i ] ) > EQUAL_EPSILON )
651 /* debug code hacking */
652 //% if( lm->numLightSurfaces > 1 )
657 if( info->plane == NULL )
660 /* add surface to lightmap bounds */
661 AddPointToBounds( info->mins, lm->mins, lm->maxs );
662 AddPointToBounds( info->maxs, lm->mins, lm->maxs );
664 /* check to see if this is a non-planar patch */
665 if( ds->surfaceType == MST_PATCH &&
666 lm->axis[ 0 ] == 0.0f && lm->axis[ 1 ] == 0.0f && lm->axis[ 2 ] == 0.0f )
667 return AddPatchToRawLightmap( num, lm );
669 /* start with initially requested sample size */
670 sampleSize = lm->sampleSize;
672 /* round to the lightmap resolution */
673 for( i = 0; i < 3; i++ )
675 mins[ i ] = sampleSize * floor( lm->mins[ i ] / sampleSize );
676 maxs[ i ] = sampleSize * ceil( lm->maxs[ i ] / sampleSize );
677 size[ i ] = (maxs[ i ] - mins[ i ]) / sampleSize + 1.0f;
679 /* hack (god this sucks) */
680 if( size[ i ] > lm->customWidth || size[ i ] > lm->customHeight || (lmLimitSize && size[i] > lmLimitSize))
687 if(sampleSize != lm->sampleSize && lmLimitSize == 0)
689 Sys_FPrintf(SYS_VRB,"WARNING: surface at (%6.0f %6.0f %6.0f) (%6.0f %6.0f %6.0f) too large for desired samplesize/lightmapsize/lightmapscale combination, increased samplesize from %d to %d\n",
700 /* set actual sample size */
701 lm->actualSampleSize = sampleSize;
703 /* fixme: copy rounded mins/maxes to lightmap record? */
704 if( lm->plane == NULL )
706 VectorCopy( mins, lm->mins );
707 VectorCopy( maxs, lm->maxs );
708 VectorCopy( mins, origin );
711 /* set lightmap origin */
712 VectorCopy( lm->mins, origin );
714 /* make absolute axis */
715 faxis[ 0 ] = fabs( lm->axis[ 0 ] );
716 faxis[ 1 ] = fabs( lm->axis[ 1 ] );
717 faxis[ 2 ] = fabs( lm->axis[ 2 ] );
719 /* clear out lightmap vectors */
720 memset( vecs, 0, sizeof( vecs ) );
722 /* classify the plane (x y or z major) (ydnar: biased to z axis projection) */
723 if( faxis[ 2 ] >= faxis[ 0 ] && faxis[ 2 ] >= faxis[ 1 ] )
728 vecs[ 0 ][ 0 ] = 1.0f / sampleSize;
729 vecs[ 1 ][ 1 ] = 1.0f / sampleSize;
731 else if( faxis[ 0 ] >= faxis[ 1 ] && faxis[ 0 ] >= faxis[ 2 ] )
736 vecs[ 0 ][ 1 ] = 1.0f / sampleSize;
737 vecs[ 1 ][ 2 ] = 1.0f / sampleSize;
744 vecs[ 0 ][ 0 ] = 1.0f / sampleSize;
745 vecs[ 1 ][ 2 ] = 1.0f / sampleSize;
748 /* check for bogus axis */
749 if( faxis[ axisNum ] == 0.0f )
751 Sys_Printf( "WARNING: ProjectSurfaceLightmap: Chose a 0 valued axis\n" );
756 /* store the axis number in the lightmap */
757 lm->axisNum = axisNum;
759 /* walk the list of surfaces on this raw lightmap */
760 for( n = 0; n < lm->numLightSurfaces; n++ )
763 num2 = lightSurfaces[ lm->firstLightSurface + n ];
764 ds2 = &bspDrawSurfaces[ num2 ];
765 verts = &yDrawVerts[ ds2->firstVert ];
767 /* set the lightmap texture coordinates in yDrawVerts in [0, superSample * lm->customWidth] space */
768 for( i = 0; i < ds2->numVerts; i++ )
770 VectorSubtract( verts[ i ].xyz, origin, delta );
771 s = DotProduct( delta, vecs[ 0 ] ) + 0.5f;
772 t = DotProduct( delta, vecs[ 1 ] ) + 0.5f;
773 verts[ i ].lightmap[ 0 ][ 0 ] = s * superSample;
774 verts[ i ].lightmap[ 0 ][ 1 ] = t * superSample;
776 if( s > (float) lm->w || t > (float) lm->h )
778 Sys_FPrintf( SYS_VRB, "WARNING: Lightmap texture coords out of range: S %1.4f > %3d || T %1.4f > %3d\n",
779 s, lm->w, t, lm->h );
784 /* get first drawsurface */
785 num2 = lightSurfaces[ lm->firstLightSurface ];
786 ds2 = &bspDrawSurfaces[ num2 ];
787 verts = &yDrawVerts[ ds2->firstVert ];
789 /* calculate lightmap origin */
790 if( VectorLength( ds2->lightmapVecs[ 2 ] ) )
791 VectorCopy( ds2->lightmapVecs[ 2 ], plane );
793 VectorCopy( lm->axis, plane );
794 plane[ 3 ] = DotProduct( verts[ 0 ].xyz, plane );
796 VectorCopy( origin, lm->origin );
797 d = DotProduct( lm->origin, plane ) - plane[ 3 ];
798 d /= plane[ axisNum ];
799 lm->origin[ axisNum ] -= d;
802 VectorCopy( lm->origin, ds->lightmapOrigin );
804 /* for planar surfaces, create lightmap vectors for st->xyz conversion */
805 if( VectorLength( ds->lightmapVecs[ 2 ] ) || 1 ) /* ydnar: can't remember what exactly i was thinking here... */
807 /* allocate space for the vectors */
808 lm->vecs = safe_malloc( 3 * sizeof( vec3_t ) );
809 memset( lm->vecs, 0, 3 * sizeof( vec3_t ) );
810 VectorCopy( ds->lightmapVecs[ 2 ], lm->vecs[ 2 ] );
812 /* project stepped lightmap blocks and subtract to get planevecs */
813 for( i = 0; i < 2; i++ )
815 len = VectorNormalize( vecs[ i ], normalized );
816 VectorScale( normalized, (1.0 / len), lm->vecs[ i ] );
817 d = DotProduct( lm->vecs[ i ], plane );
818 d /= plane[ axisNum ];
819 lm->vecs[ i ][ axisNum ] -= d;
824 /* lightmap vectors are useless on a non-planar surface */
829 if( ds->surfaceType == MST_PATCH )
831 numPatchesLightmapped++;
832 if( lm->plane != NULL )
833 numPlanarPatchesLightmapped++;
837 if( lm->plane != NULL )
838 numPlanarsLightmapped++;
840 numNonPlanarsLightmapped++;
851 compare function for qsort()
854 static int CompareSurfaceInfo( const void *a, const void *b )
856 surfaceInfo_t *aInfo, *bInfo;
860 /* get surface info */
861 aInfo = &surfaceInfos[ *((const int*) a) ];
862 bInfo = &surfaceInfos[ *((const int*) b) ];
865 if( aInfo->modelindex < bInfo->modelindex )
867 else if( aInfo->modelindex > bInfo->modelindex )
870 /* then lightmap status */
871 if( aInfo->hasLightmap < bInfo->hasLightmap )
873 else if( aInfo->hasLightmap > bInfo->hasLightmap )
876 /* 27: then shader! */
877 if (aInfo->si < bInfo->si)
879 else if (aInfo->si > bInfo->si)
883 /* then lightmap sample size */
884 if( aInfo->sampleSize < bInfo->sampleSize )
886 else if( aInfo->sampleSize > bInfo->sampleSize )
889 /* then lightmap axis */
890 for( i = 0; i < 3; i++ )
892 if( aInfo->axis[ i ] < bInfo->axis[ i ] )
894 else if( aInfo->axis[ i ] > bInfo->axis[ i ] )
899 if( aInfo->plane == NULL && bInfo->plane != NULL )
901 else if( aInfo->plane != NULL && bInfo->plane == NULL )
903 else if( aInfo->plane != NULL && bInfo->plane != NULL )
905 for( i = 0; i < 4; i++ )
907 if( aInfo->plane[ i ] < bInfo->plane[ i ] )
909 else if( aInfo->plane[ i ] > bInfo->plane[ i ] )
914 /* then position in world */
915 for( i = 0; i < 3; i++ )
917 if( aInfo->mins[ i ] < bInfo->mins[ i ] )
919 else if( aInfo->mins[ i ] > bInfo->mins[ i ] )
923 /* these are functionally identical (this should almost never happen) */
930 SetupSurfaceLightmaps()
931 allocates lightmaps for every surface in the bsp that needs one
932 this depends on yDrawVerts being allocated
935 void SetupSurfaceLightmaps( void )
937 int i, j, k, s,num, num2;
940 bspDrawSurface_t *ds;
941 surfaceInfo_t *info, *info2;
944 vec3_t mapSize, entityOrigin;
948 Sys_FPrintf( SYS_VRB, "--- SetupSurfaceLightmaps ---\n");
950 /* determine supersample amount */
951 if( superSample < 1 )
953 else if( superSample > 8 )
955 Sys_Printf( "WARNING: Insane supersampling amount (%d) detected.\n", superSample );
959 /* clear map bounds */
960 ClearBounds( mapMins, mapMaxs );
962 /* allocate a list of surface clusters */
963 numSurfaceClusters = 0;
964 maxSurfaceClusters = numBSPLeafSurfaces;
965 surfaceClusters = safe_malloc( maxSurfaceClusters * sizeof( *surfaceClusters ) );
966 memset( surfaceClusters, 0, maxSurfaceClusters * sizeof( *surfaceClusters ) );
968 /* allocate a list for per-surface info */
969 surfaceInfos = safe_malloc( numBSPDrawSurfaces * sizeof( *surfaceInfos ) );
970 memset( surfaceInfos, 0, numBSPDrawSurfaces * sizeof( *surfaceInfos ) );
971 for( i = 0; i < numBSPDrawSurfaces; i++ )
972 surfaceInfos[ i ].childSurfaceNum = -1;
974 /* allocate a list of surface indexes to be sorted */
975 sortSurfaces = safe_malloc( numBSPDrawSurfaces * sizeof( int ) );
976 memset( sortSurfaces, 0, numBSPDrawSurfaces * sizeof( int ) );
978 /* walk each model in the bsp */
979 for( i = 0; i < numBSPModels; i++ )
982 model = &bspModels[ i ];
984 /* walk the list of surfaces in this model and fill out the info structs */
985 for( j = 0; j < model->numBSPSurfaces; j++ )
987 /* make surface index */
988 num = model->firstBSPSurface + j;
990 /* copy index to sort list */
991 sortSurfaces[ num ] = num;
993 /* get surface and info */
994 ds = &bspDrawSurfaces[ num ];
995 info = &surfaceInfos[ num ];
997 /* set entity origin */
998 if( ds->numVerts > 0 )
999 VectorSubtract( yDrawVerts[ ds->firstVert ].xyz, bspDrawVerts[ ds->firstVert ].xyz, entityOrigin );
1001 VectorClear( entityOrigin );
1004 info->modelindex = i;
1007 info->firstSurfaceCluster = numSurfaceClusters;
1009 /* get extra data */
1010 info->si = GetSurfaceExtraShaderInfo( num );
1011 if( info->si == NULL )
1012 info->si = ShaderInfoForShader( bspShaders[ ds->shaderNum ].shader );
1013 info->parentSurfaceNum = GetSurfaceExtraParentSurfaceNum( num );
1014 info->entityNum = GetSurfaceExtraEntityNum( num );
1015 info->castShadows = GetSurfaceExtraCastShadows( num );
1016 info->recvShadows = GetSurfaceExtraRecvShadows( num );
1017 info->sampleSize = GetSurfaceExtraSampleSize( num );
1018 info->longestCurve = GetSurfaceExtraLongestCurve( num );
1019 info->patchIterations = IterationsForCurve( info->longestCurve, patchSubdivisions );
1020 GetSurfaceExtraLightmapAxis( num, info->axis );
1023 if( info->parentSurfaceNum >= 0 )
1024 surfaceInfos[ info->parentSurfaceNum ].childSurfaceNum = j;
1026 /* determine surface bounds */
1027 ClearBounds( info->mins, info->maxs );
1028 for( k = 0; k < ds->numVerts; k++ )
1030 AddPointToBounds( yDrawVerts[ ds->firstVert + k ].xyz, mapMins, mapMaxs );
1031 AddPointToBounds( yDrawVerts[ ds->firstVert + k ].xyz, info->mins, info->maxs );
1034 /* find all the bsp clusters the surface falls into */
1035 for( k = 0; k < numBSPLeafs; k++ )
1038 leaf = &bspLeafs[ k ];
1041 if( leaf->mins[ 0 ] > info->maxs[ 0 ] || leaf->maxs[ 0 ] < info->mins[ 0 ] ||
1042 leaf->mins[ 1 ] > info->maxs[ 1 ] || leaf->maxs[ 1 ] < info->mins[ 1 ] ||
1043 leaf->mins[ 2 ] > info->maxs[ 2 ] || leaf->maxs[ 2 ] < info->mins[ 2 ] )
1046 /* test leaf surfaces */
1047 for( s = 0; s < leaf->numBSPLeafSurfaces; s++ )
1049 if( bspLeafSurfaces[ leaf->firstBSPLeafSurface + s ] == num )
1051 if( numSurfaceClusters >= maxSurfaceClusters )
1052 Error( "maxSurfaceClusters exceeded" );
1053 surfaceClusters[ numSurfaceClusters ] = leaf->cluster;
1054 numSurfaceClusters++;
1055 info->numSurfaceClusters++;
1060 /* determine if surface is planar */
1061 if( VectorLength( ds->lightmapVecs[ 2 ] ) > 0.0f )
1064 info->plane = safe_malloc( 4 * sizeof( float ) );
1065 VectorCopy( ds->lightmapVecs[ 2 ], info->plane );
1066 info->plane[ 3 ] = DotProduct( yDrawVerts[ ds->firstVert ].xyz, info->plane );
1069 /* determine if surface requires a lightmap */
1070 if( ds->surfaceType == MST_TRIANGLE_SOUP ||
1071 ds->surfaceType == MST_FOLIAGE ||
1072 (info->si->compileFlags & C_VERTEXLIT) )
1073 numSurfsVertexLit++;
1076 numSurfsLightmapped++;
1077 info->hasLightmap = qtrue;
1082 /* find longest map distance */
1083 VectorSubtract( mapMaxs, mapMins, mapSize );
1084 maxMapDistance = VectorLength( mapSize );
1086 /* sort the surfaces info list */
1087 qsort( sortSurfaces, numBSPDrawSurfaces, sizeof( int ), CompareSurfaceInfo );
1089 /* allocate a list of surfaces that would go into raw lightmaps */
1090 numLightSurfaces = 0;
1091 lightSurfaces = safe_malloc( numSurfsLightmapped * sizeof( int ) );
1092 memset( lightSurfaces, 0, numSurfsLightmapped * sizeof( int ) );
1094 /* allocate a list of raw lightmaps */
1095 numRawSuperLuxels = 0;
1096 numRawLightmaps = 0;
1097 rawLightmaps = safe_malloc( numSurfsLightmapped * sizeof( *rawLightmaps ) );
1098 memset( rawLightmaps, 0, numSurfsLightmapped * sizeof( *rawLightmaps ) );
1100 /* walk the list of sorted surfaces */
1101 for( i = 0; i < numBSPDrawSurfaces; i++ )
1103 /* get info and attempt early out */
1104 num = sortSurfaces[ i ];
1105 ds = &bspDrawSurfaces[ num ];
1106 info = &surfaceInfos[ num ];
1107 if( info->hasLightmap == qfalse || info->lm != NULL || info->parentSurfaceNum >= 0 )
1110 /* allocate a new raw lightmap */
1111 lm = &rawLightmaps[ numRawLightmaps ];
1115 lm->splotchFix = info->si->splotchFix;
1116 lm->firstLightSurface = numLightSurfaces;
1117 lm->numLightSurfaces = 0;
1118 /* vortex: multiply lightmap sample size by -samplescale */
1119 if (sampleScale > 0)
1120 lm->sampleSize = info->sampleSize*sampleScale;
1122 lm->sampleSize = info->sampleSize;
1123 lm->actualSampleSize = lm->sampleSize;
1124 lm->entityNum = info->entityNum;
1125 lm->recvShadows = info->recvShadows;
1126 lm->brightness = info->si->lmBrightness;
1127 lm->filterRadius = info->si->lmFilterRadius;
1128 VectorCopy(info->si->floodlightRGB, lm->floodlightRGB);
1129 lm->floodlightDistance = info->si->floodlightDistance;
1130 lm->floodlightIntensity = info->si->floodlightIntensity;
1131 lm->floodlightDirectionScale = info->si->floodlightDirectionScale;
1132 VectorCopy( info->axis, lm->axis );
1133 lm->plane = info->plane;
1134 VectorCopy( info->mins, lm->mins );
1135 VectorCopy( info->maxs, lm->maxs );
1137 lm->customWidth = info->si->lmCustomWidth;
1138 lm->customHeight = info->si->lmCustomHeight;
1140 /* add the surface to the raw lightmap */
1141 AddSurfaceToRawLightmap( num, lm );
1144 /* do an exhaustive merge */
1148 /* walk the list of surfaces again */
1150 for( j = i + 1; j < numBSPDrawSurfaces && lm->finished == qfalse; j++ )
1152 /* get info and attempt early out */
1153 num2 = sortSurfaces[ j ];
1154 info2 = &surfaceInfos[ num2 ];
1155 if( info2->hasLightmap == qfalse || info2->lm != NULL )
1158 /* add the surface to the raw lightmap */
1159 if( AddSurfaceToRawLightmap( num2, lm ) )
1167 lm->numLightSurfaces--;
1173 /* finish the lightmap and allocate the various buffers */
1174 FinishRawLightmap( lm );
1177 /* allocate vertex luxel storage */
1178 for( k = 0; k < MAX_LIGHTMAPS; k++ )
1180 vertexLuxels[ k ] = safe_malloc( numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
1181 memset( vertexLuxels[ k ], 0, numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
1182 radVertexLuxels[ k ] = safe_malloc( numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
1183 memset( radVertexLuxels[ k ], 0, numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
1186 /* emit some stats */
1187 Sys_FPrintf( SYS_VRB, "%9d surfaces\n", numBSPDrawSurfaces );
1188 Sys_FPrintf( SYS_VRB, "%9d raw lightmaps\n", numRawLightmaps );
1189 Sys_FPrintf( SYS_VRB, "%9d surfaces vertex lit\n", numSurfsVertexLit );
1190 Sys_FPrintf( SYS_VRB, "%9d surfaces lightmapped\n", numSurfsLightmapped );
1191 Sys_FPrintf( SYS_VRB, "%9d planar surfaces lightmapped\n", numPlanarsLightmapped );
1192 Sys_FPrintf( SYS_VRB, "%9d non-planar surfaces lightmapped\n", numNonPlanarsLightmapped );
1193 Sys_FPrintf( SYS_VRB, "%9d patches lightmapped\n", numPatchesLightmapped );
1194 Sys_FPrintf( SYS_VRB, "%9d planar patches lightmapped\n", numPlanarPatchesLightmapped );
1200 StitchSurfaceLightmaps()
1201 stitches lightmap edges
1202 2002-11-20 update: use this func only for stitching nonplanar patch lightmap seams
1205 #define MAX_STITCH_CANDIDATES 32
1206 #define MAX_STITCH_LUXELS 64
1208 void StitchSurfaceLightmaps( void )
1210 int i, j, x, y, x2, y2, *cluster, *cluster2,
1211 numStitched, numCandidates, numLuxels, f, fOld, start;
1212 rawLightmap_t *lm, *a, *b, *c[ MAX_STITCH_CANDIDATES ];
1213 float *luxel, *luxel2, *origin, *origin2, *normal, *normal2,
1214 sampleSize, average[ 3 ], totalColor, ootc;
1217 /* disabled for now */
1221 Sys_Printf( "--- StitchSurfaceLightmaps ---\n");
1225 start = I_FloatTime();
1227 /* walk the list of raw lightmaps */
1229 for( i = 0; i < numRawLightmaps; i++ )
1231 /* print pacifier */
1232 f = 10 * i / numRawLightmaps;
1236 Sys_Printf( "%i...", f );
1239 /* get lightmap a */
1240 a = &rawLightmaps[ i ];
1242 /* walk rest of lightmaps */
1244 for( j = i + 1; j < numRawLightmaps && numCandidates < MAX_STITCH_CANDIDATES; j++ )
1246 /* get lightmap b */
1247 b = &rawLightmaps[ j ];
1249 /* test bounding box */
1250 if( a->mins[ 0 ] > b->maxs[ 0 ] || a->maxs[ 0 ] < b->mins[ 0 ] ||
1251 a->mins[ 1 ] > b->maxs[ 1 ] || a->maxs[ 1 ] < b->mins[ 1 ] ||
1252 a->mins[ 2 ] > b->maxs[ 2 ] || a->maxs[ 2 ] < b->mins[ 2 ] )
1256 c[ numCandidates++ ] = b;
1260 for( y = 0; y < a->sh; y++ )
1262 for( x = 0; x < a->sw; x++ )
1264 /* ignore unmapped/unlit luxels */
1266 cluster = SUPER_CLUSTER( x, y );
1267 if( *cluster == CLUSTER_UNMAPPED )
1269 luxel = SUPER_LUXEL( 0, x, y );
1270 if( luxel[ 3 ] <= 0.0f )
1273 /* get particulars */
1274 origin = SUPER_ORIGIN( x, y );
1275 normal = SUPER_NORMAL( x, y );
1277 /* walk candidate list */
1278 for( j = 0; j < numCandidates; j++ )
1284 /* set samplesize to the smaller of the pair */
1285 sampleSize = 0.5f * (a->actualSampleSize < b->actualSampleSize ? a->actualSampleSize : b->actualSampleSize);
1287 /* test bounding box */
1288 if( origin[ 0 ] < (b->mins[ 0 ] - sampleSize) || (origin[ 0 ] > b->maxs[ 0 ] + sampleSize) ||
1289 origin[ 1 ] < (b->mins[ 1 ] - sampleSize) || (origin[ 1 ] > b->maxs[ 1 ] + sampleSize) ||
1290 origin[ 2 ] < (b->mins[ 2 ] - sampleSize) || (origin[ 2 ] > b->maxs[ 2 ] + sampleSize) )
1293 /* walk candidate luxels */
1294 VectorClear( average );
1297 for( y2 = 0; y2 < b->sh && numLuxels < MAX_STITCH_LUXELS; y2++ )
1299 for( x2 = 0; x2 < b->sw && numLuxels < MAX_STITCH_LUXELS; x2++ )
1301 /* ignore same luxels */
1302 if( a == b && abs( x - x2 ) <= 1 && abs( y - y2 ) <= 1 )
1305 /* ignore unmapped/unlit luxels */
1306 cluster2 = SUPER_CLUSTER( x2, y2 );
1307 if( *cluster2 == CLUSTER_UNMAPPED )
1309 luxel2 = SUPER_LUXEL( 0, x2, y2 );
1310 if( luxel2[ 3 ] <= 0.0f )
1313 /* get particulars */
1314 origin2 = SUPER_ORIGIN( x2, y2 );
1315 normal2 = SUPER_NORMAL( x2, y2 );
1318 if( DotProduct( normal, normal2 ) < 0.5f )
1322 if( fabs( origin[ 0 ] - origin2[ 0 ] ) > sampleSize ||
1323 fabs( origin[ 1 ] - origin2[ 1 ] ) > sampleSize ||
1324 fabs( origin[ 2 ] - origin2[ 2 ] ) > sampleSize )
1328 //% VectorSet( luxel2, 255, 0, 255 );
1329 VectorAdd( average, luxel2, average );
1330 totalColor += luxel2[ 3 ];
1335 if( numLuxels == 0 )
1339 ootc = 1.0f / totalColor;
1340 VectorScale( average, ootc, luxel );
1348 /* emit statistics */
1349 Sys_Printf( " (%i)\n", (int) (I_FloatTime() - start) );
1350 Sys_FPrintf( SYS_VRB, "%9d luxels stitched\n", numStitched );
1357 compares two surface lightmaps' bsp luxels, ignoring occluded luxels
1360 #define SOLID_EPSILON 0.0625
1361 #define LUXEL_TOLERANCE 0.0025
1362 #define LUXEL_COLOR_FRAC 0.001302083 /* 1 / 3 / 256 */
1364 static qboolean CompareBSPLuxels( rawLightmap_t *a, int aNum, rawLightmap_t *b, int bNum )
1368 double delta, total, rd, gd, bd;
1369 float *aLuxel, *bLuxel;
1372 /* styled lightmaps will never be collapsed to non-styled lightmaps when there is _minlight */
1373 if( (minLight[ 0 ] || minLight[ 1 ] || minLight[ 2 ]) &&
1374 ((aNum == 0 && bNum != 0) || (aNum != 0 && bNum == 0)) )
1378 if( a->customWidth != b->customWidth || a->customHeight != b->customHeight ||
1379 a->brightness != b->brightness ||
1380 a->solid[ aNum ] != b->solid[ bNum ] ||
1381 a->bspLuxels[ aNum ] == NULL || b->bspLuxels[ bNum ] == NULL )
1384 /* compare solid color lightmaps */
1385 if( a->solid[ aNum ] && b->solid[ bNum ] )
1388 rd = fabs( a->solidColor[ aNum ][ 0 ] - b->solidColor[ bNum ][ 0 ] );
1389 gd = fabs( a->solidColor[ aNum ][ 1 ] - b->solidColor[ bNum ][ 1 ] );
1390 bd = fabs( a->solidColor[ aNum ][ 2 ] - b->solidColor[ bNum ][ 2 ] );
1393 if( rd > SOLID_EPSILON || gd > SOLID_EPSILON|| bd > SOLID_EPSILON )
1400 /* compare nonsolid lightmaps */
1401 if( a->w != b->w || a->h != b->h )
1404 /* compare luxels */
1407 for( y = 0; y < a->h; y++ )
1409 for( x = 0; x < a->w; x++ )
1411 /* increment total */
1415 lm = a; aLuxel = BSP_LUXEL( aNum, x, y );
1416 lm = b; bLuxel = BSP_LUXEL( bNum, x, y );
1418 /* ignore unused luxels */
1419 if( aLuxel[ 0 ] < 0 || bLuxel[ 0 ] < 0 )
1423 rd = fabs( aLuxel[ 0 ] - bLuxel[ 0 ] );
1424 gd = fabs( aLuxel[ 1 ] - bLuxel[ 1 ] );
1425 bd = fabs( aLuxel[ 2 ] - bLuxel[ 2 ] );
1427 /* 2003-09-27: compare individual luxels */
1428 if( rd > 3.0 || gd > 3.0 || bd > 3.0 )
1431 /* compare (fixme: take into account perceptual differences) */
1432 delta += rd * LUXEL_COLOR_FRAC;
1433 delta += gd * LUXEL_COLOR_FRAC;
1434 delta += bd * LUXEL_COLOR_FRAC;
1436 /* is the change too high? */
1437 if( total > 0.0 && ((delta / total) > LUXEL_TOLERANCE) )
1442 /* made it this far, they must be identical (or close enough) */
1450 merges two surface lightmaps' bsp luxels, overwriting occluded luxels
1453 static qboolean MergeBSPLuxels( rawLightmap_t *a, int aNum, rawLightmap_t *b, int bNum )
1457 float luxel[ 3 ], *aLuxel, *bLuxel;
1461 if( a->customWidth != b->customWidth || a->customHeight != b->customHeight ||
1462 a->brightness != b->brightness ||
1463 a->solid[ aNum ] != b->solid[ bNum ] ||
1464 a->bspLuxels[ aNum ] == NULL || b->bspLuxels[ bNum ] == NULL )
1467 /* compare solid lightmaps */
1468 if( a->solid[ aNum ] && b->solid[ bNum ] )
1471 VectorAdd( a->solidColor[ aNum ], b->solidColor[ bNum ], luxel );
1472 VectorScale( luxel, 0.5f, luxel );
1475 VectorCopy( luxel, a->solidColor[ aNum ] );
1476 VectorCopy( luxel, b->solidColor[ bNum ] );
1478 /* return to sender */
1482 /* compare nonsolid lightmaps */
1483 if( a->w != b->w || a->h != b->h )
1487 for( y = 0; y < a->h; y++ )
1489 for( x = 0; x < a->w; x++ )
1492 lm = a; aLuxel = BSP_LUXEL( aNum, x, y );
1493 lm = b; bLuxel = BSP_LUXEL( bNum, x, y );
1495 /* handle occlusion mismatch */
1496 if( aLuxel[ 0 ] < 0.0f )
1497 VectorCopy( bLuxel, aLuxel );
1498 else if( bLuxel[ 0 ] < 0.0f )
1499 VectorCopy( aLuxel, bLuxel );
1503 VectorAdd( aLuxel, bLuxel, luxel );
1504 VectorScale( luxel, 0.5f, luxel );
1506 /* debugging code */
1507 //% luxel[ 2 ] += 64.0f;
1510 VectorCopy( luxel, aLuxel );
1511 VectorCopy( luxel, bLuxel );
1524 determines if a single luxel is can be approximated with the interpolated vertex rgba
1527 static qboolean ApproximateLuxel( rawLightmap_t *lm, bspDrawVert_t *dv )
1529 int i, x, y, d, lightmapNum;
1531 vec3_t color, vertexColor;
1532 byte cb[ 4 ], vcb[ 4 ];
1535 /* find luxel xy coords */
1536 x = dv->lightmap[ 0 ][ 0 ] / superSample;
1537 y = dv->lightmap[ 0 ][ 1 ] / superSample;
1540 else if( x >= lm->w )
1544 else if( y >= lm->h )
1548 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1551 if( lm->styles[ lightmapNum ] == LS_NONE )
1555 luxel = BSP_LUXEL( lightmapNum, x, y );
1557 /* ignore occluded luxels */
1558 if( luxel[ 0 ] < 0.0f || luxel[ 1 ] < 0.0f || luxel[ 2 ] < 0.0f )
1561 /* copy, set min color and compare */
1562 VectorCopy( luxel, color );
1563 VectorCopy( dv->color[ 0 ], vertexColor );
1565 /* styles are not affected by minlight */
1566 if( lightmapNum == 0 )
1568 for( i = 0; i < 3; i++ )
1571 if( color[ i ] < minLight[ i ] )
1572 color[ i ] = minLight[ i ];
1573 if( vertexColor[ i ] < minLight[ i ] ) /* note NOT minVertexLight */
1574 vertexColor[ i ] = minLight[ i ];
1579 ColorToBytes( color, cb, 1.0f );
1580 ColorToBytes( vertexColor, vcb, 1.0f );
1583 for( i = 0; i < 3; i++ )
1585 d = cb[ i ] - vcb[ i ];
1588 if( d > approximateTolerance )
1593 /* close enough for the girls i date */
1600 ApproximateTriangle()
1601 determines if a single triangle can be approximated with vertex rgba
1604 static qboolean ApproximateTriangle_r( rawLightmap_t *lm, bspDrawVert_t *dv[ 3 ] )
1606 bspDrawVert_t mid, *dv2[ 3 ];
1610 /* approximate the vertexes */
1611 if( ApproximateLuxel( lm, dv[ 0 ] ) == qfalse )
1613 if( ApproximateLuxel( lm, dv[ 1 ] ) == qfalse )
1615 if( ApproximateLuxel( lm, dv[ 2 ] ) == qfalse )
1618 /* subdivide calc */
1621 float dx, dy, dist, maxDist;
1624 /* find the longest edge and split it */
1627 for( i = 0; i < 3; i++ )
1629 dx = dv[ i ]->lightmap[ 0 ][ 0 ] - dv[ (i + 1) % 3 ]->lightmap[ 0 ][ 0 ];
1630 dy = dv[ i ]->lightmap[ 0 ][ 1 ] - dv[ (i + 1) % 3 ]->lightmap[ 0 ][ 1 ];
1631 dist = sqrt( (dx * dx) + (dy * dy) );
1632 if( dist > maxDist )
1639 /* try to early out */
1640 if( i < 0 || maxDist < subdivideThreshold )
1644 /* split the longest edge and map it */
1645 LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid );
1646 if( ApproximateLuxel( lm, &mid ) == qfalse )
1649 /* recurse to first triangle */
1650 VectorCopy( dv, dv2 );
1652 if( ApproximateTriangle_r( lm, dv2 ) == qfalse )
1655 /* recurse to second triangle */
1656 VectorCopy( dv, dv2 );
1657 dv2[ (max + 1) % 3 ] = ∣
1658 return ApproximateTriangle_r( lm, dv2 );
1664 ApproximateLightmap()
1665 determines if a raw lightmap can be approximated sufficiently with vertex colors
1668 static qboolean ApproximateLightmap( rawLightmap_t *lm )
1670 int n, num, i, x, y, pw[ 5 ], r;
1671 bspDrawSurface_t *ds;
1672 surfaceInfo_t *info;
1673 mesh_t src, *subdivided, *mesh;
1674 bspDrawVert_t *verts, *dv[ 3 ];
1675 qboolean approximated;
1678 /* approximating? */
1679 if( approximateTolerance <= 0 )
1682 /* test for jmonroe */
1684 /* don't approx lightmaps with styled twins */
1685 if( lm->numStyledTwins > 0 )
1688 /* don't approx lightmaps with styles */
1689 for( i = 1; i < MAX_LIGHTMAPS; i++ )
1691 if( lm->styles[ i ] != LS_NONE )
1696 /* assume reduced until shadow detail is found */
1697 approximated = qtrue;
1699 /* walk the list of surfaces on this raw lightmap */
1700 for( n = 0; n < lm->numLightSurfaces; n++ )
1703 num = lightSurfaces[ lm->firstLightSurface + n ];
1704 ds = &bspDrawSurfaces[ num ];
1705 info = &surfaceInfos[ num ];
1707 /* assume not-reduced initially */
1708 info->approximated = qfalse;
1710 /* bail if lightmap doesn't match up */
1711 if( info->lm != lm )
1714 /* bail if not vertex lit */
1715 if( info->si->noVertexLight )
1718 /* assume that surfaces whose bounding boxes is smaller than 2x samplesize will be forced to vertex */
1719 if( (info->maxs[ 0 ] - info->mins[ 0 ]) <= (2.0f * info->sampleSize) &&
1720 (info->maxs[ 1 ] - info->mins[ 1 ]) <= (2.0f * info->sampleSize) &&
1721 (info->maxs[ 2 ] - info->mins[ 2 ]) <= (2.0f * info->sampleSize) )
1723 info->approximated = qtrue;
1724 numSurfsVertexForced++;
1728 /* handle the triangles */
1729 switch( ds->surfaceType )
1733 verts = yDrawVerts + ds->firstVert;
1735 /* map the triangles */
1736 info->approximated = qtrue;
1737 for( i = 0; i < ds->numIndexes && info->approximated; i += 3 )
1739 dv[ 0 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i ] ];
1740 dv[ 1 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 1 ] ];
1741 dv[ 2 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 2 ] ];
1742 info->approximated = ApproximateTriangle_r( lm, dv );
1747 /* make a mesh from the drawsurf */
1748 src.width = ds->patchWidth;
1749 src.height = ds->patchHeight;
1750 src.verts = &yDrawVerts[ ds->firstVert ];
1751 //% subdivided = SubdivideMesh( src, 8, 512 );
1752 subdivided = SubdivideMesh2( src, info->patchIterations );
1754 /* fit it to the curve and remove colinear verts on rows/columns */
1755 PutMeshOnCurve( *subdivided );
1756 mesh = RemoveLinearMeshColumnsRows( subdivided );
1757 FreeMesh( subdivided );
1760 verts = mesh->verts;
1762 /* map the mesh quads */
1763 info->approximated = qtrue;
1764 for( y = 0; y < (mesh->height - 1) && info->approximated; y++ )
1766 for( x = 0; x < (mesh->width - 1) && info->approximated; x++ )
1769 pw[ 0 ] = x + (y * mesh->width);
1770 pw[ 1 ] = x + ((y + 1) * mesh->width);
1771 pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
1772 pw[ 3 ] = x + 1 + (y * mesh->width);
1773 pw[ 4 ] = x + (y * mesh->width); /* same as pw[ 0 ] */
1778 /* get drawverts and map first triangle */
1779 dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1780 dv[ 1 ] = &verts[ pw[ r + 1 ] ];
1781 dv[ 2 ] = &verts[ pw[ r + 2 ] ];
1782 info->approximated = ApproximateTriangle_r( lm, dv );
1784 /* get drawverts and map second triangle */
1785 dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1786 dv[ 1 ] = &verts[ pw[ r + 2 ] ];
1787 dv[ 2 ] = &verts[ pw[ r + 3 ] ];
1788 if( info->approximated )
1789 info->approximated = ApproximateTriangle_r( lm, dv );
1802 if( info->approximated == qfalse )
1803 approximated = qfalse;
1805 numSurfsVertexApproximated++;
1809 return approximated;
1815 TestOutLightmapStamp()
1816 tests a stamp on a given lightmap for validity
1819 static qboolean TestOutLightmapStamp( rawLightmap_t *lm, int lightmapNum, outLightmap_t *olm, int x, int y )
1821 int sx, sy, ox, oy, offset;
1826 if( x < 0 || y < 0 || (x + lm->w) > olm->customWidth || (y + lm->h) > olm->customHeight )
1829 /* solid lightmaps test a 1x1 stamp */
1830 if( lm->solid[ lightmapNum ] )
1832 offset = (y * olm->customWidth) + x;
1833 if( olm->lightBits[ offset >> 3 ] & (1 << (offset & 7)) )
1838 /* test the stamp */
1839 for( sy = 0; sy < lm->h; sy++ )
1841 for( sx = 0; sx < lm->w; sx++ )
1844 luxel = BSP_LUXEL( lightmapNum, sx, sy );
1845 if( luxel[ 0 ] < 0.0f )
1848 /* get bsp lightmap coords and test */
1851 offset = (oy * olm->customWidth) + ox;
1852 if( olm->lightBits[ offset >> 3 ] & (1 << (offset & 7)) )
1857 /* stamp is empty */
1865 sets up an output lightmap
1868 static void SetupOutLightmap( rawLightmap_t *lm, outLightmap_t *olm )
1871 if( lm == NULL || olm == NULL )
1874 /* is this a "normal" bsp-stored lightmap? */
1875 if( (lm->customWidth == game->lightmapSize && lm->customHeight == game->lightmapSize) || externalLightmaps )
1877 olm->lightmapNum = numBSPLightmaps;
1880 /* lightmaps are interleaved with light direction maps */
1885 olm->lightmapNum = -3;
1887 /* set external lightmap number */
1888 olm->extLightmapNum = -1;
1891 olm->numLightmaps = 0;
1892 olm->customWidth = lm->customWidth;
1893 olm->customHeight = lm->customHeight;
1894 olm->freeLuxels = olm->customWidth * olm->customHeight;
1895 olm->numShaders = 0;
1897 /* allocate buffers */
1898 olm->lightBits = safe_malloc( (olm->customWidth * olm->customHeight / 8) + 8 );
1899 memset( olm->lightBits, 0, (olm->customWidth * olm->customHeight / 8) + 8 );
1900 olm->bspLightBytes = safe_malloc( olm->customWidth * olm->customHeight * 3 );
1901 memset( olm->bspLightBytes, 0, olm->customWidth * olm->customHeight * 3 );
1904 olm->bspDirBytes = safe_malloc( olm->customWidth * olm->customHeight * 3 );
1905 memset( olm->bspDirBytes, 0, olm->customWidth * olm->customHeight * 3 );
1913 for a given surface lightmap, find output lightmap pages and positions for it
1916 #define LIGHTMAP_RESERVE_COUNT 1
1917 static void FindOutLightmaps( rawLightmap_t *lm )
1919 int i, j, k, lightmapNum, xMax, yMax, x = -1, y = -1, sx, sy, ox, oy, offset;
1921 surfaceInfo_t *info;
1922 float *luxel, *deluxel;
1923 vec3_t color, direction;
1928 /* set default lightmap number (-3 = LIGHTMAP_BY_VERTEX) */
1929 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1930 lm->outLightmapNums[ lightmapNum ] = -3;
1932 /* can this lightmap be approximated with vertex color? */
1933 if( ApproximateLightmap( lm ) )
1937 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1940 if( lm->styles[ lightmapNum ] == LS_NONE )
1943 /* don't store twinned lightmaps */
1944 if( lm->twins[ lightmapNum ] != NULL )
1947 /* if this is a styled lightmap, try some normalized locations first */
1949 if( lightmapNum > 0 && outLightmaps != NULL )
1952 for( j = 0; j < 2; j++ )
1954 /* try identical position */
1955 for( i = 0; i < numOutLightmaps; i++ )
1957 /* get the output lightmap */
1958 olm = &outLightmaps[ i ];
1960 /* simple early out test */
1961 if( olm->freeLuxels < lm->used )
1964 /* don't store non-custom raw lightmaps on custom bsp lightmaps */
1965 if( olm->customWidth != lm->customWidth ||
1966 olm->customHeight != lm->customHeight )
1972 x = lm->lightmapX[ 0 ];
1973 y = lm->lightmapY[ 0 ];
1974 ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );
1980 for( sy = -1; sy <= 1; sy++ )
1982 for( sx = -1; sx <= 1; sx++ )
1984 x = lm->lightmapX[ 0 ] + sx * (olm->customWidth >> 1); //% lm->w;
1985 y = lm->lightmapY[ 0 ] + sy * (olm->customHeight >> 1); //% lm->h;
1986 ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );
2006 /* try normal placement algorithm */
2013 /* walk the list of lightmap pages */
2014 if(lightmapSearchBlockSize <= 0 || numOutLightmaps < LIGHTMAP_RESERVE_COUNT)
2017 i = ((numOutLightmaps - LIGHTMAP_RESERVE_COUNT) / lightmapSearchBlockSize) * lightmapSearchBlockSize;
2018 for( ; i < numOutLightmaps; i++ )
2020 /* get the output lightmap */
2021 olm = &outLightmaps[ i ];
2023 /* simple early out test */
2024 if( olm->freeLuxels < lm->used )
2027 /* don't store non-custom raw lightmaps on custom bsp lightmaps */
2028 if( olm->customWidth != lm->customWidth ||
2029 olm->customHeight != lm->customHeight )
2033 if( lm->solid[ lightmapNum ] )
2035 xMax = olm->customWidth;
2036 yMax = olm->customHeight;
2040 xMax = (olm->customWidth - lm->w) + 1;
2041 yMax = (olm->customHeight - lm->h) + 1;
2044 /* walk the origin around the lightmap */
2045 for( y = 0; y < yMax; y++ )
2047 for( x = 0; x < xMax; x++ )
2049 /* find a fine tract of lauhnd */
2050 ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );
2072 /* allocate LIGHTMAP_RESERVE_COUNT new output lightmaps */
2073 numOutLightmaps += LIGHTMAP_RESERVE_COUNT;
2074 olm = safe_malloc( numOutLightmaps * sizeof( outLightmap_t ) );
2075 if( outLightmaps != NULL && numOutLightmaps > LIGHTMAP_RESERVE_COUNT )
2077 memcpy( olm, outLightmaps, (numOutLightmaps - LIGHTMAP_RESERVE_COUNT) * sizeof( outLightmap_t ) );
2078 free( outLightmaps );
2082 /* initialize both out lightmaps */
2083 for(k = numOutLightmaps - LIGHTMAP_RESERVE_COUNT; k < numOutLightmaps; ++k)
2084 SetupOutLightmap( lm, &outLightmaps[ k ] );
2086 /* set out lightmap */
2087 i = numOutLightmaps - LIGHTMAP_RESERVE_COUNT;
2088 olm = &outLightmaps[ i ];
2090 /* set stamp xy origin to the first surface lightmap */
2091 if( lightmapNum > 0 )
2093 x = lm->lightmapX[ 0 ];
2094 y = lm->lightmapY[ 0 ];
2098 /* if this is a style-using lightmap, it must be exported */
2099 if( lightmapNum > 0 && game->load != LoadRBSPFile )
2100 olm->extLightmapNum = 0;
2102 /* add the surface lightmap to the bsp lightmap */
2103 lm->outLightmapNums[ lightmapNum ] = i;
2104 lm->lightmapX[ lightmapNum ] = x;
2105 lm->lightmapY[ lightmapNum ] = y;
2106 olm->numLightmaps++;
2109 for( i = 0; i < lm->numLightSurfaces; i++ )
2111 /* get surface info */
2112 info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + i ] ];
2114 /* test for shader */
2115 for( j = 0; j < olm->numShaders; j++ )
2117 if( olm->shaders[ j ] == info->si )
2121 /* if it doesn't exist, add it */
2122 if( j >= olm->numShaders && olm->numShaders < MAX_LIGHTMAP_SHADERS )
2124 olm->shaders[ olm->numShaders ] = info->si;
2126 numLightmapShaders++;
2131 if( lm->solid[ lightmapNum ] )
2142 /* mark the bits used */
2143 for( y = 0; y < yMax; y++ )
2145 for( x = 0; x < xMax; x++ )
2148 luxel = BSP_LUXEL( lightmapNum, x, y );
2149 deluxel = BSP_DELUXEL( x, y );
2150 if( luxel[ 0 ] < 0.0f && !lm->solid[ lightmapNum ])
2153 /* set minimum light */
2154 if( lm->solid[ lightmapNum ] )
2157 VectorSet( color, 255.0f, 0.0f, 0.0f );
2159 VectorCopy( lm->solidColor[ lightmapNum ], color );
2162 VectorCopy( luxel, color );
2164 /* styles are not affected by minlight */
2165 if( lightmapNum == 0 )
2167 for( i = 0; i < 3; i++ )
2169 if( color[ i ] < minLight[ i ] )
2170 color[ i ] = minLight[ i ];
2174 /* get bsp lightmap coords */
2175 ox = x + lm->lightmapX[ lightmapNum ];
2176 oy = y + lm->lightmapY[ lightmapNum ];
2177 offset = (oy * olm->customWidth) + ox;
2179 /* flag pixel as used */
2180 olm->lightBits[ offset >> 3 ] |= (1 << (offset & 7));
2184 pixel = olm->bspLightBytes + (((oy * olm->customWidth) + ox) * 3);
2185 ColorToBytes( color, pixel, lm->brightness );
2187 /* store direction */
2190 /* normalize average light direction */
2191 pixel = olm->bspDirBytes + (((oy * olm->customWidth) + ox) * 3);
2192 VectorScale( deluxel, 1000.0f, direction );
2193 VectorNormalize( direction, direction );
2194 VectorScale( direction, 127.5f, direction );
2195 for( i = 0; i < 3; i++ )
2196 pixel[ i ] = (byte)( 127.5f + direction[ i ] );
2206 CompareRawLightmap()
2207 compare function for qsort()
2210 static int CompareRawLightmap( const void *a, const void *b )
2212 rawLightmap_t *alm, *blm;
2213 surfaceInfo_t *aInfo, *bInfo;
2218 alm = &rawLightmaps[ *((const int*) a) ];
2219 blm = &rawLightmaps[ *((const int*) b) ];
2221 /* get min number of surfaces */
2222 min = (alm->numLightSurfaces < blm->numLightSurfaces ? alm->numLightSurfaces : blm->numLightSurfaces);
2225 for( i = 0; i < min; i++ )
2227 /* get surface info */
2228 aInfo = &surfaceInfos[ lightSurfaces[ alm->firstLightSurface + i ] ];
2229 bInfo = &surfaceInfos[ lightSurfaces[ blm->firstLightSurface + i ] ];
2231 /* compare shader names */
2232 diff = strcmp( aInfo->si->shader, bInfo->si->shader );
2237 /* test style count */
2239 for( i = 0; i < MAX_LIGHTMAPS; i++ )
2240 diff += blm->styles[ i ] - alm->styles[ i ];
2245 diff = (blm->w * blm->h) - (alm->w * alm->h);
2249 /* must be equivalent */
2253 void FillOutLightmap(outLightmap_t *olm)
2257 vec3_t dir_sum, light_sum;
2259 byte *lightBitsNew = NULL;
2260 byte *lightBytesNew = NULL;
2261 byte *dirBytesNew = NULL;
2263 lightBitsNew = safe_malloc((olm->customWidth * olm->customHeight + 8) / 8);
2264 lightBytesNew = safe_malloc(olm->customWidth * olm->customHeight * 3);
2266 dirBytesNew = safe_malloc(olm->customWidth * olm->customHeight * 3);
2269 memset(olm->lightBits, 0, (olm->customWidth * olm->customHeight + 8) / 8);
2270 olm->lightBits[0] |= 1;
2271 olm->lightBits[(10 * olm->customWidth + 30) >> 3] |= 1 << ((10 * olm->customWidth + 30) & 7);
2272 memset(olm->bspLightBytes, 0, olm->customWidth * olm->customHeight * 3);
2273 olm->bspLightBytes[0] = 255;
2274 olm->bspLightBytes[(10 * olm->customWidth + 30) * 3 + 2] = 255;
2277 memcpy(lightBitsNew, olm->lightBits, (olm->customWidth * olm->customHeight + 8) / 8);
2278 memcpy(lightBytesNew, olm->bspLightBytes, olm->customWidth * olm->customHeight * 3);
2280 memcpy(dirBytesNew, olm->bspDirBytes, olm->customWidth * olm->customHeight * 3);
2285 for(y = 0; y < olm->customHeight; ++y)
2287 for(x = 0; x < olm->customWidth; ++x)
2289 ofs = y * olm->customWidth + x;
2290 if(olm->lightBits[ofs >> 3] & (1 << (ofs & 7))) /* already filled */
2293 VectorClear(dir_sum);
2294 VectorClear(light_sum);
2296 /* try all four neighbors */
2297 ofs = ((y + olm->customHeight - 1) % olm->customHeight) * olm->customWidth + x;
2298 if(olm->lightBits[ofs >> 3] & (1 << (ofs & 7))) /* already filled */
2301 VectorAdd(light_sum, olm->bspLightBytes + ofs * 3, light_sum);
2303 VectorAdd(dir_sum, olm->bspDirBytes + ofs * 3, dir_sum);
2306 ofs = ((y + 1) % olm->customHeight) * olm->customWidth + x;
2307 if(olm->lightBits[ofs >> 3] & (1 << (ofs & 7))) /* already filled */
2310 VectorAdd(light_sum, olm->bspLightBytes + ofs * 3, light_sum);
2312 VectorAdd(dir_sum, olm->bspDirBytes + ofs * 3, dir_sum);
2315 ofs = y * olm->customWidth + (x + olm->customWidth - 1) % olm->customWidth;
2316 if(olm->lightBits[ofs >> 3] & (1 << (ofs & 7))) /* already filled */
2319 VectorAdd(light_sum, olm->bspLightBytes + ofs * 3, light_sum);
2321 VectorAdd(dir_sum, olm->bspDirBytes + ofs * 3, dir_sum);
2324 ofs = y * olm->customWidth + (x + 1) % olm->customWidth;
2325 if(olm->lightBits[ofs >> 3] & (1 << (ofs & 7))) /* already filled */
2328 VectorAdd(light_sum, olm->bspLightBytes + ofs * 3, light_sum);
2330 VectorAdd(dir_sum, olm->bspDirBytes + ofs * 3, dir_sum);
2336 ofs = y * olm->customWidth + x;
2337 lightBitsNew[ofs >> 3] |= (1 << (ofs & 7));
2338 VectorScale(light_sum, 1.0/cnt, lightBytesNew + ofs * 3);
2340 VectorScale(dir_sum, 1.0/cnt, dirBytesNew + ofs * 3);
2348 memcpy(olm->lightBits, lightBitsNew, (olm->customWidth * olm->customHeight + 8) / 8);
2349 memcpy(olm->bspLightBytes, lightBytesNew, olm->customWidth * olm->customHeight * 3);
2351 memcpy(olm->bspDirBytes, dirBytesNew, olm->customWidth * olm->customHeight * 3);
2355 free(lightBytesNew);
2361 StoreSurfaceLightmaps()
2362 stores the surface lightmaps into the bsp as byte rgb triplets
2365 void StoreSurfaceLightmaps( void )
2367 int i, j, k, x, y, lx, ly, sx, sy, *cluster, mappedSamples;
2368 int style, size, lightmapNum, lightmapNum2;
2369 float *normal, *luxel, *bspLuxel, *bspLuxel2, *radLuxel, samples, occludedSamples;
2370 vec3_t sample, occludedSample, dirSample, colorMins, colorMaxs;
2371 float *deluxel, *bspDeluxel, *bspDeluxel2;
2373 int numUsed, numTwins, numTwinLuxels, numStored;
2374 float lmx, lmy, efficiency;
2376 bspDrawSurface_t *ds, *parent, dsTemp;
2377 surfaceInfo_t *info;
2378 rawLightmap_t *lm, *lm2;
2380 bspDrawVert_t *dv, *ydv, *dvParent;
2381 char dirname[ 1024 ], filename[ 1024 ];
2383 char lightmapName[ 128 ];
2384 const char *rgbGenValues[ 256 ];
2385 const char *alphaGenValues[ 256 ];
2389 Sys_Printf( "--- StoreSurfaceLightmaps ---\n");
2394 strcpy( dirname, lmCustomDir );
2398 strcpy( dirname, source );
2399 StripExtension( dirname );
2401 memset( rgbGenValues, 0, sizeof( rgbGenValues ) );
2402 memset( alphaGenValues, 0, sizeof( alphaGenValues ) );
2404 /* -----------------------------------------------------------------
2405 average the sampled luxels into the bsp luxels
2406 ----------------------------------------------------------------- */
2409 Sys_Printf( "Subsampling..." );
2411 /* walk the list of raw lightmaps */
2415 numSolidLightmaps = 0;
2416 for( i = 0; i < numRawLightmaps; i++ )
2419 lm = &rawLightmaps[ i ];
2421 /* walk individual lightmaps */
2422 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2425 if( lm->superLuxels[ lightmapNum ] == NULL )
2428 /* allocate bsp luxel storage */
2429 if( lm->bspLuxels[ lightmapNum ] == NULL )
2431 size = lm->w * lm->h * BSP_LUXEL_SIZE * sizeof( float );
2432 lm->bspLuxels[ lightmapNum ] = safe_malloc( size );
2433 memset( lm->bspLuxels[ lightmapNum ], 0, size );
2436 /* allocate radiosity lightmap storage */
2439 size = lm->w * lm->h * RAD_LUXEL_SIZE * sizeof( float );
2440 if( lm->radLuxels[ lightmapNum ] == NULL )
2441 lm->radLuxels[ lightmapNum ] = safe_malloc( size );
2442 memset( lm->radLuxels[ lightmapNum ], 0, size );
2445 /* average supersampled luxels */
2446 for( y = 0; y < lm->h; y++ )
2448 for( x = 0; x < lm->w; x++ )
2452 occludedSamples = 0.0f;
2454 VectorClear( sample );
2455 VectorClear( occludedSample );
2456 VectorClear( dirSample );
2457 for( ly = 0; ly < superSample; ly++ )
2459 for( lx = 0; lx < superSample; lx++ )
2462 sx = x * superSample + lx;
2463 sy = y * superSample + ly;
2464 luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2465 deluxel = SUPER_DELUXEL( sx, sy );
2466 normal = SUPER_NORMAL( sx, sy );
2467 cluster = SUPER_CLUSTER( sx, sy );
2469 /* sample deluxemap */
2470 if( deluxemap && lightmapNum == 0 )
2471 VectorAdd( dirSample, deluxel, dirSample );
2473 /* keep track of used/occluded samples */
2474 if( *cluster != CLUSTER_UNMAPPED )
2477 /* handle lightmap border? */
2478 if( lightmapBorder && (sx == 0 || sx == (lm->sw - 1) || sy == 0 || sy == (lm->sh - 1) ) && luxel[ 3 ] > 0.0f )
2480 VectorSet( sample, 255.0f, 0.0f, 0.0f );
2485 else if( debug && *cluster < 0 )
2487 if( *cluster == CLUSTER_UNMAPPED )
2488 VectorSet( luxel, 255, 204, 0 );
2489 else if( *cluster == CLUSTER_OCCLUDED )
2490 VectorSet( luxel, 255, 0, 255 );
2491 else if( *cluster == CLUSTER_FLOODED )
2492 VectorSet( luxel, 0, 32, 255 );
2493 VectorAdd( occludedSample, luxel, occludedSample );
2494 occludedSamples += 1.0f;
2497 /* normal luxel handling */
2498 else if( luxel[ 3 ] > 0.0f )
2500 /* handle lit or flooded luxels */
2501 if( *cluster > 0 || *cluster == CLUSTER_FLOODED )
2503 VectorAdd( sample, luxel, sample );
2504 samples += luxel[ 3 ];
2507 /* handle occluded or unmapped luxels */
2510 VectorAdd( occludedSample, luxel, occludedSample );
2511 occludedSamples += luxel[ 3 ];
2514 /* handle style debugging */
2515 if( debug && lightmapNum > 0 && x < 2 && y < 2 )
2517 VectorCopy( debugColors[ 0 ], sample );
2524 /* only use occluded samples if necessary */
2525 if( samples <= 0.0f )
2527 VectorCopy( occludedSample, sample );
2528 samples = occludedSamples;
2532 luxel = SUPER_LUXEL( lightmapNum, x, y );
2533 deluxel = SUPER_DELUXEL( x, y );
2535 /* store light direction */
2536 if( deluxemap && lightmapNum == 0 )
2537 VectorCopy( dirSample, deluxel );
2539 /* store the sample back in super luxels */
2540 if( samples > 0.01f )
2542 VectorScale( sample, (1.0f / samples), luxel );
2546 /* if any samples were mapped in any way, store ambient color */
2547 else if( mappedSamples > 0 )
2549 if( lightmapNum == 0 )
2550 VectorCopy( ambientColor, luxel );
2552 VectorClear( luxel );
2556 /* store a bogus value to be fixed later */
2559 VectorClear( luxel );
2567 ClearBounds( colorMins, colorMaxs );
2569 /* clean up and store into bsp luxels */
2570 for( y = 0; y < lm->h; y++ )
2572 for( x = 0; x < lm->w; x++ )
2575 luxel = SUPER_LUXEL( lightmapNum, x, y );
2576 deluxel = SUPER_DELUXEL( x, y );
2578 /* copy light direction */
2579 if( deluxemap && lightmapNum == 0 )
2580 VectorCopy( deluxel, dirSample );
2582 /* is this a valid sample? */
2583 if( luxel[ 3 ] > 0.0f )
2585 VectorCopy( luxel, sample );
2586 samples = luxel[ 3 ];
2590 /* fix negative samples */
2591 for( j = 0; j < 3; j++ )
2593 if( sample[ j ] < 0.0f )
2599 /* nick an average value from the neighbors */
2600 VectorClear( sample );
2601 VectorClear( dirSample );
2604 /* fixme: why is this disabled?? */
2605 for( sy = (y - 1); sy <= (y + 1); sy++ )
2607 if( sy < 0 || sy >= lm->h )
2610 for( sx = (x - 1); sx <= (x + 1); sx++ )
2612 if( sx < 0 || sx >= lm->w || (sx == x && sy == y) )
2615 /* get neighbor's particulars */
2616 luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2617 if( luxel[ 3 ] < 0.0f )
2619 VectorAdd( sample, luxel, sample );
2620 samples += luxel[ 3 ];
2625 if( samples == 0.0f )
2627 VectorSet( sample, -1.0f, -1.0f, -1.0f );
2635 /* fix negative samples */
2636 for( j = 0; j < 3; j++ )
2638 if( sample[ j ] < 0.0f )
2644 /* scale the sample */
2645 VectorScale( sample, (1.0f / samples), sample );
2647 /* store the sample in the radiosity luxels */
2650 radLuxel = RAD_LUXEL( lightmapNum, x, y );
2651 VectorCopy( sample, radLuxel );
2653 /* if only storing bounced light, early out here */
2654 if( bounceOnly && !bouncing )
2658 /* store the sample in the bsp luxels */
2659 bspLuxel = BSP_LUXEL( lightmapNum, x, y );
2660 bspDeluxel = BSP_DELUXEL( x, y );
2662 VectorAdd( bspLuxel, sample, bspLuxel );
2663 if( deluxemap && lightmapNum == 0 )
2664 VectorAdd( bspDeluxel, dirSample, bspDeluxel );
2666 /* add color to bounds for solid checking */
2667 if( samples > 0.0f )
2668 AddPointToBounds( bspLuxel, colorMins, colorMaxs );
2672 /* set solid color */
2673 lm->solid[ lightmapNum ] = qfalse;
2674 VectorAdd( colorMins, colorMaxs, lm->solidColor[ lightmapNum ] );
2675 VectorScale( lm->solidColor[ lightmapNum ], 0.5f, lm->solidColor[ lightmapNum ] );
2677 /* nocollapse prevents solid lightmaps */
2678 if( noCollapse == qfalse )
2680 /* check solid color */
2681 VectorSubtract( colorMaxs, colorMins, sample );
2682 if( (sample[ 0 ] <= SOLID_EPSILON && sample[ 1 ] <= SOLID_EPSILON && sample[ 2 ] <= SOLID_EPSILON) ||
2683 (lm->w <= 2 && lm->h <= 2) ) /* small lightmaps get forced to solid color */
2686 VectorCopy( colorMins, lm->solidColor[ lightmapNum ] );
2687 lm->solid[ lightmapNum ] = qtrue;
2688 numSolidLightmaps++;
2691 /* if all lightmaps aren't solid, then none of them are solid */
2692 if( lm->solid[ lightmapNum ] != lm->solid[ 0 ] )
2694 for( y = 0; y < MAX_LIGHTMAPS; y++ )
2696 if( lm->solid[ y ] )
2697 numSolidLightmaps--;
2698 lm->solid[ y ] = qfalse;
2703 /* wrap bsp luxels if necessary */
2706 for( y = 0; y < lm->h; y++ )
2708 bspLuxel = BSP_LUXEL( lightmapNum, 0, y );
2709 bspLuxel2 = BSP_LUXEL( lightmapNum, lm->w - 1, y );
2710 VectorAdd( bspLuxel, bspLuxel2, bspLuxel );
2711 VectorScale( bspLuxel, 0.5f, bspLuxel );
2712 VectorCopy( bspLuxel, bspLuxel2 );
2713 if( deluxemap && lightmapNum == 0 )
2715 bspDeluxel = BSP_DELUXEL( 0, y );
2716 bspDeluxel2 = BSP_DELUXEL( lm->w - 1, y );
2717 VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel );
2718 VectorScale( bspDeluxel, 0.5f, bspDeluxel );
2719 VectorCopy( bspDeluxel, bspDeluxel2 );
2725 for( x = 0; x < lm->w; x++ )
2727 bspLuxel = BSP_LUXEL( lightmapNum, x, 0 );
2728 bspLuxel2 = BSP_LUXEL( lightmapNum, x, lm->h - 1 );
2729 VectorAdd( bspLuxel, bspLuxel2, bspLuxel );
2730 VectorScale( bspLuxel, 0.5f, bspLuxel );
2731 VectorCopy( bspLuxel, bspLuxel2 );
2732 if( deluxemap && lightmapNum == 0 )
2734 bspDeluxel = BSP_DELUXEL( x, 0 );
2735 bspDeluxel2 = BSP_DELUXEL( x, lm->h - 1 );
2736 VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel );
2737 VectorScale( bspDeluxel, 0.5f, bspDeluxel );
2738 VectorCopy( bspDeluxel, bspDeluxel2 );
2745 /* -----------------------------------------------------------------
2746 convert modelspace deluxemaps to tangentspace
2747 ----------------------------------------------------------------- */
2751 if( deluxemap && deluxemode == 1)
2753 vec3_t worldUp, myNormal, myTangent, myBinormal;
2756 Sys_Printf( "converting..." );
2758 for( i = 0; i < numRawLightmaps; i++ )
2761 lm = &rawLightmaps[ i ];
2763 /* walk lightmap samples */
2764 for( y = 0; y < lm->sh; y++ )
2766 for( x = 0; x < lm->sw; x++ )
2768 /* get normal and deluxel */
2769 normal = SUPER_NORMAL(x, y);
2770 cluster = SUPER_CLUSTER(x, y);
2771 bspDeluxel = BSP_DELUXEL( x, y );
2772 deluxel = SUPER_DELUXEL( x, y );
2775 VectorSet( myNormal, normal[0], normal[1], normal[2] );
2777 /* get tangent vectors */
2778 if( myNormal[ 0 ] == 0.0f && myNormal[ 1 ] == 0.0f )
2780 if( myNormal[ 2 ] == 1.0f )
2782 VectorSet( myTangent, 1.0f, 0.0f, 0.0f );
2783 VectorSet( myBinormal, 0.0f, 1.0f, 0.0f );
2785 else if( myNormal[ 2 ] == -1.0f )
2787 VectorSet( myTangent, -1.0f, 0.0f, 0.0f );
2788 VectorSet( myBinormal, 0.0f, 1.0f, 0.0f );
2793 VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
2794 CrossProduct( myNormal, worldUp, myTangent );
2795 VectorNormalize( myTangent, myTangent );
2796 CrossProduct( myTangent, myNormal, myBinormal );
2797 VectorNormalize( myBinormal, myBinormal );
2800 /* project onto plane */
2801 dist = -DotProduct(myTangent, myNormal);
2802 VectorMA(myTangent, dist, myNormal, myTangent);
2803 dist = -DotProduct(myBinormal, myNormal);
2804 VectorMA(myBinormal, dist, myNormal, myBinormal);
2807 VectorNormalize( myTangent, myTangent );
2808 VectorNormalize( myBinormal, myBinormal );
2810 /* convert modelspace deluxel to tangentspace */
2811 dirSample[0] = bspDeluxel[0];
2812 dirSample[1] = bspDeluxel[1];
2813 dirSample[2] = bspDeluxel[2];
2814 VectorNormalize(dirSample, dirSample);
2816 /* fix tangents to world matrix */
2817 if (myNormal[0] > 0 || myNormal[1] < 0 || myNormal[2] < 0)
2818 VectorNegate(myTangent, myTangent);
2820 /* build tangentspace vectors */
2821 bspDeluxel[0] = DotProduct(dirSample, myTangent);
2822 bspDeluxel[1] = DotProduct(dirSample, myBinormal);
2823 bspDeluxel[2] = DotProduct(dirSample, myNormal);
2830 /* -----------------------------------------------------------------
2832 ----------------------------------------------------------------- */
2834 #ifdef sdfsdfwq312323
2836 Sys_Printf( "blending..." );
2838 for( i = 0; i < numRawLightmaps; i++ )
2844 lm = &rawLightmaps[ i ];
2846 /* walk individual lightmaps */
2847 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2850 if( lm->superLuxels[ lightmapNum ] == NULL )
2853 /* walk lightmap samples */
2854 for( y = 0; y < lm->sh; y++ )
2856 for( x = 0; x < lm->sw; x++ )
2859 bspLuxel = BSP_LUXEL( lightmapNum, x, y );
2862 VectorNormalize(bspLuxel, myColor);
2863 myBrightness = VectorLength(bspLuxel);
2864 myBrightness *= (1 / 127.0f);
2865 myBrightness = myBrightness*myBrightness;
2866 myBrightness *= 127.0f;
2867 VectorScale(myColor, myBrightness, bspLuxel);
2874 /* -----------------------------------------------------------------
2875 collapse non-unique lightmaps
2876 ----------------------------------------------------------------- */
2878 if( noCollapse == qfalse && deluxemap == qfalse )
2881 Sys_Printf( "collapsing..." );
2883 /* set all twin refs to null */
2884 for( i = 0; i < numRawLightmaps; i++ )
2886 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2888 rawLightmaps[ i ].twins[ lightmapNum ] = NULL;
2889 rawLightmaps[ i ].twinNums[ lightmapNum ] = -1;
2890 rawLightmaps[ i ].numStyledTwins = 0;
2894 /* walk the list of raw lightmaps */
2895 for( i = 0; i < numRawLightmaps; i++ )
2898 lm = &rawLightmaps[ i ];
2900 /* walk lightmaps */
2901 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2904 if( lm->bspLuxels[ lightmapNum ] == NULL ||
2905 lm->twins[ lightmapNum ] != NULL )
2908 /* find all lightmaps that are virtually identical to this one */
2909 for( j = i + 1; j < numRawLightmaps; j++ )
2912 lm2 = &rawLightmaps[ j ];
2914 /* walk lightmaps */
2915 for( lightmapNum2 = 0; lightmapNum2 < MAX_LIGHTMAPS; lightmapNum2++ )
2918 if( lm2->bspLuxels[ lightmapNum2 ] == NULL ||
2919 lm2->twins[ lightmapNum2 ] != NULL )
2923 if( CompareBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ) )
2925 /* merge and set twin */
2926 if( MergeBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ) )
2928 lm2->twins[ lightmapNum2 ] = lm;
2929 lm2->twinNums[ lightmapNum2 ] = lightmapNum;
2931 numTwinLuxels += (lm->w * lm->h);
2933 /* count styled twins */
2934 if( lightmapNum > 0 )
2935 lm->numStyledTwins++;
2944 /* -----------------------------------------------------------------
2945 sort raw lightmaps by shader
2946 ----------------------------------------------------------------- */
2949 Sys_Printf( "sorting..." );
2951 /* allocate a new sorted list */
2952 if( sortLightmaps == NULL )
2953 sortLightmaps = safe_malloc( numRawLightmaps * sizeof( int ) );
2955 /* fill it out and sort it */
2956 for( i = 0; i < numRawLightmaps; i++ )
2957 sortLightmaps[ i ] = i;
2958 qsort( sortLightmaps, numRawLightmaps, sizeof( int ), CompareRawLightmap );
2960 /* -----------------------------------------------------------------
2961 allocate output lightmaps
2962 ----------------------------------------------------------------- */
2965 Sys_Printf( "allocating..." );
2967 /* kill all existing output lightmaps */
2968 if( outLightmaps != NULL )
2970 for( i = 0; i < numOutLightmaps; i++ )
2972 free( outLightmaps[ i ].lightBits );
2973 free( outLightmaps[ i ].bspLightBytes );
2975 free( outLightmaps );
2976 outLightmaps = NULL;
2979 numLightmapShaders = 0;
2980 numOutLightmaps = 0;
2981 numBSPLightmaps = 0;
2982 numExtLightmaps = 0;
2984 /* find output lightmap */
2985 for( i = 0; i < numRawLightmaps; i++ )
2987 lm = &rawLightmaps[ sortLightmaps[ i ] ];
2988 FindOutLightmaps( lm );
2991 /* set output numbers in twinned lightmaps */
2992 for( i = 0; i < numRawLightmaps; i++ )
2995 lm = &rawLightmaps[ sortLightmaps[ i ] ];
2997 /* walk lightmaps */
2998 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3001 lm2 = lm->twins[ lightmapNum ];
3004 lightmapNum2 = lm->twinNums[ lightmapNum ];
3006 /* find output lightmap from twin */
3007 lm->outLightmapNums[ lightmapNum ] = lm2->outLightmapNums[ lightmapNum2 ];
3008 lm->lightmapX[ lightmapNum ] = lm2->lightmapX[ lightmapNum2 ];
3009 lm->lightmapY[ lightmapNum ] = lm2->lightmapY[ lightmapNum2 ];
3013 /* -----------------------------------------------------------------
3014 store output lightmaps
3015 ----------------------------------------------------------------- */
3018 Sys_Printf( "storing..." );
3020 /* count the bsp lightmaps and allocate space */
3021 if( bspLightBytes != NULL )
3022 free( bspLightBytes );
3023 if( numBSPLightmaps == 0 || externalLightmaps )
3025 numBSPLightBytes = 0;
3026 bspLightBytes = NULL;
3030 numBSPLightBytes = (numBSPLightmaps * game->lightmapSize * game->lightmapSize * 3);
3031 bspLightBytes = safe_malloc( numBSPLightBytes );
3032 memset( bspLightBytes, 0, numBSPLightBytes );
3035 /* walk the list of output lightmaps */
3036 for( i = 0; i < numOutLightmaps; i++ )
3038 /* get output lightmap */
3039 olm = &outLightmaps[ i ];
3041 /* fill output lightmap */
3043 FillOutLightmap(olm);
3045 /* is this a valid bsp lightmap? */
3046 if( olm->lightmapNum >= 0 && !externalLightmaps )
3048 /* copy lighting data */
3049 lb = bspLightBytes + (olm->lightmapNum * game->lightmapSize * game->lightmapSize * 3);
3050 memcpy( lb, olm->bspLightBytes, game->lightmapSize * game->lightmapSize * 3 );
3052 /* copy direction data */
3055 lb = bspLightBytes + ((olm->lightmapNum + 1) * game->lightmapSize * game->lightmapSize * 3);
3056 memcpy( lb, olm->bspDirBytes, game->lightmapSize * game->lightmapSize * 3 );
3060 /* external lightmap? */
3061 if( olm->lightmapNum < 0 || olm->extLightmapNum >= 0 || externalLightmaps )
3063 /* make a directory for the lightmaps */
3066 /* set external lightmap number */
3067 olm->extLightmapNum = numExtLightmaps;
3069 /* write lightmap */
3070 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
3071 Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
3072 WriteTGA24( filename, olm->bspLightBytes, olm->customWidth, olm->customHeight, qtrue );
3075 /* write deluxemap */
3078 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
3079 Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
3080 WriteTGA24( filename, olm->bspDirBytes, olm->customWidth, olm->customHeight, qtrue );
3083 if( debugDeluxemap )
3084 olm->extLightmapNum++;
3089 if( numExtLightmaps > 0 )
3092 /* delete unused external lightmaps */
3093 for( i = numExtLightmaps; i; i++ )
3095 /* determine if file exists */
3096 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, i );
3097 if( !FileExists( filename ) )
3104 /* -----------------------------------------------------------------
3105 project the lightmaps onto the bsp surfaces
3106 ----------------------------------------------------------------- */
3109 Sys_Printf( "projecting..." );
3111 /* walk the list of surfaces */
3112 for( i = 0; i < numBSPDrawSurfaces; i++ )
3114 /* get the surface and info */
3115 ds = &bspDrawSurfaces[ i ];
3116 info = &surfaceInfos[ i ];
3120 /* handle surfaces with identical parent */
3121 if( info->parentSurfaceNum >= 0 )
3123 /* preserve original data and get parent */
3124 parent = &bspDrawSurfaces[ info->parentSurfaceNum ];
3125 memcpy( &dsTemp, ds, sizeof( *ds ) );
3127 /* overwrite child with parent data */
3128 memcpy( ds, parent, sizeof( *ds ) );
3130 /* restore key parts */
3131 ds->fogNum = dsTemp.fogNum;
3132 ds->firstVert = dsTemp.firstVert;
3133 ds->firstIndex = dsTemp.firstIndex;
3134 memcpy( ds->lightmapVecs, dsTemp.lightmapVecs, sizeof( dsTemp.lightmapVecs ) );
3136 /* set vertex data */
3137 dv = &bspDrawVerts[ ds->firstVert ];
3138 dvParent = &bspDrawVerts[ parent->firstVert ];
3139 for( j = 0; j < ds->numVerts; j++ )
3141 memcpy( dv[ j ].lightmap, dvParent[ j ].lightmap, sizeof( dv[ j ].lightmap ) );
3142 memcpy( dv[ j ].color, dvParent[ j ].color, sizeof( dv[ j ].color ) );
3149 /* handle vertex lit or approximated surfaces */
3150 else if( lm == NULL || lm->outLightmapNums[ 0 ] < 0 )
3152 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3154 ds->lightmapNum[ lightmapNum ] = -3;
3155 ds->lightmapStyles[ lightmapNum ] = ds->vertexStyles[ lightmapNum ];
3159 /* handle lightmapped surfaces */
3162 /* walk lightmaps */
3163 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3166 ds->lightmapStyles[ lightmapNum ] = lm->styles[ lightmapNum ];
3168 /* handle unused style */
3169 if( lm->styles[ lightmapNum ] == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 )
3171 ds->lightmapNum[ lightmapNum ] = -3;
3175 /* get output lightmap */
3176 olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
3178 /* set bsp lightmap number */
3179 ds->lightmapNum[ lightmapNum ] = olm->lightmapNum;
3181 /* deluxemap debugging makes the deluxemap visible */
3182 if( deluxemap && debugDeluxemap && lightmapNum == 0 )
3183 ds->lightmapNum[ lightmapNum ]++;
3185 /* calc lightmap origin in texture space */
3186 lmx = (float) lm->lightmapX[ lightmapNum ] / (float) olm->customWidth;
3187 lmy = (float) lm->lightmapY[ lightmapNum ] / (float) olm->customHeight;
3189 /* calc lightmap st coords */
3190 dv = &bspDrawVerts[ ds->firstVert ];
3191 ydv = &yDrawVerts[ ds->firstVert ];
3192 for( j = 0; j < ds->numVerts; j++ )
3194 if( lm->solid[ lightmapNum ] )
3196 dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + (0.5f / (float) olm->customWidth);
3197 dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + (0.5f / (float) olm->customWidth);
3201 dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + (ydv[ j ].lightmap[ 0 ][ 0 ] / (superSample * olm->customWidth));
3202 dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + (ydv[ j ].lightmap[ 0 ][ 1 ] / (superSample * olm->customHeight));
3208 /* store vertex colors */
3209 dv = &bspDrawVerts[ ds->firstVert ];
3210 for( j = 0; j < ds->numVerts; j++ )
3212 /* walk lightmaps */
3213 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3215 /* handle unused style */
3216 if( ds->vertexStyles[ lightmapNum ] == LS_NONE )
3217 VectorClear( color );
3220 /* get vertex color */
3221 luxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + j );
3222 VectorCopy( luxel, color );
3224 /* set minimum light */
3225 if( lightmapNum == 0 )
3227 for( k = 0; k < 3; k++ )
3228 if( color[ k ] < minVertexLight[ k ] )
3229 color[ k ] = minVertexLight[ k ];
3233 /* store to bytes */
3234 if( !info->si->noVertexLight )
3235 ColorToBytes( color, dv[ j ].color[ lightmapNum ], info->si->vertexScale );
3239 /* surfaces with styled lightmaps and a style marker get a custom generated shader (fixme: make this work with external lightmaps) */
3240 if( olm != NULL && lm != NULL && lm->styles[ 1 ] != LS_NONE && game->load != LoadRBSPFile ) //% info->si->styleMarker > 0 )
3243 char key[ 32 ], styleStage[ 512 ], styleStages[ 4096 ], rgbGen[ 128 ], alphaGen[ 128 ];
3247 sprintf( styleStages, "\n\t// Q3Map2 custom lightstyle stage(s)\n" );
3248 dv = &bspDrawVerts[ ds->firstVert ];
3250 /* depthFunc equal? */
3251 if( info->si->styleMarker == 2 || info->si->implicitMap == IM_MASKED )
3256 /* generate stages for styled lightmaps */
3257 for( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3260 style = lm->styles[ lightmapNum ];
3261 if( style == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 )
3264 /* get output lightmap */
3265 olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
3268 if( lm->outLightmapNums[ lightmapNum ] == lm->outLightmapNums[ 0 ] )
3269 strcpy( lightmapName, "$lightmap" );
3271 sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
3273 /* get rgbgen string */
3274 if( rgbGenValues[ style ] == NULL )
3276 sprintf( key, "_style%drgbgen", style );
3277 rgbGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
3278 if( rgbGenValues[ style ][ 0 ] == '\0' )
3279 rgbGenValues[ style ] = "wave noise 0.5 1 0 5.37";
3282 if( rgbGenValues[ style ][ 0 ] != '\0' )
3283 sprintf( rgbGen, "\t\trgbGen %s // style %d\n", rgbGenValues[ style ], style );
3287 /* get alphagen string */
3288 if( alphaGenValues[ style ] == NULL )
3290 sprintf( key, "_style%dalphagen", style );
3291 alphaGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
3293 if( alphaGenValues[ style ][ 0 ] != '\0' )
3294 sprintf( alphaGen, "\t\talphaGen %s // style %d\n", alphaGenValues[ style ], style );
3296 alphaGen[ 0 ] = '\0';
3298 /* calculate st offset */
3299 lmx = dv[ 0 ].lightmap[ lightmapNum ][ 0 ] - dv[ 0 ].lightmap[ 0 ][ 0 ];
3300 lmy = dv[ 0 ].lightmap[ lightmapNum ][ 1 ] - dv[ 0 ].lightmap[ 0 ][ 1 ];
3302 /* create additional stage */
3303 if( lmx == 0.0f && lmy == 0.0f )
3305 sprintf( styleStage, "\t{\n"
3306 "\t\tmap %s\n" /* lightmap */
3307 "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
3308 "%s" /* depthFunc equal */
3311 "\t\ttcGen lightmap\n"
3314 (dfEqual ? "\t\tdepthFunc equal\n" : ""),
3320 sprintf( styleStage, "\t{\n"
3321 "\t\tmap %s\n" /* lightmap */
3322 "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
3323 "%s" /* depthFunc equal */
3326 "\t\ttcGen lightmap\n"
3327 "\t\ttcMod transform 1 0 0 1 %1.5f %1.5f\n" /* st offset */
3330 (dfEqual ? "\t\tdepthFunc equal\n" : ""),
3338 strcat( styleStages, styleStage );
3341 /* create custom shader */
3342 if( info->si->styleMarker == 2 )
3343 csi = CustomShader( info->si, "q3map_styleMarker2", styleStages );
3345 csi = CustomShader( info->si, "q3map_styleMarker", styleStages );
3347 /* emit remap command */
3348 //% EmitVertexRemapShader( csi->shader, info->si->shader );
3351 //% Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
3352 ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3353 //% Sys_Printf( ")\n" );
3356 /* devise a custom shader for this surface (fixme: make this work with light styles) */
3357 else if( olm != NULL && lm != NULL && !externalLightmaps &&
3358 (olm->customWidth != game->lightmapSize || olm->customHeight != game->lightmapSize) )
3360 /* get output lightmap */
3361 olm = &outLightmaps[ lm->outLightmapNums[ 0 ] ];
3363 /* do some name mangling */
3364 sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
3366 /* create custom shader */
3367 csi = CustomShader( info->si, "$lightmap", lightmapName );
3370 //% Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
3371 ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3372 //% Sys_Printf( ")\n" );
3375 /* use the normal plain-jane shader */
3377 ds->shaderNum = EmitShader( info->si->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3381 Sys_Printf( "done.\n" );
3383 /* calc num stored */
3384 numStored = numBSPLightBytes / 3;
3385 efficiency = (numStored <= 0)
3387 : (float) numUsed / (float) numStored;
3390 Sys_Printf( "%9d luxels used\n", numUsed );
3391 Sys_Printf( "%9d luxels stored (%3.2f percent efficiency)\n", numStored, efficiency * 100.0f );
3392 Sys_Printf( "%9d solid surface lightmaps\n", numSolidLightmaps );
3393 Sys_Printf( "%9d identical surface lightmaps, using %d luxels\n", numTwins, numTwinLuxels );
3394 Sys_Printf( "%9d vertex forced surfaces\n", numSurfsVertexForced );
3395 Sys_Printf( "%9d vertex approximated surfaces\n", numSurfsVertexApproximated );
3396 Sys_Printf( "%9d BSP lightmaps\n", numBSPLightmaps );
3397 Sys_Printf( "%9d total lightmaps\n", numOutLightmaps );
3398 Sys_Printf( "%9d unique lightmap/shader combinations\n", numLightmapShaders );
3400 /* write map shader file */
3401 WriteMapShaderFile();