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[ *((int*) a) ].si;
295 bsi = surfaceInfos[ *((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 )
688 if(sampleSize != lm->sampleSize)
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[ *((int*) a) ];
865 bInfo = &surfaceInfos[ *((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 /* then lightmap sample size */
880 if( aInfo->sampleSize < bInfo->sampleSize )
882 else if( aInfo->sampleSize > bInfo->sampleSize )
885 /* then lightmap axis */
886 for( i = 0; i < 3; i++ )
888 if( aInfo->axis[ i ] < bInfo->axis[ i ] )
890 else if( aInfo->axis[ i ] > bInfo->axis[ i ] )
895 if( aInfo->plane == NULL && bInfo->plane != NULL )
897 else if( aInfo->plane != NULL && bInfo->plane == NULL )
899 else if( aInfo->plane != NULL && bInfo->plane != NULL )
901 for( i = 0; i < 4; i++ )
903 if( aInfo->plane[ i ] < bInfo->plane[ i ] )
905 else if( aInfo->plane[ i ] > bInfo->plane[ i ] )
910 /* then position in world */
911 for( i = 0; i < 3; i++ )
913 if( aInfo->mins[ i ] < bInfo->mins[ i ] )
915 else if( aInfo->mins[ i ] > bInfo->mins[ i ] )
919 /* these are functionally identical (this should almost never happen) */
926 SetupSurfaceLightmaps()
927 allocates lightmaps for every surface in the bsp that needs one
928 this depends on yDrawVerts being allocated
931 void SetupSurfaceLightmaps( void )
933 int i, j, k, s,num, num2;
936 bspDrawSurface_t *ds, *ds2;
937 surfaceInfo_t *info, *info2;
940 vec3_t mapSize, entityOrigin;
944 Sys_FPrintf( SYS_VRB, "--- SetupSurfaceLightmaps ---\n");
946 /* determine supersample amount */
947 if( superSample < 1 )
949 else if( superSample > 8 )
951 Sys_Printf( "WARNING: Insane supersampling amount (%d) detected.\n", superSample );
955 /* clear map bounds */
956 ClearBounds( mapMins, mapMaxs );
958 /* allocate a list of surface clusters */
959 numSurfaceClusters = 0;
960 maxSurfaceClusters = numBSPLeafSurfaces;
961 surfaceClusters = safe_malloc( maxSurfaceClusters * sizeof( *surfaceClusters ) );
962 memset( surfaceClusters, 0, maxSurfaceClusters * sizeof( *surfaceClusters ) );
964 /* allocate a list for per-surface info */
965 surfaceInfos = safe_malloc( numBSPDrawSurfaces * sizeof( *surfaceInfos ) );
966 memset( surfaceInfos, 0, numBSPDrawSurfaces * sizeof( *surfaceInfos ) );
967 for( i = 0; i < numBSPDrawSurfaces; i++ )
968 surfaceInfos[ i ].childSurfaceNum = -1;
970 /* allocate a list of surface indexes to be sorted */
971 sortSurfaces = safe_malloc( numBSPDrawSurfaces * sizeof( int ) );
972 memset( sortSurfaces, 0, numBSPDrawSurfaces * sizeof( int ) );
974 /* walk each model in the bsp */
975 for( i = 0; i < numBSPModels; i++ )
978 model = &bspModels[ i ];
980 /* walk the list of surfaces in this model and fill out the info structs */
981 for( j = 0; j < model->numBSPSurfaces; j++ )
983 /* make surface index */
984 num = model->firstBSPSurface + j;
986 /* copy index to sort list */
987 sortSurfaces[ num ] = num;
989 /* get surface and info */
990 ds = &bspDrawSurfaces[ num ];
991 info = &surfaceInfos[ num ];
993 /* set entity origin */
994 if( ds->numVerts > 0 )
995 VectorSubtract( yDrawVerts[ ds->firstVert ].xyz, bspDrawVerts[ ds->firstVert ].xyz, entityOrigin );
997 VectorClear( entityOrigin );
1000 info->modelindex = i;
1003 info->firstSurfaceCluster = numSurfaceClusters;
1005 /* get extra data */
1006 info->si = GetSurfaceExtraShaderInfo( num );
1007 if( info->si == NULL )
1008 info->si = ShaderInfoForShader( bspShaders[ ds->shaderNum ].shader );
1009 info->parentSurfaceNum = GetSurfaceExtraParentSurfaceNum( num );
1010 info->entityNum = GetSurfaceExtraEntityNum( num );
1011 info->castShadows = GetSurfaceExtraCastShadows( num );
1012 info->recvShadows = GetSurfaceExtraRecvShadows( num );
1013 info->sampleSize = GetSurfaceExtraSampleSize( num );
1014 info->longestCurve = GetSurfaceExtraLongestCurve( num );
1015 info->patchIterations = IterationsForCurve( info->longestCurve, patchSubdivisions );
1016 GetSurfaceExtraLightmapAxis( num, info->axis );
1019 if( info->parentSurfaceNum >= 0 )
1020 surfaceInfos[ info->parentSurfaceNum ].childSurfaceNum = j;
1022 /* determine surface bounds */
1023 ClearBounds( info->mins, info->maxs );
1024 for( k = 0; k < ds->numVerts; k++ )
1026 AddPointToBounds( yDrawVerts[ ds->firstVert + k ].xyz, mapMins, mapMaxs );
1027 AddPointToBounds( yDrawVerts[ ds->firstVert + k ].xyz, info->mins, info->maxs );
1030 /* find all the bsp clusters the surface falls into */
1031 for( k = 0; k < numBSPLeafs; k++ )
1034 leaf = &bspLeafs[ k ];
1037 if( leaf->mins[ 0 ] > info->maxs[ 0 ] || leaf->maxs[ 0 ] < info->mins[ 0 ] ||
1038 leaf->mins[ 1 ] > info->maxs[ 1 ] || leaf->maxs[ 1 ] < info->mins[ 1 ] ||
1039 leaf->mins[ 2 ] > info->maxs[ 2 ] || leaf->maxs[ 2 ] < info->mins[ 2 ] )
1042 /* test leaf surfaces */
1043 for( s = 0; s < leaf->numBSPLeafSurfaces; s++ )
1045 if( bspLeafSurfaces[ leaf->firstBSPLeafSurface + s ] == num )
1047 if( numSurfaceClusters >= maxSurfaceClusters )
1048 Error( "maxSurfaceClusters exceeded" );
1049 surfaceClusters[ numSurfaceClusters ] = leaf->cluster;
1050 numSurfaceClusters++;
1051 info->numSurfaceClusters++;
1056 /* determine if surface is planar */
1057 if( VectorLength( ds->lightmapVecs[ 2 ] ) > 0.0f )
1060 info->plane = safe_malloc( 4 * sizeof( float ) );
1061 VectorCopy( ds->lightmapVecs[ 2 ], info->plane );
1062 info->plane[ 3 ] = DotProduct( yDrawVerts[ ds->firstVert ].xyz, info->plane );
1065 /* determine if surface requires a lightmap */
1066 if( ds->surfaceType == MST_TRIANGLE_SOUP ||
1067 ds->surfaceType == MST_FOLIAGE ||
1068 (info->si->compileFlags & C_VERTEXLIT) )
1069 numSurfsVertexLit++;
1072 numSurfsLightmapped++;
1073 info->hasLightmap = qtrue;
1078 /* find longest map distance */
1079 VectorSubtract( mapMaxs, mapMins, mapSize );
1080 maxMapDistance = VectorLength( mapSize );
1082 /* sort the surfaces info list */
1083 qsort( sortSurfaces, numBSPDrawSurfaces, sizeof( int ), CompareSurfaceInfo );
1085 /* allocate a list of surfaces that would go into raw lightmaps */
1086 numLightSurfaces = 0;
1087 lightSurfaces = safe_malloc( numSurfsLightmapped * sizeof( int ) );
1088 memset( lightSurfaces, 0, numSurfsLightmapped * sizeof( int ) );
1090 /* allocate a list of raw lightmaps */
1091 numRawSuperLuxels = 0;
1092 numRawLightmaps = 0;
1093 rawLightmaps = safe_malloc( numSurfsLightmapped * sizeof( *rawLightmaps ) );
1094 memset( rawLightmaps, 0, numSurfsLightmapped * sizeof( *rawLightmaps ) );
1096 /* walk the list of sorted surfaces */
1097 for( i = 0; i < numBSPDrawSurfaces; i++ )
1099 /* get info and attempt early out */
1100 num = sortSurfaces[ i ];
1101 ds = &bspDrawSurfaces[ num ];
1102 info = &surfaceInfos[ num ];
1103 if( info->hasLightmap == qfalse || info->lm != NULL || info->parentSurfaceNum >= 0 )
1106 /* allocate a new raw lightmap */
1107 lm = &rawLightmaps[ numRawLightmaps ];
1111 lm->splotchFix = info->si->splotchFix;
1112 lm->firstLightSurface = numLightSurfaces;
1113 lm->numLightSurfaces = 0;
1114 /* vortex: multiply lightmap sample size by -samplescale */
1115 if (sampleScale > 0)
1116 lm->sampleSize = info->sampleSize*sampleScale;
1118 lm->sampleSize = info->sampleSize;
1119 lm->actualSampleSize = lm->sampleSize;
1120 lm->entityNum = info->entityNum;
1121 lm->recvShadows = info->recvShadows;
1122 lm->brightness = info->si->lmBrightness;
1123 lm->filterRadius = info->si->lmFilterRadius;
1124 VectorCopy(info->si->floodlightRGB, lm->floodlightRGB);
1125 lm->floodlightDistance = info->si->floodlightDistance;
1126 lm->floodlightIntensity = info->si->floodlightIntensity;
1127 lm->floodlightDirectionScale = info->si->floodlightDirectionScale;
1128 VectorCopy( info->axis, lm->axis );
1129 lm->plane = info->plane;
1130 VectorCopy( info->mins, lm->mins );
1131 VectorCopy( info->maxs, lm->maxs );
1133 lm->customWidth = info->si->lmCustomWidth;
1134 lm->customHeight = info->si->lmCustomHeight;
1136 /* add the surface to the raw lightmap */
1137 AddSurfaceToRawLightmap( num, lm );
1140 /* do an exhaustive merge */
1144 /* walk the list of surfaces again */
1146 for( j = i + 1; j < numBSPDrawSurfaces && lm->finished == qfalse; j++ )
1148 /* get info and attempt early out */
1149 num2 = sortSurfaces[ j ];
1150 ds2 = &bspDrawSurfaces[ num2 ];
1151 info2 = &surfaceInfos[ num2 ];
1152 if( info2->hasLightmap == qfalse || info2->lm != NULL )
1155 /* add the surface to the raw lightmap */
1156 if( AddSurfaceToRawLightmap( num2, lm ) )
1164 lm->numLightSurfaces--;
1170 /* finish the lightmap and allocate the various buffers */
1171 FinishRawLightmap( lm );
1174 /* allocate vertex luxel storage */
1175 for( k = 0; k < MAX_LIGHTMAPS; k++ )
1177 vertexLuxels[ k ] = safe_malloc( numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
1178 memset( vertexLuxels[ k ], 0, numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
1179 radVertexLuxels[ k ] = safe_malloc( numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
1180 memset( radVertexLuxels[ k ], 0, numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
1183 /* emit some stats */
1184 Sys_FPrintf( SYS_VRB, "%9d surfaces\n", numBSPDrawSurfaces );
1185 Sys_FPrintf( SYS_VRB, "%9d raw lightmaps\n", numRawLightmaps );
1186 Sys_FPrintf( SYS_VRB, "%9d surfaces vertex lit\n", numSurfsVertexLit );
1187 Sys_FPrintf( SYS_VRB, "%9d surfaces lightmapped\n", numSurfsLightmapped );
1188 Sys_FPrintf( SYS_VRB, "%9d planar surfaces lightmapped\n", numPlanarsLightmapped );
1189 Sys_FPrintf( SYS_VRB, "%9d non-planar surfaces lightmapped\n", numNonPlanarsLightmapped );
1190 Sys_FPrintf( SYS_VRB, "%9d patches lightmapped\n", numPatchesLightmapped );
1191 Sys_FPrintf( SYS_VRB, "%9d planar patches lightmapped\n", numPlanarPatchesLightmapped );
1197 StitchSurfaceLightmaps()
1198 stitches lightmap edges
1199 2002-11-20 update: use this func only for stitching nonplanar patch lightmap seams
1202 #define MAX_STITCH_CANDIDATES 32
1203 #define MAX_STITCH_LUXELS 64
1205 void StitchSurfaceLightmaps( void )
1207 int i, j, x, y, x2, y2, *cluster, *cluster2,
1208 numStitched, numCandidates, numLuxels, f, fOld, start;
1209 rawLightmap_t *lm, *a, *b, *c[ MAX_STITCH_CANDIDATES ];
1210 float *luxel, *luxel2, *origin, *origin2, *normal, *normal2,
1211 sampleSize, average[ 3 ], totalColor, ootc, *luxels[ MAX_STITCH_LUXELS ];
1214 /* disabled for now */
1218 Sys_Printf( "--- StitchSurfaceLightmaps ---\n");
1222 start = I_FloatTime();
1224 /* walk the list of raw lightmaps */
1226 for( i = 0; i < numRawLightmaps; i++ )
1228 /* print pacifier */
1229 f = 10 * i / numRawLightmaps;
1233 Sys_Printf( "%i...", f );
1236 /* get lightmap a */
1237 a = &rawLightmaps[ i ];
1239 /* walk rest of lightmaps */
1241 for( j = i + 1; j < numRawLightmaps && numCandidates < MAX_STITCH_CANDIDATES; j++ )
1243 /* get lightmap b */
1244 b = &rawLightmaps[ j ];
1246 /* test bounding box */
1247 if( a->mins[ 0 ] > b->maxs[ 0 ] || a->maxs[ 0 ] < b->mins[ 0 ] ||
1248 a->mins[ 1 ] > b->maxs[ 1 ] || a->maxs[ 1 ] < b->mins[ 1 ] ||
1249 a->mins[ 2 ] > b->maxs[ 2 ] || a->maxs[ 2 ] < b->mins[ 2 ] )
1253 c[ numCandidates++ ] = b;
1257 for( y = 0; y < a->sh; y++ )
1259 for( x = 0; x < a->sw; x++ )
1261 /* ignore unmapped/unlit luxels */
1263 cluster = SUPER_CLUSTER( x, y );
1264 if( *cluster == CLUSTER_UNMAPPED )
1266 luxel = SUPER_LUXEL( 0, x, y );
1267 if( luxel[ 3 ] <= 0.0f )
1270 /* get particulars */
1271 origin = SUPER_ORIGIN( x, y );
1272 normal = SUPER_NORMAL( x, y );
1274 /* walk candidate list */
1275 for( j = 0; j < numCandidates; j++ )
1281 /* set samplesize to the smaller of the pair */
1282 sampleSize = 0.5f * (a->actualSampleSize < b->actualSampleSize ? a->actualSampleSize : b->actualSampleSize);
1284 /* test bounding box */
1285 if( origin[ 0 ] < (b->mins[ 0 ] - sampleSize) || (origin[ 0 ] > b->maxs[ 0 ] + sampleSize) ||
1286 origin[ 1 ] < (b->mins[ 1 ] - sampleSize) || (origin[ 1 ] > b->maxs[ 1 ] + sampleSize) ||
1287 origin[ 2 ] < (b->mins[ 2 ] - sampleSize) || (origin[ 2 ] > b->maxs[ 2 ] + sampleSize) )
1290 /* walk candidate luxels */
1291 VectorClear( average );
1294 for( y2 = 0; y2 < b->sh && numLuxels < MAX_STITCH_LUXELS; y2++ )
1296 for( x2 = 0; x2 < b->sw && numLuxels < MAX_STITCH_LUXELS; x2++ )
1298 /* ignore same luxels */
1299 if( a == b && abs( x - x2 ) <= 1 && abs( y - y2 ) <= 1 )
1302 /* ignore unmapped/unlit luxels */
1303 cluster2 = SUPER_CLUSTER( x2, y2 );
1304 if( *cluster2 == CLUSTER_UNMAPPED )
1306 luxel2 = SUPER_LUXEL( 0, x2, y2 );
1307 if( luxel2[ 3 ] <= 0.0f )
1310 /* get particulars */
1311 origin2 = SUPER_ORIGIN( x2, y2 );
1312 normal2 = SUPER_NORMAL( x2, y2 );
1315 if( DotProduct( normal, normal2 ) < 0.5f )
1319 if( fabs( origin[ 0 ] - origin2[ 0 ] ) > sampleSize ||
1320 fabs( origin[ 1 ] - origin2[ 1 ] ) > sampleSize ||
1321 fabs( origin[ 2 ] - origin2[ 2 ] ) > sampleSize )
1325 //% VectorSet( luxel2, 255, 0, 255 );
1326 luxels[ numLuxels++ ] = luxel2;
1327 VectorAdd( average, luxel2, average );
1328 totalColor += luxel2[ 3 ];
1333 if( numLuxels == 0 )
1337 ootc = 1.0f / totalColor;
1338 VectorScale( average, ootc, luxel );
1346 /* emit statistics */
1347 Sys_Printf( " (%i)\n", (int) (I_FloatTime() - start) );
1348 Sys_FPrintf( SYS_VRB, "%9d luxels stitched\n", numStitched );
1355 compares two surface lightmaps' bsp luxels, ignoring occluded luxels
1358 #define SOLID_EPSILON 0.0625
1359 #define LUXEL_TOLERANCE 0.0025
1360 #define LUXEL_COLOR_FRAC 0.001302083 /* 1 / 3 / 256 */
1362 static qboolean CompareBSPLuxels( rawLightmap_t *a, int aNum, rawLightmap_t *b, int bNum )
1366 double delta, total, rd, gd, bd;
1367 float *aLuxel, *bLuxel;
1370 /* styled lightmaps will never be collapsed to non-styled lightmaps when there is _minlight */
1371 if( (minLight[ 0 ] || minLight[ 1 ] || minLight[ 2 ]) &&
1372 ((aNum == 0 && bNum != 0) || (aNum != 0 && bNum == 0)) )
1376 if( a->customWidth != b->customWidth || a->customHeight != b->customHeight ||
1377 a->brightness != b->brightness ||
1378 a->solid[ aNum ] != b->solid[ bNum ] ||
1379 a->bspLuxels[ aNum ] == NULL || b->bspLuxels[ bNum ] == NULL )
1382 /* compare solid color lightmaps */
1383 if( a->solid[ aNum ] && b->solid[ bNum ] )
1386 rd = fabs( a->solidColor[ aNum ][ 0 ] - b->solidColor[ bNum ][ 0 ] );
1387 gd = fabs( a->solidColor[ aNum ][ 1 ] - b->solidColor[ bNum ][ 1 ] );
1388 bd = fabs( a->solidColor[ aNum ][ 2 ] - b->solidColor[ bNum ][ 2 ] );
1391 if( rd > SOLID_EPSILON || gd > SOLID_EPSILON|| bd > SOLID_EPSILON )
1398 /* compare nonsolid lightmaps */
1399 if( a->w != b->w || a->h != b->h )
1402 /* compare luxels */
1405 for( y = 0; y < a->h; y++ )
1407 for( x = 0; x < a->w; x++ )
1409 /* increment total */
1413 lm = a; aLuxel = BSP_LUXEL( aNum, x, y );
1414 lm = b; bLuxel = BSP_LUXEL( bNum, x, y );
1416 /* ignore unused luxels */
1417 if( aLuxel[ 0 ] < 0 || bLuxel[ 0 ] < 0 )
1421 rd = fabs( aLuxel[ 0 ] - bLuxel[ 0 ] );
1422 gd = fabs( aLuxel[ 1 ] - bLuxel[ 1 ] );
1423 bd = fabs( aLuxel[ 2 ] - bLuxel[ 2 ] );
1425 /* 2003-09-27: compare individual luxels */
1426 if( rd > 3.0 || gd > 3.0 || bd > 3.0 )
1429 /* compare (fixme: take into account perceptual differences) */
1430 delta += rd * LUXEL_COLOR_FRAC;
1431 delta += gd * LUXEL_COLOR_FRAC;
1432 delta += bd * LUXEL_COLOR_FRAC;
1434 /* is the change too high? */
1435 if( total > 0.0 && ((delta / total) > LUXEL_TOLERANCE) )
1440 /* made it this far, they must be identical (or close enough) */
1448 merges two surface lightmaps' bsp luxels, overwriting occluded luxels
1451 static qboolean MergeBSPLuxels( rawLightmap_t *a, int aNum, rawLightmap_t *b, int bNum )
1455 float luxel[ 3 ], *aLuxel, *bLuxel;
1459 if( a->customWidth != b->customWidth || a->customHeight != b->customHeight ||
1460 a->brightness != b->brightness ||
1461 a->solid[ aNum ] != b->solid[ bNum ] ||
1462 a->bspLuxels[ aNum ] == NULL || b->bspLuxels[ bNum ] == NULL )
1465 /* compare solid lightmaps */
1466 if( a->solid[ aNum ] && b->solid[ bNum ] )
1469 VectorAdd( a->solidColor[ aNum ], b->solidColor[ bNum ], luxel );
1470 VectorScale( luxel, 0.5f, luxel );
1473 VectorCopy( luxel, a->solidColor[ aNum ] );
1474 VectorCopy( luxel, b->solidColor[ bNum ] );
1476 /* return to sender */
1480 /* compare nonsolid lightmaps */
1481 if( a->w != b->w || a->h != b->h )
1485 for( y = 0; y < a->h; y++ )
1487 for( x = 0; x < a->w; x++ )
1490 lm = a; aLuxel = BSP_LUXEL( aNum, x, y );
1491 lm = b; bLuxel = BSP_LUXEL( bNum, x, y );
1493 /* handle occlusion mismatch */
1494 if( aLuxel[ 0 ] < 0.0f )
1495 VectorCopy( bLuxel, aLuxel );
1496 else if( bLuxel[ 0 ] < 0.0f )
1497 VectorCopy( aLuxel, bLuxel );
1501 VectorAdd( aLuxel, bLuxel, luxel );
1502 VectorScale( luxel, 0.5f, luxel );
1504 /* debugging code */
1505 //% luxel[ 2 ] += 64.0f;
1508 VectorCopy( luxel, aLuxel );
1509 VectorCopy( luxel, bLuxel );
1522 determines if a single luxel is can be approximated with the interpolated vertex rgba
1525 static qboolean ApproximateLuxel( rawLightmap_t *lm, bspDrawVert_t *dv )
1527 int i, x, y, d, lightmapNum;
1529 vec3_t color, vertexColor;
1530 byte cb[ 4 ], vcb[ 4 ];
1533 /* find luxel xy coords */
1534 x = dv->lightmap[ 0 ][ 0 ] / superSample;
1535 y = dv->lightmap[ 0 ][ 1 ] / superSample;
1538 else if( x >= lm->w )
1542 else if( y >= lm->h )
1546 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1549 if( lm->styles[ lightmapNum ] == LS_NONE )
1553 luxel = BSP_LUXEL( lightmapNum, x, y );
1555 /* ignore occluded luxels */
1556 if( luxel[ 0 ] < 0.0f || luxel[ 1 ] < 0.0f || luxel[ 2 ] < 0.0f )
1559 /* copy, set min color and compare */
1560 VectorCopy( luxel, color );
1561 VectorCopy( dv->color[ 0 ], vertexColor );
1563 /* styles are not affected by minlight */
1564 if( lightmapNum == 0 )
1566 for( i = 0; i < 3; i++ )
1569 if( color[ i ] < minLight[ i ] )
1570 color[ i ] = minLight[ i ];
1571 if( vertexColor[ i ] < minLight[ i ] ) /* note NOT minVertexLight */
1572 vertexColor[ i ] = minLight[ i ];
1577 ColorToBytes( color, cb, 1.0f );
1578 ColorToBytes( vertexColor, vcb, 1.0f );
1581 for( i = 0; i < 3; i++ )
1583 d = cb[ i ] - vcb[ i ];
1586 if( d > approximateTolerance )
1591 /* close enough for the girls i date */
1598 ApproximateTriangle()
1599 determines if a single triangle can be approximated with vertex rgba
1602 static qboolean ApproximateTriangle_r( rawLightmap_t *lm, bspDrawVert_t *dv[ 3 ] )
1604 bspDrawVert_t mid, *dv2[ 3 ];
1608 /* approximate the vertexes */
1609 if( ApproximateLuxel( lm, dv[ 0 ] ) == qfalse )
1611 if( ApproximateLuxel( lm, dv[ 1 ] ) == qfalse )
1613 if( ApproximateLuxel( lm, dv[ 2 ] ) == qfalse )
1616 /* subdivide calc */
1619 float dx, dy, dist, maxDist;
1622 /* find the longest edge and split it */
1625 for( i = 0; i < 3; i++ )
1627 dx = dv[ i ]->lightmap[ 0 ][ 0 ] - dv[ (i + 1) % 3 ]->lightmap[ 0 ][ 0 ];
1628 dy = dv[ i ]->lightmap[ 0 ][ 1 ] - dv[ (i + 1) % 3 ]->lightmap[ 0 ][ 1 ];
1629 dist = sqrt( (dx * dx) + (dy * dy) );
1630 if( dist > maxDist )
1637 /* try to early out */
1638 if( i < 0 || maxDist < subdivideThreshold )
1642 /* split the longest edge and map it */
1643 LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid );
1644 if( ApproximateLuxel( lm, &mid ) == qfalse )
1647 /* recurse to first triangle */
1648 VectorCopy( dv, dv2 );
1650 if( ApproximateTriangle_r( lm, dv2 ) == qfalse )
1653 /* recurse to second triangle */
1654 VectorCopy( dv, dv2 );
1655 dv2[ (max + 1) % 3 ] = ∣
1656 return ApproximateTriangle_r( lm, dv2 );
1662 ApproximateLightmap()
1663 determines if a raw lightmap can be approximated sufficiently with vertex colors
1666 static qboolean ApproximateLightmap( rawLightmap_t *lm )
1668 int n, num, i, x, y, pw[ 5 ], r;
1669 bspDrawSurface_t *ds;
1670 surfaceInfo_t *info;
1671 mesh_t src, *subdivided, *mesh;
1672 bspDrawVert_t *verts, *dv[ 3 ];
1673 qboolean approximated;
1676 /* approximating? */
1677 if( approximateTolerance <= 0 )
1680 /* test for jmonroe */
1682 /* don't approx lightmaps with styled twins */
1683 if( lm->numStyledTwins > 0 )
1686 /* don't approx lightmaps with styles */
1687 for( i = 1; i < MAX_LIGHTMAPS; i++ )
1689 if( lm->styles[ i ] != LS_NONE )
1694 /* assume reduced until shadow detail is found */
1695 approximated = qtrue;
1697 /* walk the list of surfaces on this raw lightmap */
1698 for( n = 0; n < lm->numLightSurfaces; n++ )
1701 num = lightSurfaces[ lm->firstLightSurface + n ];
1702 ds = &bspDrawSurfaces[ num ];
1703 info = &surfaceInfos[ num ];
1705 /* assume not-reduced initially */
1706 info->approximated = qfalse;
1708 /* bail if lightmap doesn't match up */
1709 if( info->lm != lm )
1712 /* bail if not vertex lit */
1713 if( info->si->noVertexLight )
1716 /* assume that surfaces whose bounding boxes is smaller than 2x samplesize will be forced to vertex */
1717 if( (info->maxs[ 0 ] - info->mins[ 0 ]) <= (2.0f * info->sampleSize) &&
1718 (info->maxs[ 1 ] - info->mins[ 1 ]) <= (2.0f * info->sampleSize) &&
1719 (info->maxs[ 2 ] - info->mins[ 2 ]) <= (2.0f * info->sampleSize) )
1721 info->approximated = qtrue;
1722 numSurfsVertexForced++;
1726 /* handle the triangles */
1727 switch( ds->surfaceType )
1731 verts = yDrawVerts + ds->firstVert;
1733 /* map the triangles */
1734 info->approximated = qtrue;
1735 for( i = 0; i < ds->numIndexes && info->approximated; i += 3 )
1737 dv[ 0 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i ] ];
1738 dv[ 1 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 1 ] ];
1739 dv[ 2 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 2 ] ];
1740 info->approximated = ApproximateTriangle_r( lm, dv );
1745 /* make a mesh from the drawsurf */
1746 src.width = ds->patchWidth;
1747 src.height = ds->patchHeight;
1748 src.verts = &yDrawVerts[ ds->firstVert ];
1749 //% subdivided = SubdivideMesh( src, 8, 512 );
1750 subdivided = SubdivideMesh2( src, info->patchIterations );
1752 /* fit it to the curve and remove colinear verts on rows/columns */
1753 PutMeshOnCurve( *subdivided );
1754 mesh = RemoveLinearMeshColumnsRows( subdivided );
1755 FreeMesh( subdivided );
1758 verts = mesh->verts;
1760 /* map the mesh quads */
1761 info->approximated = qtrue;
1762 for( y = 0; y < (mesh->height - 1) && info->approximated; y++ )
1764 for( x = 0; x < (mesh->width - 1) && info->approximated; x++ )
1767 pw[ 0 ] = x + (y * mesh->width);
1768 pw[ 1 ] = x + ((y + 1) * mesh->width);
1769 pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
1770 pw[ 3 ] = x + 1 + (y * mesh->width);
1771 pw[ 4 ] = x + (y * mesh->width); /* same as pw[ 0 ] */
1776 /* get drawverts and map first triangle */
1777 dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1778 dv[ 1 ] = &verts[ pw[ r + 1 ] ];
1779 dv[ 2 ] = &verts[ pw[ r + 2 ] ];
1780 info->approximated = ApproximateTriangle_r( lm, dv );
1782 /* get drawverts and map second triangle */
1783 dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1784 dv[ 1 ] = &verts[ pw[ r + 2 ] ];
1785 dv[ 2 ] = &verts[ pw[ r + 3 ] ];
1786 if( info->approximated )
1787 info->approximated = ApproximateTriangle_r( lm, dv );
1800 if( info->approximated == qfalse )
1801 approximated = qfalse;
1803 numSurfsVertexApproximated++;
1807 return approximated;
1813 TestOutLightmapStamp()
1814 tests a stamp on a given lightmap for validity
1817 static qboolean TestOutLightmapStamp( rawLightmap_t *lm, int lightmapNum, outLightmap_t *olm, int x, int y )
1819 int sx, sy, ox, oy, offset;
1824 if( x < 0 || y < 0 || (x + lm->w) > olm->customWidth || (y + lm->h) > olm->customHeight )
1827 /* solid lightmaps test a 1x1 stamp */
1828 if( lm->solid[ lightmapNum ] )
1830 offset = (y * olm->customWidth) + x;
1831 if( olm->lightBits[ offset >> 3 ] & (1 << (offset & 7)) )
1836 /* test the stamp */
1837 for( sy = 0; sy < lm->h; sy++ )
1839 for( sx = 0; sx < lm->w; sx++ )
1842 luxel = BSP_LUXEL( lightmapNum, sx, sy );
1843 if( luxel[ 0 ] < 0.0f )
1846 /* get bsp lightmap coords and test */
1849 offset = (oy * olm->customWidth) + ox;
1850 if( olm->lightBits[ offset >> 3 ] & (1 << (offset & 7)) )
1855 /* stamp is empty */
1863 sets up an output lightmap
1866 static void SetupOutLightmap( rawLightmap_t *lm, outLightmap_t *olm )
1869 if( lm == NULL || olm == NULL )
1872 /* is this a "normal" bsp-stored lightmap? */
1873 if( (lm->customWidth == game->lightmapSize && lm->customHeight == game->lightmapSize) || externalLightmaps )
1875 olm->lightmapNum = numBSPLightmaps;
1878 /* lightmaps are interleaved with light direction maps */
1883 olm->lightmapNum = -3;
1885 /* set external lightmap number */
1886 olm->extLightmapNum = -1;
1889 olm->numLightmaps = 0;
1890 olm->customWidth = lm->customWidth;
1891 olm->customHeight = lm->customHeight;
1892 olm->freeLuxels = olm->customWidth * olm->customHeight;
1893 olm->numShaders = 0;
1895 /* allocate buffers */
1896 olm->lightBits = safe_malloc( (olm->customWidth * olm->customHeight / 8) + 8 );
1897 memset( olm->lightBits, 0, (olm->customWidth * olm->customHeight / 8) + 8 );
1898 olm->bspLightBytes = safe_malloc( olm->customWidth * olm->customHeight * 3 );
1899 memset( olm->bspLightBytes, 0, olm->customWidth * olm->customHeight * 3 );
1902 olm->bspDirBytes = safe_malloc( olm->customWidth * olm->customHeight * 3 );
1903 memset( olm->bspDirBytes, 0, olm->customWidth * olm->customHeight * 3 );
1911 for a given surface lightmap, find output lightmap pages and positions for it
1914 static void FindOutLightmaps( rawLightmap_t *lm )
1916 int i, j, lightmapNum, xMax, yMax, x, y, sx, sy, ox, oy, offset, temp;
1918 surfaceInfo_t *info;
1919 float *luxel, *deluxel;
1920 vec3_t color, direction;
1925 /* set default lightmap number (-3 = LIGHTMAP_BY_VERTEX) */
1926 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1927 lm->outLightmapNums[ lightmapNum ] = -3;
1929 /* can this lightmap be approximated with vertex color? */
1930 if( ApproximateLightmap( lm ) )
1934 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1937 if( lm->styles[ lightmapNum ] == LS_NONE )
1940 /* don't store twinned lightmaps */
1941 if( lm->twins[ lightmapNum ] != NULL )
1944 /* if this is a styled lightmap, try some normalized locations first */
1946 if( lightmapNum > 0 && outLightmaps != NULL )
1949 for( j = 0; j < 2; j++ )
1951 /* try identical position */
1952 for( i = 0; i < numOutLightmaps; i++ )
1954 /* get the output lightmap */
1955 olm = &outLightmaps[ i ];
1957 /* simple early out test */
1958 if( olm->freeLuxels < lm->used )
1961 /* don't store non-custom raw lightmaps on custom bsp lightmaps */
1962 if( olm->customWidth != lm->customWidth ||
1963 olm->customHeight != lm->customHeight )
1969 x = lm->lightmapX[ 0 ];
1970 y = lm->lightmapY[ 0 ];
1971 ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );
1977 for( sy = -1; sy <= 1; sy++ )
1979 for( sx = -1; sx <= 1; sx++ )
1981 x = lm->lightmapX[ 0 ] + sx * (olm->customWidth >> 1); //% lm->w;
1982 y = lm->lightmapY[ 0 ] + sy * (olm->customHeight >> 1); //% lm->h;
1983 ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );
2003 /* try normal placement algorithm */
2010 /* walk the list of lightmap pages */
2011 for( i = 0; i < numOutLightmaps; i++ )
2013 /* get the output lightmap */
2014 olm = &outLightmaps[ i ];
2016 /* simple early out test */
2017 if( olm->freeLuxels < lm->used )
2020 /* don't store non-custom raw lightmaps on custom bsp lightmaps */
2021 if( olm->customWidth != lm->customWidth ||
2022 olm->customHeight != lm->customHeight )
2026 if( lm->solid[ lightmapNum ] )
2028 xMax = olm->customWidth;
2029 yMax = olm->customHeight;
2033 xMax = (olm->customWidth - lm->w) + 1;
2034 yMax = (olm->customHeight - lm->h) + 1;
2037 /* walk the origin around the lightmap */
2038 for( y = 0; y < yMax; y++ )
2040 for( x = 0; x < xMax; x++ )
2042 /* find a fine tract of lauhnd */
2043 ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );
2065 /* allocate two new output lightmaps */
2066 numOutLightmaps += 2;
2067 olm = safe_malloc( numOutLightmaps * sizeof( outLightmap_t ) );
2068 if( outLightmaps != NULL && numOutLightmaps > 2 )
2070 memcpy( olm, outLightmaps, (numOutLightmaps - 2) * sizeof( outLightmap_t ) );
2071 free( outLightmaps );
2075 /* initialize both out lightmaps */
2076 SetupOutLightmap( lm, &outLightmaps[ numOutLightmaps - 2 ] );
2077 SetupOutLightmap( lm, &outLightmaps[ numOutLightmaps - 1 ] );
2079 /* set out lightmap */
2080 i = numOutLightmaps - 2;
2081 olm = &outLightmaps[ i ];
2083 /* set stamp xy origin to the first surface lightmap */
2084 if( lightmapNum > 0 )
2086 x = lm->lightmapX[ 0 ];
2087 y = lm->lightmapY[ 0 ];
2091 /* if this is a style-using lightmap, it must be exported */
2092 if( lightmapNum > 0 && game->load != LoadRBSPFile )
2093 olm->extLightmapNum = 0;
2095 /* add the surface lightmap to the bsp lightmap */
2096 lm->outLightmapNums[ lightmapNum ] = i;
2097 lm->lightmapX[ lightmapNum ] = x;
2098 lm->lightmapY[ lightmapNum ] = y;
2099 olm->numLightmaps++;
2102 for( i = 0; i < lm->numLightSurfaces; i++ )
2104 /* get surface info */
2105 info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + i ] ];
2107 /* test for shader */
2108 for( j = 0; j < olm->numShaders; j++ )
2110 if( olm->shaders[ j ] == info->si )
2114 /* if it doesn't exist, add it */
2115 if( j >= olm->numShaders && olm->numShaders < MAX_LIGHTMAP_SHADERS )
2117 olm->shaders[ olm->numShaders ] = info->si;
2119 numLightmapShaders++;
2124 if( lm->solid[ lightmapNum ] )
2135 /* mark the bits used */
2136 for( y = 0; y < yMax; y++ )
2138 for( x = 0; x < xMax; x++ )
2141 luxel = BSP_LUXEL( lightmapNum, x, y );
2142 deluxel = BSP_DELUXEL( x, y );
2143 if( luxel[ 0 ] < 0.0f && !lm->solid[ lightmapNum ])
2146 /* set minimum light */
2147 if( lm->solid[ lightmapNum ] )
2150 VectorSet( color, 255.0f, 0.0f, 0.0f );
2152 VectorCopy( lm->solidColor[ lightmapNum ], color );
2155 VectorCopy( luxel, color );
2157 /* styles are not affected by minlight */
2158 if( lightmapNum == 0 )
2160 for( i = 0; i < 3; i++ )
2162 if( color[ i ] < minLight[ i ] )
2163 color[ i ] = minLight[ i ];
2167 /* get bsp lightmap coords */
2168 ox = x + lm->lightmapX[ lightmapNum ];
2169 oy = y + lm->lightmapY[ lightmapNum ];
2170 offset = (oy * olm->customWidth) + ox;
2172 /* flag pixel as used */
2173 olm->lightBits[ offset >> 3 ] |= (1 << (offset & 7));
2177 pixel = olm->bspLightBytes + (((oy * olm->customWidth) + ox) * 3);
2178 ColorToBytes( color, pixel, lm->brightness );
2180 /* store direction */
2183 /* normalize average light direction */
2184 if( VectorNormalize( deluxel, direction ) )
2186 /* encode [-1,1] in [0,255] */
2187 pixel = olm->bspDirBytes + (((oy * olm->customWidth) + ox) * 3);
2188 for( i = 0; i < 3; i++ )
2190 temp = (direction[ i ] + 1.0f) * 127.5f;
2193 else if( temp > 255 )
2208 CompareRawLightmap()
2209 compare function for qsort()
2212 static int CompareRawLightmap( const void *a, const void *b )
2214 rawLightmap_t *alm, *blm;
2215 surfaceInfo_t *aInfo, *bInfo;
2220 alm = &rawLightmaps[ *((int*) a) ];
2221 blm = &rawLightmaps[ *((int*) b) ];
2223 /* get min number of surfaces */
2224 min = (alm->numLightSurfaces < blm->numLightSurfaces ? alm->numLightSurfaces : blm->numLightSurfaces);
2227 for( i = 0; i < min; i++ )
2229 /* get surface info */
2230 aInfo = &surfaceInfos[ lightSurfaces[ alm->firstLightSurface + i ] ];
2231 bInfo = &surfaceInfos[ lightSurfaces[ blm->firstLightSurface + i ] ];
2233 /* compare shader names */
2234 diff = strcmp( aInfo->si->shader, bInfo->si->shader );
2239 /* test style count */
2241 for( i = 0; i < MAX_LIGHTMAPS; i++ )
2242 diff += blm->styles[ i ] - alm->styles[ i ];
2247 diff = (blm->w * blm->h) - (alm->w * alm->h);
2251 /* must be equivalent */
2258 StoreSurfaceLightmaps()
2259 stores the surface lightmaps into the bsp as byte rgb triplets
2262 void StoreSurfaceLightmaps( void )
2264 int i, j, k, x, y, lx, ly, sx, sy, *cluster, mappedSamples;
2265 int style, size, lightmapNum, lightmapNum2;
2266 float *normal, *luxel, *bspLuxel, *bspLuxel2, *radLuxel, samples, occludedSamples;
2267 vec3_t sample, occludedSample, dirSample, colorMins, colorMaxs;
2268 float *deluxel, *bspDeluxel, *bspDeluxel2;
2270 int numUsed, numTwins, numTwinLuxels, numStored;
2271 float lmx, lmy, efficiency;
2273 bspDrawSurface_t *ds, *parent, dsTemp;
2274 surfaceInfo_t *info;
2275 rawLightmap_t *lm, *lm2;
2277 bspDrawVert_t *dv, *ydv, *dvParent;
2278 char dirname[ 1024 ], filename[ 1024 ];
2280 char lightmapName[ 128 ];
2281 char *rgbGenValues[ 256 ];
2282 char *alphaGenValues[ 256 ];
2286 Sys_Printf( "--- StoreSurfaceLightmaps ---\n");
2291 strcpy( dirname, lmCustomDir );
2295 strcpy( dirname, source );
2296 StripExtension( dirname );
2298 memset( rgbGenValues, 0, sizeof( rgbGenValues ) );
2299 memset( alphaGenValues, 0, sizeof( alphaGenValues ) );
2301 /* -----------------------------------------------------------------
2302 average the sampled luxels into the bsp luxels
2303 ----------------------------------------------------------------- */
2306 Sys_Printf( "Subsampling..." );
2308 /* walk the list of raw lightmaps */
2312 numSolidLightmaps = 0;
2313 for( i = 0; i < numRawLightmaps; i++ )
2316 lm = &rawLightmaps[ i ];
2318 /* walk individual lightmaps */
2319 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2322 if( lm->superLuxels[ lightmapNum ] == NULL )
2325 /* allocate bsp luxel storage */
2326 if( lm->bspLuxels[ lightmapNum ] == NULL )
2328 size = lm->w * lm->h * BSP_LUXEL_SIZE * sizeof( float );
2329 lm->bspLuxels[ lightmapNum ] = safe_malloc( size );
2330 memset( lm->bspLuxels[ lightmapNum ], 0, size );
2333 /* allocate radiosity lightmap storage */
2336 size = lm->w * lm->h * RAD_LUXEL_SIZE * sizeof( float );
2337 if( lm->radLuxels[ lightmapNum ] == NULL )
2338 lm->radLuxels[ lightmapNum ] = safe_malloc( size );
2339 memset( lm->radLuxels[ lightmapNum ], 0, size );
2342 /* average supersampled luxels */
2343 for( y = 0; y < lm->h; y++ )
2345 for( x = 0; x < lm->w; x++ )
2349 occludedSamples = 0.0f;
2351 VectorClear( sample );
2352 VectorClear( occludedSample );
2353 VectorClear( dirSample );
2354 for( ly = 0; ly < superSample; ly++ )
2356 for( lx = 0; lx < superSample; lx++ )
2359 sx = x * superSample + lx;
2360 sy = y * superSample + ly;
2361 luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2362 deluxel = SUPER_DELUXEL( sx, sy );
2363 normal = SUPER_NORMAL( sx, sy );
2364 cluster = SUPER_CLUSTER( sx, sy );
2366 /* sample deluxemap */
2367 if( deluxemap && lightmapNum == 0 )
2368 VectorAdd( dirSample, deluxel, dirSample );
2370 /* keep track of used/occluded samples */
2371 if( *cluster != CLUSTER_UNMAPPED )
2374 /* handle lightmap border? */
2375 if( lightmapBorder && (sx == 0 || sx == (lm->sw - 1) || sy == 0 || sy == (lm->sh - 1) ) && luxel[ 3 ] > 0.0f )
2377 VectorSet( sample, 255.0f, 0.0f, 0.0f );
2382 else if( debug && *cluster < 0 )
2384 if( *cluster == CLUSTER_UNMAPPED )
2385 VectorSet( luxel, 255, 204, 0 );
2386 else if( *cluster == CLUSTER_OCCLUDED )
2387 VectorSet( luxel, 255, 0, 255 );
2388 else if( *cluster == CLUSTER_FLOODED )
2389 VectorSet( luxel, 0, 32, 255 );
2390 VectorAdd( occludedSample, luxel, occludedSample );
2391 occludedSamples += 1.0f;
2394 /* normal luxel handling */
2395 else if( luxel[ 3 ] > 0.0f )
2397 /* handle lit or flooded luxels */
2398 if( *cluster > 0 || *cluster == CLUSTER_FLOODED )
2400 VectorAdd( sample, luxel, sample );
2401 samples += luxel[ 3 ];
2404 /* handle occluded or unmapped luxels */
2407 VectorAdd( occludedSample, luxel, occludedSample );
2408 occludedSamples += luxel[ 3 ];
2411 /* handle style debugging */
2412 if( debug && lightmapNum > 0 && x < 2 && y < 2 )
2414 VectorCopy( debugColors[ 0 ], sample );
2421 /* only use occluded samples if necessary */
2422 if( samples <= 0.0f )
2424 VectorCopy( occludedSample, sample );
2425 samples = occludedSamples;
2429 luxel = SUPER_LUXEL( lightmapNum, x, y );
2430 deluxel = SUPER_DELUXEL( x, y );
2432 /* store light direction */
2433 if( deluxemap && lightmapNum == 0 )
2434 VectorCopy( dirSample, deluxel );
2436 /* store the sample back in super luxels */
2437 if( samples > 0.01f )
2439 VectorScale( sample, (1.0f / samples), luxel );
2443 /* if any samples were mapped in any way, store ambient color */
2444 else if( mappedSamples > 0 )
2446 if( lightmapNum == 0 )
2447 VectorCopy( ambientColor, luxel );
2449 VectorClear( luxel );
2453 /* store a bogus value to be fixed later */
2456 VectorClear( luxel );
2464 ClearBounds( colorMins, colorMaxs );
2466 /* clean up and store into bsp luxels */
2467 for( y = 0; y < lm->h; y++ )
2469 for( x = 0; x < lm->w; x++ )
2472 luxel = SUPER_LUXEL( lightmapNum, x, y );
2473 deluxel = SUPER_DELUXEL( x, y );
2475 /* copy light direction */
2476 if( deluxemap && lightmapNum == 0 )
2477 VectorCopy( deluxel, dirSample );
2479 /* is this a valid sample? */
2480 if( luxel[ 3 ] > 0.0f )
2482 VectorCopy( luxel, sample );
2483 samples = luxel[ 3 ];
2487 /* fix negative samples */
2488 for( j = 0; j < 3; j++ )
2490 if( sample[ j ] < 0.0f )
2496 /* nick an average value from the neighbors */
2497 VectorClear( sample );
2498 VectorClear( dirSample );
2501 /* fixme: why is this disabled?? */
2502 for( sy = (y - 1); sy <= (y + 1); sy++ )
2504 if( sy < 0 || sy >= lm->h )
2507 for( sx = (x - 1); sx <= (x + 1); sx++ )
2509 if( sx < 0 || sx >= lm->w || (sx == x && sy == y) )
2512 /* get neighbor's particulars */
2513 luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2514 if( luxel[ 3 ] < 0.0f )
2516 VectorAdd( sample, luxel, sample );
2517 samples += luxel[ 3 ];
2522 if( samples == 0.0f )
2524 VectorSet( sample, -1.0f, -1.0f, -1.0f );
2532 /* fix negative samples */
2533 for( j = 0; j < 3; j++ )
2535 if( sample[ j ] < 0.0f )
2541 /* scale the sample */
2542 VectorScale( sample, (1.0f / samples), sample );
2544 /* store the sample in the radiosity luxels */
2547 radLuxel = RAD_LUXEL( lightmapNum, x, y );
2548 VectorCopy( sample, radLuxel );
2550 /* if only storing bounced light, early out here */
2551 if( bounceOnly && !bouncing )
2555 /* store the sample in the bsp luxels */
2556 bspLuxel = BSP_LUXEL( lightmapNum, x, y );
2557 bspDeluxel = BSP_DELUXEL( x, y );
2559 VectorAdd( bspLuxel, sample, bspLuxel );
2560 if( deluxemap && lightmapNum == 0 )
2561 VectorAdd( bspDeluxel, dirSample, bspDeluxel );
2563 /* add color to bounds for solid checking */
2564 if( samples > 0.0f )
2565 AddPointToBounds( bspLuxel, colorMins, colorMaxs );
2569 /* set solid color */
2570 lm->solid[ lightmapNum ] = qfalse;
2571 VectorAdd( colorMins, colorMaxs, lm->solidColor[ lightmapNum ] );
2572 VectorScale( lm->solidColor[ lightmapNum ], 0.5f, lm->solidColor[ lightmapNum ] );
2574 /* nocollapse prevents solid lightmaps */
2575 if( noCollapse == qfalse )
2577 /* check solid color */
2578 VectorSubtract( colorMaxs, colorMins, sample );
2579 if( (sample[ 0 ] <= SOLID_EPSILON && sample[ 1 ] <= SOLID_EPSILON && sample[ 2 ] <= SOLID_EPSILON) ||
2580 (lm->w <= 2 && lm->h <= 2) ) /* small lightmaps get forced to solid color */
2583 VectorCopy( colorMins, lm->solidColor[ lightmapNum ] );
2584 lm->solid[ lightmapNum ] = qtrue;
2585 numSolidLightmaps++;
2588 /* if all lightmaps aren't solid, then none of them are solid */
2589 if( lm->solid[ lightmapNum ] != lm->solid[ 0 ] )
2591 for( y = 0; y < MAX_LIGHTMAPS; y++ )
2593 if( lm->solid[ y ] )
2594 numSolidLightmaps--;
2595 lm->solid[ y ] = qfalse;
2600 /* wrap bsp luxels if necessary */
2603 for( y = 0; y < lm->h; y++ )
2605 bspLuxel = BSP_LUXEL( lightmapNum, 0, y );
2606 bspLuxel2 = BSP_LUXEL( lightmapNum, lm->w - 1, y );
2607 VectorAdd( bspLuxel, bspLuxel2, bspLuxel );
2608 VectorScale( bspLuxel, 0.5f, bspLuxel );
2609 VectorCopy( bspLuxel, bspLuxel2 );
2610 if( deluxemap && lightmapNum == 0 )
2612 bspDeluxel = BSP_DELUXEL( 0, y );
2613 bspDeluxel2 = BSP_DELUXEL( lm->w - 1, y );
2614 VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel );
2615 VectorScale( bspDeluxel, 0.5f, bspDeluxel );
2616 VectorCopy( bspDeluxel, bspDeluxel2 );
2622 for( x = 0; x < lm->w; x++ )
2624 bspLuxel = BSP_LUXEL( lightmapNum, x, 0 );
2625 bspLuxel2 = BSP_LUXEL( lightmapNum, x, lm->h - 1 );
2626 VectorAdd( bspLuxel, bspLuxel2, bspLuxel );
2627 VectorScale( bspLuxel, 0.5f, bspLuxel );
2628 VectorCopy( bspLuxel, bspLuxel2 );
2629 if( deluxemap && lightmapNum == 0 )
2631 bspDeluxel = BSP_DELUXEL( x, 0 );
2632 bspDeluxel2 = BSP_DELUXEL( x, lm->h - 1 );
2633 VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel );
2634 VectorScale( bspDeluxel, 0.5f, bspDeluxel );
2635 VectorCopy( bspDeluxel, bspDeluxel2 );
2642 /* -----------------------------------------------------------------
2643 convert modelspace deluxemaps to tangentspace
2644 ----------------------------------------------------------------- */
2648 if( deluxemap && deluxemode == 1)
2650 vec3_t worldUp, myNormal, myTangent, myBinormal;
2653 Sys_Printf( "converting..." );
2655 for( i = 0; i < numRawLightmaps; i++ )
2658 lm = &rawLightmaps[ i ];
2660 /* walk lightmap samples */
2661 for( y = 0; y < lm->sh; y++ )
2663 for( x = 0; x < lm->sw; x++ )
2665 /* get normal and deluxel */
2666 normal = SUPER_NORMAL(x, y);
2667 cluster = SUPER_CLUSTER(x, y);
2668 bspDeluxel = BSP_DELUXEL( x, y );
2669 deluxel = SUPER_DELUXEL( x, y );
2672 VectorSet( myNormal, normal[0], normal[1], normal[2] );
2674 /* get tangent vectors */
2675 if( myNormal[ 0 ] == 0.0f && myNormal[ 1 ] == 0.0f )
2677 if( myNormal[ 2 ] == 1.0f )
2679 VectorSet( myTangent, 1.0f, 0.0f, 0.0f );
2680 VectorSet( myBinormal, 0.0f, 1.0f, 0.0f );
2682 else if( myNormal[ 2 ] == -1.0f )
2684 VectorSet( myTangent, -1.0f, 0.0f, 0.0f );
2685 VectorSet( myBinormal, 0.0f, 1.0f, 0.0f );
2690 VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
2691 CrossProduct( myNormal, worldUp, myTangent );
2692 VectorNormalize( myTangent, myTangent );
2693 CrossProduct( myTangent, myNormal, myBinormal );
2694 VectorNormalize( myBinormal, myBinormal );
2697 /* project onto plane */
2698 dist = -DotProduct(myTangent, myNormal);
2699 VectorMA(myTangent, dist, myNormal, myTangent);
2700 dist = -DotProduct(myBinormal, myNormal);
2701 VectorMA(myBinormal, dist, myNormal, myBinormal);
2704 VectorNormalize( myTangent, myTangent );
2705 VectorNormalize( myBinormal, myBinormal );
2707 /* convert modelspace deluxel to tangentspace */
2708 dirSample[0] = bspDeluxel[0];
2709 dirSample[1] = bspDeluxel[1];
2710 dirSample[2] = bspDeluxel[2];
2711 VectorNormalize(dirSample, dirSample);
2713 /* fix tangents to world matrix */
2714 if (myNormal[0] > 0 || myNormal[1] < 0 || myNormal[2] < 0)
2715 VectorNegate(myTangent, myTangent);
2717 /* build tangentspace vectors */
2718 bspDeluxel[0] = DotProduct(dirSample, myTangent);
2719 bspDeluxel[1] = DotProduct(dirSample, myBinormal);
2720 bspDeluxel[2] = DotProduct(dirSample, myNormal);
2727 /* -----------------------------------------------------------------
2729 ----------------------------------------------------------------- */
2731 #ifdef sdfsdfwq312323
2733 Sys_Printf( "blending..." );
2735 for( i = 0; i < numRawLightmaps; i++ )
2741 lm = &rawLightmaps[ i ];
2743 /* walk individual lightmaps */
2744 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2747 if( lm->superLuxels[ lightmapNum ] == NULL )
2750 /* walk lightmap samples */
2751 for( y = 0; y < lm->sh; y++ )
2753 for( x = 0; x < lm->sw; x++ )
2756 bspLuxel = BSP_LUXEL( lightmapNum, x, y );
2759 VectorNormalize(bspLuxel, myColor);
2760 myBrightness = VectorLength(bspLuxel);
2761 myBrightness *= (1 / 127.0f);
2762 myBrightness = myBrightness*myBrightness;
2763 myBrightness *= 127.0f;
2764 VectorScale(myColor, myBrightness, bspLuxel);
2771 /* -----------------------------------------------------------------
2772 collapse non-unique lightmaps
2773 ----------------------------------------------------------------- */
2775 if( noCollapse == qfalse && deluxemap == qfalse )
2778 Sys_Printf( "collapsing..." );
2780 /* set all twin refs to null */
2781 for( i = 0; i < numRawLightmaps; i++ )
2783 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2785 rawLightmaps[ i ].twins[ lightmapNum ] = NULL;
2786 rawLightmaps[ i ].twinNums[ lightmapNum ] = -1;
2787 rawLightmaps[ i ].numStyledTwins = 0;
2791 /* walk the list of raw lightmaps */
2792 for( i = 0; i < numRawLightmaps; i++ )
2795 lm = &rawLightmaps[ i ];
2797 /* walk lightmaps */
2798 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2801 if( lm->bspLuxels[ lightmapNum ] == NULL ||
2802 lm->twins[ lightmapNum ] != NULL )
2805 /* find all lightmaps that are virtually identical to this one */
2806 for( j = i + 1; j < numRawLightmaps; j++ )
2809 lm2 = &rawLightmaps[ j ];
2811 /* walk lightmaps */
2812 for( lightmapNum2 = 0; lightmapNum2 < MAX_LIGHTMAPS; lightmapNum2++ )
2815 if( lm2->bspLuxels[ lightmapNum2 ] == NULL ||
2816 lm2->twins[ lightmapNum2 ] != NULL )
2820 if( CompareBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ) )
2822 /* merge and set twin */
2823 if( MergeBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ) )
2825 lm2->twins[ lightmapNum2 ] = lm;
2826 lm2->twinNums[ lightmapNum2 ] = lightmapNum;
2828 numTwinLuxels += (lm->w * lm->h);
2830 /* count styled twins */
2831 if( lightmapNum > 0 )
2832 lm->numStyledTwins++;
2841 /* -----------------------------------------------------------------
2842 sort raw lightmaps by shader
2843 ----------------------------------------------------------------- */
2846 Sys_Printf( "sorting..." );
2848 /* allocate a new sorted list */
2849 if( sortLightmaps == NULL )
2850 sortLightmaps = safe_malloc( numRawLightmaps * sizeof( int ) );
2852 /* fill it out and sort it */
2853 for( i = 0; i < numRawLightmaps; i++ )
2854 sortLightmaps[ i ] = i;
2855 qsort( sortLightmaps, numRawLightmaps, sizeof( int ), CompareRawLightmap );
2857 /* -----------------------------------------------------------------
2858 allocate output lightmaps
2859 ----------------------------------------------------------------- */
2862 Sys_Printf( "allocating..." );
2864 /* kill all existing output lightmaps */
2865 if( outLightmaps != NULL )
2867 for( i = 0; i < numOutLightmaps; i++ )
2869 free( outLightmaps[ i ].lightBits );
2870 free( outLightmaps[ i ].bspLightBytes );
2872 free( outLightmaps );
2873 outLightmaps = NULL;
2876 numLightmapShaders = 0;
2877 numOutLightmaps = 0;
2878 numBSPLightmaps = 0;
2879 numExtLightmaps = 0;
2881 /* find output lightmap */
2882 for( i = 0; i < numRawLightmaps; i++ )
2884 lm = &rawLightmaps[ sortLightmaps[ i ] ];
2885 FindOutLightmaps( lm );
2888 /* set output numbers in twinned lightmaps */
2889 for( i = 0; i < numRawLightmaps; i++ )
2892 lm = &rawLightmaps[ sortLightmaps[ i ] ];
2894 /* walk lightmaps */
2895 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2898 lm2 = lm->twins[ lightmapNum ];
2901 lightmapNum2 = lm->twinNums[ lightmapNum ];
2903 /* find output lightmap from twin */
2904 lm->outLightmapNums[ lightmapNum ] = lm2->outLightmapNums[ lightmapNum2 ];
2905 lm->lightmapX[ lightmapNum ] = lm2->lightmapX[ lightmapNum2 ];
2906 lm->lightmapY[ lightmapNum ] = lm2->lightmapY[ lightmapNum2 ];
2910 /* -----------------------------------------------------------------
2911 store output lightmaps
2912 ----------------------------------------------------------------- */
2915 Sys_Printf( "storing..." );
2917 /* count the bsp lightmaps and allocate space */
2918 if( bspLightBytes != NULL )
2919 free( bspLightBytes );
2920 if( numBSPLightmaps == 0 || externalLightmaps )
2922 numBSPLightBytes = 0;
2923 bspLightBytes = NULL;
2927 numBSPLightBytes = (numBSPLightmaps * game->lightmapSize * game->lightmapSize * 3);
2928 bspLightBytes = safe_malloc( numBSPLightBytes );
2929 memset( bspLightBytes, 0, numBSPLightBytes );
2932 /* walk the list of output lightmaps */
2933 for( i = 0; i < numOutLightmaps; i++ )
2935 /* get output lightmap */
2936 olm = &outLightmaps[ i ];
2938 /* is this a valid bsp lightmap? */
2939 if( olm->lightmapNum >= 0 && !externalLightmaps )
2941 /* copy lighting data */
2942 lb = bspLightBytes + (olm->lightmapNum * game->lightmapSize * game->lightmapSize * 3);
2943 memcpy( lb, olm->bspLightBytes, game->lightmapSize * game->lightmapSize * 3 );
2945 /* copy direction data */
2948 lb = bspLightBytes + ((olm->lightmapNum + 1) * game->lightmapSize * game->lightmapSize * 3);
2949 memcpy( lb, olm->bspDirBytes, game->lightmapSize * game->lightmapSize * 3 );
2953 /* external lightmap? */
2954 if( olm->lightmapNum < 0 || olm->extLightmapNum >= 0 || externalLightmaps )
2956 /* make a directory for the lightmaps */
2959 /* set external lightmap number */
2960 olm->extLightmapNum = numExtLightmaps;
2962 /* write lightmap */
2963 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
2964 Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
2965 WriteTGA24( filename, olm->bspLightBytes, olm->customWidth, olm->customHeight, qtrue );
2968 /* write deluxemap */
2971 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
2972 Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
2973 WriteTGA24( filename, olm->bspDirBytes, olm->customWidth, olm->customHeight, qtrue );
2976 if( debugDeluxemap )
2977 olm->extLightmapNum++;
2982 if( numExtLightmaps > 0 )
2985 /* delete unused external lightmaps */
2986 for( i = numExtLightmaps; i; i++ )
2988 /* determine if file exists */
2989 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, i );
2990 if( !FileExists( filename ) )
2997 /* -----------------------------------------------------------------
2998 project the lightmaps onto the bsp surfaces
2999 ----------------------------------------------------------------- */
3002 Sys_Printf( "projecting..." );
3004 /* walk the list of surfaces */
3005 for( i = 0; i < numBSPDrawSurfaces; i++ )
3007 /* get the surface and info */
3008 ds = &bspDrawSurfaces[ i ];
3009 info = &surfaceInfos[ i ];
3013 /* handle surfaces with identical parent */
3014 if( info->parentSurfaceNum >= 0 )
3016 /* preserve original data and get parent */
3017 parent = &bspDrawSurfaces[ info->parentSurfaceNum ];
3018 memcpy( &dsTemp, ds, sizeof( *ds ) );
3020 /* overwrite child with parent data */
3021 memcpy( ds, parent, sizeof( *ds ) );
3023 /* restore key parts */
3024 ds->fogNum = dsTemp.fogNum;
3025 ds->firstVert = dsTemp.firstVert;
3026 ds->firstIndex = dsTemp.firstIndex;
3027 memcpy( ds->lightmapVecs, dsTemp.lightmapVecs, sizeof( dsTemp.lightmapVecs ) );
3029 /* set vertex data */
3030 dv = &bspDrawVerts[ ds->firstVert ];
3031 dvParent = &bspDrawVerts[ parent->firstVert ];
3032 for( j = 0; j < ds->numVerts; j++ )
3034 memcpy( dv[ j ].lightmap, dvParent[ j ].lightmap, sizeof( dv[ j ].lightmap ) );
3035 memcpy( dv[ j ].color, dvParent[ j ].color, sizeof( dv[ j ].color ) );
3042 /* handle vertex lit or approximated surfaces */
3043 else if( lm == NULL || lm->outLightmapNums[ 0 ] < 0 )
3045 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3047 ds->lightmapNum[ lightmapNum ] = -3;
3048 ds->lightmapStyles[ lightmapNum ] = ds->vertexStyles[ lightmapNum ];
3052 /* handle lightmapped surfaces */
3055 /* walk lightmaps */
3056 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3059 ds->lightmapStyles[ lightmapNum ] = lm->styles[ lightmapNum ];
3061 /* handle unused style */
3062 if( lm->styles[ lightmapNum ] == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 )
3064 ds->lightmapNum[ lightmapNum ] = -3;
3068 /* get output lightmap */
3069 olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
3071 /* set bsp lightmap number */
3072 ds->lightmapNum[ lightmapNum ] = olm->lightmapNum;
3074 /* deluxemap debugging makes the deluxemap visible */
3075 if( deluxemap && debugDeluxemap && lightmapNum == 0 )
3076 ds->lightmapNum[ lightmapNum ]++;
3078 /* calc lightmap origin in texture space */
3079 lmx = (float) lm->lightmapX[ lightmapNum ] / (float) olm->customWidth;
3080 lmy = (float) lm->lightmapY[ lightmapNum ] / (float) olm->customHeight;
3082 /* calc lightmap st coords */
3083 dv = &bspDrawVerts[ ds->firstVert ];
3084 ydv = &yDrawVerts[ ds->firstVert ];
3085 for( j = 0; j < ds->numVerts; j++ )
3087 if( lm->solid[ lightmapNum ] )
3089 dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + (0.5f / (float) olm->customWidth);
3090 dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + (0.5f / (float) olm->customWidth);
3094 dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + (ydv[ j ].lightmap[ 0 ][ 0 ] / (superSample * olm->customWidth));
3095 dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + (ydv[ j ].lightmap[ 0 ][ 1 ] / (superSample * olm->customHeight));
3101 /* store vertex colors */
3102 dv = &bspDrawVerts[ ds->firstVert ];
3103 for( j = 0; j < ds->numVerts; j++ )
3105 /* walk lightmaps */
3106 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3108 /* handle unused style */
3109 if( ds->vertexStyles[ lightmapNum ] == LS_NONE )
3110 VectorClear( color );
3113 /* get vertex color */
3114 luxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + j );
3115 VectorCopy( luxel, color );
3117 /* set minimum light */
3118 if( lightmapNum == 0 )
3120 for( k = 0; k < 3; k++ )
3121 if( color[ k ] < minVertexLight[ k ] )
3122 color[ k ] = minVertexLight[ k ];
3126 /* store to bytes */
3127 if( !info->si->noVertexLight )
3128 ColorToBytes( color, dv[ j ].color[ lightmapNum ], info->si->vertexScale );
3132 /* surfaces with styled lightmaps and a style marker get a custom generated shader (fixme: make this work with external lightmaps) */
3133 if( olm != NULL && lm != NULL && lm->styles[ 1 ] != LS_NONE && game->load != LoadRBSPFile ) //% info->si->styleMarker > 0 )
3136 char key[ 32 ], styleStage[ 512 ], styleStages[ 4096 ], rgbGen[ 128 ], alphaGen[ 128 ];
3140 sprintf( styleStages, "\n\t// Q3Map2 custom lightstyle stage(s)\n" );
3141 dv = &bspDrawVerts[ ds->firstVert ];
3143 /* depthFunc equal? */
3144 if( info->si->styleMarker == 2 || info->si->implicitMap == IM_MASKED )
3149 /* generate stages for styled lightmaps */
3150 for( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3153 style = lm->styles[ lightmapNum ];
3154 if( style == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 )
3157 /* get output lightmap */
3158 olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
3161 if( lm->outLightmapNums[ lightmapNum ] == lm->outLightmapNums[ 0 ] )
3162 strcpy( lightmapName, "$lightmap" );
3164 sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
3166 /* get rgbgen string */
3167 if( rgbGenValues[ style ] == NULL )
3169 sprintf( key, "_style%drgbgen", style );
3170 rgbGenValues[ style ] = (char*) ValueForKey( &entities[ 0 ], key );
3171 if( rgbGenValues[ style ][ 0 ] == '\0' )
3172 rgbGenValues[ style ] = "wave noise 0.5 1 0 5.37";
3175 if( rgbGenValues[ style ][ 0 ] != '\0' )
3176 sprintf( rgbGen, "\t\trgbGen %s // style %d\n", rgbGenValues[ style ], style );
3180 /* get alphagen string */
3181 if( alphaGenValues[ style ] == NULL )
3183 sprintf( key, "_style%dalphagen", style );
3184 alphaGenValues[ style ] = (char*) ValueForKey( &entities[ 0 ], key );
3186 if( alphaGenValues[ style ][ 0 ] != '\0' )
3187 sprintf( alphaGen, "\t\talphaGen %s // style %d\n", alphaGenValues[ style ], style );
3189 alphaGen[ 0 ] = '\0';
3191 /* calculate st offset */
3192 lmx = dv[ 0 ].lightmap[ lightmapNum ][ 0 ] - dv[ 0 ].lightmap[ 0 ][ 0 ];
3193 lmy = dv[ 0 ].lightmap[ lightmapNum ][ 1 ] - dv[ 0 ].lightmap[ 0 ][ 1 ];
3195 /* create additional stage */
3196 if( lmx == 0.0f && lmy == 0.0f )
3198 sprintf( styleStage, "\t{\n"
3199 "\t\tmap %s\n" /* lightmap */
3200 "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
3201 "%s" /* depthFunc equal */
3204 "\t\ttcGen lightmap\n"
3207 (dfEqual ? "\t\tdepthFunc equal\n" : ""),
3213 sprintf( styleStage, "\t{\n"
3214 "\t\tmap %s\n" /* lightmap */
3215 "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
3216 "%s" /* depthFunc equal */
3219 "\t\ttcGen lightmap\n"
3220 "\t\ttcMod transform 1 0 0 1 %1.5f %1.5f\n" /* st offset */
3223 (dfEqual ? "\t\tdepthFunc equal\n" : ""),
3231 strcat( styleStages, styleStage );
3234 /* create custom shader */
3235 if( info->si->styleMarker == 2 )
3236 csi = CustomShader( info->si, "q3map_styleMarker2", styleStages );
3238 csi = CustomShader( info->si, "q3map_styleMarker", styleStages );
3240 /* emit remap command */
3241 //% EmitVertexRemapShader( csi->shader, info->si->shader );
3244 //% Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
3245 ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3246 //% Sys_Printf( ")\n" );
3249 /* devise a custom shader for this surface (fixme: make this work with light styles) */
3250 else if( olm != NULL && lm != NULL && !externalLightmaps &&
3251 (olm->customWidth != game->lightmapSize || olm->customHeight != game->lightmapSize) )
3253 /* get output lightmap */
3254 olm = &outLightmaps[ lm->outLightmapNums[ 0 ] ];
3256 /* do some name mangling */
3257 sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
3259 /* create custom shader */
3260 csi = CustomShader( info->si, "$lightmap", lightmapName );
3263 //% Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
3264 ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3265 //% Sys_Printf( ")\n" );
3268 /* use the normal plain-jane shader */
3270 ds->shaderNum = EmitShader( info->si->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3274 Sys_Printf( "done.\n" );
3276 /* calc num stored */
3277 numStored = numBSPLightBytes / 3;
3278 efficiency = (numStored <= 0)
3280 : (float) numUsed / (float) numStored;
3283 Sys_Printf( "%9d luxels used\n", numUsed );
3284 Sys_Printf( "%9d luxels stored (%3.2f percent efficiency)\n", numStored, efficiency * 100.0f );
3285 Sys_Printf( "%9d solid surface lightmaps\n", numSolidLightmaps );
3286 Sys_Printf( "%9d identical surface lightmaps, using %d luxels\n", numTwins, numTwinLuxels );
3287 Sys_Printf( "%9d vertex forced surfaces\n", numSurfsVertexForced );
3288 Sys_Printf( "%9d vertex approximated surfaces\n", numSurfsVertexApproximated );
3289 Sys_Printf( "%9d BSP lightmaps\n", numBSPLightmaps );
3290 Sys_Printf( "%9d total lightmaps\n", numOutLightmaps );
3291 Sys_Printf( "%9d unique lightmap/shader combinations\n", numLightmapShaders );
3293 /* write map shader file */
3294 WriteMapShaderFile();