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