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