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