]> git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/lightmaps_ydnar.c
Merge commit 'fe73dd74d0e40a33c090993390e4d5721a1f9e05' 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 ( !olm ){
2187                                 Error( "FindOutLightmaps: Failed to allocate memory.\n" );
2188                         }
2189
2190                         if ( outLightmaps != NULL && numOutLightmaps > LIGHTMAP_RESERVE_COUNT ) {
2191                                 memcpy( olm, outLightmaps, ( numOutLightmaps - LIGHTMAP_RESERVE_COUNT ) * sizeof( outLightmap_t ) );
2192                                 free( outLightmaps );
2193                         }
2194                         outLightmaps = olm;
2195
2196                         /* initialize both out lightmaps */
2197                         for ( k = numOutLightmaps - LIGHTMAP_RESERVE_COUNT; k < numOutLightmaps; ++k )
2198                                 SetupOutLightmap( lm, &outLightmaps[ k ] );
2199
2200                         /* set out lightmap */
2201                         i = numOutLightmaps - LIGHTMAP_RESERVE_COUNT;
2202                         olm = &outLightmaps[ i ];
2203
2204                         /* set stamp xy origin to the first surface lightmap */
2205                         if ( lightmapNum > 0 ) {
2206                                 x = lm->lightmapX[ 0 ];
2207                                 y = lm->lightmapY[ 0 ];
2208                         }
2209                 }
2210
2211                 /* if this is a style-using lightmap, it must be exported */
2212                 if ( lightmapNum > 0 && game->load != LoadRBSPFile ) {
2213                         olm->extLightmapNum = 0;
2214                 }
2215
2216                 /* add the surface lightmap to the bsp lightmap */
2217                 lm->outLightmapNums[ lightmapNum ] = i;
2218                 lm->lightmapX[ lightmapNum ] = x;
2219                 lm->lightmapY[ lightmapNum ] = y;
2220                 olm->numLightmaps++;
2221
2222                 /* add shaders */
2223                 for ( i = 0; i < lm->numLightSurfaces; i++ )
2224                 {
2225                         /* get surface info */
2226                         info = &surfaceInfos[ lightSurfaces[ lm->firstLightSurface + i ] ];
2227
2228                         /* test for shader */
2229                         for ( j = 0; j < olm->numShaders; j++ )
2230                         {
2231                                 if ( olm->shaders[ j ] == info->si ) {
2232                                         break;
2233                                 }
2234                         }
2235
2236                         /* if it doesn't exist, add it */
2237                         if ( j >= olm->numShaders && olm->numShaders < MAX_LIGHTMAP_SHADERS ) {
2238                                 olm->shaders[ olm->numShaders ] = info->si;
2239                                 olm->numShaders++;
2240                                 numLightmapShaders++;
2241                         }
2242                 }
2243
2244                 /* set maxs */
2245                 if ( lm->solid[ lightmapNum ] ) {
2246                         xMax = 1;
2247                         yMax = 1;
2248                 }
2249                 else
2250                 {
2251                         xMax = lm->w;
2252                         yMax = lm->h;
2253                 }
2254
2255                 /* mark the bits used */
2256                 for ( y = 0; y < yMax; y++ )
2257                 {
2258                         for ( x = 0; x < xMax; x++ )
2259                         {
2260                                 /* get luxel */
2261                                 luxel = BSP_LUXEL( lightmapNum, x, y );
2262                                 deluxel = BSP_DELUXEL( x, y );
2263                                 if ( luxel[ 0 ] < 0.0f && !lm->solid[ lightmapNum ] ) {
2264                                         continue;
2265                                 }
2266
2267                                 /* set minimum light */
2268                                 if ( lm->solid[ lightmapNum ] ) {
2269                                         if ( debug ) {
2270                                                 VectorSet( color, 255.0f, 0.0f, 0.0f );
2271                                         }
2272                                         else{
2273                                                 VectorCopy( lm->solidColor[ lightmapNum ], color );
2274                                         }
2275                                 }
2276                                 else{
2277                                         VectorCopy( luxel, color );
2278                                 }
2279
2280                                 /* styles are not affected by minlight */
2281                                 if ( lightmapNum == 0 ) {
2282                                         for ( i = 0; i < 3; i++ )
2283                                         {
2284                                                 if ( color[ i ] < minLight[ i ] ) {
2285                                                         color[ i ] = minLight[ i ];
2286                                                 }
2287                                         }
2288                                 }
2289
2290                                 /* get bsp lightmap coords  */
2291                                 ox = x + lm->lightmapX[ lightmapNum ];
2292                                 oy = y + lm->lightmapY[ lightmapNum ];
2293                                 offset = ( oy * olm->customWidth ) + ox;
2294
2295                                 /* flag pixel as used */
2296                                 olm->lightBits[ offset >> 3 ] |= ( 1 << ( offset & 7 ) );
2297                                 olm->freeLuxels--;
2298
2299                                 /* store color */
2300                                 pixel = olm->bspLightBytes + ( ( ( oy * olm->customWidth ) + ox ) * 3 );
2301                                 ColorToBytes( color, pixel, lm->brightness );
2302
2303                                 /* store direction */
2304                                 if ( deluxemap ) {
2305                                         /* normalize average light direction */
2306                                         pixel = olm->bspDirBytes + ( ( ( oy * olm->customWidth ) + ox ) * 3 );
2307                                         VectorScale( deluxel, 1000.0f, direction );
2308                                         VectorNormalize( direction, direction );
2309                                         VectorScale( direction, 127.5f, direction );
2310                                         for ( i = 0; i < 3; i++ )
2311                                                 pixel[ i ] = (byte)( 127.5f + direction[ i ] );
2312                                 }
2313                         }
2314                 }
2315         }
2316 }
2317
2318
2319
2320 /*
2321    CompareRawLightmap()
2322    compare function for qsort()
2323  */
2324
2325 static int CompareRawLightmap( const void *a, const void *b ){
2326         rawLightmap_t   *alm, *blm;
2327         surfaceInfo_t   *aInfo, *bInfo;
2328         int i, min, diff;
2329
2330
2331         /* get lightmaps */
2332         alm = &rawLightmaps[ *( (const int*) a ) ];
2333         blm = &rawLightmaps[ *( (const int*) b ) ];
2334
2335         /* get min number of surfaces */
2336         min = ( alm->numLightSurfaces < blm->numLightSurfaces ? alm->numLightSurfaces : blm->numLightSurfaces );
2337
2338         /* iterate */
2339         for ( i = 0; i < min; i++ )
2340         {
2341                 /* get surface info */
2342                 aInfo = &surfaceInfos[ lightSurfaces[ alm->firstLightSurface + i ] ];
2343                 bInfo = &surfaceInfos[ lightSurfaces[ blm->firstLightSurface + i ] ];
2344
2345                 /* compare shader names */
2346                 diff = strcmp( aInfo->si->shader, bInfo->si->shader );
2347                 if ( diff != 0 ) {
2348                         return diff;
2349                 }
2350         }
2351
2352         /* test style count */
2353         diff = 0;
2354         for ( i = 0; i < MAX_LIGHTMAPS; i++ )
2355                 diff += blm->styles[ i ] - alm->styles[ i ];
2356         if ( diff ) {
2357                 return diff;
2358         }
2359
2360         /* compare size */
2361         diff = ( blm->w * blm->h ) - ( alm->w * alm->h );
2362         if ( diff != 0 ) {
2363                 return diff;
2364         }
2365
2366         /* must be equivalent */
2367         return 0;
2368 }
2369
2370
2371
2372 void FillOutLightmap( outLightmap_t *olm ){
2373         int x, y;
2374         int ofs;
2375         vec3_t dir_sum, light_sum;
2376         int cnt, filled;
2377         byte *lightBitsNew = NULL;
2378         byte *lightBytesNew = NULL;
2379         byte *dirBytesNew = NULL;
2380
2381         lightBitsNew = safe_malloc( ( olm->customWidth * olm->customHeight + 8 ) / 8 );
2382         lightBytesNew = safe_malloc( olm->customWidth * olm->customHeight * 3 );
2383         if ( deluxemap ) {
2384                 dirBytesNew = safe_malloc( olm->customWidth * olm->customHeight * 3 );
2385         }
2386
2387         /*
2388            memset(olm->lightBits, 0, (olm->customWidth * olm->customHeight + 8) / 8);
2389             olm->lightBits[0] |= 1;
2390             olm->lightBits[(10 * olm->customWidth + 30) >> 3] |= 1 << ((10 * olm->customWidth + 30) & 7);
2391            memset(olm->bspLightBytes, 0, olm->customWidth * olm->customHeight * 3);
2392             olm->bspLightBytes[0] = 255;
2393             olm->bspLightBytes[(10 * olm->customWidth + 30) * 3 + 2] = 255;
2394          */
2395
2396         memcpy( lightBitsNew, olm->lightBits, ( olm->customWidth * olm->customHeight + 8 ) / 8 );
2397         memcpy( lightBytesNew, olm->bspLightBytes, olm->customWidth * olm->customHeight * 3 );
2398         if ( deluxemap ) {
2399                 memcpy( dirBytesNew, olm->bspDirBytes, olm->customWidth * olm->customHeight * 3 );
2400         }
2401
2402         for (;; )
2403         {
2404                 filled = 0;
2405                 for ( y = 0; y < olm->customHeight; ++y )
2406                 {
2407                         for ( x = 0; x < olm->customWidth; ++x )
2408                         {
2409                                 ofs = y * olm->customWidth + x;
2410                                 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2411                                         continue;
2412                                 }
2413                                 cnt = 0;
2414                                 VectorClear( dir_sum );
2415                                 VectorClear( light_sum );
2416
2417                                 /* try all four neighbors */
2418                                 ofs = ( ( y + olm->customHeight - 1 ) % olm->customHeight ) * olm->customWidth + x;
2419                                 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2420                                         ++cnt;
2421                                         VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2422                                         if ( deluxemap ) {
2423                                                 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2424                                         }
2425                                 }
2426
2427                                 ofs = ( ( y + 1 ) % olm->customHeight ) * olm->customWidth + x;
2428                                 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2429                                         ++cnt;
2430                                         VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2431                                         if ( deluxemap ) {
2432                                                 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2433                                         }
2434                                 }
2435
2436                                 ofs = y * olm->customWidth + ( x + olm->customWidth - 1 ) % olm->customWidth;
2437                                 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2438                                         ++cnt;
2439                                         VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2440                                         if ( deluxemap ) {
2441                                                 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2442                                         }
2443                                 }
2444
2445                                 ofs = y * olm->customWidth + ( x + 1 ) % olm->customWidth;
2446                                 if ( olm->lightBits[ofs >> 3] & ( 1 << ( ofs & 7 ) ) ) { /* already filled */
2447                                         ++cnt;
2448                                         VectorAdd( light_sum, olm->bspLightBytes + ofs * 3, light_sum );
2449                                         if ( deluxemap ) {
2450                                                 VectorAdd( dir_sum, olm->bspDirBytes + ofs * 3, dir_sum );
2451                                         }
2452                                 }
2453
2454                                 if ( cnt ) {
2455                                         ++filled;
2456                                         ofs = y * olm->customWidth + x;
2457                                         lightBitsNew[ofs >> 3] |= ( 1 << ( ofs & 7 ) );
2458                                         VectorScale( light_sum, 1.0 / cnt, lightBytesNew + ofs * 3 );
2459                                         if ( deluxemap ) {
2460                                                 VectorScale( dir_sum, 1.0 / cnt, dirBytesNew + ofs * 3 );
2461                                         }
2462                                 }
2463                         }
2464                 }
2465
2466                 if ( !filled ) {
2467                         break;
2468                 }
2469
2470                 memcpy( olm->lightBits, lightBitsNew, ( olm->customWidth * olm->customHeight + 8 ) / 8 );
2471                 memcpy( olm->bspLightBytes, lightBytesNew, olm->customWidth * olm->customHeight * 3 );
2472                 if ( deluxemap ) {
2473                         memcpy( olm->bspDirBytes, dirBytesNew, olm->customWidth * olm->customHeight * 3 );
2474                 }
2475         }
2476
2477         free( lightBitsNew );
2478         free( lightBytesNew );
2479         if ( deluxemap ) {
2480                 free( dirBytesNew );
2481         }
2482 }
2483
2484
2485
2486 /*
2487    StoreSurfaceLightmaps()
2488    stores the surface lightmaps into the bsp as byte rgb triplets
2489  */
2490
2491 void StoreSurfaceLightmaps( qboolean fastAllocate ){
2492         int i, j, k, x, y, lx, ly, sx, sy, *cluster, mappedSamples;
2493         int style, size, lightmapNum, lightmapNum2;
2494         float               *normal, *luxel, *bspLuxel, *bspLuxel2, *radLuxel, samples, occludedSamples;
2495         vec3_t sample, occludedSample, dirSample, colorMins, colorMaxs;
2496         float               *deluxel, *bspDeluxel, *bspDeluxel2;
2497         byte                *lb;
2498         int numUsed, numTwins, numTwinLuxels, numStored;
2499         float lmx, lmy, efficiency;
2500         vec3_t color;
2501         bspDrawSurface_t    *ds, *parent, dsTemp;
2502         surfaceInfo_t       *info;
2503         rawLightmap_t       *lm, *lm2;
2504         outLightmap_t       *olm;
2505         bspDrawVert_t       *dv, *ydv, *dvParent;
2506         char dirname[ 1024 ], filename[ 1024 ];
2507         shaderInfo_t        *csi;
2508         char lightmapName[ 128 ];
2509         const char          *rgbGenValues[ 256 ];
2510         const char          *alphaGenValues[ 256 ];
2511
2512
2513         /* note it */
2514         Sys_Printf( "--- StoreSurfaceLightmaps ---\n" );
2515
2516         /* setup */
2517         if ( lmCustomDir ) {
2518                 strcpy( dirname, lmCustomDir );
2519         }
2520         else
2521         {
2522                 strcpy( dirname, source );
2523                 StripExtension( dirname );
2524         }
2525         memset( rgbGenValues, 0, sizeof( rgbGenValues ) );
2526         memset( alphaGenValues, 0, sizeof( alphaGenValues ) );
2527
2528         /* -----------------------------------------------------------------
2529            average the sampled luxels into the bsp luxels
2530            ----------------------------------------------------------------- */
2531
2532         /* note it */
2533         Sys_FPrintf( SYS_VRB, "Subsampling..." );
2534
2535         /* walk the list of raw lightmaps */
2536         numUsed = 0;
2537         numTwins = 0;
2538         numTwinLuxels = 0;
2539         numSolidLightmaps = 0;
2540         for ( i = 0; i < numRawLightmaps; i++ )
2541         {
2542                 /* get lightmap */
2543                 lm = &rawLightmaps[ i ];
2544
2545                 /* walk individual lightmaps */
2546                 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2547                 {
2548                         /* early outs */
2549                         if ( lm->superLuxels[ lightmapNum ] == NULL ) {
2550                                 continue;
2551                         }
2552
2553                         /* allocate bsp luxel storage */
2554                         if ( lm->bspLuxels[ lightmapNum ] == NULL ) {
2555                                 size = lm->w * lm->h * BSP_LUXEL_SIZE * sizeof( float );
2556                                 lm->bspLuxels[ lightmapNum ] = safe_malloc( size );
2557                                 memset( lm->bspLuxels[ lightmapNum ], 0, size );
2558                         }
2559
2560                         /* allocate radiosity lightmap storage */
2561                         if ( bounce ) {
2562                                 size = lm->w * lm->h * RAD_LUXEL_SIZE * sizeof( float );
2563                                 if ( lm->radLuxels[ lightmapNum ] == NULL ) {
2564                                         lm->radLuxels[ lightmapNum ] = safe_malloc( size );
2565                                 }
2566                                 memset( lm->radLuxels[ lightmapNum ], 0, size );
2567                         }
2568
2569                         /* average supersampled luxels */
2570                         for ( y = 0; y < lm->h; y++ )
2571                         {
2572                                 for ( x = 0; x < lm->w; x++ )
2573                                 {
2574                                         /* subsample */
2575                                         samples = 0.0f;
2576                                         occludedSamples = 0.0f;
2577                                         mappedSamples = 0;
2578                                         VectorClear( sample );
2579                                         VectorClear( occludedSample );
2580                                         VectorClear( dirSample );
2581                                         for ( ly = 0; ly < superSample; ly++ )
2582                                         {
2583                                                 for ( lx = 0; lx < superSample; lx++ )
2584                                                 {
2585                                                         /* sample luxel */
2586                                                         sx = x * superSample + lx;
2587                                                         sy = y * superSample + ly;
2588                                                         luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2589                                                         deluxel = SUPER_DELUXEL( sx, sy );
2590                                                         normal = SUPER_NORMAL( sx, sy );
2591                                                         cluster = SUPER_CLUSTER( sx, sy );
2592
2593                                                         /* sample deluxemap */
2594                                                         if ( deluxemap && lightmapNum == 0 ) {
2595                                                                 VectorAdd( dirSample, deluxel, dirSample );
2596                                                         }
2597
2598                                                         /* keep track of used/occluded samples */
2599                                                         if ( *cluster != CLUSTER_UNMAPPED ) {
2600                                                                 mappedSamples++;
2601                                                         }
2602
2603                                                         /* handle lightmap border? */
2604                                                         if ( lightmapBorder && ( sx == 0 || sx == ( lm->sw - 1 ) || sy == 0 || sy == ( lm->sh - 1 ) ) && luxel[ 3 ] > 0.0f ) {
2605                                                                 VectorSet( sample, 255.0f, 0.0f, 0.0f );
2606                                                                 samples += 1.0f;
2607                                                         }
2608
2609                                                         /* handle debug */
2610                                                         else if ( debug && *cluster < 0 ) {
2611                                                                 if ( *cluster == CLUSTER_UNMAPPED ) {
2612                                                                         VectorSet( luxel, 255, 204, 0 );
2613                                                                 }
2614                                                                 else if ( *cluster == CLUSTER_OCCLUDED ) {
2615                                                                         VectorSet( luxel, 255, 0, 255 );
2616                                                                 }
2617                                                                 else if ( *cluster == CLUSTER_FLOODED ) {
2618                                                                         VectorSet( luxel, 0, 32, 255 );
2619                                                                 }
2620                                                                 VectorAdd( occludedSample, luxel, occludedSample );
2621                                                                 occludedSamples += 1.0f;
2622                                                         }
2623
2624                                                         /* normal luxel handling */
2625                                                         else if ( luxel[ 3 ] > 0.0f ) {
2626                                                                 /* handle lit or flooded luxels */
2627                                                                 if ( *cluster > 0 || *cluster == CLUSTER_FLOODED ) {
2628                                                                         VectorAdd( sample, luxel, sample );
2629                                                                         samples += luxel[ 3 ];
2630                                                                 }
2631
2632                                                                 /* handle occluded or unmapped luxels */
2633                                                                 else
2634                                                                 {
2635                                                                         VectorAdd( occludedSample, luxel, occludedSample );
2636                                                                         occludedSamples += luxel[ 3 ];
2637                                                                 }
2638
2639                                                                 /* handle style debugging */
2640                                                                 if ( debug && lightmapNum > 0 && x < 2 && y < 2 ) {
2641                                                                         VectorCopy( debugColors[ 0 ], sample );
2642                                                                         samples = 1;
2643                                                                 }
2644                                                         }
2645                                                 }
2646                                         }
2647
2648                                         /* only use occluded samples if necessary */
2649                                         if ( samples <= 0.0f ) {
2650                                                 VectorCopy( occludedSample, sample );
2651                                                 samples = occludedSamples;
2652                                         }
2653
2654                                         /* get luxels */
2655                                         luxel = SUPER_LUXEL( lightmapNum, x, y );
2656                                         deluxel = SUPER_DELUXEL( x, y );
2657
2658                                         /* store light direction */
2659                                         if ( deluxemap && lightmapNum == 0 ) {
2660                                                 VectorCopy( dirSample, deluxel );
2661                                         }
2662
2663                                         /* store the sample back in super luxels */
2664                                         if ( samples > 0.01f ) {
2665                                                 VectorScale( sample, ( 1.0f / samples ), luxel );
2666                                                 luxel[ 3 ] = 1.0f;
2667                                         }
2668
2669                                         /* if any samples were mapped in any way, store ambient color */
2670                                         else if ( mappedSamples > 0 ) {
2671                                                 if ( lightmapNum == 0 ) {
2672                                                         VectorCopy( ambientColor, luxel );
2673                                                 }
2674                                                 else{
2675                                                         VectorClear( luxel );
2676                                                 }
2677                                                 luxel[ 3 ] = 1.0f;
2678                                         }
2679
2680                                         /* store a bogus value to be fixed later */
2681                                         else
2682                                         {
2683                                                 VectorClear( luxel );
2684                                                 luxel[ 3 ] = -1.0f;
2685                                         }
2686                                 }
2687                         }
2688
2689                         /* setup */
2690                         lm->used = 0;
2691                         ClearBounds( colorMins, colorMaxs );
2692
2693                         /* clean up and store into bsp luxels */
2694                         for ( y = 0; y < lm->h; y++ )
2695                         {
2696                                 for ( x = 0; x < lm->w; x++ )
2697                                 {
2698                                         /* get luxels */
2699                                         luxel = SUPER_LUXEL( lightmapNum, x, y );
2700                                         deluxel = SUPER_DELUXEL( x, y );
2701
2702                                         /* copy light direction */
2703                                         if ( deluxemap && lightmapNum == 0 ) {
2704                                                 VectorCopy( deluxel, dirSample );
2705                                         }
2706
2707                                         /* is this a valid sample? */
2708                                         if ( luxel[ 3 ] > 0.0f ) {
2709                                                 VectorCopy( luxel, sample );
2710                                                 samples = luxel[ 3 ];
2711                                                 numUsed++;
2712                                                 lm->used++;
2713
2714                                                 /* fix negative samples */
2715                                                 for ( j = 0; j < 3; j++ )
2716                                                 {
2717                                                         if ( sample[ j ] < 0.0f ) {
2718                                                                 sample[ j ] = 0.0f;
2719                                                         }
2720                                                 }
2721                                         }
2722                                         else
2723                                         {
2724                                                 /* nick an average value from the neighbors */
2725                                                 VectorClear( sample );
2726                                                 VectorClear( dirSample );
2727                                                 samples = 0.0f;
2728
2729                                                 /* fixme: why is this disabled?? */
2730                                                 for ( sy = ( y - 1 ); sy <= ( y + 1 ); sy++ )
2731                                                 {
2732                                                         if ( sy < 0 || sy >= lm->h ) {
2733                                                                 continue;
2734                                                         }
2735
2736                                                         for ( sx = ( x - 1 ); sx <= ( x + 1 ); sx++ )
2737                                                         {
2738                                                                 if ( sx < 0 || sx >= lm->w || ( sx == x && sy == y ) ) {
2739                                                                         continue;
2740                                                                 }
2741
2742                                                                 /* get neighbor's particulars */
2743                                                                 luxel = SUPER_LUXEL( lightmapNum, sx, sy );
2744                                                                 if ( luxel[ 3 ] < 0.0f ) {
2745                                                                         continue;
2746                                                                 }
2747                                                                 VectorAdd( sample, luxel, sample );
2748                                                                 samples += luxel[ 3 ];
2749                                                         }
2750                                                 }
2751
2752                                                 /* no samples? */
2753                                                 if ( samples == 0.0f ) {
2754                                                         VectorSet( sample, -1.0f, -1.0f, -1.0f );
2755                                                         samples = 1.0f;
2756                                                 }
2757                                                 else
2758                                                 {
2759                                                         numUsed++;
2760                                                         lm->used++;
2761
2762                                                         /* fix negative samples */
2763                                                         for ( j = 0; j < 3; j++ )
2764                                                         {
2765                                                                 if ( sample[ j ] < 0.0f ) {
2766                                                                         sample[ j ] = 0.0f;
2767                                                                 }
2768                                                         }
2769                                                 }
2770                                         }
2771
2772                                         /* scale the sample */
2773                                         VectorScale( sample, ( 1.0f / samples ), sample );
2774
2775                                         /* store the sample in the radiosity luxels */
2776                                         if ( bounce > 0 ) {
2777                                                 radLuxel = RAD_LUXEL( lightmapNum, x, y );
2778                                                 VectorCopy( sample, radLuxel );
2779
2780                                                 /* if only storing bounced light, early out here */
2781                                                 if ( bounceOnly && !bouncing ) {
2782                                                         continue;
2783                                                 }
2784                                         }
2785
2786                                         /* store the sample in the bsp luxels */
2787                                         bspLuxel = BSP_LUXEL( lightmapNum, x, y );
2788                                         bspDeluxel = BSP_DELUXEL( x, y );
2789
2790                                         VectorAdd( bspLuxel, sample, bspLuxel );
2791                                         if ( deluxemap && lightmapNum == 0 ) {
2792                                                 VectorAdd( bspDeluxel, dirSample, bspDeluxel );
2793                                         }
2794
2795                                         /* add color to bounds for solid checking */
2796                                         if ( samples > 0.0f ) {
2797                                                 AddPointToBounds( bspLuxel, colorMins, colorMaxs );
2798                                         }
2799                                 }
2800                         }
2801
2802                         /* set solid color */
2803                         lm->solid[ lightmapNum ] = qfalse;
2804                         VectorAdd( colorMins, colorMaxs, lm->solidColor[ lightmapNum ] );
2805                         VectorScale( lm->solidColor[ lightmapNum ], 0.5f, lm->solidColor[ lightmapNum ] );
2806
2807                         /* nocollapse prevents solid lightmaps */
2808                         if ( noCollapse == qfalse ) {
2809                                 /* check solid color */
2810                                 VectorSubtract( colorMaxs, colorMins, sample );
2811                                 if ( ( sample[ 0 ] <= SOLID_EPSILON && sample[ 1 ] <= SOLID_EPSILON && sample[ 2 ] <= SOLID_EPSILON ) ||
2812                                          ( lm->w <= 2 && lm->h <= 2 ) ) { /* small lightmaps get forced to solid color */
2813                                         /* set to solid */
2814                                         VectorCopy( colorMins, lm->solidColor[ lightmapNum ] );
2815                                         lm->solid[ lightmapNum ] = qtrue;
2816                                         numSolidLightmaps++;
2817                                 }
2818
2819                                 /* if all lightmaps aren't solid, then none of them are solid */
2820                                 if ( lm->solid[ lightmapNum ] != lm->solid[ 0 ] ) {
2821                                         for ( y = 0; y < MAX_LIGHTMAPS; y++ )
2822                                         {
2823                                                 if ( lm->solid[ y ] ) {
2824                                                         numSolidLightmaps--;
2825                                                 }
2826                                                 lm->solid[ y ] = qfalse;
2827                                         }
2828                                 }
2829                         }
2830
2831                         /* wrap bsp luxels if necessary */
2832                         if ( lm->wrap[ 0 ] ) {
2833                                 for ( y = 0; y < lm->h; y++ )
2834                                 {
2835                                         bspLuxel = BSP_LUXEL( lightmapNum, 0, y );
2836                                         bspLuxel2 = BSP_LUXEL( lightmapNum, lm->w - 1, y );
2837                                         VectorAdd( bspLuxel, bspLuxel2, bspLuxel );
2838                                         VectorScale( bspLuxel, 0.5f, bspLuxel );
2839                                         VectorCopy( bspLuxel, bspLuxel2 );
2840                                         if ( deluxemap && lightmapNum == 0 ) {
2841                                                 bspDeluxel = BSP_DELUXEL( 0, y );
2842                                                 bspDeluxel2 = BSP_DELUXEL( lm->w - 1, y );
2843                                                 VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel );
2844                                                 VectorScale( bspDeluxel, 0.5f, bspDeluxel );
2845                                                 VectorCopy( bspDeluxel, bspDeluxel2 );
2846                                         }
2847                                 }
2848                         }
2849                         if ( lm->wrap[ 1 ] ) {
2850                                 for ( x = 0; x < lm->w; x++ )
2851                                 {
2852                                         bspLuxel = BSP_LUXEL( lightmapNum, x, 0 );
2853                                         bspLuxel2 = BSP_LUXEL( lightmapNum, x, lm->h - 1 );
2854                                         VectorAdd( bspLuxel, bspLuxel2, bspLuxel );
2855                                         VectorScale( bspLuxel, 0.5f, bspLuxel );
2856                                         VectorCopy( bspLuxel, bspLuxel2 );
2857                                         if ( deluxemap && lightmapNum == 0 ) {
2858                                                 bspDeluxel = BSP_DELUXEL( x, 0 );
2859                                                 bspDeluxel2 = BSP_DELUXEL( x, lm->h - 1 );
2860                                                 VectorAdd( bspDeluxel, bspDeluxel2, bspDeluxel );
2861                                                 VectorScale( bspDeluxel, 0.5f, bspDeluxel );
2862                                                 VectorCopy( bspDeluxel, bspDeluxel2 );
2863                                         }
2864                                 }
2865                         }
2866                 }
2867         }
2868
2869         /* -----------------------------------------------------------------
2870            convert modelspace deluxemaps to tangentspace
2871            ----------------------------------------------------------------- */
2872         /* note it */
2873         if ( !bouncing ) {
2874                 if ( deluxemap && deluxemode == 1 ) {
2875                         vec3_t worldUp, myNormal, myTangent, myBinormal;
2876                         float dist;
2877
2878                         Sys_Printf( "converting..." );
2879
2880                         for ( i = 0; i < numRawLightmaps; i++ )
2881                         {
2882                                 /* get lightmap */
2883                                 lm = &rawLightmaps[ i ];
2884
2885                                 /* walk lightmap samples */
2886                                 for ( y = 0; y < lm->sh; y++ )
2887                                 {
2888                                         for ( x = 0; x < lm->sw; x++ )
2889                                         {
2890                                                 /* get normal and deluxel */
2891                                                 normal = SUPER_NORMAL( x, y );
2892                                                 cluster = SUPER_CLUSTER( x, y );
2893                                                 bspDeluxel = BSP_DELUXEL( x, y );
2894                                                 deluxel = SUPER_DELUXEL( x, y );
2895
2896                                                 /* get normal */
2897                                                 VectorSet( myNormal, normal[0], normal[1], normal[2] );
2898
2899                                                 /* get tangent vectors */
2900                                                 if ( myNormal[ 0 ] == 0.0f && myNormal[ 1 ] == 0.0f ) {
2901                                                         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                                                         else if ( myNormal[ 2 ] == -1.0f ) {
2906                                                                 VectorSet( myTangent, -1.0f, 0.0f, 0.0f );
2907                                                                 VectorSet( myBinormal,  0.0f, 1.0f, 0.0f );
2908                                                         }
2909                                                 }
2910                                                 else
2911                                                 {
2912                                                         VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
2913                                                         CrossProduct( myNormal, worldUp, myTangent );
2914                                                         VectorNormalize( myTangent, myTangent );
2915                                                         CrossProduct( myTangent, myNormal, myBinormal );
2916                                                         VectorNormalize( myBinormal, myBinormal );
2917                                                 }
2918
2919                                                 /* project onto plane */
2920                                                 dist = -DotProduct( myTangent, myNormal );
2921                                                 VectorMA( myTangent, dist, myNormal, myTangent );
2922                                                 dist = -DotProduct( myBinormal, myNormal );
2923                                                 VectorMA( myBinormal, dist, myNormal, myBinormal );
2924
2925                                                 /* renormalize */
2926                                                 VectorNormalize( myTangent, myTangent );
2927                                                 VectorNormalize( myBinormal, myBinormal );
2928
2929                                                 /* convert modelspace deluxel to tangentspace */
2930                                                 dirSample[0] = bspDeluxel[0];
2931                                                 dirSample[1] = bspDeluxel[1];
2932                                                 dirSample[2] = bspDeluxel[2];
2933                                                 VectorNormalize( dirSample, dirSample );
2934
2935                                                 /* fix tangents to world matrix */
2936                                                 if ( myNormal[0] > 0 || myNormal[1] < 0 || myNormal[2] < 0 ) {
2937                                                         VectorNegate( myTangent, myTangent );
2938                                                 }
2939
2940                                                 /* build tangentspace vectors */
2941                                                 bspDeluxel[0] = DotProduct( dirSample, myTangent );
2942                                                 bspDeluxel[1] = DotProduct( dirSample, myBinormal );
2943                                                 bspDeluxel[2] = DotProduct( dirSample, myNormal );
2944                                         }
2945                                 }
2946                         }
2947                 }
2948         }
2949
2950         /* -----------------------------------------------------------------
2951            blend lightmaps
2952            ----------------------------------------------------------------- */
2953
2954 #ifdef sdfsdfwq312323
2955         /* note it */
2956         Sys_Printf( "blending..." );
2957
2958         for ( i = 0; i < numRawLightmaps; i++ )
2959         {
2960                 vec3_t myColor;
2961                 float myBrightness;
2962
2963                 /* get lightmap */
2964                 lm = &rawLightmaps[ i ];
2965
2966                 /* walk individual lightmaps */
2967                 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
2968                 {
2969                         /* early outs */
2970                         if ( lm->superLuxels[ lightmapNum ] == NULL ) {
2971                                 continue;
2972                         }
2973
2974                         /* walk lightmap samples */
2975                         for ( y = 0; y < lm->sh; y++ )
2976                         {
2977                                 for ( x = 0; x < lm->sw; x++ )
2978                                 {
2979                                         /* get luxel */
2980                                         bspLuxel = BSP_LUXEL( lightmapNum, x, y );
2981
2982                                         /* get color */
2983                                         VectorNormalize( bspLuxel, myColor );
2984                                         myBrightness = VectorLength( bspLuxel );
2985                                         myBrightness *= ( 1 / 127.0f );
2986                                         myBrightness = myBrightness * myBrightness;
2987                                         myBrightness *= 127.0f;
2988                                         VectorScale( myColor, myBrightness, bspLuxel );
2989                                 }
2990                         }
2991                 }
2992         }
2993 #endif
2994
2995         /* -----------------------------------------------------------------
2996            collapse non-unique lightmaps
2997            ----------------------------------------------------------------- */
2998
2999         if ( noCollapse == qfalse && deluxemap == qfalse ) {
3000                 /* note it */
3001                 Sys_FPrintf( SYS_VRB, "collapsing..." );
3002
3003                 /* set all twin refs to null */
3004                 for ( i = 0; i < numRawLightmaps; i++ )
3005                 {
3006                         for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3007                         {
3008                                 rawLightmaps[ i ].twins[ lightmapNum ] = NULL;
3009                                 rawLightmaps[ i ].twinNums[ lightmapNum ] = -1;
3010                                 rawLightmaps[ i ].numStyledTwins = 0;
3011                         }
3012                 }
3013
3014                 /* walk the list of raw lightmaps */
3015                 for ( i = 0; i < numRawLightmaps; i++ )
3016                 {
3017                         /* get lightmap */
3018                         lm = &rawLightmaps[ i ];
3019
3020                         /* walk lightmaps */
3021                         for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3022                         {
3023                                 /* early outs */
3024                                 if ( lm->bspLuxels[ lightmapNum ] == NULL ||
3025                                          lm->twins[ lightmapNum ] != NULL ) {
3026                                         continue;
3027                                 }
3028
3029                                 /* find all lightmaps that are virtually identical to this one */
3030                                 for ( j = i + 1; j < numRawLightmaps; j++ )
3031                                 {
3032                                         /* get lightmap */
3033                                         lm2 = &rawLightmaps[ j ];
3034
3035                                         /* walk lightmaps */
3036                                         for ( lightmapNum2 = 0; lightmapNum2 < MAX_LIGHTMAPS; lightmapNum2++ )
3037                                         {
3038                                                 /* early outs */
3039                                                 if ( lm2->bspLuxels[ lightmapNum2 ] == NULL ||
3040                                                          lm2->twins[ lightmapNum2 ] != NULL ) {
3041                                                         continue;
3042                                                 }
3043
3044                                                 /* compare them */
3045                                                 if ( CompareBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ) ) {
3046                                                         /* merge and set twin */
3047                                                         if ( MergeBSPLuxels( lm, lightmapNum, lm2, lightmapNum2 ) ) {
3048                                                                 lm2->twins[ lightmapNum2 ] = lm;
3049                                                                 lm2->twinNums[ lightmapNum2 ] = lightmapNum;
3050                                                                 numTwins++;
3051                                                                 numTwinLuxels += ( lm->w * lm->h );
3052
3053                                                                 /* count styled twins */
3054                                                                 if ( lightmapNum > 0 ) {
3055                                                                         lm->numStyledTwins++;
3056                                                                 }
3057                                                         }
3058                                                 }
3059                                         }
3060                                 }
3061                         }
3062                 }
3063         }
3064
3065         /* -----------------------------------------------------------------
3066            sort raw lightmaps by shader
3067            ----------------------------------------------------------------- */
3068
3069         /* note it */
3070         Sys_FPrintf( SYS_VRB, "sorting..." );
3071
3072         /* allocate a new sorted list */
3073         if ( sortLightmaps == NULL ) {
3074                 sortLightmaps = safe_malloc( numRawLightmaps * sizeof( int ) );
3075         }
3076
3077         /* fill it out and sort it */
3078         for ( i = 0; i < numRawLightmaps; i++ )
3079                 sortLightmaps[ i ] = i;
3080         qsort( sortLightmaps, numRawLightmaps, sizeof( int ), CompareRawLightmap );
3081
3082         /* -----------------------------------------------------------------
3083            allocate output lightmaps
3084            ----------------------------------------------------------------- */
3085
3086         /* note it */
3087         Sys_FPrintf( SYS_VRB, "allocating..." );
3088
3089         /* kill all existing output lightmaps */
3090         if ( outLightmaps != NULL ) {
3091                 for ( i = 0; i < numOutLightmaps; i++ )
3092                 {
3093                         free( outLightmaps[ i ].lightBits );
3094                         free( outLightmaps[ i ].bspLightBytes );
3095                 }
3096                 free( outLightmaps );
3097                 outLightmaps = NULL;
3098         }
3099
3100         numLightmapShaders = 0;
3101         numOutLightmaps = 0;
3102         numBSPLightmaps = 0;
3103         numExtLightmaps = 0;
3104
3105         /* find output lightmap */
3106         for ( i = 0; i < numRawLightmaps; i++ )
3107         {
3108                 lm = &rawLightmaps[ sortLightmaps[ i ] ];
3109                 FindOutLightmaps( lm, fastAllocate );
3110         }
3111
3112         /* set output numbers in twinned lightmaps */
3113         for ( i = 0; i < numRawLightmaps; i++ )
3114         {
3115                 /* get lightmap */
3116                 lm = &rawLightmaps[ sortLightmaps[ i ] ];
3117
3118                 /* walk lightmaps */
3119                 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3120                 {
3121                         /* get twin */
3122                         lm2 = lm->twins[ lightmapNum ];
3123                         if ( lm2 == NULL ) {
3124                                 continue;
3125                         }
3126                         lightmapNum2 = lm->twinNums[ lightmapNum ];
3127
3128                         /* find output lightmap from twin */
3129                         lm->outLightmapNums[ lightmapNum ] = lm2->outLightmapNums[ lightmapNum2 ];
3130                         lm->lightmapX[ lightmapNum ] = lm2->lightmapX[ lightmapNum2 ];
3131                         lm->lightmapY[ lightmapNum ] = lm2->lightmapY[ lightmapNum2 ];
3132                 }
3133         }
3134
3135         /* -----------------------------------------------------------------
3136            store output lightmaps
3137            ----------------------------------------------------------------- */
3138
3139         /* note it */
3140         Sys_FPrintf( SYS_VRB, "storing..." );
3141
3142         /* count the bsp lightmaps and allocate space */
3143         if ( bspLightBytes != NULL ) {
3144                 free( bspLightBytes );
3145         }
3146         if ( numBSPLightmaps == 0 || externalLightmaps ) {
3147                 numBSPLightBytes = 0;
3148                 bspLightBytes = NULL;
3149         }
3150         else
3151         {
3152                 numBSPLightBytes = ( numBSPLightmaps * game->lightmapSize * game->lightmapSize * 3 );
3153                 bspLightBytes = safe_malloc( numBSPLightBytes );
3154                 memset( bspLightBytes, 0, numBSPLightBytes );
3155         }
3156
3157         /* walk the list of output lightmaps */
3158         for ( i = 0; i < numOutLightmaps; i++ )
3159         {
3160                 /* get output lightmap */
3161                 olm = &outLightmaps[ i ];
3162
3163                 /* fill output lightmap */
3164                 if ( lightmapFill ) {
3165                         FillOutLightmap( olm );
3166                 }
3167
3168                 /* is this a valid bsp lightmap? */
3169                 if ( olm->lightmapNum >= 0 && !externalLightmaps ) {
3170                         /* copy lighting data */
3171                         lb = bspLightBytes + ( olm->lightmapNum * game->lightmapSize * game->lightmapSize * 3 );
3172                         memcpy( lb, olm->bspLightBytes, game->lightmapSize * game->lightmapSize * 3 );
3173
3174                         /* copy direction data */
3175                         if ( deluxemap ) {
3176                                 lb = bspLightBytes + ( ( olm->lightmapNum + 1 ) * game->lightmapSize * game->lightmapSize * 3 );
3177                                 memcpy( lb, olm->bspDirBytes, game->lightmapSize * game->lightmapSize * 3 );
3178                         }
3179                 }
3180
3181                 /* external lightmap? */
3182                 if ( olm->lightmapNum < 0 || olm->extLightmapNum >= 0 || externalLightmaps ) {
3183                         /* make a directory for the lightmaps */
3184                         Q_mkdir( dirname );
3185
3186                         /* set external lightmap number */
3187                         olm->extLightmapNum = numExtLightmaps;
3188
3189                         /* write lightmap */
3190                         sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
3191                         Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
3192                         WriteTGA24( filename, olm->bspLightBytes, olm->customWidth, olm->customHeight, qtrue );
3193                         numExtLightmaps++;
3194
3195                         /* write deluxemap */
3196                         if ( deluxemap ) {
3197                                 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, numExtLightmaps );
3198                                 Sys_FPrintf( SYS_VRB, "\nwriting %s", filename );
3199                                 WriteTGA24( filename, olm->bspDirBytes, olm->customWidth, olm->customHeight, qtrue );
3200                                 numExtLightmaps++;
3201
3202                                 if ( debugDeluxemap ) {
3203                                         olm->extLightmapNum++;
3204                                 }
3205                         }
3206                 }
3207         }
3208
3209         if ( numExtLightmaps > 0 ) {
3210                 Sys_FPrintf( SYS_VRB, "\n" );
3211         }
3212
3213         /* delete unused external lightmaps */
3214         for ( i = numExtLightmaps; i; i++ )
3215         {
3216                 /* determine if file exists */
3217                 sprintf( filename, "%s/" EXTERNAL_LIGHTMAP, dirname, i );
3218                 if ( !FileExists( filename ) ) {
3219                         break;
3220                 }
3221
3222                 /* delete it */
3223                 remove( filename );
3224         }
3225
3226         /* -----------------------------------------------------------------
3227            project the lightmaps onto the bsp surfaces
3228            ----------------------------------------------------------------- */
3229
3230         /* note it */
3231         Sys_FPrintf( SYS_VRB, "projecting..." );
3232
3233         /* walk the list of surfaces */
3234         for ( i = 0; i < numBSPDrawSurfaces; i++ )
3235         {
3236                 /* get the surface and info */
3237                 ds = &bspDrawSurfaces[ i ];
3238                 info = &surfaceInfos[ i ];
3239                 lm = info->lm;
3240                 olm = NULL;
3241
3242                 /* handle surfaces with identical parent */
3243                 if ( info->parentSurfaceNum >= 0 ) {
3244                         /* preserve original data and get parent */
3245                         parent = &bspDrawSurfaces[ info->parentSurfaceNum ];
3246                         memcpy( &dsTemp, ds, sizeof( *ds ) );
3247
3248                         /* overwrite child with parent data */
3249                         memcpy( ds, parent, sizeof( *ds ) );
3250
3251                         /* restore key parts */
3252                         ds->fogNum = dsTemp.fogNum;
3253                         ds->firstVert = dsTemp.firstVert;
3254                         ds->firstIndex = dsTemp.firstIndex;
3255                         memcpy( ds->lightmapVecs, dsTemp.lightmapVecs, sizeof( dsTemp.lightmapVecs ) );
3256
3257                         /* set vertex data */
3258                         dv = &bspDrawVerts[ ds->firstVert ];
3259                         dvParent = &bspDrawVerts[ parent->firstVert ];
3260                         for ( j = 0; j < ds->numVerts; j++ )
3261                         {
3262                                 memcpy( dv[ j ].lightmap, dvParent[ j ].lightmap, sizeof( dv[ j ].lightmap ) );
3263                                 memcpy( dv[ j ].color, dvParent[ j ].color, sizeof( dv[ j ].color ) );
3264                         }
3265
3266                         /* skip the rest */
3267                         continue;
3268                 }
3269
3270                 /* handle vertex lit or approximated surfaces */
3271                 else if ( lm == NULL || lm->outLightmapNums[ 0 ] < 0 ) {
3272                         for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3273                         {
3274                                 ds->lightmapNum[ lightmapNum ] = -3;
3275                                 ds->lightmapStyles[ lightmapNum ] = ds->vertexStyles[ lightmapNum ];
3276                         }
3277                 }
3278
3279                 /* handle lightmapped surfaces */
3280                 else
3281                 {
3282                         /* walk lightmaps */
3283                         for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3284                         {
3285                                 /* set style */
3286                                 ds->lightmapStyles[ lightmapNum ] = lm->styles[ lightmapNum ];
3287
3288                                 /* handle unused style */
3289                                 if ( lm->styles[ lightmapNum ] == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 ) {
3290                                         ds->lightmapNum[ lightmapNum ] = -3;
3291                                         continue;
3292                                 }
3293
3294                                 /* get output lightmap */
3295                                 olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
3296
3297                                 /* set bsp lightmap number */
3298                                 ds->lightmapNum[ lightmapNum ] = olm->lightmapNum;
3299
3300                                 /* deluxemap debugging makes the deluxemap visible */
3301                                 if ( deluxemap && debugDeluxemap && lightmapNum == 0 ) {
3302                                         ds->lightmapNum[ lightmapNum ]++;
3303                                 }
3304
3305                                 /* calc lightmap origin in texture space */
3306                                 lmx = (float) lm->lightmapX[ lightmapNum ] / (float) olm->customWidth;
3307                                 lmy = (float) lm->lightmapY[ lightmapNum ] / (float) olm->customHeight;
3308
3309                                 /* calc lightmap st coords */
3310                                 dv = &bspDrawVerts[ ds->firstVert ];
3311                                 ydv = &yDrawVerts[ ds->firstVert ];
3312                                 for ( j = 0; j < ds->numVerts; j++ )
3313                                 {
3314                                         if ( lm->solid[ lightmapNum ] ) {
3315                                                 dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + ( 0.5f / (float) olm->customWidth );
3316                                                 dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + ( 0.5f / (float) olm->customWidth );
3317                                         }
3318                                         else
3319                                         {
3320                                                 dv[ j ].lightmap[ lightmapNum ][ 0 ] = lmx + ( ydv[ j ].lightmap[ 0 ][ 0 ] / ( superSample * olm->customWidth ) );
3321                                                 dv[ j ].lightmap[ lightmapNum ][ 1 ] = lmy + ( ydv[ j ].lightmap[ 0 ][ 1 ] / ( superSample * olm->customHeight ) );
3322                                         }
3323                                 }
3324                         }
3325                 }
3326
3327                 /* store vertex colors */
3328                 dv = &bspDrawVerts[ ds->firstVert ];
3329                 for ( j = 0; j < ds->numVerts; j++ )
3330                 {
3331                         /* walk lightmaps */
3332                         for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3333                         {
3334                                 /* handle unused style */
3335                                 if ( ds->vertexStyles[ lightmapNum ] == LS_NONE ) {
3336                                         VectorClear( color );
3337                                 }
3338                                 else
3339                                 {
3340                                         /* get vertex color */
3341                                         luxel = VERTEX_LUXEL( lightmapNum, ds->firstVert + j );
3342                                         VectorCopy( luxel, color );
3343
3344                                         /* set minimum light */
3345                                         if ( lightmapNum == 0 ) {
3346                                                 for ( k = 0; k < 3; k++ )
3347                                                         if ( color[ k ] < minVertexLight[ k ] ) {
3348                                                                 color[ k ] = minVertexLight[ k ];
3349                                                         }
3350                                         }
3351                                 }
3352
3353                                 /* store to bytes */
3354                                 if ( !info->si->noVertexLight ) {
3355                                         ColorToBytes( color, dv[ j ].color[ lightmapNum ], info->si->vertexScale );
3356                                 }
3357                         }
3358                 }
3359
3360                 /* surfaces with styled lightmaps and a style marker get a custom generated shader (fixme: make this work with external lightmaps) */
3361                 if ( olm != NULL && lm != NULL && lm->styles[ 1 ] != LS_NONE && game->load != LoadRBSPFile ) { //%      info->si->styleMarker > 0 )
3362                         qboolean dfEqual;
3363                         char key[ 32 ], styleStage[ 512 ], styleStages[ 4096 ], rgbGen[ 128 ], alphaGen[ 128 ];
3364
3365
3366                         /* setup */
3367                         sprintf( styleStages, "\n\t// Q3Map2 custom lightstyle stage(s)\n" );
3368                         dv = &bspDrawVerts[ ds->firstVert ];
3369
3370                         /* depthFunc equal? */
3371                         if ( info->si->styleMarker == 2 || info->si->implicitMap == IM_MASKED ) {
3372                                 dfEqual = qtrue;
3373                         }
3374                         else{
3375                                 dfEqual = qfalse;
3376                         }
3377
3378                         /* generate stages for styled lightmaps */
3379                         for ( lightmapNum = 1; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
3380                         {
3381                                 /* early out */
3382                                 style = lm->styles[ lightmapNum ];
3383                                 if ( style == LS_NONE || lm->outLightmapNums[ lightmapNum ] < 0 ) {
3384                                         continue;
3385                                 }
3386
3387                                 /* get output lightmap */
3388                                 olm = &outLightmaps[ lm->outLightmapNums[ lightmapNum ] ];
3389
3390                                 /* lightmap name */
3391                                 if ( lm->outLightmapNums[ lightmapNum ] == lm->outLightmapNums[ 0 ] ) {
3392                                         strcpy( lightmapName, "$lightmap" );
3393                                 }
3394                                 else{
3395                                         sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
3396                                 }
3397
3398                                 /* get rgbgen string */
3399                                 if ( rgbGenValues[ style ] == NULL ) {
3400                                         sprintf( key, "_style%drgbgen", style );
3401                                         rgbGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
3402                                         if ( rgbGenValues[ style ][ 0 ] == '\0' ) {
3403                                                 rgbGenValues[ style ] = "wave noise 0.5 1 0 5.37";
3404                                         }
3405                                 }
3406                                 rgbGen[ 0 ] = '\0';
3407                                 if ( rgbGenValues[ style ][ 0 ] != '\0' ) {
3408                                         sprintf( rgbGen, "\t\trgbGen %s // style %d\n", rgbGenValues[ style ], style );
3409                                 }
3410                                 else{
3411                                         rgbGen[ 0 ] = '\0';
3412                                 }
3413
3414                                 /* get alphagen string */
3415                                 if ( alphaGenValues[ style ] == NULL ) {
3416                                         sprintf( key, "_style%dalphagen", style );
3417                                         alphaGenValues[ style ] = ValueForKey( &entities[ 0 ], key );
3418                                 }
3419                                 if ( alphaGenValues[ style ][ 0 ] != '\0' ) {
3420                                         sprintf( alphaGen, "\t\talphaGen %s // style %d\n", alphaGenValues[ style ], style );
3421                                 }
3422                                 else{
3423                                         alphaGen[ 0 ] = '\0';
3424                                 }
3425
3426                                 /* calculate st offset */
3427                                 lmx = dv[ 0 ].lightmap[ lightmapNum ][ 0 ] - dv[ 0 ].lightmap[ 0 ][ 0 ];
3428                                 lmy = dv[ 0 ].lightmap[ lightmapNum ][ 1 ] - dv[ 0 ].lightmap[ 0 ][ 1 ];
3429
3430                                 /* create additional stage */
3431                                 if ( lmx == 0.0f && lmy == 0.0f ) {
3432                                         sprintf( styleStage,    "\t{\n"
3433                                                                                         "\t\tmap %s\n"                                      /* lightmap */
3434                                                                                         "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
3435                                                                                         "%s"                                                /* depthFunc equal */
3436                                                                                         "%s"                                                /* rgbGen */
3437                                                                                         "%s"                                                /* alphaGen */
3438                                                                                         "\t\ttcGen lightmap\n"
3439                                                                                         "\t}\n",
3440                                                          lightmapName,
3441                                                          ( dfEqual ? "\t\tdepthFunc equal\n" : "" ),
3442                                                          rgbGen,
3443                                                          alphaGen );
3444                                 }
3445                                 else
3446                                 {
3447                                         sprintf( styleStage,    "\t{\n"
3448                                                                                         "\t\tmap %s\n"                                      /* lightmap */
3449                                                                                         "\t\tblendFunc GL_SRC_ALPHA GL_ONE\n"
3450                                                                                         "%s"                                                /* depthFunc equal */
3451                                                                                         "%s"                                                /* rgbGen */
3452                                                                                         "%s"                                                /* alphaGen */
3453                                                                                         "\t\ttcGen lightmap\n"
3454                                                                                         "\t\ttcMod transform 1 0 0 1 %1.5f %1.5f\n"         /* st offset */
3455                                                                                         "\t}\n",
3456                                                          lightmapName,
3457                                                          ( dfEqual ? "\t\tdepthFunc equal\n" : "" ),
3458                                                          rgbGen,
3459                                                          alphaGen,
3460                                                          lmx, lmy );
3461
3462                                 }
3463
3464                                 /* concatenate */
3465                                 strcat( styleStages, styleStage );
3466                         }
3467
3468                         /* create custom shader */
3469                         if ( info->si->styleMarker == 2 ) {
3470                                 csi = CustomShader( info->si, "q3map_styleMarker2", styleStages );
3471                         }
3472                         else{
3473                                 csi = CustomShader( info->si, "q3map_styleMarker", styleStages );
3474                         }
3475
3476                         /* emit remap command */
3477                         //%     EmitVertexRemapShader( csi->shader, info->si->shader );
3478
3479                         /* store it */
3480                         //%     Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
3481                         ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3482                         //%     Sys_Printf( ")\n" );
3483                 }
3484
3485                 /* devise a custom shader for this surface (fixme: make this work with light styles) */
3486                 else if ( olm != NULL && lm != NULL && !externalLightmaps &&
3487                                   ( olm->customWidth != game->lightmapSize || olm->customHeight != game->lightmapSize ) ) {
3488                         /* get output lightmap */
3489                         olm = &outLightmaps[ lm->outLightmapNums[ 0 ] ];
3490
3491                         /* do some name mangling */
3492                         sprintf( lightmapName, "maps/%s/" EXTERNAL_LIGHTMAP, mapName, olm->extLightmapNum );
3493
3494                         /* create custom shader */
3495                         csi = CustomShader( info->si, "$lightmap", lightmapName );
3496
3497                         /* store it */
3498                         //%     Sys_Printf( "Emitting: %s (%d", csi->shader, strlen( csi->shader ) );
3499                         ds->shaderNum = EmitShader( csi->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3500                         //%     Sys_Printf( ")\n" );
3501                 }
3502
3503                 /* use the normal plain-jane shader */
3504                 else{
3505                         ds->shaderNum = EmitShader( info->si->shader, &bspShaders[ ds->shaderNum ].contentFlags, &bspShaders[ ds->shaderNum ].surfaceFlags );
3506                 }
3507         }
3508
3509         /* finish */
3510         Sys_FPrintf( SYS_VRB, "done.\n" );
3511
3512         /* calc num stored */
3513         numStored = numBSPLightBytes / 3;
3514         efficiency = ( numStored <= 0 )
3515                                  ? 0
3516                                  : (float) numUsed / (float) numStored;
3517
3518         /* print stats */
3519         Sys_Printf( "%9d luxels used\n", numUsed );
3520         Sys_Printf( "%9d luxels stored (%3.2f percent efficiency)\n", numStored, efficiency * 100.0f );
3521         Sys_Printf( "%9d solid surface lightmaps\n", numSolidLightmaps );
3522         Sys_Printf( "%9d identical surface lightmaps, using %d luxels\n", numTwins, numTwinLuxels );
3523         Sys_Printf( "%9d vertex forced surfaces\n", numSurfsVertexForced );
3524         Sys_Printf( "%9d vertex approximated surfaces\n", numSurfsVertexApproximated );
3525         Sys_Printf( "%9d BSP lightmaps\n", numBSPLightmaps );
3526         Sys_Printf( "%9d total lightmaps\n", numOutLightmaps );
3527         Sys_Printf( "%9d unique lightmap/shader combinations\n", numLightmapShaders );
3528
3529         /* write map shader file */
3530         WriteMapShaderFile();
3531 }