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 );
2338 //#define allocate_bigger_first
2339 #ifdef allocate_bigger_first
2340 /* compare size, allocate bigger first */
2341 // fastAllocate commit part: can kick fps by unique lightmap/shader combinations*=~2 + bigger compile time
2342 //return -diff; makes packing faster and rough
2343 diff = ( blm->w * blm->h ) - ( alm->w * alm->h );
2349 for ( i = 0; i < min; i++ )
2351 /* get surface info */
2352 aInfo = &surfaceInfos[ lightSurfaces[ alm->firstLightSurface + i ] ];
2353 bInfo = &surfaceInfos[ lightSurfaces[ blm->firstLightSurface + i ] ];
2355 /* compare shader names */
2356 diff = strcmp( aInfo->si->shader, bInfo->si->shader );
2362 /* test style count */
2364 for ( i = 0; i < MAX_LIGHTMAPS; i++ )
2365 diff += blm->styles[ i ] - alm->styles[ i ];
2369 #ifndef allocate_bigger_first
2371 diff = ( blm->w * blm->h ) - ( alm->w * alm->h );
2376 /* must be equivalent */
2382 void FillOutLightmap( outLightmap_t *olm ){
2385 vec3_t dir_sum, light_sum;
2387 byte *lightBitsNew = NULL;
2388 byte *lightBytesNew = NULL;
2389 byte *dirBytesNew = NULL;
2391 lightBitsNew = safe_malloc( ( olm->customWidth * olm->customHeight + 8 ) / 8 );
2392 lightBytesNew = safe_malloc( olm->customWidth * olm->customHeight * 3 );
2394 dirBytesNew = safe_malloc( olm->customWidth * olm->customHeight * 3 );
2398 memset(olm->lightBits, 0, (olm->customWidth * olm->customHeight + 8) / 8);
2399 olm->lightBits[0] |= 1;
2400 olm->lightBits[(10 * olm->customWidth + 30) >> 3] |= 1 << ((10 * olm->customWidth + 30) & 7);
2401 memset(olm->bspLightBytes, 0, olm->customWidth * olm->customHeight * 3);
2402 olm->bspLightBytes[0] = 255;
2403 olm->bspLightBytes[(10 * olm->customWidth + 30) * 3 + 2] = 255;
2406 memcpy( lightBitsNew, olm->lightBits, ( olm->customWidth * olm->customHeight + 8 ) / 8 );
2407 memcpy( lightBytesNew, olm->bspLightBytes, olm->customWidth * olm->customHeight * 3 );
2409 memcpy( dirBytesNew, olm->bspDirBytes, olm->customWidth * olm->customHeight * 3 );
2415 for ( y = 0; y < olm->customHeight; ++y )
2417 for ( x = 0; x < olm->customWidth; ++x )
2419 ofs = y * olm->customWidth + x;
2420 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2424 VectorClear( dir_sum );
2425 VectorClear( light_sum );
2427 /* try all four neighbors */
2428 ofs = ( ( y + olm->customHeight - 1 ) % olm->customHeight ) * olm->customWidth + x;
2429 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2431 VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2433 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2437 ofs = ( ( y + 1 ) % olm->customHeight ) * olm->customWidth + x;
2438 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2440 VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2442 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2446 ofs = y * olm->customWidth + ( x + olm->customWidth - 1 ) % olm->customWidth;
2447 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2449 VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2451 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2455 ofs = y * olm->customWidth + ( x + 1 ) % olm->customWidth;
2456 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2458 VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2460 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2466 ofs = y * olm->customWidth + x;
2467 lightBitsNew[ofs >> 3] |= ( 1 << ( ofs & 7 ) );
2468 VectorScale( light_sum, 1.0 / cnt, lightBytesNew + ofs * 3 );
2470 VectorScale( dir_sum, 1.0 / cnt, dirBytesNew + ofs * 3 );
2480 memcpy( olm->lightBits, lightBitsNew, ( olm->customWidth * olm->customHeight + 8 ) / 8 );
2481 memcpy( olm->bspLightBytes, lightBytesNew, olm->customWidth * olm->customHeight * 3 );
2483 memcpy( olm->bspDirBytes, dirBytesNew, olm->customWidth * olm->customHeight * 3 );
2487 free( lightBitsNew );
2488 free( lightBytesNew );
2490 free( dirBytesNew );
2495 StoreSurfaceLightmaps()
2496 stores the surface lightmaps into the bsp as byte rgb triplets
2499 void StoreSurfaceLightmaps( qboolean fastAllocate ){
2500 int i, j, k, x, y, lx, ly, sx, sy, *cluster, mappedSamples, timer_start;
2501 int style, size, lightmapNum, lightmapNum2;
2502 float *normal, *luxel, *bspLuxel, *bspLuxel2, *radLuxel, samples, occludedSamples;
2503 vec3_t sample, occludedSample, dirSample, colorMins, colorMaxs;
2504 float *deluxel, *bspDeluxel, *bspDeluxel2;
2506 int numUsed, numTwins, numTwinLuxels, numStored;
2507 float lmx, lmy, efficiency;
2509 bspDrawSurface_t *ds, *parent, dsTemp;
2510 surfaceInfo_t *info;
2511 rawLightmap_t *lm, *lm2;
2513 bspDrawVert_t *dv, *ydv, *dvParent;
2514 char dirname[ 1024 ], filename[ 1024 ];
2516 char lightmapName[ 128 ];
2517 const char *rgbGenValues[ 256 ];
2518 const char *alphaGenValues[ 256 ];
2522 Sys_Printf( "--- StoreSurfaceLightmaps ---\n" );
2525 if ( lmCustomDir ) {
2526 strcpy( dirname, lmCustomDir );
2530 strcpy( dirname, source );
2531 StripExtension( dirname );
2533 memset( rgbGenValues, 0, sizeof( rgbGenValues ) );
2534 memset( alphaGenValues, 0, sizeof( alphaGenValues ) );
2536 /* -----------------------------------------------------------------
2537 average the sampled luxels into the bsp luxels
2538 ----------------------------------------------------------------- */
2541 Sys_FPrintf( SYS_VRB, "Subsampling..." );
2543 timer_start = I_FloatTime();
2545 /* walk the list of raw lightmaps */
2549 numSolidLightmaps = 0;
2550 for ( i = 0; i < numRawLightmaps; i++ )
2553 lm = &rawLightmaps[ i ];
2555 /* walk individual lightmaps */
2556 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2559 if ( lm->superLuxels[ lightmapNum ] == NULL ) {
2563 /* allocate bsp luxel storage */
2564 if ( lm->bspLuxels[ lightmapNum ] == NULL ) {
2565 size = lm->w * lm->h * BSP_LUXEL_SIZE * sizeof( float );
2566 lm->bspLuxels[ lightmapNum ] = safe_malloc( size );
2567 memset( lm->bspLuxels[ lightmapNum ], 0, size );
2570 /* allocate radiosity lightmap storage */
2572 size = lm->w * lm->h * RAD_LUXEL_SIZE * sizeof( float );
2573 if ( lm->radLuxels[ lightmapNum ] == NULL ) {
2574 lm->radLuxels[ lightmapNum ] = safe_malloc( size );
2576 memset( lm->radLuxels[ lightmapNum ], 0, size );
2579 /* average supersampled luxels */
2580 for ( y = 0; y < lm->h; y++ )
2582 for ( x = 0; x < lm->w; x++ )
2586 occludedSamples = 0.0f;
2588 VectorClear( sample );
2589 VectorClear( occludedSample );
2590 VectorClear( dirSample );
2591 for ( ly = 0; ly < superSample; ly++ )
2593 for ( lx = 0; lx < superSample; lx++ )
2596 sx = x * superSample + lx;
2597 sy = y * superSample + ly;
2598 luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2599 deluxel = SUPER_DELUXEL( sx, sy );
2600 normal = SUPER_NORMAL( sx, sy );
2601 cluster = SUPER_CLUSTER( sx, sy );
2603 /* sample deluxemap */
2604 if ( deluxemap && lightmapNum == 0 ) {
2605 VectorAdd( dirSample, deluxel, dirSample );
2608 /* keep track of used/occluded samples */
2609 if ( *cluster != CLUSTER_UNMAPPED ) {
2613 /* handle lightmap border? */
2614 if ( lightmapBorder && ( sx == 0 || sx == ( lm->sw - 1 ) || sy == 0 || sy == ( lm->sh - 1 ) ) && luxel[ 3 ] > 0.0f ) {
2615 VectorSet( sample, 255.0f, 0.0f, 0.0f );
2620 else if ( debug && *cluster < 0 ) {
2621 if ( *cluster == CLUSTER_UNMAPPED ) {
2622 VectorSet( luxel, 255, 204, 0 );
2624 else if ( *cluster == CLUSTER_OCCLUDED ) {
2625 VectorSet( luxel, 255, 0, 255 );
2627 else if ( *cluster == CLUSTER_FLOODED ) {
2628 VectorSet( luxel, 0, 32, 255 );
2630 VectorAdd( occludedSample, luxel, occludedSample );
2631 occludedSamples += 1.0f;
2634 /* normal luxel handling */
2635 else if ( luxel[ 3 ] > 0.0f ) {
2636 /* handle lit or flooded luxels */
2637 if ( *cluster > 0 || *cluster == CLUSTER_FLOODED ) {
2638 VectorAdd( sample, luxel, sample );
2639 samples += luxel[ 3 ];
2642 /* handle occluded or unmapped luxels */
2645 VectorAdd( occludedSample, luxel, occludedSample );
2646 occludedSamples += luxel[ 3 ];
2649 /* handle style debugging */
2650 if ( debug && lightmapNum > 0 && x < 2 && y < 2 ) {
2651 VectorCopy( debugColors[ 0 ], sample );
2658 /* only use occluded samples if necessary */
2659 if ( samples <= 0.0f ) {
2660 VectorCopy( occludedSample, sample );
2661 samples = occludedSamples;
2665 luxel = SUPER_LUXEL( lightmapNum, x, y );
2666 deluxel = SUPER_DELUXEL( x, y );
2668 /* store light direction */
2669 if ( deluxemap && lightmapNum == 0 ) {
2670 VectorCopy( dirSample, deluxel );
2673 /* store the sample back in super luxels */
2674 if ( samples > 0.01f ) {
2675 VectorScale( sample, ( 1.0f / samples ), luxel );
2679 /* if any samples were mapped in any way, store ambient color */
2680 else if ( mappedSamples > 0 ) {
2681 if ( lightmapNum == 0 ) {
2682 VectorCopy( ambientColor, luxel );
2685 VectorClear( luxel );
2690 /* store a bogus value to be fixed later */
2693 VectorClear( luxel );
2701 ClearBounds( colorMins, colorMaxs );
2703 /* clean up and store into bsp luxels */
2704 for ( y = 0; y < lm->h; y++ )
2706 for ( x = 0; x < lm->w; x++ )
2709 luxel = SUPER_LUXEL( lightmapNum, x, y );
2710 deluxel = SUPER_DELUXEL( x, y );
2712 /* copy light direction */
2713 if ( deluxemap && lightmapNum == 0 ) {
2714 VectorCopy( deluxel, dirSample );
2717 /* is this a valid sample? */
2718 if ( luxel[ 3 ] > 0.0f ) {
2719 VectorCopy( luxel, sample );
2720 samples = luxel[ 3 ];
2724 /* fix negative samples */
2725 for ( j = 0; j < 3; j++ )
2727 if ( sample[ j ] < 0.0f ) {
2734 /* nick an average value from the neighbors */
2735 VectorClear( sample );
2736 VectorClear( dirSample );
2739 /* fixme: why is this disabled?? */
2740 for ( sy = ( y - 1 ); sy <= ( y + 1 ); sy++ )
2742 if ( sy < 0 || sy >= lm->h ) {
2746 for ( sx = ( x - 1 ); sx <= ( x + 1 ); sx++ )
2748 if ( sx < 0 || sx >= lm->w || ( sx == x && sy == y ) ) {
2752 /* get neighbor's particulars */
2753 luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2754 if ( luxel[ 3 ] < 0.0f ) {
2757 VectorAdd( sample, luxel, sample );
2758 samples += luxel[ 3 ];
2763 if ( samples == 0.0f ) {
2764 VectorSet( sample, -1.0f, -1.0f, -1.0f );
2772 /* fix negative samples */
2773 for ( j = 0; j < 3; j++ )
2775 if ( sample[ j ] < 0.0f ) {
2782 /* scale the sample */
2783 VectorScale( sample, ( 1.0f / samples ), sample );
2785 /* store the sample in the radiosity luxels */
2787 radLuxel = RAD_LUXEL( lightmapNum, x, y );
2788 VectorCopy( sample, radLuxel );
2790 /* if only storing bounced light, early out here */
2791 if ( bounceOnly && !bouncing ) {
2796 /* store the sample in the bsp luxels */
2797 bspLuxel = BSP_LUXEL( lightmapNum, x, y );
2798 bspDeluxel = BSP_DELUXEL( x, y );
2800 VectorAdd( bspLuxel, sample, bspLuxel );
2801 if ( deluxemap && lightmapNum == 0 ) {
2802 VectorAdd( bspDeluxel, dirSample, bspDeluxel );
2805 /* add color to bounds for solid checking */
2806 if ( samples > 0.0f ) {
2807 AddPointToBounds( bspLuxel, colorMins, colorMaxs );
2812 /* set solid color */
2813 lm->solid[ lightmapNum ] = qfalse;
2814 VectorAdd( colorMins, colorMaxs, lm->solidColor[ lightmapNum ] );
2815 VectorScale( lm->solidColor[ lightmapNum ], 0.5f, lm->solidColor[ lightmapNum ] );
2817 /* nocollapse prevents solid lightmaps */
2818 if ( noCollapse == qfalse ) {
2819 /* check solid color */
2820 VectorSubtract( colorMaxs, colorMins, sample );
2821 if ( ( sample[ 0 ] <= SOLID_EPSILON && sample[ 1 ] <= SOLID_EPSILON && sample[ 2 ] <= SOLID_EPSILON ) ||
2822 ( lm->w <= 2 && lm->h <= 2 ) ) { /* small lightmaps get forced to solid color */
2824 VectorCopy( colorMins, lm->solidColor[ lightmapNum ] );
2825 lm->solid[ lightmapNum ] = qtrue;
2826 numSolidLightmaps++;
2829 /* if all lightmaps aren't solid, then none of them are solid */
2830 if ( lm->solid[ lightmapNum ] != lm->solid[ 0 ] ) {
2831 for ( y = 0; y < MAX_LIGHTMAPS; y++ )
2833 if ( lm->solid[ y ] ) {
2834 numSolidLightmaps--;
2836 lm->solid[ y ] = qfalse;
2841 /* wrap bsp luxels if necessary */
2842 if ( lm->wrap[ 0 ] ) {
2843 for ( y = 0; y < lm->h; y++ )
2845 bspLuxel = BSP_LUXEL( lightmapNum, 0, y );
2846 bspLuxel2 = BSP_LUXEL( lightmapNum, lm->w - 1, y );
2847 VectorAdd( bspLuxel, bspLuxel2, bspLuxel );
2848 VectorScale( bspLuxel, 0.5f, bspLuxel );
2849 VectorCopy( bspLuxel, bspLuxel2 );
2850 if ( deluxemap && lightmapNum == 0 ) {
2851 bspDeluxel = BSP_DELUXEL( 0, y );
2852 bspDeluxel2 = BSP_DELUXEL( lm->w - 1, y );
2853 VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel );
2854 VectorScale( bspDeluxel, 0.5f, bspDeluxel );
2855 VectorCopy( bspDeluxel, bspDeluxel2 );
2859 if ( lm->wrap[ 1 ] ) {
2860 for ( x = 0; x < lm->w; x++ )
2862 bspLuxel = BSP_LUXEL( lightmapNum, x, 0 );
2863 bspLuxel2 = BSP_LUXEL( lightmapNum, x, lm->h - 1 );
2864 VectorAdd( bspLuxel, bspLuxel2, bspLuxel );
2865 VectorScale( bspLuxel, 0.5f, bspLuxel );
2866 VectorCopy( bspLuxel, bspLuxel2 );
2867 if ( deluxemap && lightmapNum == 0 ) {
2868 bspDeluxel = BSP_DELUXEL( x, 0 );
2869 bspDeluxel2 = BSP_DELUXEL( x, lm->h - 1 );
2870 VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel );
2871 VectorScale( bspDeluxel, 0.5f, bspDeluxel );
2872 VectorCopy( bspDeluxel, bspDeluxel2 );
2879 Sys_FPrintf( SYS_VRB, "%d.", (int) ( I_FloatTime() - timer_start ) );
2881 /* -----------------------------------------------------------------
2882 convert modelspace deluxemaps to tangentspace
2883 ----------------------------------------------------------------- */
2886 if ( deluxemap && deluxemode == 1 ) {
2887 vec3_t worldUp, myNormal, myTangent, myBinormal;
2890 timer_start = I_FloatTime();
2892 Sys_Printf( "converting..." );
2894 for ( i = 0; i < numRawLightmaps; i++ )
2897 lm = &rawLightmaps[ i ];
2899 /* walk lightmap samples */
2900 for ( y = 0; y < lm->sh; y++ )
2902 for ( x = 0; x < lm->sw; x++ )
2904 /* get normal and deluxel */
2905 normal = SUPER_NORMAL( x, y );
2906 cluster = SUPER_CLUSTER( x, y );
2907 bspDeluxel = BSP_DELUXEL( x, y );
2908 deluxel = SUPER_DELUXEL( x, y );
2911 VectorSet( myNormal, normal[0], normal[1], normal[2] );
2913 /* get tangent vectors */
2914 if ( myNormal[ 0 ] == 0.0f && myNormal[ 1 ] == 0.0f ) {
2915 if ( myNormal[ 2 ] == 1.0f ) {
2916 VectorSet( myTangent, 1.0f, 0.0f, 0.0f );
2917 VectorSet( myBinormal, 0.0f, 1.0f, 0.0f );
2919 else if ( myNormal[ 2 ] == -1.0f ) {
2920 VectorSet( myTangent, -1.0f, 0.0f, 0.0f );
2921 VectorSet( myBinormal, 0.0f, 1.0f, 0.0f );
2926 VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
2927 CrossProduct( myNormal, worldUp, myTangent );
2928 VectorNormalize( myTangent, myTangent );
2929 CrossProduct( myTangent, myNormal, myBinormal );
2930 VectorNormalize( myBinormal, myBinormal );
2933 /* project onto plane */
2934 dist = -DotProduct( myTangent, myNormal );
2935 VectorMA( myTangent, dist, myNormal, myTangent );
2936 dist = -DotProduct( myBinormal, myNormal );
2937 VectorMA( myBinormal, dist, myNormal, myBinormal );
2940 VectorNormalize( myTangent, myTangent );
2941 VectorNormalize( myBinormal, myBinormal );
2943 /* convert modelspace deluxel to tangentspace */
2944 dirSample[0] = bspDeluxel[0];
2945 dirSample[1] = bspDeluxel[1];
2946 dirSample[2] = bspDeluxel[2];
2947 VectorNormalize( dirSample, dirSample );
2949 /* fix tangents to world matrix */
2950 if ( myNormal[0] > 0 || myNormal[1] < 0 || myNormal[2] < 0 ) {
2951 VectorNegate( myTangent, myTangent );
2954 /* build tangentspace vectors */
2955 bspDeluxel[0] = DotProduct( dirSample, myTangent );
2956 bspDeluxel[1] = DotProduct( dirSample, myBinormal );
2957 bspDeluxel[2] = DotProduct( dirSample, myNormal );
2962 Sys_FPrintf( SYS_VRB, "%d.", (int) ( I_FloatTime() - timer_start ) );
2966 /* -----------------------------------------------------------------
2968 ----------------------------------------------------------------- */
2970 #ifdef sdfsdfwq312323
2972 Sys_Printf( "blending..." );
2974 for ( i = 0; i < numRawLightmaps; i++ )
2980 lm = &rawLightmaps[ i ];
2982 /* walk individual lightmaps */
2983 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2986 if ( lm->superLuxels[ lightmapNum ] == NULL ) {
2990 /* walk lightmap samples */
2991 for ( y = 0; y < lm->sh; y++ )
2993 for ( x = 0; x < lm->sw; x++ )
2996 bspLuxel = BSP_LUXEL( lightmapNum, x, y );
2999 VectorNormalize( bspLuxel, myColor );
3000 myBrightness = VectorLength( bspLuxel );
3001 myBrightness *= ( 1 / 127.0f );
3002 myBrightness = myBrightness * myBrightness;
3003 myBrightness *= 127.0f;
3004 VectorScale( myColor, myBrightness, bspLuxel );
3011 /* -----------------------------------------------------------------
3012 collapse non-unique lightmaps
3013 ----------------------------------------------------------------- */
3015 if ( noCollapse == qfalse && deluxemap == qfalse ) {
3017 Sys_FPrintf( SYS_VRB, "collapsing..." );
3019 timer_start = I_FloatTime();
3021 /* set all twin refs to null */
3022 for ( i = 0; i < numRawLightmaps; i++ )
3024 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3026 rawLightmaps[ i ].twins[ lightmapNum ] = NULL;
3027 rawLightmaps[ i ].twinNums[ lightmapNum ] = -1;
3028 rawLightmaps[ i ].numStyledTwins = 0;
3032 /* walk the list of raw lightmaps */
3033 for ( i = 0; i < numRawLightmaps; i++ )
3036 lm = &rawLightmaps[ i ];
3038 /* walk lightmaps */
3039 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3042 if ( lm->bspLuxels[ lightmapNum ] == NULL ||
3043 lm->twins[ lightmapNum ] != NULL ) {
3047 /* find all lightmaps that are virtually identical to this one */
3048 for ( j = i + 1; j < numRawLightmaps; j++ )
3051 lm2 = &rawLightmaps[ j ];
3053 /* walk lightmaps */
3054 for ( lightmapNum2 = 0; lightmapNum2 < MAX_LIGHTMAPS; lightmapNum2++ )
3057 if ( lm2->bspLuxels[ lightmapNum2 ] == NULL ||
3058 lm2->twins[ lightmapNum2 ] != NULL ) {
3063 if ( CompareBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ) ) {
3064 /* merge and set twin */
3065 if ( MergeBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ) ) {
3066 lm2->twins[ lightmapNum2 ] = lm;
3067 lm2->twinNums[ lightmapNum2 ] = lightmapNum;
3069 numTwinLuxels += ( lm->w * lm->h );
3071 /* count styled twins */
3072 if ( lightmapNum > 0 ) {
3073 lm->numStyledTwins++;
3082 Sys_FPrintf( SYS_VRB, "%d.", (int) ( I_FloatTime() - timer_start ) );
3085 /* -----------------------------------------------------------------
3086 sort raw lightmaps by shader
3087 ----------------------------------------------------------------- */
3090 Sys_FPrintf( SYS_VRB, "sorting..." );
3092 timer_start = I_FloatTime();
3094 /* allocate a new sorted list */
3095 if ( sortLightmaps == NULL ) {
3096 sortLightmaps = safe_malloc( numRawLightmaps * sizeof( int ) );
3099 /* fill it out and sort it */
3100 for ( i = 0; i < numRawLightmaps; i++ )
3101 sortLightmaps[ i ] = i;
3102 qsort( sortLightmaps, numRawLightmaps, sizeof( int ), CompareRawLightmap );
3104 Sys_FPrintf( SYS_VRB, "%d.", (int) ( I_FloatTime() - timer_start ) );
3106 /* -----------------------------------------------------------------
3107 allocate output lightmaps
3108 ----------------------------------------------------------------- */
3111 Sys_FPrintf( SYS_VRB, "allocating..." );
3113 timer_start = I_FloatTime();
3115 /* kill all existing output lightmaps */
3116 if ( outLightmaps != NULL ) {
3117 for ( i = 0; i < numOutLightmaps; i++ )
3119 free( outLightmaps[ i ].lightBits );
3120 free( outLightmaps[ i ].bspLightBytes );
3122 free( outLightmaps );
3123 outLightmaps = NULL;
3126 numLightmapShaders = 0;
3127 numOutLightmaps = 0;
3128 numBSPLightmaps = 0;
3129 numExtLightmaps = 0;
3131 /* find output lightmap */
3132 for ( i = 0; i < numRawLightmaps; i++ )
3134 lm = &rawLightmaps[ sortLightmaps[ i ] ];
3135 FindOutLightmaps( lm, fastAllocate );
3138 /* set output numbers in twinned lightmaps */
3139 for ( i = 0; i < numRawLightmaps; i++ )
3142 lm = &rawLightmaps[ sortLightmaps[ i ] ];
3144 /* walk lightmaps */
3145 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3148 lm2 = lm->twins[ lightmapNum ];
3149 if ( lm2 == NULL ) {
3152 lightmapNum2 = lm->twinNums[ lightmapNum ];
3154 /* find output lightmap from twin */
3155 lm->outLightmapNums[ lightmapNum ] = lm2->outLightmapNums[ lightmapNum2 ];
3156 lm->lightmapX[ lightmapNum ] = lm2->lightmapX[ lightmapNum2 ];
3157 lm->lightmapY[ lightmapNum ] = lm2->lightmapY[ lightmapNum2 ];
3161 Sys_FPrintf( SYS_VRB, "%d.", (int) ( I_FloatTime() - timer_start ) );
3163 /* -----------------------------------------------------------------
3164 store output lightmaps
3165 ----------------------------------------------------------------- */
3168 Sys_FPrintf( SYS_VRB, "storing..." );
3170 timer_start = I_FloatTime();
3172 /* count the bsp lightmaps and allocate space */
3173 if ( bspLightBytes != NULL ) {
3174 free( bspLightBytes );
3176 if ( numBSPLightmaps == 0 || externalLightmaps ) {
3177 numBSPLightBytes = 0;
3178 bspLightBytes = NULL;
3182 numBSPLightBytes = ( numBSPLightmaps * game->lightmapSize * game->lightmapSize * 3 );
3183 bspLightBytes = safe_malloc( numBSPLightBytes );
3184 memset( bspLightBytes, 0, numBSPLightBytes );
3187 /* walk the list of output lightmaps */
3188 for ( i = 0; i < numOutLightmaps; i++ )
3190 /* get output lightmap */
3191 olm = &outLightmaps[ i ];
3193 /* fill output lightmap */
3194 if ( lightmapFill ) {
3195 FillOutLightmap( olm );
3198 /* is this a valid bsp lightmap? */
3199 if ( olm->lightmapNum >= 0 && !externalLightmaps ) {
3200 /* copy lighting data */
3201 lb = bspLightBytes + ( olm->lightmapNum * game->lightmapSize * game->lightmapSize * 3 );
3202 memcpy( lb, olm->bspLightBytes, game->lightmapSize * game->lightmapSize * 3 );
3204 /* copy direction data */
3206 lb = bspLightBytes + ( ( olm->lightmapNum + 1 ) * game->lightmapSize * game->lightmapSize * 3 );
3207 memcpy( lb, olm->bspDirBytes, game->lightmapSize * game->lightmapSize * 3 );
3211 /* external lightmap? */
3212 if ( olm->lightmapNum < 0 || olm->extLightmapNum >= 0 || externalLightmaps ) {
3213 /* make a directory for the lightmaps */
3216 /* set external lightmap number */
3217 olm->extLightmapNum = numExtLightmaps;
3219 /* write lightmap */
3220 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
3221 Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
3222 WriteTGA24( filename, olm->bspLightBytes, olm->customWidth, olm->customHeight, qtrue );
3225 /* write deluxemap */
3227 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
3228 Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
3229 WriteTGA24( filename, olm->bspDirBytes, olm->customWidth, olm->customHeight, qtrue );
3232 if ( debugDeluxemap ) {
3233 olm->extLightmapNum++;
3239 if ( numExtLightmaps > 0 ) {
3240 Sys_FPrintf( SYS_VRB, "\n" );
3243 /* delete unused external lightmaps */
3244 for ( i = numExtLightmaps; i; i++ )
3246 /* determine if file exists */
3247 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, i );
3248 if ( !FileExists( filename ) ) {
3256 Sys_FPrintf( SYS_VRB, "%d.", (int) ( I_FloatTime() - timer_start ) );
3258 /* -----------------------------------------------------------------
3259 project the lightmaps onto the bsp surfaces
3260 ----------------------------------------------------------------- */
3263 Sys_FPrintf( SYS_VRB, "projecting..." );
3265 timer_start = I_FloatTime();
3267 /* walk the list of surfaces */
3268 for ( i = 0; i < numBSPDrawSurfaces; i++ )
3270 /* get the surface and info */
3271 ds = &bspDrawSurfaces[ i ];
3272 info = &surfaceInfos[ i ];
3276 /* handle surfaces with identical parent */
3277 if ( info->parentSurfaceNum >= 0 ) {
3278 /* preserve original data and get parent */
3279 parent = &bspDrawSurfaces[ info->parentSurfaceNum ];
3280 memcpy( &dsTemp, ds, sizeof( *ds ) );
3282 /* overwrite child with parent data */
3283 memcpy( ds, parent, sizeof( *ds ) );
3285 /* restore key parts */
3286 ds->fogNum = dsTemp.fogNum;
3287 ds->firstVert = dsTemp.firstVert;
3288 ds->firstIndex = dsTemp.firstIndex;
3289 memcpy( ds->lightmapVecs, dsTemp.lightmapVecs, sizeof( dsTemp.lightmapVecs ) );
3291 /* set vertex data */
3292 dv = &bspDrawVerts[ ds->firstVert ];
3293 dvParent = &bspDrawVerts[ parent->firstVert ];
3294 for ( j = 0; j < ds->numVerts; j++ )
3296 memcpy( dv[ j ].lightmap, dvParent[ j ].lightmap, sizeof( dv[ j ].lightmap ) );
3297 memcpy( dv[ j ].color, dvParent[ j ].color, sizeof( dv[ j ].color ) );
3304 /* handle vertex lit or approximated surfaces */
3305 else if ( lm == NULL || lm->outLightmapNums[ 0 ] < 0 ) {
3306 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3308 ds->lightmapNum[ lightmapNum ] = -3;
3309 ds->lightmapStyles[ lightmapNum ] = ds->vertexStyles[ lightmapNum ];
3313 /* handle lightmapped surfaces */
3316 /* walk lightmaps */
3317 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3320 ds->lightmapStyles[ lightmapNum ] = lm->styles[ lightmapNum ];
3322 /* handle unused style */
3323 if ( lm->styles[ lightmapNum ] == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 ) {
3324 ds->lightmapNum[ lightmapNum ] = -3;
3328 /* get output lightmap */
3329 olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
3331 /* set bsp lightmap number */
3332 ds->lightmapNum[ lightmapNum ] = olm->lightmapNum;
3334 /* deluxemap debugging makes the deluxemap visible */
3335 if ( deluxemap && debugDeluxemap && lightmapNum == 0 ) {
3336 ds->lightmapNum[ lightmapNum ]++;
3339 /* calc lightmap origin in texture space */
3340 lmx = (float) lm->lightmapX[ lightmapNum ] / (float) olm->customWidth;
3341 lmy = (float) lm->lightmapY[ lightmapNum ] / (float) olm->customHeight;
3343 /* calc lightmap st coords */
3344 dv = &bspDrawVerts[ ds->firstVert ];
3345 ydv = &yDrawVerts[ ds->firstVert ];
3346 for ( j = 0; j < ds->numVerts; j++ )
3348 if ( lm->solid[ lightmapNum ] ) {
3349 dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + ( 0.5f / (float) olm->customWidth );
3350 dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + ( 0.5f / (float) olm->customWidth );
3354 dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + ( ydv[ j ].lightmap[ 0 ][ 0 ] / ( superSample * olm->customWidth ) );
3355 dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + ( ydv[ j ].lightmap[ 0 ][ 1 ] / ( superSample * olm->customHeight ) );
3361 /* store vertex colors */
3362 dv = &bspDrawVerts[ ds->firstVert ];
3363 for ( j = 0; j < ds->numVerts; j++ )
3365 /* walk lightmaps */
3366 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3368 /* handle unused style */
3369 if ( ds->vertexStyles[ lightmapNum ] == LS_NONE ) {
3370 VectorClear( color );
3374 /* get vertex color */
3375 luxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + j );
3376 VectorCopy( luxel, color );
3378 /* set minimum light */
3379 if ( lightmapNum == 0 ) {
3380 for ( k = 0; k < 3; k++ )
3381 if ( color[ k ] < minVertexLight[ k ] ) {
3382 color[ k ] = minVertexLight[ k ];
3387 /* store to bytes */
3388 if ( !info->si->noVertexLight ) {
3389 ColorToBytes( color, dv[ j ].color[ lightmapNum ], info->si->vertexScale );
3394 /* surfaces with styled lightmaps and a style marker get a custom generated shader (fixme: make this work with external lightmaps) */
3395 if ( olm != NULL && lm != NULL && lm->styles[ 1 ] != LS_NONE && game->load != LoadRBSPFile ) { //% info->si->styleMarker > 0 )
3397 char key[ 32 ], styleStage[ 512 ], styleStages[ 4096 ], rgbGen[ 128 ], alphaGen[ 128 ];
3401 sprintf( styleStages, "\n\t// Q3Map2 custom lightstyle stage(s)\n" );
3402 dv = &bspDrawVerts[ ds->firstVert ];
3404 /* depthFunc equal? */
3405 if ( info->si->styleMarker == 2 || info->si->implicitMap == IM_MASKED ) {
3412 /* generate stages for styled lightmaps */
3413 for ( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3416 style = lm->styles[ lightmapNum ];
3417 if ( style == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 ) {
3421 /* get output lightmap */
3422 olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
3425 if ( lm->outLightmapNums[ lightmapNum ] == lm->outLightmapNums[ 0 ] ) {
3426 strcpy( lightmapName, "$lightmap" );
3429 sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
3432 /* get rgbgen string */
3433 if ( rgbGenValues[ style ] == NULL ) {
3434 sprintf( key, "_style%drgbgen", style );
3435 rgbGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
3436 if ( rgbGenValues[ style ][ 0 ] == '\0' ) {
3437 rgbGenValues[ style ] = "wave noise 0.5 1 0 5.37";
3441 if ( rgbGenValues[ style ][ 0 ] != '\0' ) {
3442 sprintf( rgbGen, "\t\trgbGen %s // style %d\n", rgbGenValues[ style ], style );
3448 /* get alphagen string */
3449 if ( alphaGenValues[ style ] == NULL ) {
3450 sprintf( key, "_style%dalphagen", style );
3451 alphaGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
3453 if ( alphaGenValues[ style ][ 0 ] != '\0' ) {
3454 sprintf( alphaGen, "\t\talphaGen %s // style %d\n", alphaGenValues[ style ], style );
3457 alphaGen[ 0 ] = '\0';
3460 /* calculate st offset */
3461 lmx = dv[ 0 ].lightmap[ lightmapNum ][ 0 ] - dv[ 0 ].lightmap[ 0 ][ 0 ];
3462 lmy = dv[ 0 ].lightmap[ lightmapNum ][ 1 ] - dv[ 0 ].lightmap[ 0 ][ 1 ];
3464 /* create additional stage */
3465 if ( lmx == 0.0f && lmy == 0.0f ) {
3466 sprintf( styleStage, "\t{\n"
3467 "\t\tmap %s\n" /* lightmap */
3468 "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
3469 "%s" /* depthFunc equal */
3472 "\t\ttcGen lightmap\n"
3475 ( dfEqual ? "\t\tdepthFunc equal\n" : "" ),
3481 sprintf( styleStage, "\t{\n"
3482 "\t\tmap %s\n" /* lightmap */
3483 "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
3484 "%s" /* depthFunc equal */
3487 "\t\ttcGen lightmap\n"
3488 "\t\ttcMod transform 1 0 0 1 %1.5f %1.5f\n" /* st offset */
3491 ( dfEqual ? "\t\tdepthFunc equal\n" : "" ),
3499 strcat( styleStages, styleStage );
3502 /* create custom shader */
3503 if ( info->si->styleMarker == 2 ) {
3504 csi = CustomShader( info->si, "q3map_styleMarker2", styleStages );
3507 csi = CustomShader( info->si, "q3map_styleMarker", styleStages );
3510 /* emit remap command */
3511 //% EmitVertexRemapShader( csi->shader, info->si->shader );
3514 //% Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
3515 ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3516 //% Sys_Printf( ")\n" );
3519 /* devise a custom shader for this surface (fixme: make this work with light styles) */
3520 else if ( olm != NULL && lm != NULL && !externalLightmaps &&
3521 ( olm->customWidth != game->lightmapSize || olm->customHeight != game->lightmapSize ) ) {
3522 /* get output lightmap */
3523 olm = &outLightmaps[ lm->outLightmapNums[ 0 ] ];
3525 /* do some name mangling */
3526 sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
3528 /* create custom shader */
3529 csi = CustomShader( info->si, "$lightmap", lightmapName );
3532 //% Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
3533 ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3534 //% Sys_Printf( ")\n" );
3537 /* use the normal plain-jane shader */
3539 ds->shaderNum = EmitShader( info->si->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3543 Sys_FPrintf( SYS_VRB, "%d.", (int) ( I_FloatTime() - timer_start ) );
3546 Sys_FPrintf( SYS_VRB, "done.\n" );
3548 /* calc num stored */
3549 numStored = numBSPLightBytes / 3;
3550 efficiency = ( numStored <= 0 )
3552 : (float) numUsed / (float) numStored;
3555 Sys_Printf( "%9d luxels used\n", numUsed );
3556 Sys_Printf( "%9d luxels stored (%3.2f percent efficiency)\n", numStored, efficiency * 100.0f );
3557 Sys_Printf( "%9d solid surface lightmaps\n", numSolidLightmaps );
3558 Sys_Printf( "%9d identical surface lightmaps, using %d luxels\n", numTwins, numTwinLuxels );
3559 Sys_Printf( "%9d vertex forced surfaces\n", numSurfsVertexForced );
3560 Sys_Printf( "%9d vertex approximated surfaces\n", numSurfsVertexApproximated );
3561 Sys_Printf( "%9d BSP lightmaps\n", numBSPLightmaps );
3562 Sys_Printf( "%9d total lightmaps\n", numOutLightmaps );
3563 Sys_Printf( "%9d unique lightmap/shader combinations\n", numLightmapShaders );
3565 /* write map shader file */
3566 WriteMapShaderFile();