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