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