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