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