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_Printf( "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_Printf( "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_Printf( "WARNING: Unable to load image %s\n", filename );
243 if ( width != game->lightmapSize || height != game->lightmapSize ) {
244 Sys_Printf( "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 = ceil( length / lm->sampleSize ) + 1;
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 = ceil( length / lm->sampleSize ) + 1;
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_Printf( "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 ) {
911 /* then lightmap sample size */
912 if ( aInfo->sampleSize < bInfo->sampleSize ) {
915 else if ( aInfo->sampleSize > bInfo->sampleSize ) {
919 /* then lightmap axis */
920 for ( i = 0; i < 3; i++ )
922 if ( aInfo->axis[ i ] < bInfo->axis[ i ] ) {
925 else if ( aInfo->axis[ i ] > bInfo->axis[ i ] ) {
931 if ( aInfo->plane == NULL && bInfo->plane != NULL ) {
934 else if ( aInfo->plane != NULL && bInfo->plane == NULL ) {
937 else if ( aInfo->plane != NULL && bInfo->plane != NULL ) {
938 for ( i = 0; i < 4; i++ )
940 if ( aInfo->plane[ i ] < bInfo->plane[ i ] ) {
943 else if ( aInfo->plane[ i ] > bInfo->plane[ i ] ) {
949 /* then position in world */
950 for ( i = 0; i < 3; i++ )
952 if ( aInfo->mins[ i ] < bInfo->mins[ i ] ) {
955 else if ( aInfo->mins[ i ] > bInfo->mins[ i ] ) {
960 /* these are functionally identical (this should almost never happen) */
967 SetupSurfaceLightmaps()
968 allocates lightmaps for every surface in the bsp that needs one
969 this depends on yDrawVerts being allocated
972 void SetupSurfaceLightmaps( void ){
973 int i, j, k, s,num, num2;
976 bspDrawSurface_t *ds;
977 surfaceInfo_t *info, *info2;
980 vec3_t mapSize, entityOrigin;
984 Sys_FPrintf( SYS_VRB, "--- SetupSurfaceLightmaps ---\n" );
986 /* determine supersample amount */
987 if ( superSample < 1 ) {
990 else if ( superSample > 8 ) {
991 Sys_Printf( "WARNING: Insane supersampling amount (%d) detected.\n", superSample );
995 /* clear map bounds */
996 ClearBounds( mapMins, mapMaxs );
998 /* allocate a list of surface clusters */
999 numSurfaceClusters = 0;
1000 maxSurfaceClusters = numBSPLeafSurfaces;
1001 surfaceClusters = safe_malloc( maxSurfaceClusters * sizeof( *surfaceClusters ) );
1002 memset( surfaceClusters, 0, maxSurfaceClusters * sizeof( *surfaceClusters ) );
1004 /* allocate a list for per-surface info */
1005 surfaceInfos = safe_malloc( numBSPDrawSurfaces * sizeof( *surfaceInfos ) );
1006 memset( surfaceInfos, 0, numBSPDrawSurfaces * sizeof( *surfaceInfos ) );
1007 for ( i = 0; i < numBSPDrawSurfaces; i++ )
1008 surfaceInfos[ i ].childSurfaceNum = -1;
1010 /* allocate a list of surface indexes to be sorted */
1011 sortSurfaces = safe_malloc( numBSPDrawSurfaces * sizeof( int ) );
1012 memset( sortSurfaces, 0, numBSPDrawSurfaces * sizeof( int ) );
1014 /* walk each model in the bsp */
1015 for ( i = 0; i < numBSPModels; i++ )
1018 model = &bspModels[ i ];
1020 /* walk the list of surfaces in this model and fill out the info structs */
1021 for ( j = 0; j < model->numBSPSurfaces; j++ )
1023 /* make surface index */
1024 num = model->firstBSPSurface + j;
1026 /* copy index to sort list */
1027 sortSurfaces[ num ] = num;
1029 /* get surface and info */
1030 ds = &bspDrawSurfaces[ num ];
1031 info = &surfaceInfos[ num ];
1033 /* set entity origin */
1034 if ( ds->numVerts > 0 ) {
1035 VectorSubtract( yDrawVerts[ ds->firstVert ].xyz, bspDrawVerts[ ds->firstVert ].xyz, entityOrigin );
1038 VectorClear( entityOrigin );
1042 info->modelindex = i;
1045 info->firstSurfaceCluster = numSurfaceClusters;
1047 /* get extra data */
1048 info->si = GetSurfaceExtraShaderInfo( num );
1049 if ( info->si == NULL ) {
1050 info->si = ShaderInfoForShader( bspShaders[ ds->shaderNum ].shader );
1052 info->parentSurfaceNum = GetSurfaceExtraParentSurfaceNum( num );
1053 info->entityNum = GetSurfaceExtraEntityNum( num );
1054 info->castShadows = GetSurfaceExtraCastShadows( num );
1055 info->recvShadows = GetSurfaceExtraRecvShadows( num );
1056 info->sampleSize = GetSurfaceExtraSampleSize( num );
1057 info->longestCurve = GetSurfaceExtraLongestCurve( num );
1058 info->patchIterations = IterationsForCurve( info->longestCurve, patchSubdivisions );
1059 GetSurfaceExtraLightmapAxis( num, info->axis );
1062 if ( info->parentSurfaceNum >= 0 ) {
1063 surfaceInfos[ info->parentSurfaceNum ].childSurfaceNum = j;
1066 /* determine surface bounds */
1067 ClearBounds( info->mins, info->maxs );
1068 for ( k = 0; k < ds->numVerts; k++ )
1070 AddPointToBounds( yDrawVerts[ ds->firstVert + k ].xyz, mapMins, mapMaxs );
1071 AddPointToBounds( yDrawVerts[ ds->firstVert + k ].xyz, info->mins, info->maxs );
1074 /* find all the bsp clusters the surface falls into */
1075 for ( k = 0; k < numBSPLeafs; k++ )
1078 leaf = &bspLeafs[ k ];
1081 if ( leaf->mins[ 0 ] > info->maxs[ 0 ] || leaf->maxs[ 0 ] < info->mins[ 0 ] ||
1082 leaf->mins[ 1 ] > info->maxs[ 1 ] || leaf->maxs[ 1 ] < info->mins[ 1 ] ||
1083 leaf->mins[ 2 ] > info->maxs[ 2 ] || leaf->maxs[ 2 ] < info->mins[ 2 ] ) {
1087 /* test leaf surfaces */
1088 for ( s = 0; s < leaf->numBSPLeafSurfaces; s++ )
1090 if ( bspLeafSurfaces[ leaf->firstBSPLeafSurface + s ] == num ) {
1091 if ( numSurfaceClusters >= maxSurfaceClusters ) {
1092 Error( "maxSurfaceClusters exceeded" );
1094 surfaceClusters[ numSurfaceClusters ] = leaf->cluster;
1095 numSurfaceClusters++;
1096 info->numSurfaceClusters++;
1101 /* determine if surface is planar */
1102 if ( VectorLength( ds->lightmapVecs[ 2 ] ) > 0.0f ) {
1104 info->plane = safe_malloc( 4 * sizeof( float ) );
1105 VectorCopy( ds->lightmapVecs[ 2 ], info->plane );
1106 info->plane[ 3 ] = DotProduct( yDrawVerts[ ds->firstVert ].xyz, info->plane );
1109 /* determine if surface requires a lightmap */
1110 if ( ds->surfaceType == MST_TRIANGLE_SOUP ||
1111 ds->surfaceType == MST_FOLIAGE ||
1112 ( info->si->compileFlags & C_VERTEXLIT ) ||
1114 numSurfsVertexLit++;
1118 numSurfsLightmapped++;
1119 info->hasLightmap = qtrue;
1124 /* find longest map distance */
1125 VectorSubtract( mapMaxs, mapMins, mapSize );
1126 maxMapDistance = VectorLength( mapSize );
1128 /* sort the surfaces info list */
1129 qsort( sortSurfaces, numBSPDrawSurfaces, sizeof( int ), CompareSurfaceInfo );
1131 /* allocate a list of surfaces that would go into raw lightmaps */
1132 numLightSurfaces = 0;
1133 lightSurfaces = safe_malloc( numSurfsLightmapped * sizeof( int ) );
1134 memset( lightSurfaces, 0, numSurfsLightmapped * sizeof( int ) );
1136 /* allocate a list of raw lightmaps */
1137 numRawSuperLuxels = 0;
1138 numRawLightmaps = 0;
1139 rawLightmaps = safe_malloc( numSurfsLightmapped * sizeof( *rawLightmaps ) );
1140 memset( rawLightmaps, 0, numSurfsLightmapped * sizeof( *rawLightmaps ) );
1142 /* walk the list of sorted surfaces */
1143 for ( i = 0; i < numBSPDrawSurfaces; i++ )
1145 /* get info and attempt early out */
1146 num = sortSurfaces[ i ];
1147 ds = &bspDrawSurfaces[ num ];
1148 info = &surfaceInfos[ num ];
1149 if ( info->hasLightmap == qfalse || info->lm != NULL || info->parentSurfaceNum >= 0 ) {
1153 /* allocate a new raw lightmap */
1154 lm = &rawLightmaps[ numRawLightmaps ];
1158 lm->splotchFix = info->si->splotchFix;
1159 lm->firstLightSurface = numLightSurfaces;
1160 lm->numLightSurfaces = 0;
1161 /* vortex: multiply lightmap sample size by -samplescale */
1162 if ( sampleScale > 0 ) {
1163 lm->sampleSize = info->sampleSize * sampleScale;
1166 lm->sampleSize = info->sampleSize;
1168 lm->actualSampleSize = lm->sampleSize;
1169 lm->entityNum = info->entityNum;
1170 lm->recvShadows = info->recvShadows;
1171 lm->brightness = info->si->lmBrightness;
1172 lm->filterRadius = info->si->lmFilterRadius;
1173 VectorCopy( info->si->floodlightRGB, lm->floodlightRGB );
1174 lm->floodlightDistance = info->si->floodlightDistance;
1175 lm->floodlightIntensity = info->si->floodlightIntensity;
1176 lm->floodlightDirectionScale = info->si->floodlightDirectionScale;
1177 VectorCopy( info->axis, lm->axis );
1178 lm->plane = info->plane;
1179 VectorCopy( info->mins, lm->mins );
1180 VectorCopy( info->maxs, lm->maxs );
1182 lm->customWidth = info->si->lmCustomWidth;
1183 lm->customHeight = info->si->lmCustomHeight;
1185 /* add the surface to the raw lightmap */
1186 AddSurfaceToRawLightmap( num, lm );
1189 /* do an exhaustive merge */
1193 /* walk the list of surfaces again */
1195 for ( j = i + 1; j < numBSPDrawSurfaces && lm->finished == qfalse; j++ )
1197 /* get info and attempt early out */
1198 num2 = sortSurfaces[ j ];
1199 info2 = &surfaceInfos[ num2 ];
1200 if ( info2->hasLightmap == qfalse || info2->lm != NULL ) {
1204 /* add the surface to the raw lightmap */
1205 if ( AddSurfaceToRawLightmap( num2, lm ) ) {
1212 lm->numLightSurfaces--;
1218 /* finish the lightmap and allocate the various buffers */
1219 FinishRawLightmap( lm );
1222 if ( debugSampleSize < -1 ){
1223 Sys_FPrintf( SYS_VRB, "+%d similar occurrences;\t-debugSampleSize to show ones\n", -debugSampleSize - 1 );
1226 /* allocate vertex luxel storage */
1227 for ( k = 0; k < MAX_LIGHTMAPS; k++ )
1229 vertexLuxels[ k ] = safe_malloc( numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
1230 memset( vertexLuxels[ k ], 0, numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
1231 radVertexLuxels[ k ] = safe_malloc( numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
1232 memset( radVertexLuxels[ k ], 0, numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
1235 /* emit some stats */
1236 Sys_FPrintf( SYS_VRB, "%9d surfaces\n", numBSPDrawSurfaces );
1237 Sys_FPrintf( SYS_VRB, "%9d raw lightmaps\n", numRawLightmaps );
1238 Sys_FPrintf( SYS_VRB, "%9d surfaces vertex lit\n", numSurfsVertexLit );
1239 Sys_FPrintf( SYS_VRB, "%9d surfaces lightmapped\n", numSurfsLightmapped );
1240 Sys_FPrintf( SYS_VRB, "%9d planar surfaces lightmapped\n", numPlanarsLightmapped );
1241 Sys_FPrintf( SYS_VRB, "%9d non-planar surfaces lightmapped\n", numNonPlanarsLightmapped );
1242 Sys_FPrintf( SYS_VRB, "%9d patches lightmapped\n", numPatchesLightmapped );
1243 Sys_FPrintf( SYS_VRB, "%9d planar patches lightmapped\n", numPlanarPatchesLightmapped );
1249 StitchSurfaceLightmaps()
1250 stitches lightmap edges
1251 2002-11-20 update: use this func only for stitching nonplanar patch lightmap seams
1254 #define MAX_STITCH_CANDIDATES 32
1255 #define MAX_STITCH_LUXELS 64
1257 void StitchSurfaceLightmaps( void ){
1258 int i, j, x, y, x2, y2, *cluster, *cluster2,
1259 numStitched, numCandidates, numLuxels, f, fOld, start;
1260 rawLightmap_t *lm, *a, *b, *c[ MAX_STITCH_CANDIDATES ];
1261 float *luxel, *luxel2, *origin, *origin2, *normal, *normal2,
1262 sampleSize, average[ 3 ], totalColor, ootc;
1265 /* disabled for now */
1269 Sys_Printf( "--- StitchSurfaceLightmaps ---\n" );
1273 start = I_FloatTime();
1275 /* walk the list of raw lightmaps */
1277 for ( i = 0; i < numRawLightmaps; i++ )
1279 /* print pacifier */
1280 f = 10 * i / numRawLightmaps;
1283 Sys_Printf( "%i...", f );
1286 /* get lightmap a */
1287 a = &rawLightmaps[ i ];
1289 /* walk rest of lightmaps */
1291 for ( j = i + 1; j < numRawLightmaps && numCandidates < MAX_STITCH_CANDIDATES; j++ )
1293 /* get lightmap b */
1294 b = &rawLightmaps[ j ];
1296 /* test bounding box */
1297 if ( a->mins[ 0 ] > b->maxs[ 0 ] || a->maxs[ 0 ] < b->mins[ 0 ] ||
1298 a->mins[ 1 ] > b->maxs[ 1 ] || a->maxs[ 1 ] < b->mins[ 1 ] ||
1299 a->mins[ 2 ] > b->maxs[ 2 ] || a->maxs[ 2 ] < b->mins[ 2 ] ) {
1304 c[ numCandidates++ ] = b;
1308 for ( y = 0; y < a->sh; y++ )
1310 for ( x = 0; x < a->sw; x++ )
1312 /* ignore unmapped/unlit luxels */
1314 cluster = SUPER_CLUSTER( x, y );
1315 if ( *cluster == CLUSTER_UNMAPPED ) {
1318 luxel = SUPER_LUXEL( 0, x, y );
1319 if ( luxel[ 3 ] <= 0.0f ) {
1323 /* get particulars */
1324 origin = SUPER_ORIGIN( x, y );
1325 normal = SUPER_NORMAL( x, y );
1327 /* walk candidate list */
1328 for ( j = 0; j < numCandidates; j++ )
1334 /* set samplesize to the smaller of the pair */
1335 sampleSize = 0.5f * ( a->actualSampleSize < b->actualSampleSize ? a->actualSampleSize : b->actualSampleSize );
1337 /* test bounding box */
1338 if ( origin[ 0 ] < ( b->mins[ 0 ] - sampleSize ) || ( origin[ 0 ] > b->maxs[ 0 ] + sampleSize ) ||
1339 origin[ 1 ] < ( b->mins[ 1 ] - sampleSize ) || ( origin[ 1 ] > b->maxs[ 1 ] + sampleSize ) ||
1340 origin[ 2 ] < ( b->mins[ 2 ] - sampleSize ) || ( origin[ 2 ] > b->maxs[ 2 ] + sampleSize ) ) {
1344 /* walk candidate luxels */
1345 VectorClear( average );
1348 for ( y2 = 0; y2 < b->sh && numLuxels < MAX_STITCH_LUXELS; y2++ )
1350 for ( x2 = 0; x2 < b->sw && numLuxels < MAX_STITCH_LUXELS; x2++ )
1352 /* ignore same luxels */
1353 if ( a == b && abs( x - x2 ) <= 1 && abs( y - y2 ) <= 1 ) {
1357 /* ignore unmapped/unlit luxels */
1358 cluster2 = SUPER_CLUSTER( x2, y2 );
1359 if ( *cluster2 == CLUSTER_UNMAPPED ) {
1362 luxel2 = SUPER_LUXEL( 0, x2, y2 );
1363 if ( luxel2[ 3 ] <= 0.0f ) {
1367 /* get particulars */
1368 origin2 = SUPER_ORIGIN( x2, y2 );
1369 normal2 = SUPER_NORMAL( x2, y2 );
1372 if ( DotProduct( normal, normal2 ) < 0.5f ) {
1377 if ( fabs( origin[ 0 ] - origin2[ 0 ] ) > sampleSize ||
1378 fabs( origin[ 1 ] - origin2[ 1 ] ) > sampleSize ||
1379 fabs( origin[ 2 ] - origin2[ 2 ] ) > sampleSize ) {
1384 //% VectorSet( luxel2, 255, 0, 255 );
1385 VectorAdd( average, luxel2, average );
1386 totalColor += luxel2[ 3 ];
1391 if ( numLuxels == 0 ) {
1396 ootc = 1.0f / totalColor;
1397 VectorScale( average, ootc, luxel );
1405 /* emit statistics */
1406 Sys_Printf( " (%i)\n", (int) ( I_FloatTime() - start ) );
1407 Sys_FPrintf( SYS_VRB, "%9d luxels stitched\n", numStitched );
1414 compares two surface lightmaps' bsp luxels, ignoring occluded luxels
1417 #define SOLID_EPSILON 0.0625
1418 #define LUXEL_TOLERANCE 0.0025
1419 #define LUXEL_COLOR_FRAC 0.001302083 /* 1 / 3 / 256 */
1421 static qboolean CompareBSPLuxels( rawLightmap_t *a, int aNum, rawLightmap_t *b, int bNum ){
1424 double delta, total, rd, gd, bd;
1425 float *aLuxel, *bLuxel;
1428 /* styled lightmaps will never be collapsed to non-styled lightmaps when there is _minlight */
1429 if ( ( minLight[ 0 ] || minLight[ 1 ] || minLight[ 2 ] ) &&
1430 ( ( aNum == 0 && bNum != 0 ) || ( aNum != 0 && bNum == 0 ) ) ) {
1435 if ( a->customWidth != b->customWidth || a->customHeight != b->customHeight ||
1436 a->brightness != b->brightness ||
1437 a->solid[ aNum ] != b->solid[ bNum ] ||
1438 a->bspLuxels[ aNum ] == NULL || b->bspLuxels[ bNum ] == NULL ) {
1442 /* compare solid color lightmaps */
1443 if ( a->solid[ aNum ] && b->solid[ bNum ] ) {
1445 rd = fabs( a->solidColor[ aNum ][ 0 ] - b->solidColor[ bNum ][ 0 ] );
1446 gd = fabs( a->solidColor[ aNum ][ 1 ] - b->solidColor[ bNum ][ 1 ] );
1447 bd = fabs( a->solidColor[ aNum ][ 2 ] - b->solidColor[ bNum ][ 2 ] );
1450 if ( rd > SOLID_EPSILON || gd > SOLID_EPSILON || bd > SOLID_EPSILON ) {
1458 /* compare nonsolid lightmaps */
1459 if ( a->w != b->w || a->h != b->h ) {
1463 /* compare luxels */
1466 for ( y = 0; y < a->h; y++ )
1468 for ( x = 0; x < a->w; x++ )
1470 /* increment total */
1474 lm = a; aLuxel = BSP_LUXEL( aNum, x, y );
1475 lm = b; bLuxel = BSP_LUXEL( bNum, x, y );
1477 /* ignore unused luxels */
1478 if ( aLuxel[ 0 ] < 0 || bLuxel[ 0 ] < 0 ) {
1483 rd = fabs( aLuxel[ 0 ] - bLuxel[ 0 ] );
1484 gd = fabs( aLuxel[ 1 ] - bLuxel[ 1 ] );
1485 bd = fabs( aLuxel[ 2 ] - bLuxel[ 2 ] );
1487 /* 2003-09-27: compare individual luxels */
1488 if ( rd > 3.0 || gd > 3.0 || bd > 3.0 ) {
1492 /* compare (fixme: take into account perceptual differences) */
1493 delta += rd * LUXEL_COLOR_FRAC;
1494 delta += gd * LUXEL_COLOR_FRAC;
1495 delta += bd * LUXEL_COLOR_FRAC;
1497 /* is the change too high? */
1498 if ( total > 0.0 && ( ( delta / total ) > LUXEL_TOLERANCE ) ) {
1504 /* made it this far, they must be identical (or close enough) */
1512 merges two surface lightmaps' bsp luxels, overwriting occluded luxels
1515 static qboolean MergeBSPLuxels( rawLightmap_t *a, int aNum, rawLightmap_t *b, int bNum ){
1518 float luxel[ 3 ], *aLuxel, *bLuxel;
1522 if ( a->customWidth != b->customWidth || a->customHeight != b->customHeight ||
1523 a->brightness != b->brightness ||
1524 a->solid[ aNum ] != b->solid[ bNum ] ||
1525 a->bspLuxels[ aNum ] == NULL || b->bspLuxels[ bNum ] == NULL ) {
1529 /* compare solid lightmaps */
1530 if ( a->solid[ aNum ] && b->solid[ bNum ] ) {
1532 VectorAdd( a->solidColor[ aNum ], b->solidColor[ bNum ], luxel );
1533 VectorScale( luxel, 0.5f, luxel );
1536 VectorCopy( luxel, a->solidColor[ aNum ] );
1537 VectorCopy( luxel, b->solidColor[ bNum ] );
1539 /* return to sender */
1543 /* compare nonsolid lightmaps */
1544 if ( a->w != b->w || a->h != b->h ) {
1549 for ( y = 0; y < a->h; y++ )
1551 for ( x = 0; x < a->w; x++ )
1554 lm = a; aLuxel = BSP_LUXEL( aNum, x, y );
1555 lm = b; bLuxel = BSP_LUXEL( bNum, x, y );
1557 /* handle occlusion mismatch */
1558 if ( aLuxel[ 0 ] < 0.0f ) {
1559 VectorCopy( bLuxel, aLuxel );
1561 else if ( bLuxel[ 0 ] < 0.0f ) {
1562 VectorCopy( aLuxel, bLuxel );
1567 VectorAdd( aLuxel, bLuxel, luxel );
1568 VectorScale( luxel, 0.5f, luxel );
1570 /* debugging code */
1571 //% luxel[ 2 ] += 64.0f;
1574 VectorCopy( luxel, aLuxel );
1575 VectorCopy( luxel, bLuxel );
1588 determines if a single luxel is can be approximated with the interpolated vertex rgba
1591 static qboolean ApproximateLuxel( rawLightmap_t *lm, bspDrawVert_t *dv ){
1592 int i, x, y, d, lightmapNum;
1594 vec3_t color, vertexColor;
1595 byte cb[ 4 ], vcb[ 4 ];
1598 /* find luxel xy coords */
1599 x = dv->lightmap[ 0 ][ 0 ] / superSample;
1600 y = dv->lightmap[ 0 ][ 1 ] / superSample;
1604 else if ( x >= lm->w ) {
1610 else if ( y >= lm->h ) {
1615 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1618 if ( lm->styles[ lightmapNum ] == LS_NONE ) {
1623 luxel = BSP_LUXEL( lightmapNum, x, y );
1625 /* ignore occluded luxels */
1626 if ( luxel[ 0 ] < 0.0f || luxel[ 1 ] < 0.0f || luxel[ 2 ] < 0.0f ) {
1630 /* copy, set min color and compare */
1631 VectorCopy( luxel, color );
1632 VectorCopy( dv->color[ 0 ], vertexColor );
1634 /* styles are not affected by minlight */
1635 if ( lightmapNum == 0 ) {
1636 for ( i = 0; i < 3; i++ )
1639 if ( color[ i ] < minLight[ i ] ) {
1640 color[ i ] = minLight[ i ];
1642 if ( vertexColor[ i ] < minLight[ i ] ) { /* note NOT minVertexLight */
1643 vertexColor[ i ] = minLight[ i ];
1649 ColorToBytes( color, cb, 1.0f );
1650 ColorToBytes( vertexColor, vcb, 1.0f );
1653 for ( i = 0; i < 3; i++ )
1655 d = cb[ i ] - vcb[ i ];
1659 if ( d > approximateTolerance ) {
1665 /* close enough for the girls i date */
1672 ApproximateTriangle()
1673 determines if a single triangle can be approximated with vertex rgba
1676 static qboolean ApproximateTriangle_r( rawLightmap_t *lm, bspDrawVert_t *dv[ 3 ] ){
1677 bspDrawVert_t mid, *dv2[ 3 ];
1681 /* approximate the vertexes */
1682 if ( ApproximateLuxel( lm, dv[ 0 ] ) == qfalse ) {
1685 if ( ApproximateLuxel( lm, dv[ 1 ] ) == qfalse ) {
1688 if ( ApproximateLuxel( lm, dv[ 2 ] ) == qfalse ) {
1692 /* subdivide calc */
1695 float dx, dy, dist, maxDist;
1698 /* find the longest edge and split it */
1701 for ( i = 0; i < 3; i++ )
1703 dx = dv[ i ]->lightmap[ 0 ][ 0 ] - dv[ ( i + 1 ) % 3 ]->lightmap[ 0 ][ 0 ];
1704 dy = dv[ i ]->lightmap[ 0 ][ 1 ] - dv[ ( i + 1 ) % 3 ]->lightmap[ 0 ][ 1 ];
1705 dist = sqrt( ( dx * dx ) + ( dy * dy ) );
1706 if ( dist > maxDist ) {
1712 /* try to early out */
1713 if ( i < 0 || maxDist < subdivideThreshold ) {
1718 /* split the longest edge and map it */
1719 LerpDrawVert( dv[ max ], dv[ ( max + 1 ) % 3 ], &mid );
1720 if ( ApproximateLuxel( lm, &mid ) == qfalse ) {
1724 /* recurse to first triangle */
1725 VectorCopy( dv, dv2 );
1727 if ( ApproximateTriangle_r( lm, dv2 ) == qfalse ) {
1731 /* recurse to second triangle */
1732 VectorCopy( dv, dv2 );
1733 dv2[ ( max + 1 ) % 3 ] = ∣
1734 return ApproximateTriangle_r( lm, dv2 );
1740 ApproximateLightmap()
1741 determines if a raw lightmap can be approximated sufficiently with vertex colors
1744 static qboolean ApproximateLightmap( rawLightmap_t *lm ){
1745 int n, num, i, x, y, pw[ 5 ], r;
1746 bspDrawSurface_t *ds;
1747 surfaceInfo_t *info;
1748 mesh_t src, *subdivided, *mesh;
1749 bspDrawVert_t *verts, *dv[ 3 ];
1750 qboolean approximated;
1753 /* approximating? */
1754 if ( approximateTolerance <= 0 ) {
1758 /* test for jmonroe */
1760 /* don't approx lightmaps with styled twins */
1761 if ( lm->numStyledTwins > 0 ) {
1765 /* don't approx lightmaps with styles */
1766 for ( i = 1; i < MAX_LIGHTMAPS; i++ )
1768 if ( lm->styles[ i ] != LS_NONE ) {
1774 /* assume reduced until shadow detail is found */
1775 approximated = qtrue;
1777 /* walk the list of surfaces on this raw lightmap */
1778 for ( n = 0; n < lm->numLightSurfaces; n++ )
1781 num = lightSurfaces[ lm->firstLightSurface + n ];
1782 ds = &bspDrawSurfaces[ num ];
1783 info = &surfaceInfos[ num ];
1785 /* assume not-reduced initially */
1786 info->approximated = qfalse;
1788 /* bail if lightmap doesn't match up */
1789 if ( info->lm != lm ) {
1793 /* bail if not vertex lit */
1794 if ( info->si->noVertexLight ) {
1798 /* assume that surfaces whose bounding boxes is smaller than 2x samplesize will be forced to vertex */
1799 if ( ( info->maxs[ 0 ] - info->mins[ 0 ] ) <= ( 2.0f * info->sampleSize ) &&
1800 ( info->maxs[ 1 ] - info->mins[ 1 ] ) <= ( 2.0f * info->sampleSize ) &&
1801 ( info->maxs[ 2 ] - info->mins[ 2 ] ) <= ( 2.0f * info->sampleSize ) ) {
1802 info->approximated = qtrue;
1803 numSurfsVertexForced++;
1807 /* handle the triangles */
1808 switch ( ds->surfaceType )
1812 verts = yDrawVerts + ds->firstVert;
1814 /* map the triangles */
1815 info->approximated = qtrue;
1816 for ( i = 0; i < ds->numIndexes && info->approximated; i += 3 )
1818 dv[ 0 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i ] ];
1819 dv[ 1 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 1 ] ];
1820 dv[ 2 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 2 ] ];
1821 info->approximated = ApproximateTriangle_r( lm, dv );
1826 /* make a mesh from the drawsurf */
1827 src.width = ds->patchWidth;
1828 src.height = ds->patchHeight;
1829 src.verts = &yDrawVerts[ ds->firstVert ];
1830 //% subdivided = SubdivideMesh( src, 8, 512 );
1831 subdivided = SubdivideMesh2( src, info->patchIterations );
1833 /* fit it to the curve and remove colinear verts on rows/columns */
1834 PutMeshOnCurve( *subdivided );
1835 mesh = RemoveLinearMeshColumnsRows( subdivided );
1836 FreeMesh( subdivided );
1839 verts = mesh->verts;
1841 /* map the mesh quads */
1842 info->approximated = qtrue;
1843 for ( y = 0; y < ( mesh->height - 1 ) && info->approximated; y++ )
1845 for ( x = 0; x < ( mesh->width - 1 ) && info->approximated; x++ )
1848 pw[ 0 ] = x + ( y * mesh->width );
1849 pw[ 1 ] = x + ( ( y + 1 ) * mesh->width );
1850 pw[ 2 ] = x + 1 + ( ( y + 1 ) * mesh->width );
1851 pw[ 3 ] = x + 1 + ( y * mesh->width );
1852 pw[ 4 ] = x + ( y * mesh->width ); /* same as pw[ 0 ] */
1857 /* get drawverts and map first triangle */
1858 dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1859 dv[ 1 ] = &verts[ pw[ r + 1 ] ];
1860 dv[ 2 ] = &verts[ pw[ r + 2 ] ];
1861 info->approximated = ApproximateTriangle_r( lm, dv );
1863 /* get drawverts and map second triangle */
1864 dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1865 dv[ 1 ] = &verts[ pw[ r + 2 ] ];
1866 dv[ 2 ] = &verts[ pw[ r + 3 ] ];
1867 if ( info->approximated ) {
1868 info->approximated = ApproximateTriangle_r( lm, dv );
1882 if ( info->approximated == qfalse ) {
1883 approximated = qfalse;
1886 numSurfsVertexApproximated++;
1891 return approximated;
1897 TestOutLightmapStamp()
1898 tests a stamp on a given lightmap for validity
1901 static qboolean TestOutLightmapStamp( rawLightmap_t *lm, int lightmapNum, outLightmap_t *olm, int x, int y ){
1902 int sx, sy, ox, oy, offset;
1907 if ( x < 0 || y < 0 || ( x + lm->w ) > olm->customWidth || ( y + lm->h ) > olm->customHeight ) {
1911 /* solid lightmaps test a 1x1 stamp */
1912 if ( lm->solid[ lightmapNum ] ) {
1913 offset = ( y * olm->customWidth ) + x;
1914 if ( olm->lightBits[ offset >> 3 ] & ( 1 << ( offset & 7 ) ) ) {
1920 /* test the stamp */
1921 for ( sy = 0; sy < lm->h; sy++ )
1923 for ( sx = 0; sx < lm->w; sx++ )
1926 luxel = BSP_LUXEL( lightmapNum, sx, sy );
1927 if ( luxel[ 0 ] < 0.0f ) {
1931 /* get bsp lightmap coords and test */
1934 offset = ( oy * olm->customWidth ) + ox;
1935 if ( olm->lightBits[ offset >> 3 ] & ( 1 << ( offset & 7 ) ) ) {
1941 /* stamp is empty */
1949 sets up an output lightmap
1952 static void SetupOutLightmap( rawLightmap_t *lm, outLightmap_t *olm ){
1954 if ( lm == NULL || olm == NULL ) {
1958 /* is this a "normal" bsp-stored lightmap? */
1959 if ( ( lm->customWidth == game->lightmapSize && lm->customHeight == game->lightmapSize ) || externalLightmaps ) {
1960 olm->lightmapNum = numBSPLightmaps;
1963 /* lightmaps are interleaved with light direction maps */
1969 olm->lightmapNum = -3;
1972 /* set external lightmap number */
1973 olm->extLightmapNum = -1;
1976 olm->numLightmaps = 0;
1977 olm->customWidth = lm->customWidth;
1978 olm->customHeight = lm->customHeight;
1979 olm->freeLuxels = olm->customWidth * olm->customHeight;
1980 olm->numShaders = 0;
1982 /* allocate buffers */
1983 olm->lightBits = safe_malloc( ( olm->customWidth * olm->customHeight / 8 ) + 8 );
1984 memset( olm->lightBits, 0, ( olm->customWidth * olm->customHeight / 8 ) + 8 );
1985 olm->bspLightBytes = safe_malloc( olm->customWidth * olm->customHeight * 3 );
1986 memset( olm->bspLightBytes, 0, olm->customWidth * olm->customHeight * 3 );
1988 olm->bspDirBytes = safe_malloc( olm->customWidth * olm->customHeight * 3 );
1989 memset( olm->bspDirBytes, 0, olm->customWidth * olm->customHeight * 3 );
1997 for a given surface lightmap, find output lightmap pages and positions for it
2000 #define LIGHTMAP_RESERVE_COUNT 1
2001 static void FindOutLightmaps( rawLightmap_t *lm ){
2002 int i, j, k, lightmapNum, xMax, yMax, x = -1, y = -1, sx, sy, ox, oy, offset;
2004 surfaceInfo_t *info;
2005 float *luxel, *deluxel;
2006 vec3_t color, direction;
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 /* don't store non-custom raw lightmaps on custom bsp lightmaps */
2120 if ( olm->customWidth != lm->customWidth ||
2121 olm->customHeight != lm->customHeight ) {
2126 if ( lm->solid[ lightmapNum ] ) {
2127 xMax = olm->customWidth;
2128 yMax = olm->customHeight;
2132 xMax = ( olm->customWidth - lm->w ) + 1;
2133 yMax = ( olm->customHeight - lm->h ) + 1;
2136 /* walk the origin around the lightmap */
2137 for ( y = 0; y < yMax; y++ )
2139 for ( x = 0; x < xMax; x++ )
2141 /* find a fine tract of lauhnd */
2142 ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );
2165 if ( ok == qfalse ) {
2166 /* allocate LIGHTMAP_RESERVE_COUNT new output lightmaps */
2167 numOutLightmaps += LIGHTMAP_RESERVE_COUNT;
2168 olm = safe_malloc( numOutLightmaps * sizeof( outLightmap_t ) );
2170 Error( "FindOutLightmaps: Failed to allocate memory.\n" );
2173 if ( outLightmaps != NULL && numOutLightmaps > LIGHTMAP_RESERVE_COUNT ) {
2174 memcpy( olm, outLightmaps, ( numOutLightmaps - LIGHTMAP_RESERVE_COUNT ) * sizeof( outLightmap_t ) );
2175 free( outLightmaps );
2179 /* initialize both out lightmaps */
2180 for ( k = numOutLightmaps - LIGHTMAP_RESERVE_COUNT; k < numOutLightmaps; ++k )
2181 SetupOutLightmap( lm, &outLightmaps[ k ] );
2183 /* set out lightmap */
2184 i = numOutLightmaps - LIGHTMAP_RESERVE_COUNT;
2185 olm = &outLightmaps[ i ];
2187 /* set stamp xy origin to the first surface lightmap */
2188 if ( lightmapNum > 0 ) {
2189 x = lm->lightmapX[ 0 ];
2190 y = lm->lightmapY[ 0 ];
2194 /* if this is a style-using lightmap, it must be exported */
2195 if ( lightmapNum > 0 && game->load != LoadRBSPFile ) {
2196 olm->extLightmapNum = 0;
2199 /* add the surface lightmap to the bsp lightmap */
2200 lm->outLightmapNums[ lightmapNum ] = i;
2201 lm->lightmapX[ lightmapNum ] = x;
2202 lm->lightmapY[ lightmapNum ] = y;
2203 olm->numLightmaps++;
2206 for ( i = 0; i < lm->numLightSurfaces; i++ )
2208 /* get surface info */
2209 info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + i ] ];
2211 /* test for shader */
2212 for ( j = 0; j < olm->numShaders; j++ )
2214 if ( olm->shaders[ j ] == info->si ) {
2219 /* if it doesn't exist, add it */
2220 if ( j >= olm->numShaders && olm->numShaders < MAX_LIGHTMAP_SHADERS ) {
2221 olm->shaders[ olm->numShaders ] = info->si;
2223 numLightmapShaders++;
2228 if ( lm->solid[ lightmapNum ] ) {
2238 /* mark the bits used */
2239 for ( y = 0; y < yMax; y++ )
2241 for ( x = 0; x < xMax; x++ )
2244 luxel = BSP_LUXEL( lightmapNum, x, y );
2245 deluxel = BSP_DELUXEL( x, y );
2246 if ( luxel[ 0 ] < 0.0f && !lm->solid[ lightmapNum ] ) {
2250 /* set minimum light */
2251 if ( lm->solid[ lightmapNum ] ) {
2253 VectorSet( color, 255.0f, 0.0f, 0.0f );
2256 VectorCopy( lm->solidColor[ lightmapNum ], color );
2260 VectorCopy( luxel, color );
2263 /* styles are not affected by minlight */
2264 if ( lightmapNum == 0 ) {
2265 for ( i = 0; i < 3; i++ )
2267 if ( color[ i ] < minLight[ i ] ) {
2268 color[ i ] = minLight[ i ];
2273 /* get bsp lightmap coords */
2274 ox = x + lm->lightmapX[ lightmapNum ];
2275 oy = y + lm->lightmapY[ lightmapNum ];
2276 offset = ( oy * olm->customWidth ) + ox;
2278 /* flag pixel as used */
2279 olm->lightBits[ offset >> 3 ] |= ( 1 << ( offset & 7 ) );
2283 pixel = olm->bspLightBytes + ( ( ( oy * olm->customWidth ) + ox ) * 3 );
2284 ColorToBytes( color, pixel, lm->brightness );
2286 /* store direction */
2288 /* normalize average light direction */
2289 pixel = olm->bspDirBytes + ( ( ( oy * olm->customWidth ) + ox ) * 3 );
2290 VectorScale( deluxel, 1000.0f, direction );
2291 VectorNormalize( direction, direction );
2292 VectorScale( direction, 127.5f, direction );
2293 for ( i = 0; i < 3; i++ )
2294 pixel[ i ] = (byte)( 127.5f + direction[ i ] );
2304 CompareRawLightmap()
2305 compare function for qsort()
2308 static int CompareRawLightmap( const void *a, const void *b ){
2309 rawLightmap_t *alm, *blm;
2310 surfaceInfo_t *aInfo, *bInfo;
2315 alm = &rawLightmaps[ *( (const int*) a ) ];
2316 blm = &rawLightmaps[ *( (const int*) b ) ];
2318 /* get min number of surfaces */
2319 min = ( alm->numLightSurfaces < blm->numLightSurfaces ? alm->numLightSurfaces : blm->numLightSurfaces );
2322 for ( i = 0; i < min; i++ )
2324 /* get surface info */
2325 aInfo = &surfaceInfos[ lightSurfaces[ alm->firstLightSurface + i ] ];
2326 bInfo = &surfaceInfos[ lightSurfaces[ blm->firstLightSurface + i ] ];
2328 /* compare shader names */
2329 diff = strcmp( aInfo->si->shader, bInfo->si->shader );
2335 /* test style count */
2337 for ( i = 0; i < MAX_LIGHTMAPS; i++ )
2338 diff += blm->styles[ i ] - alm->styles[ i ];
2344 diff = ( blm->w * blm->h ) - ( alm->w * alm->h );
2349 /* must be equivalent */
2353 void FillOutLightmap( outLightmap_t *olm ){
2356 vec3_t dir_sum, light_sum;
2358 byte *lightBitsNew = NULL;
2359 byte *lightBytesNew = NULL;
2360 byte *dirBytesNew = NULL;
2362 lightBitsNew = safe_malloc( ( olm->customWidth * olm->customHeight + 8 ) / 8 );
2363 lightBytesNew = safe_malloc( olm->customWidth * olm->customHeight * 3 );
2365 dirBytesNew = safe_malloc( olm->customWidth * olm->customHeight * 3 );
2369 memset(olm->lightBits, 0, (olm->customWidth * olm->customHeight + 8) / 8);
2370 olm->lightBits[0] |= 1;
2371 olm->lightBits[(10 * olm->customWidth + 30) >> 3] |= 1 << ((10 * olm->customWidth + 30) & 7);
2372 memset(olm->bspLightBytes, 0, olm->customWidth * olm->customHeight * 3);
2373 olm->bspLightBytes[0] = 255;
2374 olm->bspLightBytes[(10 * olm->customWidth + 30) * 3 + 2] = 255;
2377 memcpy( lightBitsNew, olm->lightBits, ( olm->customWidth * olm->customHeight + 8 ) / 8 );
2378 memcpy( lightBytesNew, olm->bspLightBytes, olm->customWidth * olm->customHeight * 3 );
2380 memcpy( dirBytesNew, olm->bspDirBytes, olm->customWidth * olm->customHeight * 3 );
2386 for ( y = 0; y < olm->customHeight; ++y )
2388 for ( x = 0; x < olm->customWidth; ++x )
2390 ofs = y * olm->customWidth + x;
2391 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2395 VectorClear( dir_sum );
2396 VectorClear( light_sum );
2398 /* try all four neighbors */
2399 ofs = ( ( y + olm->customHeight - 1 ) % olm->customHeight ) * olm->customWidth + x;
2400 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2402 VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2404 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2408 ofs = ( ( y + 1 ) % olm->customHeight ) * olm->customWidth + x;
2409 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2411 VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2413 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2417 ofs = y * olm->customWidth + ( x + olm->customWidth - 1 ) % olm->customWidth;
2418 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2420 VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2422 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2426 ofs = y * olm->customWidth + ( x + 1 ) % olm->customWidth;
2427 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2429 VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2431 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2437 ofs = y * olm->customWidth + x;
2438 lightBitsNew[ofs >> 3] |= ( 1 << ( ofs & 7 ) );
2439 VectorScale( light_sum, 1.0 / cnt, lightBytesNew + ofs * 3 );
2441 VectorScale( dir_sum, 1.0 / cnt, dirBytesNew + ofs * 3 );
2451 memcpy( olm->lightBits, lightBitsNew, ( olm->customWidth * olm->customHeight + 8 ) / 8 );
2452 memcpy( olm->bspLightBytes, lightBytesNew, olm->customWidth * olm->customHeight * 3 );
2454 memcpy( olm->bspDirBytes, dirBytesNew, olm->customWidth * olm->customHeight * 3 );
2458 free( lightBitsNew );
2459 free( lightBytesNew );
2461 free( dirBytesNew );
2466 StoreSurfaceLightmaps()
2467 stores the surface lightmaps into the bsp as byte rgb triplets
2470 void StoreSurfaceLightmaps( void ){
2471 int i, j, k, x, y, lx, ly, sx, sy, *cluster, mappedSamples;
2472 int style, size, lightmapNum, lightmapNum2;
2473 float *normal, *luxel, *bspLuxel, *bspLuxel2, *radLuxel, samples, occludedSamples;
2474 vec3_t sample, occludedSample, dirSample, colorMins, colorMaxs;
2475 float *deluxel, *bspDeluxel, *bspDeluxel2;
2477 int numUsed, numTwins, numTwinLuxels, numStored;
2478 float lmx, lmy, efficiency;
2480 bspDrawSurface_t *ds, *parent, dsTemp;
2481 surfaceInfo_t *info;
2482 rawLightmap_t *lm, *lm2;
2484 bspDrawVert_t *dv, *ydv, *dvParent;
2485 char dirname[ 1024 ], filename[ 1024 ];
2487 char lightmapName[ 128 ];
2488 const char *rgbGenValues[ 256 ];
2489 const char *alphaGenValues[ 256 ];
2493 Sys_Printf( "--- StoreSurfaceLightmaps ---\n" );
2496 if ( lmCustomDir ) {
2497 strcpy( dirname, lmCustomDir );
2501 strcpy( dirname, source );
2502 StripExtension( dirname );
2504 memset( rgbGenValues, 0, sizeof( rgbGenValues ) );
2505 memset( alphaGenValues, 0, sizeof( alphaGenValues ) );
2507 /* -----------------------------------------------------------------
2508 average the sampled luxels into the bsp luxels
2509 ----------------------------------------------------------------- */
2512 Sys_Printf( "Subsampling..." );
2514 /* walk the list of raw lightmaps */
2518 numSolidLightmaps = 0;
2519 for ( i = 0; i < numRawLightmaps; i++ )
2522 lm = &rawLightmaps[ i ];
2524 /* walk individual lightmaps */
2525 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2528 if ( lm->superLuxels[ lightmapNum ] == NULL ) {
2532 /* allocate bsp luxel storage */
2533 if ( lm->bspLuxels[ lightmapNum ] == NULL ) {
2534 size = lm->w * lm->h * BSP_LUXEL_SIZE * sizeof( float );
2535 lm->bspLuxels[ lightmapNum ] = safe_malloc( size );
2536 memset( lm->bspLuxels[ lightmapNum ], 0, size );
2539 /* allocate radiosity lightmap storage */
2541 size = lm->w * lm->h * RAD_LUXEL_SIZE * sizeof( float );
2542 if ( lm->radLuxels[ lightmapNum ] == NULL ) {
2543 lm->radLuxels[ lightmapNum ] = safe_malloc( size );
2545 memset( lm->radLuxels[ lightmapNum ], 0, size );
2548 /* average supersampled luxels */
2549 for ( y = 0; y < lm->h; y++ )
2551 for ( x = 0; x < lm->w; x++ )
2555 occludedSamples = 0.0f;
2557 VectorClear( sample );
2558 VectorClear( occludedSample );
2559 VectorClear( dirSample );
2560 for ( ly = 0; ly < superSample; ly++ )
2562 for ( lx = 0; lx < superSample; lx++ )
2565 sx = x * superSample + lx;
2566 sy = y * superSample + ly;
2567 luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2568 deluxel = SUPER_DELUXEL( sx, sy );
2569 normal = SUPER_NORMAL( sx, sy );
2570 cluster = SUPER_CLUSTER( sx, sy );
2572 /* sample deluxemap */
2573 if ( deluxemap && lightmapNum == 0 ) {
2574 VectorAdd( dirSample, deluxel, dirSample );
2577 /* keep track of used/occluded samples */
2578 if ( *cluster != CLUSTER_UNMAPPED ) {
2582 /* handle lightmap border? */
2583 if ( lightmapBorder && ( sx == 0 || sx == ( lm->sw - 1 ) || sy == 0 || sy == ( lm->sh - 1 ) ) && luxel[ 3 ] > 0.0f ) {
2584 VectorSet( sample, 255.0f, 0.0f, 0.0f );
2589 else if ( debug && *cluster < 0 ) {
2590 if ( *cluster == CLUSTER_UNMAPPED ) {
2591 VectorSet( luxel, 255, 204, 0 );
2593 else if ( *cluster == CLUSTER_OCCLUDED ) {
2594 VectorSet( luxel, 255, 0, 255 );
2596 else if ( *cluster == CLUSTER_FLOODED ) {
2597 VectorSet( luxel, 0, 32, 255 );
2599 VectorAdd( occludedSample, luxel, occludedSample );
2600 occludedSamples += 1.0f;
2603 /* normal luxel handling */
2604 else if ( luxel[ 3 ] > 0.0f ) {
2605 /* handle lit or flooded luxels */
2606 if ( *cluster > 0 || *cluster == CLUSTER_FLOODED ) {
2607 VectorAdd( sample, luxel, sample );
2608 samples += luxel[ 3 ];
2611 /* handle occluded or unmapped luxels */
2614 VectorAdd( occludedSample, luxel, occludedSample );
2615 occludedSamples += luxel[ 3 ];
2618 /* handle style debugging */
2619 if ( debug && lightmapNum > 0 && x < 2 && y < 2 ) {
2620 VectorCopy( debugColors[ 0 ], sample );
2627 /* only use occluded samples if necessary */
2628 if ( samples <= 0.0f ) {
2629 VectorCopy( occludedSample, sample );
2630 samples = occludedSamples;
2634 luxel = SUPER_LUXEL( lightmapNum, x, y );
2635 deluxel = SUPER_DELUXEL( x, y );
2637 /* store light direction */
2638 if ( deluxemap && lightmapNum == 0 ) {
2639 VectorCopy( dirSample, deluxel );
2642 /* store the sample back in super luxels */
2643 if ( samples > 0.01f ) {
2644 VectorScale( sample, ( 1.0f / samples ), luxel );
2648 /* if any samples were mapped in any way, store ambient color */
2649 else if ( mappedSamples > 0 ) {
2650 if ( lightmapNum == 0 ) {
2651 VectorCopy( ambientColor, luxel );
2654 VectorClear( luxel );
2659 /* store a bogus value to be fixed later */
2662 VectorClear( luxel );
2670 ClearBounds( colorMins, colorMaxs );
2672 /* clean up and store into bsp luxels */
2673 for ( y = 0; y < lm->h; y++ )
2675 for ( x = 0; x < lm->w; x++ )
2678 luxel = SUPER_LUXEL( lightmapNum, x, y );
2679 deluxel = SUPER_DELUXEL( x, y );
2681 /* copy light direction */
2682 if ( deluxemap && lightmapNum == 0 ) {
2683 VectorCopy( deluxel, dirSample );
2686 /* is this a valid sample? */
2687 if ( luxel[ 3 ] > 0.0f ) {
2688 VectorCopy( luxel, sample );
2689 samples = luxel[ 3 ];
2693 /* fix negative samples */
2694 for ( j = 0; j < 3; j++ )
2696 if ( sample[ j ] < 0.0f ) {
2703 /* nick an average value from the neighbors */
2704 VectorClear( sample );
2705 VectorClear( dirSample );
2708 /* fixme: why is this disabled?? */
2709 for ( sy = ( y - 1 ); sy <= ( y + 1 ); sy++ )
2711 if ( sy < 0 || sy >= lm->h ) {
2715 for ( sx = ( x - 1 ); sx <= ( x + 1 ); sx++ )
2717 if ( sx < 0 || sx >= lm->w || ( sx == x && sy == y ) ) {
2721 /* get neighbor's particulars */
2722 luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2723 if ( luxel[ 3 ] < 0.0f ) {
2726 VectorAdd( sample, luxel, sample );
2727 samples += luxel[ 3 ];
2732 if ( samples == 0.0f ) {
2733 VectorSet( sample, -1.0f, -1.0f, -1.0f );
2741 /* fix negative samples */
2742 for ( j = 0; j < 3; j++ )
2744 if ( sample[ j ] < 0.0f ) {
2751 /* scale the sample */
2752 VectorScale( sample, ( 1.0f / samples ), sample );
2754 /* store the sample in the radiosity luxels */
2756 radLuxel = RAD_LUXEL( lightmapNum, x, y );
2757 VectorCopy( sample, radLuxel );
2759 /* if only storing bounced light, early out here */
2760 if ( bounceOnly && !bouncing ) {
2765 /* store the sample in the bsp luxels */
2766 bspLuxel = BSP_LUXEL( lightmapNum, x, y );
2767 bspDeluxel = BSP_DELUXEL( x, y );
2769 VectorAdd( bspLuxel, sample, bspLuxel );
2770 if ( deluxemap && lightmapNum == 0 ) {
2771 VectorAdd( bspDeluxel, dirSample, bspDeluxel );
2774 /* add color to bounds for solid checking */
2775 if ( samples > 0.0f ) {
2776 AddPointToBounds( bspLuxel, colorMins, colorMaxs );
2781 /* set solid color */
2782 lm->solid[ lightmapNum ] = qfalse;
2783 VectorAdd( colorMins, colorMaxs, lm->solidColor[ lightmapNum ] );
2784 VectorScale( lm->solidColor[ lightmapNum ], 0.5f, lm->solidColor[ lightmapNum ] );
2786 /* nocollapse prevents solid lightmaps */
2787 if ( noCollapse == qfalse ) {
2788 /* check solid color */
2789 VectorSubtract( colorMaxs, colorMins, sample );
2790 if ( ( sample[ 0 ] <= SOLID_EPSILON && sample[ 1 ] <= SOLID_EPSILON && sample[ 2 ] <= SOLID_EPSILON ) ||
2791 ( lm->w <= 2 && lm->h <= 2 ) ) { /* small lightmaps get forced to solid color */
2793 VectorCopy( colorMins, lm->solidColor[ lightmapNum ] );
2794 lm->solid[ lightmapNum ] = qtrue;
2795 numSolidLightmaps++;
2798 /* if all lightmaps aren't solid, then none of them are solid */
2799 if ( lm->solid[ lightmapNum ] != lm->solid[ 0 ] ) {
2800 for ( y = 0; y < MAX_LIGHTMAPS; y++ )
2802 if ( lm->solid[ y ] ) {
2803 numSolidLightmaps--;
2805 lm->solid[ y ] = qfalse;
2810 /* wrap bsp luxels if necessary */
2811 if ( lm->wrap[ 0 ] ) {
2812 for ( y = 0; y < lm->h; y++ )
2814 bspLuxel = BSP_LUXEL( lightmapNum, 0, y );
2815 bspLuxel2 = BSP_LUXEL( lightmapNum, lm->w - 1, y );
2816 VectorAdd( bspLuxel, bspLuxel2, bspLuxel );
2817 VectorScale( bspLuxel, 0.5f, bspLuxel );
2818 VectorCopy( bspLuxel, bspLuxel2 );
2819 if ( deluxemap && lightmapNum == 0 ) {
2820 bspDeluxel = BSP_DELUXEL( 0, y );
2821 bspDeluxel2 = BSP_DELUXEL( lm->w - 1, y );
2822 VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel );
2823 VectorScale( bspDeluxel, 0.5f, bspDeluxel );
2824 VectorCopy( bspDeluxel, bspDeluxel2 );
2828 if ( lm->wrap[ 1 ] ) {
2829 for ( x = 0; x < lm->w; x++ )
2831 bspLuxel = BSP_LUXEL( lightmapNum, x, 0 );
2832 bspLuxel2 = BSP_LUXEL( lightmapNum, x, lm->h - 1 );
2833 VectorAdd( bspLuxel, bspLuxel2, bspLuxel );
2834 VectorScale( bspLuxel, 0.5f, bspLuxel );
2835 VectorCopy( bspLuxel, bspLuxel2 );
2836 if ( deluxemap && lightmapNum == 0 ) {
2837 bspDeluxel = BSP_DELUXEL( x, 0 );
2838 bspDeluxel2 = BSP_DELUXEL( x, lm->h - 1 );
2839 VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel );
2840 VectorScale( bspDeluxel, 0.5f, bspDeluxel );
2841 VectorCopy( bspDeluxel, bspDeluxel2 );
2848 /* -----------------------------------------------------------------
2849 convert modelspace deluxemaps to tangentspace
2850 ----------------------------------------------------------------- */
2853 if ( deluxemap && deluxemode == 1 ) {
2854 vec3_t worldUp, myNormal, myTangent, myBinormal;
2857 Sys_Printf( "converting..." );
2859 for ( i = 0; i < numRawLightmaps; i++ )
2862 lm = &rawLightmaps[ i ];
2864 /* walk lightmap samples */
2865 for ( y = 0; y < lm->sh; y++ )
2867 for ( x = 0; x < lm->sw; x++ )
2869 /* get normal and deluxel */
2870 normal = SUPER_NORMAL( x, y );
2871 cluster = SUPER_CLUSTER( x, y );
2872 bspDeluxel = BSP_DELUXEL( x, y );
2873 deluxel = SUPER_DELUXEL( x, y );
2876 VectorSet( myNormal, normal[0], normal[1], normal[2] );
2878 /* get tangent vectors */
2879 if ( myNormal[ 0 ] == 0.0f && myNormal[ 1 ] == 0.0f ) {
2880 if ( myNormal[ 2 ] == 1.0f ) {
2881 VectorSet( myTangent, 1.0f, 0.0f, 0.0f );
2882 VectorSet( myBinormal, 0.0f, 1.0f, 0.0f );
2884 else if ( myNormal[ 2 ] == -1.0f ) {
2885 VectorSet( myTangent, -1.0f, 0.0f, 0.0f );
2886 VectorSet( myBinormal, 0.0f, 1.0f, 0.0f );
2891 VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
2892 CrossProduct( myNormal, worldUp, myTangent );
2893 VectorNormalize( myTangent, myTangent );
2894 CrossProduct( myTangent, myNormal, myBinormal );
2895 VectorNormalize( myBinormal, myBinormal );
2898 /* project onto plane */
2899 dist = -DotProduct( myTangent, myNormal );
2900 VectorMA( myTangent, dist, myNormal, myTangent );
2901 dist = -DotProduct( myBinormal, myNormal );
2902 VectorMA( myBinormal, dist, myNormal, myBinormal );
2905 VectorNormalize( myTangent, myTangent );
2906 VectorNormalize( myBinormal, myBinormal );
2908 /* convert modelspace deluxel to tangentspace */
2909 dirSample[0] = bspDeluxel[0];
2910 dirSample[1] = bspDeluxel[1];
2911 dirSample[2] = bspDeluxel[2];
2912 VectorNormalize( dirSample, dirSample );
2914 /* fix tangents to world matrix */
2915 if ( myNormal[0] > 0 || myNormal[1] < 0 || myNormal[2] < 0 ) {
2916 VectorNegate( myTangent, myTangent );
2919 /* build tangentspace vectors */
2920 bspDeluxel[0] = DotProduct( dirSample, myTangent );
2921 bspDeluxel[1] = DotProduct( dirSample, myBinormal );
2922 bspDeluxel[2] = DotProduct( dirSample, myNormal );
2929 /* -----------------------------------------------------------------
2931 ----------------------------------------------------------------- */
2933 #ifdef sdfsdfwq312323
2935 Sys_Printf( "blending..." );
2937 for ( i = 0; i < numRawLightmaps; i++ )
2943 lm = &rawLightmaps[ i ];
2945 /* walk individual lightmaps */
2946 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2949 if ( lm->superLuxels[ lightmapNum ] == NULL ) {
2953 /* walk lightmap samples */
2954 for ( y = 0; y < lm->sh; y++ )
2956 for ( x = 0; x < lm->sw; x++ )
2959 bspLuxel = BSP_LUXEL( lightmapNum, x, y );
2962 VectorNormalize( bspLuxel, myColor );
2963 myBrightness = VectorLength( bspLuxel );
2964 myBrightness *= ( 1 / 127.0f );
2965 myBrightness = myBrightness * myBrightness;
2966 myBrightness *= 127.0f;
2967 VectorScale( myColor, myBrightness, bspLuxel );
2974 /* -----------------------------------------------------------------
2975 collapse non-unique lightmaps
2976 ----------------------------------------------------------------- */
2978 if ( noCollapse == qfalse && deluxemap == qfalse ) {
2980 Sys_Printf( "collapsing..." );
2982 /* set all twin refs to null */
2983 for ( i = 0; i < numRawLightmaps; i++ )
2985 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2987 rawLightmaps[ i ].twins[ lightmapNum ] = NULL;
2988 rawLightmaps[ i ].twinNums[ lightmapNum ] = -1;
2989 rawLightmaps[ i ].numStyledTwins = 0;
2993 /* walk the list of raw lightmaps */
2994 for ( i = 0; i < numRawLightmaps; i++ )
2997 lm = &rawLightmaps[ i ];
2999 /* walk lightmaps */
3000 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3003 if ( lm->bspLuxels[ lightmapNum ] == NULL ||
3004 lm->twins[ lightmapNum ] != NULL ) {
3008 /* find all lightmaps that are virtually identical to this one */
3009 for ( j = i + 1; j < numRawLightmaps; j++ )
3012 lm2 = &rawLightmaps[ j ];
3014 /* walk lightmaps */
3015 for ( lightmapNum2 = 0; lightmapNum2 < MAX_LIGHTMAPS; lightmapNum2++ )
3018 if ( lm2->bspLuxels[ lightmapNum2 ] == NULL ||
3019 lm2->twins[ lightmapNum2 ] != NULL ) {
3024 if ( CompareBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ) ) {
3025 /* merge and set twin */
3026 if ( MergeBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ) ) {
3027 lm2->twins[ lightmapNum2 ] = lm;
3028 lm2->twinNums[ lightmapNum2 ] = lightmapNum;
3030 numTwinLuxels += ( lm->w * lm->h );
3032 /* count styled twins */
3033 if ( lightmapNum > 0 ) {
3034 lm->numStyledTwins++;
3044 /* -----------------------------------------------------------------
3045 sort raw lightmaps by shader
3046 ----------------------------------------------------------------- */
3049 Sys_Printf( "sorting..." );
3051 /* allocate a new sorted list */
3052 if ( sortLightmaps == NULL ) {
3053 sortLightmaps = safe_malloc( numRawLightmaps * sizeof( int ) );
3056 /* fill it out and sort it */
3057 for ( i = 0; i < numRawLightmaps; i++ )
3058 sortLightmaps[ i ] = i;
3059 qsort( sortLightmaps, numRawLightmaps, sizeof( int ), CompareRawLightmap );
3061 /* -----------------------------------------------------------------
3062 allocate output lightmaps
3063 ----------------------------------------------------------------- */
3066 Sys_Printf( "allocating..." );
3068 /* kill all existing output lightmaps */
3069 if ( outLightmaps != NULL ) {
3070 for ( i = 0; i < numOutLightmaps; i++ )
3072 free( outLightmaps[ i ].lightBits );
3073 free( outLightmaps[ i ].bspLightBytes );
3075 free( outLightmaps );
3076 outLightmaps = NULL;
3079 numLightmapShaders = 0;
3080 numOutLightmaps = 0;
3081 numBSPLightmaps = 0;
3082 numExtLightmaps = 0;
3084 /* find output lightmap */
3085 for ( i = 0; i < numRawLightmaps; i++ )
3087 lm = &rawLightmaps[ sortLightmaps[ i ] ];
3088 FindOutLightmaps( lm );
3091 /* set output numbers in twinned lightmaps */
3092 for ( i = 0; i < numRawLightmaps; i++ )
3095 lm = &rawLightmaps[ sortLightmaps[ i ] ];
3097 /* walk lightmaps */
3098 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3101 lm2 = lm->twins[ lightmapNum ];
3102 if ( lm2 == NULL ) {
3105 lightmapNum2 = lm->twinNums[ lightmapNum ];
3107 /* find output lightmap from twin */
3108 lm->outLightmapNums[ lightmapNum ] = lm2->outLightmapNums[ lightmapNum2 ];
3109 lm->lightmapX[ lightmapNum ] = lm2->lightmapX[ lightmapNum2 ];
3110 lm->lightmapY[ lightmapNum ] = lm2->lightmapY[ lightmapNum2 ];
3114 /* -----------------------------------------------------------------
3115 store output lightmaps
3116 ----------------------------------------------------------------- */
3119 Sys_Printf( "storing..." );
3121 /* count the bsp lightmaps and allocate space */
3122 if ( bspLightBytes != NULL ) {
3123 free( bspLightBytes );
3125 if ( numBSPLightmaps == 0 || externalLightmaps ) {
3126 numBSPLightBytes = 0;
3127 bspLightBytes = NULL;
3131 numBSPLightBytes = ( numBSPLightmaps * game->lightmapSize * game->lightmapSize * 3 );
3132 bspLightBytes = safe_malloc( numBSPLightBytes );
3133 memset( bspLightBytes, 0, numBSPLightBytes );
3136 /* walk the list of output lightmaps */
3137 for ( i = 0; i < numOutLightmaps; i++ )
3139 /* get output lightmap */
3140 olm = &outLightmaps[ i ];
3142 /* fill output lightmap */
3143 if ( lightmapFill ) {
3144 FillOutLightmap( olm );
3147 /* is this a valid bsp lightmap? */
3148 if ( olm->lightmapNum >= 0 && !externalLightmaps ) {
3149 /* copy lighting data */
3150 lb = bspLightBytes + ( olm->lightmapNum * game->lightmapSize * game->lightmapSize * 3 );
3151 memcpy( lb, olm->bspLightBytes, game->lightmapSize * game->lightmapSize * 3 );
3153 /* copy direction data */
3155 lb = bspLightBytes + ( ( olm->lightmapNum + 1 ) * game->lightmapSize * game->lightmapSize * 3 );
3156 memcpy( lb, olm->bspDirBytes, game->lightmapSize * game->lightmapSize * 3 );
3160 /* external lightmap? */
3161 if ( olm->lightmapNum < 0 || olm->extLightmapNum >= 0 || externalLightmaps ) {
3162 /* make a directory for the lightmaps */
3165 /* set external lightmap number */
3166 olm->extLightmapNum = numExtLightmaps;
3168 /* write lightmap */
3169 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
3170 Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
3171 WriteTGA24( filename, olm->bspLightBytes, olm->customWidth, olm->customHeight, qtrue );
3174 /* write deluxemap */
3176 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
3177 Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
3178 WriteTGA24( filename, olm->bspDirBytes, olm->customWidth, olm->customHeight, qtrue );
3181 if ( debugDeluxemap ) {
3182 olm->extLightmapNum++;
3188 if ( numExtLightmaps > 0 ) {
3192 /* delete unused external lightmaps */
3193 for ( i = numExtLightmaps; i; i++ )
3195 /* determine if file exists */
3196 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, i );
3197 if ( !FileExists( filename ) ) {
3205 /* -----------------------------------------------------------------
3206 project the lightmaps onto the bsp surfaces
3207 ----------------------------------------------------------------- */
3210 Sys_Printf( "projecting..." );
3212 /* walk the list of surfaces */
3213 for ( i = 0; i < numBSPDrawSurfaces; i++ )
3215 /* get the surface and info */
3216 ds = &bspDrawSurfaces[ i ];
3217 info = &surfaceInfos[ i ];
3221 /* handle surfaces with identical parent */
3222 if ( info->parentSurfaceNum >= 0 ) {
3223 /* preserve original data and get parent */
3224 parent = &bspDrawSurfaces[ info->parentSurfaceNum ];
3225 memcpy( &dsTemp, ds, sizeof( *ds ) );
3227 /* overwrite child with parent data */
3228 memcpy( ds, parent, sizeof( *ds ) );
3230 /* restore key parts */
3231 ds->fogNum = dsTemp.fogNum;
3232 ds->firstVert = dsTemp.firstVert;
3233 ds->firstIndex = dsTemp.firstIndex;
3234 memcpy( ds->lightmapVecs, dsTemp.lightmapVecs, sizeof( dsTemp.lightmapVecs ) );
3236 /* set vertex data */
3237 dv = &bspDrawVerts[ ds->firstVert ];
3238 dvParent = &bspDrawVerts[ parent->firstVert ];
3239 for ( j = 0; j < ds->numVerts; j++ )
3241 memcpy( dv[ j ].lightmap, dvParent[ j ].lightmap, sizeof( dv[ j ].lightmap ) );
3242 memcpy( dv[ j ].color, dvParent[ j ].color, sizeof( dv[ j ].color ) );
3249 /* handle vertex lit or approximated surfaces */
3250 else if ( lm == NULL || lm->outLightmapNums[ 0 ] < 0 ) {
3251 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3253 ds->lightmapNum[ lightmapNum ] = -3;
3254 ds->lightmapStyles[ lightmapNum ] = ds->vertexStyles[ lightmapNum ];
3258 /* handle lightmapped surfaces */
3261 /* walk lightmaps */
3262 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3265 ds->lightmapStyles[ lightmapNum ] = lm->styles[ lightmapNum ];
3267 /* handle unused style */
3268 if ( lm->styles[ lightmapNum ] == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 ) {
3269 ds->lightmapNum[ lightmapNum ] = -3;
3273 /* get output lightmap */
3274 olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
3276 /* set bsp lightmap number */
3277 ds->lightmapNum[ lightmapNum ] = olm->lightmapNum;
3279 /* deluxemap debugging makes the deluxemap visible */
3280 if ( deluxemap && debugDeluxemap && lightmapNum == 0 ) {
3281 ds->lightmapNum[ lightmapNum ]++;
3284 /* calc lightmap origin in texture space */
3285 lmx = (float) lm->lightmapX[ lightmapNum ] / (float) olm->customWidth;
3286 lmy = (float) lm->lightmapY[ lightmapNum ] / (float) olm->customHeight;
3288 /* calc lightmap st coords */
3289 dv = &bspDrawVerts[ ds->firstVert ];
3290 ydv = &yDrawVerts[ ds->firstVert ];
3291 for ( j = 0; j < ds->numVerts; j++ )
3293 if ( lm->solid[ lightmapNum ] ) {
3294 dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + ( 0.5f / (float) olm->customWidth );
3295 dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + ( 0.5f / (float) olm->customWidth );
3299 dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + ( ydv[ j ].lightmap[ 0 ][ 0 ] / ( superSample * olm->customWidth ) );
3300 dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + ( ydv[ j ].lightmap[ 0 ][ 1 ] / ( superSample * olm->customHeight ) );
3306 /* store vertex colors */
3307 dv = &bspDrawVerts[ ds->firstVert ];
3308 for ( j = 0; j < ds->numVerts; j++ )
3310 /* walk lightmaps */
3311 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3313 /* handle unused style */
3314 if ( ds->vertexStyles[ lightmapNum ] == LS_NONE ) {
3315 VectorClear( color );
3319 /* get vertex color */
3320 luxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + j );
3321 VectorCopy( luxel, color );
3323 /* set minimum light */
3324 if ( lightmapNum == 0 ) {
3325 for ( k = 0; k < 3; k++ )
3326 if ( color[ k ] < minVertexLight[ k ] ) {
3327 color[ k ] = minVertexLight[ k ];
3332 /* store to bytes */
3333 if ( !info->si->noVertexLight ) {
3334 ColorToBytes( color, dv[ j ].color[ lightmapNum ], info->si->vertexScale );
3339 /* surfaces with styled lightmaps and a style marker get a custom generated shader (fixme: make this work with external lightmaps) */
3340 if ( olm != NULL && lm != NULL && lm->styles[ 1 ] != LS_NONE && game->load != LoadRBSPFile ) { //% info->si->styleMarker > 0 )
3342 char key[ 32 ], styleStage[ 512 ], styleStages[ 4096 ], rgbGen[ 128 ], alphaGen[ 128 ];
3346 sprintf( styleStages, "\n\t// Q3Map2 custom lightstyle stage(s)\n" );
3347 dv = &bspDrawVerts[ ds->firstVert ];
3349 /* depthFunc equal? */
3350 if ( info->si->styleMarker == 2 || info->si->implicitMap == IM_MASKED ) {
3357 /* generate stages for styled lightmaps */
3358 for ( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3361 style = lm->styles[ lightmapNum ];
3362 if ( style == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 ) {
3366 /* get output lightmap */
3367 olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
3370 if ( lm->outLightmapNums[ lightmapNum ] == lm->outLightmapNums[ 0 ] ) {
3371 strcpy( lightmapName, "$lightmap" );
3374 sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
3377 /* get rgbgen string */
3378 if ( rgbGenValues[ style ] == NULL ) {
3379 sprintf( key, "_style%drgbgen", style );
3380 rgbGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
3381 if ( rgbGenValues[ style ][ 0 ] == '\0' ) {
3382 rgbGenValues[ style ] = "wave noise 0.5 1 0 5.37";
3386 if ( rgbGenValues[ style ][ 0 ] != '\0' ) {
3387 sprintf( rgbGen, "\t\trgbGen %s // style %d\n", rgbGenValues[ style ], style );
3393 /* get alphagen string */
3394 if ( alphaGenValues[ style ] == NULL ) {
3395 sprintf( key, "_style%dalphagen", style );
3396 alphaGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
3398 if ( alphaGenValues[ style ][ 0 ] != '\0' ) {
3399 sprintf( alphaGen, "\t\talphaGen %s // style %d\n", alphaGenValues[ style ], style );
3402 alphaGen[ 0 ] = '\0';
3405 /* calculate st offset */
3406 lmx = dv[ 0 ].lightmap[ lightmapNum ][ 0 ] - dv[ 0 ].lightmap[ 0 ][ 0 ];
3407 lmy = dv[ 0 ].lightmap[ lightmapNum ][ 1 ] - dv[ 0 ].lightmap[ 0 ][ 1 ];
3409 /* create additional stage */
3410 if ( lmx == 0.0f && lmy == 0.0f ) {
3411 sprintf( styleStage, "\t{\n"
3412 "\t\tmap %s\n" /* lightmap */
3413 "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
3414 "%s" /* depthFunc equal */
3417 "\t\ttcGen lightmap\n"
3420 ( dfEqual ? "\t\tdepthFunc equal\n" : "" ),
3426 sprintf( styleStage, "\t{\n"
3427 "\t\tmap %s\n" /* lightmap */
3428 "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
3429 "%s" /* depthFunc equal */
3432 "\t\ttcGen lightmap\n"
3433 "\t\ttcMod transform 1 0 0 1 %1.5f %1.5f\n" /* st offset */
3436 ( dfEqual ? "\t\tdepthFunc equal\n" : "" ),
3444 strcat( styleStages, styleStage );
3447 /* create custom shader */
3448 if ( info->si->styleMarker == 2 ) {
3449 csi = CustomShader( info->si, "q3map_styleMarker2", styleStages );
3452 csi = CustomShader( info->si, "q3map_styleMarker", styleStages );
3455 /* emit remap command */
3456 //% EmitVertexRemapShader( csi->shader, info->si->shader );
3459 //% Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
3460 ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3461 //% Sys_Printf( ")\n" );
3464 /* devise a custom shader for this surface (fixme: make this work with light styles) */
3465 else if ( olm != NULL && lm != NULL && !externalLightmaps &&
3466 ( olm->customWidth != game->lightmapSize || olm->customHeight != game->lightmapSize ) ) {
3467 /* get output lightmap */
3468 olm = &outLightmaps[ lm->outLightmapNums[ 0 ] ];
3470 /* do some name mangling */
3471 sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
3473 /* create custom shader */
3474 csi = CustomShader( info->si, "$lightmap", lightmapName );
3477 //% Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
3478 ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3479 //% Sys_Printf( ")\n" );
3482 /* use the normal plain-jane shader */
3484 ds->shaderNum = EmitShader( info->si->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3489 Sys_Printf( "done.\n" );
3491 /* calc num stored */
3492 numStored = numBSPLightBytes / 3;
3493 efficiency = ( numStored <= 0 )
3495 : (float) numUsed / (float) numStored;
3498 Sys_Printf( "%9d luxels used\n", numUsed );
3499 Sys_Printf( "%9d luxels stored (%3.2f percent efficiency)\n", numStored, efficiency * 100.0f );
3500 Sys_Printf( "%9d solid surface lightmaps\n", numSolidLightmaps );
3501 Sys_Printf( "%9d identical surface lightmaps, using %d luxels\n", numTwins, numTwinLuxels );
3502 Sys_Printf( "%9d vertex forced surfaces\n", numSurfsVertexForced );
3503 Sys_Printf( "%9d vertex approximated surfaces\n", numSurfsVertexApproximated );
3504 Sys_Printf( "%9d BSP lightmaps\n", numBSPLightmaps );
3505 Sys_Printf( "%9d total lightmaps\n", numOutLightmaps );
3506 Sys_Printf( "%9d unique lightmap/shader combinations\n", numLightmapShaders );
3508 /* write map shader file */
3509 WriteMapShaderFile();