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