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