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, qboolean fastAllocate ){
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;
2009 int xIncrement, yIncrement;
2012 /* set default lightmap number (-3 = LIGHTMAP_BY_VERTEX) */
2013 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2014 lm->outLightmapNums[ lightmapNum ] = -3;
2016 /* can this lightmap be approximated with vertex color? */
2017 if ( ApproximateLightmap( lm ) ) {
2022 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2025 if ( lm->styles[ lightmapNum ] == LS_NONE ) {
2029 /* don't store twinned lightmaps */
2030 if ( lm->twins[ lightmapNum ] != NULL ) {
2034 /* if this is a styled lightmap, try some normalized locations first */
2036 if ( lightmapNum > 0 && outLightmaps != NULL ) {
2038 for ( j = 0; j < 2; j++ )
2040 /* try identical position */
2041 for ( i = 0; i < numOutLightmaps; i++ )
2043 /* get the output lightmap */
2044 olm = &outLightmaps[ i ];
2046 /* simple early out test */
2047 if ( olm->freeLuxels < lm->used ) {
2051 /* don't store non-custom raw lightmaps on custom bsp lightmaps */
2052 if ( olm->customWidth != lm->customWidth ||
2053 olm->customHeight != lm->customHeight ) {
2059 x = lm->lightmapX[ 0 ];
2060 y = lm->lightmapY[ 0 ];
2061 ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );
2067 for ( sy = -1; sy <= 1; sy++ )
2069 for ( sx = -1; sx <= 1; sx++ )
2071 x = lm->lightmapX[ 0 ] + sx * ( olm->customWidth >> 1 ); //% lm->w;
2072 y = lm->lightmapY[ 0 ] + sy * ( olm->customHeight >> 1 ); //% lm->h;
2073 ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );
2097 /* try normal placement algorithm */
2098 if ( ok == qfalse ) {
2103 /* walk the list of lightmap pages */
2104 if ( lightmapSearchBlockSize <= 0 || numOutLightmaps < LIGHTMAP_RESERVE_COUNT ) {
2108 i = ( ( numOutLightmaps - LIGHTMAP_RESERVE_COUNT ) / lightmapSearchBlockSize ) * lightmapSearchBlockSize;
2110 for ( ; i < numOutLightmaps; i++ )
2112 /* get the output lightmap */
2113 olm = &outLightmaps[ i ];
2115 /* simple early out test */
2116 if ( olm->freeLuxels < lm->used ) {
2120 /* if fast allocation, skip lightmap files that are more than 90% complete */
2121 if ( fastAllocate == qtrue ) {
2122 if (olm->freeLuxels < (olm->customWidth * olm->customHeight) / 10) {
2127 /* don't store non-custom raw lightmaps on custom bsp lightmaps */
2128 if ( olm->customWidth != lm->customWidth ||
2129 olm->customHeight != lm->customHeight ) {
2134 if ( lm->solid[ lightmapNum ] ) {
2135 xMax = olm->customWidth;
2136 yMax = olm->customHeight;
2140 xMax = ( olm->customWidth - lm->w ) + 1;
2141 yMax = ( olm->customHeight - lm->h ) + 1;
2144 /* if fast allocation, do not test allocation on every pixels, especially for large lightmaps */
2145 if ( fastAllocate == qtrue ) {
2146 xIncrement = MAX(1, lm->w / 15);
2147 yIncrement = MAX(1, lm->h / 15);
2154 /* walk the origin around the lightmap */
2155 for ( y = 0; y < yMax; y += yIncrement )
2157 for ( x = 0; x < xMax; x += xIncrement )
2159 /* find a fine tract of lauhnd */
2160 ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );
2183 if ( ok == qfalse ) {
2184 /* allocate LIGHTMAP_RESERVE_COUNT new output lightmaps */
2185 numOutLightmaps += LIGHTMAP_RESERVE_COUNT;
2186 olm = safe_malloc( numOutLightmaps * sizeof( outLightmap_t ) );
2188 Error( "FindOutLightmaps: Failed to allocate memory.\n" );
2191 if ( outLightmaps != NULL && numOutLightmaps > LIGHTMAP_RESERVE_COUNT ) {
2192 memcpy( olm, outLightmaps, ( numOutLightmaps - LIGHTMAP_RESERVE_COUNT ) * sizeof( outLightmap_t ) );
2193 free( outLightmaps );
2197 /* initialize both out lightmaps */
2198 for ( k = numOutLightmaps - LIGHTMAP_RESERVE_COUNT; k < numOutLightmaps; ++k )
2199 SetupOutLightmap( lm, &outLightmaps[ k ] );
2201 /* set out lightmap */
2202 i = numOutLightmaps - LIGHTMAP_RESERVE_COUNT;
2203 olm = &outLightmaps[ i ];
2205 /* set stamp xy origin to the first surface lightmap */
2206 if ( lightmapNum > 0 ) {
2207 x = lm->lightmapX[ 0 ];
2208 y = lm->lightmapY[ 0 ];
2212 /* if this is a style-using lightmap, it must be exported */
2213 if ( lightmapNum > 0 && game->load != LoadRBSPFile ) {
2214 olm->extLightmapNum = 0;
2217 /* add the surface lightmap to the bsp lightmap */
2218 lm->outLightmapNums[ lightmapNum ] = i;
2219 lm->lightmapX[ lightmapNum ] = x;
2220 lm->lightmapY[ lightmapNum ] = y;
2221 olm->numLightmaps++;
2224 for ( i = 0; i < lm->numLightSurfaces; i++ )
2226 /* get surface info */
2227 info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + i ] ];
2229 /* test for shader */
2230 for ( j = 0; j < olm->numShaders; j++ )
2232 if ( olm->shaders[ j ] == info->si ) {
2237 /* if it doesn't exist, add it */
2238 if ( j >= olm->numShaders && olm->numShaders < MAX_LIGHTMAP_SHADERS ) {
2239 olm->shaders[ olm->numShaders ] = info->si;
2241 numLightmapShaders++;
2246 if ( lm->solid[ lightmapNum ] ) {
2256 /* mark the bits used */
2257 for ( y = 0; y < yMax; y++ )
2259 for ( x = 0; x < xMax; x++ )
2262 luxel = BSP_LUXEL( lightmapNum, x, y );
2263 deluxel = BSP_DELUXEL( x, y );
2264 if ( luxel[ 0 ] < 0.0f && !lm->solid[ lightmapNum ] ) {
2268 /* set minimum light */
2269 if ( lm->solid[ lightmapNum ] ) {
2271 VectorSet( color, 255.0f, 0.0f, 0.0f );
2274 VectorCopy( lm->solidColor[ lightmapNum ], color );
2278 VectorCopy( luxel, color );
2281 /* styles are not affected by minlight */
2282 if ( lightmapNum == 0 ) {
2283 for ( i = 0; i < 3; i++ )
2285 if ( color[ i ] < minLight[ i ] ) {
2286 color[ i ] = minLight[ i ];
2291 /* get bsp lightmap coords */
2292 ox = x + lm->lightmapX[ lightmapNum ];
2293 oy = y + lm->lightmapY[ lightmapNum ];
2294 offset = ( oy * olm->customWidth ) + ox;
2296 /* flag pixel as used */
2297 olm->lightBits[ offset >> 3 ] |= ( 1 << ( offset & 7 ) );
2301 pixel = olm->bspLightBytes + ( ( ( oy * olm->customWidth ) + ox ) * 3 );
2302 ColorToBytes( color, pixel, lm->brightness );
2304 /* store direction */
2306 /* normalize average light direction */
2307 pixel = olm->bspDirBytes + ( ( ( oy * olm->customWidth ) + ox ) * 3 );
2308 VectorScale( deluxel, 1000.0f, direction );
2309 VectorNormalize( direction, direction );
2310 VectorScale( direction, 127.5f, direction );
2311 for ( i = 0; i < 3; i++ )
2312 pixel[ i ] = (byte)( 127.5f + direction[ i ] );
2322 CompareRawLightmap()
2323 compare function for qsort()
2326 static int CompareRawLightmap( const void *a, const void *b ){
2327 rawLightmap_t *alm, *blm;
2328 surfaceInfo_t *aInfo, *bInfo;
2333 alm = &rawLightmaps[ *( (const int*) a ) ];
2334 blm = &rawLightmaps[ *( (const int*) b ) ];
2336 /* get min number of surfaces */
2337 min = ( alm->numLightSurfaces < blm->numLightSurfaces ? alm->numLightSurfaces : blm->numLightSurfaces );
2339 //#define allocate_bigger_first
2340 #ifdef allocate_bigger_first
2341 /* compare size, allocate bigger first */
2342 // fastAllocate commit part: can kick fps by unique lightmap/shader combinations*=~2 + bigger compile time
2343 //return -diff; makes packing faster and rough
2344 diff = ( blm->w * blm->h ) - ( alm->w * alm->h );
2350 for ( i = 0; i < min; i++ )
2352 /* get surface info */
2353 aInfo = &surfaceInfos[ lightSurfaces[ alm->firstLightSurface + i ] ];
2354 bInfo = &surfaceInfos[ lightSurfaces[ blm->firstLightSurface + i ] ];
2356 /* compare shader names */
2357 diff = strcmp( aInfo->si->shader, bInfo->si->shader );
2363 /* test style count */
2365 for ( i = 0; i < MAX_LIGHTMAPS; i++ )
2366 diff += blm->styles[ i ] - alm->styles[ i ];
2370 #ifndef allocate_bigger_first
2372 diff = ( blm->w * blm->h ) - ( alm->w * alm->h );
2377 /* must be equivalent */
2381 void FillOutLightmap( outLightmap_t *olm ){
2384 vec3_t dir_sum, light_sum;
2386 byte *lightBitsNew = NULL;
2387 byte *lightBytesNew = NULL;
2388 byte *dirBytesNew = NULL;
2390 lightBitsNew = safe_malloc( ( olm->customWidth * olm->customHeight + 8 ) / 8 );
2391 lightBytesNew = safe_malloc( olm->customWidth * olm->customHeight * 3 );
2393 dirBytesNew = safe_malloc( olm->customWidth * olm->customHeight * 3 );
2397 memset(olm->lightBits, 0, (olm->customWidth * olm->customHeight + 8) / 8);
2398 olm->lightBits[0] |= 1;
2399 olm->lightBits[(10 * olm->customWidth + 30) >> 3] |= 1 << ((10 * olm->customWidth + 30) & 7);
2400 memset(olm->bspLightBytes, 0, olm->customWidth * olm->customHeight * 3);
2401 olm->bspLightBytes[0] = 255;
2402 olm->bspLightBytes[(10 * olm->customWidth + 30) * 3 + 2] = 255;
2405 memcpy( lightBitsNew, olm->lightBits, ( olm->customWidth * olm->customHeight + 8 ) / 8 );
2406 memcpy( lightBytesNew, olm->bspLightBytes, olm->customWidth * olm->customHeight * 3 );
2408 memcpy( dirBytesNew, olm->bspDirBytes, olm->customWidth * olm->customHeight * 3 );
2414 for ( y = 0; y < olm->customHeight; ++y )
2416 for ( x = 0; x < olm->customWidth; ++x )
2418 ofs = y * olm->customWidth + x;
2419 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2423 VectorClear( dir_sum );
2424 VectorClear( light_sum );
2426 /* try all four neighbors */
2427 ofs = ( ( y + olm->customHeight - 1 ) % olm->customHeight ) * olm->customWidth + x;
2428 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2430 VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2432 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2436 ofs = ( ( y + 1 ) % olm->customHeight ) * olm->customWidth + x;
2437 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2439 VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2441 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2445 ofs = y * olm->customWidth + ( x + olm->customWidth - 1 ) % olm->customWidth;
2446 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2448 VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2450 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2454 ofs = y * olm->customWidth + ( x + 1 ) % olm->customWidth;
2455 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2457 VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2459 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2465 ofs = y * olm->customWidth + x;
2466 lightBitsNew[ofs >> 3] |= ( 1 << ( ofs & 7 ) );
2467 VectorScale( light_sum, 1.0 / cnt, lightBytesNew + ofs * 3 );
2469 VectorScale( dir_sum, 1.0 / cnt, dirBytesNew + ofs * 3 );
2479 memcpy( olm->lightBits, lightBitsNew, ( olm->customWidth * olm->customHeight + 8 ) / 8 );
2480 memcpy( olm->bspLightBytes, lightBytesNew, olm->customWidth * olm->customHeight * 3 );
2482 memcpy( olm->bspDirBytes, dirBytesNew, olm->customWidth * olm->customHeight * 3 );
2486 free( lightBitsNew );
2487 free( lightBytesNew );
2489 free( dirBytesNew );
2494 StoreSurfaceLightmaps()
2495 stores the surface lightmaps into the bsp as byte rgb triplets
2498 void StoreSurfaceLightmaps( qboolean fastAllocate ){
2499 int i, j, k, x, y, lx, ly, sx, sy, *cluster, mappedSamples, timer_start;
2500 int style, size, lightmapNum, lightmapNum2;
2501 float *normal, *luxel, *bspLuxel, *bspLuxel2, *radLuxel, samples, occludedSamples;
2502 vec3_t sample, occludedSample, dirSample, colorMins, colorMaxs;
2503 float *deluxel, *bspDeluxel, *bspDeluxel2;
2505 int numUsed, numTwins, numTwinLuxels, numStored;
2506 float lmx, lmy, efficiency;
2508 bspDrawSurface_t *ds, *parent, dsTemp;
2509 surfaceInfo_t *info;
2510 rawLightmap_t *lm, *lm2;
2512 bspDrawVert_t *dv, *ydv, *dvParent;
2513 char dirname[ 1024 ], filename[ 1024 ];
2515 char lightmapName[ 128 ];
2516 const char *rgbGenValues[ 256 ];
2517 const char *alphaGenValues[ 256 ];
2521 Sys_Printf( "--- StoreSurfaceLightmaps ---\n" );
2524 if ( lmCustomDir ) {
2525 strcpy( dirname, lmCustomDir );
2529 strcpy( dirname, source );
2530 StripExtension( dirname );
2532 memset( rgbGenValues, 0, sizeof( rgbGenValues ) );
2533 memset( alphaGenValues, 0, sizeof( alphaGenValues ) );
2535 /* -----------------------------------------------------------------
2536 average the sampled luxels into the bsp luxels
2537 ----------------------------------------------------------------- */
2540 Sys_Printf( "Subsampling..." );
2542 timer_start = I_FloatTime();
2544 /* walk the list of raw lightmaps */
2548 numSolidLightmaps = 0;
2549 for ( i = 0; i < numRawLightmaps; i++ )
2552 lm = &rawLightmaps[ i ];
2554 /* walk individual lightmaps */
2555 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2558 if ( lm->superLuxels[ lightmapNum ] == NULL ) {
2562 /* allocate bsp luxel storage */
2563 if ( lm->bspLuxels[ lightmapNum ] == NULL ) {
2564 size = lm->w * lm->h * BSP_LUXEL_SIZE * sizeof( float );
2565 lm->bspLuxels[ lightmapNum ] = safe_malloc( size );
2566 memset( lm->bspLuxels[ lightmapNum ], 0, size );
2569 /* allocate radiosity lightmap storage */
2571 size = lm->w * lm->h * RAD_LUXEL_SIZE * sizeof( float );
2572 if ( lm->radLuxels[ lightmapNum ] == NULL ) {
2573 lm->radLuxels[ lightmapNum ] = safe_malloc( size );
2575 memset( lm->radLuxels[ lightmapNum ], 0, size );
2578 /* average supersampled luxels */
2579 for ( y = 0; y < lm->h; y++ )
2581 for ( x = 0; x < lm->w; x++ )
2585 occludedSamples = 0.0f;
2587 VectorClear( sample );
2588 VectorClear( occludedSample );
2589 VectorClear( dirSample );
2590 for ( ly = 0; ly < superSample; ly++ )
2592 for ( lx = 0; lx < superSample; lx++ )
2595 sx = x * superSample + lx;
2596 sy = y * superSample + ly;
2597 luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2598 deluxel = SUPER_DELUXEL( sx, sy );
2599 normal = SUPER_NORMAL( sx, sy );
2600 cluster = SUPER_CLUSTER( sx, sy );
2602 /* sample deluxemap */
2603 if ( deluxemap && lightmapNum == 0 ) {
2604 VectorAdd( dirSample, deluxel, dirSample );
2607 /* keep track of used/occluded samples */
2608 if ( *cluster != CLUSTER_UNMAPPED ) {
2612 /* handle lightmap border? */
2613 if ( lightmapBorder && ( sx == 0 || sx == ( lm->sw - 1 ) || sy == 0 || sy == ( lm->sh - 1 ) ) && luxel[ 3 ] > 0.0f ) {
2614 VectorSet( sample, 255.0f, 0.0f, 0.0f );
2619 else if ( debug && *cluster < 0 ) {
2620 if ( *cluster == CLUSTER_UNMAPPED ) {
2621 VectorSet( luxel, 255, 204, 0 );
2623 else if ( *cluster == CLUSTER_OCCLUDED ) {
2624 VectorSet( luxel, 255, 0, 255 );
2626 else if ( *cluster == CLUSTER_FLOODED ) {
2627 VectorSet( luxel, 0, 32, 255 );
2629 VectorAdd( occludedSample, luxel, occludedSample );
2630 occludedSamples += 1.0f;
2633 /* normal luxel handling */
2634 else if ( luxel[ 3 ] > 0.0f ) {
2635 /* handle lit or flooded luxels */
2636 if ( *cluster > 0 || *cluster == CLUSTER_FLOODED ) {
2637 VectorAdd( sample, luxel, sample );
2638 samples += luxel[ 3 ];
2641 /* handle occluded or unmapped luxels */
2644 VectorAdd( occludedSample, luxel, occludedSample );
2645 occludedSamples += luxel[ 3 ];
2648 /* handle style debugging */
2649 if ( debug && lightmapNum > 0 && x < 2 && y < 2 ) {
2650 VectorCopy( debugColors[ 0 ], sample );
2657 /* only use occluded samples if necessary */
2658 if ( samples <= 0.0f ) {
2659 VectorCopy( occludedSample, sample );
2660 samples = occludedSamples;
2664 luxel = SUPER_LUXEL( lightmapNum, x, y );
2665 deluxel = SUPER_DELUXEL( x, y );
2667 /* store light direction */
2668 if ( deluxemap && lightmapNum == 0 ) {
2669 VectorCopy( dirSample, deluxel );
2672 /* store the sample back in super luxels */
2673 if ( samples > 0.01f ) {
2674 VectorScale( sample, ( 1.0f / samples ), luxel );
2678 /* if any samples were mapped in any way, store ambient color */
2679 else if ( mappedSamples > 0 ) {
2680 if ( lightmapNum == 0 ) {
2681 VectorCopy( ambientColor, luxel );
2684 VectorClear( luxel );
2689 /* store a bogus value to be fixed later */
2692 VectorClear( luxel );
2700 ClearBounds( colorMins, colorMaxs );
2702 /* clean up and store into bsp luxels */
2703 for ( y = 0; y < lm->h; y++ )
2705 for ( x = 0; x < lm->w; x++ )
2708 luxel = SUPER_LUXEL( lightmapNum, x, y );
2709 deluxel = SUPER_DELUXEL( x, y );
2711 /* copy light direction */
2712 if ( deluxemap && lightmapNum == 0 ) {
2713 VectorCopy( deluxel, dirSample );
2716 /* is this a valid sample? */
2717 if ( luxel[ 3 ] > 0.0f ) {
2718 VectorCopy( luxel, sample );
2719 samples = luxel[ 3 ];
2723 /* fix negative samples */
2724 for ( j = 0; j < 3; j++ )
2726 if ( sample[ j ] < 0.0f ) {
2733 /* nick an average value from the neighbors */
2734 VectorClear( sample );
2735 VectorClear( dirSample );
2738 /* fixme: why is this disabled?? */
2739 for ( sy = ( y - 1 ); sy <= ( y + 1 ); sy++ )
2741 if ( sy < 0 || sy >= lm->h ) {
2745 for ( sx = ( x - 1 ); sx <= ( x + 1 ); sx++ )
2747 if ( sx < 0 || sx >= lm->w || ( sx == x && sy == y ) ) {
2751 /* get neighbor's particulars */
2752 luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2753 if ( luxel[ 3 ] < 0.0f ) {
2756 VectorAdd( sample, luxel, sample );
2757 samples += luxel[ 3 ];
2762 if ( samples == 0.0f ) {
2763 VectorSet( sample, -1.0f, -1.0f, -1.0f );
2771 /* fix negative samples */
2772 for ( j = 0; j < 3; j++ )
2774 if ( sample[ j ] < 0.0f ) {
2781 /* scale the sample */
2782 VectorScale( sample, ( 1.0f / samples ), sample );
2784 /* store the sample in the radiosity luxels */
2786 radLuxel = RAD_LUXEL( lightmapNum, x, y );
2787 VectorCopy( sample, radLuxel );
2789 /* if only storing bounced light, early out here */
2790 if ( bounceOnly && !bouncing ) {
2795 /* store the sample in the bsp luxels */
2796 bspLuxel = BSP_LUXEL( lightmapNum, x, y );
2797 bspDeluxel = BSP_DELUXEL( x, y );
2799 VectorAdd( bspLuxel, sample, bspLuxel );
2800 if ( deluxemap && lightmapNum == 0 ) {
2801 VectorAdd( bspDeluxel, dirSample, bspDeluxel );
2804 /* add color to bounds for solid checking */
2805 if ( samples > 0.0f ) {
2806 AddPointToBounds( bspLuxel, colorMins, colorMaxs );
2811 /* set solid color */
2812 lm->solid[ lightmapNum ] = qfalse;
2813 VectorAdd( colorMins, colorMaxs, lm->solidColor[ lightmapNum ] );
2814 VectorScale( lm->solidColor[ lightmapNum ], 0.5f, lm->solidColor[ lightmapNum ] );
2816 /* nocollapse prevents solid lightmaps */
2817 if ( noCollapse == qfalse ) {
2818 /* check solid color */
2819 VectorSubtract( colorMaxs, colorMins, sample );
2820 if ( ( sample[ 0 ] <= SOLID_EPSILON && sample[ 1 ] <= SOLID_EPSILON && sample[ 2 ] <= SOLID_EPSILON ) ||
2821 ( lm->w <= 2 && lm->h <= 2 ) ) { /* small lightmaps get forced to solid color */
2823 VectorCopy( colorMins, lm->solidColor[ lightmapNum ] );
2824 lm->solid[ lightmapNum ] = qtrue;
2825 numSolidLightmaps++;
2828 /* if all lightmaps aren't solid, then none of them are solid */
2829 if ( lm->solid[ lightmapNum ] != lm->solid[ 0 ] ) {
2830 for ( y = 0; y < MAX_LIGHTMAPS; y++ )
2832 if ( lm->solid[ y ] ) {
2833 numSolidLightmaps--;
2835 lm->solid[ y ] = qfalse;
2840 /* wrap bsp luxels if necessary */
2841 if ( lm->wrap[ 0 ] ) {
2842 for ( y = 0; y < lm->h; y++ )
2844 bspLuxel = BSP_LUXEL( lightmapNum, 0, y );
2845 bspLuxel2 = BSP_LUXEL( lightmapNum, lm->w - 1, y );
2846 VectorAdd( bspLuxel, bspLuxel2, bspLuxel );
2847 VectorScale( bspLuxel, 0.5f, bspLuxel );
2848 VectorCopy( bspLuxel, bspLuxel2 );
2849 if ( deluxemap && lightmapNum == 0 ) {
2850 bspDeluxel = BSP_DELUXEL( 0, y );
2851 bspDeluxel2 = BSP_DELUXEL( lm->w - 1, y );
2852 VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel );
2853 VectorScale( bspDeluxel, 0.5f, bspDeluxel );
2854 VectorCopy( bspDeluxel, bspDeluxel2 );
2858 if ( lm->wrap[ 1 ] ) {
2859 for ( x = 0; x < lm->w; x++ )
2861 bspLuxel = BSP_LUXEL( lightmapNum, x, 0 );
2862 bspLuxel2 = BSP_LUXEL( lightmapNum, x, lm->h - 1 );
2863 VectorAdd( bspLuxel, bspLuxel2, bspLuxel );
2864 VectorScale( bspLuxel, 0.5f, bspLuxel );
2865 VectorCopy( bspLuxel, bspLuxel2 );
2866 if ( deluxemap && lightmapNum == 0 ) {
2867 bspDeluxel = BSP_DELUXEL( x, 0 );
2868 bspDeluxel2 = BSP_DELUXEL( x, lm->h - 1 );
2869 VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel );
2870 VectorScale( bspDeluxel, 0.5f, bspDeluxel );
2871 VectorCopy( bspDeluxel, bspDeluxel2 );
2878 Sys_Printf( "%d.", (int) ( I_FloatTime() - timer_start ) );
2880 /* -----------------------------------------------------------------
2881 convert modelspace deluxemaps to tangentspace
2882 ----------------------------------------------------------------- */
2885 if ( deluxemap && deluxemode == 1 ) {
2886 vec3_t worldUp, myNormal, myTangent, myBinormal;
2889 timer_start = I_FloatTime();
2891 Sys_Printf( "converting..." );
2893 for ( i = 0; i < numRawLightmaps; i++ )
2896 lm = &rawLightmaps[ i ];
2898 /* walk lightmap samples */
2899 for ( y = 0; y < lm->sh; y++ )
2901 for ( x = 0; x < lm->sw; x++ )
2903 /* get normal and deluxel */
2904 normal = SUPER_NORMAL( x, y );
2905 cluster = SUPER_CLUSTER( x, y );
2906 bspDeluxel = BSP_DELUXEL( x, y );
2907 deluxel = SUPER_DELUXEL( x, y );
2910 VectorSet( myNormal, normal[0], normal[1], normal[2] );
2912 /* get tangent vectors */
2913 if ( myNormal[ 0 ] == 0.0f && myNormal[ 1 ] == 0.0f ) {
2914 if ( myNormal[ 2 ] == 1.0f ) {
2915 VectorSet( myTangent, 1.0f, 0.0f, 0.0f );
2916 VectorSet( myBinormal, 0.0f, 1.0f, 0.0f );
2918 else if ( myNormal[ 2 ] == -1.0f ) {
2919 VectorSet( myTangent, -1.0f, 0.0f, 0.0f );
2920 VectorSet( myBinormal, 0.0f, 1.0f, 0.0f );
2925 VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
2926 CrossProduct( myNormal, worldUp, myTangent );
2927 VectorNormalize( myTangent, myTangent );
2928 CrossProduct( myTangent, myNormal, myBinormal );
2929 VectorNormalize( myBinormal, myBinormal );
2932 /* project onto plane */
2933 dist = -DotProduct( myTangent, myNormal );
2934 VectorMA( myTangent, dist, myNormal, myTangent );
2935 dist = -DotProduct( myBinormal, myNormal );
2936 VectorMA( myBinormal, dist, myNormal, myBinormal );
2939 VectorNormalize( myTangent, myTangent );
2940 VectorNormalize( myBinormal, myBinormal );
2942 /* convert modelspace deluxel to tangentspace */
2943 dirSample[0] = bspDeluxel[0];
2944 dirSample[1] = bspDeluxel[1];
2945 dirSample[2] = bspDeluxel[2];
2946 VectorNormalize( dirSample, dirSample );
2948 /* fix tangents to world matrix */
2949 if ( myNormal[0] > 0 || myNormal[1] < 0 || myNormal[2] < 0 ) {
2950 VectorNegate( myTangent, myTangent );
2953 /* build tangentspace vectors */
2954 bspDeluxel[0] = DotProduct( dirSample, myTangent );
2955 bspDeluxel[1] = DotProduct( dirSample, myBinormal );
2956 bspDeluxel[2] = DotProduct( dirSample, myNormal );
2961 Sys_Printf( "%d.", (int) ( I_FloatTime() - timer_start ) );
2965 /* -----------------------------------------------------------------
2967 ----------------------------------------------------------------- */
2969 #ifdef sdfsdfwq312323
2971 Sys_Printf( "blending..." );
2973 for ( i = 0; i < numRawLightmaps; i++ )
2979 lm = &rawLightmaps[ i ];
2981 /* walk individual lightmaps */
2982 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2985 if ( lm->superLuxels[ lightmapNum ] == NULL ) {
2989 /* walk lightmap samples */
2990 for ( y = 0; y < lm->sh; y++ )
2992 for ( x = 0; x < lm->sw; x++ )
2995 bspLuxel = BSP_LUXEL( lightmapNum, x, y );
2998 VectorNormalize( bspLuxel, myColor );
2999 myBrightness = VectorLength( bspLuxel );
3000 myBrightness *= ( 1 / 127.0f );
3001 myBrightness = myBrightness * myBrightness;
3002 myBrightness *= 127.0f;
3003 VectorScale( myColor, myBrightness, bspLuxel );
3010 /* -----------------------------------------------------------------
3011 collapse non-unique lightmaps
3012 ----------------------------------------------------------------- */
3014 if ( noCollapse == qfalse && deluxemap == qfalse ) {
3016 Sys_Printf( "collapsing..." );
3018 timer_start = I_FloatTime();
3020 /* set all twin refs to null */
3021 for ( i = 0; i < numRawLightmaps; i++ )
3023 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3025 rawLightmaps[ i ].twins[ lightmapNum ] = NULL;
3026 rawLightmaps[ i ].twinNums[ lightmapNum ] = -1;
3027 rawLightmaps[ i ].numStyledTwins = 0;
3031 /* walk the list of raw lightmaps */
3032 for ( i = 0; i < numRawLightmaps; i++ )
3035 lm = &rawLightmaps[ i ];
3037 /* walk lightmaps */
3038 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3041 if ( lm->bspLuxels[ lightmapNum ] == NULL ||
3042 lm->twins[ lightmapNum ] != NULL ) {
3046 /* find all lightmaps that are virtually identical to this one */
3047 for ( j = i + 1; j < numRawLightmaps; j++ )
3050 lm2 = &rawLightmaps[ j ];
3052 /* walk lightmaps */
3053 for ( lightmapNum2 = 0; lightmapNum2 < MAX_LIGHTMAPS; lightmapNum2++ )
3056 if ( lm2->bspLuxels[ lightmapNum2 ] == NULL ||
3057 lm2->twins[ lightmapNum2 ] != NULL ) {
3062 if ( CompareBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ) ) {
3063 /* merge and set twin */
3064 if ( MergeBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ) ) {
3065 lm2->twins[ lightmapNum2 ] = lm;
3066 lm2->twinNums[ lightmapNum2 ] = lightmapNum;
3068 numTwinLuxels += ( lm->w * lm->h );
3070 /* count styled twins */
3071 if ( lightmapNum > 0 ) {
3072 lm->numStyledTwins++;
3081 Sys_Printf( "%d.", (int) ( I_FloatTime() - timer_start ) );
3084 /* -----------------------------------------------------------------
3085 sort raw lightmaps by shader
3086 ----------------------------------------------------------------- */
3089 Sys_Printf( "sorting..." );
3091 timer_start = I_FloatTime();
3093 /* allocate a new sorted list */
3094 if ( sortLightmaps == NULL ) {
3095 sortLightmaps = safe_malloc( numRawLightmaps * sizeof( int ) );
3098 /* fill it out and sort it */
3099 for ( i = 0; i < numRawLightmaps; i++ )
3100 sortLightmaps[ i ] = i;
3101 qsort( sortLightmaps, numRawLightmaps, sizeof( int ), CompareRawLightmap );
3103 Sys_Printf( "%d.", (int) ( I_FloatTime() - timer_start ) );
3105 /* -----------------------------------------------------------------
3106 allocate output lightmaps
3107 ----------------------------------------------------------------- */
3110 Sys_Printf( "allocating..." );
3112 timer_start = I_FloatTime();
3114 /* kill all existing output lightmaps */
3115 if ( outLightmaps != NULL ) {
3116 for ( i = 0; i < numOutLightmaps; i++ )
3118 free( outLightmaps[ i ].lightBits );
3119 free( outLightmaps[ i ].bspLightBytes );
3121 free( outLightmaps );
3122 outLightmaps = NULL;
3125 numLightmapShaders = 0;
3126 numOutLightmaps = 0;
3127 numBSPLightmaps = 0;
3128 numExtLightmaps = 0;
3130 /* find output lightmap */
3131 for ( i = 0; i < numRawLightmaps; i++ )
3133 lm = &rawLightmaps[ sortLightmaps[ i ] ];
3134 FindOutLightmaps( lm, fastAllocate );
3137 /* set output numbers in twinned lightmaps */
3138 for ( i = 0; i < numRawLightmaps; i++ )
3141 lm = &rawLightmaps[ sortLightmaps[ i ] ];
3143 /* walk lightmaps */
3144 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3147 lm2 = lm->twins[ lightmapNum ];
3148 if ( lm2 == NULL ) {
3151 lightmapNum2 = lm->twinNums[ lightmapNum ];
3153 /* find output lightmap from twin */
3154 lm->outLightmapNums[ lightmapNum ] = lm2->outLightmapNums[ lightmapNum2 ];
3155 lm->lightmapX[ lightmapNum ] = lm2->lightmapX[ lightmapNum2 ];
3156 lm->lightmapY[ lightmapNum ] = lm2->lightmapY[ lightmapNum2 ];
3160 Sys_Printf( "%d.", (int) ( I_FloatTime() - timer_start ) );
3162 /* -----------------------------------------------------------------
3163 store output lightmaps
3164 ----------------------------------------------------------------- */
3167 Sys_Printf( "storing..." );
3169 timer_start = I_FloatTime();
3171 /* count the bsp lightmaps and allocate space */
3172 if ( bspLightBytes != NULL ) {
3173 free( bspLightBytes );
3175 if ( numBSPLightmaps == 0 || externalLightmaps ) {
3176 numBSPLightBytes = 0;
3177 bspLightBytes = NULL;
3181 numBSPLightBytes = ( numBSPLightmaps * game->lightmapSize * game->lightmapSize * 3 );
3182 bspLightBytes = safe_malloc( numBSPLightBytes );
3183 memset( bspLightBytes, 0, numBSPLightBytes );
3186 /* walk the list of output lightmaps */
3187 for ( i = 0; i < numOutLightmaps; i++ )
3189 /* get output lightmap */
3190 olm = &outLightmaps[ i ];
3192 /* fill output lightmap */
3193 if ( lightmapFill ) {
3194 FillOutLightmap( olm );
3197 /* is this a valid bsp lightmap? */
3198 if ( olm->lightmapNum >= 0 && !externalLightmaps ) {
3199 /* copy lighting data */
3200 lb = bspLightBytes + ( olm->lightmapNum * game->lightmapSize * game->lightmapSize * 3 );
3201 memcpy( lb, olm->bspLightBytes, game->lightmapSize * game->lightmapSize * 3 );
3203 /* copy direction data */
3205 lb = bspLightBytes + ( ( olm->lightmapNum + 1 ) * game->lightmapSize * game->lightmapSize * 3 );
3206 memcpy( lb, olm->bspDirBytes, game->lightmapSize * game->lightmapSize * 3 );
3210 /* external lightmap? */
3211 if ( olm->lightmapNum < 0 || olm->extLightmapNum >= 0 || externalLightmaps ) {
3212 /* make a directory for the lightmaps */
3215 /* set external lightmap number */
3216 olm->extLightmapNum = numExtLightmaps;
3218 /* write lightmap */
3219 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
3220 Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
3221 WriteTGA24( filename, olm->bspLightBytes, olm->customWidth, olm->customHeight, qtrue );
3224 /* write deluxemap */
3226 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
3227 Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
3228 WriteTGA24( filename, olm->bspDirBytes, olm->customWidth, olm->customHeight, qtrue );
3231 if ( debugDeluxemap ) {
3232 olm->extLightmapNum++;
3238 if ( numExtLightmaps > 0 ) {
3242 /* delete unused external lightmaps */
3243 for ( i = numExtLightmaps; i; i++ )
3245 /* determine if file exists */
3246 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, i );
3247 if ( !FileExists( filename ) ) {
3255 Sys_Printf( "%d.", (int) ( I_FloatTime() - timer_start ) );
3257 /* -----------------------------------------------------------------
3258 project the lightmaps onto the bsp surfaces
3259 ----------------------------------------------------------------- */
3262 Sys_Printf( "projecting..." );
3264 timer_start = I_FloatTime();
3266 /* walk the list of surfaces */
3267 for ( i = 0; i < numBSPDrawSurfaces; i++ )
3269 /* get the surface and info */
3270 ds = &bspDrawSurfaces[ i ];
3271 info = &surfaceInfos[ i ];
3275 /* handle surfaces with identical parent */
3276 if ( info->parentSurfaceNum >= 0 ) {
3277 /* preserve original data and get parent */
3278 parent = &bspDrawSurfaces[ info->parentSurfaceNum ];
3279 memcpy( &dsTemp, ds, sizeof( *ds ) );
3281 /* overwrite child with parent data */
3282 memcpy( ds, parent, sizeof( *ds ) );
3284 /* restore key parts */
3285 ds->fogNum = dsTemp.fogNum;
3286 ds->firstVert = dsTemp.firstVert;
3287 ds->firstIndex = dsTemp.firstIndex;
3288 memcpy( ds->lightmapVecs, dsTemp.lightmapVecs, sizeof( dsTemp.lightmapVecs ) );
3290 /* set vertex data */
3291 dv = &bspDrawVerts[ ds->firstVert ];
3292 dvParent = &bspDrawVerts[ parent->firstVert ];
3293 for ( j = 0; j < ds->numVerts; j++ )
3295 memcpy( dv[ j ].lightmap, dvParent[ j ].lightmap, sizeof( dv[ j ].lightmap ) );
3296 memcpy( dv[ j ].color, dvParent[ j ].color, sizeof( dv[ j ].color ) );
3303 /* handle vertex lit or approximated surfaces */
3304 else if ( lm == NULL || lm->outLightmapNums[ 0 ] < 0 ) {
3305 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3307 ds->lightmapNum[ lightmapNum ] = -3;
3308 ds->lightmapStyles[ lightmapNum ] = ds->vertexStyles[ lightmapNum ];
3312 /* handle lightmapped surfaces */
3315 /* walk lightmaps */
3316 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3319 ds->lightmapStyles[ lightmapNum ] = lm->styles[ lightmapNum ];
3321 /* handle unused style */
3322 if ( lm->styles[ lightmapNum ] == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 ) {
3323 ds->lightmapNum[ lightmapNum ] = -3;
3327 /* get output lightmap */
3328 olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
3330 /* set bsp lightmap number */
3331 ds->lightmapNum[ lightmapNum ] = olm->lightmapNum;
3333 /* deluxemap debugging makes the deluxemap visible */
3334 if ( deluxemap && debugDeluxemap && lightmapNum == 0 ) {
3335 ds->lightmapNum[ lightmapNum ]++;
3338 /* calc lightmap origin in texture space */
3339 lmx = (float) lm->lightmapX[ lightmapNum ] / (float) olm->customWidth;
3340 lmy = (float) lm->lightmapY[ lightmapNum ] / (float) olm->customHeight;
3342 /* calc lightmap st coords */
3343 dv = &bspDrawVerts[ ds->firstVert ];
3344 ydv = &yDrawVerts[ ds->firstVert ];
3345 for ( j = 0; j < ds->numVerts; j++ )
3347 if ( lm->solid[ lightmapNum ] ) {
3348 dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + ( 0.5f / (float) olm->customWidth );
3349 dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + ( 0.5f / (float) olm->customWidth );
3353 dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + ( ydv[ j ].lightmap[ 0 ][ 0 ] / ( superSample * olm->customWidth ) );
3354 dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + ( ydv[ j ].lightmap[ 0 ][ 1 ] / ( superSample * olm->customHeight ) );
3360 /* store vertex colors */
3361 dv = &bspDrawVerts[ ds->firstVert ];
3362 for ( j = 0; j < ds->numVerts; j++ )
3364 /* walk lightmaps */
3365 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3367 /* handle unused style */
3368 if ( ds->vertexStyles[ lightmapNum ] == LS_NONE ) {
3369 VectorClear( color );
3373 /* get vertex color */
3374 luxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + j );
3375 VectorCopy( luxel, color );
3377 /* set minimum light */
3378 if ( lightmapNum == 0 ) {
3379 for ( k = 0; k < 3; k++ )
3380 if ( color[ k ] < minVertexLight[ k ] ) {
3381 color[ k ] = minVertexLight[ k ];
3386 /* store to bytes */
3387 if ( !info->si->noVertexLight ) {
3388 ColorToBytes( color, dv[ j ].color[ lightmapNum ], info->si->vertexScale );
3393 /* surfaces with styled lightmaps and a style marker get a custom generated shader (fixme: make this work with external lightmaps) */
3394 if ( olm != NULL && lm != NULL && lm->styles[ 1 ] != LS_NONE && game->load != LoadRBSPFile ) { //% info->si->styleMarker > 0 )
3396 char key[ 32 ], styleStage[ 512 ], styleStages[ 4096 ], rgbGen[ 128 ], alphaGen[ 128 ];
3400 sprintf( styleStages, "\n\t// Q3Map2 custom lightstyle stage(s)\n" );
3401 dv = &bspDrawVerts[ ds->firstVert ];
3403 /* depthFunc equal? */
3404 if ( info->si->styleMarker == 2 || info->si->implicitMap == IM_MASKED ) {
3411 /* generate stages for styled lightmaps */
3412 for ( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3415 style = lm->styles[ lightmapNum ];
3416 if ( style == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 ) {
3420 /* get output lightmap */
3421 olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
3424 if ( lm->outLightmapNums[ lightmapNum ] == lm->outLightmapNums[ 0 ] ) {
3425 strcpy( lightmapName, "$lightmap" );
3428 sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
3431 /* get rgbgen string */
3432 if ( rgbGenValues[ style ] == NULL ) {
3433 sprintf( key, "_style%drgbgen", style );
3434 rgbGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
3435 if ( rgbGenValues[ style ][ 0 ] == '\0' ) {
3436 rgbGenValues[ style ] = "wave noise 0.5 1 0 5.37";
3440 if ( rgbGenValues[ style ][ 0 ] != '\0' ) {
3441 sprintf( rgbGen, "\t\trgbGen %s // style %d\n", rgbGenValues[ style ], style );
3447 /* get alphagen string */
3448 if ( alphaGenValues[ style ] == NULL ) {
3449 sprintf( key, "_style%dalphagen", style );
3450 alphaGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
3452 if ( alphaGenValues[ style ][ 0 ] != '\0' ) {
3453 sprintf( alphaGen, "\t\talphaGen %s // style %d\n", alphaGenValues[ style ], style );
3456 alphaGen[ 0 ] = '\0';
3459 /* calculate st offset */
3460 lmx = dv[ 0 ].lightmap[ lightmapNum ][ 0 ] - dv[ 0 ].lightmap[ 0 ][ 0 ];
3461 lmy = dv[ 0 ].lightmap[ lightmapNum ][ 1 ] - dv[ 0 ].lightmap[ 0 ][ 1 ];
3463 /* create additional stage */
3464 if ( lmx == 0.0f && lmy == 0.0f ) {
3465 sprintf( styleStage, "\t{\n"
3466 "\t\tmap %s\n" /* lightmap */
3467 "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
3468 "%s" /* depthFunc equal */
3471 "\t\ttcGen lightmap\n"
3474 ( dfEqual ? "\t\tdepthFunc equal\n" : "" ),
3480 sprintf( styleStage, "\t{\n"
3481 "\t\tmap %s\n" /* lightmap */
3482 "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
3483 "%s" /* depthFunc equal */
3486 "\t\ttcGen lightmap\n"
3487 "\t\ttcMod transform 1 0 0 1 %1.5f %1.5f\n" /* st offset */
3490 ( dfEqual ? "\t\tdepthFunc equal\n" : "" ),
3498 strcat( styleStages, styleStage );
3501 /* create custom shader */
3502 if ( info->si->styleMarker == 2 ) {
3503 csi = CustomShader( info->si, "q3map_styleMarker2", styleStages );
3506 csi = CustomShader( info->si, "q3map_styleMarker", styleStages );
3509 /* emit remap command */
3510 //% EmitVertexRemapShader( csi->shader, info->si->shader );
3513 //% Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
3514 ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3515 //% Sys_Printf( ")\n" );
3518 /* devise a custom shader for this surface (fixme: make this work with light styles) */
3519 else if ( olm != NULL && lm != NULL && !externalLightmaps &&
3520 ( olm->customWidth != game->lightmapSize || olm->customHeight != game->lightmapSize ) ) {
3521 /* get output lightmap */
3522 olm = &outLightmaps[ lm->outLightmapNums[ 0 ] ];
3524 /* do some name mangling */
3525 sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
3527 /* create custom shader */
3528 csi = CustomShader( info->si, "$lightmap", lightmapName );
3531 //% Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
3532 ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3533 //% Sys_Printf( ")\n" );
3536 /* use the normal plain-jane shader */
3538 ds->shaderNum = EmitShader( info->si->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3542 Sys_Printf( "%d.", (int) ( I_FloatTime() - timer_start ) );
3545 Sys_Printf( "done.\n" );
3547 /* calc num stored */
3548 numStored = numBSPLightBytes / 3;
3549 efficiency = ( numStored <= 0 )
3551 : (float) numUsed / (float) numStored;
3554 Sys_Printf( "%9d luxels used\n", numUsed );
3555 Sys_Printf( "%9d luxels stored (%3.2f percent efficiency)\n", numStored, efficiency * 100.0f );
3556 Sys_Printf( "%9d solid surface lightmaps\n", numSolidLightmaps );
3557 Sys_Printf( "%9d identical surface lightmaps, using %d luxels\n", numTwins, numTwinLuxels );
3558 Sys_Printf( "%9d vertex forced surfaces\n", numSurfsVertexForced );
3559 Sys_Printf( "%9d vertex approximated surfaces\n", numSurfsVertexApproximated );
3560 Sys_Printf( "%9d BSP lightmaps\n", numBSPLightmaps );
3561 Sys_Printf( "%9d total lightmaps\n", numOutLightmaps );
3562 Sys_Printf( "%9d unique lightmap/shader combinations\n", numLightmapShaders );
3564 /* write map shader file */
3565 WriteMapShaderFile();