1 /* -------------------------------------------------------------------------------
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
6 This file is part of GtkRadiant.
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.
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.
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
22 ----------------------------------------------------------------------------------
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."
27 ------------------------------------------------------------------------------- */
32 #define LIGHT_BOUNCE_C
45 deletes any existing lights, freeing up memory for the next bounce
48 void RadFreeLights( void )
50 light_t *light, *next;
54 for( light = lights; light; light = next )
57 if( light->w != NULL )
58 FreeWinding( light->w );
68 RadClipWindingEpsilon()
69 clips a rad winding by a plane
70 based off the regular clip winding code
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 )
79 vec_t dot; /* ydnar: changed from static b/c of threading */ /* VC 4.2 optimizer bug if not static? */
81 radVert_t *v1, *v2, mid;
90 counts[ 0 ] = counts[ 1 ] = counts[ 2 ] = 0;
92 /* determine sides for each point */
93 for( i = 0; i < in->numVerts; i++ )
95 dot = DotProduct( in->verts[ i ].xyz, normal );
99 sides[ i ] = SIDE_FRONT;
100 else if( dot < -epsilon )
101 sides[ i ] = SIDE_BACK;
103 sides[ i ] = SIDE_ON;
104 counts[ sides[ i ] ]++;
106 sides[ i ] = sides[ 0 ];
107 dists[ i ] = dists[ 0 ];
109 /* clear front and back */
110 front->numVerts = back->numVerts = 0;
112 /* handle all on one side cases */
113 if( counts[ 0 ] == 0 )
115 memcpy( back, in, sizeof( radWinding_t ) );
118 if( counts[ 1 ] == 0 )
120 memcpy( front, in, sizeof( radWinding_t ) );
125 maxPoints = in->numVerts + 4;
127 /* do individual verts */
128 for( i = 0; i < in->numVerts; i++ )
130 /* do simple vertex copies first */
131 v1 = &in->verts[ i ];
133 if( sides[ i ] == SIDE_ON )
135 memcpy( &front->verts[ front->numVerts++ ], v1, sizeof( radVert_t ) );
136 memcpy( &back->verts[ back->numVerts++ ], v1, sizeof( radVert_t ) );
140 if( sides[ i ] == SIDE_FRONT )
141 memcpy( &front->verts[ front->numVerts++ ], v1, sizeof( radVert_t ) );
143 if( sides[ i ] == SIDE_BACK )
144 memcpy( &back->verts[ back->numVerts++ ], v1, sizeof( radVert_t ) );
146 if( sides[ i + 1 ] == SIDE_ON || sides[ i + 1 ] == sides[ i ] )
149 /* generate a split vertex */
150 v2 = &in->verts[ (i + 1) % in->numVerts ];
152 dot = dists[ i ] / (dists[ i ] - dists[ i + 1 ]);
154 /* average vertex values */
155 for( j = 0; j < 4; j++ )
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 ]);
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 ]);
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 ]);
180 /* normalize the averaged normal */
181 VectorNormalize( mid.normal, mid.normal );
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 ) );
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" );
201 samples a texture image for a given color
202 returns qfalse if pixels are bad
205 qboolean RadSampleImage( byte *pixels, int width, int height, float st[ 2 ], float color[ 4 ] )
211 /* clear color first */
212 color[ 0 ] = color[ 1 ] = color[ 2 ] = color[ 3 ] = 255;
215 if( pixels == NULL || width < 1 || height < 1 )
220 while( sto[ 0 ] < 0.0f )
223 while( sto[ 1 ] < 0.0f )
227 x = ((float) width * sto[ 0 ]) + 0.5f;
229 y = ((float) height * sto[ 1 ]) + 0.5f;
233 pixels += (y * width * 4) + (x * 4);
234 VectorCopy( pixels, color );
235 color[ 3 ] = pixels[ 3 ];
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;
251 samples a fragment's lightmap or vertex color and returns an
252 average color and a color gradient for the sample
255 #define MAX_SAMPLES 150
256 #define SAMPLE_GRANULARITY 6
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 )
260 int i, j, k, l, v, x, y, samples;
261 vec3_t color, mins, maxs;
263 float alpha, alphaI, bf;
265 float st[ 2 ], lightmap[ 2 ], *radLuxel;
270 ClearBounds( mins, maxs );
271 VectorClear( average );
272 VectorClear( gradient );
276 if( rw == NULL || rw->numVerts < 3 )
282 /* sample vertex colors if no lightmap or this is the initial pass */
283 if( lm == NULL || lm->radLuxels[ lightmapNum ] == NULL || bouncing == qfalse )
285 for( samples = 0; samples < rw->numVerts; samples++ )
287 /* multiply by texture color */
288 if( !RadSampleImage( si->lightImage->pixels, si->lightImage->width, si->lightImage->height, rw->verts[ samples ].st, textureColor ) )
290 VectorCopy( si->averageColor, textureColor );
291 textureColor[ 4 ] = 255.0f;
293 for( i = 0; i < 3; i++ )
294 color[ i ] = (textureColor[ i ] / 255) * (rw->verts[ samples ].color[ lightmapNum ][ i ] / 255.0f);
296 AddPointToBounds( color, mins, maxs );
297 VectorAdd( average, color, average );
300 alpha += (textureColor[ 3 ] / 255.0f) * (rw->verts[ samples ].color[ lightmapNum ][ 3 ] / 255.0f);
304 *style = ds->vertexStyles[ lightmapNum ];
307 /* sample lightmap */
310 /* fracture the winding into a fan (including degenerate tris) */
311 for( v = 1; v < (rw->numVerts - 1) && samples < MAX_SAMPLES; v++ )
314 rv[ 0 ] = &rw->verts[ 0 ];
315 rv[ 1 ] = &rw->verts[ v ];
316 rv[ 2 ] = &rw->verts[ v + 1 ];
318 /* this code is embarassing (really should just rasterize the triangle) */
319 for( i = 1; i < SAMPLE_GRANULARITY && samples < MAX_SAMPLES; i++ )
321 for( j = 1; j < SAMPLE_GRANULARITY && samples < MAX_SAMPLES; j++ )
323 for( k = 1; k < SAMPLE_GRANULARITY && samples < MAX_SAMPLES; k++ )
325 /* create a blend vector (barycentric coordinates) */
329 bf = (1.0 / (blend[ 0 ] + blend[ 1 ] + blend[ 2 ]));
330 VectorScale( blend, bf, blend );
332 /* create a blended sample */
333 st[ 0 ] = st[ 1 ] = 0.0f;
334 lightmap[ 0 ] = lightmap[ 1 ] = 0.0f;
336 for( l = 0; l < 3; l++ )
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 ]);
345 /* get lightmap xy coords */
346 x = lightmap[ 0 ] / (float) superSample;
347 y = lightmap[ 1 ] / (float) superSample;
350 else if ( x >= lm->w )
354 else if ( y >= lm->h )
357 /* get radiosity luxel */
358 radLuxel = RAD_LUXEL( lightmapNum, x, y );
360 /* ignore unlit/unused luxels */
361 if( radLuxel[ 0 ] < 0.0f )
367 /* multiply by texture color */
368 if( !RadSampleImage( si->lightImage->pixels, si->lightImage->width, si->lightImage->height, st, textureColor ) )
370 VectorCopy( si->averageColor, textureColor );
371 textureColor[ 4 ] = 255;
373 for( i = 0; i < 3; i++ )
374 color[ i ] = (textureColor[ i ] / 255) * (radLuxel[ i ] / 255);
376 AddPointToBounds( color, mins, maxs );
377 VectorAdd( average, color, average );
380 alpha += (textureColor[ 3 ] / 255) * (alphaI / 255);
387 *style = ds->lightmapStyles[ lightmapNum ];
394 /* average the color */
395 VectorScale( average, (1.0 / samples), average );
397 /* create the color gradient */
398 //% VectorSubtract( maxs, mins, delta );
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;
405 /* newer: another contrast function */
406 for( i = 0; i < 3; i++ )
407 gradient[ i ] = (maxs[ i ] - mins[ i ]) * maxs[ i ];
413 RadSubdivideDiffuseLight()
414 subdivides a radiosity winding until it is smaller than subdivide, then generates an area light
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
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 )
426 float dist, area, value;
427 vec3_t mins, maxs, normal, d1, d2, cross, color, gradient;
428 light_t *light, *splash;
433 if( rw == NULL || rw->numVerts < 3 )
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 );
441 /* subdivide if necessary */
442 for( i = 0; i < 3; i++ )
444 if( maxs[ i ] - mins[ i ] > subdivide )
446 radWinding_t front, back;
449 /* make axial plane */
450 VectorClear( normal );
452 dist = (maxs[ i ] + mins[ i ]) * 0.5f;
454 /* clip the winding */
455 RadClipWindingEpsilon( rw, normal, dist, RADIOSITY_CLIP_EPSILON, &front, &back, cw );
458 RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qfalse, &front, cw );
459 RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qfalse, &back, cw );
466 for( i = 2; i < rw->numVerts; i++ )
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 );
473 if( area < 1.0f || area > 20000000.0f )
476 /* more subdivision may be necessary */
479 /* get color sample for the surface fragment */
480 RadSample( lightmapNum, ds, lm, si, rw, color, gradient, &style );
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) )
486 RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, (subdivide / 2.0f), qfalse, rw, cw );
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++ )
497 VectorCopy( rw->verts[ i ].xyz, w->p[ i ] );
498 VectorAdd( normal, rw->verts[ i ].normal, normal );
500 VectorScale( normal, (1.0f / rw->numVerts), normal );
501 if( VectorNormalize( normal, normal ) == 0.0f )
505 if( bouncing && VectorLength( color ) < RADIOSITY_MIN )
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 ] );
512 /* increment counts */
514 switch( ds->surfaceType )
517 numBrushDiffuseLights++;
520 case MST_TRIANGLE_SOUP:
521 numTriangleDiffuseLights++;
525 numPatchDiffuseLights++;
530 light = safe_malloc( sizeof( *light ) );
531 memset( light, 0, sizeof( *light ) );
535 light->next = lights;
539 /* initialize the light */
540 light->flags = LIGHT_AREA_DEFAULT;
541 light->type = EMIT_AREA;
546 /* set falloff threshold */
547 light->falloffTolerance = falloffTolerance;
549 /* bouncing light? */
552 /* handle first-pass lights in normal q3a style */
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;
563 VectorAdd( mins, maxs, light->origin );
564 VectorScale( light->origin, 0.5f, light->origin );
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 );
571 /* optionally create a point splashsplash light for first pass */
572 if( original && si->backsplashFraction > 0 )
574 /* allocate a new point light */
575 splash = safe_malloc( sizeof( *splash ) );
576 memset( splash, 0, sizeof( *splash ) );
577 splash->next = lights;
581 splash->flags = LIGHT_Q3A_DEFAULT;
582 splash->type = EMIT_POINT;
583 splash->photons = light->photons * si->backsplashFraction;
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;
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;
608 WindingCenter( w, light->origin );
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 );
616 /* emit light from both sides? */
617 if( si->compileFlags & C_FOG || si->twoSided )
618 light->flags |= LIGHT_TWOSIDED;
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 );
629 RadLightForTriangles()
630 creates unbounced diffuse lights for triangle soup (misc_models, etc)
633 void RadLightForTriangles( int num, int lightmapNum, rawLightmap_t *lm, shaderInfo_t *si, float scale, float subdivide, clipWork_t *cw )
636 bspDrawSurface_t *ds;
637 float *radVertexLuxel;
642 ds = &bspDrawSurfaces[ num ];
644 /* each triangle is a potential emitter */
646 for( i = 0; i < ds->numIndexes; i += 3 )
649 for( j = 0; j < 3; j++ )
651 /* get vertex index and rad vertex luxel */
652 v = ds->firstVert + bspDrawIndexes[ ds->firstIndex + i + j ];
654 /* get most everything */
655 memcpy( &rw.verts[ j ], &yDrawVerts[ v ], sizeof( bspDrawVert_t ) );
658 for( k = 0; k < MAX_LIGHTMAPS; k++ )
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 ];
666 /* subdivide into area lights */
667 RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw );
675 creates unbounced diffuse lights for patches
678 #define PLANAR_EPSILON 0.1f
680 void RadLightForPatch( int num, int lightmapNum, rawLightmap_t *lm, shaderInfo_t *si, float scale, float subdivide, clipWork_t *cw )
682 int i, x, y, v, t, pw[ 5 ], r;
683 bspDrawSurface_t *ds;
685 bspDrawVert_t *bogus;
686 bspDrawVert_t *dv[ 4 ];
687 mesh_t src, *subdivided, *mesh;
688 float *radVertexLuxel;
696 ds = &bspDrawSurfaces[ num ];
697 info = &surfaceInfos[ num ];
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;
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;
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 );
718 /* FIXME: build interpolation table into color[ 1 ] */
720 /* fix up color indexes */
721 for( i = 0; i < (mesh->width * mesh->height); i++ )
723 dv[ 0 ] = &mesh->verts[ i ];
724 if( dv[ 0 ]->color[ 0 ][ 0 ] >= ds->numVerts )
725 dv[ 0 ]->color[ 0 ][ 0 ] = ds->numVerts - 1;
728 /* iterate through the mesh quads */
729 for( y = 0; y < (mesh->height - 1); y++ )
731 for( x = 0; x < (mesh->width - 1); x++ )
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 ] */
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 ] ];
750 planar = PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz );
753 dist = DotProduct( dv[ 1 ]->xyz, plane ) - plane[ 3 ];
754 if( fabs( dist ) > PLANAR_EPSILON )
758 /* generate a quad */
762 for( v = 0; v < 4; v++ )
764 /* get most everything */
765 memcpy( &rw.verts[ v ], dv[ v ], sizeof( bspDrawVert_t ) );
768 for( i = 0; i < MAX_LIGHTMAPS; i++ )
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 ];
776 /* subdivide into area lights */
777 RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw );
780 /* generate 2 tris */
784 for( t = 0; t < 2; t++ )
786 for( v = 0; v < 3 + t; v++ )
788 /* get "other" triangle (stupid hacky logic, but whatevah) */
789 if( v == 1 && t == 1 )
792 /* get most everything */
793 memcpy( &rw.verts[ v ], dv[ v ], sizeof( bspDrawVert_t ) );
796 for( i = 0; i < MAX_LIGHTMAPS; i++ )
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 ];
804 /* subdivide into area lights */
805 RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw );
820 creates unbounced diffuse lights for a given surface
823 void RadLight( int num )
826 float scale, subdivide;
827 int contentFlags, surfaceFlags, compileFlags;
828 bspDrawSurface_t *ds;
835 /* get drawsurface, lightmap, and shader info */
836 ds = &bspDrawSurfaces[ num ];
837 info = &surfaceInfos[ num ];
840 scale = si->bounceScale;
842 /* find nodraw bit */
843 contentFlags = surfaceFlags = compileFlags = 0;
844 ApplySurfaceParm( "nodraw", &contentFlags, &surfaceFlags, &compileFlags );
846 // jal : avoid bouncing on trans surfaces
847 ApplySurfaceParm( "trans", &contentFlags, &surfaceFlags, &compileFlags );
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) )
855 /* determine how much we need to chop up the surface */
856 if( si->lightSubdivide )
857 subdivide = si->lightSubdivide;
859 subdivide = diffuseSubdivide;
862 numDiffuseSurfaces++;
864 /* iterate through styles (this could be more efficient, yes) */
865 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
868 if( ds->lightmapStyles[ lightmapNum ] != LS_NONE && ds->lightmapStyles[ lightmapNum ] != LS_UNUSED )
870 switch( ds->surfaceType )
873 case MST_TRIANGLE_SOUP:
874 RadLightForTriangles( num, lightmapNum, lm, si, scale, subdivide, &cw );
878 RadLightForPatch( num, lightmapNum, lm, si, scale, subdivide, &cw );
891 RadCreateDiffuseLights()
892 creates lights for unbounced light on surfaces in the bsp
897 void RadCreateDiffuseLights( void )
900 Sys_FPrintf( SYS_VRB, "--- RadCreateDiffuseLights ---\n" );
901 numDiffuseSurfaces = 0;
902 numDiffuseLights = 0;
903 numBrushDiffuseLights = 0;
904 numTriangleDiffuseLights = 0;
905 numPatchDiffuseLights = 0;
908 /* hit every surface (threaded) */
909 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, RadLight );
911 /* dump the lights generated to a file */
914 char dumpName[ 1024 ], ext[ 64 ];
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 );
926 for( light = lights; light; light = light->next )
930 "\"classname\" \"light\"\n"
932 "\"origin\" \"%.0f %.0f %.0f\"\n"
933 "\"_color\" \"%.3f %.3f %.3f\"\n"
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 );