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