]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/light_bounce.c
Merge branch 'NateEag-master-patch-12920' into 'master'
[xonotic/netradiant.git] / tools / quake3 / q3map2 / light_bounce.c
1 /* -------------------------------------------------------------------------------
2
3    Copyright (C) 1999-2007 id Software, Inc. and contributors.
4    For a list of contributors, see the accompanying CONTRIBUTORS file.
5
6    This file is part of GtkRadiant.
7
8    GtkRadiant is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    GtkRadiant is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with GtkRadiant; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21
22    ----------------------------------------------------------------------------------
23
24    This code has been altered significantly from its original form, to support
25    several games based on the Quake III Arena engine, in the form of "Q3Map2."
26
27    ------------------------------------------------------------------------------- */
28
29
30
31 /* marker */
32 #define 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
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
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 ) {
189                 Error( "RadClipWindingEpsilon: points exceeded estimate" );
190         }
191         if ( front->numVerts > MAX_POINTS_ON_WINDING ) {
192                 Error( "RadClipWindingEpsilon: MAX_POINTS_ON_WINDING" );
193         }
194 }
195
196
197
198 /*
199    Modulo1IfNegative()
200    Previously the bias computation was doing:
201
202       while ( f < 0.0f ) {
203          f += 1.0f;
204       }
205
206    That may end in infinite loop in some case.
207    It may also be slower because of useless loops.
208    I don't know what that computation is for.
209    -- illwieckz
210 */
211 float Modulo1IfNegative( float f ){
212         return f < 0.0f ? f - floor( f ) : f;
213 }
214
215
216
217 /*
218    RadSampleImage()
219    samples a texture image for a given color
220    returns qfalse if pixels are bad
221  */
222
223 qboolean RadSampleImage( byte *pixels, int width, int height, float st[ 2 ], float color[ 4 ] ){
224         int x, y;
225
226         /* clear color first */
227         color[ 0 ] = color[ 1 ] = color[ 2 ] = color[ 3 ] = 255;
228
229         /* dummy check */
230         if ( pixels == NULL || width < 1 || height < 1 ) {
231                 return qfalse;
232         }
233
234         /* get offsets */
235         x = ( (float) width * Modulo1IfNegative( st[ 0 ] ) ) + 0.5f;
236         x %= width;
237         y = ( (float) height * Modulo1IfNegative( st[ 1 ] ) ) + 0.5f;
238         y %= height;
239
240         /* get pixel */
241         pixels += ( y * width * 4 ) + ( x * 4 );
242         VectorCopy( pixels, color );
243         color[ 3 ] = pixels[ 3 ];
244
245         if ( texturesRGB ) {
246                 color[0] = Image_LinearFloatFromsRGBFloat( color[0] * ( 1.0 / 255.0 ) ) * 255.0;
247                 color[1] = Image_LinearFloatFromsRGBFloat( color[1] * ( 1.0 / 255.0 ) ) * 255.0;
248                 color[2] = Image_LinearFloatFromsRGBFloat( color[2] * ( 1.0 / 255.0 ) ) * 255.0;
249         }
250
251         return qtrue;
252 }
253
254
255
256 /*
257    RadSample()
258    samples a fragment's lightmap or vertex color and returns an
259    average color and a color gradient for the sample
260  */
261
262 #define MAX_SAMPLES         150
263 #define SAMPLE_GRANULARITY  6
264
265 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 ){
266         int i, j, k, l, v, x, y, samples, avgcolor, f_superSample;
267         vec3_t color, mins, maxs;
268         vec4_t textureColor;
269         float alpha, alphaI, bf;
270         vec3_t blend;
271         float st[ 2 ], lightmap[ 2 ], *radLuxel;
272         radVert_t   *rv[ 3 ];
273
274         if (!bouncing)
275                 Sys_Printf( "BUG: RadSample: !bouncing shouldn't happen\n" );
276
277         /* initial setup */
278         ClearBounds( mins, maxs );
279         VectorClear( average );
280         VectorClear( gradient );
281         alpha = 0;
282
283         /* dummy check */
284         if ( rw == NULL || rw->numVerts < 3 ) {
285                 return;
286         }
287
288         /* start sampling */
289         samples = 0;
290
291         /* sample vertex colors if no lightmap or this is the initial pass */
292         if ( lm == NULL || lm->radLuxels[ lightmapNum ] == NULL || bouncing == qfalse ) {
293                 for ( samples = 0; samples < rw->numVerts; samples++ )
294                 {
295                         /* multiply by texture color */
296                         if ( !RadSampleImage( si->lightImage->pixels, si->lightImage->width, si->lightImage->height, rw->verts[ samples ].st, textureColor ) ) {
297                                 VectorCopy( si->averageColor, textureColor );
298                                 textureColor[ 3 ] = 255.0f;
299                         }
300                         avgcolor = ( textureColor[ 0 ] + textureColor[ 1 ] + textureColor[ 2 ] ) / 3;
301                         for ( i = 0; i < 3; i++ )
302                                 color[ i ] = ( ( textureColor[ i ] * bounceColorRatio + ( avgcolor * ( 1 - bounceColorRatio ) ) ) / 255 ) * ( rw->verts[ samples ].color[ lightmapNum ][ i ] / 255.0f );
303 //                              color[ i ] = ( textureColor[ i ] / 255 ) * ( rw->verts[ samples ].color[ lightmapNum ][ i ] / 255.0f );
304
305                         AddPointToBounds( color, mins, maxs );
306                         VectorAdd( average, color, average );
307
308                         /* get alpha */
309                         alpha += ( textureColor[ 3 ] / 255.0f ) * ( rw->verts[ samples ].color[ lightmapNum ][ 3 ] / 255.0f );
310                 }
311
312                 /* set style */
313                 *style = ds->vertexStyles[ lightmapNum ];
314         }
315
316         /* sample lightmap */
317         else
318         {
319                 f_superSample = (float)superSample;
320                 /* fracture the winding into a fan (including degenerate tris) */
321                 for ( v = 1; v < ( rw->numVerts - 1 ) && samples < MAX_SAMPLES; v++ )
322                 {
323                         /* get a triangle */
324                         rv[ 0 ] = &rw->verts[ 0 ];
325                         rv[ 1 ] = &rw->verts[ v ];
326                         rv[ 2 ] = &rw->verts[ v + 1 ];
327
328                         /* this code is embarassing (really should just rasterize the triangle) */
329                         for ( i = 1; i < SAMPLE_GRANULARITY && samples < MAX_SAMPLES; i++ )
330                         {
331                                 for ( j = 1; j < SAMPLE_GRANULARITY && samples < MAX_SAMPLES; j++ )
332                                 {
333                                         for ( k = 1; k < SAMPLE_GRANULARITY && samples < MAX_SAMPLES; k++ )
334                                         {
335                                                 /* create a blend vector (barycentric coordinates) */
336                                                 blend[ 0 ] = i;
337                                                 blend[ 1 ] = j;
338                                                 blend[ 2 ] = k;
339                                                 bf = ( 1.0f / ( blend[ 0 ] + blend[ 1 ] + blend[ 2 ] ) );
340                                                 VectorScale( blend, bf, blend );
341
342                                                 /* create a blended sample */
343                                                 st[ 0 ] = st[ 1 ] = 0.0f;
344                                                 lightmap[ 0 ] = lightmap[ 1 ] = 0.0f;
345                                                 alphaI = 0.0f;
346                                                 for ( l = 0; l < 3; l++ )
347                                                 {
348                                                         st[ 0 ] += ( rv[ l ]->st[ 0 ] * blend[ l ] );
349                                                         st[ 1 ] += ( rv[ l ]->st[ 1 ] * blend[ l ] );
350                                                         lightmap[ 0 ] += ( rv[ l ]->lightmap[ lightmapNum ][ 0 ] * blend[ l ] );
351                                                         lightmap[ 1 ] += ( rv[ l ]->lightmap[ lightmapNum ][ 1 ] * blend[ l ] );
352                                                         alphaI += ( rv[ l ]->color[ lightmapNum ][ 3 ] * blend[ l ] );
353                                                 }
354
355                                                 /* get lightmap xy coords */
356                                                 /* xy = clamp(lightmap/superSample, 0, lm - 1)*/
357                                                 x = lightmap[ 0 ] / f_superSample;
358                                                 y = lightmap[ 1 ] / f_superSample;
359
360                                                 if ( x < 0 ) {
361                                                         x = 0;
362                                                 }
363                                                 else if ( x >= lm->w ) {
364                                                         x = lm->w - 1;
365                                                 }
366                                                 if ( y < 0 ) {
367                                                         y = 0;
368                                                 }
369                                                 else if ( y >= lm->h ) {
370                                                         y = lm->h - 1;
371                                                 }
372
373                                                 /* get radiosity luxel */
374                                                 radLuxel = RAD_LUXEL( lightmapNum, x, y );
375
376                                                 /* ignore unlit/unused luxels */
377                                                 if ( radLuxel[ 0 ] < 0.0f ) {
378                                                         continue;
379                                                 }
380
381                                                 /* inc samples */
382                                                 samples++;
383
384                                                 /* multiply by texture color */
385                                                 if ( !RadSampleImage( si->lightImage->pixels, si->lightImage->width, si->lightImage->height, st, textureColor ) ) {
386                                                         VectorCopy( si->averageColor, textureColor );
387                                                         textureColor[ 3 ] = 255;
388                                                 }
389                                                 avgcolor = ( textureColor[ 0 ] + textureColor[ 1 ] + textureColor[ 2 ] ) / 3;
390                                                 for ( i = 0; i < 3; i++ ){
391                                                         color[ i ] = ( ( textureColor[ i ] * bounceColorRatio + ( avgcolor * ( 1 - bounceColorRatio ) ) ) / 255 ) * ( radLuxel[ i ] / 255 );
392                                                 /*
393                                                    Workaround for https://gitlab.com/xonotic/netradiant/-/issues/182
394                                                    This loop normally uses the l iterator instead of i:
395                                                    for ( l = 0; l < 3; l++ ){
396                                                         color[ l ] = ( ( textureColor[ l ] * bounceColorRatio + ( avgcolor * ( 1 - bounceColorRatio ) ) ) / 255 ) * ( radLuxel[ l ] / 255 );
397                                                         }
398                                                 */
399                                                 //Sys_Printf( "%i %i %i %i %i \n", (int) textureColor[ 0 ], (int) textureColor[ 1 ], (int) textureColor[ 2 ], (int) avgcolor, (int) color[ i ] );
400                                                 }
401                                                 AddPointToBounds( color, mins, maxs );
402                                                 VectorAdd( average, color, average );
403
404                                                 /* get alpha */
405                                                 alpha += ( textureColor[ 3 ] / 255 ) * ( alphaI / 255 );
406                                         }
407                                 }
408                         }
409                 }
410
411                 /* set style */
412                 *style = ds->lightmapStyles[ lightmapNum ];
413         }
414
415         /* any samples? */
416         if ( samples <= 0 ) {
417                 return;
418         }
419
420         /* average the color */
421         VectorScale( average, ( 1.0 / samples ), average );
422
423         /* create the color gradient */
424         //%     VectorSubtract( maxs, mins, delta );
425
426         /* new: color gradient will always be 0-1.0, expressed as the range of light relative to overall light */
427         //%     gradient[ 0 ] = maxs[ 0 ] > 0.0f ? (maxs[ 0 ] - mins[ 0 ]) / maxs[ 0 ] : 0.0f;
428         //%     gradient[ 1 ] = maxs[ 1 ] > 0.0f ? (maxs[ 1 ] - mins[ 1 ]) / maxs[ 1 ] : 0.0f;
429         //%     gradient[ 2 ] = maxs[ 2 ] > 0.0f ? (maxs[ 2 ] - mins[ 2 ]) / maxs[ 2 ] : 0.0f;
430
431         /* newer: another contrast function */
432         for ( i = 0; i < 3; i++ )
433                 gradient[ i ] = ( maxs[ i ] - mins[ i ] ) * maxs[ i ];
434 }
435
436
437
438 /*
439    RadSubdivideDiffuseLight()
440    subdivides a radiosity winding until it is smaller than subdivide, then generates an area light
441  */
442
443 #define RADIOSITY_MAX_GRADIENT      0.75f   //% 0.25f
444 #define RADIOSITY_VALUE             500.0f
445 #define RADIOSITY_MIN               0.0001f
446 #define RADIOSITY_CLIP_EPSILON      0.125f
447
448
449
450 static void RadSubdivideDiffuseLight( int lightmapNum, bspDrawSurface_t *ds, rawLightmap_t *lm, shaderInfo_t *si,
451                                                                           float scale, float subdivide, radWinding_t *rw, clipWork_t *cw ){
452         int i, style = 0;
453         float dist, area, value;
454         vec3_t mins, maxs, normal, d1, d2, cross, color, gradient;
455         light_t         *light, *splash;
456         winding_t       *w, *splash_w;
457
458
459         /* dummy check */
460         if ( rw == NULL || rw->numVerts < 3 ) {
461                 return;
462         }
463
464         /* get bounds for winding */
465         ClearBounds( mins, maxs );
466         for ( i = 0; i < rw->numVerts; i++ )
467                 AddPointToBounds( rw->verts[ i ].xyz, mins, maxs );
468
469         /* subdivide if necessary */
470         for ( i = 0; i < 3; i++ )
471         {
472                 if ( maxs[ i ] - mins[ i ] > subdivide ) {
473                         radWinding_t front, back;
474
475
476                         /* make axial plane */
477                         VectorClear( normal );
478                         normal[ i ] = 1;
479                         dist = ( maxs[ i ] + mins[ i ] ) * 0.5f;
480
481                         /* clip the winding */
482                         RadClipWindingEpsilon( rw, normal, dist, RADIOSITY_CLIP_EPSILON, &front, &back, cw );
483
484                         /* recurse */
485                         RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, &front, cw );
486                         RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, &back, cw );
487                         return;
488                 }
489         }
490
491         /* check area */
492         area = 0.0f;
493         for ( i = 2; i < rw->numVerts; i++ )
494         {
495                 VectorSubtract( rw->verts[ i - 1 ].xyz, rw->verts[ 0 ].xyz, d1 );
496                 VectorSubtract( rw->verts[ i ].xyz, rw->verts[ 0 ].xyz, d2 );
497                 CrossProduct( d1, d2, cross );
498                 area += 0.5f * VectorLength( cross );
499         }
500         if ( area < 1.0f || area > 20000000.0f ) {
501                 return;
502         }
503
504         /* more subdivision may be necessary */
505         if ( bouncing ) {
506                 /* get color sample for the surface fragment */
507                 RadSample( lightmapNum, ds, lm, si, rw, color, gradient, &style );
508
509                 /* if color gradient is too high, subdivide again */
510                 if ( subdivide > minDiffuseSubdivide &&
511                          ( gradient[ 0 ] > RADIOSITY_MAX_GRADIENT || gradient[ 1 ] > RADIOSITY_MAX_GRADIENT || gradient[ 2 ] > RADIOSITY_MAX_GRADIENT ) ) {
512                         RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, ( subdivide / 2.0f ), rw, cw );
513                         return;
514                 }
515         }
516
517         /* create a regular winding and an average normal */
518         w = AllocWinding( rw->numVerts );
519         w->numpoints = rw->numVerts;
520         VectorClear( normal );
521         for ( i = 0; i < rw->numVerts; i++ )
522         {
523                 VectorCopy( rw->verts[ i ].xyz, w->p[ i ] );
524                 VectorAdd( normal, rw->verts[ i ].normal, normal );
525         }
526         VectorScale( normal, ( 1.0f / rw->numVerts ), normal );
527         if ( VectorNormalize( normal, normal ) == 0.0f ) {
528                 return;
529         }
530
531         /* early out? */
532         if ( bouncing && VectorLength( color ) < RADIOSITY_MIN ) {
533                 return;
534         }
535
536         /* debug code */
537         //%     Sys_Printf( "Size: %d %d %d\n", (int) (maxs[ 0 ] - mins[ 0 ]), (int) (maxs[ 1 ] - mins[ 1 ]), (int) (maxs[ 2 ] - mins[ 2 ]) );
538         //%     Sys_Printf( "Grad: %f %f %f\n", gradient[ 0 ], gradient[ 1 ], gradient[ 2 ] );
539
540         /* increment counts */
541         numDiffuseLights++;
542         switch ( ds->surfaceType )
543         {
544         case MST_PLANAR:
545                 numBrushDiffuseLights++;
546                 break;
547
548         case MST_TRIANGLE_SOUP:
549                 numTriangleDiffuseLights++;
550                 break;
551
552         case MST_PATCH:
553                 numPatchDiffuseLights++;
554                 break;
555         }
556
557         /* create a light */
558         light = safe_malloc0( sizeof( *light ) );
559
560         /* attach it */
561         ThreadLock();
562         light->next = lights;
563         lights = light;
564         ThreadUnlock();
565
566         /* initialize the light */
567         light->flags = LIGHT_AREA_DEFAULT;
568         light->type = EMIT_AREA;
569         light->si = si;
570         light->fade = 1.0f;
571         light->w = w;
572
573         /* set falloff threshold */
574         light->falloffTolerance = falloffTolerance;
575
576         /* bouncing light? */
577         if ( bouncing == qfalse ) {
578                 /* This is weird. This actually handles surfacelight and not
579                  * bounces. */
580
581                 /* handle first-pass lights in normal q3a style */
582                 value = si->value;
583                 light->photons = value * area * areaScale;
584                 light->add = value * formFactorValueScale * areaScale;
585                 VectorCopy( si->color, light->color );
586                 VectorScale( light->color, light->add, light->emitColor );
587                 light->style = noStyles ? LS_NORMAL : si->lightStyle;
588                 if ( light->style < LS_NORMAL || light->style >= LS_NONE ) {
589                         light->style = LS_NORMAL;
590                 }
591
592                 /* set origin */
593                 VectorAdd( mins, maxs, light->origin );
594                 VectorScale( light->origin, 0.5f, light->origin );
595
596                 /* nudge it off the plane a bit */
597                 VectorCopy( normal, light->normal );
598                 VectorMA( light->origin, 1.0f, light->normal, light->origin );
599                 light->dist = DotProduct( light->origin, normal );
600
601 #if 0
602                 /* optionally create a point backsplash light */
603                 if ( si->backsplashFraction > 0 ) {
604
605                         /* allocate a new point light */
606                         splash = safe_malloc0( sizeof( *splash ) );
607
608                         splash->next = lights;
609                         lights = splash;
610
611
612                         /* set it up */
613                         splash->flags = LIGHT_Q3A_DEFAULT;
614                         splash->type = EMIT_POINT;
615                         splash->photons = light->photons * si->backsplashFraction;
616
617                         splash->fade = 1.0f;
618                         splash->si = si;
619                         VectorMA( light->origin, si->backsplashDistance, normal, splash->origin );
620                         VectorCopy( si->color, splash->color );
621
622                         splash->falloffTolerance = falloffTolerance;
623                         splash->style = noStyles ? LS_NORMAL : light->style;
624
625                         /* add to counts */
626                         numPointLights++;
627                 }
628 #endif
629
630 #if 1
631                 /* optionally create area backsplash light */
632                 //if ( original && si->backsplashFraction > 0 ) {
633                 if ( si->backsplashFraction > 0 && !( si->compileFlags & C_SKY ) ) {
634                         /* allocate a new area light */
635                         splash = safe_malloc( sizeof( *splash ) );
636                         memset( splash, 0, sizeof( *splash ) );
637                         ThreadLock();
638                         splash->next = lights;
639                         lights = splash;
640                         ThreadUnlock();
641
642                         /* set it up */
643                         splash->flags = LIGHT_AREA_DEFAULT;
644                         splash->type = EMIT_AREA;
645                         splash->photons = light->photons * 7.0f * si->backsplashFraction;
646                         splash->add = light->add * 7.0f * si->backsplashFraction;
647                         splash->fade = 1.0f;
648                         splash->si = si;
649                         VectorCopy( si->color, splash->color );
650                         VectorScale( splash->color, splash->add, splash->emitColor );
651                         splash->falloffTolerance = falloffTolerance;
652                         splash->style = noStyles ? LS_NORMAL : si->lightStyle;
653                         if ( splash->style < LS_NORMAL || splash->style >= LS_NONE ) {
654                                 splash->style = LS_NORMAL;
655                         }
656
657                         /* create a regular winding */
658                         splash_w = AllocWinding( rw->numVerts );
659                         splash_w->numpoints = rw->numVerts;
660                         for ( i = 0; i < rw->numVerts; i++ )
661                                 VectorMA( rw->verts[rw->numVerts - 1 - i].xyz, si->backsplashDistance, normal, splash_w->p[ i ] );
662                         splash->w = splash_w;
663
664                         VectorMA( light->origin, si->backsplashDistance, normal, splash->origin );
665                         VectorNegate( normal, splash->normal );
666             splash->dist = DotProduct( splash->origin, splash->normal );
667
668 //                      splash->flags |= LIGHT_TWOSIDED;
669                 }
670 #endif
671
672         }
673         else
674         {
675                 /* handle bounced light (radiosity) a little differently */
676                 value = RADIOSITY_VALUE * si->bounceScale * 0.375f;
677                 light->photons = value * area * bounceScale;
678                 light->add = value * formFactorValueScale * bounceScale;
679                 VectorCopy( color, light->color );
680                 VectorScale( light->color, light->add, light->emitColor );
681                 light->style = noStyles ? LS_NORMAL : style;
682                 if ( light->style < LS_NORMAL || light->style >= LS_NONE ) {
683                         light->style = LS_NORMAL;
684                 }
685
686                 /* set origin */
687                 WindingCenter( w, light->origin );
688
689                 /* nudge it off the plane a bit */
690                 VectorCopy( normal, light->normal );
691                 VectorMA( light->origin, 1.0f, light->normal, light->origin );
692                 light->dist = DotProduct( light->origin, normal );
693         }
694
695         if (light->photons < 0 || light->add < 0 || light->color[0] < 0 || light->color[1] < 0 || light->color[2] < 0)
696                 Sys_Printf( "BUG: RadSubdivideDiffuseLight created a darkbulb\n" );
697
698         /* emit light from both sides? */
699         if ( si->compileFlags & C_FOG || si->twoSided ) {
700                 light->flags |= LIGHT_TWOSIDED;
701         }
702
703         //%     Sys_Printf( "\nAL: C: (%6f, %6f, %6f) [%6f] N: (%6f, %6f, %6f) %s\n",
704         //%             light->color[ 0 ], light->color[ 1 ], light->color[ 2 ], light->add,
705         //%             light->normal[ 0 ], light->normal[ 1 ], light->normal[ 2 ],
706         //%             light->si->shader );
707 }
708
709
710 /*
711    RadLightForTriangles()
712    creates unbounced diffuse lights for triangle soup (misc_models, etc)
713  */
714
715 void RadLightForTriangles( int num, int lightmapNum, rawLightmap_t *lm, shaderInfo_t *si, float scale, float subdivide, clipWork_t *cw ){
716         int i, j, k, v;
717         bspDrawSurface_t    *ds;
718         float               *radVertexLuxel;
719         radWinding_t rw;
720
721
722         /* get surface */
723         ds = &bspDrawSurfaces[ num ];
724
725         /* each triangle is a potential emitter */
726         rw.numVerts = 3;
727         for ( i = 0; i < ds->numIndexes; i += 3 )
728         {
729                 /* copy each vert */
730                 for ( j = 0; j < 3; j++ )
731                 {
732                         /* get vertex index and rad vertex luxel */
733                         v = ds->firstVert + bspDrawIndexes[ ds->firstIndex + i + j ];
734
735                         /* get most everything */
736                         memcpy( &rw.verts[ j ], &yDrawVerts[ v ], sizeof( bspDrawVert_t ) );
737
738                         /* fix colors */
739                         for ( k = 0; k < MAX_LIGHTMAPS; k++ )
740                         {
741                                 radVertexLuxel = RAD_VERTEX_LUXEL( k, ds->firstVert + bspDrawIndexes[ ds->firstIndex + i + j ] );
742                                 VectorCopy( radVertexLuxel, rw.verts[ j ].color[ k ] );
743                                 rw.verts[ j ].color[ k ][ 3 ] = yDrawVerts[ v ].color[ k ][ 3 ];
744                         }
745                 }
746
747                 /* subdivide into area lights */
748                 RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, &rw, cw );
749         }
750 }
751
752
753
754 /*
755    RadLightForPatch()
756    creates unbounced diffuse lights for patches
757  */
758
759 #define PLANAR_EPSILON  0.1f
760
761 void RadLightForPatch( int num, int lightmapNum, rawLightmap_t *lm, shaderInfo_t *si, float scale, float subdivide, clipWork_t *cw ){
762         int i, x, y, v, t, pw[ 5 ], r;
763         bspDrawSurface_t    *ds;
764         surfaceInfo_t       *info;
765         bspDrawVert_t       *bogus;
766         bspDrawVert_t       *dv[ 4 ];
767         mesh_t src, *subdivided, *mesh;
768         float               *radVertexLuxel;
769         float dist;
770         vec4_t plane;
771         qboolean planar;
772         radWinding_t rw;
773
774
775         /* get surface */
776         ds = &bspDrawSurfaces[ num ];
777         info = &surfaceInfos[ num ];
778
779         /* construct a bogus vert list with color index stuffed into color[ 0 ] */
780         bogus = safe_malloc( ds->numVerts * sizeof( bspDrawVert_t ) );
781         memcpy( bogus, &yDrawVerts[ ds->firstVert ], ds->numVerts * sizeof( bspDrawVert_t ) );
782         for ( i = 0; i < ds->numVerts; i++ )
783                 bogus[ i ].color[ 0 ][ 0 ] = i;
784
785         /* build a subdivided mesh identical to shadow facets for this patch */
786         /* this MUST MATCH FacetsForPatch() identically! */
787         src.width = ds->patchWidth;
788         src.height = ds->patchHeight;
789         src.verts = bogus;
790         //%     subdivided = SubdivideMesh( src, 8, 512 );
791         subdivided = SubdivideMesh2( src, info->patchIterations );
792         PutMeshOnCurve( *subdivided );
793         //%     MakeMeshNormals( *subdivided );
794         mesh = RemoveLinearMeshColumnsRows( subdivided );
795         FreeMesh( subdivided );
796         free( bogus );
797
798         /* FIXME: build interpolation table into color[ 1 ] */
799
800         /* fix up color indexes */
801         for ( i = 0; i < ( mesh->width * mesh->height ); i++ )
802         {
803                 dv[ 0 ] = &mesh->verts[ i ];
804                 if ( dv[ 0 ]->color[ 0 ][ 0 ] >= ds->numVerts ) {
805                         dv[ 0 ]->color[ 0 ][ 0 ] = ds->numVerts - 1;
806                 }
807         }
808
809         /* iterate through the mesh quads */
810         for ( y = 0; y < ( mesh->height - 1 ); y++ )
811         {
812                 for ( x = 0; x < ( mesh->width - 1 ); x++ )
813                 {
814                         /* set indexes */
815                         pw[ 0 ] = x + ( y * mesh->width );
816                         pw[ 1 ] = x + ( ( y + 1 ) * mesh->width );
817                         pw[ 2 ] = x + 1 + ( ( y + 1 ) * mesh->width );
818                         pw[ 3 ] = x + 1 + ( y * mesh->width );
819                         pw[ 4 ] = x + ( y * mesh->width );    /* same as pw[ 0 ] */
820
821                         /* set radix */
822                         r = ( x + y ) & 1;
823
824                         /* get drawverts */
825                         dv[ 0 ] = &mesh->verts[ pw[ r + 0 ] ];
826                         dv[ 1 ] = &mesh->verts[ pw[ r + 1 ] ];
827                         dv[ 2 ] = &mesh->verts[ pw[ r + 2 ] ];
828                         dv[ 3 ] = &mesh->verts[ pw[ r + 3 ] ];
829
830                         /* planar? */
831                         planar = PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz );
832                         if ( planar ) {
833                                 dist = DotProduct( dv[ 1 ]->xyz, plane ) - plane[ 3 ];
834                                 if ( fabs( dist ) > PLANAR_EPSILON ) {
835                                         planar = qfalse;
836                                 }
837                         }
838
839                         /* generate a quad */
840                         if ( planar ) {
841                                 rw.numVerts = 4;
842                                 for ( v = 0; v < 4; v++ )
843                                 {
844                                         /* get most everything */
845                                         memcpy( &rw.verts[ v ], dv[ v ], sizeof( bspDrawVert_t ) );
846
847                                         /* fix colors */
848                                         for ( i = 0; i < MAX_LIGHTMAPS; i++ )
849                                         {
850                                                 radVertexLuxel = RAD_VERTEX_LUXEL( i, ds->firstVert + dv[ v ]->color[ 0 ][ 0 ] );
851                                                 VectorCopy( radVertexLuxel, rw.verts[ v ].color[ i ] );
852                                                 rw.verts[ v ].color[ i ][ 3 ] = dv[ v ]->color[ i ][ 3 ];
853                                         }
854                                 }
855
856                                 /* subdivide into area lights */
857                                 RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, &rw, cw );
858                         }
859
860                         /* generate 2 tris */
861                         else
862                         {
863                                 rw.numVerts = 3;
864                                 for ( t = 0; t < 2; t++ )
865                                 {
866                                         for ( v = 0; v < 3 + t; v++ )
867                                         {
868                                                 /* get "other" triangle (stupid hacky logic, but whatevah) */
869                                                 if ( v == 1 && t == 1 ) {
870                                                         v++;
871                                                 }
872
873                                                 /* get most everything */
874                                                 memcpy( &rw.verts[ v ], dv[ v ], sizeof( bspDrawVert_t ) );
875
876                                                 /* fix colors */
877                                                 for ( i = 0; i < MAX_LIGHTMAPS; i++ )
878                                                 {
879                                                         radVertexLuxel = RAD_VERTEX_LUXEL( i, ds->firstVert + dv[ v ]->color[ 0 ][ 0 ] );
880                                                         VectorCopy( radVertexLuxel, rw.verts[ v ].color[ i ] );
881                                                         rw.verts[ v ].color[ i ][ 3 ] = dv[ v ]->color[ i ][ 3 ];
882                                                 }
883                                         }
884
885                                         /* subdivide into area lights */
886                                         RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, &rw, cw );
887                                 }
888                         }
889                 }
890         }
891
892         /* free the mesh */
893         FreeMesh( mesh );
894 }
895
896
897
898
899 /*
900    RadLight()
901    creates unbounced diffuse lights for a given surface
902  */
903
904 void RadLight( int num ){
905         int lightmapNum;
906         float scale, subdivide;
907         int contentFlags, surfaceFlags, compileFlags;
908         bspDrawSurface_t    *ds;
909         surfaceInfo_t       *info;
910         rawLightmap_t       *lm;
911         shaderInfo_t        *si;
912         clipWork_t cw;
913
914
915         /* get drawsurface, lightmap, and shader info */
916         ds = &bspDrawSurfaces[ num ];
917         info = &surfaceInfos[ num ];
918         lm = info->lm;
919         si = info->si;
920         scale = si->bounceScale;
921
922         /* find nodraw bit */
923         contentFlags = surfaceFlags = compileFlags = 0;
924         ApplySurfaceParm( "nodraw", &contentFlags, &surfaceFlags, &compileFlags );
925
926         // jal : avoid bouncing on trans surfaces
927         ApplySurfaceParm( "trans", &contentFlags, &surfaceFlags, &compileFlags );
928
929         /* early outs? */
930         if ( scale <= 0.0f || ( si->compileFlags & C_SKY ) || si->autosprite ||
931                  ( bspShaders[ ds->shaderNum ].contentFlags & contentFlags ) || ( bspShaders[ ds->shaderNum ].surfaceFlags & surfaceFlags ) ||
932                  ( si->compileFlags & compileFlags ) ) {
933                 return;
934         }
935
936         /* determine how much we need to chop up the surface */
937         if ( si->lightSubdivide ) {
938                 subdivide = si->lightSubdivide;
939         }
940         else{
941                 subdivide = diffuseSubdivide;
942         }
943
944         /* inc counts */
945         numDiffuseSurfaces++;
946
947         /* iterate through styles (this could be more efficient, yes) */
948         for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
949         {
950                 /* switch on type */
951                 if ( ds->lightmapStyles[ lightmapNum ] != LS_NONE && ds->lightmapStyles[ lightmapNum ] != LS_UNUSED ) {
952                         switch ( ds->surfaceType )
953                         {
954                         case MST_PLANAR:
955                         case MST_TRIANGLE_SOUP:
956                                 RadLightForTriangles( num, lightmapNum, lm, si, scale, subdivide, &cw );
957                                 break;
958
959                         case MST_PATCH:
960                                 RadLightForPatch( num, lightmapNum, lm, si, scale, subdivide, &cw );
961                                 break;
962
963                         default:
964                                 break;
965                         }
966                 }
967         }
968 }
969
970
971
972 /*
973    RadCreateDiffuseLights()
974    creates lights for unbounced light on surfaces in the bsp
975  */
976
977 int iterations = 0;
978
979 void RadCreateDiffuseLights( void ){
980         /* startup */
981         Sys_FPrintf( SYS_VRB, "--- RadCreateDiffuseLights ---\n" );
982         numDiffuseSurfaces = 0;
983         numDiffuseLights = 0;
984         numBrushDiffuseLights = 0;
985         numTriangleDiffuseLights = 0;
986         numPatchDiffuseLights = 0;
987         numAreaLights = 0;
988
989         /* hit every surface (threaded) */
990         RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, RadLight );
991
992         /* dump the lights generated to a file */
993         if ( dump ) {
994                 char dumpName[ 1024 ], ext[ 64 ];
995                 FILE    *file;
996                 light_t *light;
997
998                 strcpy( dumpName, source );
999                 StripExtension( dumpName );
1000                 sprintf( ext, "_bounce_%03d.map", iterations );
1001                 strcat( dumpName, ext );
1002                 file = fopen( dumpName, "wb" );
1003                 Sys_Printf( "Writing %s...\n", dumpName );
1004                 if ( file ) {
1005                         for ( light = lights; light; light = light->next )
1006                         {
1007                                 fprintf( file,
1008                                                  "{\n"
1009                                                  "\"classname\" \"light\"\n"
1010                                                  "\"light\" \"%d\"\n"
1011                                                  "\"origin\" \"%.0f %.0f %.0f\"\n"
1012                                                  "\"_color\" \"%.3f %.3f %.3f\"\n"
1013                                                  "}\n",
1014
1015                                                  (int) light->add,
1016
1017                                                  light->origin[ 0 ],
1018                                                  light->origin[ 1 ],
1019                                                  light->origin[ 2 ],
1020
1021                                                  light->color[ 0 ],
1022                                                  light->color[ 1 ],
1023                                                  light->color[ 2 ] );
1024                         }
1025                         fclose( file );
1026                 }
1027         }
1028
1029         /* increment */
1030         iterations++;
1031
1032         /* print counts */
1033         Sys_Printf( "%8d diffuse surfaces\n", numDiffuseSurfaces );
1034         Sys_FPrintf( SYS_VRB, "%8d total diffuse lights\n", numDiffuseLights );
1035         Sys_FPrintf( SYS_VRB, "%8d brush diffuse lights\n", numBrushDiffuseLights );
1036         Sys_FPrintf( SYS_VRB, "%8d patch diffuse lights\n", numPatchDiffuseLights );
1037         Sys_FPrintf( SYS_VRB, "%8d triangle diffuse lights\n", numTriangleDiffuseLights );
1038 }