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