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