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 LIGHT_BOUNCE_C
33 
34 
35 
36 /* dependencies */
37 #include "q3map2.h"
38 
39 
40 
41 /* functions */
42 
43 /*
44    RadFreeLights()
45    deletes any existing lights, freeing up memory for the next bounce
46  */
47 
RadFreeLights(void)48 void RadFreeLights( void ){
49 	light_t     *light, *next;
50 
51 
52 	/* delete lights */
53 	for ( light = lights; light; light = next )
54 	{
55 		next = light->next;
56 		if ( light->w != NULL ) {
57 			FreeWinding( light->w );
58 		}
59 		free( light );
60 	}
61 	numLights = 0;
62 	lights = NULL;
63 }
64 
65 
66 
67 /*
68    RadClipWindingEpsilon()
69    clips a rad winding by a plane
70    based off the regular clip winding code
71  */
72 
RadClipWindingEpsilon(radWinding_t * in,vec3_t normal,vec_t dist,vec_t epsilon,radWinding_t * front,radWinding_t * back,clipWork_t * cw)73 static void RadClipWindingEpsilon( radWinding_t *in, vec3_t normal, vec_t dist,
74 								   vec_t epsilon, radWinding_t *front, radWinding_t *back, clipWork_t *cw ){
75 	vec_t           *dists;
76 	int             *sides;
77 	int counts[ 3 ];
78 	vec_t dot;                  /* ydnar: changed from static b/c of threading */ /* VC 4.2 optimizer bug if not static? */
79 	int i, j, k;
80 	radVert_t       *v1, *v2, mid;
81 	int maxPoints;
82 
83 
84 	/* crutch */
85 	dists = cw->dists;
86 	sides = cw->sides;
87 
88 	/* clear counts */
89 	counts[ 0 ] = counts[ 1 ] = counts[ 2 ] = 0;
90 
91 	/* determine sides for each point */
92 	for ( i = 0; i < in->numVerts; i++ )
93 	{
94 		dot = DotProduct( in->verts[ i ].xyz, normal );
95 		dot -= dist;
96 		dists[ i ] = dot;
97 		if ( dot > epsilon ) {
98 			sides[ i ] = SIDE_FRONT;
99 		}
100 		else if ( dot < -epsilon ) {
101 			sides[ i ] = SIDE_BACK;
102 		}
103 		else{
104 			sides[ i ] = SIDE_ON;
105 		}
106 		counts[ sides[ i ] ]++;
107 	}
108 	sides[ i ] = sides[ 0 ];
109 	dists[ i ] = dists[ 0 ];
110 
111 	/* clear front and back */
112 	front->numVerts = back->numVerts = 0;
113 
114 	/* handle all on one side cases */
115 	if ( counts[ 0 ] == 0 ) {
116 		memcpy( back, in, sizeof( radWinding_t ) );
117 		return;
118 	}
119 	if ( counts[ 1 ] == 0 ) {
120 		memcpy( front, in, sizeof( radWinding_t ) );
121 		return;
122 	}
123 
124 	/* setup windings */
125 	maxPoints = in->numVerts + 4;
126 
127 	/* do individual verts */
128 	for ( i = 0; i < in->numVerts; i++ )
129 	{
130 		/* do simple vertex copies first */
131 		v1 = &in->verts[ i ];
132 
133 		if ( sides[ i ] == SIDE_ON ) {
134 			memcpy( &front->verts[ front->numVerts++ ], v1, sizeof( radVert_t ) );
135 			memcpy( &back->verts[ back->numVerts++ ], v1, sizeof( radVert_t ) );
136 			continue;
137 		}
138 
139 		if ( sides[ i ] == SIDE_FRONT ) {
140 			memcpy( &front->verts[ front->numVerts++ ], v1, sizeof( radVert_t ) );
141 		}
142 
143 		if ( sides[ i ] == SIDE_BACK ) {
144 			memcpy( &back->verts[ back->numVerts++ ], v1, sizeof( radVert_t ) );
145 		}
146 
147 		if ( sides[ i + 1 ] == SIDE_ON || sides[ i + 1 ] == sides[ i ] ) {
148 			continue;
149 		}
150 
151 		/* generate a split vertex */
152 		v2 = &in->verts[ ( i + 1 ) % in->numVerts ];
153 
154 		dot = dists[ i ] / ( dists[ i ] - dists[ i + 1 ] );
155 
156 		/* average vertex values */
157 		for ( j = 0; j < 4; j++ )
158 		{
159 			/* color */
160 			if ( j < 4 ) {
161 				for ( k = 0; k < MAX_LIGHTMAPS; k++ )
162 					mid.color[ k ][ j ] = v1->color[ k ][ j ] + dot * ( v2->color[ k ][ j ] - v1->color[ k ][ j ] );
163 			}
164 
165 			/* xyz, normal */
166 			if ( j < 3 ) {
167 				mid.xyz[ j ] = v1->xyz[ j ] + dot * ( v2->xyz[ j ] - v1->xyz[ j ] );
168 				mid.normal[ j ] = v1->normal[ j ] + dot * ( v2->normal[ j ] - v1->normal[ j ] );
169 			}
170 
171 			/* st, lightmap */
172 			if ( j < 2 ) {
173 				mid.st[ j ] = v1->st[ j ] + dot * ( v2->st[ j ] - v1->st[ j ] );
174 				for ( k = 0; k < MAX_LIGHTMAPS; k++ )
175 					mid.lightmap[ k ][ j ] = v1->lightmap[ k ][ j ] + dot * ( v2->lightmap[ k ][ j ] - v1->lightmap[ k ][ j ] );
176 			}
177 		}
178 
179 		/* normalize the averaged normal */
180 		VectorNormalize( mid.normal, mid.normal );
181 
182 		/* copy the midpoint to both windings */
183 		memcpy( &front->verts[ front->numVerts++ ], &mid, sizeof( radVert_t ) );
184 		memcpy( &back->verts[ back->numVerts++ ], &mid, sizeof( radVert_t ) );
185 	}
186 
187 	/* error check */
188 	if ( front->numVerts > maxPoints || front->numVerts > maxPoints ) {
189 		Error( "RadClipWindingEpsilon: points exceeded estimate" );
190 	}
191 	if ( front->numVerts > MAX_POINTS_ON_WINDING || front->numVerts > MAX_POINTS_ON_WINDING ) {
192 		Error( "RadClipWindingEpsilon: MAX_POINTS_ON_WINDING" );
193 	}
194 }
195 
196 
197 
198 
199 
200 /*
201    RadSampleImage()
202    samples a texture image for a given color
203    returns qfalse if pixels are bad
204  */
205 
RadSampleImage(byte * pixels,int width,int height,float st[2],float color[4])206 qboolean RadSampleImage( byte *pixels, int width, int height, float st[ 2 ], float color[ 4 ] ){
207 	float sto[ 2 ];
208 	int x, y;
209 
210 
211 	/* clear color first */
212 	color[ 0 ] = color[ 1 ] = color[ 2 ] = color[ 3 ] = 255;
213 
214 	/* dummy check */
215 	if ( pixels == NULL || width < 1 || height < 1 ) {
216 		return qfalse;
217 	}
218 
219 	/* bias st */
220 	sto[ 0 ] = st[ 0 ];
221 	while ( sto[ 0 ] < 0.0f )
222 		sto[ 0 ] += 1.0f;
223 	sto[ 1 ] = st[ 1 ];
224 	while ( sto[ 1 ] < 0.0f )
225 		sto[ 1 ] += 1.0f;
226 
227 	/* get offsets */
228 	x = ( (float) width * sto[ 0 ] ) + 0.5f;
229 	x %= width;
230 	y = ( (float) height * sto[ 1 ] )  + 0.5f;
231 	y %= height;
232 
233 	/* get pixel */
234 	pixels += ( y * width * 4 ) + ( x * 4 );
235 	VectorCopy( pixels, color );
236 	color[ 3 ] = pixels[ 3 ];
237 
238 	if ( texturesRGB ) {
239 		color[0] = Image_LinearFloatFromsRGBFloat( color[0] * ( 1.0 / 255.0 ) ) * 255.0;
240 		color[1] = Image_LinearFloatFromsRGBFloat( color[1] * ( 1.0 / 255.0 ) ) * 255.0;
241 		color[2] = Image_LinearFloatFromsRGBFloat( color[2] * ( 1.0 / 255.0 ) ) * 255.0;
242 	}
243 
244 	return qtrue;
245 }
246 
247 
248 
249 /*
250    RadSample()
251    samples a fragment's lightmap or vertex color and returns an
252    average color and a color gradient for the sample
253  */
254 
255 #define MAX_SAMPLES         150
256 #define SAMPLE_GRANULARITY  6
257 
RadSample(int lightmapNum,bspDrawSurface_t * ds,rawLightmap_t * lm,shaderInfo_t * si,radWinding_t * rw,vec3_t average,vec3_t gradient,int * style)258 static void RadSample( int lightmapNum, bspDrawSurface_t *ds, rawLightmap_t *lm, shaderInfo_t *si, radWinding_t *rw, vec3_t average, vec3_t gradient, int *style ){
259 	int i, j, k, l, v, x, y, samples;
260 	vec3_t color, mins, maxs;
261 	vec4_t textureColor;
262 	float alpha, alphaI, bf;
263 	vec3_t blend;
264 	float st[ 2 ], lightmap[ 2 ], *radLuxel;
265 	radVert_t   *rv[ 3 ];
266 
267 	if (!bouncing)
268 		Sys_Printf( "BUG: RadSample: !bouncing shouldn't happen\n" );
269 
270 	/* initial setup */
271 	ClearBounds( mins, maxs );
272 	VectorClear( average );
273 	VectorClear( gradient );
274 	alpha = 0;
275 
276 	/* dummy check */
277 	if ( rw == NULL || rw->numVerts < 3 ) {
278 		return;
279 	}
280 
281 	/* start sampling */
282 	samples = 0;
283 
284 	/* sample vertex colors if no lightmap or this is the initial pass */
285 	if ( lm == NULL || lm->radLuxels[ lightmapNum ] == NULL || bouncing == qfalse ) {
286 		for ( samples = 0; samples < rw->numVerts; samples++ )
287 		{
288 			/* multiply by texture color */
289 			if ( !RadSampleImage( si->lightImage->pixels, si->lightImage->width, si->lightImage->height, rw->verts[ samples ].st, textureColor ) ) {
290 				VectorCopy( si->averageColor, textureColor );
291 				textureColor[ 4 ] = 255.0f;
292 			}
293 			for ( i = 0; i < 3; i++ )
294 				color[ i ] = ( textureColor[ i ] / 255 ) * ( rw->verts[ samples ].color[ lightmapNum ][ i ] / 255.0f );
295 
296 			AddPointToBounds( color, mins, maxs );
297 			VectorAdd( average, color, average );
298 
299 			/* get alpha */
300 			alpha += ( textureColor[ 3 ] / 255.0f ) * ( rw->verts[ samples ].color[ lightmapNum ][ 3 ] / 255.0f );
301 		}
302 
303 		/* set style */
304 		*style = ds->vertexStyles[ lightmapNum ];
305 	}
306 
307 	/* sample lightmap */
308 	else
309 	{
310 		/* fracture the winding into a fan (including degenerate tris) */
311 		for ( v = 1; v < ( rw->numVerts - 1 ) && samples < MAX_SAMPLES; v++ )
312 		{
313 			/* get a triangle */
314 			rv[ 0 ] = &rw->verts[ 0 ];
315 			rv[ 1 ] = &rw->verts[ v ];
316 			rv[ 2 ] = &rw->verts[ v + 1 ];
317 
318 			/* this code is embarassing (really should just rasterize the triangle) */
319 			for ( i = 1; i < SAMPLE_GRANULARITY && samples < MAX_SAMPLES; i++ )
320 			{
321 				for ( j = 1; j < SAMPLE_GRANULARITY && samples < MAX_SAMPLES; j++ )
322 				{
323 					for ( k = 1; k < SAMPLE_GRANULARITY && samples < MAX_SAMPLES; k++ )
324 					{
325 						/* create a blend vector (barycentric coordinates) */
326 						blend[ 0 ] = i;
327 						blend[ 1 ] = j;
328 						blend[ 2 ] = k;
329 						bf = ( 1.0 / ( blend[ 0 ] + blend[ 1 ] + blend[ 2 ] ) );
330 						VectorScale( blend, bf, blend );
331 
332 						/* create a blended sample */
333 						st[ 0 ] = st[ 1 ] = 0.0f;
334 						lightmap[ 0 ] = lightmap[ 1 ] = 0.0f;
335 						alphaI = 0.0f;
336 						for ( l = 0; l < 3; l++ )
337 						{
338 							st[ 0 ] += ( rv[ l ]->st[ 0 ] * blend[ l ] );
339 							st[ 1 ] += ( rv[ l ]->st[ 1 ] * blend[ l ] );
340 							lightmap[ 0 ] += ( rv[ l ]->lightmap[ lightmapNum ][ 0 ] * blend[ l ] );
341 							lightmap[ 1 ] += ( rv[ l ]->lightmap[ lightmapNum ][ 1 ] * blend[ l ] );
342 							alphaI += ( rv[ l ]->color[ lightmapNum ][ 3 ] * blend[ l ] );
343 						}
344 
345 						/* get lightmap xy coords */
346 						x = lightmap[ 0 ] / (float) superSample;
347 						y = lightmap[ 1 ] / (float) superSample;
348 						if ( x < 0 ) {
349 							x = 0;
350 						}
351 						else if ( x >= lm->w ) {
352 							x = lm->w - 1;
353 						}
354 						if ( y < 0 ) {
355 							y = 0;
356 						}
357 						else if ( y >= lm->h ) {
358 							y = lm->h - 1;
359 						}
360 
361 						/* get radiosity luxel */
362 						radLuxel = RAD_LUXEL( lightmapNum, x, y );
363 
364 						/* ignore unlit/unused luxels */
365 						if ( radLuxel[ 0 ] < 0.0f ) {
366 							continue;
367 						}
368 
369 						/* inc samples */
370 						samples++;
371 
372 						/* multiply by texture color */
373 						if ( !RadSampleImage( si->lightImage->pixels, si->lightImage->width, si->lightImage->height, st, textureColor ) ) {
374 							VectorCopy( si->averageColor, textureColor );
375 							textureColor[ 4 ] = 255;
376 						}
377 						for ( i = 0; i < 3; i++ )
378 							color[ i ] = ( textureColor[ i ] / 255 ) * ( radLuxel[ i ] / 255 );
379 
380 						AddPointToBounds( color, mins, maxs );
381 						VectorAdd( average, color, average );
382 
383 						/* get alpha */
384 						alpha += ( textureColor[ 3 ] / 255 ) * ( alphaI / 255 );
385 					}
386 				}
387 			}
388 		}
389 
390 		/* set style */
391 		*style = ds->lightmapStyles[ lightmapNum ];
392 	}
393 
394 	/* any samples? */
395 	if ( samples <= 0 ) {
396 		return;
397 	}
398 
399 	/* average the color */
400 	VectorScale( average, ( 1.0 / samples ), average );
401 
402 	/* create the color gradient */
403 	//%	VectorSubtract( maxs, mins, delta );
404 
405 	/* new: color gradient will always be 0-1.0, expressed as the range of light relative to overall light */
406 	//%	gradient[ 0 ] = maxs[ 0 ] > 0.0f ? (maxs[ 0 ] - mins[ 0 ]) / maxs[ 0 ] : 0.0f;
407 	//%	gradient[ 1 ] = maxs[ 1 ] > 0.0f ? (maxs[ 1 ] - mins[ 1 ]) / maxs[ 1 ] : 0.0f;
408 	//%	gradient[ 2 ] = maxs[ 2 ] > 0.0f ? (maxs[ 2 ] - mins[ 2 ]) / maxs[ 2 ] : 0.0f;
409 
410 	/* newer: another contrast function */
411 	for ( i = 0; i < 3; i++ )
412 		gradient[ i ] = ( maxs[ i ] - mins[ i ] ) * maxs[ i ];
413 }
414 
415 
416 
417 /*
418    RadSubdivideDiffuseLight()
419    subdivides a radiosity winding until it is smaller than subdivide, then generates an area light
420  */
421 
422 #define RADIOSITY_MAX_GRADIENT      0.75f   //%	0.25f
423 #define RADIOSITY_VALUE             500.0f
424 #define RADIOSITY_MIN               0.0001f
425 #define RADIOSITY_CLIP_EPSILON      0.125f
426 
RadSubdivideDiffuseLight(int lightmapNum,bspDrawSurface_t * ds,rawLightmap_t * lm,shaderInfo_t * si,float scale,float subdivide,qboolean original,radWinding_t * rw,clipWork_t * cw)427 static void RadSubdivideDiffuseLight( int lightmapNum, bspDrawSurface_t *ds, rawLightmap_t *lm, shaderInfo_t *si,
428 									  float scale, float subdivide, qboolean original, radWinding_t *rw, clipWork_t *cw ){
429 	int i, style = 0;
430 	float dist, area, value;
431 	vec3_t mins, maxs, normal, d1, d2, cross, color, gradient;
432 	light_t         *light, *splash;
433 	winding_t       *w;
434 
435 
436 	/* dummy check */
437 	if ( rw == NULL || rw->numVerts < 3 ) {
438 		return;
439 	}
440 
441 	/* get bounds for winding */
442 	ClearBounds( mins, maxs );
443 	for ( i = 0; i < rw->numVerts; i++ )
444 		AddPointToBounds( rw->verts[ i ].xyz, mins, maxs );
445 
446 	/* subdivide if necessary */
447 	for ( i = 0; i < 3; i++ )
448 	{
449 		if ( maxs[ i ] - mins[ i ] > subdivide ) {
450 			radWinding_t front, back;
451 
452 
453 			/* make axial plane */
454 			VectorClear( normal );
455 			normal[ i ] = 1;
456 			dist = ( maxs[ i ] + mins[ i ] ) * 0.5f;
457 
458 			/* clip the winding */
459 			RadClipWindingEpsilon( rw, normal, dist, RADIOSITY_CLIP_EPSILON, &front, &back, cw );
460 
461 			/* recurse */
462 			RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qfalse, &front, cw );
463 			RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qfalse, &back, cw );
464 			return;
465 		}
466 	}
467 
468 	/* check area */
469 	area = 0.0f;
470 	for ( i = 2; i < rw->numVerts; i++ )
471 	{
472 		VectorSubtract( rw->verts[ i - 1 ].xyz, rw->verts[ 0 ].xyz, d1 );
473 		VectorSubtract( rw->verts[ i ].xyz, rw->verts[ 0 ].xyz, d2 );
474 		CrossProduct( d1, d2, cross );
475 		area += 0.5f * VectorLength( cross );
476 	}
477 	if ( area < 1.0f || area > 20000000.0f ) {
478 		return;
479 	}
480 
481 	/* more subdivision may be necessary */
482 	if ( bouncing ) {
483 		/* get color sample for the surface fragment */
484 		RadSample( lightmapNum, ds, lm, si, rw, color, gradient, &style );
485 
486 		/* if color gradient is too high, subdivide again */
487 		if ( subdivide > minDiffuseSubdivide &&
488 			 ( gradient[ 0 ] > RADIOSITY_MAX_GRADIENT || gradient[ 1 ] > RADIOSITY_MAX_GRADIENT || gradient[ 2 ] > RADIOSITY_MAX_GRADIENT ) ) {
489 			RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, ( subdivide / 2.0f ), qfalse, rw, cw );
490 			return;
491 		}
492 	}
493 
494 	/* create a regular winding and an average normal */
495 	w = AllocWinding( rw->numVerts );
496 	w->numpoints = rw->numVerts;
497 	VectorClear( normal );
498 	for ( i = 0; i < rw->numVerts; i++ )
499 	{
500 		VectorCopy( rw->verts[ i ].xyz, w->p[ i ] );
501 		VectorAdd( normal, rw->verts[ i ].normal, normal );
502 	}
503 	VectorScale( normal, ( 1.0f / rw->numVerts ), normal );
504 	if ( VectorNormalize( normal, normal ) == 0.0f ) {
505 		return;
506 	}
507 
508 	/* early out? */
509 	if ( bouncing && VectorLength( color ) < RADIOSITY_MIN ) {
510 		return;
511 	}
512 
513 	/* debug code */
514 	//%	Sys_Printf( "Size: %d %d %d\n", (int) (maxs[ 0 ] - mins[ 0 ]), (int) (maxs[ 1 ] - mins[ 1 ]), (int) (maxs[ 2 ] - mins[ 2 ]) );
515 	//%	Sys_Printf( "Grad: %f %f %f\n", gradient[ 0 ], gradient[ 1 ], gradient[ 2 ] );
516 
517 	/* increment counts */
518 	numDiffuseLights++;
519 	switch ( ds->surfaceType )
520 	{
521 	case MST_PLANAR:
522 		numBrushDiffuseLights++;
523 		break;
524 
525 	case MST_TRIANGLE_SOUP:
526 		numTriangleDiffuseLights++;
527 		break;
528 
529 	case MST_PATCH:
530 		numPatchDiffuseLights++;
531 		break;
532 	}
533 
534 	/* create a light */
535 	light = safe_malloc( sizeof( *light ) );
536 	memset( light, 0, sizeof( *light ) );
537 
538 	/* attach it */
539 	ThreadLock();
540 	light->next = lights;
541 	lights = light;
542 	ThreadUnlock();
543 
544 	/* initialize the light */
545 	light->flags = LIGHT_AREA_DEFAULT;
546 	light->type = EMIT_AREA;
547 	light->si = si;
548 	light->fade = 1.0f;
549 	light->w = w;
550 
551 	/* set falloff threshold */
552 	light->falloffTolerance = falloffTolerance;
553 
554 	/* bouncing light? */
555 	if ( !bouncing ) {
556 		/* This is weird. This actually handles surfacelight and not
557  		 * bounces. */
558 
559 		/* handle first-pass lights in normal q3a style */
560 		value = si->value;
561 		light->photons = value * area * areaScale;
562 		light->add = value * formFactorValueScale * areaScale;
563 		VectorCopy( si->color, light->color );
564 		VectorScale( light->color, light->add, light->emitColor );
565 		light->style = noStyles ? LS_NORMAL : si->lightStyle;
566 		if ( light->style < LS_NORMAL || light->style >= LS_NONE ) {
567 			light->style = LS_NORMAL;
568 		}
569 
570 		/* set origin */
571 		VectorAdd( mins, maxs, light->origin );
572 		VectorScale( light->origin, 0.5f, light->origin );
573 
574 		/* nudge it off the plane a bit */
575 		VectorCopy( normal, light->normal );
576 		VectorMA( light->origin, 1.0f, light->normal, light->origin );
577 		light->dist = DotProduct( light->origin, normal );
578 
579 		/* optionally create a point splashsplash light for first pass */
580 		if ( original && si->backsplashFraction > 0 ) {
581 			/* allocate a new point light */
582 			splash = safe_malloc( sizeof( *splash ) );
583 			memset( splash, 0, sizeof( *splash ) );
584 			splash->next = lights;
585 			lights = splash;
586 
587 			/* set it up */
588 			splash->flags = LIGHT_Q3A_DEFAULT;
589 			splash->type = EMIT_POINT;
590 			splash->photons = light->photons * si->backsplashFraction;
591 			splash->fade = 1.0f;
592 			splash->si = si;
593 			VectorMA( light->origin, si->backsplashDistance, normal, splash->origin );
594 			VectorCopy( si->color, splash->color );
595 			splash->falloffTolerance = falloffTolerance;
596 			splash->style = noStyles ? LS_NORMAL : light->style;
597 
598 			/* add to counts */
599 			numPointLights++;
600 		}
601 	}
602 	else
603 	{
604 		/* handle bounced light (radiosity) a little differently */
605 		value = RADIOSITY_VALUE * si->bounceScale * 0.375f;
606 		light->photons = value * area * bounceScale;
607 		light->add = value * formFactorValueScale * bounceScale;
608 		VectorCopy( color, light->color );
609 		VectorScale( light->color, light->add, light->emitColor );
610 		light->style = noStyles ? LS_NORMAL : style;
611 		if ( light->style < LS_NORMAL || light->style >= LS_NONE ) {
612 			light->style = LS_NORMAL;
613 		}
614 
615 		/* set origin */
616 		WindingCenter( w, light->origin );
617 
618 		/* nudge it off the plane a bit */
619 		VectorCopy( normal, light->normal );
620 		VectorMA( light->origin, 1.0f, light->normal, light->origin );
621 		light->dist = DotProduct( light->origin, normal );
622 	}
623 
624 	if (light->photons < 0 || light->add < 0 || light->color[0] < 0 || light->color[1] < 0 || light->color[2] < 0)
625 		Sys_Printf( "BUG: RadSubdivideDiffuseLight created a darkbulb\n" );
626 
627 	/* emit light from both sides? */
628 	if ( si->compileFlags & C_FOG || si->twoSided ) {
629 		light->flags |= LIGHT_TWOSIDED;
630 	}
631 
632 	//%	Sys_Printf( "\nAL: C: (%6f, %6f, %6f) [%6f] N: (%6f, %6f, %6f) %s\n",
633 	//%		light->color[ 0 ], light->color[ 1 ], light->color[ 2 ], light->add,
634 	//%		light->normal[ 0 ], light->normal[ 1 ], light->normal[ 2 ],
635 	//%		light->si->shader );
636 }
637 
638 
639 
640 /*
641    RadLightForTriangles()
642    creates unbounced diffuse lights for triangle soup (misc_models, etc)
643  */
644 
RadLightForTriangles(int num,int lightmapNum,rawLightmap_t * lm,shaderInfo_t * si,float scale,float subdivide,clipWork_t * cw)645 void RadLightForTriangles( int num, int lightmapNum, rawLightmap_t *lm, shaderInfo_t *si, float scale, float subdivide, clipWork_t *cw ){
646 	int i, j, k, v;
647 	bspDrawSurface_t    *ds;
648 	float               *radVertexLuxel;
649 	radWinding_t rw;
650 
651 
652 	/* get surface */
653 	ds = &bspDrawSurfaces[ num ];
654 
655 	/* each triangle is a potential emitter */
656 	rw.numVerts = 3;
657 	for ( i = 0; i < ds->numIndexes; i += 3 )
658 	{
659 		/* copy each vert */
660 		for ( j = 0; j < 3; j++ )
661 		{
662 			/* get vertex index and rad vertex luxel */
663 			v = ds->firstVert + bspDrawIndexes[ ds->firstIndex + i + j ];
664 
665 			/* get most everything */
666 			memcpy( &rw.verts[ j ], &yDrawVerts[ v ], sizeof( bspDrawVert_t ) );
667 
668 			/* fix colors */
669 			for ( k = 0; k < MAX_LIGHTMAPS; k++ )
670 			{
671 				radVertexLuxel = RAD_VERTEX_LUXEL( k, ds->firstVert + bspDrawIndexes[ ds->firstIndex + i + j ] );
672 				VectorCopy( radVertexLuxel, rw.verts[ j ].color[ k ] );
673 				rw.verts[ j ].color[ k ][ 3 ] = yDrawVerts[ v ].color[ k ][ 3 ];
674 			}
675 		}
676 
677 		/* subdivide into area lights */
678 		RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw );
679 	}
680 }
681 
682 
683 
684 /*
685    RadLightForPatch()
686    creates unbounced diffuse lights for patches
687  */
688 
689 #define PLANAR_EPSILON  0.1f
690 
RadLightForPatch(int num,int lightmapNum,rawLightmap_t * lm,shaderInfo_t * si,float scale,float subdivide,clipWork_t * cw)691 void RadLightForPatch( int num, int lightmapNum, rawLightmap_t *lm, shaderInfo_t *si, float scale, float subdivide, clipWork_t *cw ){
692 	int i, x, y, v, t, pw[ 5 ], r;
693 	bspDrawSurface_t    *ds;
694 	surfaceInfo_t       *info;
695 	bspDrawVert_t       *bogus;
696 	bspDrawVert_t       *dv[ 4 ];
697 	mesh_t src, *subdivided, *mesh;
698 	float               *radVertexLuxel;
699 	float dist;
700 	vec4_t plane;
701 	qboolean planar;
702 	radWinding_t rw;
703 
704 
705 	/* get surface */
706 	ds = &bspDrawSurfaces[ num ];
707 	info = &surfaceInfos[ num ];
708 
709 	/* construct a bogus vert list with color index stuffed into color[ 0 ] */
710 	bogus = safe_malloc( ds->numVerts * sizeof( bspDrawVert_t ) );
711 	memcpy( bogus, &yDrawVerts[ ds->firstVert ], ds->numVerts * sizeof( bspDrawVert_t ) );
712 	for ( i = 0; i < ds->numVerts; i++ )
713 		bogus[ i ].color[ 0 ][ 0 ] = i;
714 
715 	/* build a subdivided mesh identical to shadow facets for this patch */
716 	/* this MUST MATCH FacetsForPatch() identically! */
717 	src.width = ds->patchWidth;
718 	src.height = ds->patchHeight;
719 	src.verts = bogus;
720 	//%	subdivided = SubdivideMesh( src, 8, 512 );
721 	subdivided = SubdivideMesh2( src, info->patchIterations );
722 	PutMeshOnCurve( *subdivided );
723 	//%	MakeMeshNormals( *subdivided );
724 	mesh = RemoveLinearMeshColumnsRows( subdivided );
725 	FreeMesh( subdivided );
726 	free( bogus );
727 
728 	/* FIXME: build interpolation table into color[ 1 ] */
729 
730 	/* fix up color indexes */
731 	for ( i = 0; i < ( mesh->width * mesh->height ); i++ )
732 	{
733 		dv[ 0 ] = &mesh->verts[ i ];
734 		if ( dv[ 0 ]->color[ 0 ][ 0 ] >= ds->numVerts ) {
735 			dv[ 0 ]->color[ 0 ][ 0 ] = ds->numVerts - 1;
736 		}
737 	}
738 
739 	/* iterate through the mesh quads */
740 	for ( y = 0; y < ( mesh->height - 1 ); y++ )
741 	{
742 		for ( x = 0; x < ( mesh->width - 1 ); x++ )
743 		{
744 			/* set indexes */
745 			pw[ 0 ] = x + ( y * mesh->width );
746 			pw[ 1 ] = x + ( ( y + 1 ) * mesh->width );
747 			pw[ 2 ] = x + 1 + ( ( y + 1 ) * mesh->width );
748 			pw[ 3 ] = x + 1 + ( y * mesh->width );
749 			pw[ 4 ] = x + ( y * mesh->width );    /* same as pw[ 0 ] */
750 
751 			/* set radix */
752 			r = ( x + y ) & 1;
753 
754 			/* get drawverts */
755 			dv[ 0 ] = &mesh->verts[ pw[ r + 0 ] ];
756 			dv[ 1 ] = &mesh->verts[ pw[ r + 1 ] ];
757 			dv[ 2 ] = &mesh->verts[ pw[ r + 2 ] ];
758 			dv[ 3 ] = &mesh->verts[ pw[ r + 3 ] ];
759 
760 			/* planar? */
761 			planar = PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz );
762 			if ( planar ) {
763 				dist = DotProduct( dv[ 1 ]->xyz, plane ) - plane[ 3 ];
764 				if ( fabs( dist ) > PLANAR_EPSILON ) {
765 					planar = qfalse;
766 				}
767 			}
768 
769 			/* generate a quad */
770 			if ( planar ) {
771 				rw.numVerts = 4;
772 				for ( v = 0; v < 4; v++ )
773 				{
774 					/* get most everything */
775 					memcpy( &rw.verts[ v ], dv[ v ], sizeof( bspDrawVert_t ) );
776 
777 					/* fix colors */
778 					for ( i = 0; i < MAX_LIGHTMAPS; i++ )
779 					{
780 						radVertexLuxel = RAD_VERTEX_LUXEL( i, ds->firstVert + dv[ v ]->color[ 0 ][ 0 ] );
781 						VectorCopy( radVertexLuxel, rw.verts[ v ].color[ i ] );
782 						rw.verts[ v ].color[ i ][ 3 ] = dv[ v ]->color[ i ][ 3 ];
783 					}
784 				}
785 
786 				/* subdivide into area lights */
787 				RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw );
788 			}
789 
790 			/* generate 2 tris */
791 			else
792 			{
793 				rw.numVerts = 3;
794 				for ( t = 0; t < 2; t++ )
795 				{
796 					for ( v = 0; v < 3 + t; v++ )
797 					{
798 						/* get "other" triangle (stupid hacky logic, but whatevah) */
799 						if ( v == 1 && t == 1 ) {
800 							v++;
801 						}
802 
803 						/* get most everything */
804 						memcpy( &rw.verts[ v ], dv[ v ], sizeof( bspDrawVert_t ) );
805 
806 						/* fix colors */
807 						for ( i = 0; i < MAX_LIGHTMAPS; i++ )
808 						{
809 							radVertexLuxel = RAD_VERTEX_LUXEL( i, ds->firstVert + dv[ v ]->color[ 0 ][ 0 ] );
810 							VectorCopy( radVertexLuxel, rw.verts[ v ].color[ i ] );
811 							rw.verts[ v ].color[ i ][ 3 ] = dv[ v ]->color[ i ][ 3 ];
812 						}
813 					}
814 
815 					/* subdivide into area lights */
816 					RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw );
817 				}
818 			}
819 		}
820 	}
821 
822 	/* free the mesh */
823 	FreeMesh( mesh );
824 }
825 
826 
827 
828 
829 /*
830    RadLight()
831    creates unbounced diffuse lights for a given surface
832  */
833 
RadLight(int num)834 void RadLight( int num ){
835 	int lightmapNum;
836 	float scale, subdivide;
837 	int contentFlags, surfaceFlags, compileFlags;
838 	bspDrawSurface_t    *ds;
839 	surfaceInfo_t       *info;
840 	rawLightmap_t       *lm;
841 	shaderInfo_t        *si;
842 	clipWork_t cw;
843 
844 
845 	/* get drawsurface, lightmap, and shader info */
846 	ds = &bspDrawSurfaces[ num ];
847 	info = &surfaceInfos[ num ];
848 	lm = info->lm;
849 	si = info->si;
850 	scale = si->bounceScale;
851 
852 	/* find nodraw bit */
853 	contentFlags = surfaceFlags = compileFlags = 0;
854 	ApplySurfaceParm( "nodraw", &contentFlags, &surfaceFlags, &compileFlags );
855 
856 	// jal : avoid bouncing on trans surfaces
857 	ApplySurfaceParm( "trans", &contentFlags, &surfaceFlags, &compileFlags );
858 
859 	/* early outs? */
860 	if ( scale <= 0.0f || ( si->compileFlags & C_SKY ) || si->autosprite ||
861 		 ( bspShaders[ ds->shaderNum ].contentFlags & contentFlags ) || ( bspShaders[ ds->shaderNum ].surfaceFlags & surfaceFlags ) ||
862 		 ( si->compileFlags & compileFlags ) ) {
863 		return;
864 	}
865 
866 	/* determine how much we need to chop up the surface */
867 	if ( si->lightSubdivide ) {
868 		subdivide = si->lightSubdivide;
869 	}
870 	else{
871 		subdivide = diffuseSubdivide;
872 	}
873 
874 	/* inc counts */
875 	numDiffuseSurfaces++;
876 
877 	/* iterate through styles (this could be more efficient, yes) */
878 	for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
879 	{
880 		/* switch on type */
881 		if ( ds->lightmapStyles[ lightmapNum ] != LS_NONE && ds->lightmapStyles[ lightmapNum ] != LS_UNUSED ) {
882 			switch ( ds->surfaceType )
883 			{
884 			case MST_PLANAR:
885 			case MST_TRIANGLE_SOUP:
886 				RadLightForTriangles( num, lightmapNum, lm, si, scale, subdivide, &cw );
887 				break;
888 
889 			case MST_PATCH:
890 				RadLightForPatch( num, lightmapNum, lm, si, scale, subdivide, &cw );
891 				break;
892 
893 			default:
894 				break;
895 			}
896 		}
897 	}
898 }
899 
900 
901 
902 /*
903    RadCreateDiffuseLights()
904    creates lights for unbounced light on surfaces in the bsp
905  */
906 
907 int iterations = 0;
908 
RadCreateDiffuseLights(void)909 void RadCreateDiffuseLights( void ){
910 	/* startup */
911 	Sys_FPrintf( SYS_VRB, "--- RadCreateDiffuseLights ---\n" );
912 	numDiffuseSurfaces = 0;
913 	numDiffuseLights = 0;
914 	numBrushDiffuseLights = 0;
915 	numTriangleDiffuseLights = 0;
916 	numPatchDiffuseLights = 0;
917 	numAreaLights = 0;
918 
919 	/* hit every surface (threaded) */
920 	RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, RadLight );
921 
922 	/* dump the lights generated to a file */
923 	if ( dump ) {
924 		char dumpName[ 1024 ], ext[ 64 ];
925 		FILE    *file;
926 		light_t *light;
927 
928 		strcpy( dumpName, source );
929 		StripExtension( dumpName );
930 		sprintf( ext, "_bounce_%03d.map", iterations );
931 		strcat( dumpName, ext );
932 		file = fopen( dumpName, "wb" );
933 		Sys_Printf( "Writing %s...\n", dumpName );
934 		if ( file ) {
935 			for ( light = lights; light; light = light->next )
936 			{
937 				fprintf( file,
938 						 "{\n"
939 						 "\"classname\" \"light\"\n"
940 						 "\"light\" \"%d\"\n"
941 						 "\"origin\" \"%.0f %.0f %.0f\"\n"
942 						 "\"_color\" \"%.3f %.3f %.3f\"\n"
943 						 "}\n",
944 
945 						 (int) light->add,
946 
947 						 light->origin[ 0 ],
948 						 light->origin[ 1 ],
949 						 light->origin[ 2 ],
950 
951 						 light->color[ 0 ],
952 						 light->color[ 1 ],
953 						 light->color[ 2 ] );
954 			}
955 			fclose( file );
956 		}
957 	}
958 
959 	/* increment */
960 	iterations++;
961 
962 	/* print counts */
963 	Sys_Printf( "%8d diffuse surfaces\n", numDiffuseSurfaces );
964 	Sys_FPrintf( SYS_VRB, "%8d total diffuse lights\n", numDiffuseLights );
965 	Sys_FPrintf( SYS_VRB, "%8d brush diffuse lights\n", numBrushDiffuseLights );
966 	Sys_FPrintf( SYS_VRB, "%8d patch diffuse lights\n", numPatchDiffuseLights );
967 	Sys_FPrintf( SYS_VRB, "%8d triangle diffuse lights\n", numTriangleDiffuseLights );
968 }
969