/* -------------------------------------------------------------------------------
-Copyright (C) 1999-2007 id Software, Inc. and contributors.
-For a list of contributors, see the accompanying CONTRIBUTORS file.
+ Copyright (C) 1999-2007 id Software, Inc. and contributors.
+ For a list of contributors, see the accompanying CONTRIBUTORS file.
-This file is part of GtkRadiant.
+ This file is part of GtkRadiant.
-GtkRadiant is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+ GtkRadiant is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
-GtkRadiant is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+ GtkRadiant is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with GtkRadiant; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ You should have received a copy of the GNU General Public License
+ along with GtkRadiant; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-----------------------------------------------------------------------------------
+ ----------------------------------------------------------------------------------
-This code has been altered significantly from its original form, to support
-several games based on the Quake III Arena engine, in the form of "Q3Map2."
+ This code has been altered significantly from its original form, to support
+ several games based on the Quake III Arena engine, in the form of "Q3Map2."
-------------------------------------------------------------------------------- */
+ ------------------------------------------------------------------------------- */
/* functions */
/*
-RadFreeLights()
-deletes any existing lights, freeing up memory for the next bounce
-*/
+ RadFreeLights()
+ deletes any existing lights, freeing up memory for the next bounce
+ */
+
+void RadFreeLights( void ){
+ light_t *light, *next;
+
-void RadFreeLights( void )
-{
- light_t *light, *next;
-
-
/* delete lights */
- for( light = lights; light; light = next )
+ for ( light = lights; light; light = next )
{
next = light->next;
- if( light->w != NULL )
+ if ( light->w != NULL ) {
FreeWinding( light->w );
+ }
free( light );
}
numLights = 0;
/*
-RadClipWindingEpsilon()
-clips a rad winding by a plane
-based off the regular clip winding code
-*/
+ RadClipWindingEpsilon()
+ clips a rad winding by a plane
+ based off the regular clip winding code
+ */
static void RadClipWindingEpsilon( radWinding_t *in, vec3_t normal, vec_t dist,
- vec_t epsilon, radWinding_t *front, radWinding_t *back, clipWork_t *cw )
-{
- vec_t *dists;
- int *sides;
- int counts[ 3 ];
- vec_t dot; /* ydnar: changed from static b/c of threading */ /* VC 4.2 optimizer bug if not static? */
- int i, j, k;
- radVert_t *v1, *v2, mid;
- int maxPoints;
-
-
+ vec_t epsilon, radWinding_t *front, radWinding_t *back, clipWork_t *cw ){
+ vec_t *dists;
+ int *sides;
+ int counts[ 3 ];
+ vec_t dot; /* ydnar: changed from static b/c of threading */ /* VC 4.2 optimizer bug if not static? */
+ int i, j, k;
+ radVert_t *v1, *v2, mid;
+ int maxPoints;
+
+
/* crutch */
dists = cw->dists;
sides = cw->sides;
-
+
/* clear counts */
counts[ 0 ] = counts[ 1 ] = counts[ 2 ] = 0;
/* determine sides for each point */
- for( i = 0; i < in->numVerts; i++ )
+ for ( i = 0; i < in->numVerts; i++ )
{
dot = DotProduct( in->verts[ i ].xyz, normal );
dot -= dist;
dists[ i ] = dot;
- if( dot > epsilon )
+ if ( dot > epsilon ) {
sides[ i ] = SIDE_FRONT;
- else if( dot < -epsilon )
+ }
+ else if ( dot < -epsilon ) {
sides[ i ] = SIDE_BACK;
- else
+ }
+ else{
sides[ i ] = SIDE_ON;
+ }
counts[ sides[ i ] ]++;
}
sides[ i ] = sides[ 0 ];
dists[ i ] = dists[ 0 ];
-
+
/* clear front and back */
front->numVerts = back->numVerts = 0;
-
+
/* handle all on one side cases */
- if( counts[ 0 ] == 0 )
- {
+ if ( counts[ 0 ] == 0 ) {
memcpy( back, in, sizeof( radWinding_t ) );
return;
}
- if( counts[ 1 ] == 0 )
- {
+ if ( counts[ 1 ] == 0 ) {
memcpy( front, in, sizeof( radWinding_t ) );
return;
}
-
+
/* setup windings */
maxPoints = in->numVerts + 4;
-
+
/* do individual verts */
- for( i = 0; i < in->numVerts; i++ )
+ for ( i = 0; i < in->numVerts; i++ )
{
/* do simple vertex copies first */
v1 = &in->verts[ i ];
-
- if( sides[ i ] == SIDE_ON )
- {
+
+ if ( sides[ i ] == SIDE_ON ) {
memcpy( &front->verts[ front->numVerts++ ], v1, sizeof( radVert_t ) );
memcpy( &back->verts[ back->numVerts++ ], v1, sizeof( radVert_t ) );
continue;
}
-
- if( sides[ i ] == SIDE_FRONT )
+
+ if ( sides[ i ] == SIDE_FRONT ) {
memcpy( &front->verts[ front->numVerts++ ], v1, sizeof( radVert_t ) );
-
- if( sides[ i ] == SIDE_BACK )
+ }
+
+ if ( sides[ i ] == SIDE_BACK ) {
memcpy( &back->verts[ back->numVerts++ ], v1, sizeof( radVert_t ) );
-
- if( sides[ i + 1 ] == SIDE_ON || sides[ i + 1 ] == sides[ i ] )
+ }
+
+ if ( sides[ i + 1 ] == SIDE_ON || sides[ i + 1 ] == sides[ i ] ) {
continue;
-
+ }
+
/* generate a split vertex */
- v2 = &in->verts[ (i + 1) % in->numVerts ];
-
- dot = dists[ i ] / (dists[ i ] - dists[ i + 1 ]);
+ v2 = &in->verts[ ( i + 1 ) % in->numVerts ];
+
+ dot = dists[ i ] / ( dists[ i ] - dists[ i + 1 ] );
/* average vertex values */
- for( j = 0; j < 4; j++ )
+ for ( j = 0; j < 4; j++ )
{
/* color */
- if( j < 4 )
- {
- for( k = 0; k < MAX_LIGHTMAPS; k++ )
- mid.color[ k ][ j ] = v1->color[ k ][ j ] + dot * (v2->color[ k ][ j ] - v1->color[ k ][ j ]);
+ if ( j < 4 ) {
+ for ( k = 0; k < MAX_LIGHTMAPS; k++ )
+ mid.color[ k ][ j ] = v1->color[ k ][ j ] + dot * ( v2->color[ k ][ j ] - v1->color[ k ][ j ] );
}
-
+
/* xyz, normal */
- if( j < 3 )
- {
- mid.xyz[ j ] = v1->xyz[ j ] + dot * (v2->xyz[ j ] - v1->xyz[ j ]);
- mid.normal[ j ] = v1->normal[ j ] + dot * (v2->normal[ j ] - v1->normal[ j ]);
+ if ( j < 3 ) {
+ mid.xyz[ j ] = v1->xyz[ j ] + dot * ( v2->xyz[ j ] - v1->xyz[ j ] );
+ mid.normal[ j ] = v1->normal[ j ] + dot * ( v2->normal[ j ] - v1->normal[ j ] );
}
-
+
/* st, lightmap */
- if( j < 2 )
- {
- mid.st[ j ] = v1->st[ j ] + dot * (v2->st[ j ] - v1->st[ j ]);
- for( k = 0; k < MAX_LIGHTMAPS; k++ )
- mid.lightmap[ k ][ j ] = v1->lightmap[ k ][ j ] + dot * (v2->lightmap[ k ][ j ] - v1->lightmap[ k ][ j ]);
+ if ( j < 2 ) {
+ mid.st[ j ] = v1->st[ j ] + dot * ( v2->st[ j ] - v1->st[ j ] );
+ for ( k = 0; k < MAX_LIGHTMAPS; k++ )
+ mid.lightmap[ k ][ j ] = v1->lightmap[ k ][ j ] + dot * ( v2->lightmap[ k ][ j ] - v1->lightmap[ k ][ j ] );
}
}
-
+
/* normalize the averaged normal */
VectorNormalize( mid.normal, mid.normal );
memcpy( &front->verts[ front->numVerts++ ], &mid, sizeof( radVert_t ) );
memcpy( &back->verts[ back->numVerts++ ], &mid, sizeof( radVert_t ) );
}
-
+
/* error check */
- if( front->numVerts > maxPoints || front->numVerts > maxPoints )
+ if ( front->numVerts > maxPoints || front->numVerts > maxPoints ) {
Error( "RadClipWindingEpsilon: points exceeded estimate" );
- if( front->numVerts > MAX_POINTS_ON_WINDING || front->numVerts > MAX_POINTS_ON_WINDING )
+ }
+ if ( front->numVerts > MAX_POINTS_ON_WINDING || front->numVerts > MAX_POINTS_ON_WINDING ) {
Error( "RadClipWindingEpsilon: MAX_POINTS_ON_WINDING" );
+ }
}
+/*
+ Modulo1IfNegative()
+ Previously the bias computation was doing:
+ while ( f < 0.0f ) {
+ f += 1.0f;
+ }
-/*
-RadSampleImage()
-samples a texture image for a given color
-returns qfalse if pixels are bad
+ That may end in infinite loop in some case.
+ It may also be slower because of useless loops.
+ I don't know what that computation is for.
+ -- illwieckz
*/
+float Modulo1IfNegative( float f ){
+ return f < 0.0f ? f - floor( f ) : f;
+}
+
+
+
+/*
+ RadSampleImage()
+ samples a texture image for a given color
+ returns qfalse if pixels are bad
+ */
+
+qboolean RadSampleImage( byte *pixels, int width, int height, float st[ 2 ], float color[ 4 ] ){
+ int x, y;
-qboolean RadSampleImage( byte *pixels, int width, int height, float st[ 2 ], float color[ 4 ] )
-{
- float sto[ 2 ];
- int x, y;
-
-
/* clear color first */
color[ 0 ] = color[ 1 ] = color[ 2 ] = color[ 3 ] = 255;
-
+
/* dummy check */
- if( pixels == NULL || width < 1 || height < 1 )
+ if ( pixels == NULL || width < 1 || height < 1 ) {
return qfalse;
-
- /* bias st */
- sto[ 0 ] = st[ 0 ];
- while( sto[ 0 ] < 0.0f )
- sto[ 0 ] += 1.0f;
- sto[ 1 ] = st[ 1 ];
- while( sto[ 1 ] < 0.0f )
- sto[ 1 ] += 1.0f;
+ }
/* get offsets */
- x = ((float) width * sto[ 0 ]) + 0.5f;
+ x = ( (float) width * Modulo1IfNegative( st[ 0 ] ) ) + 0.5f;
x %= width;
- y = ((float) height * sto[ 1 ]) + 0.5f;
+ y = ( (float) height * Modulo1IfNegative( st[ 1 ] ) ) + 0.5f;
y %= height;
-
+
/* get pixel */
- pixels += (y * width * 4) + (x * 4);
+ pixels += ( y * width * 4 ) + ( x * 4 );
VectorCopy( pixels, color );
color[ 3 ] = pixels[ 3 ];
+
+ if ( texturesRGB ) {
+ color[0] = Image_LinearFloatFromsRGBFloat( color[0] * ( 1.0 / 255.0 ) ) * 255.0;
+ color[1] = Image_LinearFloatFromsRGBFloat( color[1] * ( 1.0 / 255.0 ) ) * 255.0;
+ color[2] = Image_LinearFloatFromsRGBFloat( color[2] * ( 1.0 / 255.0 ) ) * 255.0;
+ }
+
return qtrue;
}
/*
-RadSample()
-samples a fragment's lightmap or vertex color and returns an
-average color and a color gradient for the sample
-*/
+ RadSample()
+ samples a fragment's lightmap or vertex color and returns an
+ average color and a color gradient for the sample
+ */
+
+#define MAX_SAMPLES 150
+#define SAMPLE_GRANULARITY 6
+
+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 ){
+ int i, j, k, l, v, x, y, samples, avgcolor;
+ vec3_t color, mins, maxs;
+ vec4_t textureColor;
+ float alpha, alphaI, bf;
+ vec3_t blend;
+ float st[ 2 ], lightmap[ 2 ], *radLuxel;
+ radVert_t *rv[ 3 ];
+
+ if (!bouncing)
+ Sys_Printf( "BUG: RadSample: !bouncing shouldn't happen\n" );
-#define MAX_SAMPLES 150
-#define SAMPLE_GRANULARITY 6
-
-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 )
-{
- int i, j, k, l, v, x, y, samples;
- vec3_t color, mins, maxs;
- vec4_t textureColor;
- float alpha, alphaI, bf;
- vec3_t blend;
- float st[ 2 ], lightmap[ 2 ], *radLuxel;
- radVert_t *rv[ 3 ];
-
-
/* initial setup */
ClearBounds( mins, maxs );
VectorClear( average );
VectorClear( gradient );
alpha = 0;
-
+
/* dummy check */
- if( rw == NULL || rw->numVerts < 3 )
+ if ( rw == NULL || rw->numVerts < 3 ) {
return;
-
+ }
+
/* start sampling */
samples = 0;
-
+
/* sample vertex colors if no lightmap or this is the initial pass */
- if( lm == NULL || lm->radLuxels[ lightmapNum ] == NULL || bouncing == qfalse )
- {
- for( samples = 0; samples < rw->numVerts; samples++ )
+ if ( lm == NULL || lm->radLuxels[ lightmapNum ] == NULL || bouncing == qfalse ) {
+ for ( samples = 0; samples < rw->numVerts; samples++ )
{
/* multiply by texture color */
- if( !RadSampleImage( si->lightImage->pixels, si->lightImage->width, si->lightImage->height, rw->verts[ samples ].st, textureColor ) )
- {
+ if ( !RadSampleImage( si->lightImage->pixels, si->lightImage->width, si->lightImage->height, rw->verts[ samples ].st, textureColor ) ) {
VectorCopy( si->averageColor, textureColor );
textureColor[ 4 ] = 255.0f;
}
- for( i = 0; i < 3; i++ )
- color[ i ] = (textureColor[ i ] / 255) * (rw->verts[ samples ].color[ lightmapNum ][ i ] / 255.0f);
-
+ avgcolor = ( textureColor[ 0 ] + textureColor[ 1 ] + textureColor[ 2 ] ) / 3;
+ for ( i = 0; i < 3; i++ )
+ color[ i ] = ( ( textureColor[ i ] * bounceColorRatio + ( avgcolor * ( 1 - bounceColorRatio ) ) ) / 255 ) * ( rw->verts[ samples ].color[ lightmapNum ][ i ] / 255.0f );
+// color[ i ] = ( textureColor[ i ] / 255 ) * ( rw->verts[ samples ].color[ lightmapNum ][ i ] / 255.0f );
+
AddPointToBounds( color, mins, maxs );
VectorAdd( average, color, average );
-
+
/* get alpha */
- alpha += (textureColor[ 3 ] / 255.0f) * (rw->verts[ samples ].color[ lightmapNum ][ 3 ] / 255.0f);
+ alpha += ( textureColor[ 3 ] / 255.0f ) * ( rw->verts[ samples ].color[ lightmapNum ][ 3 ] / 255.0f );
}
-
+
/* set style */
*style = ds->vertexStyles[ lightmapNum ];
}
-
+
/* sample lightmap */
else
{
/* fracture the winding into a fan (including degenerate tris) */
- for( v = 1; v < (rw->numVerts - 1) && samples < MAX_SAMPLES; v++ )
+ for ( v = 1; v < ( rw->numVerts - 1 ) && samples < MAX_SAMPLES; v++ )
{
/* get a triangle */
rv[ 0 ] = &rw->verts[ 0 ];
rv[ 1 ] = &rw->verts[ v ];
rv[ 2 ] = &rw->verts[ v + 1 ];
-
+
/* this code is embarassing (really should just rasterize the triangle) */
- for( i = 1; i < SAMPLE_GRANULARITY && samples < MAX_SAMPLES; i++ )
+ for ( i = 1; i < SAMPLE_GRANULARITY && samples < MAX_SAMPLES; i++ )
{
- for( j = 1; j < SAMPLE_GRANULARITY && samples < MAX_SAMPLES; j++ )
+ for ( j = 1; j < SAMPLE_GRANULARITY && samples < MAX_SAMPLES; j++ )
{
- for( k = 1; k < SAMPLE_GRANULARITY && samples < MAX_SAMPLES; k++ )
+ for ( k = 1; k < SAMPLE_GRANULARITY && samples < MAX_SAMPLES; k++ )
{
/* create a blend vector (barycentric coordinates) */
blend[ 0 ] = i;
blend[ 1 ] = j;
blend[ 2 ] = k;
- bf = (1.0 / (blend[ 0 ] + blend[ 1 ] + blend[ 2 ]));
+ bf = ( 1.0 / ( blend[ 0 ] + blend[ 1 ] + blend[ 2 ] ) );
VectorScale( blend, bf, blend );
-
+
/* create a blended sample */
st[ 0 ] = st[ 1 ] = 0.0f;
lightmap[ 0 ] = lightmap[ 1 ] = 0.0f;
alphaI = 0.0f;
- for( l = 0; l < 3; l++ )
+ for ( l = 0; l < 3; l++ )
{
- st[ 0 ] += (rv[ l ]->st[ 0 ] * blend[ l ]);
- st[ 1 ] += (rv[ l ]->st[ 1 ] * blend[ l ]);
- lightmap[ 0 ] += (rv[ l ]->lightmap[ lightmapNum ][ 0 ] * blend[ l ]);
- lightmap[ 1 ] += (rv[ l ]->lightmap[ lightmapNum ][ 1 ] * blend[ l ]);
- alphaI += (rv[ l ]->color[ lightmapNum ][ 3 ] * blend[ l ]);
+ st[ 0 ] += ( rv[ l ]->st[ 0 ] * blend[ l ] );
+ st[ 1 ] += ( rv[ l ]->st[ 1 ] * blend[ l ] );
+ lightmap[ 0 ] += ( rv[ l ]->lightmap[ lightmapNum ][ 0 ] * blend[ l ] );
+ lightmap[ 1 ] += ( rv[ l ]->lightmap[ lightmapNum ][ 1 ] * blend[ l ] );
+ alphaI += ( rv[ l ]->color[ lightmapNum ][ 3 ] * blend[ l ] );
}
-
+
/* get lightmap xy coords */
x = lightmap[ 0 ] / (float) superSample;
y = lightmap[ 1 ] / (float) superSample;
- if( x < 0 )
+ if ( x < 0 ) {
x = 0;
- else if ( x >= lm->w )
+ }
+ else if ( x >= lm->w ) {
x = lm->w - 1;
- if( y < 0 )
+ }
+ if ( y < 0 ) {
y = 0;
- else if ( y >= lm->h )
+ }
+ else if ( y >= lm->h ) {
y = lm->h - 1;
-
+ }
+
/* get radiosity luxel */
radLuxel = RAD_LUXEL( lightmapNum, x, y );
-
+
/* ignore unlit/unused luxels */
- if( radLuxel[ 0 ] < 0.0f )
+ if ( radLuxel[ 0 ] < 0.0f ) {
continue;
-
+ }
+
/* inc samples */
samples++;
-
+
/* multiply by texture color */
- if( !RadSampleImage( si->lightImage->pixels, si->lightImage->width, si->lightImage->height, st, textureColor ) )
- {
+ if ( !RadSampleImage( si->lightImage->pixels, si->lightImage->width, si->lightImage->height, st, textureColor ) ) {
VectorCopy( si->averageColor, textureColor );
textureColor[ 4 ] = 255;
}
- for( i = 0; i < 3; i++ )
- color[ i ] = (textureColor[ i ] / 255) * (radLuxel[ i ] / 255);
-
+ avgcolor = ( textureColor[ 0 ] + textureColor[ 1 ] + textureColor[ 2 ] ) / 3;
+ for ( l = 0; l < 3; l++ ){
+ color[ l ] = ( ( textureColor[ l ] * bounceColorRatio + ( avgcolor * ( 1 - bounceColorRatio ) ) ) / 255 ) * ( radLuxel[ l ] / 255 );
+ //Sys_Printf( "%i %i %i %i %i \n", (int) textureColor[ 0 ], (int) textureColor[ 1 ], (int) textureColor[ 2 ], (int) avgcolor, (int) color[ i ] );
+ }
AddPointToBounds( color, mins, maxs );
VectorAdd( average, color, average );
-
+
/* get alpha */
- alpha += (textureColor[ 3 ] / 255) * (alphaI / 255);
+ alpha += ( textureColor[ 3 ] / 255 ) * ( alphaI / 255 );
}
}
}
}
-
+
/* set style */
*style = ds->lightmapStyles[ lightmapNum ];
}
-
+
/* any samples? */
- if( samples <= 0 )
+ if ( samples <= 0 ) {
return;
-
+ }
+
/* average the color */
- VectorScale( average, (1.0 / samples), average );
-
+ VectorScale( average, ( 1.0 / samples ), average );
+
/* create the color gradient */
//% VectorSubtract( maxs, mins, delta );
-
+
/* new: color gradient will always be 0-1.0, expressed as the range of light relative to overall light */
//% gradient[ 0 ] = maxs[ 0 ] > 0.0f ? (maxs[ 0 ] - mins[ 0 ]) / maxs[ 0 ] : 0.0f;
//% gradient[ 1 ] = maxs[ 1 ] > 0.0f ? (maxs[ 1 ] - mins[ 1 ]) / maxs[ 1 ] : 0.0f;
//% gradient[ 2 ] = maxs[ 2 ] > 0.0f ? (maxs[ 2 ] - mins[ 2 ]) / maxs[ 2 ] : 0.0f;
-
+
/* newer: another contrast function */
- for( i = 0; i < 3; i++ )
- gradient[ i ] = (maxs[ i ] - mins[ i ]) * maxs[ i ];
+ for ( i = 0; i < 3; i++ )
+ gradient[ i ] = ( maxs[ i ] - mins[ i ] ) * maxs[ i ];
}
/*
-RadSubdivideDiffuseLight()
-subdivides a radiosity winding until it is smaller than subdivide, then generates an area light
-*/
+ RadSubdivideDiffuseLight()
+ subdivides a radiosity winding until it is smaller than subdivide, then generates an area light
+ */
-#define RADIOSITY_MAX_GRADIENT 0.75f //% 0.25f
-#define RADIOSITY_VALUE 500.0f
-#define RADIOSITY_MIN 0.0001f
-#define RADIOSITY_CLIP_EPSILON 0.125f
+#define RADIOSITY_MAX_GRADIENT 0.75f //% 0.25f
+#define RADIOSITY_VALUE 500.0f
+#define RADIOSITY_MIN 0.0001f
+#define RADIOSITY_CLIP_EPSILON 0.125f
static void RadSubdivideDiffuseLight( int lightmapNum, bspDrawSurface_t *ds, rawLightmap_t *lm, shaderInfo_t *si,
- float scale, float subdivide, qboolean original, radWinding_t *rw, clipWork_t *cw )
-{
- int i, style = 0;
- float dist, area, value;
- vec3_t mins, maxs, normal, d1, d2, cross, color, gradient;
- light_t *light, *splash;
- winding_t *w;
-
-
+ float scale, float subdivide, qboolean original, radWinding_t *rw, clipWork_t *cw ){
+ int i, style = 0;
+ float dist, area, value;
+ vec3_t mins, maxs, normal, d1, d2, cross, color, gradient;
+ light_t *light, *splash;
+ winding_t *w;
+
+
/* dummy check */
- if( rw == NULL || rw->numVerts < 3 )
+ if ( rw == NULL || rw->numVerts < 3 ) {
return;
-
+ }
+
/* get bounds for winding */
ClearBounds( mins, maxs );
- for( i = 0; i < rw->numVerts; i++ )
+ for ( i = 0; i < rw->numVerts; i++ )
AddPointToBounds( rw->verts[ i ].xyz, mins, maxs );
-
+
/* subdivide if necessary */
- for( i = 0; i < 3; i++ )
+ for ( i = 0; i < 3; i++ )
{
- if( maxs[ i ] - mins[ i ] > subdivide )
- {
- radWinding_t front, back;
-
-
+ if ( maxs[ i ] - mins[ i ] > subdivide ) {
+ radWinding_t front, back;
+
+
/* make axial plane */
VectorClear( normal );
normal[ i ] = 1;
- dist = (maxs[ i ] + mins[ i ]) * 0.5f;
-
+ dist = ( maxs[ i ] + mins[ i ] ) * 0.5f;
+
/* clip the winding */
RadClipWindingEpsilon( rw, normal, dist, RADIOSITY_CLIP_EPSILON, &front, &back, cw );
-
+
/* recurse */
RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qfalse, &front, cw );
RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qfalse, &back, cw );
return;
}
}
-
+
/* check area */
area = 0.0f;
- for( i = 2; i < rw->numVerts; i++ )
+ for ( i = 2; i < rw->numVerts; i++ )
{
VectorSubtract( rw->verts[ i - 1 ].xyz, rw->verts[ 0 ].xyz, d1 );
VectorSubtract( rw->verts[ i ].xyz, rw->verts[ 0 ].xyz, d2 );
CrossProduct( d1, d2, cross );
area += 0.5f * VectorLength( cross );
}
- if( area < 1.0f || area > 20000000.0f )
+ if ( area < 1.0f || area > 20000000.0f ) {
return;
-
+ }
+
/* more subdivision may be necessary */
- if( bouncing )
- {
+ if ( bouncing ) {
/* get color sample for the surface fragment */
RadSample( lightmapNum, ds, lm, si, rw, color, gradient, &style );
-
+
/* if color gradient is too high, subdivide again */
- if( subdivide > minDiffuseSubdivide &&
- (gradient[ 0 ] > RADIOSITY_MAX_GRADIENT || gradient[ 1 ] > RADIOSITY_MAX_GRADIENT || gradient[ 2 ] > RADIOSITY_MAX_GRADIENT) )
- {
- RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, (subdivide / 2.0f), qfalse, rw, cw );
+ if ( subdivide > minDiffuseSubdivide &&
+ ( gradient[ 0 ] > RADIOSITY_MAX_GRADIENT || gradient[ 1 ] > RADIOSITY_MAX_GRADIENT || gradient[ 2 ] > RADIOSITY_MAX_GRADIENT ) ) {
+ RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, ( subdivide / 2.0f ), qfalse, rw, cw );
return;
}
}
-
+
/* create a regular winding and an average normal */
w = AllocWinding( rw->numVerts );
w->numpoints = rw->numVerts;
VectorClear( normal );
- for( i = 0; i < rw->numVerts; i++ )
+ for ( i = 0; i < rw->numVerts; i++ )
{
VectorCopy( rw->verts[ i ].xyz, w->p[ i ] );
VectorAdd( normal, rw->verts[ i ].normal, normal );
}
- VectorScale( normal, (1.0f / rw->numVerts), normal );
- if( VectorNormalize( normal, normal ) == 0.0f )
+ VectorScale( normal, ( 1.0f / rw->numVerts ), normal );
+ if ( VectorNormalize( normal, normal ) == 0.0f ) {
return;
-
+ }
+
/* early out? */
- if( bouncing && VectorLength( color ) < RADIOSITY_MIN )
+ if ( bouncing && VectorLength( color ) < RADIOSITY_MIN ) {
return;
-
+ }
+
/* debug code */
//% Sys_Printf( "Size: %d %d %d\n", (int) (maxs[ 0 ] - mins[ 0 ]), (int) (maxs[ 1 ] - mins[ 1 ]), (int) (maxs[ 2 ] - mins[ 2 ]) );
//% Sys_Printf( "Grad: %f %f %f\n", gradient[ 0 ], gradient[ 1 ], gradient[ 2 ] );
-
+
/* increment counts */
numDiffuseLights++;
- switch( ds->surfaceType )
+ switch ( ds->surfaceType )
{
- case MST_PLANAR:
- numBrushDiffuseLights++;
- break;
-
- case MST_TRIANGLE_SOUP:
- numTriangleDiffuseLights++;
- break;
-
- case MST_PATCH:
- numPatchDiffuseLights++;
- break;
- }
-
+ case MST_PLANAR:
+ numBrushDiffuseLights++;
+ break;
+
+ case MST_TRIANGLE_SOUP:
+ numTriangleDiffuseLights++;
+ break;
+
+ case MST_PATCH:
+ numPatchDiffuseLights++;
+ break;
+ }
+
/* create a light */
- light = safe_malloc( sizeof( *light ) );
- memset( light, 0, sizeof( *light ) );
-
+ light = safe_malloc0( sizeof( *light ) );
+
/* attach it */
ThreadLock();
light->next = lights;
lights = light;
ThreadUnlock();
-
+
/* initialize the light */
light->flags = LIGHT_AREA_DEFAULT;
light->type = EMIT_AREA;
light->si = si;
light->fade = 1.0f;
light->w = w;
-
+
/* set falloff threshold */
light->falloffTolerance = falloffTolerance;
-
+
/* bouncing light? */
- if( !bouncing )
- {
+ if ( bouncing == qfalse ) {
+ /* This is weird. This actually handles surfacelight and not
+ * bounces. */
+
/* handle first-pass lights in normal q3a style */
value = si->value;
light->photons = value * area * areaScale;
VectorCopy( si->color, light->color );
VectorScale( light->color, light->add, light->emitColor );
light->style = noStyles ? LS_NORMAL : si->lightStyle;
- if( light->style < LS_NORMAL || light->style >= LS_NONE )
+ if ( light->style < LS_NORMAL || light->style >= LS_NONE ) {
light->style = LS_NORMAL;
-
+ }
+
/* set origin */
VectorAdd( mins, maxs, light->origin );
VectorScale( light->origin, 0.5f, light->origin );
-
+
/* nudge it off the plane a bit */
VectorCopy( normal, light->normal );
VectorMA( light->origin, 1.0f, light->normal, light->origin );
light->dist = DotProduct( light->origin, normal );
-
+
/* optionally create a point splashsplash light for first pass */
- if( original && si->backsplashFraction > 0 )
- {
+ if ( original && si->backsplashFraction > 0 ) {
/* allocate a new point light */
- splash = safe_malloc( sizeof( *splash ) );
- memset( splash, 0, sizeof( *splash ) );
+ splash = safe_malloc0( sizeof( *splash ) );
splash->next = lights;
lights = splash;
-
+
/* set it up */
splash->flags = LIGHT_Q3A_DEFAULT;
splash->type = EMIT_POINT;
VectorCopy( si->color, splash->color );
splash->falloffTolerance = falloffTolerance;
splash->style = noStyles ? LS_NORMAL : light->style;
-
+
/* add to counts */
numPointLights++;
}
VectorCopy( color, light->color );
VectorScale( light->color, light->add, light->emitColor );
light->style = noStyles ? LS_NORMAL : style;
- if( light->style < LS_NORMAL || light->style >= LS_NONE )
+ if ( light->style < LS_NORMAL || light->style >= LS_NONE ) {
light->style = LS_NORMAL;
-
+ }
+
/* set origin */
WindingCenter( w, light->origin );
-
+
/* nudge it off the plane a bit */
VectorCopy( normal, light->normal );
VectorMA( light->origin, 1.0f, light->normal, light->origin );
light->dist = DotProduct( light->origin, normal );
}
-
+
+ if (light->photons < 0 || light->add < 0 || light->color[0] < 0 || light->color[1] < 0 || light->color[2] < 0)
+ Sys_Printf( "BUG: RadSubdivideDiffuseLight created a darkbulb\n" );
+
/* emit light from both sides? */
- if( si->compileFlags & C_FOG || si->twoSided )
+ if ( si->compileFlags & C_FOG || si->twoSided ) {
light->flags |= LIGHT_TWOSIDED;
-
+ }
+
//% Sys_Printf( "\nAL: C: (%6f, %6f, %6f) [%6f] N: (%6f, %6f, %6f) %s\n",
//% light->color[ 0 ], light->color[ 1 ], light->color[ 2 ], light->add,
//% light->normal[ 0 ], light->normal[ 1 ], light->normal[ 2 ],
/*
-RadLightForTriangles()
-creates unbounced diffuse lights for triangle soup (misc_models, etc)
-*/
+ RadLightForTriangles()
+ creates unbounced diffuse lights for triangle soup (misc_models, etc)
+ */
+
+void RadLightForTriangles( int num, int lightmapNum, rawLightmap_t *lm, shaderInfo_t *si, float scale, float subdivide, clipWork_t *cw ){
+ int i, j, k, v;
+ bspDrawSurface_t *ds;
+ float *radVertexLuxel;
+ radWinding_t rw;
+
-void RadLightForTriangles( int num, int lightmapNum, rawLightmap_t *lm, shaderInfo_t *si, float scale, float subdivide, clipWork_t *cw )
-{
- int i, j, k, v;
- bspDrawSurface_t *ds;
- surfaceInfo_t *info;
- float *radVertexLuxel;
- radWinding_t rw;
-
-
/* get surface */
ds = &bspDrawSurfaces[ num ];
- info = &surfaceInfos[ num ];
-
+
/* each triangle is a potential emitter */
rw.numVerts = 3;
- for( i = 0; i < ds->numIndexes; i += 3 )
+ for ( i = 0; i < ds->numIndexes; i += 3 )
{
/* copy each vert */
- for( j = 0; j < 3; j++ )
+ for ( j = 0; j < 3; j++ )
{
/* get vertex index and rad vertex luxel */
v = ds->firstVert + bspDrawIndexes[ ds->firstIndex + i + j ];
-
+
/* get most everything */
memcpy( &rw.verts[ j ], &yDrawVerts[ v ], sizeof( bspDrawVert_t ) );
-
+
/* fix colors */
- for( k = 0; k < MAX_LIGHTMAPS; k++ )
+ for ( k = 0; k < MAX_LIGHTMAPS; k++ )
{
radVertexLuxel = RAD_VERTEX_LUXEL( k, ds->firstVert + bspDrawIndexes[ ds->firstIndex + i + j ] );
VectorCopy( radVertexLuxel, rw.verts[ j ].color[ k ] );
rw.verts[ j ].color[ k ][ 3 ] = yDrawVerts[ v ].color[ k ][ 3 ];
}
}
-
+
/* subdivide into area lights */
RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw );
}
/*
-RadLightForPatch()
-creates unbounced diffuse lights for patches
-*/
+ RadLightForPatch()
+ creates unbounced diffuse lights for patches
+ */
+
+#define PLANAR_EPSILON 0.1f
+
+void RadLightForPatch( int num, int lightmapNum, rawLightmap_t *lm, shaderInfo_t *si, float scale, float subdivide, clipWork_t *cw ){
+ int i, x, y, v, t, pw[ 5 ], r;
+ bspDrawSurface_t *ds;
+ surfaceInfo_t *info;
+ bspDrawVert_t *bogus;
+ bspDrawVert_t *dv[ 4 ];
+ mesh_t src, *subdivided, *mesh;
+ float *radVertexLuxel;
+ float dist;
+ vec4_t plane;
+ qboolean planar;
+ radWinding_t rw;
+
-#define PLANAR_EPSILON 0.1f
-
-void RadLightForPatch( int num, int lightmapNum, rawLightmap_t *lm, shaderInfo_t *si, float scale, float subdivide, clipWork_t *cw )
-{
- int i, x, y, v, t, pw[ 5 ], r;
- bspDrawSurface_t *ds;
- surfaceInfo_t *info;
- bspDrawVert_t *bogus;
- bspDrawVert_t *dv[ 4 ];
- mesh_t src, *subdivided, *mesh;
- float *radVertexLuxel;
- float dist;
- vec4_t plane;
- qboolean planar;
- radWinding_t rw;
-
-
/* get surface */
ds = &bspDrawSurfaces[ num ];
info = &surfaceInfos[ num ];
-
+
/* construct a bogus vert list with color index stuffed into color[ 0 ] */
bogus = safe_malloc( ds->numVerts * sizeof( bspDrawVert_t ) );
memcpy( bogus, &yDrawVerts[ ds->firstVert ], ds->numVerts * sizeof( bspDrawVert_t ) );
- for( i = 0; i < ds->numVerts; i++ )
+ for ( i = 0; i < ds->numVerts; i++ )
bogus[ i ].color[ 0 ][ 0 ] = i;
-
+
/* build a subdivided mesh identical to shadow facets for this patch */
/* this MUST MATCH FacetsForPatch() identically! */
src.width = ds->patchWidth;
mesh = RemoveLinearMeshColumnsRows( subdivided );
FreeMesh( subdivided );
free( bogus );
-
+
/* FIXME: build interpolation table into color[ 1 ] */
-
+
/* fix up color indexes */
- for( i = 0; i < (mesh->width * mesh->height); i++ )
+ for ( i = 0; i < ( mesh->width * mesh->height ); i++ )
{
dv[ 0 ] = &mesh->verts[ i ];
- if( dv[ 0 ]->color[ 0 ][ 0 ] >= ds->numVerts )
+ if ( dv[ 0 ]->color[ 0 ][ 0 ] >= ds->numVerts ) {
dv[ 0 ]->color[ 0 ][ 0 ] = ds->numVerts - 1;
+ }
}
-
+
/* iterate through the mesh quads */
- for( y = 0; y < (mesh->height - 1); y++ )
+ for ( y = 0; y < ( mesh->height - 1 ); y++ )
{
- for( x = 0; x < (mesh->width - 1); x++ )
+ for ( x = 0; x < ( mesh->width - 1 ); x++ )
{
/* set indexes */
- pw[ 0 ] = x + (y * mesh->width);
- pw[ 1 ] = x + ((y + 1) * mesh->width);
- pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
- pw[ 3 ] = x + 1 + (y * mesh->width);
- pw[ 4 ] = x + (y * mesh->width); /* same as pw[ 0 ] */
-
+ pw[ 0 ] = x + ( y * mesh->width );
+ pw[ 1 ] = x + ( ( y + 1 ) * mesh->width );
+ pw[ 2 ] = x + 1 + ( ( y + 1 ) * mesh->width );
+ pw[ 3 ] = x + 1 + ( y * mesh->width );
+ pw[ 4 ] = x + ( y * mesh->width ); /* same as pw[ 0 ] */
+
/* set radix */
- r = (x + y) & 1;
-
+ r = ( x + y ) & 1;
+
/* get drawverts */
dv[ 0 ] = &mesh->verts[ pw[ r + 0 ] ];
dv[ 1 ] = &mesh->verts[ pw[ r + 1 ] ];
dv[ 2 ] = &mesh->verts[ pw[ r + 2 ] ];
dv[ 3 ] = &mesh->verts[ pw[ r + 3 ] ];
-
+
/* planar? */
planar = PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz );
- if( planar )
- {
+ if ( planar ) {
dist = DotProduct( dv[ 1 ]->xyz, plane ) - plane[ 3 ];
- if( fabs( dist ) > PLANAR_EPSILON )
+ if ( fabs( dist ) > PLANAR_EPSILON ) {
planar = qfalse;
+ }
}
-
+
/* generate a quad */
- if( planar )
- {
+ if ( planar ) {
rw.numVerts = 4;
- for( v = 0; v < 4; v++ )
+ for ( v = 0; v < 4; v++ )
{
/* get most everything */
memcpy( &rw.verts[ v ], dv[ v ], sizeof( bspDrawVert_t ) );
-
+
/* fix colors */
- for( i = 0; i < MAX_LIGHTMAPS; i++ )
+ for ( i = 0; i < MAX_LIGHTMAPS; i++ )
{
radVertexLuxel = RAD_VERTEX_LUXEL( i, ds->firstVert + dv[ v ]->color[ 0 ][ 0 ] );
VectorCopy( radVertexLuxel, rw.verts[ v ].color[ i ] );
rw.verts[ v ].color[ i ][ 3 ] = dv[ v ]->color[ i ][ 3 ];
}
}
-
+
/* subdivide into area lights */
RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw );
}
-
+
/* generate 2 tris */
else
{
rw.numVerts = 3;
- for( t = 0; t < 2; t++ )
+ for ( t = 0; t < 2; t++ )
{
- for( v = 0; v < 3 + t; v++ )
+ for ( v = 0; v < 3 + t; v++ )
{
/* get "other" triangle (stupid hacky logic, but whatevah) */
- if( v == 1 && t == 1 )
+ if ( v == 1 && t == 1 ) {
v++;
+ }
/* get most everything */
memcpy( &rw.verts[ v ], dv[ v ], sizeof( bspDrawVert_t ) );
-
+
/* fix colors */
- for( i = 0; i < MAX_LIGHTMAPS; i++ )
+ for ( i = 0; i < MAX_LIGHTMAPS; i++ )
{
radVertexLuxel = RAD_VERTEX_LUXEL( i, ds->firstVert + dv[ v ]->color[ 0 ][ 0 ] );
VectorCopy( radVertexLuxel, rw.verts[ v ].color[ i ] );
rw.verts[ v ].color[ i ][ 3 ] = dv[ v ]->color[ i ][ 3 ];
}
}
-
+
/* subdivide into area lights */
RadSubdivideDiffuseLight( lightmapNum, ds, lm, si, scale, subdivide, qtrue, &rw, cw );
}
}
}
}
-
+
/* free the mesh */
FreeMesh( mesh );
}
/*
-RadLight()
-creates unbounced diffuse lights for a given surface
-*/
+ RadLight()
+ creates unbounced diffuse lights for a given surface
+ */
+
+void RadLight( int num ){
+ int lightmapNum;
+ float scale, subdivide;
+ int contentFlags, surfaceFlags, compileFlags;
+ bspDrawSurface_t *ds;
+ surfaceInfo_t *info;
+ rawLightmap_t *lm;
+ shaderInfo_t *si;
+ clipWork_t cw;
+
-void RadLight( int num )
-{
- int lightmapNum;
- float scale, subdivide;
- int contentFlags, surfaceFlags, compileFlags;
- bspDrawSurface_t *ds;
- surfaceInfo_t *info;
- rawLightmap_t *lm;
- shaderInfo_t *si;
- clipWork_t cw;
-
-
/* get drawsurface, lightmap, and shader info */
ds = &bspDrawSurfaces[ num ];
info = &surfaceInfos[ num ];
lm = info->lm;
si = info->si;
scale = si->bounceScale;
-
+
/* find nodraw bit */
contentFlags = surfaceFlags = compileFlags = 0;
ApplySurfaceParm( "nodraw", &contentFlags, &surfaceFlags, &compileFlags );
// jal : avoid bouncing on trans surfaces
ApplySurfaceParm( "trans", &contentFlags, &surfaceFlags, &compileFlags );
-
+
/* early outs? */
- if( scale <= 0.0f || (si->compileFlags & C_SKY) || si->autosprite ||
- (bspShaders[ ds->shaderNum ].contentFlags & contentFlags) || (bspShaders[ ds->shaderNum ].surfaceFlags & surfaceFlags) ||
- (si->compileFlags & compileFlags) )
+ if ( scale <= 0.0f || ( si->compileFlags & C_SKY ) || si->autosprite ||
+ ( bspShaders[ ds->shaderNum ].contentFlags & contentFlags ) || ( bspShaders[ ds->shaderNum ].surfaceFlags & surfaceFlags ) ||
+ ( si->compileFlags & compileFlags ) ) {
return;
-
+ }
+
/* determine how much we need to chop up the surface */
- if( si->lightSubdivide )
+ if ( si->lightSubdivide ) {
subdivide = si->lightSubdivide;
- else
+ }
+ else{
subdivide = diffuseSubdivide;
-
+ }
+
/* inc counts */
numDiffuseSurfaces++;
-
+
/* iterate through styles (this could be more efficient, yes) */
- for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
+ for ( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
{
/* switch on type */
- if( ds->lightmapStyles[ lightmapNum ] != LS_NONE && ds->lightmapStyles[ lightmapNum ] != LS_UNUSED )
- {
- switch( ds->surfaceType )
+ if ( ds->lightmapStyles[ lightmapNum ] != LS_NONE && ds->lightmapStyles[ lightmapNum ] != LS_UNUSED ) {
+ switch ( ds->surfaceType )
{
- case MST_PLANAR:
- case MST_TRIANGLE_SOUP:
- RadLightForTriangles( num, lightmapNum, lm, si, scale, subdivide, &cw );
- break;
-
- case MST_PATCH:
- RadLightForPatch( num, lightmapNum, lm, si, scale, subdivide, &cw );
- break;
-
- default:
- break;
+ case MST_PLANAR:
+ case MST_TRIANGLE_SOUP:
+ RadLightForTriangles( num, lightmapNum, lm, si, scale, subdivide, &cw );
+ break;
+
+ case MST_PATCH:
+ RadLightForPatch( num, lightmapNum, lm, si, scale, subdivide, &cw );
+ break;
+
+ default:
+ break;
}
}
}
/*
-RadCreateDiffuseLights()
-creates lights for unbounced light on surfaces in the bsp
-*/
+ RadCreateDiffuseLights()
+ creates lights for unbounced light on surfaces in the bsp
+ */
-int iterations = 0;
+int iterations = 0;
-void RadCreateDiffuseLights( void )
-{
+void RadCreateDiffuseLights( void ){
/* startup */
Sys_FPrintf( SYS_VRB, "--- RadCreateDiffuseLights ---\n" );
numDiffuseSurfaces = 0;
numTriangleDiffuseLights = 0;
numPatchDiffuseLights = 0;
numAreaLights = 0;
-
+
/* hit every surface (threaded) */
RunThreadsOnIndividual( numBSPDrawSurfaces, qtrue, RadLight );
-
+
/* dump the lights generated to a file */
- if( dump )
- {
- char dumpName[ 1024 ], ext[ 64 ];
- FILE *file;
- light_t *light;
-
+ if ( dump ) {
+ char dumpName[ 1024 ], ext[ 64 ];
+ FILE *file;
+ light_t *light;
+
strcpy( dumpName, source );
StripExtension( dumpName );
sprintf( ext, "_bounce_%03d.map", iterations );
strcat( dumpName, ext );
file = fopen( dumpName, "wb" );
Sys_Printf( "Writing %s...\n", dumpName );
- if( file )
- {
- for( light = lights; light; light = light->next )
+ if ( file ) {
+ for ( light = lights; light; light = light->next )
{
fprintf( file,
- "{\n"
- "\"classname\" \"light\"\n"
- "\"light\" \"%d\"\n"
- "\"origin\" \"%.0f %.0f %.0f\"\n"
- "\"_color\" \"%.3f %.3f %.3f\"\n"
- "}\n",
-
- (int) light->add,
-
- light->origin[ 0 ],
- light->origin[ 1 ],
- light->origin[ 2 ],
-
- light->color[ 0 ],
- light->color[ 1 ],
- light->color[ 2 ] );
+ "{\n"
+ "\"classname\" \"light\"\n"
+ "\"light\" \"%d\"\n"
+ "\"origin\" \"%.0f %.0f %.0f\"\n"
+ "\"_color\" \"%.3f %.3f %.3f\"\n"
+ "}\n",
+
+ (int) light->add,
+
+ light->origin[ 0 ],
+ light->origin[ 1 ],
+ light->origin[ 2 ],
+
+ light->color[ 0 ],
+ light->color[ 1 ],
+ light->color[ 2 ] );
}
fclose( file );
}
}
-
+
/* increment */
iterations++;
-
+
/* print counts */
Sys_Printf( "%8d diffuse surfaces\n", numDiffuseSurfaces );
Sys_FPrintf( SYS_VRB, "%8d total diffuse lights\n", numDiffuseLights );
Sys_FPrintf( SYS_VRB, "%8d patch diffuse lights\n", numPatchDiffuseLights );
Sys_FPrintf( SYS_VRB, "%8d triangle diffuse lights\n", numTriangleDiffuseLights );
}
-
-
-
-
-
-