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 ){
49 light_t *light, *next;
53 for ( light = lights; light; light = next )
56 if ( light->w != NULL ) {
57 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 ){
78 vec_t dot; /* ydnar: changed from static b/c of threading */ /* VC 4.2 optimizer bug if not static? */
80 radVert_t *v1, *v2, mid;
89 counts[ 0 ] = counts[ 1 ] = counts[ 2 ] = 0;
91 /* determine sides for each point */
92 for ( i = 0; i < in->numVerts; i++ )
94 dot = DotProduct( in->verts[ i ].xyz, normal );
97 if ( dot > epsilon ) {
98 sides[ i ] = SIDE_FRONT;
100 else if ( dot < -epsilon ) {
101 sides[ i ] = SIDE_BACK;
104 sides[ i ] = SIDE_ON;
106 counts[ sides[ i ] ]++;
108 sides[ i ] = sides[ 0 ];
109 dists[ i ] = dists[ 0 ];
111 /* clear front and back */
112 front->numVerts = back->numVerts = 0;
114 /* handle all on one side cases */
115 if ( counts[ 0 ] == 0 ) {
116 memcpy( back, in, sizeof( radWinding_t ) );
119 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 ) {
134 memcpy( &front->verts[ front->numVerts++ ], v1, sizeof( radVert_t ) );
135 memcpy( &back->verts[ back->numVerts++ ], v1, sizeof( radVert_t ) );
139 if ( sides[ i ] == SIDE_FRONT ) {
140 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 ) );
147 if ( sides[ i + 1 ] == SIDE_ON || sides[ i + 1 ] == sides[ i ] ) {
151 /* generate a split vertex */
152 v2 = &in->verts[ ( i + 1 ) % in->numVerts ];
154 dot = dists[ i ] / ( dists[ i ] - dists[ i + 1 ] );
156 /* average vertex values */
157 for ( j = 0; j < 4; j++ )
161 for ( k = 0; k < MAX_LIGHTMAPS; k++ )
162 mid.color[ k ][ j ] = v1->color[ k ][ j ] + dot * ( v2->color[ k ][ j ] - v1->color[ k ][ j ] );
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 ] );
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 ] );
179 /* normalize the averaged normal */
180 VectorNormalize( mid.normal, mid.normal );
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 ) );
188 if ( front->numVerts > maxPoints ) {
189 Error( "RadClipWindingEpsilon: points exceeded estimate" );
191 if ( front->numVerts > MAX_POINTS_ON_WINDING ) {
192 Error( "RadClipWindingEpsilon: MAX_POINTS_ON_WINDING" );
200 Previously the bias computation was doing:
206 That may end in infinite loop in some case.
207 It may also be slower because of useless loops.
208 I don't know what that computation is for.
211 float Modulo1IfNegative( float f ){
212 return f < 0.0f ? f - floor( f ) : f;
219 samples a texture image for a given color
220 returns qfalse if pixels are bad
223 qboolean RadSampleImage( byte *pixels, int width, int height, float st[ 2 ], float color[ 4 ] ){
226 /* clear color first */
227 color[ 0 ] = color[ 1 ] = color[ 2 ] = color[ 3 ] = 255;
230 if ( pixels == NULL || width < 1 || height < 1 ) {
235 x = ( (float) width * Modulo1IfNegative( st[ 0 ] ) ) + 0.5f;
237 y = ( (float) height * Modulo1IfNegative( st[ 1 ] ) ) + 0.5f;
241 pixels += ( y * width * 4 ) + ( x * 4 );
242 VectorCopy( pixels, color );
243 color[ 3 ] = pixels[ 3 ];
246 color[0] = Image_LinearFloatFromsRGBFloat( color[0] * ( 1.0 / 255.0 ) ) * 255.0;
247 color[1] = Image_LinearFloatFromsRGBFloat( color[1] * ( 1.0 / 255.0 ) ) * 255.0;
248 color[2] = Image_LinearFloatFromsRGBFloat( color[2] * ( 1.0 / 255.0 ) ) * 255.0;
258 samples a fragment's lightmap or vertex color and returns an
259 average color and a color gradient for the sample
262 #define MAX_SAMPLES 150
263 #define SAMPLE_GRANULARITY 6
265 static void RadSample( int lightmapNum, bspDrawSurface_t *ds, rawLightmap_t *lm, shaderInfo_t *si, radWinding_t *rw, vec3_t average, vec3_t gradient, int *style ){
266 int i, j, k, l, v, x, y, samples, avgcolor;
267 vec3_t color, mins, maxs;
269 float alpha, alphaI, bf;
271 float st[ 2 ], lightmap[ 2 ], *radLuxel;
275 Sys_Printf( "BUG: RadSample: !bouncing shouldn't happen\n" );
278 ClearBounds( mins, maxs );
279 VectorClear( average );
280 VectorClear( gradient );
284 if ( rw == NULL || rw->numVerts < 3 ) {
291 /* sample vertex colors if no lightmap or this is the initial pass */
292 if ( lm == NULL || lm->radLuxels[ lightmapNum ] == NULL || bouncing == qfalse ) {
293 for ( samples = 0; samples < rw->numVerts; samples++ )
295 /* multiply by texture color */
296 if ( !RadSampleImage( si->lightImage->pixels, si->lightImage->width, si->lightImage->height, rw->verts[ samples ].st, textureColor ) ) {
297 VectorCopy( si->averageColor, textureColor );
298 textureColor[ 3 ] = 255.0f;
300 avgcolor = ( textureColor[ 0 ] + textureColor[ 1 ] + textureColor[ 2 ] ) / 3;
301 for ( i = 0; i < 3; i++ )
302 color[ i ] = ( ( textureColor[ i ] * bounceColorRatio + ( avgcolor * ( 1 - bounceColorRatio ) ) ) / 255 ) * ( rw->verts[ samples ].color[ lightmapNum ][ i ] / 255.0f );
303 // color[ i ] = ( textureColor[ i ] / 255 ) * ( rw->verts[ samples ].color[ lightmapNum ][ i ] / 255.0f );
305 AddPointToBounds( color, mins, maxs );
306 VectorAdd( average, color, average );
309 alpha += ( textureColor[ 3 ] / 255.0f ) * ( rw->verts[ samples ].color[ lightmapNum ][ 3 ] / 255.0f );
313 *style = ds->vertexStyles[ lightmapNum ];
316 /* sample lightmap */
319 /* fracture the winding into a fan (including degenerate tris) */
320 for ( v = 1; v < ( rw->numVerts - 1 ) && samples < MAX_SAMPLES; v++ )
323 rv[ 0 ] = &rw->verts[ 0 ];
324 rv[ 1 ] = &rw->verts[ v ];
325 rv[ 2 ] = &rw->verts[ v + 1 ];
327 /* this code is embarassing (really should just rasterize the triangle) */
328 for ( i = 1; i < SAMPLE_GRANULARITY && samples < MAX_SAMPLES; i++ )
330 for ( j = 1; j < SAMPLE_GRANULARITY && samples < MAX_SAMPLES; j++ )
332 for ( k = 1; k < SAMPLE_GRANULARITY && samples < MAX_SAMPLES; k++ )
334 /* create a blend vector (barycentric coordinates) */
338 bf = ( 1.0 / ( blend[ 0 ] + blend[ 1 ] + blend[ 2 ] ) );
339 VectorScale( blend, bf, blend );
341 /* create a blended sample */
342 st[ 0 ] = st[ 1 ] = 0.0f;
343 lightmap[ 0 ] = lightmap[ 1 ] = 0.0f;
345 for ( l = 0; l < 3; l++ )
347 st[ 0 ] += ( rv[ l ]->st[ 0 ] * blend[ l ] );
348 st[ 1 ] += ( rv[ l ]->st[ 1 ] * blend[ l ] );
349 lightmap[ 0 ] += ( rv[ l ]->lightmap[ lightmapNum ][ 0 ] * blend[ l ] );
350 lightmap[ 1 ] += ( rv[ l ]->lightmap[ lightmapNum ][ 1 ] * blend[ l ] );
351 alphaI += ( rv[ l ]->color[ lightmapNum ][ 3 ] * blend[ l ] );
354 /* get lightmap xy coords */
355 x = lightmap[ 0 ] / (float) superSample;
356 y = lightmap[ 1 ] / (float) superSample;
360 else if ( x >= lm->w ) {
366 else if ( y >= lm->h ) {
370 /* get radiosity luxel */
371 radLuxel = RAD_LUXEL( lightmapNum, x, y );
373 /* ignore unlit/unused luxels */
374 if ( radLuxel[ 0 ] < 0.0f ) {
381 /* multiply by texture color */
382 if ( !RadSampleImage( si->lightImage->pixels, si->lightImage->width, si->lightImage->height, st, textureColor ) ) {
383 VectorCopy( si->averageColor, textureColor );
384 textureColor[ 3 ] = 255;
386 avgcolor = ( textureColor[ 0 ] + textureColor[ 1 ] + textureColor[ 2 ] ) / 3;
387 for ( l = 0; l < 3; l++ ){
388 color[ l ] = ( ( textureColor[ l ] * bounceColorRatio + ( avgcolor * ( 1 - bounceColorRatio ) ) ) / 255 ) * ( radLuxel[ l ] / 255 );
389 //Sys_Printf( "%i %i %i %i %i \n", (int) textureColor[ 0 ], (int) textureColor[ 1 ], (int) textureColor[ 2 ], (int) avgcolor, (int) color[ i ] );
391 AddPointToBounds( color, mins, maxs );
392 VectorAdd( average, color, average );
395 alpha += ( textureColor[ 3 ] / 255 ) * ( alphaI / 255 );
402 *style = ds->lightmapStyles[ lightmapNum ];
406 if ( samples <= 0 ) {
410 /* average the color */
411 VectorScale( average, ( 1.0 / samples ), average );
413 /* create the color gradient */
414 //% VectorSubtract( maxs, mins, delta );
416 /* new: color gradient will always be 0-1.0, expressed as the range of light relative to overall light */
417 //% gradient[ 0 ] = maxs[ 0 ] > 0.0f ? (maxs[ 0 ] - mins[ 0 ]) / maxs[ 0 ] : 0.0f;
418 //% gradient[ 1 ] = maxs[ 1 ] > 0.0f ? (maxs[ 1 ] - mins[ 1 ]) / maxs[ 1 ] : 0.0f;
419 //% gradient[ 2 ] = maxs[ 2 ] > 0.0f ? (maxs[ 2 ] - mins[ 2 ]) / maxs[ 2 ] : 0.0f;
421 /* newer: another contrast function */
422 for ( i = 0; i < 3; i++ )
423 gradient[ i ] = ( maxs[ i ] - mins[ i ] ) * maxs[ i ];
429 RadSubdivideDiffuseLight()
430 subdivides a radiosity winding until it is smaller than subdivide, then generates an area light
433 #define RADIOSITY_MAX_GRADIENT 0.75f //% 0.25f
434 #define RADIOSITY_VALUE 500.0f
435 #define RADIOSITY_MIN 0.0001f
436 #define RADIOSITY_CLIP_EPSILON 0.125f
438 static void RadSubdivideDiffuseLight( int lightmapNum, bspDrawSurface_t *ds, rawLightmap_t *lm, shaderInfo_t *si,
439 float scale, float subdivide, qboolean original, radWinding_t *rw, clipWork_t *cw ){
441 float dist, area, value;
442 vec3_t mins, maxs, normal, d1, d2, cross, color, gradient;
443 light_t *light, *splash;
448 if ( rw == NULL || rw->numVerts < 3 ) {
452 /* get bounds for winding */
453 ClearBounds( mins, maxs );
454 for ( i = 0; i < rw->numVerts; i++ )
455 AddPointToBounds( rw->verts[ i ].xyz, mins, maxs );
457 /* subdivide if necessary */
458 for ( i = 0; i < 3; i++ )
460 if ( maxs[ i ] - mins[ i ] > subdivide ) {
461 radWinding_t front, back;
464 /* make axial plane */
465 VectorClear( normal );
467 dist = ( maxs[ i ] + mins[ i ] ) * 0.5f;
469 /* clip the winding */
470 RadClipWindingEpsilon( rw, normal, dist, RADIOSITY_CLIP_EPSILON, &front, &back, cw );
473 RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qfalse, &front, cw );
474 RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qfalse, &back, cw );
481 for ( i = 2; i < rw->numVerts; i++ )
483 VectorSubtract( rw->verts[ i - 1 ].xyz, rw->verts[ 0 ].xyz, d1 );
484 VectorSubtract( rw->verts[ i ].xyz, rw->verts[ 0 ].xyz, d2 );
485 CrossProduct( d1, d2, cross );
486 area += 0.5f * VectorLength( cross );
488 if ( area < 1.0f || area > 20000000.0f ) {
492 /* more subdivision may be necessary */
494 /* get color sample for the surface fragment */
495 RadSample( lightmapNum, ds, lm, si, rw, color, gradient, &style );
497 /* if color gradient is too high, subdivide again */
498 if ( subdivide > minDiffuseSubdivide &&
499 ( gradient[ 0 ] > RADIOSITY_MAX_GRADIENT || gradient[ 1 ] > RADIOSITY_MAX_GRADIENT || gradient[ 2 ] > RADIOSITY_MAX_GRADIENT ) ) {
500 RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, ( subdivide / 2.0f ), qfalse, rw, cw );
505 /* create a regular winding and an average normal */
506 w = AllocWinding( rw->numVerts );
507 w->numpoints = rw->numVerts;
508 VectorClear( normal );
509 for ( i = 0; i < rw->numVerts; i++ )
511 VectorCopy( rw->verts[ i ].xyz, w->p[ i ] );
512 VectorAdd( normal, rw->verts[ i ].normal, normal );
514 VectorScale( normal, ( 1.0f / rw->numVerts ), normal );
515 if ( VectorNormalize( normal, normal ) == 0.0f ) {
520 if ( bouncing && VectorLength( color ) < RADIOSITY_MIN ) {
525 //% Sys_Printf( "Size: %d %d %d\n", (int) (maxs[ 0 ] - mins[ 0 ]), (int) (maxs[ 1 ] - mins[ 1 ]), (int) (maxs[ 2 ] - mins[ 2 ]) );
526 //% Sys_Printf( "Grad: %f %f %f\n", gradient[ 0 ], gradient[ 1 ], gradient[ 2 ] );
528 /* increment counts */
530 switch ( ds->surfaceType )
533 numBrushDiffuseLights++;
536 case MST_TRIANGLE_SOUP:
537 numTriangleDiffuseLights++;
541 numPatchDiffuseLights++;
546 light = safe_malloc0( sizeof( *light ) );
550 light->next = lights;
554 /* initialize the light */
555 light->flags = LIGHT_AREA_DEFAULT;
556 light->type = EMIT_AREA;
561 /* set falloff threshold */
562 light->falloffTolerance = falloffTolerance;
564 /* bouncing light? */
565 if ( bouncing == qfalse ) {
566 /* This is weird. This actually handles surfacelight and not
569 /* handle first-pass lights in normal q3a style */
571 light->photons = value * area * areaScale;
572 light->add = value * formFactorValueScale * areaScale;
573 VectorCopy( si->color, light->color );
574 VectorScale( light->color, light->add, light->emitColor );
575 light->style = noStyles ? LS_NORMAL : si->lightStyle;
576 if ( light->style < LS_NORMAL || light->style >= LS_NONE ) {
577 light->style = LS_NORMAL;
581 VectorAdd( mins, maxs, light->origin );
582 VectorScale( light->origin, 0.5f, light->origin );
584 /* nudge it off the plane a bit */
585 VectorCopy( normal, light->normal );
586 VectorMA( light->origin, 1.0f, light->normal, light->origin );
587 light->dist = DotProduct( light->origin, normal );
589 /* optionally create a point backsplash light for first pass */
590 if ( original && si->backsplashFraction > 0 ) {
591 /* allocate a new point light */
592 splash = safe_malloc0( sizeof( *splash ) );
593 splash->next = lights;
597 splash->flags = LIGHT_Q3A_DEFAULT;
598 splash->type = EMIT_POINT;
599 splash->photons = light->photons * si->backsplashFraction;
602 VectorMA( light->origin, si->backsplashDistance, normal, splash->origin );
603 VectorCopy( si->color, splash->color );
604 splash->falloffTolerance = falloffTolerance;
605 splash->style = noStyles ? LS_NORMAL : light->style;
613 /* handle bounced light (radiosity) a little differently */
614 value = RADIOSITY_VALUE * si->bounceScale * 0.375f;
615 light->photons = value * area * bounceScale;
616 light->add = value * formFactorValueScale * bounceScale;
617 VectorCopy( color, light->color );
618 VectorScale( light->color, light->add, light->emitColor );
619 light->style = noStyles ? LS_NORMAL : style;
620 if ( light->style < LS_NORMAL || light->style >= LS_NONE ) {
621 light->style = LS_NORMAL;
625 WindingCenter( w, light->origin );
627 /* nudge it off the plane a bit */
628 VectorCopy( normal, light->normal );
629 VectorMA( light->origin, 1.0f, light->normal, light->origin );
630 light->dist = DotProduct( light->origin, normal );
633 if (light->photons < 0 || light->add < 0 || light->color[0] < 0 || light->color[1] < 0 || light->color[2] < 0)
634 Sys_Printf( "BUG: RadSubdivideDiffuseLight created a darkbulb\n" );
636 /* emit light from both sides? */
637 if ( si->compileFlags & C_FOG || si->twoSided ) {
638 light->flags |= LIGHT_TWOSIDED;
641 //% Sys_Printf( "\nAL: C: (%6f, %6f, %6f) [%6f] N: (%6f, %6f, %6f) %s\n",
642 //% light->color[ 0 ], light->color[ 1 ], light->color[ 2 ], light->add,
643 //% light->normal[ 0 ], light->normal[ 1 ], light->normal[ 2 ],
644 //% light->si->shader );
650 RadLightForTriangles()
651 creates unbounced diffuse lights for triangle soup (misc_models, etc)
654 void RadLightForTriangles( int num, int lightmapNum, rawLightmap_t *lm, shaderInfo_t *si, float scale, float subdivide, clipWork_t *cw ){
656 bspDrawSurface_t *ds;
657 float *radVertexLuxel;
662 ds = &bspDrawSurfaces[ num ];
664 /* each triangle is a potential emitter */
666 for ( i = 0; i < ds->numIndexes; i += 3 )
669 for ( j = 0; j < 3; j++ )
671 /* get vertex index and rad vertex luxel */
672 v = ds->firstVert + bspDrawIndexes[ ds->firstIndex + i + j ];
674 /* get most everything */
675 memcpy( &rw.verts[ j ], &yDrawVerts[ v ], sizeof( bspDrawVert_t ) );
678 for ( k = 0; k < MAX_LIGHTMAPS; k++ )
680 radVertexLuxel = RAD_VERTEX_LUXEL( k, ds->firstVert + bspDrawIndexes[ ds->firstIndex + i + j ] );
681 VectorCopy( radVertexLuxel, rw.verts[ j ].color[ k ] );
682 rw.verts[ j ].color[ k ][ 3 ] = yDrawVerts[ v ].color[ k ][ 3 ];
686 /* subdivide into area lights */
687 RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw );
695 creates unbounced diffuse lights for patches
698 #define PLANAR_EPSILON 0.1f
700 void RadLightForPatch( int num, int lightmapNum, rawLightmap_t *lm, shaderInfo_t *si, float scale, float subdivide, clipWork_t *cw ){
701 int i, x, y, v, t, pw[ 5 ], r;
702 bspDrawSurface_t *ds;
704 bspDrawVert_t *bogus;
705 bspDrawVert_t *dv[ 4 ];
706 mesh_t src, *subdivided, *mesh;
707 float *radVertexLuxel;
715 ds = &bspDrawSurfaces[ num ];
716 info = &surfaceInfos[ num ];
718 /* construct a bogus vert list with color index stuffed into color[ 0 ] */
719 bogus = safe_malloc( ds->numVerts * sizeof( bspDrawVert_t ) );
720 memcpy( bogus, &yDrawVerts[ ds->firstVert ], ds->numVerts * sizeof( bspDrawVert_t ) );
721 for ( i = 0; i < ds->numVerts; i++ )
722 bogus[ i ].color[ 0 ][ 0 ] = i;
724 /* build a subdivided mesh identical to shadow facets for this patch */
725 /* this MUST MATCH FacetsForPatch() identically! */
726 src.width = ds->patchWidth;
727 src.height = ds->patchHeight;
729 //% subdivided = SubdivideMesh( src, 8, 512 );
730 subdivided = SubdivideMesh2( src, info->patchIterations );
731 PutMeshOnCurve( *subdivided );
732 //% MakeMeshNormals( *subdivided );
733 mesh = RemoveLinearMeshColumnsRows( subdivided );
734 FreeMesh( subdivided );
737 /* FIXME: build interpolation table into color[ 1 ] */
739 /* fix up color indexes */
740 for ( i = 0; i < ( mesh->width * mesh->height ); i++ )
742 dv[ 0 ] = &mesh->verts[ i ];
743 if ( dv[ 0 ]->color[ 0 ][ 0 ] >= ds->numVerts ) {
744 dv[ 0 ]->color[ 0 ][ 0 ] = ds->numVerts - 1;
748 /* iterate through the mesh quads */
749 for ( y = 0; y < ( mesh->height - 1 ); y++ )
751 for ( x = 0; x < ( mesh->width - 1 ); x++ )
754 pw[ 0 ] = x + ( y * mesh->width );
755 pw[ 1 ] = x + ( ( y + 1 ) * mesh->width );
756 pw[ 2 ] = x + 1 + ( ( y + 1 ) * mesh->width );
757 pw[ 3 ] = x + 1 + ( y * mesh->width );
758 pw[ 4 ] = x + ( y * mesh->width ); /* same as pw[ 0 ] */
764 dv[ 0 ] = &mesh->verts[ pw[ r + 0 ] ];
765 dv[ 1 ] = &mesh->verts[ pw[ r + 1 ] ];
766 dv[ 2 ] = &mesh->verts[ pw[ r + 2 ] ];
767 dv[ 3 ] = &mesh->verts[ pw[ r + 3 ] ];
770 planar = PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz );
772 dist = DotProduct( dv[ 1 ]->xyz, plane ) - plane[ 3 ];
773 if ( fabs( dist ) > PLANAR_EPSILON ) {
778 /* generate a quad */
781 for ( v = 0; v < 4; v++ )
783 /* get most everything */
784 memcpy( &rw.verts[ v ], dv[ v ], sizeof( bspDrawVert_t ) );
787 for ( i = 0; i < MAX_LIGHTMAPS; i++ )
789 radVertexLuxel = RAD_VERTEX_LUXEL( i, ds->firstVert + dv[ v ]->color[ 0 ][ 0 ] );
790 VectorCopy( radVertexLuxel, rw.verts[ v ].color[ i ] );
791 rw.verts[ v ].color[ i ][ 3 ] = dv[ v ]->color[ i ][ 3 ];
795 /* subdivide into area lights */
796 RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw );
799 /* generate 2 tris */
803 for ( t = 0; t < 2; t++ )
805 for ( v = 0; v < 3 + t; v++ )
807 /* get "other" triangle (stupid hacky logic, but whatevah) */
808 if ( v == 1 && t == 1 ) {
812 /* get most everything */
813 memcpy( &rw.verts[ v ], dv[ v ], sizeof( bspDrawVert_t ) );
816 for ( i = 0; i < MAX_LIGHTMAPS; i++ )
818 radVertexLuxel = RAD_VERTEX_LUXEL( i, ds->firstVert + dv[ v ]->color[ 0 ][ 0 ] );
819 VectorCopy( radVertexLuxel, rw.verts[ v ].color[ i ] );
820 rw.verts[ v ].color[ i ][ 3 ] = dv[ v ]->color[ i ][ 3 ];
824 /* subdivide into area lights */
825 RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw );
840 creates unbounced diffuse lights for a given surface
843 void RadLight( int num ){
845 float scale, subdivide;
846 int contentFlags, surfaceFlags, compileFlags;
847 bspDrawSurface_t *ds;
854 /* get drawsurface, lightmap, and shader info */
855 ds = &bspDrawSurfaces[ num ];
856 info = &surfaceInfos[ num ];
859 scale = si->bounceScale;
861 /* find nodraw bit */
862 contentFlags = surfaceFlags = compileFlags = 0;
863 ApplySurfaceParm( "nodraw", &contentFlags, &surfaceFlags, &compileFlags );
865 // jal : avoid bouncing on trans surfaces
866 ApplySurfaceParm( "trans", &contentFlags, &surfaceFlags, &compileFlags );
869 if ( scale <= 0.0f || ( si->compileFlags & C_SKY ) || si->autosprite ||
870 ( bspShaders[ ds->shaderNum ].contentFlags & contentFlags ) || ( bspShaders[ ds->shaderNum ].surfaceFlags & surfaceFlags ) ||
871 ( si->compileFlags & compileFlags ) ) {
875 /* determine how much we need to chop up the surface */
876 if ( si->lightSubdivide ) {
877 subdivide = si->lightSubdivide;
880 subdivide = diffuseSubdivide;
884 numDiffuseSurfaces++;
886 /* iterate through styles (this could be more efficient, yes) */
887 for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
890 if ( ds->lightmapStyles[ lightmapNum ] != LS_NONE && ds->lightmapStyles[ lightmapNum ] != LS_UNUSED ) {
891 switch ( ds->surfaceType )
894 case MST_TRIANGLE_SOUP:
895 RadLightForTriangles( num, lightmapNum, lm, si, scale, subdivide, &cw );
899 RadLightForPatch( num, lightmapNum, lm, si, scale, subdivide, &cw );
912 RadCreateDiffuseLights()
913 creates lights for unbounced light on surfaces in the bsp
918 void RadCreateDiffuseLights( void ){
920 Sys_FPrintf( SYS_VRB, "--- RadCreateDiffuseLights ---\n" );
921 numDiffuseSurfaces = 0;
922 numDiffuseLights = 0;
923 numBrushDiffuseLights = 0;
924 numTriangleDiffuseLights = 0;
925 numPatchDiffuseLights = 0;
928 /* hit every surface (threaded) */
929 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, RadLight );
931 /* dump the lights generated to a file */
933 char dumpName[ 1024 ], ext[ 64 ];
937 strcpy( dumpName, source );
938 StripExtension( dumpName );
939 sprintf( ext, "_bounce_%03d.map", iterations );
940 strcat( dumpName, ext );
941 file = fopen( dumpName, "wb" );
942 Sys_Printf( "Writing %s...\n", dumpName );
944 for ( light = lights; light; light = light->next )
948 "\"classname\" \"light\"\n"
950 "\"origin\" \"%.0f %.0f %.0f\"\n"
951 "\"_color\" \"%.3f %.3f %.3f\"\n"
972 Sys_Printf( "%8d diffuse surfaces\n", numDiffuseSurfaces );
973 Sys_FPrintf( SYS_VRB, "%8d total diffuse lights\n", numDiffuseLights );
974 Sys_FPrintf( SYS_VRB, "%8d brush diffuse lights\n", numBrushDiffuseLights );
975 Sys_FPrintf( SYS_VRB, "%8d patch diffuse lights\n", numPatchDiffuseLights );
976 Sys_FPrintf( SYS_VRB, "%8d triangle diffuse lights\n", numTriangleDiffuseLights );