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 ){
68 /* allocate a buffer and set it up */
69 buffer = safe_malloc( width * height * 3 + 18 );
70 memset( buffer, 0, 18 );
72 buffer[ 12 ] = width & 255;
73 buffer[ 13 ] = width >> 8;
74 buffer[ 14 ] = height & 255;
75 buffer[ 15 ] = height >> 8;
79 c = ( width * height * 3 ) + 18;
80 for ( i = 18; i < c; i += 3 )
82 buffer[ i ] = data[ i - 18 + 2 ]; /* blue */
83 buffer[ i + 1 ] = data[ i - 18 + 1 ]; /* green */
84 buffer[ i + 2 ] = data[ i - 18 + 0 ]; /* red */
87 /* write it and free the buffer */
88 file = fopen( filename, "wb" );
90 Error( "Unable to open %s for writing", filename );
93 /* flip vertically? */
95 fwrite( buffer, 1, 18, file );
96 for ( in = buffer + ( ( height - 1 ) * width * 3 ) + 18; in >= buffer; in -= ( width * 3 ) )
97 fwrite( in, 1, ( width * 3 ), file );
100 fwrite( buffer, 1, c, file );
112 exports the lightmaps as a list of numbered tga images
115 void ExportLightmaps( void ){
117 char dirname[ 1024 ], filename[ 1024 ];
122 Sys_FPrintf( SYS_VRB, "--- ExportLightmaps ---\n" );
124 /* do some path mangling */
125 strcpy( dirname, source );
126 StripExtension( dirname );
129 if ( bspLightBytes == NULL ) {
130 Sys_FPrintf( SYS_WRN, "WARNING: No BSP lightmap data\n" );
134 /* make a directory for the lightmaps */
137 /* iterate through the lightmaps */
138 for ( i = 0, lightmap = bspLightBytes; lightmap < ( bspLightBytes + numBSPLightBytes ); i++, lightmap += ( game->lightmapSize * game->lightmapSize * 3 ) )
140 /* write a tga image out */
141 sprintf( filename, "%s/lightmap_%04d.tga", dirname, i );
142 Sys_Printf( "Writing %s\n", filename );
143 WriteTGA24( filename, lightmap, game->lightmapSize, game->lightmapSize, qfalse );
150 ExportLightmapsMain()
151 exports the lightmaps as a list of numbered tga images
154 int ExportLightmapsMain( int argc, char **argv ){
157 Sys_Printf( "Usage: q3map -export [-v] <mapname>\n" );
161 /* do some path mangling */
162 strcpy( source, ExpandArg( argv[ argc - 1 ] ) );
163 StripExtension( source );
164 DefaultExtension( source, ".bsp" );
167 Sys_Printf( "Loading %s\n", source );
168 LoadBSPFile( source );
170 /* export the lightmaps */
173 /* return to sender */
180 ImportLightmapsMain()
181 imports the lightmaps from a list of numbered tga images
184 int ImportLightmapsMain( int argc, char **argv ){
185 int i, x, y, len, width, height;
186 char dirname[ 1024 ], filename[ 1024 ];
187 byte *lightmap, *buffer, *pixels, *in, *out;
192 Sys_Printf( "Usage: q3map -import [-v] <mapname>\n" );
196 /* do some path mangling */
197 strcpy( source, ExpandArg( argv[ argc - 1 ] ) );
198 StripExtension( source );
199 DefaultExtension( source, ".bsp" );
202 Sys_Printf( "Loading %s\n", source );
203 LoadBSPFile( source );
206 Sys_FPrintf( SYS_VRB, "--- ImportLightmaps ---\n" );
208 /* do some path mangling */
209 strcpy( dirname, source );
210 StripExtension( dirname );
213 if ( bspLightBytes == NULL ) {
214 Error( "No lightmap data" );
217 /* make a directory for the lightmaps */
220 /* iterate through the lightmaps */
221 for ( i = 0, lightmap = bspLightBytes; lightmap < ( bspLightBytes + numBSPLightBytes ); i++, lightmap += ( game->lightmapSize * game->lightmapSize * 3 ) )
223 /* read a tga image */
224 sprintf( filename, "%s/lightmap_%04d.tga", dirname, i );
225 Sys_Printf( "Loading %s\n", filename );
227 len = vfsLoadFile( filename, (void*) &buffer, -1 );
229 Sys_FPrintf( SYS_WRN, "WARNING: Unable to load image %s\n", filename );
233 /* parse file into an image */
235 LoadTGABuffer( buffer, buffer + len, &pixels, &width, &height );
238 /* sanity check it */
239 if ( pixels == NULL ) {
240 Sys_FPrintf( SYS_WRN, "WARNING: Unable to load image %s\n", filename );
243 if ( width != game->lightmapSize || height != game->lightmapSize ) {
244 Sys_FPrintf( SYS_WRN, "WARNING: Image %s is not the right size (%d, %d) != (%d, %d)\n",
245 filename, width, height, game->lightmapSize, game->lightmapSize );
248 /* copy the pixels */
250 for ( y = 1; y <= game->lightmapSize; y++ )
252 out = lightmap + ( ( game->lightmapSize - y ) * game->lightmapSize * 3 );
253 for ( x = 0; x < game->lightmapSize; x++, in += 4, out += 3 )
254 VectorCopy( in, out );
262 Sys_Printf( "writing %s\n", source );
263 WriteBSPFile( source );
265 /* return to sender */
271 /* -------------------------------------------------------------------------------
273 this section deals with projecting a lightmap onto a raw drawsurface
275 ------------------------------------------------------------------------------- */
278 CompareLightSurface()
279 compare function for qsort()
282 static int CompareLightSurface( const void *a, const void *b ){
283 shaderInfo_t *asi, *bsi;
287 asi = surfaceInfos[ *( (const int*) a ) ].si;
288 bsi = surfaceInfos[ *( (const int*) b ) ].si;
298 /* compare shader names */
299 return strcmp( asi->shader, bsi->shader );
306 allocates a raw lightmap's necessary buffers
309 void FinishRawLightmap( rawLightmap_t *lm ){
310 int i, j, c, size, *sc;
315 /* sort light surfaces by shader name */
316 qsort( &lightSurfaces[ lm->firstLightSurface ], lm->numLightSurfaces, sizeof( int ), CompareLightSurface );
319 lm->numLightClusters = 0;
320 for ( i = 0; i < lm->numLightSurfaces; i++ )
322 /* get surface info */
323 info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + i ] ];
325 /* add surface clusters */
326 lm->numLightClusters += info->numSurfaceClusters;
329 /* allocate buffer for clusters and copy */
330 lm->lightClusters = safe_malloc( lm->numLightClusters * sizeof( *lm->lightClusters ) );
332 for ( i = 0; i < lm->numLightSurfaces; i++ )
334 /* get surface info */
335 info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + i ] ];
337 /* add surface clusters */
338 for ( j = 0; j < info->numSurfaceClusters; j++ )
339 lm->lightClusters[ c++ ] = surfaceClusters[ info->firstSurfaceCluster + j ];
343 lm->styles[ 0 ] = LS_NORMAL;
344 for ( i = 1; i < MAX_LIGHTMAPS; i++ )
345 lm->styles[ i ] = LS_NONE;
347 /* set supersampling size */
348 lm->sw = lm->w * superSample;
349 lm->sh = lm->h * superSample;
351 /* add to super luxel count */
352 numRawSuperLuxels += ( lm->sw * lm->sh );
354 /* manipulate origin/vecs for supersampling */
355 if ( superSample > 1 && lm->vecs != NULL ) {
356 /* calc inverse supersample */
357 is = 1.0f / superSample;
359 /* scale the vectors and shift the origin */
361 /* new code that works for arbitrary supersampling values */
362 VectorMA( lm->origin, -0.5, lm->vecs[ 0 ], lm->origin );
363 VectorMA( lm->origin, -0.5, lm->vecs[ 1 ], lm->origin );
364 VectorScale( lm->vecs[ 0 ], is, lm->vecs[ 0 ] );
365 VectorScale( lm->vecs[ 1 ], is, lm->vecs[ 1 ] );
366 VectorMA( lm->origin, is, lm->vecs[ 0 ], lm->origin );
367 VectorMA( lm->origin, is, lm->vecs[ 1 ], lm->origin );
369 /* old code that only worked with a value of 2 */
370 VectorScale( lm->vecs[ 0 ], is, lm->vecs[ 0 ] );
371 VectorScale( lm->vecs[ 1 ], is, lm->vecs[ 1 ] );
372 VectorMA( lm->origin, -is, lm->vecs[ 0 ], lm->origin );
373 VectorMA( lm->origin, -is, lm->vecs[ 1 ], lm->origin );
377 /* allocate bsp lightmap storage */
378 size = lm->w * lm->h * BSP_LUXEL_SIZE * sizeof( float );
379 if ( lm->bspLuxels[ 0 ] == NULL ) {
380 lm->bspLuxels[ 0 ] = safe_malloc( size );
382 memset( lm->bspLuxels[ 0 ], 0, size );
384 /* allocate radiosity lightmap storage */
386 size = lm->w * lm->h * RAD_LUXEL_SIZE * sizeof( float );
387 if ( lm->radLuxels[ 0 ] == NULL ) {
388 lm->radLuxels[ 0 ] = safe_malloc( size );
390 memset( lm->radLuxels[ 0 ], 0, size );
393 /* allocate sampling lightmap storage */
394 size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float );
395 if ( lm->superLuxels[ 0 ] == NULL ) {
396 lm->superLuxels[ 0 ] = safe_malloc( size );
398 memset( lm->superLuxels[ 0 ], 0, size );
400 /* allocate origin map storage */
401 size = lm->sw * lm->sh * SUPER_ORIGIN_SIZE * sizeof( float );
402 if ( lm->superOrigins == NULL ) {
403 lm->superOrigins = safe_malloc( size );
405 memset( lm->superOrigins, 0, size );
407 /* allocate normal map storage */
408 size = lm->sw * lm->sh * SUPER_NORMAL_SIZE * sizeof( float );
409 if ( lm->superNormals == NULL ) {
410 lm->superNormals = safe_malloc( size );
412 memset( lm->superNormals, 0, size );
414 /* allocate floodlight map storage */
415 size = lm->sw * lm->sh * SUPER_FLOODLIGHT_SIZE * sizeof( float );
416 if ( lm->superFloodLight == NULL ) {
417 lm->superFloodLight = safe_malloc( size );
419 memset( lm->superFloodLight, 0, size );
421 /* allocate cluster map storage */
422 size = lm->sw * lm->sh * sizeof( int );
423 if ( lm->superClusters == NULL ) {
424 lm->superClusters = safe_malloc( size );
426 size = lm->sw * lm->sh;
427 sc = lm->superClusters;
428 for ( i = 0; i < size; i++ )
429 ( *sc++ ) = CLUSTER_UNMAPPED;
431 /* deluxemap allocation */
433 /* allocate sampling deluxel storage */
434 size = lm->sw * lm->sh * SUPER_DELUXEL_SIZE * sizeof( float );
435 if ( lm->superDeluxels == NULL ) {
436 lm->superDeluxels = safe_malloc( size );
438 memset( lm->superDeluxels, 0, size );
440 /* allocate bsp deluxel storage */
441 size = lm->w * lm->h * BSP_DELUXEL_SIZE * sizeof( float );
442 if ( lm->bspDeluxels == NULL ) {
443 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 ){
463 bspDrawSurface_t *ds;
466 bspDrawVert_t *verts, *a, *b;
468 mesh_t src, *subdivided, *mesh;
469 float sBasis, tBasis, s, t;
470 float length, widthTable[ MAX_EXPANDED_AXIS ], heightTable[ MAX_EXPANDED_AXIS ];
473 /* patches finish a raw lightmap */
474 lm->finished = qtrue;
476 /* get surface and info */
477 ds = &bspDrawSurfaces[ num ];
478 info = &surfaceInfos[ num ];
480 /* make a temporary mesh from the drawsurf */
481 src.width = ds->patchWidth;
482 src.height = ds->patchHeight;
483 src.verts = &yDrawVerts[ ds->firstVert ];
484 //% subdivided = SubdivideMesh( src, 8, 512 );
485 subdivided = SubdivideMesh2( src, info->patchIterations );
487 /* fit it to the curve and remove colinear verts on rows/columns */
488 PutMeshOnCurve( *subdivided );
489 mesh = RemoveLinearMeshColumnsRows( subdivided );
490 FreeMesh( subdivided );
492 /* find the longest distance on each row/column */
494 memset( widthTable, 0, sizeof( widthTable ) );
495 memset( heightTable, 0, sizeof( heightTable ) );
496 for ( y = 0; y < mesh->height; y++ )
498 for ( x = 0; x < mesh->width; x++ )
501 if ( x + 1 < mesh->width ) {
502 a = &verts[ ( y * mesh->width ) + x ];
503 b = &verts[ ( y * mesh->width ) + x + 1 ];
504 VectorSubtract( a->xyz, b->xyz, delta );
505 length = VectorLength( delta );
506 if ( length > widthTable[ x ] ) {
507 widthTable[ x ] = length;
512 if ( y + 1 < mesh->height ) {
513 a = &verts[ ( y * mesh->width ) + x ];
514 b = &verts[ ( ( y + 1 ) * mesh->width ) + x ];
515 VectorSubtract( a->xyz, b->xyz, delta );
516 length = VectorLength( delta );
517 if ( length > heightTable[ y ] ) {
518 heightTable[ y ] = length;
524 /* determine lightmap width */
526 for ( x = 0; x < ( mesh->width - 1 ); x++ )
527 length += widthTable[ x ];
528 lm->w = lm->sampleSize != 0 ? ceil( length / lm->sampleSize ) + 1 : 0;
529 if ( lm->w < ds->patchWidth ) {
530 lm->w = ds->patchWidth;
532 if ( lm->w > lm->customWidth ) {
533 lm->w = lm->customWidth;
535 sBasis = (float) ( lm->w - 1 ) / (float) ( ds->patchWidth - 1 );
537 /* determine lightmap height */
539 for ( y = 0; y < ( mesh->height - 1 ); y++ )
540 length += heightTable[ y ];
541 lm->h = lm->sampleSize != 0 ? ceil( length / lm->sampleSize ) + 1 : 0;
542 if ( lm->h < ds->patchHeight ) {
543 lm->h = ds->patchHeight;
545 if ( lm->h > lm->customHeight ) {
546 lm->h = lm->customHeight;
548 tBasis = (float) ( lm->h - 1 ) / (float) ( ds->patchHeight - 1 );
550 /* free the temporary mesh */
553 /* set the lightmap texture coordinates in yDrawVerts */
554 lm->wrap[ 0 ] = qtrue;
555 lm->wrap[ 1 ] = qtrue;
556 verts = &yDrawVerts[ ds->firstVert ];
557 for ( y = 0; y < ds->patchHeight; y++ )
559 t = ( tBasis * y ) + 0.5f;
560 for ( x = 0; x < ds->patchWidth; x++ )
562 s = ( sBasis * x ) + 0.5f;
563 verts[ ( y * ds->patchWidth ) + x ].lightmap[ 0 ][ 0 ] = s * superSample;
564 verts[ ( y * ds->patchWidth ) + x ].lightmap[ 0 ][ 1 ] = t * superSample;
566 if ( y == 0 && !VectorCompare( verts[ x ].xyz, verts[ ( ( ds->patchHeight - 1 ) * ds->patchWidth ) + x ].xyz ) ) {
567 lm->wrap[ 1 ] = qfalse;
571 if ( !VectorCompare( verts[ ( y * ds->patchWidth ) ].xyz, verts[ ( y * ds->patchWidth ) + ( ds->patchWidth - 1 ) ].xyz ) ) {
572 lm->wrap[ 0 ] = qfalse;
577 //% Sys_Printf( "wrap S: %d wrap T: %d\n", lm->wrap[ 0 ], lm->wrap[ 1 ] );
578 //% if( lm->w > (ds->lightmapWidth & 0xFF) || lm->h > (ds->lightmapHeight & 0xFF) )
579 //% Sys_Printf( "Patch lightmap: (%3d %3d) > (%3d, %3d)\n", lm->w, lm->h, ds->lightmapWidth & 0xFF, ds->lightmapHeight & 0xFF );
580 //% ds->lightmapWidth = lm->w | (ds->lightmapWidth & 0xFFFF0000);
581 //% ds->lightmapHeight = lm->h | (ds->lightmapHeight & 0xFFFF0000);
584 numPatchesLightmapped++;
593 AddSurfaceToRawLightmap()
594 projects a lightmap for a surface
595 based on AllocateLightmapForSurface()
598 qboolean AddSurfaceToRawLightmap( int num, rawLightmap_t *lm ){
599 bspDrawSurface_t *ds, *ds2;
601 int num2, n, i, axisNum;
602 float s, t, d, len, sampleSize;
603 vec3_t mins, maxs, origin, faxis, size, delta, normalized, vecs[ 2 ];
605 bspDrawVert_t *verts;
608 /* get surface and info */
609 ds = &bspDrawSurfaces[ num ];
610 info = &surfaceInfos[ num ];
612 /* add the surface to the raw lightmap */
613 lightSurfaces[ numLightSurfaces++ ] = num;
614 lm->numLightSurfaces++;
616 /* does this raw lightmap already have any surfaces? */
617 if ( lm->numLightSurfaces > 1 ) {
618 /* surface and raw lightmap must have the same lightmap projection axis */
619 if ( VectorCompare( info->axis, lm->axis ) == qfalse ) {
623 /* match identical attributes */
624 if ( info->sampleSize != lm->sampleSize ||
625 info->entityNum != lm->entityNum ||
626 info->recvShadows != lm->recvShadows ||
627 info->si->lmCustomWidth != lm->customWidth ||
628 info->si->lmCustomHeight != lm->customHeight ||
629 info->si->lmBrightness != lm->brightness ||
630 info->si->lmFilterRadius != lm->filterRadius ||
631 info->si->splotchFix != lm->splotchFix ) {
635 /* surface bounds must intersect with raw lightmap bounds */
636 for ( i = 0; i < 3; i++ )
638 if ( info->mins[ i ] > lm->maxs[ i ] ) {
641 if ( info->maxs[ i ] < lm->mins[ i ] ) {
646 /* plane check (fixme: allow merging of nonplanars) */
647 if ( info->si->lmMergable == qfalse ) {
648 if ( info->plane == NULL || lm->plane == NULL ) {
653 for ( i = 0; i < 4; i++ )
654 if ( fabs( info->plane[ i ] - lm->plane[ i ] ) > EQUAL_EPSILON ) {
659 /* debug code hacking */
660 //% if( lm->numLightSurfaces > 1 )
665 if ( info->plane == NULL ) {
669 /* add surface to lightmap bounds */
670 AddPointToBounds( info->mins, lm->mins, lm->maxs );
671 AddPointToBounds( info->maxs, lm->mins, lm->maxs );
673 /* check to see if this is a non-planar patch */
674 if ( ds->surfaceType == MST_PATCH &&
675 lm->axis[ 0 ] == 0.0f && lm->axis[ 1 ] == 0.0f && lm->axis[ 2 ] == 0.0f ) {
676 return AddPatchToRawLightmap( num, lm );
679 /* start with initially requested sample size */
680 sampleSize = lm->sampleSize;
682 /* round to the lightmap resolution */
683 for ( i = 0; i < 3; i++ )
685 mins[ i ] = sampleSize * floor( lm->mins[ i ] / sampleSize );
686 maxs[ i ] = sampleSize * ceil( lm->maxs[ i ] / sampleSize );
687 size[ i ] = ( maxs[ i ] - mins[ i ] ) / sampleSize + 1.0f;
689 /* hack (god this sucks) */
690 if ( size[ i ] > lm->customWidth || size[ i ] > lm->customHeight || ( lmLimitSize && size[i] > lmLimitSize ) ) {
696 if ( sampleSize != lm->sampleSize && lmLimitSize == 0 ){
697 if ( debugSampleSize == 1 || lm->customWidth > 128 ){
698 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",
708 else if ( debugSampleSize == 0 ){
709 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",
725 /* set actual sample size */
726 lm->actualSampleSize = sampleSize;
728 /* fixme: copy rounded mins/maxes to lightmap record? */
729 if ( lm->plane == NULL ) {
730 VectorCopy( mins, lm->mins );
731 VectorCopy( maxs, lm->maxs );
732 VectorCopy( mins, origin );
735 /* set lightmap origin */
736 VectorCopy( lm->mins, origin );
738 /* make absolute axis */
739 faxis[ 0 ] = fabs( lm->axis[ 0 ] );
740 faxis[ 1 ] = fabs( lm->axis[ 1 ] );
741 faxis[ 2 ] = fabs( lm->axis[ 2 ] );
743 /* clear out lightmap vectors */
744 memset( vecs, 0, sizeof( vecs ) );
746 /* classify the plane (x y or z major) (ydnar: biased to z axis projection) */
747 if ( faxis[ 2 ] >= faxis[ 0 ] && faxis[ 2 ] >= faxis[ 1 ] ) {
751 vecs[ 0 ][ 0 ] = 1.0f / sampleSize;
752 vecs[ 1 ][ 1 ] = 1.0f / sampleSize;
754 else if ( faxis[ 0 ] >= faxis[ 1 ] && faxis[ 0 ] >= faxis[ 2 ] ) {
758 vecs[ 0 ][ 1 ] = 1.0f / sampleSize;
759 vecs[ 1 ][ 2 ] = 1.0f / sampleSize;
766 vecs[ 0 ][ 0 ] = 1.0f / sampleSize;
767 vecs[ 1 ][ 2 ] = 1.0f / sampleSize;
770 /* check for bogus axis */
771 if ( faxis[ axisNum ] == 0.0f ) {
772 Sys_FPrintf( SYS_WRN, "WARNING: ProjectSurfaceLightmap: Chose a 0 valued axis\n" );
777 /* store the axis number in the lightmap */
778 lm->axisNum = axisNum;
780 /* walk the list of surfaces on this raw lightmap */
781 for ( n = 0; n < lm->numLightSurfaces; n++ )
784 num2 = lightSurfaces[ lm->firstLightSurface + n ];
785 ds2 = &bspDrawSurfaces[ num2 ];
786 verts = &yDrawVerts[ ds2->firstVert ];
788 /* set the lightmap texture coordinates in yDrawVerts in [0, superSample * lm->customWidth] space */
789 for ( i = 0; i < ds2->numVerts; i++ )
791 VectorSubtract( verts[ i ].xyz, origin, delta );
792 s = DotProduct( delta, vecs[ 0 ] ) + 0.5f;
793 t = DotProduct( delta, vecs[ 1 ] ) + 0.5f;
794 verts[ i ].lightmap[ 0 ][ 0 ] = s * superSample;
795 verts[ i ].lightmap[ 0 ][ 1 ] = t * superSample;
797 if ( s > (float) lm->w || t > (float) lm->h ) {
798 Sys_FPrintf( SYS_VRB, "WARNING: Lightmap texture coords out of range: S %1.4f > %3d || T %1.4f > %3d\n",
799 s, lm->w, t, lm->h );
804 /* get first drawsurface */
805 num2 = lightSurfaces[ lm->firstLightSurface ];
806 ds2 = &bspDrawSurfaces[ num2 ];
807 verts = &yDrawVerts[ ds2->firstVert ];
809 /* calculate lightmap origin */
810 if ( VectorLength( ds2->lightmapVecs[ 2 ] ) ) {
811 VectorCopy( ds2->lightmapVecs[ 2 ], plane );
814 VectorCopy( lm->axis, plane );
816 plane[ 3 ] = DotProduct( verts[ 0 ].xyz, plane );
818 VectorCopy( origin, lm->origin );
819 d = DotProduct( lm->origin, plane ) - plane[ 3 ];
820 d /= plane[ axisNum ];
821 lm->origin[ axisNum ] -= d;
824 VectorCopy( lm->origin, ds->lightmapOrigin );
826 /* for planar surfaces, create lightmap vectors for st->xyz conversion */
827 if ( VectorLength( ds->lightmapVecs[ 2 ] ) || 1 ) { /* ydnar: can't remember what exactly i was thinking here... */
828 /* allocate space for the vectors */
829 lm->vecs = safe_malloc( 3 * sizeof( vec3_t ) );
830 memset( lm->vecs, 0, 3 * sizeof( vec3_t ) );
831 VectorCopy( ds->lightmapVecs[ 2 ], lm->vecs[ 2 ] );
833 /* project stepped lightmap blocks and subtract to get planevecs */
834 for ( i = 0; i < 2; i++ )
836 len = VectorNormalize( vecs[ i ], normalized );
837 VectorScale( normalized, ( 1.0 / len ), lm->vecs[ i ] );
838 d = DotProduct( lm->vecs[ i ], plane );
839 d /= plane[ axisNum ];
840 lm->vecs[ i ][ axisNum ] -= d;
845 /* lightmap vectors are useless on a non-planar surface */
850 if ( ds->surfaceType == MST_PATCH ) {
851 numPatchesLightmapped++;
852 if ( lm->plane != NULL ) {
853 numPlanarPatchesLightmapped++;
858 if ( lm->plane != NULL ) {
859 numPlanarsLightmapped++;
862 numNonPlanarsLightmapped++;
874 compare function for qsort()
877 static int CompareSurfaceInfo( const void *a, const void *b ){
878 surfaceInfo_t *aInfo, *bInfo;
882 /* get surface info */
883 aInfo = &surfaceInfos[ *( (const int*) a ) ];
884 bInfo = &surfaceInfos[ *( (const int*) b ) ];
887 if ( aInfo->modelindex < bInfo->modelindex ) {
890 else if ( aInfo->modelindex > bInfo->modelindex ) {
894 /* then lightmap status */
895 if ( aInfo->hasLightmap < bInfo->hasLightmap ) {
898 else if ( aInfo->hasLightmap > bInfo->hasLightmap ) {
902 /* 27: then shader! */
903 if ( aInfo->si < bInfo->si ) {
906 else if ( aInfo->si > bInfo->si ) {
910 /* then lightmap sample size */
911 if ( aInfo->sampleSize < bInfo->sampleSize ) {
914 else if ( aInfo->sampleSize > bInfo->sampleSize ) {
918 /* then lightmap axis */
919 for ( i = 0; i < 3; i++ )
921 if ( aInfo->axis[ i ] < bInfo->axis[ i ] ) {
924 else if ( aInfo->axis[ i ] > bInfo->axis[ i ] ) {
930 if ( aInfo->plane == NULL && bInfo->plane != NULL ) {
933 else if ( aInfo->plane != NULL && bInfo->plane == NULL ) {
936 else if ( aInfo->plane != NULL && bInfo->plane != NULL ) {
937 for ( i = 0; i < 4; i++ )
939 if ( aInfo->plane[ i ] < bInfo->plane[ i ] ) {
942 else if ( aInfo->plane[ i ] > bInfo->plane[ i ] ) {
948 /* then position in world */
949 for ( i = 0; i < 3; i++ )
951 if ( aInfo->mins[ i ] < bInfo->mins[ i ] ) {
954 else if ( aInfo->mins[ i ] > bInfo->mins[ i ] ) {
959 /* these are functionally identical (this should almost never happen) */
966 SetupSurfaceLightmaps()
967 allocates lightmaps for every surface in the bsp that needs one
968 this depends on yDrawVerts being allocated
971 void SetupSurfaceLightmaps( void ){
972 int i, j, k, s,num, num2;
975 bspDrawSurface_t *ds;
976 surfaceInfo_t *info, *info2;
979 vec3_t mapSize, entityOrigin;
983 Sys_FPrintf( SYS_VRB, "--- SetupSurfaceLightmaps ---\n" );
985 /* determine supersample amount */
986 if ( superSample < 1 ) {
989 else if ( superSample > 8 ) {
990 Sys_FPrintf( SYS_WRN, "WARNING: Insane supersampling amount (%d) detected.\n", superSample );
994 /* clear map bounds */
995 ClearBounds( mapMins, mapMaxs );
997 /* allocate a list of surface clusters */
998 numSurfaceClusters = 0;
999 maxSurfaceClusters = numBSPLeafSurfaces;
1000 surfaceClusters = safe_malloc( maxSurfaceClusters * sizeof( *surfaceClusters ) );
1001 memset( surfaceClusters, 0, maxSurfaceClusters * sizeof( *surfaceClusters ) );
1003 /* allocate a list for per-surface info */
1004 surfaceInfos = safe_malloc( numBSPDrawSurfaces * sizeof( *surfaceInfos ) );
1005 memset( surfaceInfos, 0, numBSPDrawSurfaces * sizeof( *surfaceInfos ) );
1006 for ( i = 0; i < numBSPDrawSurfaces; i++ )
1007 surfaceInfos[ i ].childSurfaceNum = -1;
1009 /* allocate a list of surface indexes to be sorted */
1010 sortSurfaces = safe_malloc( numBSPDrawSurfaces * sizeof( int ) );
1011 memset( sortSurfaces, 0, numBSPDrawSurfaces * sizeof( int ) );
1013 /* walk each model in the bsp */
1014 for ( i = 0; i < numBSPModels; i++ )
1017 model = &bspModels[ i ];
1019 /* walk the list of surfaces in this model and fill out the info structs */
1020 for ( j = 0; j < model->numBSPSurfaces; j++ )
1022 /* make surface index */
1023 num = model->firstBSPSurface + j;
1025 /* copy index to sort list */
1026 sortSurfaces[ num ] = num;
1028 /* get surface and info */
1029 ds = &bspDrawSurfaces[ num ];
1030 info = &surfaceInfos[ num ];
1032 /* set entity origin */
1033 if ( ds->numVerts > 0 ) {
1034 VectorSubtract( yDrawVerts[ ds->firstVert ].xyz, bspDrawVerts[ ds->firstVert ].xyz, entityOrigin );
1037 VectorClear( entityOrigin );
1041 info->modelindex = i;
1044 info->firstSurfaceCluster = numSurfaceClusters;
1046 /* get extra data */
1047 info->si = GetSurfaceExtraShaderInfo( num );
1048 if ( info->si == NULL ) {
1049 info->si = ShaderInfoForShader( bspShaders[ ds->shaderNum ].shader );
1051 info->parentSurfaceNum = GetSurfaceExtraParentSurfaceNum( num );
1052 info->entityNum = GetSurfaceExtraEntityNum( num );
1053 info->castShadows = GetSurfaceExtraCastShadows( num );
1054 info->recvShadows = GetSurfaceExtraRecvShadows( num );
1055 info->sampleSize = GetSurfaceExtraSampleSize( num );
1056 info->longestCurve = GetSurfaceExtraLongestCurve( num );
1057 info->patchIterations = IterationsForCurve( info->longestCurve, patchSubdivisions );
1058 GetSurfaceExtraLightmapAxis( num, info->axis );
1061 if ( info->parentSurfaceNum >= 0 ) {
1062 surfaceInfos[ info->parentSurfaceNum ].childSurfaceNum = j;
1065 /* determine surface bounds */
1066 ClearBounds( info->mins, info->maxs );
1067 for ( k = 0; k < ds->numVerts; k++ )
1069 AddPointToBounds( yDrawVerts[ ds->firstVert + k ].xyz, mapMins, mapMaxs );
1070 AddPointToBounds( yDrawVerts[ ds->firstVert + k ].xyz, info->mins, info->maxs );
1073 /* find all the bsp clusters the surface falls into */
1074 for ( k = 0; k < numBSPLeafs; k++ )
1077 leaf = &bspLeafs[ k ];
1080 if ( leaf->mins[ 0 ] > info->maxs[ 0 ] || leaf->maxs[ 0 ] < info->mins[ 0 ] ||
1081 leaf->mins[ 1 ] > info->maxs[ 1 ] || leaf->maxs[ 1 ] < info->mins[ 1 ] ||
1082 leaf->mins[ 2 ] > info->maxs[ 2 ] || leaf->maxs[ 2 ] < info->mins[ 2 ] ) {
1086 /* test leaf surfaces */
1087 for ( s = 0; s < leaf->numBSPLeafSurfaces; s++ )
1089 if ( bspLeafSurfaces[ leaf->firstBSPLeafSurface + s ] == num ) {
1090 if ( numSurfaceClusters >= maxSurfaceClusters ) {
1091 Error( "maxSurfaceClusters exceeded" );
1093 surfaceClusters[ numSurfaceClusters ] = leaf->cluster;
1094 numSurfaceClusters++;
1095 info->numSurfaceClusters++;
1100 /* determine if surface is planar */
1101 if ( VectorLength( ds->lightmapVecs[ 2 ] ) > 0.0f ) {
1103 info->plane = safe_malloc( 4 * sizeof( float ) );
1104 VectorCopy( ds->lightmapVecs[ 2 ], info->plane );
1105 info->plane[ 3 ] = DotProduct( yDrawVerts[ ds->firstVert ].xyz, info->plane );
1108 /* determine if surface requires a lightmap */
1109 if ( ds->surfaceType == MST_TRIANGLE_SOUP ||
1110 ds->surfaceType == MST_FOLIAGE ||
1111 ( info->si->compileFlags & C_VERTEXLIT ) ||
1113 numSurfsVertexLit++;
1117 numSurfsLightmapped++;
1118 info->hasLightmap = qtrue;
1123 /* find longest map distance */
1124 VectorSubtract( mapMaxs, mapMins, mapSize );
1125 maxMapDistance = VectorLength( mapSize );
1127 /* sort the surfaces info list */
1128 qsort( sortSurfaces, numBSPDrawSurfaces, sizeof( int ), CompareSurfaceInfo );
1130 /* allocate a list of surfaces that would go into raw lightmaps */
1131 numLightSurfaces = 0;
1132 lightSurfaces = safe_malloc( numSurfsLightmapped * sizeof( int ) );
1133 memset( lightSurfaces, 0, numSurfsLightmapped * sizeof( int ) );
1135 /* allocate a list of raw lightmaps */
1136 numRawSuperLuxels = 0;
1137 numRawLightmaps = 0;
1138 rawLightmaps = safe_malloc( numSurfsLightmapped * sizeof( *rawLightmaps ) );
1139 memset( rawLightmaps, 0, numSurfsLightmapped * sizeof( *rawLightmaps ) );
1141 /* walk the list of sorted surfaces */
1142 for ( i = 0; i < numBSPDrawSurfaces; i++ )
1144 /* get info and attempt early out */
1145 num = sortSurfaces[ i ];
1146 ds = &bspDrawSurfaces[ num ];
1147 info = &surfaceInfos[ num ];
1148 if ( info->hasLightmap == qfalse || info->lm != NULL || info->parentSurfaceNum >= 0 ) {
1152 /* allocate a new raw lightmap */
1153 lm = &rawLightmaps[ numRawLightmaps ];
1157 lm->splotchFix = info->si->splotchFix;
1158 lm->firstLightSurface = numLightSurfaces;
1159 lm->numLightSurfaces = 0;
1160 /* vortex: multiply lightmap sample size by -samplescale */
1161 if ( sampleScale > 0 ) {
1162 lm->sampleSize = info->sampleSize * sampleScale;
1165 lm->sampleSize = info->sampleSize;
1167 lm->actualSampleSize = lm->sampleSize;
1168 lm->entityNum = info->entityNum;
1169 lm->recvShadows = info->recvShadows;
1170 lm->brightness = info->si->lmBrightness;
1171 lm->filterRadius = info->si->lmFilterRadius;
1172 VectorCopy( info->si->floodlightRGB, lm->floodlightRGB );
1173 lm->floodlightDistance = info->si->floodlightDistance;
1174 lm->floodlightIntensity = info->si->floodlightIntensity;
1175 lm->floodlightDirectionScale = info->si->floodlightDirectionScale;
1176 VectorCopy( info->axis, lm->axis );
1177 lm->plane = info->plane;
1178 VectorCopy( info->mins, lm->mins );
1179 VectorCopy( info->maxs, lm->maxs );
1181 lm->customWidth = info->si->lmCustomWidth;
1182 lm->customHeight = info->si->lmCustomHeight;
1184 /* add the surface to the raw lightmap */
1185 AddSurfaceToRawLightmap( num, lm );
1188 /* do an exhaustive merge */
1192 /* walk the list of surfaces again */
1194 for ( j = i + 1; j < numBSPDrawSurfaces && lm->finished == qfalse; j++ )
1196 /* get info and attempt early out */
1197 num2 = sortSurfaces[ j ];
1198 info2 = &surfaceInfos[ num2 ];
1199 if ( info2->hasLightmap == qfalse || info2->lm != NULL ) {
1203 /* add the surface to the raw lightmap */
1204 if ( AddSurfaceToRawLightmap( num2, lm ) ) {
1211 lm->numLightSurfaces--;
1217 /* finish the lightmap and allocate the various buffers */
1218 FinishRawLightmap( lm );
1221 if ( debugSampleSize < -1 ){
1222 Sys_FPrintf( SYS_VRB, "+%d similar occurrences;\t-debugSampleSize to show ones\n", -debugSampleSize - 1 );
1225 /* allocate vertex luxel storage */
1226 for ( k = 0; k < MAX_LIGHTMAPS; k++ )
1228 vertexLuxels[ k ] = safe_malloc( numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
1229 memset( vertexLuxels[ k ], 0, numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
1230 radVertexLuxels[ k ] = safe_malloc( numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
1231 memset( radVertexLuxels[ k ], 0, numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
1234 /* emit some stats */
1235 Sys_FPrintf( SYS_VRB, "%9d surfaces\n", numBSPDrawSurfaces );
1236 Sys_FPrintf( SYS_VRB, "%9d raw lightmaps\n", numRawLightmaps );
1237 Sys_FPrintf( SYS_VRB, "%9d surfaces vertex lit\n", numSurfsVertexLit );
1238 Sys_FPrintf( SYS_VRB, "%9d surfaces lightmapped\n", numSurfsLightmapped );
1239 Sys_FPrintf( SYS_VRB, "%9d planar surfaces lightmapped\n", numPlanarsLightmapped );
1240 Sys_FPrintf( SYS_VRB, "%9d non-planar surfaces lightmapped\n", numNonPlanarsLightmapped );
1241 Sys_FPrintf( SYS_VRB, "%9d patches lightmapped\n", numPatchesLightmapped );
1242 Sys_FPrintf( SYS_VRB, "%9d planar patches lightmapped\n", numPlanarPatchesLightmapped );
1248 StitchSurfaceLightmaps()
1249 stitches lightmap edges
1250 2002-11-20 update: use this func only for stitching nonplanar patch lightmap seams
1253 #define MAX_STITCH_CANDIDATES 32
1254 #define MAX_STITCH_LUXELS 64
1256 void StitchSurfaceLightmaps( void ){
1257 int i, j, x, y, x2, y2, *cluster, *cluster2,
1258 numStitched, numCandidates, numLuxels, f, fOld, start;
1259 rawLightmap_t *lm, *a, *b, *c[ MAX_STITCH_CANDIDATES ];
1260 float *luxel, *luxel2, *origin, *origin2, *normal, *normal2,
1261 sampleSize, average[ 3 ], totalColor, ootc;
1264 /* disabled for now */
1268 Sys_Printf( "--- StitchSurfaceLightmaps ---\n" );
1272 start = I_FloatTime();
1274 /* walk the list of raw lightmaps */
1276 for ( i = 0; i < numRawLightmaps; i++ )
1278 /* print pacifier */
1279 f = 10 * i / numRawLightmaps;
1282 Sys_Printf( "%i...", f );
1285 /* get lightmap a */
1286 a = &rawLightmaps[ i ];
1288 /* walk rest of lightmaps */
1290 for ( j = i + 1; j < numRawLightmaps && numCandidates < MAX_STITCH_CANDIDATES; j++ )
1292 /* get lightmap b */
1293 b = &rawLightmaps[ j ];
1295 /* test bounding box */
1296 if ( a->mins[ 0 ] > b->maxs[ 0 ] || a->maxs[ 0 ] < b->mins[ 0 ] ||
1297 a->mins[ 1 ] > b->maxs[ 1 ] || a->maxs[ 1 ] < b->mins[ 1 ] ||
1298 a->mins[ 2 ] > b->maxs[ 2 ] || a->maxs[ 2 ] < b->mins[ 2 ] ) {
1303 c[ numCandidates++ ] = b;
1307 for ( y = 0; y < a->sh; y++ )
1309 for ( x = 0; x < a->sw; x++ )
1311 /* ignore unmapped/unlit luxels */
1313 cluster = SUPER_CLUSTER( x, y );
1314 if ( *cluster == CLUSTER_UNMAPPED ) {
1317 luxel = SUPER_LUXEL( 0, x, y );
1318 if ( luxel[ 3 ] <= 0.0f ) {
1322 /* get particulars */
1323 origin = SUPER_ORIGIN( x, y );
1324 normal = SUPER_NORMAL( x, y );
1326 /* walk candidate list */
1327 for ( j = 0; j < numCandidates; j++ )
1333 /* set samplesize to the smaller of the pair */
1334 sampleSize = 0.5f * ( a->actualSampleSize < b->actualSampleSize ? a->actualSampleSize : b->actualSampleSize );
1336 /* test bounding box */
1337 if ( origin[ 0 ] < ( b->mins[ 0 ] - sampleSize ) || ( origin[ 0 ] > b->maxs[ 0 ] + sampleSize ) ||
1338 origin[ 1 ] < ( b->mins[ 1 ] - sampleSize ) || ( origin[ 1 ] > b->maxs[ 1 ] + sampleSize ) ||
1339 origin[ 2 ] < ( b->mins[ 2 ] - sampleSize ) || ( origin[ 2 ] > b->maxs[ 2 ] + sampleSize ) ) {
1343 /* walk candidate luxels */
1344 VectorClear( average );
1347 for ( y2 = 0; y2 < b->sh && numLuxels < MAX_STITCH_LUXELS; y2++ )
1349 for ( x2 = 0; x2 < b->sw && numLuxels < MAX_STITCH_LUXELS; x2++ )
1351 /* ignore same luxels */
1352 if ( a == b && abs( x - x2 ) <= 1 && abs( y - y2 ) <= 1 ) {
1356 /* ignore unmapped/unlit luxels */
1357 cluster2 = SUPER_CLUSTER( x2, y2 );
1358 if ( *cluster2 == CLUSTER_UNMAPPED ) {
1361 luxel2 = SUPER_LUXEL( 0, x2, y2 );
1362 if ( luxel2[ 3 ] <= 0.0f ) {
1366 /* get particulars */
1367 origin2 = SUPER_ORIGIN( x2, y2 );
1368 normal2 = SUPER_NORMAL( x2, y2 );
1371 if ( DotProduct( normal, normal2 ) < 0.5f ) {
1376 if ( fabs( origin[ 0 ] - origin2[ 0 ] ) > sampleSize ||
1377 fabs( origin[ 1 ] - origin2[ 1 ] ) > sampleSize ||
1378 fabs( origin[ 2 ] - origin2[ 2 ] ) > sampleSize ) {
1383 //% VectorSet( luxel2, 255, 0, 255 );
1384 VectorAdd( average, luxel2, average );
1385 totalColor += luxel2[ 3 ];
1390 if ( numLuxels == 0 ) {
1395 ootc = 1.0f / totalColor;
1396 VectorScale( average, ootc, luxel );
1404 /* emit statistics */
1405 Sys_Printf( " (%i)\n", (int) ( I_FloatTime() - start ) );
1406 Sys_FPrintf( SYS_VRB, "%9d luxels stitched\n", numStitched );
1413 compares two surface lightmaps' bsp luxels, ignoring occluded luxels
1416 #define SOLID_EPSILON 0.0625
1417 #define LUXEL_TOLERANCE 0.0025
1418 #define LUXEL_COLOR_FRAC 0.001302083 /* 1 / 3 / 256 */
1420 static qboolean CompareBSPLuxels( rawLightmap_t *a, int aNum, rawLightmap_t *b, int bNum ){
1423 double delta, total, rd, gd, bd;
1424 float *aLuxel, *bLuxel;
1427 /* styled lightmaps will never be collapsed to non-styled lightmaps when there is _minlight */
1428 if ( ( minLight[ 0 ] || minLight[ 1 ] || minLight[ 2 ] ) &&
1429 ( ( aNum == 0 && bNum != 0 ) || ( aNum != 0 && bNum == 0 ) ) ) {
1434 if ( a->customWidth != b->customWidth || a->customHeight != b->customHeight ||
1435 a->brightness != b->brightness ||
1436 a->solid[ aNum ] != b->solid[ bNum ] ||
1437 a->bspLuxels[ aNum ] == NULL || b->bspLuxels[ bNum ] == NULL ) {
1441 /* compare solid color lightmaps */
1442 if ( a->solid[ aNum ] && b->solid[ bNum ] ) {
1444 rd = fabs( a->solidColor[ aNum ][ 0 ] - b->solidColor[ bNum ][ 0 ] );
1445 gd = fabs( a->solidColor[ aNum ][ 1 ] - b->solidColor[ bNum ][ 1 ] );
1446 bd = fabs( a->solidColor[ aNum ][ 2 ] - b->solidColor[ bNum ][ 2 ] );
1449 if ( rd > SOLID_EPSILON || gd > SOLID_EPSILON || bd > SOLID_EPSILON ) {
1457 /* compare nonsolid lightmaps */
1458 if ( a->w != b->w || a->h != b->h ) {
1462 /* compare luxels */
1465 for ( y = 0; y < a->h; y++ )
1467 for ( x = 0; x < a->w; x++ )
1469 /* increment total */
1473 lm = a; aLuxel = BSP_LUXEL( aNum, x, y );
1474 lm = b; bLuxel = BSP_LUXEL( bNum, x, y );
1476 /* ignore unused luxels */
1477 if ( aLuxel[ 0 ] < 0 || bLuxel[ 0 ] < 0 ) {
1482 rd = fabs( aLuxel[ 0 ] - bLuxel[ 0 ] );
1483 gd = fabs( aLuxel[ 1 ] - bLuxel[ 1 ] );
1484 bd = fabs( aLuxel[ 2 ] - bLuxel[ 2 ] );
1486 /* 2003-09-27: compare individual luxels */
1487 if ( rd > 3.0 || gd > 3.0 || bd > 3.0 ) {
1491 /* compare (fixme: take into account perceptual differences) */
1492 delta += rd * LUXEL_COLOR_FRAC;
1493 delta += gd * LUXEL_COLOR_FRAC;
1494 delta += bd * LUXEL_COLOR_FRAC;
1496 /* is the change too high? */
1497 if ( total > 0.0 && ( ( delta / total ) > LUXEL_TOLERANCE ) ) {
1503 /* made it this far, they must be identical (or close enough) */
1511 merges two surface lightmaps' bsp luxels, overwriting occluded luxels
1514 static qboolean MergeBSPLuxels( rawLightmap_t *a, int aNum, rawLightmap_t *b, int bNum ){
1517 float luxel[ 3 ], *aLuxel, *bLuxel;
1521 if ( a->customWidth != b->customWidth || a->customHeight != b->customHeight ||
1522 a->brightness != b->brightness ||
1523 a->solid[ aNum ] != b->solid[ bNum ] ||
1524 a->bspLuxels[ aNum ] == NULL || b->bspLuxels[ bNum ] == NULL ) {
1528 /* compare solid lightmaps */
1529 if ( a->solid[ aNum ] && b->solid[ bNum ] ) {
1531 VectorAdd( a->solidColor[ aNum ], b->solidColor[ bNum ], luxel );
1532 VectorScale( luxel, 0.5f, luxel );
1535 VectorCopy( luxel, a->solidColor[ aNum ] );
1536 VectorCopy( luxel, b->solidColor[ bNum ] );
1538 /* return to sender */
1542 /* compare nonsolid lightmaps */
1543 if ( a->w != b->w || a->h != b->h ) {
1548 for ( y = 0; y < a->h; y++ )
1550 for ( x = 0; x < a->w; x++ )
1553 lm = a; aLuxel = BSP_LUXEL( aNum, x, y );
1554 lm = b; bLuxel = BSP_LUXEL( bNum, x, y );
1556 /* handle occlusion mismatch */
1557 if ( aLuxel[ 0 ] < 0.0f ) {
1558 VectorCopy( bLuxel, aLuxel );
1560 else if ( bLuxel[ 0 ] < 0.0f ) {
1561 VectorCopy( aLuxel, bLuxel );
1566 VectorAdd( aLuxel, bLuxel, luxel );
1567 VectorScale( luxel, 0.5f, luxel );
1569 /* debugging code */
1570 //% luxel[ 2 ] += 64.0f;
1573 VectorCopy( luxel, aLuxel );
1574 VectorCopy( luxel, bLuxel );
1587 determines if a single luxel is can be approximated with the interpolated vertex rgba
1590 static qboolean ApproximateLuxel( rawLightmap_t *lm, bspDrawVert_t *dv ){
1591 int i, x, y, d, lightmapNum;
1593 vec3_t color, vertexColor;
1594 byte cb[ 4 ], vcb[ 4 ];
1597 /* find luxel xy coords */
1598 x = dv->lightmap[ 0 ][ 0 ] / superSample;
1599 y = dv->lightmap[ 0 ][ 1 ] / superSample;
1603 else if ( x >= lm->w ) {
1609 else if ( y >= lm->h ) {
1614 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1617 if ( lm->styles[ lightmapNum ] == LS_NONE ) {
1622 luxel = BSP_LUXEL( lightmapNum, x, y );
1624 /* ignore occluded luxels */
1625 if ( luxel[ 0 ] < 0.0f || luxel[ 1 ] < 0.0f || luxel[ 2 ] < 0.0f ) {
1629 /* copy, set min color and compare */
1630 VectorCopy( luxel, color );
1631 VectorCopy( dv->color[ 0 ], vertexColor );
1633 /* styles are not affected by minlight */
1634 if ( lightmapNum == 0 ) {
1635 for ( i = 0; i < 3; i++ )
1638 if ( color[ i ] < minLight[ i ] ) {
1639 color[ i ] = minLight[ i ];
1641 if ( vertexColor[ i ] < minLight[ i ] ) { /* note NOT minVertexLight */
1642 vertexColor[ i ] = minLight[ i ];
1648 ColorToBytes( color, cb, 1.0f );
1649 ColorToBytes( vertexColor, vcb, 1.0f );
1652 for ( i = 0; i < 3; i++ )
1654 d = cb[ i ] - vcb[ i ];
1658 if ( d > approximateTolerance ) {
1664 /* close enough for the girls i date */
1671 ApproximateTriangle()
1672 determines if a single triangle can be approximated with vertex rgba
1675 static qboolean ApproximateTriangle_r( rawLightmap_t *lm, bspDrawVert_t *dv[ 3 ] ){
1676 bspDrawVert_t mid, *dv2[ 3 ];
1680 /* approximate the vertexes */
1681 if ( ApproximateLuxel( lm, dv[ 0 ] ) == qfalse ) {
1684 if ( ApproximateLuxel( lm, dv[ 1 ] ) == qfalse ) {
1687 if ( ApproximateLuxel( lm, dv[ 2 ] ) == qfalse ) {
1691 /* subdivide calc */
1694 float dx, dy, dist, maxDist;
1697 /* find the longest edge and split it */
1700 for ( i = 0; i < 3; i++ )
1702 dx = dv[ i ]->lightmap[ 0 ][ 0 ] - dv[ ( i + 1 ) % 3 ]->lightmap[ 0 ][ 0 ];
1703 dy = dv[ i ]->lightmap[ 0 ][ 1 ] - dv[ ( i + 1 ) % 3 ]->lightmap[ 0 ][ 1 ];
1704 dist = sqrt( ( dx * dx ) + ( dy * dy ) );
1705 if ( dist > maxDist ) {
1711 /* try to early out */
1712 if ( i < 0 || maxDist < subdivideThreshold ) {
1717 /* split the longest edge and map it */
1718 LerpDrawVert( dv[ max ], dv[ ( max + 1 ) % 3 ], &mid );
1719 if ( ApproximateLuxel( lm, &mid ) == qfalse ) {
1723 /* recurse to first triangle */
1724 VectorCopy( dv, dv2 );
1726 if ( ApproximateTriangle_r( lm, dv2 ) == qfalse ) {
1730 /* recurse to second triangle */
1731 VectorCopy( dv, dv2 );
1732 dv2[ ( max + 1 ) % 3 ] = ∣
1733 return ApproximateTriangle_r( lm, dv2 );
1739 ApproximateLightmap()
1740 determines if a raw lightmap can be approximated sufficiently with vertex colors
1743 static qboolean ApproximateLightmap( rawLightmap_t *lm ){
1744 int n, num, i, x, y, pw[ 5 ], r;
1745 bspDrawSurface_t *ds;
1746 surfaceInfo_t *info;
1747 mesh_t src, *subdivided, *mesh;
1748 bspDrawVert_t *verts, *dv[ 3 ];
1749 qboolean approximated;
1752 /* approximating? */
1753 if ( approximateTolerance <= 0 ) {
1757 /* test for jmonroe */
1759 /* don't approx lightmaps with styled twins */
1760 if ( lm->numStyledTwins > 0 ) {
1764 /* don't approx lightmaps with styles */
1765 for ( i = 1; i < MAX_LIGHTMAPS; i++ )
1767 if ( lm->styles[ i ] != LS_NONE ) {
1773 /* assume reduced until shadow detail is found */
1774 approximated = qtrue;
1776 /* walk the list of surfaces on this raw lightmap */
1777 for ( n = 0; n < lm->numLightSurfaces; n++ )
1780 num = lightSurfaces[ lm->firstLightSurface + n ];
1781 ds = &bspDrawSurfaces[ num ];
1782 info = &surfaceInfos[ num ];
1784 /* assume not-reduced initially */
1785 info->approximated = qfalse;
1787 /* bail if lightmap doesn't match up */
1788 if ( info->lm != lm ) {
1792 /* bail if not vertex lit */
1793 if ( info->si->noVertexLight ) {
1797 /* assume that surfaces whose bounding boxes is smaller than 2x samplesize will be forced to vertex */
1798 if ( ( info->maxs[ 0 ] - info->mins[ 0 ] ) <= ( 2.0f * info->sampleSize ) &&
1799 ( info->maxs[ 1 ] - info->mins[ 1 ] ) <= ( 2.0f * info->sampleSize ) &&
1800 ( info->maxs[ 2 ] - info->mins[ 2 ] ) <= ( 2.0f * info->sampleSize ) ) {
1801 info->approximated = qtrue;
1802 numSurfsVertexForced++;
1806 /* handle the triangles */
1807 switch ( ds->surfaceType )
1811 verts = yDrawVerts + ds->firstVert;
1813 /* map the triangles */
1814 info->approximated = qtrue;
1815 for ( i = 0; i < ds->numIndexes && info->approximated; i += 3 )
1817 dv[ 0 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i ] ];
1818 dv[ 1 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 1 ] ];
1819 dv[ 2 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 2 ] ];
1820 info->approximated = ApproximateTriangle_r( lm, dv );
1825 /* make a mesh from the drawsurf */
1826 src.width = ds->patchWidth;
1827 src.height = ds->patchHeight;
1828 src.verts = &yDrawVerts[ ds->firstVert ];
1829 //% subdivided = SubdivideMesh( src, 8, 512 );
1830 subdivided = SubdivideMesh2( src, info->patchIterations );
1832 /* fit it to the curve and remove colinear verts on rows/columns */
1833 PutMeshOnCurve( *subdivided );
1834 mesh = RemoveLinearMeshColumnsRows( subdivided );
1835 FreeMesh( subdivided );
1838 verts = mesh->verts;
1840 /* map the mesh quads */
1841 info->approximated = qtrue;
1842 for ( y = 0; y < ( mesh->height - 1 ) && info->approximated; y++ )
1844 for ( x = 0; x < ( mesh->width - 1 ) && info->approximated; x++ )
1847 pw[ 0 ] = x + ( y * mesh->width );
1848 pw[ 1 ] = x + ( ( y + 1 ) * mesh->width );
1849 pw[ 2 ] = x + 1 + ( ( y + 1 ) * mesh->width );
1850 pw[ 3 ] = x + 1 + ( y * mesh->width );
1851 pw[ 4 ] = x + ( y * mesh->width ); /* same as pw[ 0 ] */
1856 /* get drawverts and map first triangle */
1857 dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1858 dv[ 1 ] = &verts[ pw[ r + 1 ] ];
1859 dv[ 2 ] = &verts[ pw[ r + 2 ] ];
1860 info->approximated = ApproximateTriangle_r( lm, dv );
1862 /* get drawverts and map second triangle */
1863 dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1864 dv[ 1 ] = &verts[ pw[ r + 2 ] ];
1865 dv[ 2 ] = &verts[ pw[ r + 3 ] ];
1866 if ( info->approximated ) {
1867 info->approximated = ApproximateTriangle_r( lm, dv );
1881 if ( info->approximated == qfalse ) {
1882 approximated = qfalse;
1885 numSurfsVertexApproximated++;
1890 return approximated;
1896 TestOutLightmapStamp()
1897 tests a stamp on a given lightmap for validity
1900 static qboolean TestOutLightmapStamp( rawLightmap_t *lm, int lightmapNum, outLightmap_t *olm, int x, int y ){
1901 int sx, sy, ox, oy, offset;
1906 if ( x < 0 || y < 0 || ( x + lm->w ) > olm->customWidth || ( y + lm->h ) > olm->customHeight ) {
1910 /* solid lightmaps test a 1x1 stamp */
1911 if ( lm->solid[ lightmapNum ] ) {
1912 offset = ( y * olm->customWidth ) + x;
1913 if ( olm->lightBits[ offset >> 3 ] & ( 1 << ( offset & 7 ) ) ) {
1919 /* test the stamp */
1920 for ( sy = 0; sy < lm->h; sy++ )
1922 for ( sx = 0; sx < lm->w; sx++ )
1925 luxel = BSP_LUXEL( lightmapNum, sx, sy );
1926 if ( luxel[ 0 ] < 0.0f ) {
1930 /* get bsp lightmap coords and test */
1933 offset = ( oy * olm->customWidth ) + ox;
1934 if ( olm->lightBits[ offset >> 3 ] & ( 1 << ( offset & 7 ) ) ) {
1940 /* stamp is empty */
1948 sets up an output lightmap
1951 static void SetupOutLightmap( rawLightmap_t *lm, outLightmap_t *olm ){
1953 if ( lm == NULL || olm == NULL ) {
1957 /* is this a "normal" bsp-stored lightmap? */
1958 if ( ( lm->customWidth == game->lightmapSize && lm->customHeight == game->lightmapSize ) || externalLightmaps ) {
1959 olm->lightmapNum = numBSPLightmaps;
1962 /* lightmaps are interleaved with light direction maps */
1968 olm->lightmapNum = -3;
1971 /* set external lightmap number */
1972 olm->extLightmapNum = -1;
1975 olm->numLightmaps = 0;
1976 olm->customWidth = lm->customWidth;
1977 olm->customHeight = lm->customHeight;
1978 olm->freeLuxels = olm->customWidth * olm->customHeight;
1979 olm->numShaders = 0;
1981 /* allocate buffers */
1982 olm->lightBits = safe_malloc( ( olm->customWidth * olm->customHeight / 8 ) + 8 );
1983 memset( olm->lightBits, 0, ( olm->customWidth * olm->customHeight / 8 ) + 8 );
1984 olm->bspLightBytes = safe_malloc( olm->customWidth * olm->customHeight * 3 );
1985 memset( olm->bspLightBytes, 0, olm->customWidth * olm->customHeight * 3 );
1987 olm->bspDirBytes = safe_malloc( olm->customWidth * olm->customHeight * 3 );
1988 memset( olm->bspDirBytes, 0, olm->customWidth * olm->customHeight * 3 );
1996 for a given surface lightmap, find output lightmap pages and positions for it
1999 #define LIGHTMAP_RESERVE_COUNT 1
2000 static void FindOutLightmaps( rawLightmap_t *lm, qboolean fastAllocate ){
2001 int i, j, k, lightmapNum, xMax, yMax, x = -1, y = -1, sx, sy, ox, oy, offset;
2003 surfaceInfo_t *info;
2004 float *luxel, *deluxel;
2005 vec3_t color, direction;
2008 int xIncrement, yIncrement;
2011 /* set default lightmap number (-3 = LIGHTMAP_BY_VERTEX) */
2012 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2013 lm->outLightmapNums[ lightmapNum ] = -3;
2015 /* can this lightmap be approximated with vertex color? */
2016 if ( ApproximateLightmap( lm ) ) {
2021 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2024 if ( lm->styles[ lightmapNum ] == LS_NONE ) {
2028 /* don't store twinned lightmaps */
2029 if ( lm->twins[ lightmapNum ] != NULL ) {
2033 /* if this is a styled lightmap, try some normalized locations first */
2035 if ( lightmapNum > 0 && outLightmaps != NULL ) {
2037 for ( j = 0; j < 2; j++ )
2039 /* try identical position */
2040 for ( i = 0; i < numOutLightmaps; i++ )
2042 /* get the output lightmap */
2043 olm = &outLightmaps[ i ];
2045 /* simple early out test */
2046 if ( olm->freeLuxels < lm->used ) {
2050 /* don't store non-custom raw lightmaps on custom bsp lightmaps */
2051 if ( olm->customWidth != lm->customWidth ||
2052 olm->customHeight != lm->customHeight ) {
2058 x = lm->lightmapX[ 0 ];
2059 y = lm->lightmapY[ 0 ];
2060 ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );
2066 for ( sy = -1; sy <= 1; sy++ )
2068 for ( sx = -1; sx <= 1; sx++ )
2070 x = lm->lightmapX[ 0 ] + sx * ( olm->customWidth >> 1 ); //% lm->w;
2071 y = lm->lightmapY[ 0 ] + sy * ( olm->customHeight >> 1 ); //% lm->h;
2072 ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );
2096 /* try normal placement algorithm */
2097 if ( ok == qfalse ) {
2102 /* walk the list of lightmap pages */
2103 if ( lightmapSearchBlockSize <= 0 || numOutLightmaps < LIGHTMAP_RESERVE_COUNT ) {
2107 i = ( ( numOutLightmaps - LIGHTMAP_RESERVE_COUNT ) / lightmapSearchBlockSize ) * lightmapSearchBlockSize;
2109 for ( ; i < numOutLightmaps; i++ )
2111 /* get the output lightmap */
2112 olm = &outLightmaps[ i ];
2114 /* simple early out test */
2115 if ( olm->freeLuxels < lm->used ) {
2119 /* if fast allocation, skip lightmap files that are more than 90% complete */
2120 if ( fastAllocate == qtrue ) {
2121 if (olm->freeLuxels < (olm->customWidth * olm->customHeight) / 10) {
2126 /* don't store non-custom raw lightmaps on custom bsp lightmaps */
2127 if ( olm->customWidth != lm->customWidth ||
2128 olm->customHeight != lm->customHeight ) {
2133 if ( lm->solid[ lightmapNum ] ) {
2134 xMax = olm->customWidth;
2135 yMax = olm->customHeight;
2139 xMax = ( olm->customWidth - lm->w ) + 1;
2140 yMax = ( olm->customHeight - lm->h ) + 1;
2143 /* if fast allocation, do not test allocation on every pixels, especially for large lightmaps */
2144 if ( fastAllocate == qtrue ) {
2145 xIncrement = MAX(1, lm->w / 15);
2146 yIncrement = MAX(1, lm->h / 15);
2153 /* walk the origin around the lightmap */
2154 for ( y = 0; y < yMax; y += yIncrement )
2156 for ( x = 0; x < xMax; x += xIncrement )
2158 /* find a fine tract of lauhnd */
2159 ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );
2182 if ( ok == qfalse ) {
2183 /* allocate LIGHTMAP_RESERVE_COUNT new output lightmaps */
2184 numOutLightmaps += LIGHTMAP_RESERVE_COUNT;
2185 olm = safe_malloc( numOutLightmaps * sizeof( outLightmap_t ) );
2187 Error( "FindOutLightmaps: Failed to allocate memory.\n" );
2190 if ( outLightmaps != NULL && numOutLightmaps > LIGHTMAP_RESERVE_COUNT ) {
2191 memcpy( olm, outLightmaps, ( numOutLightmaps - LIGHTMAP_RESERVE_COUNT ) * sizeof( outLightmap_t ) );
2192 free( outLightmaps );
2196 /* initialize both out lightmaps */
2197 for ( k = numOutLightmaps - LIGHTMAP_RESERVE_COUNT; k < numOutLightmaps; ++k )
2198 SetupOutLightmap( lm, &outLightmaps[ k ] );
2200 /* set out lightmap */
2201 i = numOutLightmaps - LIGHTMAP_RESERVE_COUNT;
2202 olm = &outLightmaps[ i ];
2204 /* set stamp xy origin to the first surface lightmap */
2205 if ( lightmapNum > 0 ) {
2206 x = lm->lightmapX[ 0 ];
2207 y = lm->lightmapY[ 0 ];
2211 /* if this is a style-using lightmap, it must be exported */
2212 if ( lightmapNum > 0 && game->load != LoadRBSPFile ) {
2213 olm->extLightmapNum = 0;
2216 /* add the surface lightmap to the bsp lightmap */
2217 lm->outLightmapNums[ lightmapNum ] = i;
2218 lm->lightmapX[ lightmapNum ] = x;
2219 lm->lightmapY[ lightmapNum ] = y;
2220 olm->numLightmaps++;
2223 for ( i = 0; i < lm->numLightSurfaces; i++ )
2225 /* get surface info */
2226 info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + i ] ];
2228 /* test for shader */
2229 for ( j = 0; j < olm->numShaders; j++ )
2231 if ( olm->shaders[ j ] == info->si ) {
2236 /* if it doesn't exist, add it */
2237 if ( j >= olm->numShaders && olm->numShaders < MAX_LIGHTMAP_SHADERS ) {
2238 olm->shaders[ olm->numShaders ] = info->si;
2240 numLightmapShaders++;
2245 if ( lm->solid[ lightmapNum ] ) {
2255 /* mark the bits used */
2256 for ( y = 0; y < yMax; y++ )
2258 for ( x = 0; x < xMax; x++ )
2261 luxel = BSP_LUXEL( lightmapNum, x, y );
2262 deluxel = BSP_DELUXEL( x, y );
2263 if ( luxel[ 0 ] < 0.0f && !lm->solid[ lightmapNum ] ) {
2267 /* set minimum light */
2268 if ( lm->solid[ lightmapNum ] ) {
2270 VectorSet( color, 255.0f, 0.0f, 0.0f );
2273 VectorCopy( lm->solidColor[ lightmapNum ], color );
2277 VectorCopy( luxel, color );
2280 /* styles are not affected by minlight */
2281 if ( lightmapNum == 0 ) {
2282 for ( i = 0; i < 3; i++ )
2284 if ( color[ i ] < minLight[ i ] ) {
2285 color[ i ] = minLight[ i ];
2290 /* get bsp lightmap coords */
2291 ox = x + lm->lightmapX[ lightmapNum ];
2292 oy = y + lm->lightmapY[ lightmapNum ];
2293 offset = ( oy * olm->customWidth ) + ox;
2295 /* flag pixel as used */
2296 olm->lightBits[ offset >> 3 ] |= ( 1 << ( offset & 7 ) );
2300 pixel = olm->bspLightBytes + ( ( ( oy * olm->customWidth ) + ox ) * 3 );
2301 ColorToBytes( color, pixel, lm->brightness );
2303 /* store direction */
2305 /* normalize average light direction */
2306 pixel = olm->bspDirBytes + ( ( ( oy * olm->customWidth ) + ox ) * 3 );
2307 VectorScale( deluxel, 1000.0f, direction );
2308 VectorNormalize( direction, direction );
2309 VectorScale( direction, 127.5f, direction );
2310 for ( i = 0; i < 3; i++ )
2311 pixel[ i ] = (byte)( 127.5f + direction[ i ] );
2321 CompareRawLightmap()
2322 compare function for qsort()
2325 static int CompareRawLightmap( const void *a, const void *b ){
2326 rawLightmap_t *alm, *blm;
2327 surfaceInfo_t *aInfo, *bInfo;
2332 alm = &rawLightmaps[ *( (const int*) a ) ];
2333 blm = &rawLightmaps[ *( (const int*) b ) ];
2335 /* get min number of surfaces */
2336 min = ( alm->numLightSurfaces < blm->numLightSurfaces ? alm->numLightSurfaces : blm->numLightSurfaces );
2339 for ( i = 0; i < min; i++ )
2341 /* get surface info */
2342 aInfo = &surfaceInfos[ lightSurfaces[ alm->firstLightSurface + i ] ];
2343 bInfo = &surfaceInfos[ lightSurfaces[ blm->firstLightSurface + i ] ];
2345 /* compare shader names */
2346 diff = strcmp( aInfo->si->shader, bInfo->si->shader );
2352 /* test style count */
2354 for ( i = 0; i < MAX_LIGHTMAPS; i++ )
2355 diff += blm->styles[ i ] - alm->styles[ i ];
2361 diff = ( blm->w * blm->h ) - ( alm->w * alm->h );
2366 /* must be equivalent */
2372 void FillOutLightmap( outLightmap_t *olm ){
2375 vec3_t dir_sum, light_sum;
2377 byte *lightBitsNew = NULL;
2378 byte *lightBytesNew = NULL;
2379 byte *dirBytesNew = NULL;
2381 lightBitsNew = safe_malloc( ( olm->customWidth * olm->customHeight + 8 ) / 8 );
2382 lightBytesNew = safe_malloc( olm->customWidth * olm->customHeight * 3 );
2384 dirBytesNew = safe_malloc( olm->customWidth * olm->customHeight * 3 );
2388 memset(olm->lightBits, 0, (olm->customWidth * olm->customHeight + 8) / 8);
2389 olm->lightBits[0] |= 1;
2390 olm->lightBits[(10 * olm->customWidth + 30) >> 3] |= 1 << ((10 * olm->customWidth + 30) & 7);
2391 memset(olm->bspLightBytes, 0, olm->customWidth * olm->customHeight * 3);
2392 olm->bspLightBytes[0] = 255;
2393 olm->bspLightBytes[(10 * olm->customWidth + 30) * 3 + 2] = 255;
2396 memcpy( lightBitsNew, olm->lightBits, ( olm->customWidth * olm->customHeight + 8 ) / 8 );
2397 memcpy( lightBytesNew, olm->bspLightBytes, olm->customWidth * olm->customHeight * 3 );
2399 memcpy( dirBytesNew, olm->bspDirBytes, olm->customWidth * olm->customHeight * 3 );
2405 for ( y = 0; y < olm->customHeight; ++y )
2407 for ( x = 0; x < olm->customWidth; ++x )
2409 ofs = y * olm->customWidth + x;
2410 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2414 VectorClear( dir_sum );
2415 VectorClear( light_sum );
2417 /* try all four neighbors */
2418 ofs = ( ( y + olm->customHeight - 1 ) % olm->customHeight ) * olm->customWidth + x;
2419 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2421 VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2423 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2427 ofs = ( ( y + 1 ) % olm->customHeight ) * olm->customWidth + x;
2428 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2430 VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2432 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2436 ofs = y * olm->customWidth + ( x + olm->customWidth - 1 ) % olm->customWidth;
2437 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2439 VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2441 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2445 ofs = y * olm->customWidth + ( x + 1 ) % olm->customWidth;
2446 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2448 VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2450 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2456 ofs = y * olm->customWidth + x;
2457 lightBitsNew[ofs >> 3] |= ( 1 << ( ofs & 7 ) );
2458 VectorScale( light_sum, 1.0 / cnt, lightBytesNew + ofs * 3 );
2460 VectorScale( dir_sum, 1.0 / cnt, dirBytesNew + ofs * 3 );
2470 memcpy( olm->lightBits, lightBitsNew, ( olm->customWidth * olm->customHeight + 8 ) / 8 );
2471 memcpy( olm->bspLightBytes, lightBytesNew, olm->customWidth * olm->customHeight * 3 );
2473 memcpy( olm->bspDirBytes, dirBytesNew, olm->customWidth * olm->customHeight * 3 );
2477 free( lightBitsNew );
2478 free( lightBytesNew );
2480 free( dirBytesNew );
2487 StoreSurfaceLightmaps()
2488 stores the surface lightmaps into the bsp as byte rgb triplets
2491 void StoreSurfaceLightmaps( qboolean fastAllocate ){
2492 int i, j, k, x, y, lx, ly, sx, sy, *cluster, mappedSamples;
2493 int style, size, lightmapNum, lightmapNum2;
2494 float *normal, *luxel, *bspLuxel, *bspLuxel2, *radLuxel, samples, occludedSamples;
2495 vec3_t sample, occludedSample, dirSample, colorMins, colorMaxs;
2496 float *deluxel, *bspDeluxel, *bspDeluxel2;
2498 int numUsed, numTwins, numTwinLuxels, numStored;
2499 float lmx, lmy, efficiency;
2501 bspDrawSurface_t *ds, *parent, dsTemp;
2502 surfaceInfo_t *info;
2503 rawLightmap_t *lm, *lm2;
2505 bspDrawVert_t *dv, *ydv, *dvParent;
2506 char dirname[ 1024 ], filename[ 1024 ];
2508 char lightmapName[ 128 ];
2509 const char *rgbGenValues[ 256 ];
2510 const char *alphaGenValues[ 256 ];
2514 Sys_Printf( "--- StoreSurfaceLightmaps ---\n" );
2517 if ( lmCustomDir ) {
2518 strcpy( dirname, lmCustomDir );
2522 strcpy( dirname, source );
2523 StripExtension( dirname );
2525 memset( rgbGenValues, 0, sizeof( rgbGenValues ) );
2526 memset( alphaGenValues, 0, sizeof( alphaGenValues ) );
2528 /* -----------------------------------------------------------------
2529 average the sampled luxels into the bsp luxels
2530 ----------------------------------------------------------------- */
2533 Sys_FPrintf( SYS_VRB, "Subsampling..." );
2535 /* walk the list of raw lightmaps */
2539 numSolidLightmaps = 0;
2540 for ( i = 0; i < numRawLightmaps; i++ )
2543 lm = &rawLightmaps[ i ];
2545 /* walk individual lightmaps */
2546 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2549 if ( lm->superLuxels[ lightmapNum ] == NULL ) {
2553 /* allocate bsp luxel storage */
2554 if ( lm->bspLuxels[ lightmapNum ] == NULL ) {
2555 size = lm->w * lm->h * BSP_LUXEL_SIZE * sizeof( float );
2556 lm->bspLuxels[ lightmapNum ] = safe_malloc( size );
2557 memset( lm->bspLuxels[ lightmapNum ], 0, size );
2560 /* allocate radiosity lightmap storage */
2562 size = lm->w * lm->h * RAD_LUXEL_SIZE * sizeof( float );
2563 if ( lm->radLuxels[ lightmapNum ] == NULL ) {
2564 lm->radLuxels[ lightmapNum ] = safe_malloc( size );
2566 memset( lm->radLuxels[ lightmapNum ], 0, size );
2569 /* average supersampled luxels */
2570 for ( y = 0; y < lm->h; y++ )
2572 for ( x = 0; x < lm->w; x++ )
2576 occludedSamples = 0.0f;
2578 VectorClear( sample );
2579 VectorClear( occludedSample );
2580 VectorClear( dirSample );
2581 for ( ly = 0; ly < superSample; ly++ )
2583 for ( lx = 0; lx < superSample; lx++ )
2586 sx = x * superSample + lx;
2587 sy = y * superSample + ly;
2588 luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2589 deluxel = SUPER_DELUXEL( sx, sy );
2590 normal = SUPER_NORMAL( sx, sy );
2591 cluster = SUPER_CLUSTER( sx, sy );
2593 /* sample deluxemap */
2594 if ( deluxemap && lightmapNum == 0 ) {
2595 VectorAdd( dirSample, deluxel, dirSample );
2598 /* keep track of used/occluded samples */
2599 if ( *cluster != CLUSTER_UNMAPPED ) {
2603 /* handle lightmap border? */
2604 if ( lightmapBorder && ( sx == 0 || sx == ( lm->sw - 1 ) || sy == 0 || sy == ( lm->sh - 1 ) ) && luxel[ 3 ] > 0.0f ) {
2605 VectorSet( sample, 255.0f, 0.0f, 0.0f );
2610 else if ( debug && *cluster < 0 ) {
2611 if ( *cluster == CLUSTER_UNMAPPED ) {
2612 VectorSet( luxel, 255, 204, 0 );
2614 else if ( *cluster == CLUSTER_OCCLUDED ) {
2615 VectorSet( luxel, 255, 0, 255 );
2617 else if ( *cluster == CLUSTER_FLOODED ) {
2618 VectorSet( luxel, 0, 32, 255 );
2620 VectorAdd( occludedSample, luxel, occludedSample );
2621 occludedSamples += 1.0f;
2624 /* normal luxel handling */
2625 else if ( luxel[ 3 ] > 0.0f ) {
2626 /* handle lit or flooded luxels */
2627 if ( *cluster > 0 || *cluster == CLUSTER_FLOODED ) {
2628 VectorAdd( sample, luxel, sample );
2629 samples += luxel[ 3 ];
2632 /* handle occluded or unmapped luxels */
2635 VectorAdd( occludedSample, luxel, occludedSample );
2636 occludedSamples += luxel[ 3 ];
2639 /* handle style debugging */
2640 if ( debug && lightmapNum > 0 && x < 2 && y < 2 ) {
2641 VectorCopy( debugColors[ 0 ], sample );
2648 /* only use occluded samples if necessary */
2649 if ( samples <= 0.0f ) {
2650 VectorCopy( occludedSample, sample );
2651 samples = occludedSamples;
2655 luxel = SUPER_LUXEL( lightmapNum, x, y );
2656 deluxel = SUPER_DELUXEL( x, y );
2658 /* store light direction */
2659 if ( deluxemap && lightmapNum == 0 ) {
2660 VectorCopy( dirSample, deluxel );
2663 /* store the sample back in super luxels */
2664 if ( samples > 0.01f ) {
2665 VectorScale( sample, ( 1.0f / samples ), luxel );
2669 /* if any samples were mapped in any way, store ambient color */
2670 else if ( mappedSamples > 0 ) {
2671 if ( lightmapNum == 0 ) {
2672 VectorCopy( ambientColor, luxel );
2675 VectorClear( luxel );
2680 /* store a bogus value to be fixed later */
2683 VectorClear( luxel );
2691 ClearBounds( colorMins, colorMaxs );
2693 /* clean up and store into bsp luxels */
2694 for ( y = 0; y < lm->h; y++ )
2696 for ( x = 0; x < lm->w; x++ )
2699 luxel = SUPER_LUXEL( lightmapNum, x, y );
2700 deluxel = SUPER_DELUXEL( x, y );
2702 /* copy light direction */
2703 if ( deluxemap && lightmapNum == 0 ) {
2704 VectorCopy( deluxel, dirSample );
2707 /* is this a valid sample? */
2708 if ( luxel[ 3 ] > 0.0f ) {
2709 VectorCopy( luxel, sample );
2710 samples = luxel[ 3 ];
2714 /* fix negative samples */
2715 for ( j = 0; j < 3; j++ )
2717 if ( sample[ j ] < 0.0f ) {
2724 /* nick an average value from the neighbors */
2725 VectorClear( sample );
2726 VectorClear( dirSample );
2729 /* fixme: why is this disabled?? */
2730 for ( sy = ( y - 1 ); sy <= ( y + 1 ); sy++ )
2732 if ( sy < 0 || sy >= lm->h ) {
2736 for ( sx = ( x - 1 ); sx <= ( x + 1 ); sx++ )
2738 if ( sx < 0 || sx >= lm->w || ( sx == x && sy == y ) ) {
2742 /* get neighbor's particulars */
2743 luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2744 if ( luxel[ 3 ] < 0.0f ) {
2747 VectorAdd( sample, luxel, sample );
2748 samples += luxel[ 3 ];
2753 if ( samples == 0.0f ) {
2754 VectorSet( sample, -1.0f, -1.0f, -1.0f );
2762 /* fix negative samples */
2763 for ( j = 0; j < 3; j++ )
2765 if ( sample[ j ] < 0.0f ) {
2772 /* scale the sample */
2773 VectorScale( sample, ( 1.0f / samples ), sample );
2775 /* store the sample in the radiosity luxels */
2777 radLuxel = RAD_LUXEL( lightmapNum, x, y );
2778 VectorCopy( sample, radLuxel );
2780 /* if only storing bounced light, early out here */
2781 if ( bounceOnly && !bouncing ) {
2786 /* store the sample in the bsp luxels */
2787 bspLuxel = BSP_LUXEL( lightmapNum, x, y );
2788 bspDeluxel = BSP_DELUXEL( x, y );
2790 VectorAdd( bspLuxel, sample, bspLuxel );
2791 if ( deluxemap && lightmapNum == 0 ) {
2792 VectorAdd( bspDeluxel, dirSample, bspDeluxel );
2795 /* add color to bounds for solid checking */
2796 if ( samples > 0.0f ) {
2797 AddPointToBounds( bspLuxel, colorMins, colorMaxs );
2802 /* set solid color */
2803 lm->solid[ lightmapNum ] = qfalse;
2804 VectorAdd( colorMins, colorMaxs, lm->solidColor[ lightmapNum ] );
2805 VectorScale( lm->solidColor[ lightmapNum ], 0.5f, lm->solidColor[ lightmapNum ] );
2807 /* nocollapse prevents solid lightmaps */
2808 if ( noCollapse == qfalse ) {
2809 /* check solid color */
2810 VectorSubtract( colorMaxs, colorMins, sample );
2811 if ( ( sample[ 0 ] <= SOLID_EPSILON && sample[ 1 ] <= SOLID_EPSILON && sample[ 2 ] <= SOLID_EPSILON ) ||
2812 ( lm->w <= 2 && lm->h <= 2 ) ) { /* small lightmaps get forced to solid color */
2814 VectorCopy( colorMins, lm->solidColor[ lightmapNum ] );
2815 lm->solid[ lightmapNum ] = qtrue;
2816 numSolidLightmaps++;
2819 /* if all lightmaps aren't solid, then none of them are solid */
2820 if ( lm->solid[ lightmapNum ] != lm->solid[ 0 ] ) {
2821 for ( y = 0; y < MAX_LIGHTMAPS; y++ )
2823 if ( lm->solid[ y ] ) {
2824 numSolidLightmaps--;
2826 lm->solid[ y ] = qfalse;
2831 /* wrap bsp luxels if necessary */
2832 if ( lm->wrap[ 0 ] ) {
2833 for ( y = 0; y < lm->h; y++ )
2835 bspLuxel = BSP_LUXEL( lightmapNum, 0, y );
2836 bspLuxel2 = BSP_LUXEL( lightmapNum, lm->w - 1, y );
2837 VectorAdd( bspLuxel, bspLuxel2, bspLuxel );
2838 VectorScale( bspLuxel, 0.5f, bspLuxel );
2839 VectorCopy( bspLuxel, bspLuxel2 );
2840 if ( deluxemap && lightmapNum == 0 ) {
2841 bspDeluxel = BSP_DELUXEL( 0, y );
2842 bspDeluxel2 = BSP_DELUXEL( lm->w - 1, y );
2843 VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel );
2844 VectorScale( bspDeluxel, 0.5f, bspDeluxel );
2845 VectorCopy( bspDeluxel, bspDeluxel2 );
2849 if ( lm->wrap[ 1 ] ) {
2850 for ( x = 0; x < lm->w; x++ )
2852 bspLuxel = BSP_LUXEL( lightmapNum, x, 0 );
2853 bspLuxel2 = BSP_LUXEL( lightmapNum, x, lm->h - 1 );
2854 VectorAdd( bspLuxel, bspLuxel2, bspLuxel );
2855 VectorScale( bspLuxel, 0.5f, bspLuxel );
2856 VectorCopy( bspLuxel, bspLuxel2 );
2857 if ( deluxemap && lightmapNum == 0 ) {
2858 bspDeluxel = BSP_DELUXEL( x, 0 );
2859 bspDeluxel2 = BSP_DELUXEL( x, lm->h - 1 );
2860 VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel );
2861 VectorScale( bspDeluxel, 0.5f, bspDeluxel );
2862 VectorCopy( bspDeluxel, bspDeluxel2 );
2869 /* -----------------------------------------------------------------
2870 convert modelspace deluxemaps to tangentspace
2871 ----------------------------------------------------------------- */
2874 if ( deluxemap && deluxemode == 1 ) {
2875 vec3_t worldUp, myNormal, myTangent, myBinormal;
2878 Sys_Printf( "converting..." );
2880 for ( i = 0; i < numRawLightmaps; i++ )
2883 lm = &rawLightmaps[ i ];
2885 /* walk lightmap samples */
2886 for ( y = 0; y < lm->sh; y++ )
2888 for ( x = 0; x < lm->sw; x++ )
2890 /* get normal and deluxel */
2891 normal = SUPER_NORMAL( x, y );
2892 cluster = SUPER_CLUSTER( x, y );
2893 bspDeluxel = BSP_DELUXEL( x, y );
2894 deluxel = SUPER_DELUXEL( x, y );
2897 VectorSet( myNormal, normal[0], normal[1], normal[2] );
2899 /* get tangent vectors */
2900 if ( myNormal[ 0 ] == 0.0f && myNormal[ 1 ] == 0.0f ) {
2901 if ( myNormal[ 2 ] == 1.0f ) {
2902 VectorSet( myTangent, 1.0f, 0.0f, 0.0f );
2903 VectorSet( myBinormal, 0.0f, 1.0f, 0.0f );
2905 else if ( myNormal[ 2 ] == -1.0f ) {
2906 VectorSet( myTangent, -1.0f, 0.0f, 0.0f );
2907 VectorSet( myBinormal, 0.0f, 1.0f, 0.0f );
2912 VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
2913 CrossProduct( myNormal, worldUp, myTangent );
2914 VectorNormalize( myTangent, myTangent );
2915 CrossProduct( myTangent, myNormal, myBinormal );
2916 VectorNormalize( myBinormal, myBinormal );
2919 /* project onto plane */
2920 dist = -DotProduct( myTangent, myNormal );
2921 VectorMA( myTangent, dist, myNormal, myTangent );
2922 dist = -DotProduct( myBinormal, myNormal );
2923 VectorMA( myBinormal, dist, myNormal, myBinormal );
2926 VectorNormalize( myTangent, myTangent );
2927 VectorNormalize( myBinormal, myBinormal );
2929 /* convert modelspace deluxel to tangentspace */
2930 dirSample[0] = bspDeluxel[0];
2931 dirSample[1] = bspDeluxel[1];
2932 dirSample[2] = bspDeluxel[2];
2933 VectorNormalize( dirSample, dirSample );
2935 /* fix tangents to world matrix */
2936 if ( myNormal[0] > 0 || myNormal[1] < 0 || myNormal[2] < 0 ) {
2937 VectorNegate( myTangent, myTangent );
2940 /* build tangentspace vectors */
2941 bspDeluxel[0] = DotProduct( dirSample, myTangent );
2942 bspDeluxel[1] = DotProduct( dirSample, myBinormal );
2943 bspDeluxel[2] = DotProduct( dirSample, myNormal );
2950 /* -----------------------------------------------------------------
2952 ----------------------------------------------------------------- */
2954 #ifdef sdfsdfwq312323
2956 Sys_Printf( "blending..." );
2958 for ( i = 0; i < numRawLightmaps; i++ )
2964 lm = &rawLightmaps[ i ];
2966 /* walk individual lightmaps */
2967 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2970 if ( lm->superLuxels[ lightmapNum ] == NULL ) {
2974 /* walk lightmap samples */
2975 for ( y = 0; y < lm->sh; y++ )
2977 for ( x = 0; x < lm->sw; x++ )
2980 bspLuxel = BSP_LUXEL( lightmapNum, x, y );
2983 VectorNormalize( bspLuxel, myColor );
2984 myBrightness = VectorLength( bspLuxel );
2985 myBrightness *= ( 1 / 127.0f );
2986 myBrightness = myBrightness * myBrightness;
2987 myBrightness *= 127.0f;
2988 VectorScale( myColor, myBrightness, bspLuxel );
2995 /* -----------------------------------------------------------------
2996 collapse non-unique lightmaps
2997 ----------------------------------------------------------------- */
2999 if ( noCollapse == qfalse && deluxemap == qfalse ) {
3001 Sys_FPrintf( SYS_VRB, "collapsing..." );
3003 /* set all twin refs to null */
3004 for ( i = 0; i < numRawLightmaps; i++ )
3006 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3008 rawLightmaps[ i ].twins[ lightmapNum ] = NULL;
3009 rawLightmaps[ i ].twinNums[ lightmapNum ] = -1;
3010 rawLightmaps[ i ].numStyledTwins = 0;
3014 /* walk the list of raw lightmaps */
3015 for ( i = 0; i < numRawLightmaps; i++ )
3018 lm = &rawLightmaps[ i ];
3020 /* walk lightmaps */
3021 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3024 if ( lm->bspLuxels[ lightmapNum ] == NULL ||
3025 lm->twins[ lightmapNum ] != NULL ) {
3029 /* find all lightmaps that are virtually identical to this one */
3030 for ( j = i + 1; j < numRawLightmaps; j++ )
3033 lm2 = &rawLightmaps[ j ];
3035 /* walk lightmaps */
3036 for ( lightmapNum2 = 0; lightmapNum2 < MAX_LIGHTMAPS; lightmapNum2++ )
3039 if ( lm2->bspLuxels[ lightmapNum2 ] == NULL ||
3040 lm2->twins[ lightmapNum2 ] != NULL ) {
3045 if ( CompareBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ) ) {
3046 /* merge and set twin */
3047 if ( MergeBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ) ) {
3048 lm2->twins[ lightmapNum2 ] = lm;
3049 lm2->twinNums[ lightmapNum2 ] = lightmapNum;
3051 numTwinLuxels += ( lm->w * lm->h );
3053 /* count styled twins */
3054 if ( lightmapNum > 0 ) {
3055 lm->numStyledTwins++;
3065 /* -----------------------------------------------------------------
3066 sort raw lightmaps by shader
3067 ----------------------------------------------------------------- */
3070 Sys_FPrintf( SYS_VRB, "sorting..." );
3072 /* allocate a new sorted list */
3073 if ( sortLightmaps == NULL ) {
3074 sortLightmaps = safe_malloc( numRawLightmaps * sizeof( int ) );
3077 /* fill it out and sort it */
3078 for ( i = 0; i < numRawLightmaps; i++ )
3079 sortLightmaps[ i ] = i;
3080 qsort( sortLightmaps, numRawLightmaps, sizeof( int ), CompareRawLightmap );
3082 /* -----------------------------------------------------------------
3083 allocate output lightmaps
3084 ----------------------------------------------------------------- */
3087 Sys_FPrintf( SYS_VRB, "allocating..." );
3089 /* kill all existing output lightmaps */
3090 if ( outLightmaps != NULL ) {
3091 for ( i = 0; i < numOutLightmaps; i++ )
3093 free( outLightmaps[ i ].lightBits );
3094 free( outLightmaps[ i ].bspLightBytes );
3096 free( outLightmaps );
3097 outLightmaps = NULL;
3100 numLightmapShaders = 0;
3101 numOutLightmaps = 0;
3102 numBSPLightmaps = 0;
3103 numExtLightmaps = 0;
3105 /* find output lightmap */
3106 for ( i = 0; i < numRawLightmaps; i++ )
3108 lm = &rawLightmaps[ sortLightmaps[ i ] ];
3109 FindOutLightmaps( lm, fastAllocate );
3112 /* set output numbers in twinned lightmaps */
3113 for ( i = 0; i < numRawLightmaps; i++ )
3116 lm = &rawLightmaps[ sortLightmaps[ i ] ];
3118 /* walk lightmaps */
3119 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3122 lm2 = lm->twins[ lightmapNum ];
3123 if ( lm2 == NULL ) {
3126 lightmapNum2 = lm->twinNums[ lightmapNum ];
3128 /* find output lightmap from twin */
3129 lm->outLightmapNums[ lightmapNum ] = lm2->outLightmapNums[ lightmapNum2 ];
3130 lm->lightmapX[ lightmapNum ] = lm2->lightmapX[ lightmapNum2 ];
3131 lm->lightmapY[ lightmapNum ] = lm2->lightmapY[ lightmapNum2 ];
3135 /* -----------------------------------------------------------------
3136 store output lightmaps
3137 ----------------------------------------------------------------- */
3140 Sys_FPrintf( SYS_VRB, "storing..." );
3142 /* count the bsp lightmaps and allocate space */
3143 if ( bspLightBytes != NULL ) {
3144 free( bspLightBytes );
3146 if ( numBSPLightmaps == 0 || externalLightmaps ) {
3147 numBSPLightBytes = 0;
3148 bspLightBytes = NULL;
3152 numBSPLightBytes = ( numBSPLightmaps * game->lightmapSize * game->lightmapSize * 3 );
3153 bspLightBytes = safe_malloc( numBSPLightBytes );
3154 memset( bspLightBytes, 0, numBSPLightBytes );
3157 /* walk the list of output lightmaps */
3158 for ( i = 0; i < numOutLightmaps; i++ )
3160 /* get output lightmap */
3161 olm = &outLightmaps[ i ];
3163 /* fill output lightmap */
3164 if ( lightmapFill ) {
3165 FillOutLightmap( olm );
3168 /* is this a valid bsp lightmap? */
3169 if ( olm->lightmapNum >= 0 && !externalLightmaps ) {
3170 /* copy lighting data */
3171 lb = bspLightBytes + ( olm->lightmapNum * game->lightmapSize * game->lightmapSize * 3 );
3172 memcpy( lb, olm->bspLightBytes, game->lightmapSize * game->lightmapSize * 3 );
3174 /* copy direction data */
3176 lb = bspLightBytes + ( ( olm->lightmapNum + 1 ) * game->lightmapSize * game->lightmapSize * 3 );
3177 memcpy( lb, olm->bspDirBytes, game->lightmapSize * game->lightmapSize * 3 );
3181 /* external lightmap? */
3182 if ( olm->lightmapNum < 0 || olm->extLightmapNum >= 0 || externalLightmaps ) {
3183 /* make a directory for the lightmaps */
3186 /* set external lightmap number */
3187 olm->extLightmapNum = numExtLightmaps;
3189 /* write lightmap */
3190 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
3191 Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
3192 WriteTGA24( filename, olm->bspLightBytes, olm->customWidth, olm->customHeight, qtrue );
3195 /* write deluxemap */
3197 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
3198 Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
3199 WriteTGA24( filename, olm->bspDirBytes, olm->customWidth, olm->customHeight, qtrue );
3202 if ( debugDeluxemap ) {
3203 olm->extLightmapNum++;
3209 if ( numExtLightmaps > 0 ) {
3210 Sys_FPrintf( SYS_VRB, "\n" );
3213 /* delete unused external lightmaps */
3214 for ( i = numExtLightmaps; i; i++ )
3216 /* determine if file exists */
3217 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, i );
3218 if ( !FileExists( filename ) ) {
3226 /* -----------------------------------------------------------------
3227 project the lightmaps onto the bsp surfaces
3228 ----------------------------------------------------------------- */
3231 Sys_FPrintf( SYS_VRB, "projecting..." );
3233 /* walk the list of surfaces */
3234 for ( i = 0; i < numBSPDrawSurfaces; i++ )
3236 /* get the surface and info */
3237 ds = &bspDrawSurfaces[ i ];
3238 info = &surfaceInfos[ i ];
3242 /* handle surfaces with identical parent */
3243 if ( info->parentSurfaceNum >= 0 ) {
3244 /* preserve original data and get parent */
3245 parent = &bspDrawSurfaces[ info->parentSurfaceNum ];
3246 memcpy( &dsTemp, ds, sizeof( *ds ) );
3248 /* overwrite child with parent data */
3249 memcpy( ds, parent, sizeof( *ds ) );
3251 /* restore key parts */
3252 ds->fogNum = dsTemp.fogNum;
3253 ds->firstVert = dsTemp.firstVert;
3254 ds->firstIndex = dsTemp.firstIndex;
3255 memcpy( ds->lightmapVecs, dsTemp.lightmapVecs, sizeof( dsTemp.lightmapVecs ) );
3257 /* set vertex data */
3258 dv = &bspDrawVerts[ ds->firstVert ];
3259 dvParent = &bspDrawVerts[ parent->firstVert ];
3260 for ( j = 0; j < ds->numVerts; j++ )
3262 memcpy( dv[ j ].lightmap, dvParent[ j ].lightmap, sizeof( dv[ j ].lightmap ) );
3263 memcpy( dv[ j ].color, dvParent[ j ].color, sizeof( dv[ j ].color ) );
3270 /* handle vertex lit or approximated surfaces */
3271 else if ( lm == NULL || lm->outLightmapNums[ 0 ] < 0 ) {
3272 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3274 ds->lightmapNum[ lightmapNum ] = -3;
3275 ds->lightmapStyles[ lightmapNum ] = ds->vertexStyles[ lightmapNum ];
3279 /* handle lightmapped surfaces */
3282 /* walk lightmaps */
3283 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3286 ds->lightmapStyles[ lightmapNum ] = lm->styles[ lightmapNum ];
3288 /* handle unused style */
3289 if ( lm->styles[ lightmapNum ] == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 ) {
3290 ds->lightmapNum[ lightmapNum ] = -3;
3294 /* get output lightmap */
3295 olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
3297 /* set bsp lightmap number */
3298 ds->lightmapNum[ lightmapNum ] = olm->lightmapNum;
3300 /* deluxemap debugging makes the deluxemap visible */
3301 if ( deluxemap && debugDeluxemap && lightmapNum == 0 ) {
3302 ds->lightmapNum[ lightmapNum ]++;
3305 /* calc lightmap origin in texture space */
3306 lmx = (float) lm->lightmapX[ lightmapNum ] / (float) olm->customWidth;
3307 lmy = (float) lm->lightmapY[ lightmapNum ] / (float) olm->customHeight;
3309 /* calc lightmap st coords */
3310 dv = &bspDrawVerts[ ds->firstVert ];
3311 ydv = &yDrawVerts[ ds->firstVert ];
3312 for ( j = 0; j < ds->numVerts; j++ )
3314 if ( lm->solid[ lightmapNum ] ) {
3315 dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + ( 0.5f / (float) olm->customWidth );
3316 dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + ( 0.5f / (float) olm->customWidth );
3320 dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + ( ydv[ j ].lightmap[ 0 ][ 0 ] / ( superSample * olm->customWidth ) );
3321 dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + ( ydv[ j ].lightmap[ 0 ][ 1 ] / ( superSample * olm->customHeight ) );
3327 /* store vertex colors */
3328 dv = &bspDrawVerts[ ds->firstVert ];
3329 for ( j = 0; j < ds->numVerts; j++ )
3331 /* walk lightmaps */
3332 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3334 /* handle unused style */
3335 if ( ds->vertexStyles[ lightmapNum ] == LS_NONE ) {
3336 VectorClear( color );
3340 /* get vertex color */
3341 luxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + j );
3342 VectorCopy( luxel, color );
3344 /* set minimum light */
3345 if ( lightmapNum == 0 ) {
3346 for ( k = 0; k < 3; k++ )
3347 if ( color[ k ] < minVertexLight[ k ] ) {
3348 color[ k ] = minVertexLight[ k ];
3353 /* store to bytes */
3354 if ( !info->si->noVertexLight ) {
3355 ColorToBytes( color, dv[ j ].color[ lightmapNum ], info->si->vertexScale );
3360 /* surfaces with styled lightmaps and a style marker get a custom generated shader (fixme: make this work with external lightmaps) */
3361 if ( olm != NULL && lm != NULL && lm->styles[ 1 ] != LS_NONE && game->load != LoadRBSPFile ) { //% info->si->styleMarker > 0 )
3363 char key[ 32 ], styleStage[ 512 ], styleStages[ 4096 ], rgbGen[ 128 ], alphaGen[ 128 ];
3367 sprintf( styleStages, "\n\t// Q3Map2 custom lightstyle stage(s)\n" );
3368 dv = &bspDrawVerts[ ds->firstVert ];
3370 /* depthFunc equal? */
3371 if ( info->si->styleMarker == 2 || info->si->implicitMap == IM_MASKED ) {
3378 /* generate stages for styled lightmaps */
3379 for ( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3382 style = lm->styles[ lightmapNum ];
3383 if ( style == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 ) {
3387 /* get output lightmap */
3388 olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
3391 if ( lm->outLightmapNums[ lightmapNum ] == lm->outLightmapNums[ 0 ] ) {
3392 strcpy( lightmapName, "$lightmap" );
3395 sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
3398 /* get rgbgen string */
3399 if ( rgbGenValues[ style ] == NULL ) {
3400 sprintf( key, "_style%drgbgen", style );
3401 rgbGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
3402 if ( rgbGenValues[ style ][ 0 ] == '\0' ) {
3403 rgbGenValues[ style ] = "wave noise 0.5 1 0 5.37";
3407 if ( rgbGenValues[ style ][ 0 ] != '\0' ) {
3408 sprintf( rgbGen, "\t\trgbGen %s // style %d\n", rgbGenValues[ style ], style );
3414 /* get alphagen string */
3415 if ( alphaGenValues[ style ] == NULL ) {
3416 sprintf( key, "_style%dalphagen", style );
3417 alphaGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
3419 if ( alphaGenValues[ style ][ 0 ] != '\0' ) {
3420 sprintf( alphaGen, "\t\talphaGen %s // style %d\n", alphaGenValues[ style ], style );
3423 alphaGen[ 0 ] = '\0';
3426 /* calculate st offset */
3427 lmx = dv[ 0 ].lightmap[ lightmapNum ][ 0 ] - dv[ 0 ].lightmap[ 0 ][ 0 ];
3428 lmy = dv[ 0 ].lightmap[ lightmapNum ][ 1 ] - dv[ 0 ].lightmap[ 0 ][ 1 ];
3430 /* create additional stage */
3431 if ( lmx == 0.0f && lmy == 0.0f ) {
3432 sprintf( styleStage, "\t{\n"
3433 "\t\tmap %s\n" /* lightmap */
3434 "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
3435 "%s" /* depthFunc equal */
3438 "\t\ttcGen lightmap\n"
3441 ( dfEqual ? "\t\tdepthFunc equal\n" : "" ),
3447 sprintf( styleStage, "\t{\n"
3448 "\t\tmap %s\n" /* lightmap */
3449 "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
3450 "%s" /* depthFunc equal */
3453 "\t\ttcGen lightmap\n"
3454 "\t\ttcMod transform 1 0 0 1 %1.5f %1.5f\n" /* st offset */
3457 ( dfEqual ? "\t\tdepthFunc equal\n" : "" ),
3465 strcat( styleStages, styleStage );
3468 /* create custom shader */
3469 if ( info->si->styleMarker == 2 ) {
3470 csi = CustomShader( info->si, "q3map_styleMarker2", styleStages );
3473 csi = CustomShader( info->si, "q3map_styleMarker", styleStages );
3476 /* emit remap command */
3477 //% EmitVertexRemapShader( csi->shader, info->si->shader );
3480 //% Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
3481 ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3482 //% Sys_Printf( ")\n" );
3485 /* devise a custom shader for this surface (fixme: make this work with light styles) */
3486 else if ( olm != NULL && lm != NULL && !externalLightmaps &&
3487 ( olm->customWidth != game->lightmapSize || olm->customHeight != game->lightmapSize ) ) {
3488 /* get output lightmap */
3489 olm = &outLightmaps[ lm->outLightmapNums[ 0 ] ];
3491 /* do some name mangling */
3492 sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
3494 /* create custom shader */
3495 csi = CustomShader( info->si, "$lightmap", lightmapName );
3498 //% Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
3499 ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3500 //% Sys_Printf( ")\n" );
3503 /* use the normal plain-jane shader */
3505 ds->shaderNum = EmitShader( info->si->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3510 Sys_FPrintf( SYS_VRB, "done.\n" );
3512 /* calc num stored */
3513 numStored = numBSPLightBytes / 3;
3514 efficiency = ( numStored <= 0 )
3516 : (float) numUsed / (float) numStored;
3519 Sys_Printf( "%9d luxels used\n", numUsed );
3520 Sys_Printf( "%9d luxels stored (%3.2f percent efficiency)\n", numStored, efficiency * 100.0f );
3521 Sys_Printf( "%9d solid surface lightmaps\n", numSolidLightmaps );
3522 Sys_Printf( "%9d identical surface lightmaps, using %d luxels\n", numTwins, numTwinLuxels );
3523 Sys_Printf( "%9d vertex forced surfaces\n", numSurfsVertexForced );
3524 Sys_Printf( "%9d vertex approximated surfaces\n", numSurfsVertexApproximated );
3525 Sys_Printf( "%9d BSP lightmaps\n", numBSPLightmaps );
3526 Sys_Printf( "%9d total lightmaps\n", numOutLightmaps );
3527 Sys_Printf( "%9d unique lightmap/shader combinations\n", numLightmapShaders );
3529 /* write map shader file */
3530 WriteMapShaderFile();