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 ) );
2186 if ( outLightmaps != NULL && numOutLightmaps > LIGHTMAP_RESERVE_COUNT ) {
2187 memcpy( olm, outLightmaps, ( numOutLightmaps - LIGHTMAP_RESERVE_COUNT ) * sizeof( outLightmap_t ) );
2188 free( outLightmaps );
2192 /* initialize both out lightmaps */
2193 for ( k = numOutLightmaps - LIGHTMAP_RESERVE_COUNT; k < numOutLightmaps; ++k )
2194 SetupOutLightmap( lm, &outLightmaps[ k ] );
2196 /* set out lightmap */
2197 i = numOutLightmaps - LIGHTMAP_RESERVE_COUNT;
2198 olm = &outLightmaps[ i ];
2200 /* set stamp xy origin to the first surface lightmap */
2201 if ( lightmapNum > 0 ) {
2202 x = lm->lightmapX[ 0 ];
2203 y = lm->lightmapY[ 0 ];
2207 /* if this is a style-using lightmap, it must be exported */
2208 if ( lightmapNum > 0 && game->load != LoadRBSPFile ) {
2209 olm->extLightmapNum = 0;
2212 /* add the surface lightmap to the bsp lightmap */
2213 lm->outLightmapNums[ lightmapNum ] = i;
2214 lm->lightmapX[ lightmapNum ] = x;
2215 lm->lightmapY[ lightmapNum ] = y;
2216 olm->numLightmaps++;
2219 for ( i = 0; i < lm->numLightSurfaces; i++ )
2221 /* get surface info */
2222 info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + i ] ];
2224 /* test for shader */
2225 for ( j = 0; j < olm->numShaders; j++ )
2227 if ( olm->shaders[ j ] == info->si ) {
2232 /* if it doesn't exist, add it */
2233 if ( j >= olm->numShaders && olm->numShaders < MAX_LIGHTMAP_SHADERS ) {
2234 olm->shaders[ olm->numShaders ] = info->si;
2236 numLightmapShaders++;
2241 if ( lm->solid[ lightmapNum ] ) {
2251 /* mark the bits used */
2252 for ( y = 0; y < yMax; y++ )
2254 for ( x = 0; x < xMax; x++ )
2257 luxel = BSP_LUXEL( lightmapNum, x, y );
2258 deluxel = BSP_DELUXEL( x, y );
2259 if ( luxel[ 0 ] < 0.0f && !lm->solid[ lightmapNum ] ) {
2263 /* set minimum light */
2264 if ( lm->solid[ lightmapNum ] ) {
2266 VectorSet( color, 255.0f, 0.0f, 0.0f );
2269 VectorCopy( lm->solidColor[ lightmapNum ], color );
2273 VectorCopy( luxel, color );
2276 /* styles are not affected by minlight */
2277 if ( lightmapNum == 0 ) {
2278 for ( i = 0; i < 3; i++ )
2280 if ( color[ i ] < minLight[ i ] ) {
2281 color[ i ] = minLight[ i ];
2286 /* get bsp lightmap coords */
2287 ox = x + lm->lightmapX[ lightmapNum ];
2288 oy = y + lm->lightmapY[ lightmapNum ];
2289 offset = ( oy * olm->customWidth ) + ox;
2291 /* flag pixel as used */
2292 olm->lightBits[ offset >> 3 ] |= ( 1 << ( offset & 7 ) );
2296 pixel = olm->bspLightBytes + ( ( ( oy * olm->customWidth ) + ox ) * 3 );
2297 ColorToBytes( color, pixel, lm->brightness );
2299 /* store direction */
2301 /* normalize average light direction */
2302 pixel = olm->bspDirBytes + ( ( ( oy * olm->customWidth ) + ox ) * 3 );
2303 VectorScale( deluxel, 1000.0f, direction );
2304 VectorNormalize( direction, direction );
2305 VectorScale( direction, 127.5f, direction );
2306 for ( i = 0; i < 3; i++ )
2307 pixel[ i ] = (byte)( 127.5f + direction[ i ] );
2317 CompareRawLightmap()
2318 compare function for qsort()
2321 static int CompareRawLightmap( const void *a, const void *b ){
2322 rawLightmap_t *alm, *blm;
2323 surfaceInfo_t *aInfo, *bInfo;
2328 alm = &rawLightmaps[ *( (const int*) a ) ];
2329 blm = &rawLightmaps[ *( (const int*) b ) ];
2331 /* get min number of surfaces */
2332 min = ( alm->numLightSurfaces < blm->numLightSurfaces ? alm->numLightSurfaces : blm->numLightSurfaces );
2335 for ( i = 0; i < min; i++ )
2337 /* get surface info */
2338 aInfo = &surfaceInfos[ lightSurfaces[ alm->firstLightSurface + i ] ];
2339 bInfo = &surfaceInfos[ lightSurfaces[ blm->firstLightSurface + i ] ];
2341 /* compare shader names */
2342 diff = strcmp( aInfo->si->shader, bInfo->si->shader );
2348 /* test style count */
2350 for ( i = 0; i < MAX_LIGHTMAPS; i++ )
2351 diff += blm->styles[ i ] - alm->styles[ i ];
2357 diff = ( blm->w * blm->h ) - ( alm->w * alm->h );
2362 /* must be equivalent */
2368 void FillOutLightmap( outLightmap_t *olm ){
2371 vec3_t dir_sum, light_sum;
2373 byte *lightBitsNew = NULL;
2374 byte *lightBytesNew = NULL;
2375 byte *dirBytesNew = NULL;
2377 lightBitsNew = safe_malloc( ( olm->customWidth * olm->customHeight + 8 ) / 8 );
2378 lightBytesNew = safe_malloc( olm->customWidth * olm->customHeight * 3 );
2380 dirBytesNew = safe_malloc( olm->customWidth * olm->customHeight * 3 );
2384 memset(olm->lightBits, 0, (olm->customWidth * olm->customHeight + 8) / 8);
2385 olm->lightBits[0] |= 1;
2386 olm->lightBits[(10 * olm->customWidth + 30) >> 3] |= 1 << ((10 * olm->customWidth + 30) & 7);
2387 memset(olm->bspLightBytes, 0, olm->customWidth * olm->customHeight * 3);
2388 olm->bspLightBytes[0] = 255;
2389 olm->bspLightBytes[(10 * olm->customWidth + 30) * 3 + 2] = 255;
2392 memcpy( lightBitsNew, olm->lightBits, ( olm->customWidth * olm->customHeight + 8 ) / 8 );
2393 memcpy( lightBytesNew, olm->bspLightBytes, olm->customWidth * olm->customHeight * 3 );
2395 memcpy( dirBytesNew, olm->bspDirBytes, olm->customWidth * olm->customHeight * 3 );
2401 for ( y = 0; y < olm->customHeight; ++y )
2403 for ( x = 0; x < olm->customWidth; ++x )
2405 ofs = y * olm->customWidth + x;
2406 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2410 VectorClear( dir_sum );
2411 VectorClear( light_sum );
2413 /* try all four neighbors */
2414 ofs = ( ( y + olm->customHeight - 1 ) % olm->customHeight ) * olm->customWidth + x;
2415 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2417 VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2419 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2423 ofs = ( ( y + 1 ) % olm->customHeight ) * olm->customWidth + x;
2424 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2426 VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2428 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2432 ofs = y * olm->customWidth + ( x + olm->customWidth - 1 ) % olm->customWidth;
2433 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2435 VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2437 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2441 ofs = y * olm->customWidth + ( x + 1 ) % olm->customWidth;
2442 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2444 VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2446 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2452 ofs = y * olm->customWidth + x;
2453 lightBitsNew[ofs >> 3] |= ( 1 << ( ofs & 7 ) );
2454 VectorScale( light_sum, 1.0 / cnt, lightBytesNew + ofs * 3 );
2456 VectorScale( dir_sum, 1.0 / cnt, dirBytesNew + ofs * 3 );
2466 memcpy( olm->lightBits, lightBitsNew, ( olm->customWidth * olm->customHeight + 8 ) / 8 );
2467 memcpy( olm->bspLightBytes, lightBytesNew, olm->customWidth * olm->customHeight * 3 );
2469 memcpy( olm->bspDirBytes, dirBytesNew, olm->customWidth * olm->customHeight * 3 );
2473 free( lightBitsNew );
2474 free( lightBytesNew );
2476 free( dirBytesNew );
2483 StoreSurfaceLightmaps()
2484 stores the surface lightmaps into the bsp as byte rgb triplets
2487 void StoreSurfaceLightmaps( qboolean fastAllocate ){
2488 int i, j, k, x, y, lx, ly, sx, sy, *cluster, mappedSamples;
2489 int style, size, lightmapNum, lightmapNum2;
2490 float *normal, *luxel, *bspLuxel, *bspLuxel2, *radLuxel, samples, occludedSamples;
2491 vec3_t sample, occludedSample, dirSample, colorMins, colorMaxs;
2492 float *deluxel, *bspDeluxel, *bspDeluxel2;
2494 int numUsed, numTwins, numTwinLuxels, numStored;
2495 float lmx, lmy, efficiency;
2497 bspDrawSurface_t *ds, *parent, dsTemp;
2498 surfaceInfo_t *info;
2499 rawLightmap_t *lm, *lm2;
2501 bspDrawVert_t *dv, *ydv, *dvParent;
2502 char dirname[ 1024 ], filename[ 1024 ];
2504 char lightmapName[ 128 ];
2505 const char *rgbGenValues[ 256 ];
2506 const char *alphaGenValues[ 256 ];
2510 Sys_Printf( "--- StoreSurfaceLightmaps ---\n" );
2513 if ( lmCustomDir ) {
2514 strcpy( dirname, lmCustomDir );
2518 strcpy( dirname, source );
2519 StripExtension( dirname );
2521 memset( rgbGenValues, 0, sizeof( rgbGenValues ) );
2522 memset( alphaGenValues, 0, sizeof( alphaGenValues ) );
2524 /* -----------------------------------------------------------------
2525 average the sampled luxels into the bsp luxels
2526 ----------------------------------------------------------------- */
2529 Sys_FPrintf( SYS_VRB, "Subsampling..." );
2531 /* walk the list of raw lightmaps */
2535 numSolidLightmaps = 0;
2536 for ( i = 0; i < numRawLightmaps; i++ )
2539 lm = &rawLightmaps[ i ];
2541 /* walk individual lightmaps */
2542 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2545 if ( lm->superLuxels[ lightmapNum ] == NULL ) {
2549 /* allocate bsp luxel storage */
2550 if ( lm->bspLuxels[ lightmapNum ] == NULL ) {
2551 size = lm->w * lm->h * BSP_LUXEL_SIZE * sizeof( float );
2552 lm->bspLuxels[ lightmapNum ] = safe_malloc( size );
2553 memset( lm->bspLuxels[ lightmapNum ], 0, size );
2556 /* allocate radiosity lightmap storage */
2558 size = lm->w * lm->h * RAD_LUXEL_SIZE * sizeof( float );
2559 if ( lm->radLuxels[ lightmapNum ] == NULL ) {
2560 lm->radLuxels[ lightmapNum ] = safe_malloc( size );
2562 memset( lm->radLuxels[ lightmapNum ], 0, size );
2565 /* average supersampled luxels */
2566 for ( y = 0; y < lm->h; y++ )
2568 for ( x = 0; x < lm->w; x++ )
2572 occludedSamples = 0.0f;
2574 VectorClear( sample );
2575 VectorClear( occludedSample );
2576 VectorClear( dirSample );
2577 for ( ly = 0; ly < superSample; ly++ )
2579 for ( lx = 0; lx < superSample; lx++ )
2582 sx = x * superSample + lx;
2583 sy = y * superSample + ly;
2584 luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2585 deluxel = SUPER_DELUXEL( sx, sy );
2586 normal = SUPER_NORMAL( sx, sy );
2587 cluster = SUPER_CLUSTER( sx, sy );
2589 /* sample deluxemap */
2590 if ( deluxemap && lightmapNum == 0 ) {
2591 VectorAdd( dirSample, deluxel, dirSample );
2594 /* keep track of used/occluded samples */
2595 if ( *cluster != CLUSTER_UNMAPPED ) {
2599 /* handle lightmap border? */
2600 if ( lightmapBorder && ( sx == 0 || sx == ( lm->sw - 1 ) || sy == 0 || sy == ( lm->sh - 1 ) ) && luxel[ 3 ] > 0.0f ) {
2601 VectorSet( sample, 255.0f, 0.0f, 0.0f );
2606 else if ( debug && *cluster < 0 ) {
2607 if ( *cluster == CLUSTER_UNMAPPED ) {
2608 VectorSet( luxel, 255, 204, 0 );
2610 else if ( *cluster == CLUSTER_OCCLUDED ) {
2611 VectorSet( luxel, 255, 0, 255 );
2613 else if ( *cluster == CLUSTER_FLOODED ) {
2614 VectorSet( luxel, 0, 32, 255 );
2616 VectorAdd( occludedSample, luxel, occludedSample );
2617 occludedSamples += 1.0f;
2620 /* normal luxel handling */
2621 else if ( luxel[ 3 ] > 0.0f ) {
2622 /* handle lit or flooded luxels */
2623 if ( *cluster > 0 || *cluster == CLUSTER_FLOODED ) {
2624 VectorAdd( sample, luxel, sample );
2625 samples += luxel[ 3 ];
2628 /* handle occluded or unmapped luxels */
2631 VectorAdd( occludedSample, luxel, occludedSample );
2632 occludedSamples += luxel[ 3 ];
2635 /* handle style debugging */
2636 if ( debug && lightmapNum > 0 && x < 2 && y < 2 ) {
2637 VectorCopy( debugColors[ 0 ], sample );
2644 /* only use occluded samples if necessary */
2645 if ( samples <= 0.0f ) {
2646 VectorCopy( occludedSample, sample );
2647 samples = occludedSamples;
2651 luxel = SUPER_LUXEL( lightmapNum, x, y );
2652 deluxel = SUPER_DELUXEL( x, y );
2654 /* store light direction */
2655 if ( deluxemap && lightmapNum == 0 ) {
2656 VectorCopy( dirSample, deluxel );
2659 /* store the sample back in super luxels */
2660 if ( samples > 0.01f ) {
2661 VectorScale( sample, ( 1.0f / samples ), luxel );
2665 /* if any samples were mapped in any way, store ambient color */
2666 else if ( mappedSamples > 0 ) {
2667 if ( lightmapNum == 0 ) {
2668 VectorCopy( ambientColor, luxel );
2671 VectorClear( luxel );
2676 /* store a bogus value to be fixed later */
2679 VectorClear( luxel );
2687 ClearBounds( colorMins, colorMaxs );
2689 /* clean up and store into bsp luxels */
2690 for ( y = 0; y < lm->h; y++ )
2692 for ( x = 0; x < lm->w; x++ )
2695 luxel = SUPER_LUXEL( lightmapNum, x, y );
2696 deluxel = SUPER_DELUXEL( x, y );
2698 /* copy light direction */
2699 if ( deluxemap && lightmapNum == 0 ) {
2700 VectorCopy( deluxel, dirSample );
2703 /* is this a valid sample? */
2704 if ( luxel[ 3 ] > 0.0f ) {
2705 VectorCopy( luxel, sample );
2706 samples = luxel[ 3 ];
2710 /* fix negative samples */
2711 for ( j = 0; j < 3; j++ )
2713 if ( sample[ j ] < 0.0f ) {
2720 /* nick an average value from the neighbors */
2721 VectorClear( sample );
2722 VectorClear( dirSample );
2725 /* fixme: why is this disabled?? */
2726 for ( sy = ( y - 1 ); sy <= ( y + 1 ); sy++ )
2728 if ( sy < 0 || sy >= lm->h ) {
2732 for ( sx = ( x - 1 ); sx <= ( x + 1 ); sx++ )
2734 if ( sx < 0 || sx >= lm->w || ( sx == x && sy == y ) ) {
2738 /* get neighbor's particulars */
2739 luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2740 if ( luxel[ 3 ] < 0.0f ) {
2743 VectorAdd( sample, luxel, sample );
2744 samples += luxel[ 3 ];
2749 if ( samples == 0.0f ) {
2750 VectorSet( sample, -1.0f, -1.0f, -1.0f );
2758 /* fix negative samples */
2759 for ( j = 0; j < 3; j++ )
2761 if ( sample[ j ] < 0.0f ) {
2768 /* scale the sample */
2769 VectorScale( sample, ( 1.0f / samples ), sample );
2771 /* store the sample in the radiosity luxels */
2773 radLuxel = RAD_LUXEL( lightmapNum, x, y );
2774 VectorCopy( sample, radLuxel );
2776 /* if only storing bounced light, early out here */
2777 if ( bounceOnly && !bouncing ) {
2782 /* store the sample in the bsp luxels */
2783 bspLuxel = BSP_LUXEL( lightmapNum, x, y );
2784 bspDeluxel = BSP_DELUXEL( x, y );
2786 VectorAdd( bspLuxel, sample, bspLuxel );
2787 if ( deluxemap && lightmapNum == 0 ) {
2788 VectorAdd( bspDeluxel, dirSample, bspDeluxel );
2791 /* add color to bounds for solid checking */
2792 if ( samples > 0.0f ) {
2793 AddPointToBounds( bspLuxel, colorMins, colorMaxs );
2798 /* set solid color */
2799 lm->solid[ lightmapNum ] = qfalse;
2800 VectorAdd( colorMins, colorMaxs, lm->solidColor[ lightmapNum ] );
2801 VectorScale( lm->solidColor[ lightmapNum ], 0.5f, lm->solidColor[ lightmapNum ] );
2803 /* nocollapse prevents solid lightmaps */
2804 if ( noCollapse == qfalse ) {
2805 /* check solid color */
2806 VectorSubtract( colorMaxs, colorMins, sample );
2807 if ( ( sample[ 0 ] <= SOLID_EPSILON && sample[ 1 ] <= SOLID_EPSILON && sample[ 2 ] <= SOLID_EPSILON ) ||
2808 ( lm->w <= 2 && lm->h <= 2 ) ) { /* small lightmaps get forced to solid color */
2810 VectorCopy( colorMins, lm->solidColor[ lightmapNum ] );
2811 lm->solid[ lightmapNum ] = qtrue;
2812 numSolidLightmaps++;
2815 /* if all lightmaps aren't solid, then none of them are solid */
2816 if ( lm->solid[ lightmapNum ] != lm->solid[ 0 ] ) {
2817 for ( y = 0; y < MAX_LIGHTMAPS; y++ )
2819 if ( lm->solid[ y ] ) {
2820 numSolidLightmaps--;
2822 lm->solid[ y ] = qfalse;
2827 /* wrap bsp luxels if necessary */
2828 if ( lm->wrap[ 0 ] ) {
2829 for ( y = 0; y < lm->h; y++ )
2831 bspLuxel = BSP_LUXEL( lightmapNum, 0, y );
2832 bspLuxel2 = BSP_LUXEL( lightmapNum, lm->w - 1, y );
2833 VectorAdd( bspLuxel, bspLuxel2, bspLuxel );
2834 VectorScale( bspLuxel, 0.5f, bspLuxel );
2835 VectorCopy( bspLuxel, bspLuxel2 );
2836 if ( deluxemap && lightmapNum == 0 ) {
2837 bspDeluxel = BSP_DELUXEL( 0, y );
2838 bspDeluxel2 = BSP_DELUXEL( lm->w - 1, y );
2839 VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel );
2840 VectorScale( bspDeluxel, 0.5f, bspDeluxel );
2841 VectorCopy( bspDeluxel, bspDeluxel2 );
2845 if ( lm->wrap[ 1 ] ) {
2846 for ( x = 0; x < lm->w; x++ )
2848 bspLuxel = BSP_LUXEL( lightmapNum, x, 0 );
2849 bspLuxel2 = BSP_LUXEL( lightmapNum, x, lm->h - 1 );
2850 VectorAdd( bspLuxel, bspLuxel2, bspLuxel );
2851 VectorScale( bspLuxel, 0.5f, bspLuxel );
2852 VectorCopy( bspLuxel, bspLuxel2 );
2853 if ( deluxemap && lightmapNum == 0 ) {
2854 bspDeluxel = BSP_DELUXEL( x, 0 );
2855 bspDeluxel2 = BSP_DELUXEL( x, lm->h - 1 );
2856 VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel );
2857 VectorScale( bspDeluxel, 0.5f, bspDeluxel );
2858 VectorCopy( bspDeluxel, bspDeluxel2 );
2865 /* -----------------------------------------------------------------
2866 convert modelspace deluxemaps to tangentspace
2867 ----------------------------------------------------------------- */
2870 if ( deluxemap && deluxemode == 1 ) {
2871 vec3_t worldUp, myNormal, myTangent, myBinormal;
2874 Sys_Printf( "converting..." );
2876 for ( i = 0; i < numRawLightmaps; i++ )
2879 lm = &rawLightmaps[ i ];
2881 /* walk lightmap samples */
2882 for ( y = 0; y < lm->sh; y++ )
2884 for ( x = 0; x < lm->sw; x++ )
2886 /* get normal and deluxel */
2887 normal = SUPER_NORMAL( x, y );
2888 cluster = SUPER_CLUSTER( x, y );
2889 bspDeluxel = BSP_DELUXEL( x, y );
2890 deluxel = SUPER_DELUXEL( x, y );
2893 VectorSet( myNormal, normal[0], normal[1], normal[2] );
2895 /* get tangent vectors */
2896 if ( myNormal[ 0 ] == 0.0f && myNormal[ 1 ] == 0.0f ) {
2897 if ( myNormal[ 2 ] == 1.0f ) {
2898 VectorSet( myTangent, 1.0f, 0.0f, 0.0f );
2899 VectorSet( myBinormal, 0.0f, 1.0f, 0.0f );
2901 else if ( myNormal[ 2 ] == -1.0f ) {
2902 VectorSet( myTangent, -1.0f, 0.0f, 0.0f );
2903 VectorSet( myBinormal, 0.0f, 1.0f, 0.0f );
2908 VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
2909 CrossProduct( myNormal, worldUp, myTangent );
2910 VectorNormalize( myTangent, myTangent );
2911 CrossProduct( myTangent, myNormal, myBinormal );
2912 VectorNormalize( myBinormal, myBinormal );
2915 /* project onto plane */
2916 dist = -DotProduct( myTangent, myNormal );
2917 VectorMA( myTangent, dist, myNormal, myTangent );
2918 dist = -DotProduct( myBinormal, myNormal );
2919 VectorMA( myBinormal, dist, myNormal, myBinormal );
2922 VectorNormalize( myTangent, myTangent );
2923 VectorNormalize( myBinormal, myBinormal );
2925 /* convert modelspace deluxel to tangentspace */
2926 dirSample[0] = bspDeluxel[0];
2927 dirSample[1] = bspDeluxel[1];
2928 dirSample[2] = bspDeluxel[2];
2929 VectorNormalize( dirSample, dirSample );
2931 /* fix tangents to world matrix */
2932 if ( myNormal[0] > 0 || myNormal[1] < 0 || myNormal[2] < 0 ) {
2933 VectorNegate( myTangent, myTangent );
2936 /* build tangentspace vectors */
2937 bspDeluxel[0] = DotProduct( dirSample, myTangent );
2938 bspDeluxel[1] = DotProduct( dirSample, myBinormal );
2939 bspDeluxel[2] = DotProduct( dirSample, myNormal );
2946 /* -----------------------------------------------------------------
2948 ----------------------------------------------------------------- */
2950 #ifdef sdfsdfwq312323
2952 Sys_Printf( "blending..." );
2954 for ( i = 0; i < numRawLightmaps; i++ )
2960 lm = &rawLightmaps[ i ];
2962 /* walk individual lightmaps */
2963 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2966 if ( lm->superLuxels[ lightmapNum ] == NULL ) {
2970 /* walk lightmap samples */
2971 for ( y = 0; y < lm->sh; y++ )
2973 for ( x = 0; x < lm->sw; x++ )
2976 bspLuxel = BSP_LUXEL( lightmapNum, x, y );
2979 VectorNormalize( bspLuxel, myColor );
2980 myBrightness = VectorLength( bspLuxel );
2981 myBrightness *= ( 1 / 127.0f );
2982 myBrightness = myBrightness * myBrightness;
2983 myBrightness *= 127.0f;
2984 VectorScale( myColor, myBrightness, bspLuxel );
2991 /* -----------------------------------------------------------------
2992 collapse non-unique lightmaps
2993 ----------------------------------------------------------------- */
2995 if ( noCollapse == qfalse && deluxemap == qfalse ) {
2997 Sys_FPrintf( SYS_VRB, "collapsing..." );
2999 /* set all twin refs to null */
3000 for ( i = 0; i < numRawLightmaps; i++ )
3002 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3004 rawLightmaps[ i ].twins[ lightmapNum ] = NULL;
3005 rawLightmaps[ i ].twinNums[ lightmapNum ] = -1;
3006 rawLightmaps[ i ].numStyledTwins = 0;
3010 /* walk the list of raw lightmaps */
3011 for ( i = 0; i < numRawLightmaps; i++ )
3014 lm = &rawLightmaps[ i ];
3016 /* walk lightmaps */
3017 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3020 if ( lm->bspLuxels[ lightmapNum ] == NULL ||
3021 lm->twins[ lightmapNum ] != NULL ) {
3025 /* find all lightmaps that are virtually identical to this one */
3026 for ( j = i + 1; j < numRawLightmaps; j++ )
3029 lm2 = &rawLightmaps[ j ];
3031 /* walk lightmaps */
3032 for ( lightmapNum2 = 0; lightmapNum2 < MAX_LIGHTMAPS; lightmapNum2++ )
3035 if ( lm2->bspLuxels[ lightmapNum2 ] == NULL ||
3036 lm2->twins[ lightmapNum2 ] != NULL ) {
3041 if ( CompareBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ) ) {
3042 /* merge and set twin */
3043 if ( MergeBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ) ) {
3044 lm2->twins[ lightmapNum2 ] = lm;
3045 lm2->twinNums[ lightmapNum2 ] = lightmapNum;
3047 numTwinLuxels += ( lm->w * lm->h );
3049 /* count styled twins */
3050 if ( lightmapNum > 0 ) {
3051 lm->numStyledTwins++;
3061 /* -----------------------------------------------------------------
3062 sort raw lightmaps by shader
3063 ----------------------------------------------------------------- */
3066 Sys_FPrintf( SYS_VRB, "sorting..." );
3068 /* allocate a new sorted list */
3069 if ( sortLightmaps == NULL ) {
3070 sortLightmaps = safe_malloc( numRawLightmaps * sizeof( int ) );
3073 /* fill it out and sort it */
3074 for ( i = 0; i < numRawLightmaps; i++ )
3075 sortLightmaps[ i ] = i;
3076 qsort( sortLightmaps, numRawLightmaps, sizeof( int ), CompareRawLightmap );
3078 /* -----------------------------------------------------------------
3079 allocate output lightmaps
3080 ----------------------------------------------------------------- */
3083 Sys_FPrintf( SYS_VRB, "allocating..." );
3085 /* kill all existing output lightmaps */
3086 if ( outLightmaps != NULL ) {
3087 for ( i = 0; i < numOutLightmaps; i++ )
3089 free( outLightmaps[ i ].lightBits );
3090 free( outLightmaps[ i ].bspLightBytes );
3092 free( outLightmaps );
3093 outLightmaps = NULL;
3096 numLightmapShaders = 0;
3097 numOutLightmaps = 0;
3098 numBSPLightmaps = 0;
3099 numExtLightmaps = 0;
3101 /* find output lightmap */
3102 for ( i = 0; i < numRawLightmaps; i++ )
3104 lm = &rawLightmaps[ sortLightmaps[ i ] ];
3105 FindOutLightmaps( lm, fastAllocate );
3108 /* set output numbers in twinned lightmaps */
3109 for ( i = 0; i < numRawLightmaps; i++ )
3112 lm = &rawLightmaps[ sortLightmaps[ i ] ];
3114 /* walk lightmaps */
3115 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3118 lm2 = lm->twins[ lightmapNum ];
3119 if ( lm2 == NULL ) {
3122 lightmapNum2 = lm->twinNums[ lightmapNum ];
3124 /* find output lightmap from twin */
3125 lm->outLightmapNums[ lightmapNum ] = lm2->outLightmapNums[ lightmapNum2 ];
3126 lm->lightmapX[ lightmapNum ] = lm2->lightmapX[ lightmapNum2 ];
3127 lm->lightmapY[ lightmapNum ] = lm2->lightmapY[ lightmapNum2 ];
3131 /* -----------------------------------------------------------------
3132 store output lightmaps
3133 ----------------------------------------------------------------- */
3136 Sys_FPrintf( SYS_VRB, "storing..." );
3138 /* count the bsp lightmaps and allocate space */
3139 if ( bspLightBytes != NULL ) {
3140 free( bspLightBytes );
3142 if ( numBSPLightmaps == 0 || externalLightmaps ) {
3143 numBSPLightBytes = 0;
3144 bspLightBytes = NULL;
3148 numBSPLightBytes = ( numBSPLightmaps * game->lightmapSize * game->lightmapSize * 3 );
3149 bspLightBytes = safe_malloc( numBSPLightBytes );
3150 memset( bspLightBytes, 0, numBSPLightBytes );
3153 /* walk the list of output lightmaps */
3154 for ( i = 0; i < numOutLightmaps; i++ )
3156 /* get output lightmap */
3157 olm = &outLightmaps[ i ];
3159 /* fill output lightmap */
3160 if ( lightmapFill ) {
3161 FillOutLightmap( olm );
3164 /* is this a valid bsp lightmap? */
3165 if ( olm->lightmapNum >= 0 && !externalLightmaps ) {
3166 /* copy lighting data */
3167 lb = bspLightBytes + ( olm->lightmapNum * game->lightmapSize * game->lightmapSize * 3 );
3168 memcpy( lb, olm->bspLightBytes, game->lightmapSize * game->lightmapSize * 3 );
3170 /* copy direction data */
3172 lb = bspLightBytes + ( ( olm->lightmapNum + 1 ) * game->lightmapSize * game->lightmapSize * 3 );
3173 memcpy( lb, olm->bspDirBytes, game->lightmapSize * game->lightmapSize * 3 );
3177 /* external lightmap? */
3178 if ( olm->lightmapNum < 0 || olm->extLightmapNum >= 0 || externalLightmaps ) {
3179 /* make a directory for the lightmaps */
3182 /* set external lightmap number */
3183 olm->extLightmapNum = numExtLightmaps;
3185 /* write lightmap */
3186 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
3187 Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
3188 WriteTGA24( filename, olm->bspLightBytes, olm->customWidth, olm->customHeight, qtrue );
3191 /* write deluxemap */
3193 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
3194 Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
3195 WriteTGA24( filename, olm->bspDirBytes, olm->customWidth, olm->customHeight, qtrue );
3198 if ( debugDeluxemap ) {
3199 olm->extLightmapNum++;
3205 if ( numExtLightmaps > 0 ) {
3206 Sys_FPrintf( SYS_VRB, "\n" );
3209 /* delete unused external lightmaps */
3210 for ( i = numExtLightmaps; i; i++ )
3212 /* determine if file exists */
3213 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, i );
3214 if ( !FileExists( filename ) ) {
3222 /* -----------------------------------------------------------------
3223 project the lightmaps onto the bsp surfaces
3224 ----------------------------------------------------------------- */
3227 Sys_FPrintf( SYS_VRB, "projecting..." );
3229 /* walk the list of surfaces */
3230 for ( i = 0; i < numBSPDrawSurfaces; i++ )
3232 /* get the surface and info */
3233 ds = &bspDrawSurfaces[ i ];
3234 info = &surfaceInfos[ i ];
3238 /* handle surfaces with identical parent */
3239 if ( info->parentSurfaceNum >= 0 ) {
3240 /* preserve original data and get parent */
3241 parent = &bspDrawSurfaces[ info->parentSurfaceNum ];
3242 memcpy( &dsTemp, ds, sizeof( *ds ) );
3244 /* overwrite child with parent data */
3245 memcpy( ds, parent, sizeof( *ds ) );
3247 /* restore key parts */
3248 ds->fogNum = dsTemp.fogNum;
3249 ds->firstVert = dsTemp.firstVert;
3250 ds->firstIndex = dsTemp.firstIndex;
3251 memcpy( ds->lightmapVecs, dsTemp.lightmapVecs, sizeof( dsTemp.lightmapVecs ) );
3253 /* set vertex data */
3254 dv = &bspDrawVerts[ ds->firstVert ];
3255 dvParent = &bspDrawVerts[ parent->firstVert ];
3256 for ( j = 0; j < ds->numVerts; j++ )
3258 memcpy( dv[ j ].lightmap, dvParent[ j ].lightmap, sizeof( dv[ j ].lightmap ) );
3259 memcpy( dv[ j ].color, dvParent[ j ].color, sizeof( dv[ j ].color ) );
3266 /* handle vertex lit or approximated surfaces */
3267 else if ( lm == NULL || lm->outLightmapNums[ 0 ] < 0 ) {
3268 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3270 ds->lightmapNum[ lightmapNum ] = -3;
3271 ds->lightmapStyles[ lightmapNum ] = ds->vertexStyles[ lightmapNum ];
3275 /* handle lightmapped surfaces */
3278 /* walk lightmaps */
3279 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3282 ds->lightmapStyles[ lightmapNum ] = lm->styles[ lightmapNum ];
3284 /* handle unused style */
3285 if ( lm->styles[ lightmapNum ] == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 ) {
3286 ds->lightmapNum[ lightmapNum ] = -3;
3290 /* get output lightmap */
3291 olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
3293 /* set bsp lightmap number */
3294 ds->lightmapNum[ lightmapNum ] = olm->lightmapNum;
3296 /* deluxemap debugging makes the deluxemap visible */
3297 if ( deluxemap && debugDeluxemap && lightmapNum == 0 ) {
3298 ds->lightmapNum[ lightmapNum ]++;
3301 /* calc lightmap origin in texture space */
3302 lmx = (float) lm->lightmapX[ lightmapNum ] / (float) olm->customWidth;
3303 lmy = (float) lm->lightmapY[ lightmapNum ] / (float) olm->customHeight;
3305 /* calc lightmap st coords */
3306 dv = &bspDrawVerts[ ds->firstVert ];
3307 ydv = &yDrawVerts[ ds->firstVert ];
3308 for ( j = 0; j < ds->numVerts; j++ )
3310 if ( lm->solid[ lightmapNum ] ) {
3311 dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + ( 0.5f / (float) olm->customWidth );
3312 dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + ( 0.5f / (float) olm->customWidth );
3316 dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + ( ydv[ j ].lightmap[ 0 ][ 0 ] / ( superSample * olm->customWidth ) );
3317 dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + ( ydv[ j ].lightmap[ 0 ][ 1 ] / ( superSample * olm->customHeight ) );
3323 /* store vertex colors */
3324 dv = &bspDrawVerts[ ds->firstVert ];
3325 for ( j = 0; j < ds->numVerts; j++ )
3327 /* walk lightmaps */
3328 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3330 /* handle unused style */
3331 if ( ds->vertexStyles[ lightmapNum ] == LS_NONE ) {
3332 VectorClear( color );
3336 /* get vertex color */
3337 luxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + j );
3338 VectorCopy( luxel, color );
3340 /* set minimum light */
3341 if ( lightmapNum == 0 ) {
3342 for ( k = 0; k < 3; k++ )
3343 if ( color[ k ] < minVertexLight[ k ] ) {
3344 color[ k ] = minVertexLight[ k ];
3349 /* store to bytes */
3350 if ( !info->si->noVertexLight ) {
3351 ColorToBytes( color, dv[ j ].color[ lightmapNum ], info->si->vertexScale );
3356 /* surfaces with styled lightmaps and a style marker get a custom generated shader (fixme: make this work with external lightmaps) */
3357 if ( olm != NULL && lm != NULL && lm->styles[ 1 ] != LS_NONE && game->load != LoadRBSPFile ) { //% info->si->styleMarker > 0 )
3359 char key[ 32 ], styleStage[ 512 ], styleStages[ 4096 ], rgbGen[ 128 ], alphaGen[ 128 ];
3363 sprintf( styleStages, "\n\t// Q3Map2 custom lightstyle stage(s)\n" );
3364 dv = &bspDrawVerts[ ds->firstVert ];
3366 /* depthFunc equal? */
3367 if ( info->si->styleMarker == 2 || info->si->implicitMap == IM_MASKED ) {
3374 /* generate stages for styled lightmaps */
3375 for ( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3378 style = lm->styles[ lightmapNum ];
3379 if ( style == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 ) {
3383 /* get output lightmap */
3384 olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
3387 if ( lm->outLightmapNums[ lightmapNum ] == lm->outLightmapNums[ 0 ] ) {
3388 strcpy( lightmapName, "$lightmap" );
3391 sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
3394 /* get rgbgen string */
3395 if ( rgbGenValues[ style ] == NULL ) {
3396 sprintf( key, "_style%drgbgen", style );
3397 rgbGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
3398 if ( rgbGenValues[ style ][ 0 ] == '\0' ) {
3399 rgbGenValues[ style ] = "wave noise 0.5 1 0 5.37";
3403 if ( rgbGenValues[ style ][ 0 ] != '\0' ) {
3404 sprintf( rgbGen, "\t\trgbGen %s // style %d\n", rgbGenValues[ style ], style );
3410 /* get alphagen string */
3411 if ( alphaGenValues[ style ] == NULL ) {
3412 sprintf( key, "_style%dalphagen", style );
3413 alphaGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
3415 if ( alphaGenValues[ style ][ 0 ] != '\0' ) {
3416 sprintf( alphaGen, "\t\talphaGen %s // style %d\n", alphaGenValues[ style ], style );
3419 alphaGen[ 0 ] = '\0';
3422 /* calculate st offset */
3423 lmx = dv[ 0 ].lightmap[ lightmapNum ][ 0 ] - dv[ 0 ].lightmap[ 0 ][ 0 ];
3424 lmy = dv[ 0 ].lightmap[ lightmapNum ][ 1 ] - dv[ 0 ].lightmap[ 0 ][ 1 ];
3426 /* create additional stage */
3427 if ( lmx == 0.0f && lmy == 0.0f ) {
3428 sprintf( styleStage, "\t{\n"
3429 "\t\tmap %s\n" /* lightmap */
3430 "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
3431 "%s" /* depthFunc equal */
3434 "\t\ttcGen lightmap\n"
3437 ( dfEqual ? "\t\tdepthFunc equal\n" : "" ),
3443 sprintf( styleStage, "\t{\n"
3444 "\t\tmap %s\n" /* lightmap */
3445 "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
3446 "%s" /* depthFunc equal */
3449 "\t\ttcGen lightmap\n"
3450 "\t\ttcMod transform 1 0 0 1 %1.5f %1.5f\n" /* st offset */
3453 ( dfEqual ? "\t\tdepthFunc equal\n" : "" ),
3461 strcat( styleStages, styleStage );
3464 /* create custom shader */
3465 if ( info->si->styleMarker == 2 ) {
3466 csi = CustomShader( info->si, "q3map_styleMarker2", styleStages );
3469 csi = CustomShader( info->si, "q3map_styleMarker", styleStages );
3472 /* emit remap command */
3473 //% EmitVertexRemapShader( csi->shader, info->si->shader );
3476 //% Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
3477 ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3478 //% Sys_Printf( ")\n" );
3481 /* devise a custom shader for this surface (fixme: make this work with light styles) */
3482 else if ( olm != NULL && lm != NULL && !externalLightmaps &&
3483 ( olm->customWidth != game->lightmapSize || olm->customHeight != game->lightmapSize ) ) {
3484 /* get output lightmap */
3485 olm = &outLightmaps[ lm->outLightmapNums[ 0 ] ];
3487 /* do some name mangling */
3488 sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
3490 /* create custom shader */
3491 csi = CustomShader( info->si, "$lightmap", lightmapName );
3494 //% Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
3495 ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3496 //% Sys_Printf( ")\n" );
3499 /* use the normal plain-jane shader */
3501 ds->shaderNum = EmitShader( info->si->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3506 Sys_FPrintf( SYS_VRB, "done.\n" );
3508 /* calc num stored */
3509 numStored = numBSPLightBytes / 3;
3510 efficiency = ( numStored <= 0 )
3512 : (float) numUsed / (float) numStored;
3515 Sys_Printf( "%9d luxels used\n", numUsed );
3516 Sys_Printf( "%9d luxels stored (%3.2f percent efficiency)\n", numStored, efficiency * 100.0f );
3517 Sys_Printf( "%9d solid surface lightmaps\n", numSolidLightmaps );
3518 Sys_Printf( "%9d identical surface lightmaps, using %d luxels\n", numTwins, numTwinLuxels );
3519 Sys_Printf( "%9d vertex forced surfaces\n", numSurfsVertexForced );
3520 Sys_Printf( "%9d vertex approximated surfaces\n", numSurfsVertexApproximated );
3521 Sys_Printf( "%9d BSP lightmaps\n", numBSPLightmaps );
3522 Sys_Printf( "%9d total lightmaps\n", numOutLightmaps );
3523 Sys_Printf( "%9d unique lightmap/shader combinations\n", numLightmapShaders );
3525 /* write map shader file */
3526 WriteMapShaderFile();