1 /* -------------------------------------------------------------------------------
2
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
5
6 This file is part of GtkRadiant.
7
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.
12
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.
17
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
21
22 ----------------------------------------------------------------------------------
23
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."
26
27 ------------------------------------------------------------------------------- */
28
29
30
31 /* marker */
32 #define LIGHTMAPS_YDNAR_C
33
34
35
36 /* dependencies */
37 #include "q3map2.h"
38
39
40
41
42 /* -------------------------------------------------------------------------------
43
44 this file contains code that doe lightmap allocation and projection that
45 runs in the -light phase.
46
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.
50
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.
54
55 ------------------------------------------------------------------------------- */
56
57 /*
58 WriteTGA24()
59 based on WriteTGA() from imagelib.c
60 */
61
WriteTGA24(char * filename,byte * data,int width,int height,qboolean flip)62 void WriteTGA24( char *filename, byte *data, int width, int height, qboolean flip ){
63 int i, c;
64 byte *buffer, *in;
65 FILE *file;
66
67
68 /* allocate a buffer and set it up */
69 buffer = safe_malloc( width * height * 3 + 18 );
70 memset( buffer, 0, 18 );
71 buffer[ 2 ] = 2;
72 buffer[ 12 ] = width & 255;
73 buffer[ 13 ] = width >> 8;
74 buffer[ 14 ] = height & 255;
75 buffer[ 15 ] = height >> 8;
76 buffer[ 16 ] = 24;
77
78 /* swap rgb to bgr */
79 c = ( width * height * 3 ) + 18;
80 for ( i = 18; i < c; i += 3 )
81 {
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 */
85 }
86
87 /* write it and free the buffer */
88 file = fopen( filename, "wb" );
89 if ( file == NULL ) {
90 Error( "Unable to open %s for writing", filename );
91 }
92
93 /* flip vertically? */
94 if ( flip ) {
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 );
98 }
99 else{
100 fwrite( buffer, 1, c, file );
101 }
102
103 /* close the file */
104 fclose( file );
105 free( buffer );
106 }
107
108
109
110 /*
111 ExportLightmaps()
112 exports the lightmaps as a list of numbered tga images
113 */
114
ExportLightmaps(void)115 void ExportLightmaps( void ){
116 int i;
117 char dirname[ 1024 ], filename[ 1024 ];
118 byte *lightmap;
119
120
121 /* note it */
122 Sys_FPrintf( SYS_VRB, "--- ExportLightmaps ---\n" );
123
124 /* do some path mangling */
125 strcpy( dirname, source );
126 StripExtension( dirname );
127
128 /* sanity check */
129 if ( bspLightBytes == NULL ) {
130 Sys_Printf( "WARNING: No BSP lightmap data\n" );
131 return;
132 }
133
134 /* make a directory for the lightmaps */
135 Q_mkdir( dirname );
136
137 /* iterate through the lightmaps */
138 for ( i = 0, lightmap = bspLightBytes; lightmap < ( bspLightBytes + numBSPLightBytes ); i++, lightmap += ( game->lightmapSize * game->lightmapSize * 3 ) )
139 {
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 );
144 }
145 }
146
147
148
149 /*
150 ExportLightmapsMain()
151 exports the lightmaps as a list of numbered tga images
152 */
153
ExportLightmapsMain(int argc,char ** argv)154 int ExportLightmapsMain( int argc, char **argv ){
155 /* arg checking */
156 if ( argc < 1 ) {
157 Sys_Printf( "Usage: q3map -export [-v] <mapname>\n" );
158 return 0;
159 }
160
161 /* do some path mangling */
162 strcpy( source, ExpandArg( argv[ argc - 1 ] ) );
163 StripExtension( source );
164 DefaultExtension( source, ".bsp" );
165
166 /* load the bsp */
167 Sys_Printf( "Loading %s\n", source );
168 LoadBSPFile( source );
169
170 /* export the lightmaps */
171 ExportLightmaps();
172
173 /* return to sender */
174 return 0;
175 }
176
177
178
179 /*
180 ImportLightmapsMain()
181 imports the lightmaps from a list of numbered tga images
182 */
183
ImportLightmapsMain(int argc,char ** argv)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;
188
189
190 /* arg checking */
191 if ( argc < 1 ) {
192 Sys_Printf( "Usage: q3map -import [-v] <mapname>\n" );
193 return 0;
194 }
195
196 /* do some path mangling */
197 strcpy( source, ExpandArg( argv[ argc - 1 ] ) );
198 StripExtension( source );
199 DefaultExtension( source, ".bsp" );
200
201 /* load the bsp */
202 Sys_Printf( "Loading %s\n", source );
203 LoadBSPFile( source );
204
205 /* note it */
206 Sys_FPrintf( SYS_VRB, "--- ImportLightmaps ---\n" );
207
208 /* do some path mangling */
209 strcpy( dirname, source );
210 StripExtension( dirname );
211
212 /* sanity check */
213 if ( bspLightBytes == NULL ) {
214 Error( "No lightmap data" );
215 }
216
217 /* make a directory for the lightmaps */
218 Q_mkdir( dirname );
219
220 /* iterate through the lightmaps */
221 for ( i = 0, lightmap = bspLightBytes; lightmap < ( bspLightBytes + numBSPLightBytes ); i++, lightmap += ( game->lightmapSize * game->lightmapSize * 3 ) )
222 {
223 /* read a tga image */
224 sprintf( filename, "%s/lightmap_%04d.tga", dirname, i );
225 Sys_Printf( "Loading %s\n", filename );
226 buffer = NULL;
227 len = vfsLoadFile( filename, (void*) &buffer, -1 );
228 if ( len < 0 ) {
229 Sys_Printf( "WARNING: Unable to load image %s\n", filename );
230 continue;
231 }
232
233 /* parse file into an image */
234 pixels = NULL;
235 LoadTGABuffer( buffer, buffer + len, &pixels, &width, &height );
236 free( buffer );
237
238 /* sanity check it */
239 if ( pixels == NULL ) {
240 Sys_Printf( "WARNING: Unable to load image %s\n", filename );
241 continue;
242 }
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 );
246 }
247
248 /* copy the pixels */
249 in = pixels;
250 for ( y = 1; y <= game->lightmapSize; y++ )
251 {
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 );
255 }
256
257 /* free the image */
258 free( pixels );
259 }
260
261 /* write the bsp */
262 Sys_Printf( "writing %s\n", source );
263 WriteBSPFile( source );
264
265 /* return to sender */
266 return 0;
267 }
268
269
270
271 /* -------------------------------------------------------------------------------
272
273 this section deals with projecting a lightmap onto a raw drawsurface
274
275 ------------------------------------------------------------------------------- */
276
277 /*
278 CompareLightSurface()
279 compare function for qsort()
280 */
281
CompareLightSurface(const void * a,const void * b)282 static int CompareLightSurface( const void *a, const void *b ){
283 shaderInfo_t *asi, *bsi;
284
285
286 /* get shaders */
287 asi = surfaceInfos[ *( (const int*) a ) ].si;
288 bsi = surfaceInfos[ *( (const int*) b ) ].si;
289
290 /* dummy check */
291 if ( asi == NULL ) {
292 return -1;
293 }
294 if ( bsi == NULL ) {
295 return 1;
296 }
297
298 /* compare shader names */
299 return strcmp( asi->shader, bsi->shader );
300 }
301
302
303
304 /*
305 FinishRawLightmap()
306 allocates a raw lightmap's necessary buffers
307 */
308
FinishRawLightmap(rawLightmap_t * lm)309 void FinishRawLightmap( rawLightmap_t *lm ){
310 int i, j, c, size, *sc;
311 float is;
312 surfaceInfo_t *info;
313
314
315 /* sort light surfaces by shader name */
316 qsort( &lightSurfaces[ lm->firstLightSurface ], lm->numLightSurfaces, sizeof( int ), CompareLightSurface );
317
318 /* count clusters */
319 lm->numLightClusters = 0;
320 for ( i = 0; i < lm->numLightSurfaces; i++ )
321 {
322 /* get surface info */
323 info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + i ] ];
324
325 /* add surface clusters */
326 lm->numLightClusters += info->numSurfaceClusters;
327 }
328
329 /* allocate buffer for clusters and copy */
330 lm->lightClusters = safe_malloc( lm->numLightClusters * sizeof( *lm->lightClusters ) );
331 c = 0;
332 for ( i = 0; i < lm->numLightSurfaces; i++ )
333 {
334 /* get surface info */
335 info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + i ] ];
336
337 /* add surface clusters */
338 for ( j = 0; j < info->numSurfaceClusters; j++ )
339 lm->lightClusters[ c++ ] = surfaceClusters[ info->firstSurfaceCluster + j ];
340 }
341
342 /* set styles */
343 lm->styles[ 0 ] = LS_NORMAL;
344 for ( i = 1; i < MAX_LIGHTMAPS; i++ )
345 lm->styles[ i ] = LS_NONE;
346
347 /* set supersampling size */
348 lm->sw = lm->w * superSample;
349 lm->sh = lm->h * superSample;
350
351 /* add to super luxel count */
352 numRawSuperLuxels += ( lm->sw * lm->sh );
353
354 /* manipulate origin/vecs for supersampling */
355 if ( superSample > 1 && lm->vecs != NULL ) {
356 /* calc inverse supersample */
357 is = 1.0f / superSample;
358
359 /* scale the vectors and shift the origin */
360 #if 1
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 );
368 #else
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 );
374 #endif
375 }
376
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 );
381 }
382 memset( lm->bspLuxels[ 0 ], 0, size );
383
384 /* allocate radiosity lightmap storage */
385 if ( bounce ) {
386 size = lm->w * lm->h * RAD_LUXEL_SIZE * sizeof( float );
387 if ( lm->radLuxels[ 0 ] == NULL ) {
388 lm->radLuxels[ 0 ] = safe_malloc( size );
389 }
390 memset( lm->radLuxels[ 0 ], 0, size );
391 }
392
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 );
397 }
398 memset( lm->superLuxels[ 0 ], 0, size );
399
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 );
404 }
405 memset( lm->superOrigins, 0, size );
406
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 );
411 }
412 memset( lm->superNormals, 0, size );
413
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 );
418 }
419 memset( lm->superFloodLight, 0, size );
420
421 /* allocate cluster map storage */
422 size = lm->sw * lm->sh * sizeof( int );
423 if ( lm->superClusters == NULL ) {
424 lm->superClusters = safe_malloc( size );
425 }
426 size = lm->sw * lm->sh;
427 sc = lm->superClusters;
428 for ( i = 0; i < size; i++ )
429 ( *sc++ ) = CLUSTER_UNMAPPED;
430
431 /* deluxemap allocation */
432 if ( deluxemap ) {
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 );
437 }
438 memset( lm->superDeluxels, 0, size );
439
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 );
444 }
445 memset( lm->bspDeluxels, 0, size );
446 }
447
448 /* add to count */
449 numLuxels += ( lm->sw * lm->sh );
450 }
451
452
453
454 /*
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()
460 */
461
AddPatchToRawLightmap(int num,rawLightmap_t * lm)462 qboolean AddPatchToRawLightmap( int num, rawLightmap_t *lm ){
463 bspDrawSurface_t *ds;
464 surfaceInfo_t *info;
465 int x, y;
466 bspDrawVert_t *verts, *a, *b;
467 vec3_t delta;
468 mesh_t src, *subdivided, *mesh;
469 float sBasis, tBasis, s, t;
470 float length, widthTable[ MAX_EXPANDED_AXIS ], heightTable[ MAX_EXPANDED_AXIS ];
471
472
473 /* patches finish a raw lightmap */
474 lm->finished = qtrue;
475
476 /* get surface and info */
477 ds = &bspDrawSurfaces[ num ];
478 info = &surfaceInfos[ num ];
479
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 );
486
487 /* fit it to the curve and remove colinear verts on rows/columns */
488 PutMeshOnCurve( *subdivided );
489 mesh = RemoveLinearMeshColumnsRows( subdivided );
490 FreeMesh( subdivided );
491
492 /* find the longest distance on each row/column */
493 verts = mesh->verts;
494 memset( widthTable, 0, sizeof( widthTable ) );
495 memset( heightTable, 0, sizeof( heightTable ) );
496 for ( y = 0; y < mesh->height; y++ )
497 {
498 for ( x = 0; x < mesh->width; x++ )
499 {
500 /* get width */
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;
508 }
509 }
510
511 /* get height */
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;
519 }
520 }
521 }
522 }
523
524 /* determine lightmap width */
525 length = 0;
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;
531 }
532 if ( lm->w > lm->customWidth ) {
533 lm->w = lm->customWidth;
534 }
535 sBasis = (float) ( lm->w - 1 ) / (float) ( ds->patchWidth - 1 );
536
537 /* determine lightmap height */
538 length = 0;
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;
544 }
545 if ( lm->h > lm->customHeight ) {
546 lm->h = lm->customHeight;
547 }
548 tBasis = (float) ( lm->h - 1 ) / (float) ( ds->patchHeight - 1 );
549
550 /* free the temporary mesh */
551 FreeMesh( mesh );
552
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++ )
558 {
559 t = ( tBasis * y ) + 0.5f;
560 for ( x = 0; x < ds->patchWidth; x++ )
561 {
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;
565
566 if ( y == 0 && !VectorCompare( verts[ x ].xyz, verts[ ( ( ds->patchHeight - 1 ) * ds->patchWidth ) + x ].xyz ) ) {
567 lm->wrap[ 1 ] = qfalse;
568 }
569 }
570
571 if ( !VectorCompare( verts[ ( y * ds->patchWidth ) ].xyz, verts[ ( y * ds->patchWidth ) + ( ds->patchWidth - 1 ) ].xyz ) ) {
572 lm->wrap[ 0 ] = qfalse;
573 }
574 }
575
576 /* debug code: */
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);
582
583 /* add to counts */
584 numPatchesLightmapped++;
585
586 /* return */
587 return qtrue;
588 }
589
590
591
592 /*
593 AddSurfaceToRawLightmap()
594 projects a lightmap for a surface
595 based on AllocateLightmapForSurface()
596 */
597
AddSurfaceToRawLightmap(int num,rawLightmap_t * lm)598 qboolean AddSurfaceToRawLightmap( int num, rawLightmap_t *lm ){
599 bspDrawSurface_t *ds, *ds2;
600 surfaceInfo_t *info;
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 ];
604 vec4_t plane;
605 bspDrawVert_t *verts;
606
607
608 /* get surface and info */
609 ds = &bspDrawSurfaces[ num ];
610 info = &surfaceInfos[ num ];
611
612 /* add the surface to the raw lightmap */
613 lightSurfaces[ numLightSurfaces++ ] = num;
614 lm->numLightSurfaces++;
615
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 ) {
620 return qfalse;
621 }
622
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 ) {
632 return qfalse;
633 }
634
635 /* surface bounds must intersect with raw lightmap bounds */
636 for ( i = 0; i < 3; i++ )
637 {
638 if ( info->mins[ i ] > lm->maxs[ i ] ) {
639 return qfalse;
640 }
641 if ( info->maxs[ i ] < lm->mins[ i ] ) {
642 return qfalse;
643 }
644 }
645
646 /* plane check (fixme: allow merging of nonplanars) */
647 if ( info->si->lmMergable == qfalse ) {
648 if ( info->plane == NULL || lm->plane == NULL ) {
649 return qfalse;
650 }
651
652 /* compare planes */
653 for ( i = 0; i < 4; i++ )
654 if ( fabs( info->plane[ i ] - lm->plane[ i ] ) > EQUAL_EPSILON ) {
655 return qfalse;
656 }
657 }
658
659 /* debug code hacking */
660 //% if( lm->numLightSurfaces > 1 )
661 //% return qfalse;
662 }
663
664 /* set plane */
665 if ( info->plane == NULL ) {
666 lm->plane = NULL;
667 }
668
669 /* add surface to lightmap bounds */
670 AddPointToBounds( info->mins, lm->mins, lm->maxs );
671 AddPointToBounds( info->maxs, lm->mins, lm->maxs );
672
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 );
677 }
678
679 /* start with initially requested sample size */
680 sampleSize = lm->sampleSize;
681
682 /* round to the lightmap resolution */
683 for ( i = 0; i < 3; i++ )
684 {
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;
688
689 /* hack (god this sucks) */
690 if ( size[ i ] > lm->customWidth || size[ i ] > lm->customHeight || ( lmLimitSize && size[i] > lmLimitSize ) ) {
691 i = -1;
692 sampleSize += 1.0f;
693 }
694 }
695
696 if ( sampleSize != lm->sampleSize && lmLimitSize == 0 ) {
697 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",
698 info->mins[0],
699 info->mins[1],
700 info->mins[2],
701 info->maxs[0],
702 info->maxs[1],
703 info->maxs[2],
704 lm->sampleSize,
705 (int) sampleSize );
706 }
707
708 /* set actual sample size */
709 lm->actualSampleSize = sampleSize;
710
711 /* fixme: copy rounded mins/maxes to lightmap record? */
712 if ( lm->plane == NULL ) {
713 VectorCopy( mins, lm->mins );
714 VectorCopy( maxs, lm->maxs );
715 VectorCopy( mins, origin );
716 }
717
718 /* set lightmap origin */
719 VectorCopy( lm->mins, origin );
720
721 /* make absolute axis */
722 faxis[ 0 ] = fabs( lm->axis[ 0 ] );
723 faxis[ 1 ] = fabs( lm->axis[ 1 ] );
724 faxis[ 2 ] = fabs( lm->axis[ 2 ] );
725
726 /* clear out lightmap vectors */
727 memset( vecs, 0, sizeof( vecs ) );
728
729 /* classify the plane (x y or z major) (ydnar: biased to z axis projection) */
730 if ( faxis[ 2 ] >= faxis[ 0 ] && faxis[ 2 ] >= faxis[ 1 ] ) {
731 axisNum = 2;
732 lm->w = size[ 0 ];
733 lm->h = size[ 1 ];
734 vecs[ 0 ][ 0 ] = 1.0f / sampleSize;
735 vecs[ 1 ][ 1 ] = 1.0f / sampleSize;
736 }
737 else if ( faxis[ 0 ] >= faxis[ 1 ] && faxis[ 0 ] >= faxis[ 2 ] ) {
738 axisNum = 0;
739 lm->w = size[ 1 ];
740 lm->h = size[ 2 ];
741 vecs[ 0 ][ 1 ] = 1.0f / sampleSize;
742 vecs[ 1 ][ 2 ] = 1.0f / sampleSize;
743 }
744 else
745 {
746 axisNum = 1;
747 lm->w = size[ 0 ];
748 lm->h = size[ 2 ];
749 vecs[ 0 ][ 0 ] = 1.0f / sampleSize;
750 vecs[ 1 ][ 2 ] = 1.0f / sampleSize;
751 }
752
753 /* check for bogus axis */
754 if ( faxis[ axisNum ] == 0.0f ) {
755 Sys_Printf( "WARNING: ProjectSurfaceLightmap: Chose a 0 valued axis\n" );
756 lm->w = lm->h = 0;
757 return qfalse;
758 }
759
760 /* store the axis number in the lightmap */
761 lm->axisNum = axisNum;
762
763 /* walk the list of surfaces on this raw lightmap */
764 for ( n = 0; n < lm->numLightSurfaces; n++ )
765 {
766 /* get surface */
767 num2 = lightSurfaces[ lm->firstLightSurface + n ];
768 ds2 = &bspDrawSurfaces[ num2 ];
769 verts = &yDrawVerts[ ds2->firstVert ];
770
771 /* set the lightmap texture coordinates in yDrawVerts in [0, superSample * lm->customWidth] space */
772 for ( i = 0; i < ds2->numVerts; i++ )
773 {
774 VectorSubtract( verts[ i ].xyz, origin, delta );
775 s = DotProduct( delta, vecs[ 0 ] ) + 0.5f;
776 t = DotProduct( delta, vecs[ 1 ] ) + 0.5f;
777 verts[ i ].lightmap[ 0 ][ 0 ] = s * superSample;
778 verts[ i ].lightmap[ 0 ][ 1 ] = t * superSample;
779
780 if ( s > (float) lm->w || t > (float) lm->h ) {
781 Sys_FPrintf( SYS_VRB, "WARNING: Lightmap texture coords out of range: S %1.4f > %3d || T %1.4f > %3d\n",
782 s, lm->w, t, lm->h );
783 }
784 }
785 }
786
787 /* get first drawsurface */
788 num2 = lightSurfaces[ lm->firstLightSurface ];
789 ds2 = &bspDrawSurfaces[ num2 ];
790 verts = &yDrawVerts[ ds2->firstVert ];
791
792 /* calculate lightmap origin */
793 if ( VectorLength( ds2->lightmapVecs[ 2 ] ) ) {
794 VectorCopy( ds2->lightmapVecs[ 2 ], plane );
795 }
796 else{
797 VectorCopy( lm->axis, plane );
798 }
799 plane[ 3 ] = DotProduct( verts[ 0 ].xyz, plane );
800
801 VectorCopy( origin, lm->origin );
802 d = DotProduct( lm->origin, plane ) - plane[ 3 ];
803 d /= plane[ axisNum ];
804 lm->origin[ axisNum ] -= d;
805
806 /* legacy support */
807 VectorCopy( lm->origin, ds->lightmapOrigin );
808
809 /* for planar surfaces, create lightmap vectors for st->xyz conversion */
810 if ( VectorLength( ds->lightmapVecs[ 2 ] ) || 1 ) { /* ydnar: can't remember what exactly i was thinking here... */
811 /* allocate space for the vectors */
812 lm->vecs = safe_malloc( 3 * sizeof( vec3_t ) );
813 memset( lm->vecs, 0, 3 * sizeof( vec3_t ) );
814 VectorCopy( ds->lightmapVecs[ 2 ], lm->vecs[ 2 ] );
815
816 /* project stepped lightmap blocks and subtract to get planevecs */
817 for ( i = 0; i < 2; i++ )
818 {
819 len = VectorNormalize( vecs[ i ], normalized );
820 VectorScale( normalized, ( 1.0 / len ), lm->vecs[ i ] );
821 d = DotProduct( lm->vecs[ i ], plane );
822 d /= plane[ axisNum ];
823 lm->vecs[ i ][ axisNum ] -= d;
824 }
825 }
826 else
827 {
828 /* lightmap vectors are useless on a non-planar surface */
829 lm->vecs = NULL;
830 }
831
832 /* add to counts */
833 if ( ds->surfaceType == MST_PATCH ) {
834 numPatchesLightmapped++;
835 if ( lm->plane != NULL ) {
836 numPlanarPatchesLightmapped++;
837 }
838 }
839 else
840 {
841 if ( lm->plane != NULL ) {
842 numPlanarsLightmapped++;
843 }
844 else{
845 numNonPlanarsLightmapped++;
846 }
847 }
848
849 /* return */
850 return qtrue;
851 }
852
853
854
855 /*
856 CompareSurfaceInfo()
857 compare function for qsort()
858 */
859
CompareSurfaceInfo(const void * a,const void * b)860 static int CompareSurfaceInfo( const void *a, const void *b ){
861 surfaceInfo_t *aInfo, *bInfo;
862 int i;
863
864
865 /* get surface info */
866 aInfo = &surfaceInfos[ *( (const int*) a ) ];
867 bInfo = &surfaceInfos[ *( (const int*) b ) ];
868
869 /* model first */
870 if ( aInfo->modelindex < bInfo->modelindex ) {
871 return 1;
872 }
873 else if ( aInfo->modelindex > bInfo->modelindex ) {
874 return -1;
875 }
876
877 /* then lightmap status */
878 if ( aInfo->hasLightmap < bInfo->hasLightmap ) {
879 return 1;
880 }
881 else if ( aInfo->hasLightmap > bInfo->hasLightmap ) {
882 return -1;
883 }
884
885 /* 27: then shader! */
886 if ( aInfo->si < bInfo->si ) {
887 return 1;
888 }
889 else if ( aInfo->si > bInfo->si ) {
890 return -1;
891 }
892
893
894 /* then lightmap sample size */
895 if ( aInfo->sampleSize < bInfo->sampleSize ) {
896 return 1;
897 }
898 else if ( aInfo->sampleSize > bInfo->sampleSize ) {
899 return -1;
900 }
901
902 /* then lightmap axis */
903 for ( i = 0; i < 3; i++ )
904 {
905 if ( aInfo->axis[ i ] < bInfo->axis[ i ] ) {
906 return 1;
907 }
908 else if ( aInfo->axis[ i ] > bInfo->axis[ i ] ) {
909 return -1;
910 }
911 }
912
913 /* then plane */
914 if ( aInfo->plane == NULL && bInfo->plane != NULL ) {
915 return 1;
916 }
917 else if ( aInfo->plane != NULL && bInfo->plane == NULL ) {
918 return -1;
919 }
920 else if ( aInfo->plane != NULL && bInfo->plane != NULL ) {
921 for ( i = 0; i < 4; i++ )
922 {
923 if ( aInfo->plane[ i ] < bInfo->plane[ i ] ) {
924 return 1;
925 }
926 else if ( aInfo->plane[ i ] > bInfo->plane[ i ] ) {
927 return -1;
928 }
929 }
930 }
931
932 /* then position in world */
933 for ( i = 0; i < 3; i++ )
934 {
935 if ( aInfo->mins[ i ] < bInfo->mins[ i ] ) {
936 return 1;
937 }
938 else if ( aInfo->mins[ i ] > bInfo->mins[ i ] ) {
939 return -1;
940 }
941 }
942
943 /* these are functionally identical (this should almost never happen) */
944 return 0;
945 }
946
947
948
949 /*
950 SetupSurfaceLightmaps()
951 allocates lightmaps for every surface in the bsp that needs one
952 this depends on yDrawVerts being allocated
953 */
954
SetupSurfaceLightmaps(void)955 void SetupSurfaceLightmaps( void ){
956 int i, j, k, s,num, num2;
957 bspModel_t *model;
958 bspLeaf_t *leaf;
959 bspDrawSurface_t *ds;
960 surfaceInfo_t *info, *info2;
961 rawLightmap_t *lm;
962 qboolean added;
963 vec3_t mapSize, entityOrigin;
964
965
966 /* note it */
967 Sys_FPrintf( SYS_VRB, "--- SetupSurfaceLightmaps ---\n" );
968
969 /* determine supersample amount */
970 if ( superSample < 1 ) {
971 superSample = 1;
972 }
973 else if ( superSample > 8 ) {
974 Sys_Printf( "WARNING: Insane supersampling amount (%d) detected.\n", superSample );
975 superSample = 8;
976 }
977
978 /* clear map bounds */
979 ClearBounds( mapMins, mapMaxs );
980
981 /* allocate a list of surface clusters */
982 numSurfaceClusters = 0;
983 maxSurfaceClusters = numBSPLeafSurfaces;
984 surfaceClusters = safe_malloc( maxSurfaceClusters * sizeof( *surfaceClusters ) );
985 memset( surfaceClusters, 0, maxSurfaceClusters * sizeof( *surfaceClusters ) );
986
987 /* allocate a list for per-surface info */
988 surfaceInfos = safe_malloc( numBSPDrawSurfaces * sizeof( *surfaceInfos ) );
989 memset( surfaceInfos, 0, numBSPDrawSurfaces * sizeof( *surfaceInfos ) );
990 for ( i = 0; i < numBSPDrawSurfaces; i++ )
991 surfaceInfos[ i ].childSurfaceNum = -1;
992
993 /* allocate a list of surface indexes to be sorted */
994 sortSurfaces = safe_malloc( numBSPDrawSurfaces * sizeof( int ) );
995 memset( sortSurfaces, 0, numBSPDrawSurfaces * sizeof( int ) );
996
997 /* walk each model in the bsp */
998 for ( i = 0; i < numBSPModels; i++ )
999 {
1000 /* get model */
1001 model = &bspModels[ i ];
1002
1003 /* walk the list of surfaces in this model and fill out the info structs */
1004 for ( j = 0; j < model->numBSPSurfaces; j++ )
1005 {
1006 /* make surface index */
1007 num = model->firstBSPSurface + j;
1008
1009 /* copy index to sort list */
1010 sortSurfaces[ num ] = num;
1011
1012 /* get surface and info */
1013 ds = &bspDrawSurfaces[ num ];
1014 info = &surfaceInfos[ num ];
1015
1016 /* set entity origin */
1017 if ( ds->numVerts > 0 ) {
1018 VectorSubtract( yDrawVerts[ ds->firstVert ].xyz, bspDrawVerts[ ds->firstVert ].xyz, entityOrigin );
1019 }
1020 else{
1021 VectorClear( entityOrigin );
1022 }
1023
1024 /* basic setup */
1025 info->modelindex = i;
1026 info->lm = NULL;
1027 info->plane = NULL;
1028 info->firstSurfaceCluster = numSurfaceClusters;
1029
1030 /* get extra data */
1031 info->si = GetSurfaceExtraShaderInfo( num );
1032 if ( info->si == NULL ) {
1033 info->si = ShaderInfoForShader( bspShaders[ ds->shaderNum ].shader );
1034 }
1035 info->parentSurfaceNum = GetSurfaceExtraParentSurfaceNum( num );
1036 info->entityNum = GetSurfaceExtraEntityNum( num );
1037 info->castShadows = GetSurfaceExtraCastShadows( num );
1038 info->recvShadows = GetSurfaceExtraRecvShadows( num );
1039 info->sampleSize = GetSurfaceExtraSampleSize( num );
1040 info->longestCurve = GetSurfaceExtraLongestCurve( num );
1041 info->patchIterations = IterationsForCurve( info->longestCurve, patchSubdivisions );
1042 GetSurfaceExtraLightmapAxis( num, info->axis );
1043
1044 /* mark parent */
1045 if ( info->parentSurfaceNum >= 0 ) {
1046 surfaceInfos[ info->parentSurfaceNum ].childSurfaceNum = j;
1047 }
1048
1049 /* determine surface bounds */
1050 ClearBounds( info->mins, info->maxs );
1051 for ( k = 0; k < ds->numVerts; k++ )
1052 {
1053 AddPointToBounds( yDrawVerts[ ds->firstVert + k ].xyz, mapMins, mapMaxs );
1054 AddPointToBounds( yDrawVerts[ ds->firstVert + k ].xyz, info->mins, info->maxs );
1055 }
1056
1057 /* find all the bsp clusters the surface falls into */
1058 for ( k = 0; k < numBSPLeafs; k++ )
1059 {
1060 /* get leaf */
1061 leaf = &bspLeafs[ k ];
1062
1063 /* test bbox */
1064 if ( leaf->mins[ 0 ] > info->maxs[ 0 ] || leaf->maxs[ 0 ] < info->mins[ 0 ] ||
1065 leaf->mins[ 1 ] > info->maxs[ 1 ] || leaf->maxs[ 1 ] < info->mins[ 1 ] ||
1066 leaf->mins[ 2 ] > info->maxs[ 2 ] || leaf->maxs[ 2 ] < info->mins[ 2 ] ) {
1067 continue;
1068 }
1069
1070 /* test leaf surfaces */
1071 for ( s = 0; s < leaf->numBSPLeafSurfaces; s++ )
1072 {
1073 if ( bspLeafSurfaces[ leaf->firstBSPLeafSurface + s ] == num ) {
1074 if ( numSurfaceClusters >= maxSurfaceClusters ) {
1075 Error( "maxSurfaceClusters exceeded" );
1076 }
1077 surfaceClusters[ numSurfaceClusters ] = leaf->cluster;
1078 numSurfaceClusters++;
1079 info->numSurfaceClusters++;
1080 }
1081 }
1082 }
1083
1084 /* determine if surface is planar */
1085 if ( VectorLength( ds->lightmapVecs[ 2 ] ) > 0.0f ) {
1086 /* make a plane */
1087 info->plane = safe_malloc( 4 * sizeof( float ) );
1088 VectorCopy( ds->lightmapVecs[ 2 ], info->plane );
1089 info->plane[ 3 ] = DotProduct( yDrawVerts[ ds->firstVert ].xyz, info->plane );
1090 }
1091
1092 /* determine if surface requires a lightmap */
1093 if ( ds->surfaceType == MST_TRIANGLE_SOUP ||
1094 ds->surfaceType == MST_FOLIAGE ||
1095 ( info->si->compileFlags & C_VERTEXLIT ) ) {
1096 numSurfsVertexLit++;
1097 }
1098 else
1099 {
1100 numSurfsLightmapped++;
1101 info->hasLightmap = qtrue;
1102 }
1103 }
1104 }
1105
1106 /* find longest map distance */
1107 VectorSubtract( mapMaxs, mapMins, mapSize );
1108 maxMapDistance = VectorLength( mapSize );
1109
1110 /* sort the surfaces info list */
1111 qsort( sortSurfaces, numBSPDrawSurfaces, sizeof( int ), CompareSurfaceInfo );
1112
1113 /* allocate a list of surfaces that would go into raw lightmaps */
1114 numLightSurfaces = 0;
1115 lightSurfaces = safe_malloc( numSurfsLightmapped * sizeof( int ) );
1116 memset( lightSurfaces, 0, numSurfsLightmapped * sizeof( int ) );
1117
1118 /* allocate a list of raw lightmaps */
1119 numRawSuperLuxels = 0;
1120 numRawLightmaps = 0;
1121 rawLightmaps = safe_malloc( numSurfsLightmapped * sizeof( *rawLightmaps ) );
1122 memset( rawLightmaps, 0, numSurfsLightmapped * sizeof( *rawLightmaps ) );
1123
1124 /* walk the list of sorted surfaces */
1125 for ( i = 0; i < numBSPDrawSurfaces; i++ )
1126 {
1127 /* get info and attempt early out */
1128 num = sortSurfaces[ i ];
1129 ds = &bspDrawSurfaces[ num ];
1130 info = &surfaceInfos[ num ];
1131 if ( info->hasLightmap == qfalse || info->lm != NULL || info->parentSurfaceNum >= 0 ) {
1132 continue;
1133 }
1134
1135 /* allocate a new raw lightmap */
1136 lm = &rawLightmaps[ numRawLightmaps ];
1137 numRawLightmaps++;
1138
1139 /* set it up */
1140 lm->splotchFix = info->si->splotchFix;
1141 lm->firstLightSurface = numLightSurfaces;
1142 lm->numLightSurfaces = 0;
1143 /* vortex: multiply lightmap sample size by -samplescale */
1144 if ( sampleScale > 0 ) {
1145 lm->sampleSize = info->sampleSize * sampleScale;
1146 }
1147 else{
1148 lm->sampleSize = info->sampleSize;
1149 }
1150 lm->actualSampleSize = lm->sampleSize;
1151 lm->entityNum = info->entityNum;
1152 lm->recvShadows = info->recvShadows;
1153 lm->brightness = info->si->lmBrightness;
1154 lm->filterRadius = info->si->lmFilterRadius;
1155 VectorCopy( info->si->floodlightRGB, lm->floodlightRGB );
1156 lm->floodlightDistance = info->si->floodlightDistance;
1157 lm->floodlightIntensity = info->si->floodlightIntensity;
1158 lm->floodlightDirectionScale = info->si->floodlightDirectionScale;
1159 VectorCopy( info->axis, lm->axis );
1160 lm->plane = info->plane;
1161 VectorCopy( info->mins, lm->mins );
1162 VectorCopy( info->maxs, lm->maxs );
1163
1164 lm->customWidth = info->si->lmCustomWidth;
1165 lm->customHeight = info->si->lmCustomHeight;
1166
1167 /* add the surface to the raw lightmap */
1168 AddSurfaceToRawLightmap( num, lm );
1169 info->lm = lm;
1170
1171 /* do an exhaustive merge */
1172 added = qtrue;
1173 while ( added )
1174 {
1175 /* walk the list of surfaces again */
1176 added = qfalse;
1177 for ( j = i + 1; j < numBSPDrawSurfaces && lm->finished == qfalse; j++ )
1178 {
1179 /* get info and attempt early out */
1180 num2 = sortSurfaces[ j ];
1181 info2 = &surfaceInfos[ num2 ];
1182 if ( info2->hasLightmap == qfalse || info2->lm != NULL ) {
1183 continue;
1184 }
1185
1186 /* add the surface to the raw lightmap */
1187 if ( AddSurfaceToRawLightmap( num2, lm ) ) {
1188 info2->lm = lm;
1189 added = qtrue;
1190 }
1191 else
1192 {
1193 /* back up one */
1194 lm->numLightSurfaces--;
1195 numLightSurfaces--;
1196 }
1197 }
1198 }
1199
1200 /* finish the lightmap and allocate the various buffers */
1201 FinishRawLightmap( lm );
1202 }
1203
1204 /* allocate vertex luxel storage */
1205 for ( k = 0; k < MAX_LIGHTMAPS; k++ )
1206 {
1207 vertexLuxels[ k ] = safe_malloc( numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
1208 memset( vertexLuxels[ k ], 0, numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
1209 radVertexLuxels[ k ] = safe_malloc( numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
1210 memset( radVertexLuxels[ k ], 0, numBSPDrawVerts * VERTEX_LUXEL_SIZE * sizeof( float ) );
1211 }
1212
1213 /* emit some stats */
1214 Sys_FPrintf( SYS_VRB, "%9d surfaces\n", numBSPDrawSurfaces );
1215 Sys_FPrintf( SYS_VRB, "%9d raw lightmaps\n", numRawLightmaps );
1216 Sys_FPrintf( SYS_VRB, "%9d surfaces vertex lit\n", numSurfsVertexLit );
1217 Sys_FPrintf( SYS_VRB, "%9d surfaces lightmapped\n", numSurfsLightmapped );
1218 Sys_FPrintf( SYS_VRB, "%9d planar surfaces lightmapped\n", numPlanarsLightmapped );
1219 Sys_FPrintf( SYS_VRB, "%9d non-planar surfaces lightmapped\n", numNonPlanarsLightmapped );
1220 Sys_FPrintf( SYS_VRB, "%9d patches lightmapped\n", numPatchesLightmapped );
1221 Sys_FPrintf( SYS_VRB, "%9d planar patches lightmapped\n", numPlanarPatchesLightmapped );
1222 }
1223
1224
1225
1226 /*
1227 StitchSurfaceLightmaps()
1228 stitches lightmap edges
1229 2002-11-20 update: use this func only for stitching nonplanar patch lightmap seams
1230 */
1231
1232 #define MAX_STITCH_CANDIDATES 32
1233 #define MAX_STITCH_LUXELS 64
1234
StitchSurfaceLightmaps(void)1235 void StitchSurfaceLightmaps( void ){
1236 int i, j, x, y, x2, y2, *cluster, *cluster2,
1237 numStitched, numCandidates, numLuxels, f, fOld, start;
1238 rawLightmap_t *lm, *a, *b, *c[ MAX_STITCH_CANDIDATES ];
1239 float *luxel, *luxel2, *origin, *origin2, *normal, *normal2,
1240 sampleSize, average[ 3 ], totalColor, ootc;
1241
1242
1243 /* disabled for now */
1244 return;
1245
1246 /* note it */
1247 Sys_Printf( "--- StitchSurfaceLightmaps ---\n" );
1248
1249 /* init pacifier */
1250 fOld = -1;
1251 start = I_FloatTime();
1252
1253 /* walk the list of raw lightmaps */
1254 numStitched = 0;
1255 for ( i = 0; i < numRawLightmaps; i++ )
1256 {
1257 /* print pacifier */
1258 f = 10 * i / numRawLightmaps;
1259 if ( f != fOld ) {
1260 fOld = f;
1261 Sys_Printf( "%i...", f );
1262 }
1263
1264 /* get lightmap a */
1265 a = &rawLightmaps[ i ];
1266
1267 /* walk rest of lightmaps */
1268 numCandidates = 0;
1269 for ( j = i + 1; j < numRawLightmaps && numCandidates < MAX_STITCH_CANDIDATES; j++ )
1270 {
1271 /* get lightmap b */
1272 b = &rawLightmaps[ j ];
1273
1274 /* test bounding box */
1275 if ( a->mins[ 0 ] > b->maxs[ 0 ] || a->maxs[ 0 ] < b->mins[ 0 ] ||
1276 a->mins[ 1 ] > b->maxs[ 1 ] || a->maxs[ 1 ] < b->mins[ 1 ] ||
1277 a->mins[ 2 ] > b->maxs[ 2 ] || a->maxs[ 2 ] < b->mins[ 2 ] ) {
1278 continue;
1279 }
1280
1281 /* add candidate */
1282 c[ numCandidates++ ] = b;
1283 }
1284
1285 /* walk luxels */
1286 for ( y = 0; y < a->sh; y++ )
1287 {
1288 for ( x = 0; x < a->sw; x++ )
1289 {
1290 /* ignore unmapped/unlit luxels */
1291 lm = a;
1292 cluster = SUPER_CLUSTER( x, y );
1293 if ( *cluster == CLUSTER_UNMAPPED ) {
1294 continue;
1295 }
1296 luxel = SUPER_LUXEL( 0, x, y );
1297 if ( luxel[ 3 ] <= 0.0f ) {
1298 continue;
1299 }
1300
1301 /* get particulars */
1302 origin = SUPER_ORIGIN( x, y );
1303 normal = SUPER_NORMAL( x, y );
1304
1305 /* walk candidate list */
1306 for ( j = 0; j < numCandidates; j++ )
1307 {
1308 /* get candidate */
1309 b = c[ j ];
1310 lm = b;
1311
1312 /* set samplesize to the smaller of the pair */
1313 sampleSize = 0.5f * ( a->actualSampleSize < b->actualSampleSize ? a->actualSampleSize : b->actualSampleSize );
1314
1315 /* test bounding box */
1316 if ( origin[ 0 ] < ( b->mins[ 0 ] - sampleSize ) || ( origin[ 0 ] > b->maxs[ 0 ] + sampleSize ) ||
1317 origin[ 1 ] < ( b->mins[ 1 ] - sampleSize ) || ( origin[ 1 ] > b->maxs[ 1 ] + sampleSize ) ||
1318 origin[ 2 ] < ( b->mins[ 2 ] - sampleSize ) || ( origin[ 2 ] > b->maxs[ 2 ] + sampleSize ) ) {
1319 continue;
1320 }
1321
1322 /* walk candidate luxels */
1323 VectorClear( average );
1324 numLuxels = 0;
1325 totalColor = 0.0f;
1326 for ( y2 = 0; y2 < b->sh && numLuxels < MAX_STITCH_LUXELS; y2++ )
1327 {
1328 for ( x2 = 0; x2 < b->sw && numLuxels < MAX_STITCH_LUXELS; x2++ )
1329 {
1330 /* ignore same luxels */
1331 if ( a == b && abs( x - x2 ) <= 1 && abs( y - y2 ) <= 1 ) {
1332 continue;
1333 }
1334
1335 /* ignore unmapped/unlit luxels */
1336 cluster2 = SUPER_CLUSTER( x2, y2 );
1337 if ( *cluster2 == CLUSTER_UNMAPPED ) {
1338 continue;
1339 }
1340 luxel2 = SUPER_LUXEL( 0, x2, y2 );
1341 if ( luxel2[ 3 ] <= 0.0f ) {
1342 continue;
1343 }
1344
1345 /* get particulars */
1346 origin2 = SUPER_ORIGIN( x2, y2 );
1347 normal2 = SUPER_NORMAL( x2, y2 );
1348
1349 /* test normal */
1350 if ( DotProduct( normal, normal2 ) < 0.5f ) {
1351 continue;
1352 }
1353
1354 /* test bounds */
1355 if ( fabs( origin[ 0 ] - origin2[ 0 ] ) > sampleSize ||
1356 fabs( origin[ 1 ] - origin2[ 1 ] ) > sampleSize ||
1357 fabs( origin[ 2 ] - origin2[ 2 ] ) > sampleSize ) {
1358 continue;
1359 }
1360
1361 /* add luxel */
1362 //% VectorSet( luxel2, 255, 0, 255 );
1363 VectorAdd( average, luxel2, average );
1364 totalColor += luxel2[ 3 ];
1365 }
1366 }
1367
1368 /* early out */
1369 if ( numLuxels == 0 ) {
1370 continue;
1371 }
1372
1373 /* scale average */
1374 ootc = 1.0f / totalColor;
1375 VectorScale( average, ootc, luxel );
1376 luxel[ 3 ] = 1.0f;
1377 numStitched++;
1378 }
1379 }
1380 }
1381 }
1382
1383 /* emit statistics */
1384 Sys_Printf( " (%i)\n", (int) ( I_FloatTime() - start ) );
1385 Sys_FPrintf( SYS_VRB, "%9d luxels stitched\n", numStitched );
1386 }
1387
1388
1389
1390 /*
1391 CompareBSPLuxels()
1392 compares two surface lightmaps' bsp luxels, ignoring occluded luxels
1393 */
1394
1395 #define SOLID_EPSILON 0.0625
1396 #define LUXEL_TOLERANCE 0.0025
1397 #define LUXEL_COLOR_FRAC 0.001302083 /* 1 / 3 / 256 */
1398
CompareBSPLuxels(rawLightmap_t * a,int aNum,rawLightmap_t * b,int bNum)1399 static qboolean CompareBSPLuxels( rawLightmap_t *a, int aNum, rawLightmap_t *b, int bNum ){
1400 rawLightmap_t *lm;
1401 int x, y;
1402 double delta, total, rd, gd, bd;
1403 float *aLuxel, *bLuxel;
1404
1405
1406 /* styled lightmaps will never be collapsed to non-styled lightmaps when there is _minlight */
1407 if ( ( minLight[ 0 ] || minLight[ 1 ] || minLight[ 2 ] ) &&
1408 ( ( aNum == 0 && bNum != 0 ) || ( aNum != 0 && bNum == 0 ) ) ) {
1409 return qfalse;
1410 }
1411
1412 /* basic tests */
1413 if ( a->customWidth != b->customWidth || a->customHeight != b->customHeight ||
1414 a->brightness != b->brightness ||
1415 a->solid[ aNum ] != b->solid[ bNum ] ||
1416 a->bspLuxels[ aNum ] == NULL || b->bspLuxels[ bNum ] == NULL ) {
1417 return qfalse;
1418 }
1419
1420 /* compare solid color lightmaps */
1421 if ( a->solid[ aNum ] && b->solid[ bNum ] ) {
1422 /* get deltas */
1423 rd = fabs( a->solidColor[ aNum ][ 0 ] - b->solidColor[ bNum ][ 0 ] );
1424 gd = fabs( a->solidColor[ aNum ][ 1 ] - b->solidColor[ bNum ][ 1 ] );
1425 bd = fabs( a->solidColor[ aNum ][ 2 ] - b->solidColor[ bNum ][ 2 ] );
1426
1427 /* compare color */
1428 if ( rd > SOLID_EPSILON || gd > SOLID_EPSILON || bd > SOLID_EPSILON ) {
1429 return qfalse;
1430 }
1431
1432 /* okay */
1433 return qtrue;
1434 }
1435
1436 /* compare nonsolid lightmaps */
1437 if ( a->w != b->w || a->h != b->h ) {
1438 return qfalse;
1439 }
1440
1441 /* compare luxels */
1442 delta = 0.0;
1443 total = 0.0;
1444 for ( y = 0; y < a->h; y++ )
1445 {
1446 for ( x = 0; x < a->w; x++ )
1447 {
1448 /* increment total */
1449 total += 1.0;
1450
1451 /* get luxels */
1452 lm = a; aLuxel = BSP_LUXEL( aNum, x, y );
1453 lm = b; bLuxel = BSP_LUXEL( bNum, x, y );
1454
1455 /* ignore unused luxels */
1456 if ( aLuxel[ 0 ] < 0 || bLuxel[ 0 ] < 0 ) {
1457 continue;
1458 }
1459
1460 /* get deltas */
1461 rd = fabs( aLuxel[ 0 ] - bLuxel[ 0 ] );
1462 gd = fabs( aLuxel[ 1 ] - bLuxel[ 1 ] );
1463 bd = fabs( aLuxel[ 2 ] - bLuxel[ 2 ] );
1464
1465 /* 2003-09-27: compare individual luxels */
1466 if ( rd > 3.0 || gd > 3.0 || bd > 3.0 ) {
1467 return qfalse;
1468 }
1469
1470 /* compare (fixme: take into account perceptual differences) */
1471 delta += rd * LUXEL_COLOR_FRAC;
1472 delta += gd * LUXEL_COLOR_FRAC;
1473 delta += bd * LUXEL_COLOR_FRAC;
1474
1475 /* is the change too high? */
1476 if ( total > 0.0 && ( ( delta / total ) > LUXEL_TOLERANCE ) ) {
1477 return qfalse;
1478 }
1479 }
1480 }
1481
1482 /* made it this far, they must be identical (or close enough) */
1483 return qtrue;
1484 }
1485
1486
1487
1488 /*
1489 MergeBSPLuxels()
1490 merges two surface lightmaps' bsp luxels, overwriting occluded luxels
1491 */
1492
MergeBSPLuxels(rawLightmap_t * a,int aNum,rawLightmap_t * b,int bNum)1493 static qboolean MergeBSPLuxels( rawLightmap_t *a, int aNum, rawLightmap_t *b, int bNum ){
1494 rawLightmap_t *lm;
1495 int x, y;
1496 float luxel[ 3 ], *aLuxel, *bLuxel;
1497
1498
1499 /* basic tests */
1500 if ( a->customWidth != b->customWidth || a->customHeight != b->customHeight ||
1501 a->brightness != b->brightness ||
1502 a->solid[ aNum ] != b->solid[ bNum ] ||
1503 a->bspLuxels[ aNum ] == NULL || b->bspLuxels[ bNum ] == NULL ) {
1504 return qfalse;
1505 }
1506
1507 /* compare solid lightmaps */
1508 if ( a->solid[ aNum ] && b->solid[ bNum ] ) {
1509 /* average */
1510 VectorAdd( a->solidColor[ aNum ], b->solidColor[ bNum ], luxel );
1511 VectorScale( luxel, 0.5f, luxel );
1512
1513 /* copy to both */
1514 VectorCopy( luxel, a->solidColor[ aNum ] );
1515 VectorCopy( luxel, b->solidColor[ bNum ] );
1516
1517 /* return to sender */
1518 return qtrue;
1519 }
1520
1521 /* compare nonsolid lightmaps */
1522 if ( a->w != b->w || a->h != b->h ) {
1523 return qfalse;
1524 }
1525
1526 /* merge luxels */
1527 for ( y = 0; y < a->h; y++ )
1528 {
1529 for ( x = 0; x < a->w; x++ )
1530 {
1531 /* get luxels */
1532 lm = a; aLuxel = BSP_LUXEL( aNum, x, y );
1533 lm = b; bLuxel = BSP_LUXEL( bNum, x, y );
1534
1535 /* handle occlusion mismatch */
1536 if ( aLuxel[ 0 ] < 0.0f ) {
1537 VectorCopy( bLuxel, aLuxel );
1538 }
1539 else if ( bLuxel[ 0 ] < 0.0f ) {
1540 VectorCopy( aLuxel, bLuxel );
1541 }
1542 else
1543 {
1544 /* average */
1545 VectorAdd( aLuxel, bLuxel, luxel );
1546 VectorScale( luxel, 0.5f, luxel );
1547
1548 /* debugging code */
1549 //% luxel[ 2 ] += 64.0f;
1550
1551 /* copy to both */
1552 VectorCopy( luxel, aLuxel );
1553 VectorCopy( luxel, bLuxel );
1554 }
1555 }
1556 }
1557
1558 /* done */
1559 return qtrue;
1560 }
1561
1562
1563
1564 /*
1565 ApproximateLuxel()
1566 determines if a single luxel is can be approximated with the interpolated vertex rgba
1567 */
1568
ApproximateLuxel(rawLightmap_t * lm,bspDrawVert_t * dv)1569 static qboolean ApproximateLuxel( rawLightmap_t *lm, bspDrawVert_t *dv ){
1570 int i, x, y, d, lightmapNum;
1571 float *luxel;
1572 vec3_t color, vertexColor;
1573 byte cb[ 4 ], vcb[ 4 ];
1574
1575
1576 /* find luxel xy coords */
1577 x = dv->lightmap[ 0 ][ 0 ] / superSample;
1578 y = dv->lightmap[ 0 ][ 1 ] / superSample;
1579 if ( x < 0 ) {
1580 x = 0;
1581 }
1582 else if ( x >= lm->w ) {
1583 x = lm->w - 1;
1584 }
1585 if ( y < 0 ) {
1586 y = 0;
1587 }
1588 else if ( y >= lm->h ) {
1589 y = lm->h - 1;
1590 }
1591
1592 /* walk list */
1593 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1594 {
1595 /* early out */
1596 if ( lm->styles[ lightmapNum ] == LS_NONE ) {
1597 continue;
1598 }
1599
1600 /* get luxel */
1601 luxel = BSP_LUXEL( lightmapNum, x, y );
1602
1603 /* ignore occluded luxels */
1604 if ( luxel[ 0 ] < 0.0f || luxel[ 1 ] < 0.0f || luxel[ 2 ] < 0.0f ) {
1605 return qtrue;
1606 }
1607
1608 /* copy, set min color and compare */
1609 VectorCopy( luxel, color );
1610 VectorCopy( dv->color[ 0 ], vertexColor );
1611
1612 /* styles are not affected by minlight */
1613 if ( lightmapNum == 0 ) {
1614 for ( i = 0; i < 3; i++ )
1615 {
1616 /* set min color */
1617 if ( color[ i ] < minLight[ i ] ) {
1618 color[ i ] = minLight[ i ];
1619 }
1620 if ( vertexColor[ i ] < minLight[ i ] ) { /* note NOT minVertexLight */
1621 vertexColor[ i ] = minLight[ i ];
1622 }
1623 }
1624 }
1625
1626 /* set to bytes */
1627 ColorToBytes( color, cb, 1.0f );
1628 ColorToBytes( vertexColor, vcb, 1.0f );
1629
1630 /* compare */
1631 for ( i = 0; i < 3; i++ )
1632 {
1633 d = cb[ i ] - vcb[ i ];
1634 if ( d < 0 ) {
1635 d *= -1;
1636 }
1637 if ( d > approximateTolerance ) {
1638 return qfalse;
1639 }
1640 }
1641 }
1642
1643 /* close enough for the girls i date */
1644 return qtrue;
1645 }
1646
1647
1648
1649 /*
1650 ApproximateTriangle()
1651 determines if a single triangle can be approximated with vertex rgba
1652 */
1653
ApproximateTriangle_r(rawLightmap_t * lm,bspDrawVert_t * dv[3])1654 static qboolean ApproximateTriangle_r( rawLightmap_t *lm, bspDrawVert_t *dv[ 3 ] ){
1655 bspDrawVert_t mid, *dv2[ 3 ];
1656 int max;
1657
1658
1659 /* approximate the vertexes */
1660 if ( ApproximateLuxel( lm, dv[ 0 ] ) == qfalse ) {
1661 return qfalse;
1662 }
1663 if ( ApproximateLuxel( lm, dv[ 1 ] ) == qfalse ) {
1664 return qfalse;
1665 }
1666 if ( ApproximateLuxel( lm, dv[ 2 ] ) == qfalse ) {
1667 return qfalse;
1668 }
1669
1670 /* subdivide calc */
1671 {
1672 int i;
1673 float dx, dy, dist, maxDist;
1674
1675
1676 /* find the longest edge and split it */
1677 max = -1;
1678 maxDist = 0;
1679 for ( i = 0; i < 3; i++ )
1680 {
1681 dx = dv[ i ]->lightmap[ 0 ][ 0 ] - dv[ ( i + 1 ) % 3 ]->lightmap[ 0 ][ 0 ];
1682 dy = dv[ i ]->lightmap[ 0 ][ 1 ] - dv[ ( i + 1 ) % 3 ]->lightmap[ 0 ][ 1 ];
1683 dist = sqrt( ( dx * dx ) + ( dy * dy ) );
1684 if ( dist > maxDist ) {
1685 maxDist = dist;
1686 max = i;
1687 }
1688 }
1689
1690 /* try to early out */
1691 if ( i < 0 || maxDist < subdivideThreshold ) {
1692 return qtrue;
1693 }
1694 }
1695
1696 /* split the longest edge and map it */
1697 LerpDrawVert( dv[ max ], dv[ ( max + 1 ) % 3 ], &mid );
1698 if ( ApproximateLuxel( lm, &mid ) == qfalse ) {
1699 return qfalse;
1700 }
1701
1702 /* recurse to first triangle */
1703 VectorCopy( dv, dv2 );
1704 dv2[ max ] = ∣
1705 if ( ApproximateTriangle_r( lm, dv2 ) == qfalse ) {
1706 return qfalse;
1707 }
1708
1709 /* recurse to second triangle */
1710 VectorCopy( dv, dv2 );
1711 dv2[ ( max + 1 ) % 3 ] = ∣
1712 return ApproximateTriangle_r( lm, dv2 );
1713 }
1714
1715
1716
1717 /*
1718 ApproximateLightmap()
1719 determines if a raw lightmap can be approximated sufficiently with vertex colors
1720 */
1721
ApproximateLightmap(rawLightmap_t * lm)1722 static qboolean ApproximateLightmap( rawLightmap_t *lm ){
1723 int n, num, i, x, y, pw[ 5 ], r;
1724 bspDrawSurface_t *ds;
1725 surfaceInfo_t *info;
1726 mesh_t src, *subdivided, *mesh;
1727 bspDrawVert_t *verts, *dv[ 3 ];
1728 qboolean approximated;
1729
1730
1731 /* approximating? */
1732 if ( approximateTolerance <= 0 ) {
1733 return qfalse;
1734 }
1735
1736 /* test for jmonroe */
1737 #if 0
1738 /* don't approx lightmaps with styled twins */
1739 if ( lm->numStyledTwins > 0 ) {
1740 return qfalse;
1741 }
1742
1743 /* don't approx lightmaps with styles */
1744 for ( i = 1; i < MAX_LIGHTMAPS; i++ )
1745 {
1746 if ( lm->styles[ i ] != LS_NONE ) {
1747 return qfalse;
1748 }
1749 }
1750 #endif
1751
1752 /* assume reduced until shadow detail is found */
1753 approximated = qtrue;
1754
1755 /* walk the list of surfaces on this raw lightmap */
1756 for ( n = 0; n < lm->numLightSurfaces; n++ )
1757 {
1758 /* get surface */
1759 num = lightSurfaces[ lm->firstLightSurface + n ];
1760 ds = &bspDrawSurfaces[ num ];
1761 info = &surfaceInfos[ num ];
1762
1763 /* assume not-reduced initially */
1764 info->approximated = qfalse;
1765
1766 /* bail if lightmap doesn't match up */
1767 if ( info->lm != lm ) {
1768 continue;
1769 }
1770
1771 /* bail if not vertex lit */
1772 if ( info->si->noVertexLight ) {
1773 continue;
1774 }
1775
1776 /* assume that surfaces whose bounding boxes is smaller than 2x samplesize will be forced to vertex */
1777 if ( ( info->maxs[ 0 ] - info->mins[ 0 ] ) <= ( 2.0f * info->sampleSize ) &&
1778 ( info->maxs[ 1 ] - info->mins[ 1 ] ) <= ( 2.0f * info->sampleSize ) &&
1779 ( info->maxs[ 2 ] - info->mins[ 2 ] ) <= ( 2.0f * info->sampleSize ) ) {
1780 info->approximated = qtrue;
1781 numSurfsVertexForced++;
1782 continue;
1783 }
1784
1785 /* handle the triangles */
1786 switch ( ds->surfaceType )
1787 {
1788 case MST_PLANAR:
1789 /* get verts */
1790 verts = yDrawVerts + ds->firstVert;
1791
1792 /* map the triangles */
1793 info->approximated = qtrue;
1794 for ( i = 0; i < ds->numIndexes && info->approximated; i += 3 )
1795 {
1796 dv[ 0 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i ] ];
1797 dv[ 1 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 1 ] ];
1798 dv[ 2 ] = &verts[ bspDrawIndexes[ ds->firstIndex + i + 2 ] ];
1799 info->approximated = ApproximateTriangle_r( lm, dv );
1800 }
1801 break;
1802
1803 case MST_PATCH:
1804 /* make a mesh from the drawsurf */
1805 src.width = ds->patchWidth;
1806 src.height = ds->patchHeight;
1807 src.verts = &yDrawVerts[ ds->firstVert ];
1808 //% subdivided = SubdivideMesh( src, 8, 512 );
1809 subdivided = SubdivideMesh2( src, info->patchIterations );
1810
1811 /* fit it to the curve and remove colinear verts on rows/columns */
1812 PutMeshOnCurve( *subdivided );
1813 mesh = RemoveLinearMeshColumnsRows( subdivided );
1814 FreeMesh( subdivided );
1815
1816 /* get verts */
1817 verts = mesh->verts;
1818
1819 /* map the mesh quads */
1820 info->approximated = qtrue;
1821 for ( y = 0; y < ( mesh->height - 1 ) && info->approximated; y++ )
1822 {
1823 for ( x = 0; x < ( mesh->width - 1 ) && info->approximated; x++ )
1824 {
1825 /* set indexes */
1826 pw[ 0 ] = x + ( y * mesh->width );
1827 pw[ 1 ] = x + ( ( y + 1 ) * mesh->width );
1828 pw[ 2 ] = x + 1 + ( ( y + 1 ) * mesh->width );
1829 pw[ 3 ] = x + 1 + ( y * mesh->width );
1830 pw[ 4 ] = x + ( y * mesh->width ); /* same as pw[ 0 ] */
1831
1832 /* set radix */
1833 r = ( x + y ) & 1;
1834
1835 /* get drawverts and map first triangle */
1836 dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1837 dv[ 1 ] = &verts[ pw[ r + 1 ] ];
1838 dv[ 2 ] = &verts[ pw[ r + 2 ] ];
1839 info->approximated = ApproximateTriangle_r( lm, dv );
1840
1841 /* get drawverts and map second triangle */
1842 dv[ 0 ] = &verts[ pw[ r + 0 ] ];
1843 dv[ 1 ] = &verts[ pw[ r + 2 ] ];
1844 dv[ 2 ] = &verts[ pw[ r + 3 ] ];
1845 if ( info->approximated ) {
1846 info->approximated = ApproximateTriangle_r( lm, dv );
1847 }
1848 }
1849 }
1850
1851 /* free the mesh */
1852 FreeMesh( mesh );
1853 break;
1854
1855 default:
1856 break;
1857 }
1858
1859 /* reduced? */
1860 if ( info->approximated == qfalse ) {
1861 approximated = qfalse;
1862 }
1863 else{
1864 numSurfsVertexApproximated++;
1865 }
1866 }
1867
1868 /* return */
1869 return approximated;
1870 }
1871
1872
1873
1874 /*
1875 TestOutLightmapStamp()
1876 tests a stamp on a given lightmap for validity
1877 */
1878
TestOutLightmapStamp(rawLightmap_t * lm,int lightmapNum,outLightmap_t * olm,int x,int y)1879 static qboolean TestOutLightmapStamp( rawLightmap_t *lm, int lightmapNum, outLightmap_t *olm, int x, int y ){
1880 int sx, sy, ox, oy, offset;
1881 float *luxel;
1882
1883
1884 /* bounds check */
1885 if ( x < 0 || y < 0 || ( x + lm->w ) > olm->customWidth || ( y + lm->h ) > olm->customHeight ) {
1886 return qfalse;
1887 }
1888
1889 /* solid lightmaps test a 1x1 stamp */
1890 if ( lm->solid[ lightmapNum ] ) {
1891 offset = ( y * olm->customWidth ) + x;
1892 if ( olm->lightBits[ offset >> 3 ] & ( 1 << ( offset & 7 ) ) ) {
1893 return qfalse;
1894 }
1895 return qtrue;
1896 }
1897
1898 /* test the stamp */
1899 for ( sy = 0; sy < lm->h; sy++ )
1900 {
1901 for ( sx = 0; sx < lm->w; sx++ )
1902 {
1903 /* get luxel */
1904 luxel = BSP_LUXEL( lightmapNum, sx, sy );
1905 if ( luxel[ 0 ] < 0.0f ) {
1906 continue;
1907 }
1908
1909 /* get bsp lightmap coords and test */
1910 ox = x + sx;
1911 oy = y + sy;
1912 offset = ( oy * olm->customWidth ) + ox;
1913 if ( olm->lightBits[ offset >> 3 ] & ( 1 << ( offset & 7 ) ) ) {
1914 return qfalse;
1915 }
1916 }
1917 }
1918
1919 /* stamp is empty */
1920 return qtrue;
1921 }
1922
1923
1924
1925 /*
1926 SetupOutLightmap()
1927 sets up an output lightmap
1928 */
1929
SetupOutLightmap(rawLightmap_t * lm,outLightmap_t * olm)1930 static void SetupOutLightmap( rawLightmap_t *lm, outLightmap_t *olm ){
1931 /* dummy check */
1932 if ( lm == NULL || olm == NULL ) {
1933 return;
1934 }
1935
1936 /* is this a "normal" bsp-stored lightmap? */
1937 if ( ( lm->customWidth == game->lightmapSize && lm->customHeight == game->lightmapSize ) || externalLightmaps ) {
1938 olm->lightmapNum = numBSPLightmaps;
1939 numBSPLightmaps++;
1940
1941 /* lightmaps are interleaved with light direction maps */
1942 if ( deluxemap ) {
1943 numBSPLightmaps++;
1944 }
1945 }
1946 else{
1947 olm->lightmapNum = -3;
1948 }
1949
1950 /* set external lightmap number */
1951 olm->extLightmapNum = -1;
1952
1953 /* set it up */
1954 olm->numLightmaps = 0;
1955 olm->customWidth = lm->customWidth;
1956 olm->customHeight = lm->customHeight;
1957 olm->freeLuxels = olm->customWidth * olm->customHeight;
1958 olm->numShaders = 0;
1959
1960 /* allocate buffers */
1961 olm->lightBits = safe_malloc( ( olm->customWidth * olm->customHeight / 8 ) + 8 );
1962 memset( olm->lightBits, 0, ( olm->customWidth * olm->customHeight / 8 ) + 8 );
1963 olm->bspLightBytes = safe_malloc( olm->customWidth * olm->customHeight * 3 );
1964 memset( olm->bspLightBytes, 0, olm->customWidth * olm->customHeight * 3 );
1965 if ( deluxemap ) {
1966 olm->bspDirBytes = safe_malloc( olm->customWidth * olm->customHeight * 3 );
1967 memset( olm->bspDirBytes, 0, olm->customWidth * olm->customHeight * 3 );
1968 }
1969 }
1970
1971
1972
1973 /*
1974 FindOutLightmaps()
1975 for a given surface lightmap, find output lightmap pages and positions for it
1976 */
1977
1978 #define LIGHTMAP_RESERVE_COUNT 1
FindOutLightmaps(rawLightmap_t * lm)1979 static void FindOutLightmaps( rawLightmap_t *lm ){
1980 int i, j, k, lightmapNum, xMax, yMax, x = -1, y = -1, sx, sy, ox, oy, offset;
1981 outLightmap_t *olm;
1982 surfaceInfo_t *info;
1983 float *luxel, *deluxel;
1984 vec3_t color, direction;
1985 byte *pixel;
1986 qboolean ok;
1987
1988
1989 /* set default lightmap number (-3 = LIGHTMAP_BY_VERTEX) */
1990 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1991 lm->outLightmapNums[ lightmapNum ] = -3;
1992
1993 /* can this lightmap be approximated with vertex color? */
1994 if ( ApproximateLightmap( lm ) ) {
1995 return;
1996 }
1997
1998 /* walk list */
1999 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2000 {
2001 /* early out */
2002 if ( lm->styles[ lightmapNum ] == LS_NONE ) {
2003 continue;
2004 }
2005
2006 /* don't store twinned lightmaps */
2007 if ( lm->twins[ lightmapNum ] != NULL ) {
2008 continue;
2009 }
2010
2011 /* if this is a styled lightmap, try some normalized locations first */
2012 ok = qfalse;
2013 if ( lightmapNum > 0 && outLightmaps != NULL ) {
2014 /* loop twice */
2015 for ( j = 0; j < 2; j++ )
2016 {
2017 /* try identical position */
2018 for ( i = 0; i < numOutLightmaps; i++ )
2019 {
2020 /* get the output lightmap */
2021 olm = &outLightmaps[ i ];
2022
2023 /* simple early out test */
2024 if ( olm->freeLuxels < lm->used ) {
2025 continue;
2026 }
2027
2028 /* don't store non-custom raw lightmaps on custom bsp lightmaps */
2029 if ( olm->customWidth != lm->customWidth ||
2030 olm->customHeight != lm->customHeight ) {
2031 continue;
2032 }
2033
2034 /* try identical */
2035 if ( j == 0 ) {
2036 x = lm->lightmapX[ 0 ];
2037 y = lm->lightmapY[ 0 ];
2038 ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );
2039 }
2040
2041 /* try shifting */
2042 else
2043 {
2044 for ( sy = -1; sy <= 1; sy++ )
2045 {
2046 for ( sx = -1; sx <= 1; sx++ )
2047 {
2048 x = lm->lightmapX[ 0 ] + sx * ( olm->customWidth >> 1 ); //% lm->w;
2049 y = lm->lightmapY[ 0 ] + sy * ( olm->customHeight >> 1 ); //% lm->h;
2050 ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );
2051
2052 if ( ok ) {
2053 break;
2054 }
2055 }
2056
2057 if ( ok ) {
2058 break;
2059 }
2060 }
2061 }
2062
2063 if ( ok ) {
2064 break;
2065 }
2066 }
2067
2068 if ( ok ) {
2069 break;
2070 }
2071 }
2072 }
2073
2074 /* try normal placement algorithm */
2075 if ( ok == qfalse ) {
2076 /* reset origin */
2077 x = 0;
2078 y = 0;
2079
2080 /* walk the list of lightmap pages */
2081 if ( lightmapSearchBlockSize <= 0 || numOutLightmaps < LIGHTMAP_RESERVE_COUNT ) {
2082 i = 0;
2083 }
2084 else{
2085 i = ( ( numOutLightmaps - LIGHTMAP_RESERVE_COUNT ) / lightmapSearchBlockSize ) * lightmapSearchBlockSize;
2086 }
2087 for ( ; i < numOutLightmaps; i++ )
2088 {
2089 /* get the output lightmap */
2090 olm = &outLightmaps[ i ];
2091
2092 /* simple early out test */
2093 if ( olm->freeLuxels < lm->used ) {
2094 continue;
2095 }
2096
2097 /* don't store non-custom raw lightmaps on custom bsp lightmaps */
2098 if ( olm->customWidth != lm->customWidth ||
2099 olm->customHeight != lm->customHeight ) {
2100 continue;
2101 }
2102
2103 /* set maxs */
2104 if ( lm->solid[ lightmapNum ] ) {
2105 xMax = olm->customWidth;
2106 yMax = olm->customHeight;
2107 }
2108 else
2109 {
2110 xMax = ( olm->customWidth - lm->w ) + 1;
2111 yMax = ( olm->customHeight - lm->h ) + 1;
2112 }
2113
2114 /* walk the origin around the lightmap */
2115 for ( y = 0; y < yMax; y++ )
2116 {
2117 for ( x = 0; x < xMax; x++ )
2118 {
2119 /* find a fine tract of lauhnd */
2120 ok = TestOutLightmapStamp( lm, lightmapNum, olm, x, y );
2121
2122 if ( ok ) {
2123 break;
2124 }
2125 }
2126
2127 if ( ok ) {
2128 break;
2129 }
2130 }
2131
2132 if ( ok ) {
2133 break;
2134 }
2135
2136 /* reset x and y */
2137 x = 0;
2138 y = 0;
2139 }
2140 }
2141
2142 /* no match? */
2143 if ( ok == qfalse ) {
2144 /* allocate LIGHTMAP_RESERVE_COUNT new output lightmaps */
2145 numOutLightmaps += LIGHTMAP_RESERVE_COUNT;
2146 olm = safe_malloc( numOutLightmaps * sizeof( outLightmap_t ) );
2147 if ( outLightmaps != NULL && numOutLightmaps > LIGHTMAP_RESERVE_COUNT ) {
2148 memcpy( olm, outLightmaps, ( numOutLightmaps - LIGHTMAP_RESERVE_COUNT ) * sizeof( outLightmap_t ) );
2149 free( outLightmaps );
2150 }
2151 outLightmaps = olm;
2152
2153 /* initialize both out lightmaps */
2154 for ( k = numOutLightmaps - LIGHTMAP_RESERVE_COUNT; k < numOutLightmaps; ++k )
2155 SetupOutLightmap( lm, &outLightmaps[ k ] );
2156
2157 /* set out lightmap */
2158 i = numOutLightmaps - LIGHTMAP_RESERVE_COUNT;
2159 olm = &outLightmaps[ i ];
2160
2161 /* set stamp xy origin to the first surface lightmap */
2162 if ( lightmapNum > 0 ) {
2163 x = lm->lightmapX[ 0 ];
2164 y = lm->lightmapY[ 0 ];
2165 }
2166 }
2167
2168 /* if this is a style-using lightmap, it must be exported */
2169 if ( lightmapNum > 0 && game->load != LoadRBSPFile ) {
2170 olm->extLightmapNum = 0;
2171 }
2172
2173 /* add the surface lightmap to the bsp lightmap */
2174 lm->outLightmapNums[ lightmapNum ] = i;
2175 lm->lightmapX[ lightmapNum ] = x;
2176 lm->lightmapY[ lightmapNum ] = y;
2177 olm->numLightmaps++;
2178
2179 /* add shaders */
2180 for ( i = 0; i < lm->numLightSurfaces; i++ )
2181 {
2182 /* get surface info */
2183 info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + i ] ];
2184
2185 /* test for shader */
2186 for ( j = 0; j < olm->numShaders; j++ )
2187 {
2188 if ( olm->shaders[ j ] == info->si ) {
2189 break;
2190 }
2191 }
2192
2193 /* if it doesn't exist, add it */
2194 if ( j >= olm->numShaders && olm->numShaders < MAX_LIGHTMAP_SHADERS ) {
2195 olm->shaders[ olm->numShaders ] = info->si;
2196 olm->numShaders++;
2197 numLightmapShaders++;
2198 }
2199 }
2200
2201 /* set maxs */
2202 if ( lm->solid[ lightmapNum ] ) {
2203 xMax = 1;
2204 yMax = 1;
2205 }
2206 else
2207 {
2208 xMax = lm->w;
2209 yMax = lm->h;
2210 }
2211
2212 /* mark the bits used */
2213 for ( y = 0; y < yMax; y++ )
2214 {
2215 for ( x = 0; x < xMax; x++ )
2216 {
2217 /* get luxel */
2218 luxel = BSP_LUXEL( lightmapNum, x, y );
2219 deluxel = BSP_DELUXEL( x, y );
2220 if ( luxel[ 0 ] < 0.0f && !lm->solid[ lightmapNum ] ) {
2221 continue;
2222 }
2223
2224 /* set minimum light */
2225 if ( lm->solid[ lightmapNum ] ) {
2226 if ( debug ) {
2227 VectorSet( color, 255.0f, 0.0f, 0.0f );
2228 }
2229 else{
2230 VectorCopy( lm->solidColor[ lightmapNum ], color );
2231 }
2232 }
2233 else{
2234 VectorCopy( luxel, color );
2235 }
2236
2237 /* styles are not affected by minlight */
2238 if ( lightmapNum == 0 ) {
2239 for ( i = 0; i < 3; i++ )
2240 {
2241 if ( color[ i ] < minLight[ i ] ) {
2242 color[ i ] = minLight[ i ];
2243 }
2244 }
2245 }
2246
2247 /* get bsp lightmap coords */
2248 ox = x + lm->lightmapX[ lightmapNum ];
2249 oy = y + lm->lightmapY[ lightmapNum ];
2250 offset = ( oy * olm->customWidth ) + ox;
2251
2252 /* flag pixel as used */
2253 olm->lightBits[ offset >> 3 ] |= ( 1 << ( offset & 7 ) );
2254 olm->freeLuxels--;
2255
2256 /* store color */
2257 pixel = olm->bspLightBytes + ( ( ( oy * olm->customWidth ) + ox ) * 3 );
2258 ColorToBytes( color, pixel, lm->brightness );
2259
2260 /* store direction */
2261 if ( deluxemap ) {
2262 /* normalize average light direction */
2263 pixel = olm->bspDirBytes + ( ( ( oy * olm->customWidth ) + ox ) * 3 );
2264 VectorScale( deluxel, 1000.0f, direction );
2265 VectorNormalize( direction, direction );
2266 VectorScale( direction, 127.5f, direction );
2267 for ( i = 0; i < 3; i++ )
2268 pixel[ i ] = (byte)( 127.5f + direction[ i ] );
2269 }
2270 }
2271 }
2272 }
2273 }
2274
2275
2276
2277 /*
2278 CompareRawLightmap()
2279 compare function for qsort()
2280 */
2281
CompareRawLightmap(const void * a,const void * b)2282 static int CompareRawLightmap( const void *a, const void *b ){
2283 rawLightmap_t *alm, *blm;
2284 surfaceInfo_t *aInfo, *bInfo;
2285 int i, min, diff;
2286
2287
2288 /* get lightmaps */
2289 alm = &rawLightmaps[ *( (const int*) a ) ];
2290 blm = &rawLightmaps[ *( (const int*) b ) ];
2291
2292 /* get min number of surfaces */
2293 min = ( alm->numLightSurfaces < blm->numLightSurfaces ? alm->numLightSurfaces : blm->numLightSurfaces );
2294
2295 /* iterate */
2296 for ( i = 0; i < min; i++ )
2297 {
2298 /* get surface info */
2299 aInfo = &surfaceInfos[ lightSurfaces[ alm->firstLightSurface + i ] ];
2300 bInfo = &surfaceInfos[ lightSurfaces[ blm->firstLightSurface + i ] ];
2301
2302 /* compare shader names */
2303 diff = strcmp( aInfo->si->shader, bInfo->si->shader );
2304 if ( diff != 0 ) {
2305 return diff;
2306 }
2307 }
2308
2309 /* test style count */
2310 diff = 0;
2311 for ( i = 0; i < MAX_LIGHTMAPS; i++ )
2312 diff += blm->styles[ i ] - alm->styles[ i ];
2313 if ( diff ) {
2314 return diff;
2315 }
2316
2317 /* compare size */
2318 diff = ( blm->w * blm->h ) - ( alm->w * alm->h );
2319 if ( diff != 0 ) {
2320 return diff;
2321 }
2322
2323 /* must be equivalent */
2324 return 0;
2325 }
2326
FillOutLightmap(outLightmap_t * olm)2327 void FillOutLightmap( outLightmap_t *olm ){
2328 int x, y;
2329 int ofs;
2330 vec3_t dir_sum, light_sum;
2331 int cnt, filled;
2332 byte *lightBitsNew = NULL;
2333 byte *lightBytesNew = NULL;
2334 byte *dirBytesNew = NULL;
2335
2336 lightBitsNew = safe_malloc( ( olm->customWidth * olm->customHeight + 8 ) / 8 );
2337 lightBytesNew = safe_malloc( olm->customWidth * olm->customHeight * 3 );
2338 if ( deluxemap ) {
2339 dirBytesNew = safe_malloc( olm->customWidth * olm->customHeight * 3 );
2340 }
2341
2342 /*
2343 memset(olm->lightBits, 0, (olm->customWidth * olm->customHeight + 8) / 8);
2344 olm->lightBits[0] |= 1;
2345 olm->lightBits[(10 * olm->customWidth + 30) >> 3] |= 1 << ((10 * olm->customWidth + 30) & 7);
2346 memset(olm->bspLightBytes, 0, olm->customWidth * olm->customHeight * 3);
2347 olm->bspLightBytes[0] = 255;
2348 olm->bspLightBytes[(10 * olm->customWidth + 30) * 3 + 2] = 255;
2349 */
2350
2351 memcpy( lightBitsNew, olm->lightBits, ( olm->customWidth * olm->customHeight + 8 ) / 8 );
2352 memcpy( lightBytesNew, olm->bspLightBytes, olm->customWidth * olm->customHeight * 3 );
2353 if ( deluxemap ) {
2354 memcpy( dirBytesNew, olm->bspDirBytes, olm->customWidth * olm->customHeight * 3 );
2355 }
2356
2357 for (;; )
2358 {
2359 filled = 0;
2360 for ( y = 0; y < olm->customHeight; ++y )
2361 {
2362 for ( x = 0; x < olm->customWidth; ++x )
2363 {
2364 ofs = y * olm->customWidth + x;
2365 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2366 continue;
2367 }
2368 cnt = 0;
2369 VectorClear( dir_sum );
2370 VectorClear( light_sum );
2371
2372 /* try all four neighbors */
2373 ofs = ( ( y + olm->customHeight - 1 ) % olm->customHeight ) * olm->customWidth + x;
2374 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2375 ++cnt;
2376 VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2377 if ( deluxemap ) {
2378 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2379 }
2380 }
2381
2382 ofs = ( ( y + 1 ) % olm->customHeight ) * olm->customWidth + x;
2383 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2384 ++cnt;
2385 VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2386 if ( deluxemap ) {
2387 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2388 }
2389 }
2390
2391 ofs = y * olm->customWidth + ( x + olm->customWidth - 1 ) % olm->customWidth;
2392 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2393 ++cnt;
2394 VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2395 if ( deluxemap ) {
2396 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2397 }
2398 }
2399
2400 ofs = y * olm->customWidth + ( x + 1 ) % olm->customWidth;
2401 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2402 ++cnt;
2403 VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2404 if ( deluxemap ) {
2405 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2406 }
2407 }
2408
2409 if ( cnt ) {
2410 ++filled;
2411 ofs = y * olm->customWidth + x;
2412 lightBitsNew[ofs >> 3] |= ( 1 << ( ofs & 7 ) );
2413 VectorScale( light_sum, 1.0 / cnt, lightBytesNew + ofs * 3 );
2414 if ( deluxemap ) {
2415 VectorScale( dir_sum, 1.0 / cnt, dirBytesNew + ofs * 3 );
2416 }
2417 }
2418 }
2419 }
2420
2421 if ( !filled ) {
2422 break;
2423 }
2424
2425 memcpy( olm->lightBits, lightBitsNew, ( olm->customWidth * olm->customHeight + 8 ) / 8 );
2426 memcpy( olm->bspLightBytes, lightBytesNew, olm->customWidth * olm->customHeight * 3 );
2427 if ( deluxemap ) {
2428 memcpy( olm->bspDirBytes, dirBytesNew, olm->customWidth * olm->customHeight * 3 );
2429 }
2430 }
2431
2432 free( lightBitsNew );
2433 free( lightBytesNew );
2434 if ( deluxemap ) {
2435 free( dirBytesNew );
2436 }
2437 }
2438
2439 /*
2440 StoreSurfaceLightmaps()
2441 stores the surface lightmaps into the bsp as byte rgb triplets
2442 */
2443
StoreSurfaceLightmaps(void)2444 void StoreSurfaceLightmaps( void ){
2445 int i, j, k, x, y, lx, ly, sx, sy, *cluster, mappedSamples;
2446 int style, size, lightmapNum, lightmapNum2;
2447 float *normal, *luxel, *bspLuxel, *bspLuxel2, *radLuxel, samples, occludedSamples;
2448 vec3_t sample, occludedSample, dirSample, colorMins, colorMaxs;
2449 float *deluxel, *bspDeluxel, *bspDeluxel2;
2450 byte *lb;
2451 int numUsed, numTwins, numTwinLuxels, numStored;
2452 float lmx, lmy, efficiency;
2453 vec3_t color;
2454 bspDrawSurface_t *ds, *parent, dsTemp;
2455 surfaceInfo_t *info;
2456 rawLightmap_t *lm, *lm2;
2457 outLightmap_t *olm;
2458 bspDrawVert_t *dv, *ydv, *dvParent;
2459 char dirname[ 1024 ], filename[ 1024 ];
2460 shaderInfo_t *csi;
2461 char lightmapName[ 128 ];
2462 const char *rgbGenValues[ 256 ];
2463 const char *alphaGenValues[ 256 ];
2464
2465
2466 /* note it */
2467 Sys_Printf( "--- StoreSurfaceLightmaps ---\n" );
2468
2469 /* setup */
2470 if ( lmCustomDir ) {
2471 strcpy( dirname, lmCustomDir );
2472 }
2473 else
2474 {
2475 strcpy( dirname, source );
2476 StripExtension( dirname );
2477 }
2478 memset( rgbGenValues, 0, sizeof( rgbGenValues ) );
2479 memset( alphaGenValues, 0, sizeof( alphaGenValues ) );
2480
2481 /* -----------------------------------------------------------------
2482 average the sampled luxels into the bsp luxels
2483 ----------------------------------------------------------------- */
2484
2485 /* note it */
2486 Sys_Printf( "Subsampling..." );
2487
2488 /* walk the list of raw lightmaps */
2489 numUsed = 0;
2490 numTwins = 0;
2491 numTwinLuxels = 0;
2492 numSolidLightmaps = 0;
2493 for ( i = 0; i < numRawLightmaps; i++ )
2494 {
2495 /* get lightmap */
2496 lm = &rawLightmaps[ i ];
2497
2498 /* walk individual lightmaps */
2499 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2500 {
2501 /* early outs */
2502 if ( lm->superLuxels[ lightmapNum ] == NULL ) {
2503 continue;
2504 }
2505
2506 /* allocate bsp luxel storage */
2507 if ( lm->bspLuxels[ lightmapNum ] == NULL ) {
2508 size = lm->w * lm->h * BSP_LUXEL_SIZE * sizeof( float );
2509 lm->bspLuxels[ lightmapNum ] = safe_malloc( size );
2510 memset( lm->bspLuxels[ lightmapNum ], 0, size );
2511 }
2512
2513 /* allocate radiosity lightmap storage */
2514 if ( bounce ) {
2515 size = lm->w * lm->h * RAD_LUXEL_SIZE * sizeof( float );
2516 if ( lm->radLuxels[ lightmapNum ] == NULL ) {
2517 lm->radLuxels[ lightmapNum ] = safe_malloc( size );
2518 }
2519 memset( lm->radLuxels[ lightmapNum ], 0, size );
2520 }
2521
2522 /* average supersampled luxels */
2523 for ( y = 0; y < lm->h; y++ )
2524 {
2525 for ( x = 0; x < lm->w; x++ )
2526 {
2527 /* subsample */
2528 samples = 0.0f;
2529 occludedSamples = 0.0f;
2530 mappedSamples = 0;
2531 VectorClear( sample );
2532 VectorClear( occludedSample );
2533 VectorClear( dirSample );
2534 for ( ly = 0; ly < superSample; ly++ )
2535 {
2536 for ( lx = 0; lx < superSample; lx++ )
2537 {
2538 /* sample luxel */
2539 sx = x * superSample + lx;
2540 sy = y * superSample + ly;
2541 luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2542 deluxel = SUPER_DELUXEL( sx, sy );
2543 normal = SUPER_NORMAL( sx, sy );
2544 cluster = SUPER_CLUSTER( sx, sy );
2545
2546 /* sample deluxemap */
2547 if ( deluxemap && lightmapNum == 0 ) {
2548 VectorAdd( dirSample, deluxel, dirSample );
2549 }
2550
2551 /* keep track of used/occluded samples */
2552 if ( *cluster != CLUSTER_UNMAPPED ) {
2553 mappedSamples++;
2554 }
2555
2556 /* handle lightmap border? */
2557 if ( lightmapBorder && ( sx == 0 || sx == ( lm->sw - 1 ) || sy == 0 || sy == ( lm->sh - 1 ) ) && luxel[ 3 ] > 0.0f ) {
2558 VectorSet( sample, 255.0f, 0.0f, 0.0f );
2559 samples += 1.0f;
2560 }
2561
2562 /* handle debug */
2563 else if ( debug && *cluster < 0 ) {
2564 if ( *cluster == CLUSTER_UNMAPPED ) {
2565 VectorSet( luxel, 255, 204, 0 );
2566 }
2567 else if ( *cluster == CLUSTER_OCCLUDED ) {
2568 VectorSet( luxel, 255, 0, 255 );
2569 }
2570 else if ( *cluster == CLUSTER_FLOODED ) {
2571 VectorSet( luxel, 0, 32, 255 );
2572 }
2573 VectorAdd( occludedSample, luxel, occludedSample );
2574 occludedSamples += 1.0f;
2575 }
2576
2577 /* normal luxel handling */
2578 else if ( luxel[ 3 ] > 0.0f ) {
2579 /* handle lit or flooded luxels */
2580 if ( *cluster > 0 || *cluster == CLUSTER_FLOODED ) {
2581 VectorAdd( sample, luxel, sample );
2582 samples += luxel[ 3 ];
2583 }
2584
2585 /* handle occluded or unmapped luxels */
2586 else
2587 {
2588 VectorAdd( occludedSample, luxel, occludedSample );
2589 occludedSamples += luxel[ 3 ];
2590 }
2591
2592 /* handle style debugging */
2593 if ( debug && lightmapNum > 0 && x < 2 && y < 2 ) {
2594 VectorCopy( debugColors[ 0 ], sample );
2595 samples = 1;
2596 }
2597 }
2598 }
2599 }
2600
2601 /* only use occluded samples if necessary */
2602 if ( samples <= 0.0f ) {
2603 VectorCopy( occludedSample, sample );
2604 samples = occludedSamples;
2605 }
2606
2607 /* get luxels */
2608 luxel = SUPER_LUXEL( lightmapNum, x, y );
2609 deluxel = SUPER_DELUXEL( x, y );
2610
2611 /* store light direction */
2612 if ( deluxemap && lightmapNum == 0 ) {
2613 VectorCopy( dirSample, deluxel );
2614 }
2615
2616 /* store the sample back in super luxels */
2617 if ( samples > 0.01f ) {
2618 VectorScale( sample, ( 1.0f / samples ), luxel );
2619 luxel[ 3 ] = 1.0f;
2620 }
2621
2622 /* if any samples were mapped in any way, store ambient color */
2623 else if ( mappedSamples > 0 ) {
2624 if ( lightmapNum == 0 ) {
2625 VectorCopy( ambientColor, luxel );
2626 }
2627 else{
2628 VectorClear( luxel );
2629 }
2630 luxel[ 3 ] = 1.0f;
2631 }
2632
2633 /* store a bogus value to be fixed later */
2634 else
2635 {
2636 VectorClear( luxel );
2637 luxel[ 3 ] = -1.0f;
2638 }
2639 }
2640 }
2641
2642 /* setup */
2643 lm->used = 0;
2644 ClearBounds( colorMins, colorMaxs );
2645
2646 /* clean up and store into bsp luxels */
2647 for ( y = 0; y < lm->h; y++ )
2648 {
2649 for ( x = 0; x < lm->w; x++ )
2650 {
2651 /* get luxels */
2652 luxel = SUPER_LUXEL( lightmapNum, x, y );
2653 deluxel = SUPER_DELUXEL( x, y );
2654
2655 /* copy light direction */
2656 if ( deluxemap && lightmapNum == 0 ) {
2657 VectorCopy( deluxel, dirSample );
2658 }
2659
2660 /* is this a valid sample? */
2661 if ( luxel[ 3 ] > 0.0f ) {
2662 VectorCopy( luxel, sample );
2663 samples = luxel[ 3 ];
2664 numUsed++;
2665 lm->used++;
2666
2667 /* fix negative samples */
2668 for ( j = 0; j < 3; j++ )
2669 {
2670 if ( sample[ j ] < 0.0f ) {
2671 sample[ j ] = 0.0f;
2672 }
2673 }
2674 }
2675 else
2676 {
2677 /* nick an average value from the neighbors */
2678 VectorClear( sample );
2679 VectorClear( dirSample );
2680 samples = 0.0f;
2681
2682 /* fixme: why is this disabled?? */
2683 for ( sy = ( y - 1 ); sy <= ( y + 1 ); sy++ )
2684 {
2685 if ( sy < 0 || sy >= lm->h ) {
2686 continue;
2687 }
2688
2689 for ( sx = ( x - 1 ); sx <= ( x + 1 ); sx++ )
2690 {
2691 if ( sx < 0 || sx >= lm->w || ( sx == x && sy == y ) ) {
2692 continue;
2693 }
2694
2695 /* get neighbor's particulars */
2696 luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2697 if ( luxel[ 3 ] < 0.0f ) {
2698 continue;
2699 }
2700 VectorAdd( sample, luxel, sample );
2701 samples += luxel[ 3 ];
2702 }
2703 }
2704
2705 /* no samples? */
2706 if ( samples == 0.0f ) {
2707 VectorSet( sample, -1.0f, -1.0f, -1.0f );
2708 samples = 1.0f;
2709 }
2710 else
2711 {
2712 numUsed++;
2713 lm->used++;
2714
2715 /* fix negative samples */
2716 for ( j = 0; j < 3; j++ )
2717 {
2718 if ( sample[ j ] < 0.0f ) {
2719 sample[ j ] = 0.0f;
2720 }
2721 }
2722 }
2723 }
2724
2725 /* scale the sample */
2726 VectorScale( sample, ( 1.0f / samples ), sample );
2727
2728 /* store the sample in the radiosity luxels */
2729 if ( bounce > 0 ) {
2730 radLuxel = RAD_LUXEL( lightmapNum, x, y );
2731 VectorCopy( sample, radLuxel );
2732
2733 /* if only storing bounced light, early out here */
2734 if ( bounceOnly && !bouncing ) {
2735 continue;
2736 }
2737 }
2738
2739 /* store the sample in the bsp luxels */
2740 bspLuxel = BSP_LUXEL( lightmapNum, x, y );
2741 bspDeluxel = BSP_DELUXEL( x, y );
2742
2743 VectorAdd( bspLuxel, sample, bspLuxel );
2744 if ( deluxemap && lightmapNum == 0 ) {
2745 VectorAdd( bspDeluxel, dirSample, bspDeluxel );
2746 }
2747
2748 /* add color to bounds for solid checking */
2749 if ( samples > 0.0f ) {
2750 AddPointToBounds( bspLuxel, colorMins, colorMaxs );
2751 }
2752 }
2753 }
2754
2755 /* set solid color */
2756 lm->solid[ lightmapNum ] = qfalse;
2757 VectorAdd( colorMins, colorMaxs, lm->solidColor[ lightmapNum ] );
2758 VectorScale( lm->solidColor[ lightmapNum ], 0.5f, lm->solidColor[ lightmapNum ] );
2759
2760 /* nocollapse prevents solid lightmaps */
2761 if ( noCollapse == qfalse ) {
2762 /* check solid color */
2763 VectorSubtract( colorMaxs, colorMins, sample );
2764 if ( ( sample[ 0 ] <= SOLID_EPSILON && sample[ 1 ] <= SOLID_EPSILON && sample[ 2 ] <= SOLID_EPSILON ) ||
2765 ( lm->w <= 2 && lm->h <= 2 ) ) { /* small lightmaps get forced to solid color */
2766 /* set to solid */
2767 VectorCopy( colorMins, lm->solidColor[ lightmapNum ] );
2768 lm->solid[ lightmapNum ] = qtrue;
2769 numSolidLightmaps++;
2770 }
2771
2772 /* if all lightmaps aren't solid, then none of them are solid */
2773 if ( lm->solid[ lightmapNum ] != lm->solid[ 0 ] ) {
2774 for ( y = 0; y < MAX_LIGHTMAPS; y++ )
2775 {
2776 if ( lm->solid[ y ] ) {
2777 numSolidLightmaps--;
2778 }
2779 lm->solid[ y ] = qfalse;
2780 }
2781 }
2782 }
2783
2784 /* wrap bsp luxels if necessary */
2785 if ( lm->wrap[ 0 ] ) {
2786 for ( y = 0; y < lm->h; y++ )
2787 {
2788 bspLuxel = BSP_LUXEL( lightmapNum, 0, y );
2789 bspLuxel2 = BSP_LUXEL( lightmapNum, lm->w - 1, y );
2790 VectorAdd( bspLuxel, bspLuxel2, bspLuxel );
2791 VectorScale( bspLuxel, 0.5f, bspLuxel );
2792 VectorCopy( bspLuxel, bspLuxel2 );
2793 if ( deluxemap && lightmapNum == 0 ) {
2794 bspDeluxel = BSP_DELUXEL( 0, y );
2795 bspDeluxel2 = BSP_DELUXEL( lm->w - 1, y );
2796 VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel );
2797 VectorScale( bspDeluxel, 0.5f, bspDeluxel );
2798 VectorCopy( bspDeluxel, bspDeluxel2 );
2799 }
2800 }
2801 }
2802 if ( lm->wrap[ 1 ] ) {
2803 for ( x = 0; x < lm->w; x++ )
2804 {
2805 bspLuxel = BSP_LUXEL( lightmapNum, x, 0 );
2806 bspLuxel2 = BSP_LUXEL( lightmapNum, x, lm->h - 1 );
2807 VectorAdd( bspLuxel, bspLuxel2, bspLuxel );
2808 VectorScale( bspLuxel, 0.5f, bspLuxel );
2809 VectorCopy( bspLuxel, bspLuxel2 );
2810 if ( deluxemap && lightmapNum == 0 ) {
2811 bspDeluxel = BSP_DELUXEL( x, 0 );
2812 bspDeluxel2 = BSP_DELUXEL( x, lm->h - 1 );
2813 VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel );
2814 VectorScale( bspDeluxel, 0.5f, bspDeluxel );
2815 VectorCopy( bspDeluxel, bspDeluxel2 );
2816 }
2817 }
2818 }
2819 }
2820 }
2821
2822 /* -----------------------------------------------------------------
2823 convert modelspace deluxemaps to tangentspace
2824 ----------------------------------------------------------------- */
2825 /* note it */
2826 if ( !bouncing ) {
2827 if ( deluxemap && deluxemode == 1 ) {
2828 vec3_t worldUp, myNormal, myTangent, myBinormal;
2829 float dist;
2830
2831 Sys_Printf( "converting..." );
2832
2833 for ( i = 0; i < numRawLightmaps; i++ )
2834 {
2835 /* get lightmap */
2836 lm = &rawLightmaps[ i ];
2837
2838 /* walk lightmap samples */
2839 for ( y = 0; y < lm->sh; y++ )
2840 {
2841 for ( x = 0; x < lm->sw; x++ )
2842 {
2843 /* get normal and deluxel */
2844 normal = SUPER_NORMAL( x, y );
2845 cluster = SUPER_CLUSTER( x, y );
2846 bspDeluxel = BSP_DELUXEL( x, y );
2847 deluxel = SUPER_DELUXEL( x, y );
2848
2849 /* get normal */
2850 VectorSet( myNormal, normal[0], normal[1], normal[2] );
2851
2852 /* get tangent vectors */
2853 if ( myNormal[ 0 ] == 0.0f && myNormal[ 1 ] == 0.0f ) {
2854 if ( myNormal[ 2 ] == 1.0f ) {
2855 VectorSet( myTangent, 1.0f, 0.0f, 0.0f );
2856 VectorSet( myBinormal, 0.0f, 1.0f, 0.0f );
2857 }
2858 else if ( myNormal[ 2 ] == -1.0f ) {
2859 VectorSet( myTangent, -1.0f, 0.0f, 0.0f );
2860 VectorSet( myBinormal, 0.0f, 1.0f, 0.0f );
2861 }
2862 }
2863 else
2864 {
2865 VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
2866 CrossProduct( myNormal, worldUp, myTangent );
2867 VectorNormalize( myTangent, myTangent );
2868 CrossProduct( myTangent, myNormal, myBinormal );
2869 VectorNormalize( myBinormal, myBinormal );
2870 }
2871
2872 /* project onto plane */
2873 dist = -DotProduct( myTangent, myNormal );
2874 VectorMA( myTangent, dist, myNormal, myTangent );
2875 dist = -DotProduct( myBinormal, myNormal );
2876 VectorMA( myBinormal, dist, myNormal, myBinormal );
2877
2878 /* renormalize */
2879 VectorNormalize( myTangent, myTangent );
2880 VectorNormalize( myBinormal, myBinormal );
2881
2882 /* convert modelspace deluxel to tangentspace */
2883 dirSample[0] = bspDeluxel[0];
2884 dirSample[1] = bspDeluxel[1];
2885 dirSample[2] = bspDeluxel[2];
2886 VectorNormalize( dirSample, dirSample );
2887
2888 /* fix tangents to world matrix */
2889 if ( myNormal[0] > 0 || myNormal[1] < 0 || myNormal[2] < 0 ) {
2890 VectorNegate( myTangent, myTangent );
2891 }
2892
2893 /* build tangentspace vectors */
2894 bspDeluxel[0] = DotProduct( dirSample, myTangent );
2895 bspDeluxel[1] = DotProduct( dirSample, myBinormal );
2896 bspDeluxel[2] = DotProduct( dirSample, myNormal );
2897 }
2898 }
2899 }
2900 }
2901 }
2902
2903 /* -----------------------------------------------------------------
2904 blend lightmaps
2905 ----------------------------------------------------------------- */
2906
2907 #ifdef sdfsdfwq312323
2908 /* note it */
2909 Sys_Printf( "blending..." );
2910
2911 for ( i = 0; i < numRawLightmaps; i++ )
2912 {
2913 vec3_t myColor;
2914 float myBrightness;
2915
2916 /* get lightmap */
2917 lm = &rawLightmaps[ i ];
2918
2919 /* walk individual lightmaps */
2920 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2921 {
2922 /* early outs */
2923 if ( lm->superLuxels[ lightmapNum ] == NULL ) {
2924 continue;
2925 }
2926
2927 /* walk lightmap samples */
2928 for ( y = 0; y < lm->sh; y++ )
2929 {
2930 for ( x = 0; x < lm->sw; x++ )
2931 {
2932 /* get luxel */
2933 bspLuxel = BSP_LUXEL( lightmapNum, x, y );
2934
2935 /* get color */
2936 VectorNormalize( bspLuxel, myColor );
2937 myBrightness = VectorLength( bspLuxel );
2938 myBrightness *= ( 1 / 127.0f );
2939 myBrightness = myBrightness * myBrightness;
2940 myBrightness *= 127.0f;
2941 VectorScale( myColor, myBrightness, bspLuxel );
2942 }
2943 }
2944 }
2945 }
2946 #endif
2947
2948 /* -----------------------------------------------------------------
2949 collapse non-unique lightmaps
2950 ----------------------------------------------------------------- */
2951
2952 if ( noCollapse == qfalse && deluxemap == qfalse ) {
2953 /* note it */
2954 Sys_Printf( "collapsing..." );
2955
2956 /* set all twin refs to null */
2957 for ( i = 0; i < numRawLightmaps; i++ )
2958 {
2959 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2960 {
2961 rawLightmaps[ i ].twins[ lightmapNum ] = NULL;
2962 rawLightmaps[ i ].twinNums[ lightmapNum ] = -1;
2963 rawLightmaps[ i ].numStyledTwins = 0;
2964 }
2965 }
2966
2967 /* walk the list of raw lightmaps */
2968 for ( i = 0; i < numRawLightmaps; i++ )
2969 {
2970 /* get lightmap */
2971 lm = &rawLightmaps[ i ];
2972
2973 /* walk lightmaps */
2974 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2975 {
2976 /* early outs */
2977 if ( lm->bspLuxels[ lightmapNum ] == NULL ||
2978 lm->twins[ lightmapNum ] != NULL ) {
2979 continue;
2980 }
2981
2982 /* find all lightmaps that are virtually identical to this one */
2983 for ( j = i + 1; j < numRawLightmaps; j++ )
2984 {
2985 /* get lightmap */
2986 lm2 = &rawLightmaps[ j ];
2987
2988 /* walk lightmaps */
2989 for ( lightmapNum2 = 0; lightmapNum2 < MAX_LIGHTMAPS; lightmapNum2++ )
2990 {
2991 /* early outs */
2992 if ( lm2->bspLuxels[ lightmapNum2 ] == NULL ||
2993 lm2->twins[ lightmapNum2 ] != NULL ) {
2994 continue;
2995 }
2996
2997 /* compare them */
2998 if ( CompareBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ) ) {
2999 /* merge and set twin */
3000 if ( MergeBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ) ) {
3001 lm2->twins[ lightmapNum2 ] = lm;
3002 lm2->twinNums[ lightmapNum2 ] = lightmapNum;
3003 numTwins++;
3004 numTwinLuxels += ( lm->w * lm->h );
3005
3006 /* count styled twins */
3007 if ( lightmapNum > 0 ) {
3008 lm->numStyledTwins++;
3009 }
3010 }
3011 }
3012 }
3013 }
3014 }
3015 }
3016 }
3017
3018 /* -----------------------------------------------------------------
3019 sort raw lightmaps by shader
3020 ----------------------------------------------------------------- */
3021
3022 /* note it */
3023 Sys_Printf( "sorting..." );
3024
3025 /* allocate a new sorted list */
3026 if ( sortLightmaps == NULL ) {
3027 sortLightmaps = safe_malloc( numRawLightmaps * sizeof( int ) );
3028 }
3029
3030 /* fill it out and sort it */
3031 for ( i = 0; i < numRawLightmaps; i++ )
3032 sortLightmaps[ i ] = i;
3033 qsort( sortLightmaps, numRawLightmaps, sizeof( int ), CompareRawLightmap );
3034
3035 /* -----------------------------------------------------------------
3036 allocate output lightmaps
3037 ----------------------------------------------------------------- */
3038
3039 /* note it */
3040 Sys_Printf( "allocating..." );
3041
3042 /* kill all existing output lightmaps */
3043 if ( outLightmaps != NULL ) {
3044 for ( i = 0; i < numOutLightmaps; i++ )
3045 {
3046 free( outLightmaps[ i ].lightBits );
3047 free( outLightmaps[ i ].bspLightBytes );
3048 }
3049 free( outLightmaps );
3050 outLightmaps = NULL;
3051 }
3052
3053 numLightmapShaders = 0;
3054 numOutLightmaps = 0;
3055 numBSPLightmaps = 0;
3056 numExtLightmaps = 0;
3057
3058 /* find output lightmap */
3059 for ( i = 0; i < numRawLightmaps; i++ )
3060 {
3061 lm = &rawLightmaps[ sortLightmaps[ i ] ];
3062 FindOutLightmaps( lm );
3063 }
3064
3065 /* set output numbers in twinned lightmaps */
3066 for ( i = 0; i < numRawLightmaps; i++ )
3067 {
3068 /* get lightmap */
3069 lm = &rawLightmaps[ sortLightmaps[ i ] ];
3070
3071 /* walk lightmaps */
3072 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3073 {
3074 /* get twin */
3075 lm2 = lm->twins[ lightmapNum ];
3076 if ( lm2 == NULL ) {
3077 continue;
3078 }
3079 lightmapNum2 = lm->twinNums[ lightmapNum ];
3080
3081 /* find output lightmap from twin */
3082 lm->outLightmapNums[ lightmapNum ] = lm2->outLightmapNums[ lightmapNum2 ];
3083 lm->lightmapX[ lightmapNum ] = lm2->lightmapX[ lightmapNum2 ];
3084 lm->lightmapY[ lightmapNum ] = lm2->lightmapY[ lightmapNum2 ];
3085 }
3086 }
3087
3088 /* -----------------------------------------------------------------
3089 store output lightmaps
3090 ----------------------------------------------------------------- */
3091
3092 /* note it */
3093 Sys_Printf( "storing..." );
3094
3095 /* count the bsp lightmaps and allocate space */
3096 if ( bspLightBytes != NULL ) {
3097 free( bspLightBytes );
3098 }
3099 if ( numBSPLightmaps == 0 || externalLightmaps ) {
3100 numBSPLightBytes = 0;
3101 bspLightBytes = NULL;
3102 }
3103 else
3104 {
3105 numBSPLightBytes = ( numBSPLightmaps * game->lightmapSize * game->lightmapSize * 3 );
3106 bspLightBytes = safe_malloc( numBSPLightBytes );
3107 memset( bspLightBytes, 0, numBSPLightBytes );
3108 }
3109
3110 /* walk the list of output lightmaps */
3111 for ( i = 0; i < numOutLightmaps; i++ )
3112 {
3113 /* get output lightmap */
3114 olm = &outLightmaps[ i ];
3115
3116 /* fill output lightmap */
3117 if ( lightmapFill ) {
3118 FillOutLightmap( olm );
3119 }
3120
3121 /* is this a valid bsp lightmap? */
3122 if ( olm->lightmapNum >= 0 && !externalLightmaps ) {
3123 /* copy lighting data */
3124 lb = bspLightBytes + ( olm->lightmapNum * game->lightmapSize * game->lightmapSize * 3 );
3125 memcpy( lb, olm->bspLightBytes, game->lightmapSize * game->lightmapSize * 3 );
3126
3127 /* copy direction data */
3128 if ( deluxemap ) {
3129 lb = bspLightBytes + ( ( olm->lightmapNum + 1 ) * game->lightmapSize * game->lightmapSize * 3 );
3130 memcpy( lb, olm->bspDirBytes, game->lightmapSize * game->lightmapSize * 3 );
3131 }
3132 }
3133
3134 /* external lightmap? */
3135 if ( olm->lightmapNum < 0 || olm->extLightmapNum >= 0 || externalLightmaps ) {
3136 /* make a directory for the lightmaps */
3137 Q_mkdir( dirname );
3138
3139 /* set external lightmap number */
3140 olm->extLightmapNum = numExtLightmaps;
3141
3142 /* write lightmap */
3143 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
3144 Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
3145 WriteTGA24( filename, olm->bspLightBytes, olm->customWidth, olm->customHeight, qtrue );
3146 numExtLightmaps++;
3147
3148 /* write deluxemap */
3149 if ( deluxemap ) {
3150 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
3151 Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
3152 WriteTGA24( filename, olm->bspDirBytes, olm->customWidth, olm->customHeight, qtrue );
3153 numExtLightmaps++;
3154
3155 if ( debugDeluxemap ) {
3156 olm->extLightmapNum++;
3157 }
3158 }
3159 }
3160 }
3161
3162 if ( numExtLightmaps > 0 ) {
3163 Sys_Printf( "\n" );
3164 }
3165
3166 /* delete unused external lightmaps */
3167 for ( i = numExtLightmaps; i; i++ )
3168 {
3169 /* determine if file exists */
3170 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, i );
3171 if ( !FileExists( filename ) ) {
3172 break;
3173 }
3174
3175 /* delete it */
3176 remove( filename );
3177 }
3178
3179 /* -----------------------------------------------------------------
3180 project the lightmaps onto the bsp surfaces
3181 ----------------------------------------------------------------- */
3182
3183 /* note it */
3184 Sys_Printf( "projecting..." );
3185
3186 /* walk the list of surfaces */
3187 for ( i = 0; i < numBSPDrawSurfaces; i++ )
3188 {
3189 /* get the surface and info */
3190 ds = &bspDrawSurfaces[ i ];
3191 info = &surfaceInfos[ i ];
3192 lm = info->lm;
3193 olm = NULL;
3194
3195 /* handle surfaces with identical parent */
3196 if ( info->parentSurfaceNum >= 0 ) {
3197 /* preserve original data and get parent */
3198 parent = &bspDrawSurfaces[ info->parentSurfaceNum ];
3199 memcpy( &dsTemp, ds, sizeof( *ds ) );
3200
3201 /* overwrite child with parent data */
3202 memcpy( ds, parent, sizeof( *ds ) );
3203
3204 /* restore key parts */
3205 ds->fogNum = dsTemp.fogNum;
3206 ds->firstVert = dsTemp.firstVert;
3207 ds->firstIndex = dsTemp.firstIndex;
3208 memcpy( ds->lightmapVecs, dsTemp.lightmapVecs, sizeof( dsTemp.lightmapVecs ) );
3209
3210 /* set vertex data */
3211 dv = &bspDrawVerts[ ds->firstVert ];
3212 dvParent = &bspDrawVerts[ parent->firstVert ];
3213 for ( j = 0; j < ds->numVerts; j++ )
3214 {
3215 memcpy( dv[ j ].lightmap, dvParent[ j ].lightmap, sizeof( dv[ j ].lightmap ) );
3216 memcpy( dv[ j ].color, dvParent[ j ].color, sizeof( dv[ j ].color ) );
3217 }
3218
3219 /* skip the rest */
3220 continue;
3221 }
3222
3223 /* handle vertex lit or approximated surfaces */
3224 else if ( lm == NULL || lm->outLightmapNums[ 0 ] < 0 ) {
3225 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3226 {
3227 ds->lightmapNum[ lightmapNum ] = -3;
3228 ds->lightmapStyles[ lightmapNum ] = ds->vertexStyles[ lightmapNum ];
3229 }
3230 }
3231
3232 /* handle lightmapped surfaces */
3233 else
3234 {
3235 /* walk lightmaps */
3236 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3237 {
3238 /* set style */
3239 ds->lightmapStyles[ lightmapNum ] = lm->styles[ lightmapNum ];
3240
3241 /* handle unused style */
3242 if ( lm->styles[ lightmapNum ] == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 ) {
3243 ds->lightmapNum[ lightmapNum ] = -3;
3244 continue;
3245 }
3246
3247 /* get output lightmap */
3248 olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
3249
3250 /* set bsp lightmap number */
3251 ds->lightmapNum[ lightmapNum ] = olm->lightmapNum;
3252
3253 /* deluxemap debugging makes the deluxemap visible */
3254 if ( deluxemap && debugDeluxemap && lightmapNum == 0 ) {
3255 ds->lightmapNum[ lightmapNum ]++;
3256 }
3257
3258 /* calc lightmap origin in texture space */
3259 lmx = (float) lm->lightmapX[ lightmapNum ] / (float) olm->customWidth;
3260 lmy = (float) lm->lightmapY[ lightmapNum ] / (float) olm->customHeight;
3261
3262 /* calc lightmap st coords */
3263 dv = &bspDrawVerts[ ds->firstVert ];
3264 ydv = &yDrawVerts[ ds->firstVert ];
3265 for ( j = 0; j < ds->numVerts; j++ )
3266 {
3267 if ( lm->solid[ lightmapNum ] ) {
3268 dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + ( 0.5f / (float) olm->customWidth );
3269 dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + ( 0.5f / (float) olm->customWidth );
3270 }
3271 else
3272 {
3273 dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + ( ydv[ j ].lightmap[ 0 ][ 0 ] / ( superSample * olm->customWidth ) );
3274 dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + ( ydv[ j ].lightmap[ 0 ][ 1 ] / ( superSample * olm->customHeight ) );
3275 }
3276 }
3277 }
3278 }
3279
3280 /* store vertex colors */
3281 dv = &bspDrawVerts[ ds->firstVert ];
3282 for ( j = 0; j < ds->numVerts; j++ )
3283 {
3284 /* walk lightmaps */
3285 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3286 {
3287 /* handle unused style */
3288 if ( ds->vertexStyles[ lightmapNum ] == LS_NONE ) {
3289 VectorClear( color );
3290 }
3291 else
3292 {
3293 /* get vertex color */
3294 luxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + j );
3295 VectorCopy( luxel, color );
3296
3297 /* set minimum light */
3298 if ( lightmapNum == 0 ) {
3299 for ( k = 0; k < 3; k++ )
3300 if ( color[ k ] < minVertexLight[ k ] ) {
3301 color[ k ] = minVertexLight[ k ];
3302 }
3303 }
3304 }
3305
3306 /* store to bytes */
3307 if ( !info->si->noVertexLight ) {
3308 ColorToBytes( color, dv[ j ].color[ lightmapNum ], info->si->vertexScale );
3309 }
3310 }
3311 }
3312
3313 /* surfaces with styled lightmaps and a style marker get a custom generated shader (fixme: make this work with external lightmaps) */
3314 if ( olm != NULL && lm != NULL && lm->styles[ 1 ] != LS_NONE && game->load != LoadRBSPFile ) { //% info->si->styleMarker > 0 )
3315 qboolean dfEqual;
3316 char key[ 32 ], styleStage[ 512 ], styleStages[ 4096 ], rgbGen[ 128 ], alphaGen[ 128 ];
3317
3318
3319 /* setup */
3320 sprintf( styleStages, "\n\t// Q3Map2 custom lightstyle stage(s)\n" );
3321 dv = &bspDrawVerts[ ds->firstVert ];
3322
3323 /* depthFunc equal? */
3324 if ( info->si->styleMarker == 2 || info->si->implicitMap == IM_MASKED ) {
3325 dfEqual = qtrue;
3326 }
3327 else{
3328 dfEqual = qfalse;
3329 }
3330
3331 /* generate stages for styled lightmaps */
3332 for ( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3333 {
3334 /* early out */
3335 style = lm->styles[ lightmapNum ];
3336 if ( style == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 ) {
3337 continue;
3338 }
3339
3340 /* get output lightmap */
3341 olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
3342
3343 /* lightmap name */
3344 if ( lm->outLightmapNums[ lightmapNum ] == lm->outLightmapNums[ 0 ] ) {
3345 strcpy( lightmapName, "$lightmap" );
3346 }
3347 else{
3348 sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
3349 }
3350
3351 /* get rgbgen string */
3352 if ( rgbGenValues[ style ] == NULL ) {
3353 sprintf( key, "_style%drgbgen", style );
3354 rgbGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
3355 if ( rgbGenValues[ style ][ 0 ] == '\0' ) {
3356 rgbGenValues[ style ] = "wave noise 0.5 1 0 5.37";
3357 }
3358 }
3359 rgbGen[ 0 ] = '\0';
3360 if ( rgbGenValues[ style ][ 0 ] != '\0' ) {
3361 sprintf( rgbGen, "\t\trgbGen %s // style %d\n", rgbGenValues[ style ], style );
3362 }
3363 else{
3364 rgbGen[ 0 ] = '\0';
3365 }
3366
3367 /* get alphagen string */
3368 if ( alphaGenValues[ style ] == NULL ) {
3369 sprintf( key, "_style%dalphagen", style );
3370 alphaGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
3371 }
3372 if ( alphaGenValues[ style ][ 0 ] != '\0' ) {
3373 sprintf( alphaGen, "\t\talphaGen %s // style %d\n", alphaGenValues[ style ], style );
3374 }
3375 else{
3376 alphaGen[ 0 ] = '\0';
3377 }
3378
3379 /* calculate st offset */
3380 lmx = dv[ 0 ].lightmap[ lightmapNum ][ 0 ] - dv[ 0 ].lightmap[ 0 ][ 0 ];
3381 lmy = dv[ 0 ].lightmap[ lightmapNum ][ 1 ] - dv[ 0 ].lightmap[ 0 ][ 1 ];
3382
3383 /* create additional stage */
3384 if ( lmx == 0.0f && lmy == 0.0f ) {
3385 sprintf( styleStage, "\t{\n"
3386 "\t\tmap %s\n" /* lightmap */
3387 "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
3388 "%s" /* depthFunc equal */
3389 "%s" /* rgbGen */
3390 "%s" /* alphaGen */
3391 "\t\ttcGen lightmap\n"
3392 "\t}\n",
3393 lightmapName,
3394 ( dfEqual ? "\t\tdepthFunc equal\n" : "" ),
3395 rgbGen,
3396 alphaGen );
3397 }
3398 else
3399 {
3400 sprintf( styleStage, "\t{\n"
3401 "\t\tmap %s\n" /* lightmap */
3402 "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
3403 "%s" /* depthFunc equal */
3404 "%s" /* rgbGen */
3405 "%s" /* alphaGen */
3406 "\t\ttcGen lightmap\n"
3407 "\t\ttcMod transform 1 0 0 1 %1.5f %1.5f\n" /* st offset */
3408 "\t}\n",
3409 lightmapName,
3410 ( dfEqual ? "\t\tdepthFunc equal\n" : "" ),
3411 rgbGen,
3412 alphaGen,
3413 lmx, lmy );
3414
3415 }
3416
3417 /* concatenate */
3418 strcat( styleStages, styleStage );
3419 }
3420
3421 /* create custom shader */
3422 if ( info->si->styleMarker == 2 ) {
3423 csi = CustomShader( info->si, "q3map_styleMarker2", styleStages );
3424 }
3425 else{
3426 csi = CustomShader( info->si, "q3map_styleMarker", styleStages );
3427 }
3428
3429 /* emit remap command */
3430 //% EmitVertexRemapShader( csi->shader, info->si->shader );
3431
3432 /* store it */
3433 //% Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
3434 ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3435 //% Sys_Printf( ")\n" );
3436 }
3437
3438 /* devise a custom shader for this surface (fixme: make this work with light styles) */
3439 else if ( olm != NULL && lm != NULL && !externalLightmaps &&
3440 ( olm->customWidth != game->lightmapSize || olm->customHeight != game->lightmapSize ) ) {
3441 /* get output lightmap */
3442 olm = &outLightmaps[ lm->outLightmapNums[ 0 ] ];
3443
3444 /* do some name mangling */
3445 sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
3446
3447 /* create custom shader */
3448 csi = CustomShader( info->si, "$lightmap", lightmapName );
3449
3450 /* store it */
3451 //% Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
3452 ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3453 //% Sys_Printf( ")\n" );
3454 }
3455
3456 /* use the normal plain-jane shader */
3457 else{
3458 ds->shaderNum = EmitShader( info->si->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3459 }
3460 }
3461
3462 /* finish */
3463 Sys_Printf( "done.\n" );
3464
3465 /* calc num stored */
3466 numStored = numBSPLightBytes / 3;
3467 efficiency = ( numStored <= 0 )
3468 ? 0
3469 : (float) numUsed / (float) numStored;
3470
3471 /* print stats */
3472 Sys_Printf( "%9d luxels used\n", numUsed );
3473 Sys_Printf( "%9d luxels stored (%3.2f percent efficiency)\n", numStored, efficiency * 100.0f );
3474 Sys_Printf( "%9d solid surface lightmaps\n", numSolidLightmaps );
3475 Sys_Printf( "%9d identical surface lightmaps, using %d luxels\n", numTwins, numTwinLuxels );
3476 Sys_Printf( "%9d vertex forced surfaces\n", numSurfsVertexForced );
3477 Sys_Printf( "%9d vertex approximated surfaces\n", numSurfsVertexApproximated );
3478 Sys_Printf( "%9d BSP lightmaps\n", numBSPLightmaps );
3479 Sys_Printf( "%9d total lightmaps\n", numOutLightmaps );
3480 Sys_Printf( "%9d unique lightmap/shader combinations\n", numLightmapShaders );
3481
3482 /* write map shader file */
3483 WriteMapShaderFile();
3484 }
3485