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;
596 surfaceInfo_t *info, *info2;
597 int num2, n, i, axisNum;
598 float s, t, d, len, sampleSize;
599 vec3_t mins, maxs, origin, faxis, size, exactSize, 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 exactSize[ i ] = lm->maxs[ i ] - lm->mins[ i ];
676 mins[ i ] = sampleSize * floor( lm->mins[ i ] / sampleSize );
677 maxs[ i ] = sampleSize * ceil( lm->maxs[ i ] / sampleSize );
678 size[ i ] = (maxs[ i ] - mins[ i ]) / sampleSize + 1.0f;
680 /* hack (god this sucks) */
681 if( size[ i ] > lm->customWidth || size[ i ] > lm->customHeight || (lmLimitSize && size[i] > lmLimitSize))
688 if(sampleSize != lm->sampleSize && lmLimitSize == 0)
690 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",
701 /* set actual sample size */
702 lm->actualSampleSize = sampleSize;
704 /* fixme: copy rounded mins/maxes to lightmap record? */
705 if( lm->plane == NULL )
707 VectorCopy( mins, lm->mins );
708 VectorCopy( maxs, lm->maxs );
709 VectorCopy( mins, origin );
712 /* set lightmap origin */
713 VectorCopy( lm->mins, origin );
715 /* make absolute axis */
716 faxis[ 0 ] = fabs( lm->axis[ 0 ] );
717 faxis[ 1 ] = fabs( lm->axis[ 1 ] );
718 faxis[ 2 ] = fabs( lm->axis[ 2 ] );
720 /* clear out lightmap vectors */
721 memset( vecs, 0, sizeof( vecs ) );
723 /* classify the plane (x y or z major) (ydnar: biased to z axis projection) */
724 if( faxis[ 2 ] >= faxis[ 0 ] && faxis[ 2 ] >= faxis[ 1 ] )
729 vecs[ 0 ][ 0 ] = 1.0f / sampleSize;
730 vecs[ 1 ][ 1 ] = 1.0f / sampleSize;
732 else if( faxis[ 0 ] >= faxis[ 1 ] && faxis[ 0 ] >= faxis[ 2 ] )
737 vecs[ 0 ][ 1 ] = 1.0f / sampleSize;
738 vecs[ 1 ][ 2 ] = 1.0f / sampleSize;
745 vecs[ 0 ][ 0 ] = 1.0f / sampleSize;
746 vecs[ 1 ][ 2 ] = 1.0f / sampleSize;
749 /* check for bogus axis */
750 if( faxis[ axisNum ] == 0.0f )
752 Sys_Printf( "WARNING: ProjectSurfaceLightmap: Chose a 0 valued axis\n" );
757 /* store the axis number in the lightmap */
758 lm->axisNum = axisNum;
760 /* walk the list of surfaces on this raw lightmap */
761 for( n = 0; n < lm->numLightSurfaces; n++ )
764 num2 = lightSurfaces[ lm->firstLightSurface + n ];
765 ds2 = &bspDrawSurfaces[ num2 ];
766 info2 = &surfaceInfos[ num2 ];
767 verts = &yDrawVerts[ ds2->firstVert ];
769 /* set the lightmap texture coordinates in yDrawVerts in [0, superSample * lm->customWidth] space */
770 for( i = 0; i < ds2->numVerts; i++ )
772 VectorSubtract( verts[ i ].xyz, origin, delta );
773 s = DotProduct( delta, vecs[ 0 ] ) + 0.5f;
774 t = DotProduct( delta, vecs[ 1 ] ) + 0.5f;
775 verts[ i ].lightmap[ 0 ][ 0 ] = s * superSample;
776 verts[ i ].lightmap[ 0 ][ 1 ] = t * superSample;
778 if( s > (float) lm->w || t > (float) lm->h )
780 Sys_FPrintf( SYS_VRB, "WARNING: Lightmap texture coords out of range: S %1.4f > %3d || T %1.4f > %3d\n",
781 s, lm->w, t, lm->h );
786 /* get first drawsurface */
787 num2 = lightSurfaces[ lm->firstLightSurface ];
788 ds2 = &bspDrawSurfaces[ num2 ];
789 info2 = &surfaceInfos[ num2 ];
790 verts = &yDrawVerts[ ds2->firstVert ];
792 /* calculate lightmap origin */
793 if( VectorLength( ds2->lightmapVecs[ 2 ] ) )
794 VectorCopy( ds2->lightmapVecs[ 2 ], plane );
796 VectorCopy( lm->axis, plane );
797 plane[ 3 ] = DotProduct( verts[ 0 ].xyz, plane );
799 VectorCopy( origin, lm->origin );
800 d = DotProduct( lm->origin, plane ) - plane[ 3 ];
801 d /= plane[ axisNum ];
802 lm->origin[ axisNum ] -= d;
805 VectorCopy( lm->origin, ds->lightmapOrigin );
807 /* for planar surfaces, create lightmap vectors for st->xyz conversion */
808 if( VectorLength( ds->lightmapVecs[ 2 ] ) || 1 ) /* ydnar: can't remember what exactly i was thinking here... */
810 /* allocate space for the vectors */
811 lm->vecs = safe_malloc( 3 * sizeof( vec3_t ) );
812 memset( lm->vecs, 0, 3 * sizeof( vec3_t ) );
813 VectorCopy( ds->lightmapVecs[ 2 ], lm->vecs[ 2 ] );
815 /* project stepped lightmap blocks and subtract to get planevecs */
816 for( i = 0; i < 2; i++ )
818 len = VectorNormalize( vecs[ i ], normalized );
819 VectorScale( normalized, (1.0 / len), lm->vecs[ i ] );
820 d = DotProduct( lm->vecs[ i ], plane );
821 d /= plane[ axisNum ];
822 lm->vecs[ i ][ axisNum ] -= d;
827 /* lightmap vectors are useless on a non-planar surface */
832 if( ds->surfaceType == MST_PATCH )
834 numPatchesLightmapped++;
835 if( lm->plane != NULL )
836 numPlanarPatchesLightmapped++;
840 if( lm->plane != NULL )
841 numPlanarsLightmapped++;
843 numNonPlanarsLightmapped++;
854 compare function for qsort()
857 static int CompareSurfaceInfo( const void *a, const void *b )
859 surfaceInfo_t *aInfo, *bInfo;
863 /* get surface info */
864 aInfo = &surfaceInfos[ *((const int*) a) ];
865 bInfo = &surfaceInfos[ *((const int*) b) ];
868 if( aInfo->modelindex < bInfo->modelindex )
870 else if( aInfo->modelindex > bInfo->modelindex )
873 /* then lightmap status */
874 if( aInfo->hasLightmap < bInfo->hasLightmap )
876 else if( aInfo->hasLightmap > bInfo->hasLightmap )
879 /* 27: then shader! */
880 if (aInfo->si < bInfo->si)
882 else if (aInfo->si > bInfo->si)
886 /* then lightmap sample size */
887 if( aInfo->sampleSize < bInfo->sampleSize )
889 else if( aInfo->sampleSize > bInfo->sampleSize )
892 /* then lightmap axis */
893 for( i = 0; i < 3; i++ )
895 if( aInfo->axis[ i ] < bInfo->axis[ i ] )
897 else if( aInfo->axis[ i ] > bInfo->axis[ i ] )
902 if( aInfo->plane == NULL && bInfo->plane != NULL )
904 else if( aInfo->plane != NULL && bInfo->plane == NULL )
906 else if( aInfo->plane != NULL && bInfo->plane != NULL )
908 for( i = 0; i < 4; i++ )
910 if( aInfo->plane[ i ] < bInfo->plane[ i ] )
912 else if( aInfo->plane[ i ] > bInfo->plane[ i ] )
917 /* then position in world */
918 for( i = 0; i < 3; i++ )
920 if( aInfo->mins[ i ] < bInfo->mins[ i ] )
922 else if( aInfo->mins[ i ] > bInfo->mins[ i ] )
926 /* these are functionally identical (this should almost never happen) */
933 SetupSurfaceLightmaps()
934 allocates lightmaps for every surface in the bsp that needs one
935 this depends on yDrawVerts being allocated
938 void SetupSurfaceLightmaps( void )
940 int i, j, k, s,num, num2;
943 bspDrawSurface_t *ds, *ds2;
944 surfaceInfo_t *info, *info2;
947 vec3_t mapSize, entityOrigin;
951 Sys_FPrintf( SYS_VRB, "--- SetupSurfaceLightmaps ---\n");
953 /* determine supersample amount */
954 if( superSample < 1 )
956 else if( superSample > 8 )
958 Sys_Printf( "WARNING: Insane supersampling amount (%d) detected.\n", superSample );
962 /* clear map bounds */
963 ClearBounds( mapMins, mapMaxs );
965 /* allocate a list of surface clusters */
966 numSurfaceClusters = 0;
967 maxSurfaceClusters = numBSPLeafSurfaces;
968 surfaceClusters = safe_malloc( maxSurfaceClusters * sizeof( *surfaceClusters ) );
969 memset( surfaceClusters, 0, maxSurfaceClusters * sizeof( *surfaceClusters ) );
971 /* allocate a list for per-surface info */
972 surfaceInfos = safe_malloc( numBSPDrawSurfaces * sizeof( *surfaceInfos ) );
973 memset( surfaceInfos, 0, numBSPDrawSurfaces * sizeof( *surfaceInfos ) );
974 for( i = 0; i < numBSPDrawSurfaces; i++ )
975 surfaceInfos[ i ].childSurfaceNum = -1;
977 /* allocate a list of surface indexes to be sorted */
978 sortSurfaces = safe_malloc( numBSPDrawSurfaces * sizeof( int ) );
979 memset( sortSurfaces, 0, numBSPDrawSurfaces * sizeof( int ) );
981 /* walk each model in the bsp */
982 for( i = 0; i < numBSPModels; i++ )
985 model = &bspModels[ i ];
987 /* walk the list of surfaces in this model and fill out the info structs */
988 for( j = 0; j < model->numBSPSurfaces; j++ )
990 /* make surface index */
991 num = model->firstBSPSurface + j;
993 /* copy index to sort list */
994 sortSurfaces[ num ] = num;
996 /* get surface and info */
997 ds = &bspDrawSurfaces[ num ];
998 info = &surfaceInfos[ num ];
1000 /* set entity origin */
1001 if( ds->numVerts > 0 )
1002 VectorSubtract( yDrawVerts[ ds->firstVert ].xyz, bspDrawVerts[ ds->firstVert ].xyz, entityOrigin );
1004 VectorClear( entityOrigin );
1007 info->modelindex = i;
1010 info->firstSurfaceCluster = numSurfaceClusters;
1012 /* get extra data */
1013 info->si = GetSurfaceExtraShaderInfo( num );
1014 if( info->si == NULL )
1015 info->si = ShaderInfoForShader( bspShaders[ ds->shaderNum ].shader );
1016 info->parentSurfaceNum = GetSurfaceExtraParentSurfaceNum( num );
1017 info->entityNum = GetSurfaceExtraEntityNum( num );
1018 info->castShadows = GetSurfaceExtraCastShadows( num );
1019 info->recvShadows = GetSurfaceExtraRecvShadows( num );
1020 info->sampleSize = GetSurfaceExtraSampleSize( num );
1021 info->longestCurve = GetSurfaceExtraLongestCurve( num );
1022 info->patchIterations = IterationsForCurve( info->longestCurve, patchSubdivisions );
1023 GetSurfaceExtraLightmapAxis( num, info->axis );
1026 if( info->parentSurfaceNum >= 0 )
1027 surfaceInfos[ info->parentSurfaceNum ].childSurfaceNum = j;
1029 /* determine surface bounds */
1030 ClearBounds( info->mins, info->maxs );
1031 for( k = 0; k < ds->numVerts; k++ )
1033 AddPointToBounds( yDrawVerts[ ds->firstVert + k ].xyz, mapMins, mapMaxs );
1034 AddPointToBounds( yDrawVerts[ ds->firstVert + k ].xyz, info->mins, info->maxs );
1037 /* find all the bsp clusters the surface falls into */
1038 for( k = 0; k < numBSPLeafs; k++ )
1041 leaf = &bspLeafs[ k ];
1044 if( leaf->mins[ 0 ] > info->maxs[ 0 ] || leaf->maxs[ 0 ] < info->mins[ 0 ] ||
1045 leaf->mins[ 1 ] > info->maxs[ 1 ] || leaf->maxs[ 1 ] < info->mins[ 1 ] ||
1046 leaf->mins[ 2 ] > info->maxs[ 2 ] || leaf->maxs[ 2 ] < info->mins[ 2 ] )
1049 /* test leaf surfaces */
1050 for( s = 0; s < leaf->numBSPLeafSurfaces; s++ )
1052 if( bspLeafSurfaces[ leaf->firstBSPLeafSurface + s ] == num )
1054 if( numSurfaceClusters >= maxSurfaceClusters )
1055 Error( "maxSurfaceClusters exceeded" );
1056 surfaceClusters[ numSurfaceClusters ] = leaf->cluster;
1057 numSurfaceClusters++;
1058 info->numSurfaceClusters++;
1063 /* determine if surface is planar */
1064 if( VectorLength( ds->lightmapVecs[ 2 ] ) > 0.0f )
1067 info->plane = safe_malloc( 4 * sizeof( float ) );
1068 VectorCopy( ds->lightmapVecs[ 2 ], info->plane );
1069 info->plane[ 3 ] = DotProduct( yDrawVerts[ ds->firstVert ].xyz, info->plane );
1072 /* determine if surface requires a lightmap */
1073 if( ds->surfaceType == MST_TRIANGLE_SOUP ||
1074 ds->surfaceType == MST_FOLIAGE ||
1075 (info->si->compileFlags & C_VERTEXLIT) )
1076 numSurfsVertexLit++;
1079 numSurfsLightmapped++;
1080 info->hasLightmap = qtrue;
1085 /* find longest map distance */
1086 VectorSubtract( mapMaxs, mapMins, mapSize );
1087 maxMapDistance = VectorLength( mapSize );
1089 /* sort the surfaces info list */
1090 qsort( sortSurfaces, numBSPDrawSurfaces, sizeof( int ), CompareSurfaceInfo );
1092 /* allocate a list of surfaces that would go into raw lightmaps */
1093 numLightSurfaces = 0;
1094 lightSurfaces = safe_malloc( numSurfsLightmapped * sizeof( int ) );
1095 memset( lightSurfaces, 0, numSurfsLightmapped * sizeof( int ) );
1097 /* allocate a list of raw lightmaps */
1098 numRawSuperLuxels = 0;
1099 numRawLightmaps = 0;
1100 rawLightmaps = safe_malloc( numSurfsLightmapped * sizeof( *rawLightmaps ) );
1101 memset( rawLightmaps, 0, numSurfsLightmapped * sizeof( *rawLightmaps ) );
1103 /* walk the list of sorted surfaces */
1104 for( i = 0; i < numBSPDrawSurfaces; i++ )
1106 /* get info and attempt early out */
1107 num = sortSurfaces[ i ];
1108 ds = &bspDrawSurfaces[ num ];
1109 info = &surfaceInfos[ num ];
1110 if( info->hasLightmap == qfalse || info->lm != NULL || info->parentSurfaceNum >= 0 )
1113 /* allocate a new raw lightmap */
1114 lm = &rawLightmaps[ numRawLightmaps ];
1118 lm->splotchFix = info->si->splotchFix;
1119 lm->firstLightSurface = numLightSurfaces;
1120 lm->numLightSurfaces = 0;
1121 /* vortex: multiply lightmap sample size by -samplescale */
1122 if (sampleScale > 0)
1123 lm->sampleSize = info->sampleSize*sampleScale;
1125 lm->sampleSize = info->sampleSize;
1126 lm->actualSampleSize = lm->sampleSize;
1127 lm->entityNum = info->entityNum;
1128 lm->recvShadows = info->recvShadows;
1129 lm->brightness = info->si->lmBrightness;
1130 lm->filterRadius = info->si->lmFilterRadius;
1131 VectorCopy(info->si->floodlightRGB, lm->floodlightRGB);
1132 lm->floodlightDistance = info->si->floodlightDistance;
1133 lm->floodlightIntensity = info->si->floodlightIntensity;
1134 lm->floodlightDirectionScale = info->si->floodlightDirectionScale;
1135 VectorCopy( info->axis, lm->axis );
1136 lm->plane = info->plane;
1137 VectorCopy( info->mins, lm->mins );
1138 VectorCopy( info->maxs, lm->maxs );
1140 lm->customWidth = info->si->lmCustomWidth;
1141 lm->customHeight = info->si->lmCustomHeight;
1143 /* add the surface to the raw lightmap */
1144 AddSurfaceToRawLightmap( num, lm );
1147 /* do an exhaustive merge */
1151 /* walk the list of surfaces again */
1153 for( j = i + 1; j < numBSPDrawSurfaces && lm->finished == qfalse; j++ )
1155 /* get info and attempt early out */
1156 num2 = sortSurfaces[ j ];
1157 ds2 = &bspDrawSurfaces[ num2 ];
1158 info2 = &surfaceInfos[ num2 ];
1159 if( info2->hasLightmap == qfalse || info2->lm != NULL )
1162 /* add the surface to the raw lightmap */
1163 if( AddSurfaceToRawLightmap( num2, lm ) )
1171 lm->numLightSurfaces--;
1177 /* finish the lightmap and allocate the various buffers */
1178 FinishRawLightmap( lm );
1181 /* allocate vertex luxel storage */
1182 for( k = 0; k < MAX_LIGHTMAPS; k++ )
1184 vertexLuxels[ k ] = safe_malloc( numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
1185 memset( vertexLuxels[ k ], 0, numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
1186 radVertexLuxels[ k ] = safe_malloc( numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
1187 memset( radVertexLuxels[ k ], 0, numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
1190 /* emit some stats */
1191 Sys_FPrintf( SYS_VRB, "%9d surfaces\n", numBSPDrawSurfaces );
1192 Sys_FPrintf( SYS_VRB, "%9d raw lightmaps\n", numRawLightmaps );
1193 Sys_FPrintf( SYS_VRB, "%9d surfaces vertex lit\n", numSurfsVertexLit );
1194 Sys_FPrintf( SYS_VRB, "%9d surfaces lightmapped\n", numSurfsLightmapped );
1195 Sys_FPrintf( SYS_VRB, "%9d planar surfaces lightmapped\n", numPlanarsLightmapped );
1196 Sys_FPrintf( SYS_VRB, "%9d non-planar surfaces lightmapped\n", numNonPlanarsLightmapped );
1197 Sys_FPrintf( SYS_VRB, "%9d patches lightmapped\n", numPatchesLightmapped );
1198 Sys_FPrintf( SYS_VRB, "%9d planar patches lightmapped\n", numPlanarPatchesLightmapped );
1204 StitchSurfaceLightmaps()
1205 stitches lightmap edges
1206 2002-11-20 update: use this func only for stitching nonplanar patch lightmap seams
1209 #define MAX_STITCH_CANDIDATES 32
1210 #define MAX_STITCH_LUXELS 64
1212 void StitchSurfaceLightmaps( void )
1214 int i, j, x, y, x2, y2, *cluster, *cluster2,
1215 numStitched, numCandidates, numLuxels, f, fOld, start;
1216 rawLightmap_t *lm, *a, *b, *c[ MAX_STITCH_CANDIDATES ];
1217 float *luxel, *luxel2, *origin, *origin2, *normal, *normal2,
1218 sampleSize, average[ 3 ], totalColor, ootc, *luxels[ MAX_STITCH_LUXELS ];
1221 /* disabled for now */
1225 Sys_Printf( "--- StitchSurfaceLightmaps ---\n");
1229 start = I_FloatTime();
1231 /* walk the list of raw lightmaps */
1233 for( i = 0; i < numRawLightmaps; i++ )
1235 /* print pacifier */
1236 f = 10 * i / numRawLightmaps;
1240 Sys_Printf( "%i...", f );
1243 /* get lightmap a */
1244 a = &rawLightmaps[ i ];
1246 /* walk rest of lightmaps */
1248 for( j = i + 1; j < numRawLightmaps && numCandidates < MAX_STITCH_CANDIDATES; j++ )
1250 /* get lightmap b */
1251 b = &rawLightmaps[ j ];
1253 /* test bounding box */
1254 if( a->mins[ 0 ] > b->maxs[ 0 ] || a->maxs[ 0 ] < b->mins[ 0 ] ||
1255 a->mins[ 1 ] > b->maxs[ 1 ] || a->maxs[ 1 ] < b->mins[ 1 ] ||
1256 a->mins[ 2 ] > b->maxs[ 2 ] || a->maxs[ 2 ] < b->mins[ 2 ] )
1260 c[ numCandidates++ ] = b;
1264 for( y = 0; y < a->sh; y++ )
1266 for( x = 0; x < a->sw; x++ )
1268 /* ignore unmapped/unlit luxels */
1270 cluster = SUPER_CLUSTER( x, y );
1271 if( *cluster == CLUSTER_UNMAPPED )
1273 luxel = SUPER_LUXEL( 0, x, y );
1274 if( luxel[ 3 ] <= 0.0f )
1277 /* get particulars */
1278 origin = SUPER_ORIGIN( x, y );
1279 normal = SUPER_NORMAL( x, y );
1281 /* walk candidate list */
1282 for( j = 0; j < numCandidates; j++ )
1288 /* set samplesize to the smaller of the pair */
1289 sampleSize = 0.5f * (a->actualSampleSize < b->actualSampleSize ? a->actualSampleSize : b->actualSampleSize);
1291 /* test bounding box */
1292 if( origin[ 0 ] < (b->mins[ 0 ] - sampleSize) || (origin[ 0 ] > b->maxs[ 0 ] + sampleSize) ||
1293 origin[ 1 ] < (b->mins[ 1 ] - sampleSize) || (origin[ 1 ] > b->maxs[ 1 ] + sampleSize) ||
1294 origin[ 2 ] < (b->mins[ 2 ] - sampleSize) || (origin[ 2 ] > b->maxs[ 2 ] + sampleSize) )
1297 /* walk candidate luxels */
1298 VectorClear( average );
1301 for( y2 = 0; y2 < b->sh && numLuxels < MAX_STITCH_LUXELS; y2++ )
1303 for( x2 = 0; x2 < b->sw && numLuxels < MAX_STITCH_LUXELS; x2++ )
1305 /* ignore same luxels */
1306 if( a == b && abs( x - x2 ) <= 1 && abs( y - y2 ) <= 1 )
1309 /* ignore unmapped/unlit luxels */
1310 cluster2 = SUPER_CLUSTER( x2, y2 );
1311 if( *cluster2 == CLUSTER_UNMAPPED )
1313 luxel2 = SUPER_LUXEL( 0, x2, y2 );
1314 if( luxel2[ 3 ] <= 0.0f )
1317 /* get particulars */
1318 origin2 = SUPER_ORIGIN( x2, y2 );
1319 normal2 = SUPER_NORMAL( x2, y2 );
1322 if( DotProduct( normal, normal2 ) < 0.5f )
1326 if( fabs( origin[ 0 ] - origin2[ 0 ] ) > sampleSize ||
1327 fabs( origin[ 1 ] - origin2[ 1 ] ) > sampleSize ||
1328 fabs( origin[ 2 ] - origin2[ 2 ] ) > sampleSize )
1332 //% VectorSet( luxel2, 255, 0, 255 );
1333 luxels[ numLuxels++ ] = luxel2;
1334 VectorAdd( average, luxel2, average );
1335 totalColor += luxel2[ 3 ];
1340 if( numLuxels == 0 )
1344 ootc = 1.0f / totalColor;
1345 VectorScale( average, ootc, luxel );
1353 /* emit statistics */
1354 Sys_Printf( " (%i)\n", (int) (I_FloatTime() - start) );
1355 Sys_FPrintf( SYS_VRB, "%9d luxels stitched\n", numStitched );
1362 compares two surface lightmaps' bsp luxels, ignoring occluded luxels
1365 #define SOLID_EPSILON 0.0625
1366 #define LUXEL_TOLERANCE 0.0025
1367 #define LUXEL_COLOR_FRAC 0.001302083 /* 1 / 3 / 256 */
1369 static qboolean CompareBSPLuxels( rawLightmap_t *a, int aNum, rawLightmap_t *b, int bNum )
1373 double delta, total, rd, gd, bd;
1374 float *aLuxel, *bLuxel;
1377 /* styled lightmaps will never be collapsed to non-styled lightmaps when there is _minlight */
1378 if( (minLight[ 0 ] || minLight[ 1 ] || minLight[ 2 ]) &&
1379 ((aNum == 0 && bNum != 0) || (aNum != 0 && bNum == 0)) )
1383 if( a->customWidth != b->customWidth || a->customHeight != b->customHeight ||
1384 a->brightness != b->brightness ||
1385 a->solid[ aNum ] != b->solid[ bNum ] ||
1386 a->bspLuxels[ aNum ] == NULL || b->bspLuxels[ bNum ] == NULL )
1389 /* compare solid color lightmaps */
1390 if( a->solid[ aNum ] && b->solid[ bNum ] )
1393 rd = fabs( a->solidColor[ aNum ][ 0 ] - b->solidColor[ bNum ][ 0 ] );
1394 gd = fabs( a->solidColor[ aNum ][ 1 ] - b->solidColor[ bNum ][ 1 ] );
1395 bd = fabs( a->solidColor[ aNum ][ 2 ] - b->solidColor[ bNum ][ 2 ] );
1398 if( rd > SOLID_EPSILON || gd > SOLID_EPSILON|| bd > SOLID_EPSILON )
1405 /* compare nonsolid lightmaps */
1406 if( a->w != b->w || a->h != b->h )
1409 /* compare luxels */
1412 for( y = 0; y < a->h; y++ )
1414 for( x = 0; x < a->w; x++ )
1416 /* increment total */
1420 lm = a; aLuxel = BSP_LUXEL( aNum, x, y );
1421 lm = b; bLuxel = BSP_LUXEL( bNum, x, y );
1423 /* ignore unused luxels */
1424 if( aLuxel[ 0 ] < 0 || bLuxel[ 0 ] < 0 )
1428 rd = fabs( aLuxel[ 0 ] - bLuxel[ 0 ] );
1429 gd = fabs( aLuxel[ 1 ] - bLuxel[ 1 ] );
1430 bd = fabs( aLuxel[ 2 ] - bLuxel[ 2 ] );
1432 /* 2003-09-27: compare individual luxels */
1433 if( rd > 3.0 || gd > 3.0 || bd > 3.0 )
1436 /* compare (fixme: take into account perceptual differences) */
1437 delta += rd * LUXEL_COLOR_FRAC;
1438 delta += gd * LUXEL_COLOR_FRAC;
1439 delta += bd * LUXEL_COLOR_FRAC;
1441 /* is the change too high? */
1442 if( total > 0.0 && ((delta / total) > LUXEL_TOLERANCE) )
1447 /* made it this far, they must be identical (or close enough) */
1455 merges two surface lightmaps' bsp luxels, overwriting occluded luxels
1458 static qboolean MergeBSPLuxels( rawLightmap_t *a, int aNum, rawLightmap_t *b, int bNum )
1462 float luxel[ 3 ], *aLuxel, *bLuxel;
1466 if( a->customWidth != b->customWidth || a->customHeight != b->customHeight ||
1467 a->brightness != b->brightness ||
1468 a->solid[ aNum ] != b->solid[ bNum ] ||
1469 a->bspLuxels[ aNum ] == NULL || b->bspLuxels[ bNum ] == NULL )
1472 /* compare solid lightmaps */
1473 if( a->solid[ aNum ] && b->solid[ bNum ] )
1476 VectorAdd( a->solidColor[ aNum ], b->solidColor[ bNum ], luxel );
1477 VectorScale( luxel, 0.5f, luxel );
1480 VectorCopy( luxel, a->solidColor[ aNum ] );
1481 VectorCopy( luxel, b->solidColor[ bNum ] );
1483 /* return to sender */
1487 /* compare nonsolid lightmaps */
1488 if( a->w != b->w || a->h != b->h )
1492 for( y = 0; y < a->h; y++ )
1494 for( x = 0; x < a->w; x++ )
1497 lm = a; aLuxel = BSP_LUXEL( aNum, x, y );
1498 lm = b; bLuxel = BSP_LUXEL( bNum, x, y );
1500 /* handle occlusion mismatch */
1501 if( aLuxel[ 0 ] < 0.0f )
1502 VectorCopy( bLuxel, aLuxel );
1503 else if( bLuxel[ 0 ] < 0.0f )
1504 VectorCopy( aLuxel, bLuxel );
1508 VectorAdd( aLuxel, bLuxel, luxel );
1509 VectorScale( luxel, 0.5f, luxel );
1511 /* debugging code */
1512 //% luxel[ 2 ] += 64.0f;
1515 VectorCopy( luxel, aLuxel );
1516 VectorCopy( luxel, bLuxel );
1529 determines if a single luxel is can be approximated with the interpolated vertex rgba
1532 static qboolean ApproximateLuxel( rawLightmap_t *lm, bspDrawVert_t *dv )
1534 int i, x, y, d, lightmapNum;
1536 vec3_t color, vertexColor;
1537 byte cb[ 4 ], vcb[ 4 ];
1540 /* find luxel xy coords */
1541 x = dv->lightmap[ 0 ][ 0 ] / superSample;
1542 y = dv->lightmap[ 0 ][ 1 ] / superSample;
1545 else if( x >= lm->w )
1549 else if( y >= lm->h )
1553 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1556 if( lm->styles[ lightmapNum ] == LS_NONE )
1560 luxel = BSP_LUXEL( lightmapNum, x, y );
1562 /* ignore occluded luxels */
1563 if( luxel[ 0 ] < 0.0f || luxel[ 1 ] < 0.0f || luxel[ 2 ] < 0.0f )
1566 /* copy, set min color and compare */
1567 VectorCopy( luxel, color );
1568 VectorCopy( dv->color[ 0 ], vertexColor );
1570 /* styles are not affected by minlight */
1571 if( lightmapNum == 0 )
1573 for( i = 0; i < 3; i++ )
1576 if( color[ i ] < minLight[ i ] )
1577 color[ i ] = minLight[ i ];
1578 if( vertexColor[ i ] < minLight[ i ] ) /* note NOT minVertexLight */
1579 vertexColor[ i ] = minLight[ i ];
1584 ColorToBytes( color, cb, 1.0f );
1585 ColorToBytes( vertexColor, vcb, 1.0f );
1588 for( i = 0; i < 3; i++ )
1590 d = cb[ i ] - vcb[ i ];
1593 if( d > approximateTolerance )
1598 /* close enough for the girls i date */
1605 ApproximateTriangle()
1606 determines if a single triangle can be approximated with vertex rgba
1609 static qboolean ApproximateTriangle_r( rawLightmap_t *lm, bspDrawVert_t *dv[ 3 ] )
1611 bspDrawVert_t mid, *dv2[ 3 ];
1615 /* approximate the vertexes */
1616 if( ApproximateLuxel( lm, dv[ 0 ] ) == qfalse )
1618 if( ApproximateLuxel( lm, dv[ 1 ] ) == qfalse )
1620 if( ApproximateLuxel( lm, dv[ 2 ] ) == qfalse )
1623 /* subdivide calc */
1626 float dx, dy, dist, maxDist;
1629 /* find the longest edge and split it */
1632 for( i = 0; i < 3; i++ )
1634 dx = dv[ i ]->lightmap[ 0 ][ 0 ] - dv[ (i + 1) % 3 ]->lightmap[ 0 ][ 0 ];
1635 dy = dv[ i ]->lightmap[ 0 ][ 1 ] - dv[ (i + 1) % 3 ]->lightmap[ 0 ][ 1 ];
1636 dist = sqrt( (dx * dx) + (dy * dy) );
1637 if( dist > maxDist )
1644 /* try to early out */
1645 if( i < 0 || maxDist < subdivideThreshold )
1649 /* split the longest edge and map it */
1650 LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid );
1651 if( ApproximateLuxel( lm, &mid ) == qfalse )
1654 /* recurse to first triangle */
1655 VectorCopy( dv, dv2 );
1657 if( ApproximateTriangle_r( lm, dv2 ) == qfalse )
1660 /* recurse to second triangle */
1661 VectorCopy( dv, dv2 );
1662 dv2[ (max + 1) % 3 ] = ∣
1663 return ApproximateTriangle_r( lm, dv2 );
1669 ApproximateLightmap()
1670 determines if a raw lightmap can be approximated sufficiently with vertex colors
1673 static qboolean ApproximateLightmap( rawLightmap_t *lm )
1675 int n, num, i, x, y, pw[ 5 ], r;
1676 bspDrawSurface_t *ds;
1677 surfaceInfo_t *info;
1678 mesh_t src, *subdivided, *mesh;
1679 bspDrawVert_t *verts, *dv[ 3 ];
1680 qboolean approximated;
1683 /* approximating? */
1684 if( approximateTolerance <= 0 )
1687 /* test for jmonroe */
1689 /* don't approx lightmaps with styled twins */
1690 if( lm->numStyledTwins > 0 )
1693 /* don't approx lightmaps with styles */
1694 for( i = 1; i < MAX_LIGHTMAPS; i++ )
1696 if( lm->styles[ i ] != LS_NONE )
1701 /* assume reduced until shadow detail is found */
1702 approximated = qtrue;
1704 /* walk the list of surfaces on this raw lightmap */
1705 for( n = 0; n < lm->numLightSurfaces; n++ )
1708 num = lightSurfaces[ lm->firstLightSurface + n ];
1709 ds = &bspDrawSurfaces[ num ];
1710 info = &surfaceInfos[ num ];
1712 /* assume not-reduced initially */
1713 info->approximated = qfalse;
1715 /* bail if lightmap doesn't match up */
1716 if( info->lm != lm )
1719 /* bail if not vertex lit */
1720 if( info->si->noVertexLight )
1723 /* assume that surfaces whose bounding boxes is smaller than 2x samplesize will be forced to vertex */
1724 if( (info->maxs[ 0 ] - info->mins[ 0 ]) <= (2.0f * info->sampleSize) &&
1725 (info->maxs[ 1 ] - info->mins[ 1 ]) <= (2.0f * info->sampleSize) &&
1726 (info->maxs[ 2 ] - info->mins[ 2 ]) <= (2.0f * info->sampleSize) )
1728 info->approximated = qtrue;
1729 numSurfsVertexForced++;
1733 /* handle the triangles */
1734 switch( ds->surfaceType )
1738 verts = yDrawVerts + ds->firstVert;
1740 /* map the triangles */
1741 info->approximated = qtrue;
1742 for( i = 0; i < ds->numIndexes && info->approximated; i += 3 )
1744 dv[ 0 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i ] ];
1745 dv[ 1 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 1 ] ];
1746 dv[ 2 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 2 ] ];
1747 info->approximated = ApproximateTriangle_r( lm, dv );
1752 /* make a mesh from the drawsurf */
1753 src.width = ds->patchWidth;
1754 src.height = ds->patchHeight;
1755 src.verts = &yDrawVerts[ ds->firstVert ];
1756 //% subdivided = SubdivideMesh( src, 8, 512 );
1757 subdivided = SubdivideMesh2( src, info->patchIterations );
1759 /* fit it to the curve and remove colinear verts on rows/columns */
1760 PutMeshOnCurve( *subdivided );
1761 mesh = RemoveLinearMeshColumnsRows( subdivided );
1762 FreeMesh( subdivided );
1765 verts = mesh->verts;
1767 /* map the mesh quads */
1768 info->approximated = qtrue;
1769 for( y = 0; y < (mesh->height - 1) && info->approximated; y++ )
1771 for( x = 0; x < (mesh->width - 1) && info->approximated; x++ )
1774 pw[ 0 ] = x + (y * mesh->width);
1775 pw[ 1 ] = x + ((y + 1) * mesh->width);
1776 pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
1777 pw[ 3 ] = x + 1 + (y * mesh->width);
1778 pw[ 4 ] = x + (y * mesh->width); /* same as pw[ 0 ] */
1783 /* get drawverts and map first triangle */
1784 dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1785 dv[ 1 ] = &verts[ pw[ r + 1 ] ];
1786 dv[ 2 ] = &verts[ pw[ r + 2 ] ];
1787 info->approximated = ApproximateTriangle_r( lm, dv );
1789 /* get drawverts and map second triangle */
1790 dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1791 dv[ 1 ] = &verts[ pw[ r + 2 ] ];
1792 dv[ 2 ] = &verts[ pw[ r + 3 ] ];
1793 if( info->approximated )
1794 info->approximated = ApproximateTriangle_r( lm, dv );
1807 if( info->approximated == qfalse )
1808 approximated = qfalse;
1810 numSurfsVertexApproximated++;
1814 return approximated;
1820 TestOutLightmapStamp()
1821 tests a stamp on a given lightmap for validity
1824 static qboolean TestOutLightmapStamp( rawLightmap_t *lm, int lightmapNum, outLightmap_t *olm, int x, int y )
1826 int sx, sy, ox, oy, offset;
1831 if( x < 0 || y < 0 || (x + lm->w) > olm->customWidth || (y + lm->h) > olm->customHeight )
1834 /* solid lightmaps test a 1x1 stamp */
1835 if( lm->solid[ lightmapNum ] )
1837 offset = (y * olm->customWidth) + x;
1838 if( olm->lightBits[ offset >> 3 ] & (1 << (offset & 7)) )
1843 /* test the stamp */
1844 for( sy = 0; sy < lm->h; sy++ )
1846 for( sx = 0; sx < lm->w; sx++ )
1849 luxel = BSP_LUXEL( lightmapNum, sx, sy );
1850 if( luxel[ 0 ] < 0.0f )
1853 /* get bsp lightmap coords and test */
1856 offset = (oy * olm->customWidth) + ox;
1857 if( olm->lightBits[ offset >> 3 ] & (1 << (offset & 7)) )
1862 /* stamp is empty */
1870 sets up an output lightmap
1873 static void SetupOutLightmap( rawLightmap_t *lm, outLightmap_t *olm )
1876 if( lm == NULL || olm == NULL )
1879 /* is this a "normal" bsp-stored lightmap? */
1880 if( (lm->customWidth == game->lightmapSize && lm->customHeight == game->lightmapSize) || externalLightmaps )
1882 olm->lightmapNum = numBSPLightmaps;
1885 /* lightmaps are interleaved with light direction maps */
1890 olm->lightmapNum = -3;
1892 /* set external lightmap number */
1893 olm->extLightmapNum = -1;
1896 olm->numLightmaps = 0;
1897 olm->customWidth = lm->customWidth;
1898 olm->customHeight = lm->customHeight;
1899 olm->freeLuxels = olm->customWidth * olm->customHeight;
1900 olm->numShaders = 0;
1902 /* allocate buffers */
1903 olm->lightBits = safe_malloc( (olm->customWidth * olm->customHeight / 8) + 8 );
1904 memset( olm->lightBits, 0, (olm->customWidth * olm->customHeight / 8) + 8 );
1905 olm->bspLightBytes = safe_malloc( olm->customWidth * olm->customHeight * 3 );
1906 memset( olm->bspLightBytes, 0, olm->customWidth * olm->customHeight * 3 );
1909 olm->bspDirBytes = safe_malloc( olm->customWidth * olm->customHeight * 3 );
1910 memset( olm->bspDirBytes, 0, olm->customWidth * olm->customHeight * 3 );
1918 for a given surface lightmap, find output lightmap pages and positions for it
1921 #define LIGHTMAP_RESERVE_COUNT 1
1922 static void FindOutLightmaps( rawLightmap_t *lm )
1924 int i, j, k, lightmapNum, xMax, yMax, x, y, sx, sy, ox, oy, offset;
1926 surfaceInfo_t *info;
1927 float *luxel, *deluxel;
1928 vec3_t color, direction;
1933 /* set default lightmap number (-3 = LIGHTMAP_BY_VERTEX) */
1934 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1935 lm->outLightmapNums[ lightmapNum ] = -3;
1937 /* can this lightmap be approximated with vertex color? */
1938 if( ApproximateLightmap( lm ) )
1942 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1945 if( lm->styles[ lightmapNum ] == LS_NONE )
1948 /* don't store twinned lightmaps */
1949 if( lm->twins[ lightmapNum ] != NULL )
1952 /* if this is a styled lightmap, try some normalized locations first */
1954 if( lightmapNum > 0 && outLightmaps != NULL )
1957 for( j = 0; j < 2; j++ )
1959 /* try identical position */
1960 for( i = 0; i < numOutLightmaps; i++ )
1962 /* get the output lightmap */
1963 olm = &outLightmaps[ i ];
1965 /* simple early out test */
1966 if( olm->freeLuxels < lm->used )
1969 /* don't store non-custom raw lightmaps on custom bsp lightmaps */
1970 if( olm->customWidth != lm->customWidth ||
1971 olm->customHeight != lm->customHeight )
1977 x = lm->lightmapX[ 0 ];
1978 y = lm->lightmapY[ 0 ];
1979 ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );
1985 for( sy = -1; sy <= 1; sy++ )
1987 for( sx = -1; sx <= 1; sx++ )
1989 x = lm->lightmapX[ 0 ] + sx * (olm->customWidth >> 1); //% lm->w;
1990 y = lm->lightmapY[ 0 ] + sy * (olm->customHeight >> 1); //% lm->h;
1991 ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );
2011 /* try normal placement algorithm */
2018 /* walk the list of lightmap pages */
2019 if(lightmapSearchBlockSize <= 0 || numOutLightmaps < LIGHTMAP_RESERVE_COUNT)
2022 i = ((numOutLightmaps - LIGHTMAP_RESERVE_COUNT) / lightmapSearchBlockSize) * lightmapSearchBlockSize;
2023 for( ; i < numOutLightmaps; i++ )
2025 /* get the output lightmap */
2026 olm = &outLightmaps[ i ];
2028 /* simple early out test */
2029 if( olm->freeLuxels < lm->used )
2032 /* don't store non-custom raw lightmaps on custom bsp lightmaps */
2033 if( olm->customWidth != lm->customWidth ||
2034 olm->customHeight != lm->customHeight )
2038 if( lm->solid[ lightmapNum ] )
2040 xMax = olm->customWidth;
2041 yMax = olm->customHeight;
2045 xMax = (olm->customWidth - lm->w) + 1;
2046 yMax = (olm->customHeight - lm->h) + 1;
2049 /* walk the origin around the lightmap */
2050 for( y = 0; y < yMax; y++ )
2052 for( x = 0; x < xMax; x++ )
2054 /* find a fine tract of lauhnd */
2055 ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );
2077 /* allocate LIGHTMAP_RESERVE_COUNT new output lightmaps */
2078 numOutLightmaps += LIGHTMAP_RESERVE_COUNT;
2079 olm = safe_malloc( numOutLightmaps * sizeof( outLightmap_t ) );
2080 if( outLightmaps != NULL && numOutLightmaps > LIGHTMAP_RESERVE_COUNT )
2082 memcpy( olm, outLightmaps, (numOutLightmaps - LIGHTMAP_RESERVE_COUNT) * sizeof( outLightmap_t ) );
2083 free( outLightmaps );
2087 /* initialize both out lightmaps */
2088 for(k = numOutLightmaps - LIGHTMAP_RESERVE_COUNT; k < numOutLightmaps; ++k)
2089 SetupOutLightmap( lm, &outLightmaps[ k ] );
2091 /* set out lightmap */
2092 i = numOutLightmaps - LIGHTMAP_RESERVE_COUNT;
2093 olm = &outLightmaps[ i ];
2095 /* set stamp xy origin to the first surface lightmap */
2096 if( lightmapNum > 0 )
2098 x = lm->lightmapX[ 0 ];
2099 y = lm->lightmapY[ 0 ];
2103 /* if this is a style-using lightmap, it must be exported */
2104 if( lightmapNum > 0 && game->load != LoadRBSPFile )
2105 olm->extLightmapNum = 0;
2107 /* add the surface lightmap to the bsp lightmap */
2108 lm->outLightmapNums[ lightmapNum ] = i;
2109 lm->lightmapX[ lightmapNum ] = x;
2110 lm->lightmapY[ lightmapNum ] = y;
2111 olm->numLightmaps++;
2114 for( i = 0; i < lm->numLightSurfaces; i++ )
2116 /* get surface info */
2117 info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + i ] ];
2119 /* test for shader */
2120 for( j = 0; j < olm->numShaders; j++ )
2122 if( olm->shaders[ j ] == info->si )
2126 /* if it doesn't exist, add it */
2127 if( j >= olm->numShaders && olm->numShaders < MAX_LIGHTMAP_SHADERS )
2129 olm->shaders[ olm->numShaders ] = info->si;
2131 numLightmapShaders++;
2136 if( lm->solid[ lightmapNum ] )
2147 /* mark the bits used */
2148 for( y = 0; y < yMax; y++ )
2150 for( x = 0; x < xMax; x++ )
2153 luxel = BSP_LUXEL( lightmapNum, x, y );
2154 deluxel = BSP_DELUXEL( x, y );
2155 if( luxel[ 0 ] < 0.0f && !lm->solid[ lightmapNum ])
2158 /* set minimum light */
2159 if( lm->solid[ lightmapNum ] )
2162 VectorSet( color, 255.0f, 0.0f, 0.0f );
2164 VectorCopy( lm->solidColor[ lightmapNum ], color );
2167 VectorCopy( luxel, color );
2169 /* styles are not affected by minlight */
2170 if( lightmapNum == 0 )
2172 for( i = 0; i < 3; i++ )
2174 if( color[ i ] < minLight[ i ] )
2175 color[ i ] = minLight[ i ];
2179 /* get bsp lightmap coords */
2180 ox = x + lm->lightmapX[ lightmapNum ];
2181 oy = y + lm->lightmapY[ lightmapNum ];
2182 offset = (oy * olm->customWidth) + ox;
2184 /* flag pixel as used */
2185 olm->lightBits[ offset >> 3 ] |= (1 << (offset & 7));
2189 pixel = olm->bspLightBytes + (((oy * olm->customWidth) + ox) * 3);
2190 ColorToBytes( color, pixel, lm->brightness );
2192 /* store direction */
2195 /* normalize average light direction */
2196 pixel = olm->bspDirBytes + (((oy * olm->customWidth) + ox) * 3);
2197 VectorScale( deluxel, 1000.0f, direction );
2198 VectorNormalize( direction, direction );
2199 VectorScale( direction, 127.5f, direction );
2200 for( i = 0; i < 3; i++ )
2201 pixel[ i ] = (byte)( 127.5f + direction[ i ] );
2211 CompareRawLightmap()
2212 compare function for qsort()
2215 static int CompareRawLightmap( const void *a, const void *b )
2217 rawLightmap_t *alm, *blm;
2218 surfaceInfo_t *aInfo, *bInfo;
2223 alm = &rawLightmaps[ *((const int*) a) ];
2224 blm = &rawLightmaps[ *((const int*) b) ];
2226 /* get min number of surfaces */
2227 min = (alm->numLightSurfaces < blm->numLightSurfaces ? alm->numLightSurfaces : blm->numLightSurfaces);
2230 for( i = 0; i < min; i++ )
2232 /* get surface info */
2233 aInfo = &surfaceInfos[ lightSurfaces[ alm->firstLightSurface + i ] ];
2234 bInfo = &surfaceInfos[ lightSurfaces[ blm->firstLightSurface + i ] ];
2236 /* compare shader names */
2237 diff = strcmp( aInfo->si->shader, bInfo->si->shader );
2242 /* test style count */
2244 for( i = 0; i < MAX_LIGHTMAPS; i++ )
2245 diff += blm->styles[ i ] - alm->styles[ i ];
2250 diff = (blm->w * blm->h) - (alm->w * alm->h);
2254 /* must be equivalent */
2258 void FillOutLightmap(outLightmap_t *olm)
2262 vec3_t dir_sum, light_sum;
2264 byte *lightBitsNew = NULL;
2265 byte *lightBytesNew = NULL;
2266 byte *dirBytesNew = NULL;
2268 lightBitsNew = safe_malloc((olm->customWidth * olm->customHeight + 8) / 8);
2269 lightBytesNew = safe_malloc(olm->customWidth * olm->customHeight * 3);
2271 dirBytesNew = safe_malloc(olm->customWidth * olm->customHeight * 3);
2274 memset(olm->lightBits, 0, (olm->customWidth * olm->customHeight + 8) / 8);
2275 olm->lightBits[0] |= 1;
2276 olm->lightBits[(10 * olm->customWidth + 30) >> 3] |= 1 << ((10 * olm->customWidth + 30) & 7);
2277 memset(olm->bspLightBytes, 0, olm->customWidth * olm->customHeight * 3);
2278 olm->bspLightBytes[0] = 255;
2279 olm->bspLightBytes[(10 * olm->customWidth + 30) * 3 + 2] = 255;
2282 memcpy(lightBitsNew, olm->lightBits, (olm->customWidth * olm->customHeight + 8) / 8);
2283 memcpy(lightBytesNew, olm->bspLightBytes, olm->customWidth * olm->customHeight * 3);
2285 memcpy(dirBytesNew, olm->bspDirBytes, olm->customWidth * olm->customHeight * 3);
2290 for(y = 0; y < olm->customHeight; ++y)
2292 for(x = 0; x < olm->customWidth; ++x)
2294 ofs = y * olm->customWidth + x;
2295 if(olm->lightBits[ofs >> 3] & (1 << (ofs & 7))) /* already filled */
2298 VectorClear(dir_sum);
2299 VectorClear(light_sum);
2301 /* try all four neighbors */
2302 ofs = ((y + olm->customHeight - 1) % olm->customHeight) * olm->customWidth + x;
2303 if(olm->lightBits[ofs >> 3] & (1 << (ofs & 7))) /* already filled */
2306 VectorAdd(light_sum, olm->bspLightBytes + ofs * 3, light_sum);
2308 VectorAdd(dir_sum, olm->bspDirBytes + ofs * 3, dir_sum);
2311 ofs = ((y + 1) % olm->customHeight) * olm->customWidth + x;
2312 if(olm->lightBits[ofs >> 3] & (1 << (ofs & 7))) /* already filled */
2315 VectorAdd(light_sum, olm->bspLightBytes + ofs * 3, light_sum);
2317 VectorAdd(dir_sum, olm->bspDirBytes + ofs * 3, dir_sum);
2320 ofs = y * olm->customWidth + (x + olm->customWidth - 1) % olm->customWidth;
2321 if(olm->lightBits[ofs >> 3] & (1 << (ofs & 7))) /* already filled */
2324 VectorAdd(light_sum, olm->bspLightBytes + ofs * 3, light_sum);
2326 VectorAdd(dir_sum, olm->bspDirBytes + ofs * 3, dir_sum);
2329 ofs = y * olm->customWidth + (x + 1) % olm->customWidth;
2330 if(olm->lightBits[ofs >> 3] & (1 << (ofs & 7))) /* already filled */
2333 VectorAdd(light_sum, olm->bspLightBytes + ofs * 3, light_sum);
2335 VectorAdd(dir_sum, olm->bspDirBytes + ofs * 3, dir_sum);
2341 ofs = y * olm->customWidth + x;
2342 lightBitsNew[ofs >> 3] |= (1 << (ofs & 7));
2343 VectorScale(light_sum, 1.0/cnt, lightBytesNew + ofs * 3);
2345 VectorScale(dir_sum, 1.0/cnt, dirBytesNew + ofs * 3);
2353 memcpy(olm->lightBits, lightBitsNew, (olm->customWidth * olm->customHeight + 8) / 8);
2354 memcpy(olm->bspLightBytes, lightBytesNew, olm->customWidth * olm->customHeight * 3);
2356 memcpy(olm->bspDirBytes, dirBytesNew, olm->customWidth * olm->customHeight * 3);
2360 free(lightBytesNew);
2366 StoreSurfaceLightmaps()
2367 stores the surface lightmaps into the bsp as byte rgb triplets
2370 void StoreSurfaceLightmaps( void )
2372 int i, j, k, x, y, lx, ly, sx, sy, *cluster, mappedSamples;
2373 int style, size, lightmapNum, lightmapNum2;
2374 float *normal, *luxel, *bspLuxel, *bspLuxel2, *radLuxel, samples, occludedSamples;
2375 vec3_t sample, occludedSample, dirSample, colorMins, colorMaxs;
2376 float *deluxel, *bspDeluxel, *bspDeluxel2;
2378 int numUsed, numTwins, numTwinLuxels, numStored;
2379 float lmx, lmy, efficiency;
2381 bspDrawSurface_t *ds, *parent, dsTemp;
2382 surfaceInfo_t *info;
2383 rawLightmap_t *lm, *lm2;
2385 bspDrawVert_t *dv, *ydv, *dvParent;
2386 char dirname[ 1024 ], filename[ 1024 ];
2388 char lightmapName[ 128 ];
2389 const char *rgbGenValues[ 256 ];
2390 const char *alphaGenValues[ 256 ];
2394 Sys_Printf( "--- StoreSurfaceLightmaps ---\n");
2399 strcpy( dirname, lmCustomDir );
2403 strcpy( dirname, source );
2404 StripExtension( dirname );
2406 memset( rgbGenValues, 0, sizeof( rgbGenValues ) );
2407 memset( alphaGenValues, 0, sizeof( alphaGenValues ) );
2409 /* -----------------------------------------------------------------
2410 average the sampled luxels into the bsp luxels
2411 ----------------------------------------------------------------- */
2414 Sys_Printf( "Subsampling..." );
2416 /* walk the list of raw lightmaps */
2420 numSolidLightmaps = 0;
2421 for( i = 0; i < numRawLightmaps; i++ )
2424 lm = &rawLightmaps[ i ];
2426 /* walk individual lightmaps */
2427 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2430 if( lm->superLuxels[ lightmapNum ] == NULL )
2433 /* allocate bsp luxel storage */
2434 if( lm->bspLuxels[ lightmapNum ] == NULL )
2436 size = lm->w * lm->h * BSP_LUXEL_SIZE * sizeof( float );
2437 lm->bspLuxels[ lightmapNum ] = safe_malloc( size );
2438 memset( lm->bspLuxels[ lightmapNum ], 0, size );
2441 /* allocate radiosity lightmap storage */
2444 size = lm->w * lm->h * RAD_LUXEL_SIZE * sizeof( float );
2445 if( lm->radLuxels[ lightmapNum ] == NULL )
2446 lm->radLuxels[ lightmapNum ] = safe_malloc( size );
2447 memset( lm->radLuxels[ lightmapNum ], 0, size );
2450 /* average supersampled luxels */
2451 for( y = 0; y < lm->h; y++ )
2453 for( x = 0; x < lm->w; x++ )
2457 occludedSamples = 0.0f;
2459 VectorClear( sample );
2460 VectorClear( occludedSample );
2461 VectorClear( dirSample );
2462 for( ly = 0; ly < superSample; ly++ )
2464 for( lx = 0; lx < superSample; lx++ )
2467 sx = x * superSample + lx;
2468 sy = y * superSample + ly;
2469 luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2470 deluxel = SUPER_DELUXEL( sx, sy );
2471 normal = SUPER_NORMAL( sx, sy );
2472 cluster = SUPER_CLUSTER( sx, sy );
2474 /* sample deluxemap */
2475 if( deluxemap && lightmapNum == 0 )
2476 VectorAdd( dirSample, deluxel, dirSample );
2478 /* keep track of used/occluded samples */
2479 if( *cluster != CLUSTER_UNMAPPED )
2482 /* handle lightmap border? */
2483 if( lightmapBorder && (sx == 0 || sx == (lm->sw - 1) || sy == 0 || sy == (lm->sh - 1) ) && luxel[ 3 ] > 0.0f )
2485 VectorSet( sample, 255.0f, 0.0f, 0.0f );
2490 else if( debug && *cluster < 0 )
2492 if( *cluster == CLUSTER_UNMAPPED )
2493 VectorSet( luxel, 255, 204, 0 );
2494 else if( *cluster == CLUSTER_OCCLUDED )
2495 VectorSet( luxel, 255, 0, 255 );
2496 else if( *cluster == CLUSTER_FLOODED )
2497 VectorSet( luxel, 0, 32, 255 );
2498 VectorAdd( occludedSample, luxel, occludedSample );
2499 occludedSamples += 1.0f;
2502 /* normal luxel handling */
2503 else if( luxel[ 3 ] > 0.0f )
2505 /* handle lit or flooded luxels */
2506 if( *cluster > 0 || *cluster == CLUSTER_FLOODED )
2508 VectorAdd( sample, luxel, sample );
2509 samples += luxel[ 3 ];
2512 /* handle occluded or unmapped luxels */
2515 VectorAdd( occludedSample, luxel, occludedSample );
2516 occludedSamples += luxel[ 3 ];
2519 /* handle style debugging */
2520 if( debug && lightmapNum > 0 && x < 2 && y < 2 )
2522 VectorCopy( debugColors[ 0 ], sample );
2529 /* only use occluded samples if necessary */
2530 if( samples <= 0.0f )
2532 VectorCopy( occludedSample, sample );
2533 samples = occludedSamples;
2537 luxel = SUPER_LUXEL( lightmapNum, x, y );
2538 deluxel = SUPER_DELUXEL( x, y );
2540 /* store light direction */
2541 if( deluxemap && lightmapNum == 0 )
2542 VectorCopy( dirSample, deluxel );
2544 /* store the sample back in super luxels */
2545 if( samples > 0.01f )
2547 VectorScale( sample, (1.0f / samples), luxel );
2551 /* if any samples were mapped in any way, store ambient color */
2552 else if( mappedSamples > 0 )
2554 if( lightmapNum == 0 )
2555 VectorCopy( ambientColor, luxel );
2557 VectorClear( luxel );
2561 /* store a bogus value to be fixed later */
2564 VectorClear( luxel );
2572 ClearBounds( colorMins, colorMaxs );
2574 /* clean up and store into bsp luxels */
2575 for( y = 0; y < lm->h; y++ )
2577 for( x = 0; x < lm->w; x++ )
2580 luxel = SUPER_LUXEL( lightmapNum, x, y );
2581 deluxel = SUPER_DELUXEL( x, y );
2583 /* copy light direction */
2584 if( deluxemap && lightmapNum == 0 )
2585 VectorCopy( deluxel, dirSample );
2587 /* is this a valid sample? */
2588 if( luxel[ 3 ] > 0.0f )
2590 VectorCopy( luxel, sample );
2591 samples = luxel[ 3 ];
2595 /* fix negative samples */
2596 for( j = 0; j < 3; j++ )
2598 if( sample[ j ] < 0.0f )
2604 /* nick an average value from the neighbors */
2605 VectorClear( sample );
2606 VectorClear( dirSample );
2609 /* fixme: why is this disabled?? */
2610 for( sy = (y - 1); sy <= (y + 1); sy++ )
2612 if( sy < 0 || sy >= lm->h )
2615 for( sx = (x - 1); sx <= (x + 1); sx++ )
2617 if( sx < 0 || sx >= lm->w || (sx == x && sy == y) )
2620 /* get neighbor's particulars */
2621 luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2622 if( luxel[ 3 ] < 0.0f )
2624 VectorAdd( sample, luxel, sample );
2625 samples += luxel[ 3 ];
2630 if( samples == 0.0f )
2632 VectorSet( sample, -1.0f, -1.0f, -1.0f );
2640 /* fix negative samples */
2641 for( j = 0; j < 3; j++ )
2643 if( sample[ j ] < 0.0f )
2649 /* scale the sample */
2650 VectorScale( sample, (1.0f / samples), sample );
2652 /* store the sample in the radiosity luxels */
2655 radLuxel = RAD_LUXEL( lightmapNum, x, y );
2656 VectorCopy( sample, radLuxel );
2658 /* if only storing bounced light, early out here */
2659 if( bounceOnly && !bouncing )
2663 /* store the sample in the bsp luxels */
2664 bspLuxel = BSP_LUXEL( lightmapNum, x, y );
2665 bspDeluxel = BSP_DELUXEL( x, y );
2667 VectorAdd( bspLuxel, sample, bspLuxel );
2668 if( deluxemap && lightmapNum == 0 )
2669 VectorAdd( bspDeluxel, dirSample, bspDeluxel );
2671 /* add color to bounds for solid checking */
2672 if( samples > 0.0f )
2673 AddPointToBounds( bspLuxel, colorMins, colorMaxs );
2677 /* set solid color */
2678 lm->solid[ lightmapNum ] = qfalse;
2679 VectorAdd( colorMins, colorMaxs, lm->solidColor[ lightmapNum ] );
2680 VectorScale( lm->solidColor[ lightmapNum ], 0.5f, lm->solidColor[ lightmapNum ] );
2682 /* nocollapse prevents solid lightmaps */
2683 if( noCollapse == qfalse )
2685 /* check solid color */
2686 VectorSubtract( colorMaxs, colorMins, sample );
2687 if( (sample[ 0 ] <= SOLID_EPSILON && sample[ 1 ] <= SOLID_EPSILON && sample[ 2 ] <= SOLID_EPSILON) ||
2688 (lm->w <= 2 && lm->h <= 2) ) /* small lightmaps get forced to solid color */
2691 VectorCopy( colorMins, lm->solidColor[ lightmapNum ] );
2692 lm->solid[ lightmapNum ] = qtrue;
2693 numSolidLightmaps++;
2696 /* if all lightmaps aren't solid, then none of them are solid */
2697 if( lm->solid[ lightmapNum ] != lm->solid[ 0 ] )
2699 for( y = 0; y < MAX_LIGHTMAPS; y++ )
2701 if( lm->solid[ y ] )
2702 numSolidLightmaps--;
2703 lm->solid[ y ] = qfalse;
2708 /* wrap bsp luxels if necessary */
2711 for( y = 0; y < lm->h; y++ )
2713 bspLuxel = BSP_LUXEL( lightmapNum, 0, y );
2714 bspLuxel2 = BSP_LUXEL( lightmapNum, lm->w - 1, y );
2715 VectorAdd( bspLuxel, bspLuxel2, bspLuxel );
2716 VectorScale( bspLuxel, 0.5f, bspLuxel );
2717 VectorCopy( bspLuxel, bspLuxel2 );
2718 if( deluxemap && lightmapNum == 0 )
2720 bspDeluxel = BSP_DELUXEL( 0, y );
2721 bspDeluxel2 = BSP_DELUXEL( lm->w - 1, y );
2722 VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel );
2723 VectorScale( bspDeluxel, 0.5f, bspDeluxel );
2724 VectorCopy( bspDeluxel, bspDeluxel2 );
2730 for( x = 0; x < lm->w; x++ )
2732 bspLuxel = BSP_LUXEL( lightmapNum, x, 0 );
2733 bspLuxel2 = BSP_LUXEL( lightmapNum, x, lm->h - 1 );
2734 VectorAdd( bspLuxel, bspLuxel2, bspLuxel );
2735 VectorScale( bspLuxel, 0.5f, bspLuxel );
2736 VectorCopy( bspLuxel, bspLuxel2 );
2737 if( deluxemap && lightmapNum == 0 )
2739 bspDeluxel = BSP_DELUXEL( x, 0 );
2740 bspDeluxel2 = BSP_DELUXEL( x, lm->h - 1 );
2741 VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel );
2742 VectorScale( bspDeluxel, 0.5f, bspDeluxel );
2743 VectorCopy( bspDeluxel, bspDeluxel2 );
2750 /* -----------------------------------------------------------------
2751 convert modelspace deluxemaps to tangentspace
2752 ----------------------------------------------------------------- */
2756 if( deluxemap && deluxemode == 1)
2758 vec3_t worldUp, myNormal, myTangent, myBinormal;
2761 Sys_Printf( "converting..." );
2763 for( i = 0; i < numRawLightmaps; i++ )
2766 lm = &rawLightmaps[ i ];
2768 /* walk lightmap samples */
2769 for( y = 0; y < lm->sh; y++ )
2771 for( x = 0; x < lm->sw; x++ )
2773 /* get normal and deluxel */
2774 normal = SUPER_NORMAL(x, y);
2775 cluster = SUPER_CLUSTER(x, y);
2776 bspDeluxel = BSP_DELUXEL( x, y );
2777 deluxel = SUPER_DELUXEL( x, y );
2780 VectorSet( myNormal, normal[0], normal[1], normal[2] );
2782 /* get tangent vectors */
2783 if( myNormal[ 0 ] == 0.0f && myNormal[ 1 ] == 0.0f )
2785 if( myNormal[ 2 ] == 1.0f )
2787 VectorSet( myTangent, 1.0f, 0.0f, 0.0f );
2788 VectorSet( myBinormal, 0.0f, 1.0f, 0.0f );
2790 else if( myNormal[ 2 ] == -1.0f )
2792 VectorSet( myTangent, -1.0f, 0.0f, 0.0f );
2793 VectorSet( myBinormal, 0.0f, 1.0f, 0.0f );
2798 VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
2799 CrossProduct( myNormal, worldUp, myTangent );
2800 VectorNormalize( myTangent, myTangent );
2801 CrossProduct( myTangent, myNormal, myBinormal );
2802 VectorNormalize( myBinormal, myBinormal );
2805 /* project onto plane */
2806 dist = -DotProduct(myTangent, myNormal);
2807 VectorMA(myTangent, dist, myNormal, myTangent);
2808 dist = -DotProduct(myBinormal, myNormal);
2809 VectorMA(myBinormal, dist, myNormal, myBinormal);
2812 VectorNormalize( myTangent, myTangent );
2813 VectorNormalize( myBinormal, myBinormal );
2815 /* convert modelspace deluxel to tangentspace */
2816 dirSample[0] = bspDeluxel[0];
2817 dirSample[1] = bspDeluxel[1];
2818 dirSample[2] = bspDeluxel[2];
2819 VectorNormalize(dirSample, dirSample);
2821 /* fix tangents to world matrix */
2822 if (myNormal[0] > 0 || myNormal[1] < 0 || myNormal[2] < 0)
2823 VectorNegate(myTangent, myTangent);
2825 /* build tangentspace vectors */
2826 bspDeluxel[0] = DotProduct(dirSample, myTangent);
2827 bspDeluxel[1] = DotProduct(dirSample, myBinormal);
2828 bspDeluxel[2] = DotProduct(dirSample, myNormal);
2835 /* -----------------------------------------------------------------
2837 ----------------------------------------------------------------- */
2839 #ifdef sdfsdfwq312323
2841 Sys_Printf( "blending..." );
2843 for( i = 0; i < numRawLightmaps; i++ )
2849 lm = &rawLightmaps[ i ];
2851 /* walk individual lightmaps */
2852 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2855 if( lm->superLuxels[ lightmapNum ] == NULL )
2858 /* walk lightmap samples */
2859 for( y = 0; y < lm->sh; y++ )
2861 for( x = 0; x < lm->sw; x++ )
2864 bspLuxel = BSP_LUXEL( lightmapNum, x, y );
2867 VectorNormalize(bspLuxel, myColor);
2868 myBrightness = VectorLength(bspLuxel);
2869 myBrightness *= (1 / 127.0f);
2870 myBrightness = myBrightness*myBrightness;
2871 myBrightness *= 127.0f;
2872 VectorScale(myColor, myBrightness, bspLuxel);
2879 /* -----------------------------------------------------------------
2880 collapse non-unique lightmaps
2881 ----------------------------------------------------------------- */
2883 if( noCollapse == qfalse && deluxemap == qfalse )
2886 Sys_Printf( "collapsing..." );
2888 /* set all twin refs to null */
2889 for( i = 0; i < numRawLightmaps; i++ )
2891 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2893 rawLightmaps[ i ].twins[ lightmapNum ] = NULL;
2894 rawLightmaps[ i ].twinNums[ lightmapNum ] = -1;
2895 rawLightmaps[ i ].numStyledTwins = 0;
2899 /* walk the list of raw lightmaps */
2900 for( i = 0; i < numRawLightmaps; i++ )
2903 lm = &rawLightmaps[ i ];
2905 /* walk lightmaps */
2906 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2909 if( lm->bspLuxels[ lightmapNum ] == NULL ||
2910 lm->twins[ lightmapNum ] != NULL )
2913 /* find all lightmaps that are virtually identical to this one */
2914 for( j = i + 1; j < numRawLightmaps; j++ )
2917 lm2 = &rawLightmaps[ j ];
2919 /* walk lightmaps */
2920 for( lightmapNum2 = 0; lightmapNum2 < MAX_LIGHTMAPS; lightmapNum2++ )
2923 if( lm2->bspLuxels[ lightmapNum2 ] == NULL ||
2924 lm2->twins[ lightmapNum2 ] != NULL )
2928 if( CompareBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ) )
2930 /* merge and set twin */
2931 if( MergeBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ) )
2933 lm2->twins[ lightmapNum2 ] = lm;
2934 lm2->twinNums[ lightmapNum2 ] = lightmapNum;
2936 numTwinLuxels += (lm->w * lm->h);
2938 /* count styled twins */
2939 if( lightmapNum > 0 )
2940 lm->numStyledTwins++;
2949 /* -----------------------------------------------------------------
2950 sort raw lightmaps by shader
2951 ----------------------------------------------------------------- */
2954 Sys_Printf( "sorting..." );
2956 /* allocate a new sorted list */
2957 if( sortLightmaps == NULL )
2958 sortLightmaps = safe_malloc( numRawLightmaps * sizeof( int ) );
2960 /* fill it out and sort it */
2961 for( i = 0; i < numRawLightmaps; i++ )
2962 sortLightmaps[ i ] = i;
2963 qsort( sortLightmaps, numRawLightmaps, sizeof( int ), CompareRawLightmap );
2965 /* -----------------------------------------------------------------
2966 allocate output lightmaps
2967 ----------------------------------------------------------------- */
2970 Sys_Printf( "allocating..." );
2972 /* kill all existing output lightmaps */
2973 if( outLightmaps != NULL )
2975 for( i = 0; i < numOutLightmaps; i++ )
2977 free( outLightmaps[ i ].lightBits );
2978 free( outLightmaps[ i ].bspLightBytes );
2980 free( outLightmaps );
2981 outLightmaps = NULL;
2984 numLightmapShaders = 0;
2985 numOutLightmaps = 0;
2986 numBSPLightmaps = 0;
2987 numExtLightmaps = 0;
2989 /* find output lightmap */
2990 for( i = 0; i < numRawLightmaps; i++ )
2992 lm = &rawLightmaps[ sortLightmaps[ i ] ];
2993 FindOutLightmaps( lm );
2996 /* set output numbers in twinned lightmaps */
2997 for( i = 0; i < numRawLightmaps; i++ )
3000 lm = &rawLightmaps[ sortLightmaps[ i ] ];
3002 /* walk lightmaps */
3003 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3006 lm2 = lm->twins[ lightmapNum ];
3009 lightmapNum2 = lm->twinNums[ lightmapNum ];
3011 /* find output lightmap from twin */
3012 lm->outLightmapNums[ lightmapNum ] = lm2->outLightmapNums[ lightmapNum2 ];
3013 lm->lightmapX[ lightmapNum ] = lm2->lightmapX[ lightmapNum2 ];
3014 lm->lightmapY[ lightmapNum ] = lm2->lightmapY[ lightmapNum2 ];
3018 /* -----------------------------------------------------------------
3019 store output lightmaps
3020 ----------------------------------------------------------------- */
3023 Sys_Printf( "storing..." );
3025 /* count the bsp lightmaps and allocate space */
3026 if( bspLightBytes != NULL )
3027 free( bspLightBytes );
3028 if( numBSPLightmaps == 0 || externalLightmaps )
3030 numBSPLightBytes = 0;
3031 bspLightBytes = NULL;
3035 numBSPLightBytes = (numBSPLightmaps * game->lightmapSize * game->lightmapSize * 3);
3036 bspLightBytes = safe_malloc( numBSPLightBytes );
3037 memset( bspLightBytes, 0, numBSPLightBytes );
3040 /* walk the list of output lightmaps */
3041 for( i = 0; i < numOutLightmaps; i++ )
3043 /* get output lightmap */
3044 olm = &outLightmaps[ i ];
3046 /* fill output lightmap */
3048 FillOutLightmap(olm);
3050 /* is this a valid bsp lightmap? */
3051 if( olm->lightmapNum >= 0 && !externalLightmaps )
3053 /* copy lighting data */
3054 lb = bspLightBytes + (olm->lightmapNum * game->lightmapSize * game->lightmapSize * 3);
3055 memcpy( lb, olm->bspLightBytes, game->lightmapSize * game->lightmapSize * 3 );
3057 /* copy direction data */
3060 lb = bspLightBytes + ((olm->lightmapNum + 1) * game->lightmapSize * game->lightmapSize * 3);
3061 memcpy( lb, olm->bspDirBytes, game->lightmapSize * game->lightmapSize * 3 );
3065 /* external lightmap? */
3066 if( olm->lightmapNum < 0 || olm->extLightmapNum >= 0 || externalLightmaps )
3068 /* make a directory for the lightmaps */
3071 /* set external lightmap number */
3072 olm->extLightmapNum = numExtLightmaps;
3074 /* write lightmap */
3075 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
3076 Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
3077 WriteTGA24( filename, olm->bspLightBytes, olm->customWidth, olm->customHeight, qtrue );
3080 /* write deluxemap */
3083 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
3084 Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
3085 WriteTGA24( filename, olm->bspDirBytes, olm->customWidth, olm->customHeight, qtrue );
3088 if( debugDeluxemap )
3089 olm->extLightmapNum++;
3094 if( numExtLightmaps > 0 )
3097 /* delete unused external lightmaps */
3098 for( i = numExtLightmaps; i; i++ )
3100 /* determine if file exists */
3101 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, i );
3102 if( !FileExists( filename ) )
3109 /* -----------------------------------------------------------------
3110 project the lightmaps onto the bsp surfaces
3111 ----------------------------------------------------------------- */
3114 Sys_Printf( "projecting..." );
3116 /* walk the list of surfaces */
3117 for( i = 0; i < numBSPDrawSurfaces; i++ )
3119 /* get the surface and info */
3120 ds = &bspDrawSurfaces[ i ];
3121 info = &surfaceInfos[ i ];
3125 /* handle surfaces with identical parent */
3126 if( info->parentSurfaceNum >= 0 )
3128 /* preserve original data and get parent */
3129 parent = &bspDrawSurfaces[ info->parentSurfaceNum ];
3130 memcpy( &dsTemp, ds, sizeof( *ds ) );
3132 /* overwrite child with parent data */
3133 memcpy( ds, parent, sizeof( *ds ) );
3135 /* restore key parts */
3136 ds->fogNum = dsTemp.fogNum;
3137 ds->firstVert = dsTemp.firstVert;
3138 ds->firstIndex = dsTemp.firstIndex;
3139 memcpy( ds->lightmapVecs, dsTemp.lightmapVecs, sizeof( dsTemp.lightmapVecs ) );
3141 /* set vertex data */
3142 dv = &bspDrawVerts[ ds->firstVert ];
3143 dvParent = &bspDrawVerts[ parent->firstVert ];
3144 for( j = 0; j < ds->numVerts; j++ )
3146 memcpy( dv[ j ].lightmap, dvParent[ j ].lightmap, sizeof( dv[ j ].lightmap ) );
3147 memcpy( dv[ j ].color, dvParent[ j ].color, sizeof( dv[ j ].color ) );
3154 /* handle vertex lit or approximated surfaces */
3155 else if( lm == NULL || lm->outLightmapNums[ 0 ] < 0 )
3157 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3159 ds->lightmapNum[ lightmapNum ] = -3;
3160 ds->lightmapStyles[ lightmapNum ] = ds->vertexStyles[ lightmapNum ];
3164 /* handle lightmapped surfaces */
3167 /* walk lightmaps */
3168 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3171 ds->lightmapStyles[ lightmapNum ] = lm->styles[ lightmapNum ];
3173 /* handle unused style */
3174 if( lm->styles[ lightmapNum ] == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 )
3176 ds->lightmapNum[ lightmapNum ] = -3;
3180 /* get output lightmap */
3181 olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
3183 /* set bsp lightmap number */
3184 ds->lightmapNum[ lightmapNum ] = olm->lightmapNum;
3186 /* deluxemap debugging makes the deluxemap visible */
3187 if( deluxemap && debugDeluxemap && lightmapNum == 0 )
3188 ds->lightmapNum[ lightmapNum ]++;
3190 /* calc lightmap origin in texture space */
3191 lmx = (float) lm->lightmapX[ lightmapNum ] / (float) olm->customWidth;
3192 lmy = (float) lm->lightmapY[ lightmapNum ] / (float) olm->customHeight;
3194 /* calc lightmap st coords */
3195 dv = &bspDrawVerts[ ds->firstVert ];
3196 ydv = &yDrawVerts[ ds->firstVert ];
3197 for( j = 0; j < ds->numVerts; j++ )
3199 if( lm->solid[ lightmapNum ] )
3201 dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + (0.5f / (float) olm->customWidth);
3202 dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + (0.5f / (float) olm->customWidth);
3206 dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + (ydv[ j ].lightmap[ 0 ][ 0 ] / (superSample * olm->customWidth));
3207 dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + (ydv[ j ].lightmap[ 0 ][ 1 ] / (superSample * olm->customHeight));
3213 /* store vertex colors */
3214 dv = &bspDrawVerts[ ds->firstVert ];
3215 for( j = 0; j < ds->numVerts; j++ )
3217 /* walk lightmaps */
3218 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3220 /* handle unused style */
3221 if( ds->vertexStyles[ lightmapNum ] == LS_NONE )
3222 VectorClear( color );
3225 /* get vertex color */
3226 luxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + j );
3227 VectorCopy( luxel, color );
3229 /* set minimum light */
3230 if( lightmapNum == 0 )
3232 for( k = 0; k < 3; k++ )
3233 if( color[ k ] < minVertexLight[ k ] )
3234 color[ k ] = minVertexLight[ k ];
3238 /* store to bytes */
3239 if( !info->si->noVertexLight )
3240 ColorToBytes( color, dv[ j ].color[ lightmapNum ], info->si->vertexScale );
3244 /* surfaces with styled lightmaps and a style marker get a custom generated shader (fixme: make this work with external lightmaps) */
3245 if( olm != NULL && lm != NULL && lm->styles[ 1 ] != LS_NONE && game->load != LoadRBSPFile ) //% info->si->styleMarker > 0 )
3248 char key[ 32 ], styleStage[ 512 ], styleStages[ 4096 ], rgbGen[ 128 ], alphaGen[ 128 ];
3252 sprintf( styleStages, "\n\t// Q3Map2 custom lightstyle stage(s)\n" );
3253 dv = &bspDrawVerts[ ds->firstVert ];
3255 /* depthFunc equal? */
3256 if( info->si->styleMarker == 2 || info->si->implicitMap == IM_MASKED )
3261 /* generate stages for styled lightmaps */
3262 for( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3265 style = lm->styles[ lightmapNum ];
3266 if( style == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 )
3269 /* get output lightmap */
3270 olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
3273 if( lm->outLightmapNums[ lightmapNum ] == lm->outLightmapNums[ 0 ] )
3274 strcpy( lightmapName, "$lightmap" );
3276 sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
3278 /* get rgbgen string */
3279 if( rgbGenValues[ style ] == NULL )
3281 sprintf( key, "_style%drgbgen", style );
3282 rgbGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
3283 if( rgbGenValues[ style ][ 0 ] == '\0' )
3284 rgbGenValues[ style ] = "wave noise 0.5 1 0 5.37";
3287 if( rgbGenValues[ style ][ 0 ] != '\0' )
3288 sprintf( rgbGen, "\t\trgbGen %s // style %d\n", rgbGenValues[ style ], style );
3292 /* get alphagen string */
3293 if( alphaGenValues[ style ] == NULL )
3295 sprintf( key, "_style%dalphagen", style );
3296 alphaGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
3298 if( alphaGenValues[ style ][ 0 ] != '\0' )
3299 sprintf( alphaGen, "\t\talphaGen %s // style %d\n", alphaGenValues[ style ], style );
3301 alphaGen[ 0 ] = '\0';
3303 /* calculate st offset */
3304 lmx = dv[ 0 ].lightmap[ lightmapNum ][ 0 ] - dv[ 0 ].lightmap[ 0 ][ 0 ];
3305 lmy = dv[ 0 ].lightmap[ lightmapNum ][ 1 ] - dv[ 0 ].lightmap[ 0 ][ 1 ];
3307 /* create additional stage */
3308 if( lmx == 0.0f && lmy == 0.0f )
3310 sprintf( styleStage, "\t{\n"
3311 "\t\tmap %s\n" /* lightmap */
3312 "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
3313 "%s" /* depthFunc equal */
3316 "\t\ttcGen lightmap\n"
3319 (dfEqual ? "\t\tdepthFunc equal\n" : ""),
3325 sprintf( styleStage, "\t{\n"
3326 "\t\tmap %s\n" /* lightmap */
3327 "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
3328 "%s" /* depthFunc equal */
3331 "\t\ttcGen lightmap\n"
3332 "\t\ttcMod transform 1 0 0 1 %1.5f %1.5f\n" /* st offset */
3335 (dfEqual ? "\t\tdepthFunc equal\n" : ""),
3343 strcat( styleStages, styleStage );
3346 /* create custom shader */
3347 if( info->si->styleMarker == 2 )
3348 csi = CustomShader( info->si, "q3map_styleMarker2", styleStages );
3350 csi = CustomShader( info->si, "q3map_styleMarker", styleStages );
3352 /* emit remap command */
3353 //% EmitVertexRemapShader( csi->shader, info->si->shader );
3356 //% Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
3357 ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3358 //% Sys_Printf( ")\n" );
3361 /* devise a custom shader for this surface (fixme: make this work with light styles) */
3362 else if( olm != NULL && lm != NULL && !externalLightmaps &&
3363 (olm->customWidth != game->lightmapSize || olm->customHeight != game->lightmapSize) )
3365 /* get output lightmap */
3366 olm = &outLightmaps[ lm->outLightmapNums[ 0 ] ];
3368 /* do some name mangling */
3369 sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
3371 /* create custom shader */
3372 csi = CustomShader( info->si, "$lightmap", lightmapName );
3375 //% Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
3376 ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3377 //% Sys_Printf( ")\n" );
3380 /* use the normal plain-jane shader */
3382 ds->shaderNum = EmitShader( info->si->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3386 Sys_Printf( "done.\n" );
3388 /* calc num stored */
3389 numStored = numBSPLightBytes / 3;
3390 efficiency = (numStored <= 0)
3392 : (float) numUsed / (float) numStored;
3395 Sys_Printf( "%9d luxels used\n", numUsed );
3396 Sys_Printf( "%9d luxels stored (%3.2f percent efficiency)\n", numStored, efficiency * 100.0f );
3397 Sys_Printf( "%9d solid surface lightmaps\n", numSolidLightmaps );
3398 Sys_Printf( "%9d identical surface lightmaps, using %d luxels\n", numTwins, numTwinLuxels );
3399 Sys_Printf( "%9d vertex forced surfaces\n", numSurfsVertexForced );
3400 Sys_Printf( "%9d vertex approximated surfaces\n", numSurfsVertexApproximated );
3401 Sys_Printf( "%9d BSP lightmaps\n", numBSPLightmaps );
3402 Sys_Printf( "%9d total lightmaps\n", numOutLightmaps );
3403 Sys_Printf( "%9d unique lightmap/shader combinations\n", numLightmapShaders );
3405 /* write map shader file */
3406 WriteMapShaderFile();