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