2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
\r
5 This file is part of GtkRadiant.
\r
7 GtkRadiant is free software; you can redistribute it and/or modify
\r
8 it under the terms of the GNU General Public License as published by
\r
9 the Free Software Foundation; either version 2 of the License, or
\r
10 (at your option) any later version.
\r
12 GtkRadiant is distributed in the hope that it will be useful,
\r
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
15 GNU General Public License for more details.
\r
17 You should have received a copy of the GNU General Public License
\r
18 along with GtkRadiant; if not, write to the Free Software
\r
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
\r
21 ----------------------------------------------------------------------------------
\r
23 This code has been altered significantly from its original form, to support
\r
24 several games based on the Quake III Arena engine, in the form of "Q3Map2."
\r
26 ------------------------------------------------------------------------------- */
\r
31 #define LIGHT_BOUNCE_C
\r
44 deletes any existing lights, freeing up memory for the next bounce
\r
47 void RadFreeLights( void )
\r
49 light_t *light, *next;
\r
53 for( light = lights; light; light = next )
\r
56 if( light->w != NULL )
\r
57 FreeWinding( light->w );
\r
67 RadClipWindingEpsilon()
\r
68 clips a rad winding by a plane
\r
69 based off the regular clip winding code
\r
72 static void RadClipWindingEpsilon( radWinding_t *in, vec3_t normal, vec_t dist,
\r
73 vec_t epsilon, radWinding_t *front, radWinding_t *back, clipWork_t *cw )
\r
78 vec_t dot; /* ydnar: changed from static b/c of threading */ /* VC 4.2 optimizer bug if not static? */
\r
80 radVert_t *v1, *v2, mid;
\r
89 counts[ 0 ] = counts[ 1 ] = counts[ 2 ] = 0;
\r
91 /* determine sides for each point */
\r
92 for( i = 0; i < in->numVerts; i++ )
\r
94 dot = DotProduct( in->verts[ i ].xyz, normal );
\r
98 sides[ i ] = SIDE_FRONT;
\r
99 else if( dot < -epsilon )
\r
100 sides[ i ] = SIDE_BACK;
\r
102 sides[ i ] = SIDE_ON;
\r
103 counts[ sides[ i ] ]++;
\r
105 sides[ i ] = sides[ 0 ];
\r
106 dists[ i ] = dists[ 0 ];
\r
108 /* clear front and back */
\r
109 front->numVerts = back->numVerts = 0;
\r
111 /* handle all on one side cases */
\r
112 if( counts[ 0 ] == 0 )
\r
114 memcpy( back, in, sizeof( radWinding_t ) );
\r
117 if( counts[ 1 ] == 0 )
\r
119 memcpy( front, in, sizeof( radWinding_t ) );
\r
123 /* setup windings */
\r
124 maxPoints = in->numVerts + 4;
\r
126 /* do individual verts */
\r
127 for( i = 0; i < in->numVerts; i++ )
\r
129 /* do simple vertex copies first */
\r
130 v1 = &in->verts[ i ];
\r
132 if( sides[ i ] == SIDE_ON )
\r
134 memcpy( &front->verts[ front->numVerts++ ], v1, sizeof( radVert_t ) );
\r
135 memcpy( &back->verts[ back->numVerts++ ], v1, sizeof( radVert_t ) );
\r
139 if( sides[ i ] == SIDE_FRONT )
\r
140 memcpy( &front->verts[ front->numVerts++ ], v1, sizeof( radVert_t ) );
\r
142 if( sides[ i ] == SIDE_BACK )
\r
143 memcpy( &back->verts[ back->numVerts++ ], v1, sizeof( radVert_t ) );
\r
145 if( sides[ i + 1 ] == SIDE_ON || sides[ i + 1 ] == sides[ i ] )
\r
148 /* generate a split vertex */
\r
149 v2 = &in->verts[ (i + 1) % in->numVerts ];
\r
151 dot = dists[ i ] / (dists[ i ] - dists[ i + 1 ]);
\r
153 /* average vertex values */
\r
154 for( j = 0; j < 4; j++ )
\r
159 for( k = 0; k < MAX_LIGHTMAPS; k++ )
\r
160 mid.color[ k ][ j ] = v1->color[ k ][ j ] + dot * (v2->color[ k ][ j ] - v1->color[ k ][ j ]);
\r
166 mid.xyz[ j ] = v1->xyz[ j ] + dot * (v2->xyz[ j ] - v1->xyz[ j ]);
\r
167 mid.normal[ j ] = v1->normal[ j ] + dot * (v2->normal[ j ] - v1->normal[ j ]);
\r
173 mid.st[ j ] = v1->st[ j ] + dot * (v2->st[ j ] - v1->st[ j ]);
\r
174 for( k = 0; k < MAX_LIGHTMAPS; k++ )
\r
175 mid.lightmap[ k ][ j ] = v1->lightmap[ k ][ j ] + dot * (v2->lightmap[ k ][ j ] - v1->lightmap[ k ][ j ]);
\r
179 /* normalize the averaged normal */
\r
180 VectorNormalize( mid.normal, mid.normal );
\r
182 /* copy the midpoint to both windings */
\r
183 memcpy( &front->verts[ front->numVerts++ ], &mid, sizeof( radVert_t ) );
\r
184 memcpy( &back->verts[ back->numVerts++ ], &mid, sizeof( radVert_t ) );
\r
188 if( front->numVerts > maxPoints || front->numVerts > maxPoints )
\r
189 Error( "RadClipWindingEpsilon: points exceeded estimate" );
\r
190 if( front->numVerts > MAX_POINTS_ON_WINDING || front->numVerts > MAX_POINTS_ON_WINDING )
\r
191 Error( "RadClipWindingEpsilon: MAX_POINTS_ON_WINDING" );
\r
200 samples a texture image for a given color
\r
201 returns qfalse if pixels are bad
\r
204 qboolean RadSampleImage( byte *pixels, int width, int height, float st[ 2 ], float color[ 4 ] )
\r
210 /* clear color first */
\r
211 color[ 0 ] = color[ 1 ] = color[ 2 ] = color[ 3 ] = 255;
\r
214 if( pixels == NULL || width < 1 || height < 1 )
\r
218 sto[ 0 ] = st[ 0 ];
\r
219 while( sto[ 0 ] < 0.0f )
\r
221 sto[ 1 ] = st[ 1 ];
\r
222 while( sto[ 1 ] < 0.0f )
\r
226 x = ((float) width * sto[ 0 ]) + 0.5f;
\r
228 y = ((float) height * sto[ 1 ]) + 0.5f;
\r
232 pixels += (y * width * 4) + (x * 4);
\r
233 VectorCopy( pixels, color );
\r
234 color[ 3 ] = pixels[ 3 ];
\r
242 samples a fragment's lightmap or vertex color and returns an
\r
243 average color and a color gradient for the sample
\r
246 #define MAX_SAMPLES 150
\r
247 #define SAMPLE_GRANULARITY 6
\r
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 )
\r
251 int i, j, k, l, v, x, y, samples;
\r
252 vec3_t color, mins, maxs;
\r
253 vec4_t textureColor;
\r
254 float alpha, alphaI, bf;
\r
256 float st[ 2 ], lightmap[ 2 ], *radLuxel;
\r
257 radVert_t *rv[ 3 ];
\r
260 /* initial setup */
\r
261 ClearBounds( mins, maxs );
\r
262 VectorClear( average );
\r
263 VectorClear( gradient );
\r
267 if( rw == NULL || rw->numVerts < 3 )
\r
270 /* start sampling */
\r
273 /* sample vertex colors if no lightmap or this is the initial pass */
\r
274 if( lm == NULL || lm->radLuxels[ lightmapNum ] == NULL || bouncing == qfalse )
\r
276 for( samples = 0; samples < rw->numVerts; samples++ )
\r
278 /* multiply by texture color */
\r
279 if( !RadSampleImage( si->lightImage->pixels, si->lightImage->width, si->lightImage->height, rw->verts[ samples ].st, textureColor ) )
\r
281 VectorCopy( si->averageColor, textureColor );
\r
282 textureColor[ 4 ] = 255.0f;
\r
284 for( i = 0; i < 3; i++ )
\r
285 color[ i ] = (textureColor[ i ] / 255) * (rw->verts[ samples ].color[ lightmapNum ][ i ] / 255.0f);
\r
287 AddPointToBounds( color, mins, maxs );
\r
288 VectorAdd( average, color, average );
\r
291 alpha += (textureColor[ 3 ] / 255.0f) * (rw->verts[ samples ].color[ lightmapNum ][ 3 ] / 255.0f);
\r
295 *style = ds->vertexStyles[ lightmapNum ];
\r
298 /* sample lightmap */
\r
301 /* fracture the winding into a fan (including degenerate tris) */
\r
302 for( v = 1; v < (rw->numVerts - 1) && samples < MAX_SAMPLES; v++ )
\r
304 /* get a triangle */
\r
305 rv[ 0 ] = &rw->verts[ 0 ];
\r
306 rv[ 1 ] = &rw->verts[ v ];
\r
307 rv[ 2 ] = &rw->verts[ v + 1 ];
\r
309 /* this code is embarassing (really should just rasterize the triangle) */
\r
310 for( i = 1; i < SAMPLE_GRANULARITY && samples < MAX_SAMPLES; i++ )
\r
312 for( j = 1; j < SAMPLE_GRANULARITY && samples < MAX_SAMPLES; j++ )
\r
314 for( k = 1; k < SAMPLE_GRANULARITY && samples < MAX_SAMPLES; k++ )
\r
316 /* create a blend vector (barycentric coordinates) */
\r
320 bf = (1.0 / (blend[ 0 ] + blend[ 1 ] + blend[ 2 ]));
\r
321 VectorScale( blend, bf, blend );
\r
323 /* create a blended sample */
\r
324 st[ 0 ] = st[ 1 ] = 0.0f;
\r
325 lightmap[ 0 ] = lightmap[ 1 ] = 0.0f;
\r
327 for( l = 0; l < 3; l++ )
\r
329 st[ 0 ] += (rv[ l ]->st[ 0 ] * blend[ l ]);
\r
330 st[ 1 ] += (rv[ l ]->st[ 1 ] * blend[ l ]);
\r
331 lightmap[ 0 ] += (rv[ l ]->lightmap[ lightmapNum ][ 0 ] * blend[ l ]);
\r
332 lightmap[ 1 ] += (rv[ l ]->lightmap[ lightmapNum ][ 1 ] * blend[ l ]);
\r
333 alphaI += (rv[ l ]->color[ lightmapNum ][ 3 ] * blend[ l ]);
\r
336 /* get lightmap xy coords */
\r
337 x = lightmap[ 0 ] / (float) superSample;
\r
338 y = lightmap[ 1 ] / (float) superSample;
\r
341 else if ( x >= lm->w )
\r
345 else if ( y >= lm->h )
\r
348 /* get radiosity luxel */
\r
349 radLuxel = RAD_LUXEL( lightmapNum, x, y );
\r
351 /* ignore unlit/unused luxels */
\r
352 if( radLuxel[ 0 ] < 0.0f )
\r
358 /* multiply by texture color */
\r
359 if( !RadSampleImage( si->lightImage->pixels, si->lightImage->width, si->lightImage->height, st, textureColor ) )
\r
361 VectorCopy( si->averageColor, textureColor );
\r
362 textureColor[ 4 ] = 255;
\r
364 for( i = 0; i < 3; i++ )
\r
365 color[ i ] = (textureColor[ i ] / 255) * (radLuxel[ i ] / 255);
\r
367 AddPointToBounds( color, mins, maxs );
\r
368 VectorAdd( average, color, average );
\r
371 alpha += (textureColor[ 3 ] / 255) * (alphaI / 255);
\r
378 *style = ds->lightmapStyles[ lightmapNum ];
\r
385 /* average the color */
\r
386 VectorScale( average, (1.0 / samples), average );
\r
388 /* create the color gradient */
\r
389 //% VectorSubtract( maxs, mins, delta );
\r
391 /* new: color gradient will always be 0-1.0, expressed as the range of light relative to overall light */
\r
392 //% gradient[ 0 ] = maxs[ 0 ] > 0.0f ? (maxs[ 0 ] - mins[ 0 ]) / maxs[ 0 ] : 0.0f;
\r
393 //% gradient[ 1 ] = maxs[ 1 ] > 0.0f ? (maxs[ 1 ] - mins[ 1 ]) / maxs[ 1 ] : 0.0f;
\r
394 //% gradient[ 2 ] = maxs[ 2 ] > 0.0f ? (maxs[ 2 ] - mins[ 2 ]) / maxs[ 2 ] : 0.0f;
\r
396 /* newer: another contrast function */
\r
397 for( i = 0; i < 3; i++ )
\r
398 gradient[ i ] = (maxs[ i ] - mins[ i ]) * maxs[ i ];
\r
404 RadSubdivideDiffuseLight()
\r
405 subdivides a radiosity winding until it is smaller than subdivide, then generates an area light
\r
408 #define RADIOSITY_MAX_GRADIENT 0.75f //% 0.25f
\r
409 #define RADIOSITY_VALUE 500.0f
\r
410 #define RADIOSITY_MIN 0.0001f
\r
411 #define RADIOSITY_CLIP_EPSILON 0.125f
\r
413 static void RadSubdivideDiffuseLight( int lightmapNum, bspDrawSurface_t *ds, rawLightmap_t *lm, shaderInfo_t *si,
\r
414 float scale, float subdivide, qboolean original, radWinding_t *rw, clipWork_t *cw )
\r
417 float dist, area, value;
\r
418 vec3_t mins, maxs, normal, d1, d2, cross, color, gradient;
\r
419 light_t *light, *splash;
\r
424 if( rw == NULL || rw->numVerts < 3 )
\r
427 /* get bounds for winding */
\r
428 ClearBounds( mins, maxs );
\r
429 for( i = 0; i < rw->numVerts; i++ )
\r
430 AddPointToBounds( rw->verts[ i ].xyz, mins, maxs );
\r
432 /* subdivide if necessary */
\r
433 for( i = 0; i < 3; i++ )
\r
435 if( maxs[ i ] - mins[ i ] > subdivide )
\r
437 radWinding_t front, back;
\r
440 /* make axial plane */
\r
441 VectorClear( normal );
\r
443 dist = (maxs[ i ] + mins[ i ]) * 0.5f;
\r
445 /* clip the winding */
\r
446 RadClipWindingEpsilon( rw, normal, dist, RADIOSITY_CLIP_EPSILON, &front, &back, cw );
\r
449 RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qfalse, &front, cw );
\r
450 RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qfalse, &back, cw );
\r
457 for( i = 2; i < rw->numVerts; i++ )
\r
459 VectorSubtract( rw->verts[ i - 1 ].xyz, rw->verts[ 0 ].xyz, d1 );
\r
460 VectorSubtract( rw->verts[ i ].xyz, rw->verts[ 0 ].xyz, d2 );
\r
461 CrossProduct( d1, d2, cross );
\r
462 area += 0.5f * VectorLength( cross );
\r
464 if( area < 1.0f || area > 20000000.0f )
\r
467 /* more subdivision may be necessary */
\r
470 /* get color sample for the surface fragment */
\r
471 RadSample( lightmapNum, ds, lm, si, rw, color, gradient, &style );
\r
473 /* if color gradient is too high, subdivide again */
\r
474 if( subdivide > minDiffuseSubdivide &&
\r
475 (gradient[ 0 ] > RADIOSITY_MAX_GRADIENT || gradient[ 1 ] > RADIOSITY_MAX_GRADIENT || gradient[ 2 ] > RADIOSITY_MAX_GRADIENT) )
\r
477 RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, (subdivide / 2.0f), qfalse, rw, cw );
\r
482 /* create a regular winding and an average normal */
\r
483 w = AllocWinding( rw->numVerts );
\r
484 w->numpoints = rw->numVerts;
\r
485 VectorClear( normal );
\r
486 for( i = 0; i < rw->numVerts; i++ )
\r
488 VectorCopy( rw->verts[ i ].xyz, w->p[ i ] );
\r
489 VectorAdd( normal, rw->verts[ i ].normal, normal );
\r
491 VectorScale( normal, (1.0f / rw->numVerts), normal );
\r
492 if( VectorNormalize( normal, normal ) == 0.0f )
\r
496 if( bouncing && VectorLength( color ) < RADIOSITY_MIN )
\r
500 //% Sys_Printf( "Size: %d %d %d\n", (int) (maxs[ 0 ] - mins[ 0 ]), (int) (maxs[ 1 ] - mins[ 1 ]), (int) (maxs[ 2 ] - mins[ 2 ]) );
\r
501 //% Sys_Printf( "Grad: %f %f %f\n", gradient[ 0 ], gradient[ 1 ], gradient[ 2 ] );
\r
503 /* increment counts */
\r
504 numDiffuseLights++;
\r
505 switch( ds->surfaceType )
\r
508 numBrushDiffuseLights++;
\r
511 case MST_TRIANGLE_SOUP:
\r
512 numTriangleDiffuseLights;
\r
516 numPatchDiffuseLights++;
\r
520 /* create a light */
\r
521 light = safe_malloc( sizeof( *light ) );
\r
522 memset( light, 0, sizeof( *light ) );
\r
526 light->next = lights;
\r
530 /* initialize the light */
\r
531 light->flags = LIGHT_AREA_DEFAULT;
\r
532 light->type = EMIT_AREA;
\r
534 light->fade = 1.0f;
\r
537 /* set falloff threshold */
\r
538 light->falloffTolerance = falloffTolerance;
\r
540 /* bouncing light? */
\r
541 if( bouncing == qfalse )
\r
543 /* handle first-pass lights in normal q3a style */
\r
545 light->photons = value * area * areaScale;
\r
546 light->add = value * formFactorValueScale * areaScale;
\r
547 VectorCopy( si->color, light->color );
\r
548 VectorScale( light->color, light->add, light->emitColor );
\r
549 light->style = si->lightStyle;
\r
550 if( light->style < 0 || light->style >= LS_NONE )
\r
554 VectorAdd( mins, maxs, light->origin );
\r
555 VectorScale( light->origin, 0.5f, light->origin );
\r
557 /* nudge it off the plane a bit */
\r
558 VectorCopy( normal, light->normal );
\r
559 VectorMA( light->origin, 1.0f, light->normal, light->origin );
\r
560 light->dist = DotProduct( light->origin, normal );
\r
562 /* optionally create a point splashsplash light for first pass */
\r
563 if( original && si->backsplashFraction > 0 )
\r
565 /* allocate a new point light */
\r
566 splash = safe_malloc( sizeof( *splash ) );
\r
567 memset( splash, 0, sizeof( *splash ) );
\r
568 splash->next = lights;
\r
572 splash->flags = LIGHT_Q3A_DEFAULT;
\r
573 splash->type = EMIT_POINT;
\r
574 splash->photons = light->photons * si->backsplashFraction;
\r
575 splash->fade = 1.0f;
\r
577 VectorMA( light->origin, si->backsplashDistance, normal, splash->origin );
\r
578 VectorCopy( si->color, splash->color );
\r
579 splash->falloffTolerance = falloffTolerance;
\r
580 splash->style = light->style;
\r
582 /* add to counts */
\r
588 /* handle bounced light (radiosity) a little differently */
\r
589 value = RADIOSITY_VALUE * si->bounceScale * 0.375f;
\r
590 light->photons = value * area * bounceScale;
\r
591 light->add = value * formFactorValueScale * bounceScale;
\r
592 VectorCopy( color, light->color );
\r
593 VectorScale( light->color, light->add, light->emitColor );
\r
594 light->style = style;
\r
595 if( light->style < 0 || light->style >= LS_NONE )
\r
599 WindingCenter( w, light->origin );
\r
601 /* nudge it off the plane a bit */
\r
602 VectorCopy( normal, light->normal );
\r
603 VectorMA( light->origin, 1.0f, light->normal, light->origin );
\r
604 light->dist = DotProduct( light->origin, normal );
\r
607 /* emit light from both sides? */
\r
608 if( si->compileFlags & C_FOG || si->twoSided )
\r
609 light->flags |= LIGHT_TWOSIDED;
\r
611 //% Sys_Printf( "\nAL: C: (%6f, %6f, %6f) [%6f] N: (%6f, %6f, %6f) %s\n",
\r
612 //% light->color[ 0 ], light->color[ 1 ], light->color[ 2 ], light->add,
\r
613 //% light->normal[ 0 ], light->normal[ 1 ], light->normal[ 2 ],
\r
614 //% light->si->shader );
\r
620 RadLightForTriangles()
\r
621 creates unbounced diffuse lights for triangle soup (misc_models, etc)
\r
624 void RadLightForTriangles( int num, int lightmapNum, rawLightmap_t *lm, shaderInfo_t *si, float scale, float subdivide, clipWork_t *cw )
\r
627 bspDrawSurface_t *ds;
\r
628 surfaceInfo_t *info;
\r
629 float *radVertexLuxel;
\r
634 ds = &bspDrawSurfaces[ num ];
\r
635 info = &surfaceInfos[ num ];
\r
637 /* each triangle is a potential emitter */
\r
639 for( i = 0; i < ds->numIndexes; i += 3 )
\r
641 /* copy each vert */
\r
642 for( j = 0; j < 3; j++ )
\r
644 /* get vertex index and rad vertex luxel */
\r
645 v = ds->firstVert + bspDrawIndexes[ ds->firstIndex + i + j ];
\r
647 /* get most everything */
\r
648 memcpy( &rw.verts[ j ], &yDrawVerts[ v ], sizeof( bspDrawVert_t ) );
\r
651 for( k = 0; k < MAX_LIGHTMAPS; k++ )
\r
653 radVertexLuxel = RAD_VERTEX_LUXEL( k, ds->firstVert + bspDrawIndexes[ ds->firstIndex + i + j ] );
\r
654 VectorCopy( radVertexLuxel, rw.verts[ j ].color[ k ] );
\r
655 rw.verts[ j ].color[ k ][ 3 ] = yDrawVerts[ v ].color[ k ][ 3 ];
\r
659 /* subdivide into area lights */
\r
660 RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw );
\r
668 creates unbounced diffuse lights for patches
\r
671 #define PLANAR_EPSILON 0.1f
\r
673 void RadLightForPatch( int num, int lightmapNum, rawLightmap_t *lm, shaderInfo_t *si, float scale, float subdivide, clipWork_t *cw )
\r
675 int i, x, y, v, t, pw[ 5 ], r;
\r
676 bspDrawSurface_t *ds;
\r
677 surfaceInfo_t *info;
\r
678 bspDrawVert_t *bogus;
\r
679 bspDrawVert_t *dv[ 4 ];
\r
680 mesh_t src, *subdivided, *mesh;
\r
681 float *radVertexLuxel;
\r
689 ds = &bspDrawSurfaces[ num ];
\r
690 info = &surfaceInfos[ num ];
\r
692 /* construct a bogus vert list with color index stuffed into color[ 0 ] */
\r
693 bogus = safe_malloc( ds->numVerts * sizeof( bspDrawVert_t ) );
\r
694 memcpy( bogus, &yDrawVerts[ ds->firstVert ], ds->numVerts * sizeof( bspDrawVert_t ) );
\r
695 for( i = 0; i < ds->numVerts; i++ )
\r
696 bogus[ i ].color[ 0 ][ 0 ] = i;
\r
698 /* build a subdivided mesh identical to shadow facets for this patch */
\r
699 /* this MUST MATCH FacetsForPatch() identically! */
\r
700 src.width = ds->patchWidth;
\r
701 src.height = ds->patchHeight;
\r
703 //% subdivided = SubdivideMesh( src, 8, 512 );
\r
704 subdivided = SubdivideMesh2( src, info->patchIterations );
\r
705 PutMeshOnCurve( *subdivided );
\r
706 //% MakeMeshNormals( *subdivided );
\r
707 mesh = RemoveLinearMeshColumnsRows( subdivided );
\r
708 FreeMesh( subdivided );
\r
711 /* FIXME: build interpolation table into color[ 1 ] */
\r
713 /* fix up color indexes */
\r
714 for( i = 0; i < (mesh->width * mesh->height); i++ )
\r
716 dv[ 0 ] = &mesh->verts[ i ];
\r
717 if( dv[ 0 ]->color[ 0 ][ 0 ] >= ds->numVerts )
\r
718 dv[ 0 ]->color[ 0 ][ 0 ] = ds->numVerts - 1;
\r
721 /* iterate through the mesh quads */
\r
722 for( y = 0; y < (mesh->height - 1); y++ )
\r
724 for( x = 0; x < (mesh->width - 1); x++ )
\r
727 pw[ 0 ] = x + (y * mesh->width);
\r
728 pw[ 1 ] = x + ((y + 1) * mesh->width);
\r
729 pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
\r
730 pw[ 3 ] = x + 1 + (y * mesh->width);
\r
731 pw[ 4 ] = x + (y * mesh->width); /* same as pw[ 0 ] */
\r
736 /* get drawverts */
\r
737 dv[ 0 ] = &mesh->verts[ pw[ r + 0 ] ];
\r
738 dv[ 1 ] = &mesh->verts[ pw[ r + 1 ] ];
\r
739 dv[ 2 ] = &mesh->verts[ pw[ r + 2 ] ];
\r
740 dv[ 3 ] = &mesh->verts[ pw[ r + 3 ] ];
\r
743 planar = PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz );
\r
746 dist = DotProduct( dv[ 1 ]->xyz, plane ) - plane[ 3 ];
\r
747 if( fabs( dist ) > PLANAR_EPSILON )
\r
751 /* generate a quad */
\r
755 for( v = 0; v < 4; v++ )
\r
757 /* get most everything */
\r
758 memcpy( &rw.verts[ v ], dv[ v ], sizeof( bspDrawVert_t ) );
\r
761 for( i = 0; i < MAX_LIGHTMAPS; i++ )
\r
763 radVertexLuxel = RAD_VERTEX_LUXEL( i, ds->firstVert + dv[ v ]->color[ 0 ][ 0 ] );
\r
764 VectorCopy( radVertexLuxel, rw.verts[ v ].color[ i ] );
\r
765 rw.verts[ v ].color[ i ][ 3 ] = dv[ v ]->color[ i ][ 3 ];
\r
769 /* subdivide into area lights */
\r
770 RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw );
\r
773 /* generate 2 tris */
\r
777 for( t = 0; t < 2; t++ )
\r
779 for( v = 0; v < 3 + t; v++ )
\r
781 /* get "other" triangle (stupid hacky logic, but whatevah) */
\r
782 if( v == 1 && t == 1 )
\r
785 /* get most everything */
\r
786 memcpy( &rw.verts[ v ], dv[ v ], sizeof( bspDrawVert_t ) );
\r
789 for( i = 0; i < MAX_LIGHTMAPS; i++ )
\r
791 radVertexLuxel = RAD_VERTEX_LUXEL( i, ds->firstVert + dv[ v ]->color[ 0 ][ 0 ] );
\r
792 VectorCopy( radVertexLuxel, rw.verts[ v ].color[ i ] );
\r
793 rw.verts[ v ].color[ i ][ 3 ] = dv[ v ]->color[ i ][ 3 ];
\r
797 /* subdivide into area lights */
\r
798 RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw );
\r
804 /* free the mesh */
\r
813 creates unbounced diffuse lights for a given surface
\r
816 void RadLight( int num )
\r
819 float scale, subdivide;
\r
820 int contentFlags, surfaceFlags, compileFlags;
\r
821 bspDrawSurface_t *ds;
\r
822 surfaceInfo_t *info;
\r
828 /* get drawsurface, lightmap, and shader info */
\r
829 ds = &bspDrawSurfaces[ num ];
\r
830 info = &surfaceInfos[ num ];
\r
833 scale = si->bounceScale;
\r
835 /* find nodraw bit */
\r
836 contentFlags = surfaceFlags = compileFlags = 0;
\r
837 ApplySurfaceParm( "nodraw", &contentFlags, &surfaceFlags, &compileFlags );
\r
840 if( scale <= 0.0f || (si->compileFlags & C_SKY) || si->autosprite ||
\r
841 (bspShaders[ ds->shaderNum ].contentFlags & contentFlags) || (bspShaders[ ds->shaderNum ].surfaceFlags & surfaceFlags) ||
\r
842 (si->compileFlags & compileFlags) )
\r
845 /* determine how much we need to chop up the surface */
\r
846 if( si->lightSubdivide )
\r
847 subdivide = si->lightSubdivide;
\r
849 subdivide = diffuseSubdivide;
\r
852 numDiffuseSurfaces++;
\r
854 /* iterate through styles (this could be more efficient, yes) */
\r
855 for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
\r
857 /* switch on type */
\r
858 if( ds->lightmapStyles[ lightmapNum ] != LS_NONE && ds->lightmapStyles[ lightmapNum ] != LS_UNUSED )
\r
860 switch( ds->surfaceType )
\r
863 case MST_TRIANGLE_SOUP:
\r
864 RadLightForTriangles( num, lightmapNum, lm, si, scale, subdivide, &cw );
\r
868 RadLightForPatch( num, lightmapNum, lm, si, scale, subdivide, &cw );
\r
881 RadCreateDiffuseLights()
\r
882 creates lights for unbounced light on surfaces in the bsp
\r
885 int iterations = 0;
\r
887 void RadCreateDiffuseLights( void )
\r
890 Sys_FPrintf( SYS_VRB, "--- RadCreateDiffuseLights ---\n" );
\r
891 numDiffuseSurfaces = 0;
\r
892 numDiffuseLights = 0;
\r
893 numBrushDiffuseLights = 0;
\r
894 numTriangleDiffuseLights = 0;
\r
895 numPatchDiffuseLights = 0;
\r
898 /* hit every surface (threaded) */
\r
899 RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, RadLight );
\r
901 /* dump the lights generated to a file */
\r
904 char dumpName[ 1024 ], ext[ 64 ];
\r
908 strcpy( dumpName, source );
\r
909 StripExtension( dumpName );
\r
910 sprintf( ext, "_bounce_%03d.map", iterations );
\r
911 strcat( dumpName, ext );
\r
912 file = fopen( dumpName, "wb" );
\r
913 Sys_Printf( "Writing %s...\n", dumpName );
\r
916 for( light = lights; light; light = light->next )
\r
920 "\"classname\" \"light\"\n"
\r
921 "\"light\" \"%d\"\n"
\r
922 "\"origin\" \"%.0f %.0f %.0f\"\n"
\r
923 "\"_color\" \"%.3f %.3f %.3f\"\n"
\r
928 light->origin[ 0 ],
\r
929 light->origin[ 1 ],
\r
930 light->origin[ 2 ],
\r
934 light->color[ 2 ] );
\r
944 Sys_Printf( "%8d diffuse surfaces\n", numDiffuseSurfaces );
\r
945 Sys_FPrintf( SYS_VRB, "%8d total diffuse lights\n", numDiffuseLights );
\r
946 Sys_FPrintf( SYS_VRB, "%8d brush diffuse lights\n", numBrushDiffuseLights );
\r
947 Sys_FPrintf( SYS_VRB, "%8d patch diffuse lights\n", numPatchDiffuseLights );
\r
948 Sys_FPrintf( SYS_VRB, "%8d triangle diffuse lights\n", numTriangleDiffuseLights );
\r