X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fnetradiant.git;a=blobdiff_plain;f=tools%2Fquake3%2Fq3map2%2Flight_ydnar.c;h=b01084dff1c598fa7e80e6cfb9af115f3d01a627;hp=d8f0c730fa270938e7c54d645c2c6ba09c52bbe5;hb=e8f27310d6e17f99f55b4fc9184f5115c90e3ec7;hpb=2fbe76a4a5421a90082d1dbb9941edda6253b817 diff --git a/tools/quake3/q3map2/light_ydnar.c b/tools/quake3/q3map2/light_ydnar.c index d8f0c730..b01084df 100644 --- a/tools/quake3/q3map2/light_ydnar.c +++ b/tools/quake3/q3map2/light_ydnar.c @@ -120,6 +120,14 @@ void ColorToBytes( const float *color, byte *colorBytes, float scale ) /* compensate for ingame overbrighting/bitshifting */ VectorScale( sample, (1.0f / lightmapCompensate), sample ); + + /* sRGB lightmaps */ + if(lightmapsRGB) + { + sample[0] = floor(Image_sRGBFloatFromLinearFloat(sample[0] * (1.0 / 255.0)) * 255.0 + 0.5); + sample[1] = floor(Image_sRGBFloatFromLinearFloat(sample[1] * (1.0 / 255.0)) * 255.0 + 0.5); + sample[2] = floor(Image_sRGBFloatFromLinearFloat(sample[2] * (1.0 / 255.0)) * 255.0 + 0.5); + } /* store it off */ colorBytes[ 0 ] = sample[ 0 ]; @@ -533,7 +541,7 @@ static int MapSingleLuxel( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t //1) Test the sample origin to see if it lays on the wrong side of any edge (x/y) //2) if it does, nudge it onto the correct side. - if (worldverts!=NULL) + if (worldverts!=NULL && lightmapTriangleCheck) { for (j=0;j<3;j++) { @@ -604,9 +612,12 @@ static int MapSingleLuxel( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t origin[ lm->axisNum ] += lightmapSampleOffset; VectorCopy(origin,origintwo); - origintwo[0]+=vecs[2][0]; - origintwo[1]+=vecs[2][1]; - origintwo[2]+=vecs[2][2]; + if(lightmapExtraVisClusterNudge) + { + origintwo[0]+=vecs[2][0]; + origintwo[1]+=vecs[2][1]; + origintwo[2]+=vecs[2][2]; + } /* get cluster */ pointCluster = ClusterForPointExtFilter( origintwo, LUXEL_EPSILON, numClusters, clusters ); @@ -631,8 +642,8 @@ static int MapSingleLuxel( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t /* get pvs cluster */ pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); //% + 0.625 ); - //if( pointCluster >= 0 ) - // VectorCopy( nudged, origin ); + if( pointCluster >= 0 ) + VectorCopy( nudged, origin ); luxel[ 1 ] += 1.0f; } } @@ -642,8 +653,8 @@ static int MapSingleLuxel( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t { VectorMA( dv->xyz, lightmapSampleOffset, dv->normal, nudged ); pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); - //if( pointCluster >= 0 ) - // VectorCopy( nudged, origin ); + if( pointCluster >= 0 ) + VectorCopy( nudged, origin ); luxel[ 1 ] += 1.0f; } @@ -1151,13 +1162,18 @@ void MapRawLightmap( int rawLightmapNum ) if( MapQuad( lm, info, dv ) ) continue; - /* get drawverts and map first triangle */ - MapTriangle( lm, info, dv, mapNonAxial ); - - /* get drawverts and map second triangle */ - dv[ 1 ] = &verts[ pw[ r + 2 ] ]; - dv[ 2 ] = &verts[ pw[ r + 3 ] ]; - MapTriangle( lm, info, dv, mapNonAxial ); + for( mapNonAxial = 0; mapNonAxial < 2; mapNonAxial++ ) + { + /* get drawverts and map first triangle */ + dv[ 1 ] = &verts[ pw[ r + 1 ] ]; + dv[ 2 ] = &verts[ pw[ r + 2 ] ]; + MapTriangle( lm, info, dv, mapNonAxial ); + + /* get drawverts and map second triangle */ + dv[ 1 ] = &verts[ pw[ r + 2 ] ]; + dv[ 2 ] = &verts[ pw[ r + 3 ] ]; + MapTriangle( lm, info, dv, mapNonAxial ); + } } } @@ -1422,7 +1438,7 @@ float DirtForSample( trace_t *trace ) VectorCopy( trace->normal, normal ); /* check if the normal is aligned to the world-up */ - if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f ) + if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f && ( normal[ 2 ] == 1.0f || normal[ 2 ] == -1.0f ) ) { if( normal[ 2 ] == 1.0f ) { @@ -1468,7 +1484,7 @@ float DirtForSample( trace_t *trace ) /* trace */ TraceLine( trace ); - if( trace->opaque ) + if( trace->opaque && !(trace->compileFlags & C_SKY) ) { VectorSubtract( trace->hit, trace->origin, displacement ); gatherDirt += 1.0f - ooDepth * VectorLength( displacement ); @@ -1543,7 +1559,8 @@ void DirtyRawLightmap( int rawLightmapNum ) rawLightmap_t *lm; surfaceInfo_t *info; trace_t trace; - + qboolean noDirty; + /* bail if this number exceeds the number of raw lightmaps */ if( rawLightmapNum >= numRawLightmaps ) @@ -1558,7 +1575,7 @@ void DirtyRawLightmap( int rawLightmapNum ) trace.recvShadows = lm->recvShadows; trace.numSurfaces = lm->numLightSurfaces; trace.surfaces = &lightSurfaces[ lm->firstLightSurface ]; - trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS; + trace.inhibitRadius = 0.0f; trace.testAll = qfalse; /* twosided lighting (may or may not be a good idea for lightmapped stuff) */ @@ -1575,6 +1592,20 @@ void DirtyRawLightmap( int rawLightmapNum ) break; } } + + noDirty = qfalse; + for( i = 0; i < trace.numSurfaces; i++ ) + { + /* get surface */ + info = &surfaceInfos[ trace.surfaces[ i ] ]; + + /* check twosidedness */ + if( info->si->noDirty ) + { + noDirty = qtrue; + break; + } + } /* gather dirt */ for( y = 0; y < lm->sh; y++ ) @@ -1593,6 +1624,13 @@ void DirtyRawLightmap( int rawLightmapNum ) /* only look at mapped luxels */ if( *cluster < 0 ) continue; + + /* don't apply dirty on this surface */ + if( noDirty ) + { + *dirt = 1.0f; + continue; + } /* copy to trace */ trace.cluster = *cluster; @@ -1689,7 +1727,9 @@ static qboolean SubmapRawLuxel( rawLightmap_t *lm, int x, int y, float bx, float //% normal2 = SUPER_NORMAL( x, y ); } else - Sys_Printf( "WARNING: Spurious lightmap S vector\n" ); + { + Error( "Spurious lightmap S vector\n" ); + } VectorSubtract( origin2, origin, originVecs[ 0 ] ); //% VectorSubtract( normal2, normal, normalVecs[ 0 ] ); @@ -1748,14 +1788,15 @@ SubsampleRawLuxel_r() recursively subsamples a luxel until its color gradient is low enough or subsampling limit is reached */ -static void SubsampleRawLuxel_r( rawLightmap_t *lm, trace_t *trace, vec3_t sampleOrigin, int x, int y, float bias, float *lightLuxel ) +static void SubsampleRawLuxel_r( rawLightmap_t *lm, trace_t *trace, vec3_t sampleOrigin, int x, int y, float bias, float *lightLuxel, float *lightDeluxel ) { int b, samples, mapped, lighted; int cluster[ 4 ]; vec4_t luxel[ 4 ]; + vec3_t deluxel[ 3 ]; vec3_t origin[ 4 ], normal[ 4 ]; float biasDirs[ 4 ][ 2 ] = { { -1.0f, -1.0f }, { 1.0f, -1.0f }, { -1.0f, 1.0f }, { 1.0f, 1.0f } }; - vec3_t color, total; + vec3_t color, direction = { 0, 0, 0 }, total; /* limit check */ @@ -1792,9 +1833,20 @@ static void SubsampleRawLuxel_r( rawLightmap_t *lm, trace_t *trace, vec3_t sampl /* sample light */ LightContributionToSample( trace ); + if(trace->forceSubsampling > 1.0f) + { + /* alphashadow: we subsample as deep as we can */ + ++lighted; + ++mapped; + ++mapped; + } /* add to totals (fixme: make contrast function) */ VectorCopy( trace->color, luxel[ b ] ); + if(lightDeluxel) + { + VectorCopy( trace->directionContribution, deluxel[ b ] ); + } VectorAdd( total, trace->color, total ); if( (luxel[ b ][ 0 ] + luxel[ b ][ 1 ] + luxel[ b ][ 2 ]) > 0.0f ) lighted++; @@ -1809,7 +1861,7 @@ static void SubsampleRawLuxel_r( rawLightmap_t *lm, trace_t *trace, vec3_t sampl { if( cluster[ b ] < 0 ) continue; - SubsampleRawLuxel_r( lm, trace, origin[ b ], x, y, (bias * 0.25f), luxel[ b ] ); + SubsampleRawLuxel_r( lm, trace, origin[ b ], x, y, (bias * 0.5f), luxel[ b ], lightDeluxel ? deluxel[ b ] : NULL ); } } @@ -1817,12 +1869,20 @@ static void SubsampleRawLuxel_r( rawLightmap_t *lm, trace_t *trace, vec3_t sampl //% VectorClear( color ); //% samples = 0; VectorCopy( lightLuxel, color ); + if(lightDeluxel) + { + VectorCopy( lightDeluxel, direction ); + } samples = 1; for( b = 0; b < 4; b++ ) { if( cluster[ b ] < 0 ) continue; VectorAdd( color, luxel[ b ], color ); + if(lightDeluxel) + { + VectorAdd( direction, deluxel[ b ], direction ); + } samples++; } @@ -1833,10 +1893,85 @@ static void SubsampleRawLuxel_r( rawLightmap_t *lm, trace_t *trace, vec3_t sampl color[ 0 ] /= samples; color[ 1 ] /= samples; color[ 2 ] /= samples; - + /* add to color */ VectorCopy( color, lightLuxel ); lightLuxel[ 3 ] += 1.0f; + + if(lightDeluxel) + { + direction[ 0 ] /= samples; + direction[ 1 ] /= samples; + direction[ 2 ] /= samples; + VectorCopy( direction, lightDeluxel ); + } + } +} + +/* A mostly Gaussian-like bounded random distribution (sigma is expected standard deviation) */ +static void GaussLikeRandom(float sigma, float *x, float *y) +{ + float r; + r = Random() * 2 * Q_PI; + *x = sigma * 2.73861278752581783822 * cos(r); + *y = sigma * 2.73861278752581783822 * sin(r); + r = Random(); + r = 1 - sqrt(r); + r = 1 - sqrt(r); + *x *= r; + *y *= r; +} +static void RandomSubsampleRawLuxel( rawLightmap_t *lm, trace_t *trace, vec3_t sampleOrigin, int x, int y, float bias, float *lightLuxel, float *lightDeluxel ) +{ + int b, mapped; + int cluster; + vec3_t origin, normal; + vec3_t total, totaldirection; + float dx, dy; + + VectorClear( total ); + VectorClear( totaldirection ); + mapped = 0; + for(b = 0; b < lightSamples; ++b) + { + /* set origin */ + VectorCopy( sampleOrigin, origin ); + GaussLikeRandom(bias, &dx, &dy); + + /* calculate position */ + if( !SubmapRawLuxel( lm, x, y, dx, dy, &cluster, origin, normal ) ) + { + cluster = -1; + continue; + } + mapped++; + + trace->cluster = cluster; + VectorCopy( origin, trace->origin ); + VectorCopy( normal, trace->normal ); + + LightContributionToSample( trace ); + VectorAdd( total, trace->color, total ); + if(lightDeluxel) + { + VectorAdd( totaldirection, trace->directionContribution, totaldirection ); + } + } + + /* add to luxel */ + if( mapped > 0 ) + { + /* average */ + lightLuxel[ 0 ] = total[ 0 ] / mapped; + lightLuxel[ 1 ] = total[ 1 ] / mapped; + lightLuxel[ 2 ] = total[ 2 ] / mapped; + + if(lightDeluxel) + { + lightDeluxel[ 0 ] = totaldirection[ 0 ] / mapped; + lightDeluxel[ 1 ] = totaldirection[ 1 ] / mapped; + lightDeluxel[ 2 ] = totaldirection[ 2 ] / mapped; + } } } @@ -1849,23 +1984,24 @@ illuminates the luxels #define STACK_LL_SIZE (SUPER_LUXEL_SIZE * 64 * 64) #define LIGHT_LUXEL( x, y ) (lightLuxels + ((((y) * lm->sw) + (x)) * SUPER_LUXEL_SIZE)) +#define LIGHT_DELUXEL( x, y ) (lightDeluxels + ((((y) * lm->sw) + (x)) * SUPER_DELUXEL_SIZE)) void IlluminateRawLightmap( int rawLightmapNum ) { - int i, t, x, y, sx, sy, size, llSize, luxelFilterRadius, lightmapNum; + int i, t, x, y, sx, sy, size, luxelFilterRadius, lightmapNum; int *cluster, *cluster2, mapped, lighted, totalLighted; + size_t llSize, ldSize; rawLightmap_t *lm; surfaceInfo_t *info; qboolean filterColor, filterDir; float brightness; float *origin, *normal, *dirt, *luxel, *luxel2, *deluxel, *deluxel2; - float *lightLuxels, *lightLuxel, samples, filterRadius, weight; - vec3_t color, averageColor, averageDir, total, temp, temp2; + unsigned char *flag; + float *lightLuxels, *lightDeluxels, *lightLuxel, *lightDeluxel, samples, filterRadius, weight; + vec3_t color, direction, averageColor, averageDir, total, temp, temp2; float tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } }; trace_t trace; float stackLightLuxels[ STACK_LL_SIZE ]; - vec3_t flood; - float *floodlight; /* bail if this number exceeds the number of raw lightmaps */ @@ -1976,10 +2112,15 @@ void IlluminateRawLightmap( int rawLightmapNum ) { /* allocate temporary per-light luxel storage */ llSize = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( float ); + ldSize = lm->sw * lm->sh * SUPER_DELUXEL_SIZE * sizeof( float ); if( llSize <= (STACK_LL_SIZE * sizeof( float )) ) lightLuxels = stackLightLuxels; else lightLuxels = safe_malloc( llSize ); + if(deluxemap) + lightDeluxels = safe_malloc( ldSize ); + else + lightDeluxels = NULL; /* clear luxels */ //% memset( lm->superLuxels[ 0 ], 0, llSize ); @@ -2004,7 +2145,15 @@ void IlluminateRawLightmap( int rawLightmapNum ) { VectorCopy( ambientColor, luxel ); if( deluxemap ) - VectorScale( normal, 0.00390625f, deluxel ); + { + brightness = RGBTOGRAY( ambientColor ) * ( 1.0f/255.0f ); + + // use AT LEAST this amount of contribution from ambient for the deluxemap, fixes points that receive ZERO light + if(brightness < 0.00390625f) + brightness = 0.00390625f; + + VectorScale( normal, brightness, deluxel ); + } luxel[ 3 ] = 1.0f; } } @@ -2045,8 +2194,31 @@ void IlluminateRawLightmap( int rawLightmapNum ) /* setup */ memset( lightLuxels, 0, llSize ); + if(deluxemap) + memset( lightDeluxels, 0, ldSize ); totalLighted = 0; + /* determine filter radius */ + filterRadius = lm->filterRadius > trace.light->filterRadius + ? lm->filterRadius + : trace.light->filterRadius; + if( filterRadius < 0.0f ) + filterRadius = 0.0f; + + /* set luxel filter radius */ + luxelFilterRadius = superSample * filterRadius / lm->sampleSize; + if( luxelFilterRadius == 0 && (filterRadius > 0.0f || filter) ) + luxelFilterRadius = 1; + + /* allocate sampling flags storage */ + if((lightSamples > 1 || lightRandomSamples) && luxelFilterRadius == 0) + { + size = lm->sw * lm->sh * SUPER_LUXEL_SIZE * sizeof( unsigned char ); + if(lm->superFlags == NULL) + lm->superFlags = safe_malloc( size ); + memset( (void *) lm->superFlags, 0, size ); + } + /* initial pass, one sample per luxel */ for( y = 0; y < lm->sh; y++ ) { @@ -2059,9 +2231,10 @@ void IlluminateRawLightmap( int rawLightmapNum ) /* get particulars */ lightLuxel = LIGHT_LUXEL( x, y ); - deluxel = SUPER_DELUXEL( x, y ); + lightDeluxel = LIGHT_DELUXEL( x, y ); origin = SUPER_ORIGIN( x, y ); normal = SUPER_NORMAL( x, y ); + flag = SUPER_FLAG( x, y ); #if 0 ////////// 27's temp hack for testing edge clipping //// @@ -2086,20 +2259,22 @@ void IlluminateRawLightmap( int rawLightmapNum ) LightContributionToSample( &trace ); VectorCopy( trace.color, lightLuxel ); + /* add the contribution to the deluxemap */ + if( deluxemap ) + { + VectorCopy( trace.directionContribution, lightDeluxel ); + } + + /* check for evilness */ + if(trace.forceSubsampling > 1.0f && (lightSamples > 1 || lightRandomSamples) && luxelFilterRadius == 0) + { + totalLighted++; + *flag |= FLAG_FORCE_SUBSAMPLING; /* force */ + } /* add to count */ - if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] ) + else if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] ) totalLighted++; } - - /* add to light direction map (fixme: use luxel normal as starting point for deluxel?) */ - if( deluxemap ) - { - /* color to grayscale (photoshop rgb weighting) */ - brightness = trace.color[ 0 ] * 0.3f + trace.color[ 1 ] * 0.59f + trace.color[ 2 ] * 0.11f; - brightness *= (1.0 / 255.0); - VectorScale( trace.direction, brightness, trace.direction ); - VectorAdd( deluxel, trace.direction, deluxel ); - } } } @@ -2107,21 +2282,9 @@ void IlluminateRawLightmap( int rawLightmapNum ) if( totalLighted == 0 ) continue; - /* determine filter radius */ - filterRadius = lm->filterRadius > trace.light->filterRadius - ? lm->filterRadius - : trace.light->filterRadius; - if( filterRadius < 0.0f ) - filterRadius = 0.0f; - - /* set luxel filter radius */ - luxelFilterRadius = superSample * filterRadius / lm->sampleSize; - if( luxelFilterRadius == 0 && (filterRadius > 0.0f || filter) ) - luxelFilterRadius = 1; - /* secondary pass, adaptive supersampling (fixme: use a contrast function to determine if subsampling is necessary) */ /* 2003-09-27: changed it so filtering disamples supersampling, as it would waste time */ - if( lightSamples > 1 && luxelFilterRadius == 0 ) + if( (lightSamples > 1 || lightRandomSamples) && luxelFilterRadius == 0 ) { /* walk luxels */ for( y = 0; y < (lm->sh - 1); y++ ) @@ -2147,6 +2310,14 @@ void IlluminateRawLightmap( int rawLightmapNum ) mapped++; /* get luxel */ + flag = SUPER_FLAG( sx, sy ); + if(*flag & FLAG_FORCE_SUBSAMPLING) + { + /* force a lighted/mapped discrepancy so we subsample */ + ++lighted; + ++mapped; + ++mapped; + } lightLuxel = LIGHT_LUXEL( sx, sy ); VectorAdd( total, lightLuxel, total ); if( (lightLuxel[ 0 ] + lightLuxel[ 1 ] + lightLuxel[ 2 ]) > 0.0f ) @@ -2170,7 +2341,11 @@ void IlluminateRawLightmap( int rawLightmapNum ) cluster = SUPER_CLUSTER( sx, sy ); if( *cluster < 0 ) continue; + flag = SUPER_FLAG( sx, sy ); + if(*flag & FLAG_ALREADY_SUBSAMPLED) // already subsampled + continue; lightLuxel = LIGHT_LUXEL( sx, sy ); + lightDeluxel = LIGHT_DELUXEL( sx, sy ); origin = SUPER_ORIGIN( sx, sy ); /* only subsample shadowed luxels */ @@ -2178,7 +2353,12 @@ void IlluminateRawLightmap( int rawLightmapNum ) //% continue; /* subsample it */ - SubsampleRawLuxel_r( lm, &trace, origin, sx, sy, 0.25f, lightLuxel ); + if(lightRandomSamples) + RandomSubsampleRawLuxel( lm, &trace, origin, sx, sy, 0.5f * lightSamplesSearchBoxSize, lightLuxel, deluxemap ? lightDeluxel : NULL ); + else + SubsampleRawLuxel_r( lm, &trace, origin, sx, sy, 0.25f * lightSamplesSearchBoxSize, lightLuxel, deluxemap ? lightDeluxel : NULL ); + + *flag |= FLAG_ALREADY_SUBSAMPLED; /* debug code to colorize subsampled areas to yellow */ //% luxel = SUPER_LUXEL( lightmapNum, sx, sy ); @@ -2220,7 +2400,7 @@ void IlluminateRawLightmap( int rawLightmapNum ) lm->superLuxels[ lightmapNum ] = safe_malloc( size ); memset( lm->superLuxels[ lightmapNum ], 0, size ); } - + /* set style */ if( lightmapNum > 0 ) { @@ -2244,6 +2424,7 @@ void IlluminateRawLightmap( int rawLightmapNum ) { /* setup */ VectorClear( averageColor ); + VectorClear( averageDir ); samples = 0.0f; /* cheaper distance-based filtering */ @@ -2262,6 +2443,7 @@ void IlluminateRawLightmap( int rawLightmapNum ) if( *cluster < 0 ) continue; lightLuxel = LIGHT_LUXEL( sx, sy ); + lightDeluxel = LIGHT_DELUXEL( sx, sy ); /* create weight */ weight = (abs( sx - x ) == luxelFilterRadius ? 0.5f : 1.0f); @@ -2270,6 +2452,11 @@ void IlluminateRawLightmap( int rawLightmapNum ) /* scale luxel by filter weight */ VectorScale( lightLuxel, weight, color ); VectorAdd( averageColor, color, averageColor ); + if(deluxemap) + { + VectorScale( lightDeluxel, weight, direction ); + VectorAdd( averageDir, direction, averageDir ); + } samples += weight; } } @@ -2297,6 +2484,15 @@ void IlluminateRawLightmap( int rawLightmapNum ) luxel[ 1 ] += averageColor[ 1 ] / samples; luxel[ 2 ] += averageColor[ 2 ] / samples; } + + if(deluxemap) + { + /* scale into luxel */ + deluxel = SUPER_DELUXEL( x, y ); + deluxel[ 0 ] += averageDir[ 0 ] / samples; + deluxel[ 1 ] += averageDir[ 1 ] / samples; + deluxel[ 2 ] += averageDir[ 2 ] / samples; + } } /* single sample */ @@ -2304,7 +2500,9 @@ void IlluminateRawLightmap( int rawLightmapNum ) { /* get particulars */ lightLuxel = LIGHT_LUXEL( x, y ); + lightDeluxel = LIGHT_DELUXEL( x, y ); luxel = SUPER_LUXEL( lightmapNum, x, y ); + deluxel = SUPER_DELUXEL( x, y ); /* handle negative light */ if( trace.light->flags & LIGHT_NEGATIVE ) @@ -2320,6 +2518,11 @@ void IlluminateRawLightmap( int rawLightmapNum ) /* handle normal light */ else VectorAdd( luxel, lightLuxel, luxel ); + + if(deluxemap) + { + VectorAdd( deluxel, lightDeluxel, deluxel ); + } } } } @@ -2328,53 +2531,17 @@ void IlluminateRawLightmap( int rawLightmapNum ) /* free temporary luxels */ if( lightLuxels != stackLightLuxels ) free( lightLuxels ); + + if(deluxemap) + free( lightDeluxels ); } /* free light list */ FreeTraceLights( &trace ); - /* ----------------------------------------------------------------- - floodlight pass - ----------------------------------------------------------------- */ - + /* floodlight pass */ if( floodlighty ) - { - /* walk lightmaps */ - for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) - { - /* early out */ - if( lm->superLuxels[ lightmapNum ] == NULL ) - continue; - - /* apply floodlight to each luxel */ - for( y = 0; y < lm->sh; y++ ) - { - for( x = 0; x < lm->sw; x++ ) - { - /* get cluster */ - cluster = SUPER_CLUSTER( x, y ); - //% if( *cluster < 0 ) - //% continue; - - /* get particulars */ - luxel = SUPER_LUXEL( lightmapNum, x, y ); - floodlight = SUPER_FLOODLIGHT( x, y ); - - flood[0]=floodlightRGB[0]*floodlightIntensity; - flood[1]=floodlightRGB[1]*floodlightIntensity; - flood[2]=floodlightRGB[2]*floodlightIntensity; - - /* scale light value */ - VectorScale( flood, *floodlight, flood ); - luxel[0]+=flood[0]; - luxel[1]+=flood[1]; - luxel[2]+=flood[2]; - - if (luxel[3]==0) luxel[3]=1; - } - } - } - } + FloodlightIlluminateLightmap(lm); if (debugnormals) { @@ -2383,7 +2550,7 @@ void IlluminateRawLightmap( int rawLightmapNum ) /* early out */ if( lm->superLuxels[ lightmapNum ] == NULL ) continue; - + for( y = 0; y < lm->sh; y++ ) { for( x = 0; x < lm->sw; x++ ) @@ -2392,11 +2559,11 @@ void IlluminateRawLightmap( int rawLightmapNum ) cluster = SUPER_CLUSTER( x, y ); //% if( *cluster < 0 ) //% continue; - + /* get particulars */ luxel = SUPER_LUXEL( lightmapNum, x, y ); normal = SUPER_NORMAL ( x, y ); - + luxel[0]=(normal[0]*127)+127; luxel[1]=(normal[1]*127)+127; luxel[2]=(normal[2]*127)+127; @@ -2404,7 +2571,7 @@ void IlluminateRawLightmap( int rawLightmapNum ) } } } - + /* ----------------------------------------------------------------- dirt pass ----------------------------------------------------------------- */ @@ -2425,7 +2592,7 @@ void IlluminateRawLightmap( int rawLightmapNum ) { /* get cluster */ cluster = SUPER_CLUSTER( x, y ); - //% if( *cluster < 0 ) + //% if( *cluster < 0 ) // TODO why not do this check? These pixels should be zero anyway //% continue; /* get particulars */ @@ -2471,6 +2638,7 @@ void IlluminateRawLightmap( int rawLightmapNum ) if( *cluster < 0 || (lm->splotchFix && (luxel[ 0 ] <= ambientColor[ 0 ] || luxel[ 1 ] <= ambientColor[ 1 ] || luxel[ 2 ] <= ambientColor[ 2 ])) ) filterColor = qtrue; + if( deluxemap && lightmapNum == 0 && (*cluster < 0 || filter) ) filterDir = qtrue; @@ -2538,6 +2706,44 @@ void IlluminateRawLightmap( int rawLightmapNum ) } } } + + +#if 0 + // audit pass + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + /* early out */ + if( lm->superLuxels[ lightmapNum ] == NULL ) + continue; + for( y = 0; y < lm->sh; y++ ) + for( x = 0; x < lm->sw; x++ ) + { + /* get cluster */ + cluster = SUPER_CLUSTER( x, y ); + luxel = SUPER_LUXEL( lightmapNum, x, y ); + deluxel = SUPER_DELUXEL( x, y ); + if(!luxel || !deluxel || !cluster) + { + Sys_FPrintf(SYS_VRB, "WARNING: I got NULL'd.\n"); + continue; + } + else if(*cluster < 0) + { + // unmapped pixel + // should have neither deluxemap nor lightmap + if(deluxel[3]) + Sys_FPrintf(SYS_VRB, "WARNING: I have written deluxe to an unmapped luxel. Sorry.\n"); + } + else + { + // mapped pixel + // should have both deluxemap and lightmap + if(deluxel[3]) + Sys_FPrintf(SYS_VRB, "WARNING: I forgot to write deluxe to a mapped luxel. Sorry.\n"); + } + } + } +#endif } @@ -2560,6 +2766,8 @@ void IlluminateVertexes( int num ) rawLightmap_t *lm; bspDrawVert_t *verts; trace_t trace; + float floodLightAmount; + vec3_t floodColor; /* get surface, info, and raw lightmap */ @@ -2637,11 +2845,20 @@ void IlluminateVertexes( int num ) VectorCopy( verts[ i ].normal, trace.normal ); /* r7 dirt */ - if( dirty ) + if( dirty && !bouncing ) dirt = DirtForSample( &trace ); else dirt = 1.0f; + /* jal: floodlight */ + floodLightAmount = 0.0f; + VectorClear( floodColor ); + if( floodlighty && !bouncing ) + { + floodLightAmount = floodlightIntensity * FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality ); + VectorScale( floodlightRGB, floodLightAmount, floodColor ); + } + /* trace */ LightingAtSample( &trace, ds->vertexStyles, colors ); @@ -2650,6 +2867,9 @@ void IlluminateVertexes( int num ) { /* r7 dirt */ VectorScale( colors[ lightmapNum ], dirt, colors[ lightmapNum ] ); + + /* jal: floodlight */ + VectorAdd( colors[ lightmapNum ], floodColor, colors[ lightmapNum ] ); /* store */ radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i ); @@ -2665,16 +2885,16 @@ void IlluminateVertexes( int num ) radVertLuxel[ 2 ] <= ambientColor[ 2 ] ) { /* nudge the sample point around a bit */ - for( x = 0; x < 4; x++ ) + for( x = 0; x < 5; x++ ) { /* two's complement 0, 1, -1, 2, -2, etc */ x1 = ((x >> 1) ^ (x & 1 ? -1 : 0)) + (x & 1); - for( y = 0; y < 4; y++ ) + for( y = 0; y < 5; y++ ) { y1 = ((y >> 1) ^ (y & 1 ? -1 : 0)) + (y & 1); - for( z = 0; z < 4; z++ ) + for( z = 0; z < 5; z++ ) { z1 = ((z >> 1) ^ (z & 1 ? -1 : 0)) + (z & 1); @@ -2687,6 +2907,21 @@ void IlluminateVertexes( int num ) trace.cluster = ClusterForPointExtFilter( origin, VERTEX_EPSILON, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ] ); if( trace.cluster < 0 ) continue; + + /* r7 dirt */ + if( dirty && !bouncing ) + dirt = DirtForSample( &trace ); + else + dirt = 1.0f; + + /* jal: floodlight */ + floodLightAmount = 0.0f; + VectorClear( floodColor ); + if( floodlighty && !bouncing ) + { + floodLightAmount = floodlightIntensity * FloodLightForSample( &trace, floodlightDistance, floodlight_lowquality ); + VectorScale( floodlightRGB, floodLightAmount, floodColor ); + } /* trace */ LightingAtSample( &trace, ds->vertexStyles, colors ); @@ -2696,6 +2931,9 @@ void IlluminateVertexes( int num ) { /* r7 dirt */ VectorScale( colors[ lightmapNum ], dirt, colors[ lightmapNum ] ); + + /* jal: floodlight */ + VectorAdd( colors[ lightmapNum ], floodColor, colors[ lightmapNum ] ); /* store */ radVertLuxel = RAD_VERTEX_LUXEL( lightmapNum, ds->firstVert + i ); @@ -2974,7 +3212,7 @@ determines if two clusters are visible to each other using the PVS qboolean ClusterVisible( int a, int b ) { - int portalClusters, leafBytes; + int leafBytes; byte *pvs; @@ -2991,7 +3229,7 @@ qboolean ClusterVisible( int a, int b ) return qtrue; /* get pvs data */ - portalClusters = ((int *) bspVisBytes)[ 0 ]; + /* portalClusters = ((int *) bspVisBytes)[ 0 ]; */ leafBytes = ((int*) bspVisBytes)[ 1 ]; pvs = bspVisBytes + VIS_HEADER_SIZE + (a * leafBytes); @@ -3295,7 +3533,7 @@ void SetupEnvelopes( qboolean forGrid, qboolean fastFlag ) int i, x, y, z, x1, y1, z1; light_t *light, *light2, **owner; bspLeaf_t *leaf; - vec3_t origin, dir, mins, maxs, nullVector = { 0, 0, 0 }; + vec3_t origin, dir, mins, maxs; float radius, intensity; light_t *buckets[ 256 ]; @@ -3408,6 +3646,7 @@ void SetupEnvelopes( qboolean forGrid, qboolean fastFlag ) /* check for fast mode */ if( !(light->flags & LIGHT_FAST) && !(light->flags & LIGHT_FAST_TEMP) ) light->envelope = MAX_WORLD_COORD * 8.0f; + intensity = light->photons; /* hopefully not used */ } else { @@ -3785,7 +4024,7 @@ void SetupFloodLight( void ) int i, j; float angle, elevation, angleStep, elevationStep; const char *value; - double v1,v2,v3,v4,v5; + double v1,v2,v3,v4,v5,v6; /* note it */ Sys_FPrintf( SYS_VRB, "--- SetupFloodLight ---\n" ); @@ -3819,8 +4058,9 @@ void SetupFloodLight( void ) v1=v2=v3=0; v4=floodlightDistance; v5=floodlightIntensity; + v6=floodlightDirectionScale; - sscanf( value, "%lf %lf %lf %lf %lf", &v1, &v2, &v3, &v4, &v5); + sscanf( value, "%lf %lf %lf %lf %lf %lf", &v1, &v2, &v3, &v4, &v5, &v6); floodlightRGB[0]=v1; floodlightRGB[1]=v2; @@ -3833,9 +4073,11 @@ void SetupFloodLight( void ) if (v4<1) v4=1024; if (v5<1) v5=128; + if (v6<0) v6=1; floodlightDistance=v4; floodlightIntensity=v5; + floodlightDirectionScale=v6; floodlighty = qtrue; Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" ); @@ -3849,24 +4091,145 @@ void SetupFloodLight( void ) VectorNormalize(floodlightRGB,floodlightRGB); } -//27 - lighttracer style ambient occlusion light hack. -//Kudos to the dirtmapping author for most of this source. -void FloodLightRawLightmap( int rawLightmapNum ) +/* +FloodLightForSample() +calculates floodlight value for a given sample +once again, kudos to the dirtmapping coder +*/ + +float FloodLightForSample( trace_t *trace , float floodLightDistance, qboolean floodLightLowQuality) { - int i, x, y, sx, sy, *cluster; - float *origin, *normal, *floodlight, *floodlight2, average, samples; - rawLightmap_t *lm; - surfaceInfo_t *info; - trace_t trace; + int i; + float d; + float contribution; + int sub = 0; + float gatherLight, outLight; + vec3_t normal, worldUp, myUp, myRt, direction, displacement; + float dd; + int vecs = 0; + + gatherLight=0; + /* dummy check */ + //if( !dirty ) + // return 1.0f; + if( trace == NULL || trace->cluster < 0 ) + return 0.0f; + - /* bail if this number exceeds the number of raw lightmaps */ - if( rawLightmapNum >= numRawLightmaps ) - return; + /* setup */ + dd = floodLightDistance; + VectorCopy( trace->normal, normal ); + + /* check if the normal is aligned to the world-up */ + if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f && ( normal[ 2 ] == 1.0f || normal[ 2 ] == -1.0f ) ) + { + if( normal[ 2 ] == 1.0f ) + { + VectorSet( myRt, 1.0f, 0.0f, 0.0f ); + VectorSet( myUp, 0.0f, 1.0f, 0.0f ); + } + else if( normal[ 2 ] == -1.0f ) + { + VectorSet( myRt, -1.0f, 0.0f, 0.0f ); + VectorSet( myUp, 0.0f, 1.0f, 0.0f ); + } + } + else + { + VectorSet( worldUp, 0.0f, 0.0f, 1.0f ); + CrossProduct( normal, worldUp, myRt ); + VectorNormalize( myRt, myRt ); + CrossProduct( myRt, normal, myUp ); + VectorNormalize( myUp, myUp ); + } - /* get lightmap */ - lm = &rawLightmaps[ rawLightmapNum ]; + /* vortex: optimise floodLightLowQuality a bit */ + if ( floodLightLowQuality == qtrue ) + { + /* iterate through ordered vectors */ + for( i = 0; i < numFloodVectors; i++ ) + if (rand()%10 != 0 ) continue; + } + else + { + /* iterate through ordered vectors */ + for( i = 0; i < numFloodVectors; i++ ) + { + vecs++; + + /* transform vector into tangent space */ + direction[ 0 ] = myRt[ 0 ] * floodVectors[ i ][ 0 ] + myUp[ 0 ] * floodVectors[ i ][ 1 ] + normal[ 0 ] * floodVectors[ i ][ 2 ]; + direction[ 1 ] = myRt[ 1 ] * floodVectors[ i ][ 0 ] + myUp[ 1 ] * floodVectors[ i ][ 1 ] + normal[ 1 ] * floodVectors[ i ][ 2 ]; + direction[ 2 ] = myRt[ 2 ] * floodVectors[ i ][ 0 ] + myUp[ 2 ] * floodVectors[ i ][ 1 ] + normal[ 2 ] * floodVectors[ i ][ 2 ]; + + /* set endpoint */ + VectorMA( trace->origin, dd, direction, trace->end ); + + //VectorMA( trace->origin, 1, direction, trace->origin ); + + SetupTrace( trace ); + /* trace */ + TraceLine( trace ); + contribution=1; + + if ( trace->compileFlags & C_SKY || trace->compileFlags & C_TRANSLUCENT ) + { + contribution=1.0f; + } + else if ( trace->opaque ) + { + VectorSubtract( trace->hit, trace->origin, displacement ); + d=VectorLength( displacement ); + + // d=trace->distance; + //if (d>256) gatherDirt+=1; + contribution=d/dd; + if (contribution>1) contribution=1.0f; + + //gatherDirt += 1.0f - ooDepth * VectorLength( displacement ); + } + + gatherLight+=contribution; + } + } + + /* early out */ + if( gatherLight <= 0.0f ) + return 0.0f; + + sub=vecs; + + if (sub<1) sub=1; + gatherLight/=(sub); + + outLight=gatherLight; + if( outLight > 1.0f ) + outLight = 1.0f; + + /* return to sender */ + return outLight; +} +/* +FloodLightRawLightmap +lighttracer style ambient occlusion light hack. +Kudos to the dirtmapping author for most of this source. +VorteX: modified to floodlight up custom surfaces (q3map_floodLight) +VorteX: fixed problems with deluxemapping +*/ + +// floodlight pass on a lightmap +void FloodLightRawLightmapPass( rawLightmap_t *lm , vec3_t lmFloodLightRGB, float lmFloodLightIntensity, float lmFloodLightDistance, qboolean lmFloodLightLowQuality, float floodlightDirectionScale) +{ + int i, x, y, *cluster; + float *origin, *normal, *floodlight, floodLightAmount; + surfaceInfo_t *info; + trace_t trace; + // int sx, sy; + // float samples, average, *floodlight2; + memset(&trace,0,sizeof(trace_t)); + /* setup trace */ trace.testOcclusion = qtrue; trace.forceSunlight = qfalse; @@ -3877,14 +4240,14 @@ void FloodLightRawLightmap( int rawLightmapNum ) trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS; trace.testAll = qfalse; trace.distance = 1024; - + /* twosided lighting (may or may not be a good idea for lightmapped stuff) */ //trace.twoSided = qfalse; for( i = 0; i < trace.numSurfaces; i++ ) { /* get surface */ info = &surfaceInfos[ trace.surfaces[ i ] ]; - + /* check twosidedness */ if( info->si->twoSided ) { @@ -3892,8 +4255,8 @@ void FloodLightRawLightmap( int rawLightmapNum ) break; } } - - /* gather dirt */ + + /* gather floodlight */ for( y = 0; y < lm->sh; y++ ) { for( x = 0; x < lm->sw; x++ ) @@ -3903,29 +4266,35 @@ void FloodLightRawLightmap( int rawLightmapNum ) origin = SUPER_ORIGIN( x, y ); normal = SUPER_NORMAL( x, y ); floodlight = SUPER_FLOODLIGHT( x, y ); - + /* set default dirt */ *floodlight = 0.0f; - + /* only look at mapped luxels */ if( *cluster < 0 ) continue; - + /* copy to trace */ trace.cluster = *cluster; VectorCopy( origin, trace.origin ); VectorCopy( normal, trace.normal ); - - - - /* get dirt */ - *floodlight = FloodLightForSample( &trace ); + + /* get floodlight */ + floodLightAmount = FloodLightForSample( &trace , lmFloodLightDistance, lmFloodLightLowQuality)*lmFloodLightIntensity; + + /* add floodlight */ + floodlight[0] += lmFloodLightRGB[0]*floodLightAmount; + floodlight[1] += lmFloodLightRGB[1]*floodLightAmount; + floodlight[2] += lmFloodLightRGB[2]*floodLightAmount; + floodlight[3] += floodlightDirectionScale; } } - + /* testing no filtering */ return; +#if 0 + /* filter "dirt" */ for( y = 0; y < lm->sh; y++ ) { @@ -3933,8 +4302,8 @@ void FloodLightRawLightmap( int rawLightmapNum ) { /* get luxel */ cluster = SUPER_CLUSTER( x, y ); - floodlight = SUPER_FLOODLIGHT( x, y ); - + floodlight = SUPER_FLOODLIGHT(x, y ); + /* filter dirt by adjacency to unmapped luxels */ average = *floodlight; samples = 1.0f; @@ -3942,148 +4311,132 @@ void FloodLightRawLightmap( int rawLightmapNum ) { if( sy < 0 || sy >= lm->sh ) continue; - + for( sx = (x - 1); sx <= (x + 1); sx++ ) { if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) ) continue; - + /* get neighboring luxel */ cluster = SUPER_CLUSTER( sx, sy ); floodlight2 = SUPER_FLOODLIGHT( sx, sy ); if( *cluster < 0 || *floodlight2 <= 0.0f ) continue; - + /* add it */ average += *floodlight2; samples += 1.0f; } - + /* bail */ if( samples <= 0.0f ) break; } - + /* bail */ if( samples <= 0.0f ) continue; - + /* scale dirt */ *floodlight = average / samples; } } +#endif } -/* -FloodLightForSample() -calculates floodlight value for a given sample -once again, kudos to the dirtmapping coder -*/ -float FloodLightForSample( trace_t *trace ) +void FloodLightRawLightmap( int rawLightmapNum ) { - int i; - float d; - float contribution; - int sub = 0; - float gatherLight, outLight; - vec3_t normal, worldUp, myUp, myRt, direction, displacement; - float dd; - int vecs = 0; - - gatherLight=0; - /* dummy check */ - //if( !dirty ) - // return 1.0f; - if( trace == NULL || trace->cluster < 0 ) - return 0.0f; + rawLightmap_t *lm; + /* bail if this number exceeds the number of raw lightmaps */ + if( rawLightmapNum >= numRawLightmaps ) + return; + /* get lightmap */ + lm = &rawLightmaps[ rawLightmapNum ]; - /* setup */ - dd = floodlightDistance; - VectorCopy( trace->normal, normal ); + /* global pass */ + if (floodlighty && floodlightIntensity) + FloodLightRawLightmapPass(lm, floodlightRGB, floodlightIntensity, floodlightDistance, floodlight_lowquality, floodlightDirectionScale); - /* check if the normal is aligned to the world-up */ - if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f ) - { - if( normal[ 2 ] == 1.0f ) - { - VectorSet( myRt, 1.0f, 0.0f, 0.0f ); - VectorSet( myUp, 0.0f, 1.0f, 0.0f ); - } - else if( normal[ 2 ] == -1.0f ) - { - VectorSet( myRt, -1.0f, 0.0f, 0.0f ); - VectorSet( myUp, 0.0f, 1.0f, 0.0f ); - } - } - else + /* custom pass */ + if (lm->floodlightIntensity) { - VectorSet( worldUp, 0.0f, 0.0f, 1.0f ); - CrossProduct( normal, worldUp, myRt ); - VectorNormalize( myRt, myRt ); - CrossProduct( myRt, normal, myUp ); - VectorNormalize( myUp, myUp ); + FloodLightRawLightmapPass(lm, lm->floodlightRGB, lm->floodlightIntensity, lm->floodlightDistance, qfalse, lm->floodlightDirectionScale); + numSurfacesFloodlighten += 1; } +} - /* iterate through ordered vectors */ - for( i = 0; i < numFloodVectors; i++ ) - { - if (floodlight_lowquality==qtrue) - { - if (rand()%10 != 0 ) continue; - } - - vecs++; - - /* transform vector into tangent space */ - direction[ 0 ] = myRt[ 0 ] * floodVectors[ i ][ 0 ] + myUp[ 0 ] * floodVectors[ i ][ 1 ] + normal[ 0 ] * floodVectors[ i ][ 2 ]; - direction[ 1 ] = myRt[ 1 ] * floodVectors[ i ][ 0 ] + myUp[ 1 ] * floodVectors[ i ][ 1 ] + normal[ 1 ] * floodVectors[ i ][ 2 ]; - direction[ 2 ] = myRt[ 2 ] * floodVectors[ i ][ 0 ] + myUp[ 2 ] * floodVectors[ i ][ 1 ] + normal[ 2 ] * floodVectors[ i ][ 2 ]; +void FloodlightRawLightmaps() +{ + Sys_Printf( "--- FloodlightRawLightmap ---\n" ); + numSurfacesFloodlighten = 0; + RunThreadsOnIndividual( numRawLightmaps, qtrue, FloodLightRawLightmap ); + Sys_Printf( "%9d custom lightmaps floodlighted\n", numSurfacesFloodlighten ); +} - /* set endpoint */ - VectorMA( trace->origin, dd, direction, trace->end ); +/* +FloodLightIlluminate() +illuminate floodlight into lightmap luxels +*/ - //VectorMA( trace->origin, 1, direction, trace->origin ); +void FloodlightIlluminateLightmap( rawLightmap_t *lm ) +{ + float *luxel, *floodlight, *deluxel, *normal; + int *cluster; + float brightness; + int x, y, lightmapNum; - SetupTrace( trace ); - /* trace */ - TraceLine( trace ); - contribution=1; + /* walk lightmaps */ + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ ) + { + /* early out */ + if( lm->superLuxels[ lightmapNum ] == NULL ) + continue; - if (trace->compileFlags & C_SKY ) - { - contribution=1.0f; - } - else if ( trace->opaque ) + /* apply floodlight to each luxel */ + for( y = 0; y < lm->sh; y++ ) { - VectorSubtract( trace->hit, trace->origin, displacement ); - d=VectorLength( displacement ); + for( x = 0; x < lm->sw; x++ ) + { + /* get floodlight */ + floodlight = SUPER_FLOODLIGHT( x, y ); + if (!floodlight[0] && !floodlight[1] && !floodlight[2]) + continue; + + /* get cluster */ + cluster = SUPER_CLUSTER( x, y ); - // d=trace->distance; - //if (d>256) gatherDirt+=1; - contribution=d/dd; - if (contribution>1) contribution=1.0f; + /* only process mapped luxels */ + if( *cluster < 0 ) + continue; - //gatherDirt += 1.0f - ooDepth * VectorLength( displacement ); - } + /* get particulars */ + luxel = SUPER_LUXEL( lightmapNum, x, y ); + deluxel = SUPER_DELUXEL( x, y ); - gatherLight+=contribution; - } + /* add to lightmap */ + luxel[0]+=floodlight[0]; + luxel[1]+=floodlight[1]; + luxel[2]+=floodlight[2]; - /* early out */ - if( gatherLight <= 0.0f ) - return 0.0f; + if (luxel[3]==0) luxel[3]=1; - sub=vecs; + /* add to deluxemap */ + if (deluxemap && floodlight[3] > 0) + { + vec3_t lightvector; - if (sub<1) sub=1; - gatherLight/=(sub); + normal = SUPER_NORMAL( x, y ); + brightness = RGBTOGRAY( floodlight ) * ( 1.0f/255.0f ) * floodlight[3]; - outLight=gatherLight; - if( outLight > 1.0f ) - outLight = 1.0f; + // use AT LEAST this amount of contribution from ambient for the deluxemap, fixes points that receive ZERO light + if(brightness < 0.00390625f) + brightness = 0.00390625f; - /* return to sender */ - return outLight; + VectorScale( normal, brightness, lightvector ); + VectorAdd( deluxel, lightvector, deluxel ); + } + } + } + } } -