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