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