radial.cpp
来自「hl2 source code. Do not use it illegal.」· C++ 代码 · 共 891 行 · 第 1/2 页
CPP
891 行
VectorCopy( fl->light[nstyle][bumpSample][k], light[bumpSample] );
}
}
else
{
VectorCopy( fl->light[nstyle][0][k], light[0] );
}
Vector tmp;
Vector2D mins, maxs;
LuxelSpaceToWorld( &l, fl->sample[k].mins[0], fl->sample[k].mins[1], tmp );
WorldToLuxelSpace( &rad->l, tmp, mins );
LuxelSpaceToWorld( &l, fl->sample[k].maxs[0], fl->sample[k].maxs[1], tmp );
WorldToLuxelSpace( &rad->l, tmp, maxs );
AddDirectToRadial( rad, fl->sample[k].pos, mins, maxs, light,
needsBumpmap, neighborHasBumpmap );
}
}
return rad;
}
//-----------------------------------------------------------------------------
// Purpose: returns the closest light value for a given point on the surface
// this is normally a 1:1 mapping
//-----------------------------------------------------------------------------
bool SampleRadial( radial_t *rad, Vector& pnt, Vector light[NUM_BUMP_VECTS + 1], int bumpSampleCount )
{
int bumpSample;
Vector2D coord;
WorldToLuxelSpace( &rad->l, pnt, coord );
int i = ( int )( coord[0] + 0.5f ) + ( int )( coord[1] + 0.5f ) * rad->w;
bool baseSampleOk = true;
for( bumpSample = 0; bumpSample < bumpSampleCount; bumpSample++ )
{
VectorFill( light[bumpSample], 0 );
if (rad->weight[i] > WEIGHT_EPS)
{
VectorScale( rad->light[bumpSample][i], 1.0 / rad->weight[i], light[bumpSample] );
}
else
{
if ( bRed2Black )
{
// Error, luxel has no samples
light[bumpSample][0] = 0;
light[bumpSample][1] = 0;
light[bumpSample][2] = 0;
}
else
{
// Error, luxel has no samples
// Yes, it actually should be 2550
light[bumpSample][0] = 2550;
light[bumpSample][1] = 0;
light[bumpSample][2] = 0;
}
if (bumpSample == 0)
baseSampleOk = false;
}
}
return baseSampleOk;
}
// assumes that the desired mantissa range is 0..255
int CalcExponent( float in )
{
int power = 0;
if( in != 0.0f )
{
while( in > 255.0f )
{
power += 1;
in *= 0.5f;
}
while( in < 127.0f )
{
power -= 1;
in *= 2.0f;
}
}
return power;
}
void Vec3toColorRGBExp32( Vector& v, colorRGBExp32 *c )
{
int i;
float max = 0.0f;
for( i = 0; i < 3; i++ )
{
// Get the maximum value.
if( v[i] > max )
{
max = v[i];
}
}
// figure out the exponent for this luxel.
int exponent = CalcExponent( max );
// make the exponent fits into a signed byte.
if( exponent < -128 )
{
exponent = -128;
}
else if( exponent > 127 )
{
exponent = 127;
}
// undone: optimize with a table
float scalar = pow( 2.0f, -exponent );
// convert to mantissa x 2^exponent format
for( i = 0; i < 3; i++ )
{
v[i] *= scalar;
// clamp
if( v[i] > 255.0f )
{
v[i] = 255.0f;
}
}
c->r = ( unsigned char )v[0];
c->g = ( unsigned char )v[1];
c->b = ( unsigned char )v[2];
c->exponent = ( signed char )exponent;
}
bool FloatLess( float const& src1, float const& src2 )
{
return src1 < src2;
}
//-----------------------------------------------------------------------------
// Debugging!
//-----------------------------------------------------------------------------
void GetRandomColor( unsigned char *color )
{
static bool firstTime = true;
if( firstTime )
{
firstTime = false;
srand( 0 );
}
color[0] = ( unsigned char )( rand() * ( 255.0f / RAND_MAX ) );
color[1] = ( unsigned char )( rand() * ( 255.0f / RAND_MAX ) );
color[2] = ( unsigned char )( rand() * ( 255.0f / RAND_MAX ) );
}
#if 0
// debugging! -- not accurate!
void DumpLuxels( facelight_t *pFaceLight, Vector *luxelColors, int ndxFace )
{
static FileHandle_t pFpLuxels = NULL;
ThreadLock();
if( !pFpLuxels )
{
pFpLuxels = g_pFileSystem->Open( "luxels.txt", "w" );
}
dface_t *pFace = &dfaces[ndxFace];
bool bDisp = ( pFace->dispinfo != -1 );
for( int ndx = 0; ndx < pFaceLight->numluxels; ndx++ )
{
WriteWinding( pFpLuxels, pFaceLight->sample[ndx].w, luxelColors[ndx] );
if( bDumpNormals && bDisp )
{
WriteNormal( pFpLuxels, pFaceLight->luxel[ndx], pFaceLight->luxelNormals[ndx], 15.0f, Vector( 255, 255, 0 ) );
}
}
ThreadUnlock();
}
#endif
/*
=============
FinalLightFace
Add the indirect lighting on top of the direct
lighting and save into final map format
=============
*/
void FinalLightFace( int iThread, int facenum )
{
dface_t *f;
int i, j, k;
facelight_t *fl;
float minlight;
int lightstyles;
Vector lb[NUM_BUMP_VECTS + 1], v[NUM_BUMP_VECTS + 1];
unsigned char *pdata[NUM_BUMP_VECTS + 1];
int bumpSample;
radial_t *rad = NULL;
radial_t *prad = NULL;
f = &dfaces[facenum];
// test for non-lit texture
if ( texinfo[f->texinfo].flags & TEX_SPECIAL)
return;
fl = &facelight[facenum];
for (lightstyles=0; lightstyles < MAXLIGHTMAPS; lightstyles++ )
{
if ( f->styles[lightstyles] == 255 )
break;
}
if ( !lightstyles )
return;
//
// sample the triangulation
//
minlight = FloatForKey (face_entity[facenum], "_minlight") * 128;
bool needsBumpmap = ( texinfo[f->texinfo].flags & SURF_BUMPLIGHT ) ? true : false;
int bumpSampleCount = needsBumpmap ? NUM_BUMP_VECTS + 1 : 1;
bool bDisp = ( f->dispinfo != -1 );
//#define RANDOM_COLOR
#ifdef RANDOM_COLOR
unsigned char randomColor[3];
GetRandomColor( randomColor );
#endif
// NOTE: I'm using these RB trees to sort all the illumination values
// to compute median colors. Turns out that this is a somewhat better
// method that using the average; usually if there are surfaces
// with a large light intensity variation, the extremely bright regions
// have a very small area and tend to influence the average too much.
CUtlRBTree< float, unsigned int > m_Red( 0, 256, FloatLess );
CUtlRBTree< float, unsigned int > m_Green( 0, 256, FloatLess );
CUtlRBTree< float, unsigned int > m_Blue( 0, 256, FloatLess );
for (k=0 ; k < lightstyles; k++ )
{
m_Red.RemoveAll();
m_Green.RemoveAll();
m_Blue.RemoveAll();
if (!do_fast)
{
if( !bDisp )
{
rad = BuildLuxelRadial( facenum, k );
}
else
{
rad = StaticDispMgr()->BuildLuxelRadial( facenum, k, needsBumpmap );
}
}
if (numbounce > 0 && k == 0)
{
// currently only radiosity light non-displacement surfaces!
if( !bDisp )
{
prad = BuildPatchRadial( facenum );
}
else
{
prad = StaticDispMgr()->BuildPatchRadial( facenum, needsBumpmap );
}
}
// pack the nonbump texture and the three bump texture for the given
// lightstyle right next to each other.
// NOTE: Even though it's building positions for all bump-mapped data,
// it isn't going to use those positions (see loop over bumpSample below)
// The file offset is correctly computed to only store space for 1 set
// of light data if we don't have bumped lighting.
for( bumpSample = 0; bumpSample < bumpSampleCount; ++bumpSample )
{
pdata[bumpSample] = &dlightdata[f->lightofs + (k * bumpSampleCount + bumpSample) * fl->numluxels*4];
}
// Compute the average luxel color, but not for the bump samples
Vector avg( 0.0f, 0.0f, 0.0f );
int avgCount = 0;
for (j=0 ; j<fl->numluxels; j++)
{
// garymct - direct lighting
bool baseSampleOk = true;
if (!do_fast)
{
if( !bDisp )
{
baseSampleOk = SampleRadial( rad, fl->luxel[j], lb, bumpSampleCount );
}
else
{
baseSampleOk = StaticDispMgr()->SampleRadial( facenum, rad, fl->luxel[j], j, lb, bumpSampleCount, false );
}
}
else
{
for ( int iBump = 0 ; iBump < bumpSampleCount; iBump++ )
{
VectorCopy( fl->light[0][iBump][j], lb[iBump] );
}
}
if (prad)
{
// garymct - bounced light
// v is indirect light that is received on the luxel.
if( !bDisp )
{
SampleRadial( prad, fl->luxel[j], v, bumpSampleCount );
}
else
{
StaticDispMgr()->SampleRadial( facenum, prad, fl->luxel[j], j, v, bumpSampleCount, true );
}
for( bumpSample = 0; bumpSample < bumpSampleCount; ++bumpSample )
{
VectorAdd( lb[bumpSample], v[bumpSample], lb[bumpSample] );
}
}
if (fl->numsamples == 0)
{
for( i = 0; i < bumpSampleCount; i++ )
{
lb[i][0] = 255;
lb[i][1] = 0;
lb[i][2] = 0;
}
baseSampleOk = false;
}
int bumpSample;
for( bumpSample = 0; bumpSample < bumpSampleCount; bumpSample++ )
{
// clip from the bottom first
// garymct: minlight is a per entity minimum light value?
for( i=0; i<3; i++ )
{
if( lb[bumpSample][i] < minlight )
{
lb[bumpSample][i] = minlight;
}
}
// Do the average light computation, I'm assuming (perhaps incorrectly?)
// that all luxels in a particular lightmap have the same area here.
// Also, don't bother doing averages for the bump samples. Doing it here
// because of the minlight clamp above + the random color testy thingy.
// Also have to do it before Vec3toColorRGBExp32 because it
// destructively modifies lb[bumpSample] (Feh!)
if ((bumpSample == 0) && baseSampleOk)
{
++avgCount;
ApplyMacroTextures( facenum, fl->luxel[j], lb[0] );
// For median computation
m_Red.Insert( lb[bumpSample][0] );
m_Green.Insert( lb[bumpSample][1] );
m_Blue.Insert( lb[bumpSample][2] );
}
#ifdef RANDOM_COLOR
pdata[bumpSample][0] = randomColor[0] / ( bumpSample + 1 );
pdata[bumpSample][1] = randomColor[1] / ( bumpSample + 1 );
pdata[bumpSample][2] = randomColor[2] / ( bumpSample + 1 );
pdata[bumpSample][3] = 0;
#else
// convert to a 4 byte r,g,b,signed exponent format
Vec3toColorRGBExp32( lb[bumpSample], ( colorRGBExp32 *)pdata[bumpSample] );
#endif
pdata[bumpSample] += 4;
}
}
FreeRadial( rad );
if (prad)
{
FreeRadial( prad );
prad = NULL;
}
// Fill in the average color for this lightstyle
// if (avgCount)
// avg /= avgCount;
// Vec3toColorRGBExp32( avg, &f->m_AvgLightColor[k] );
// Compute the median color for this lightstyle
// Remember, the data goes *before* the specified light_ofs, in *reverse order*
colorRGBExp32 *pAvgColor = (colorRGBExp32*)&dlightdata[f->lightofs - (k+1) * 4];
if (avgCount == 0)
{
Vector median( 0, 0, 0 );
Vec3toColorRGBExp32( median, pAvgColor );
}
else
{
unsigned int r, g, b;
r = m_Red.FirstInorder();
g = m_Green.FirstInorder();
b = m_Blue.FirstInorder();
avgCount >>= 1;
while (avgCount > 0)
{
r = m_Red.NextInorder(r);
g = m_Green.NextInorder(g);
b = m_Blue.NextInorder(b);
--avgCount;
}
Vector median( m_Red[r], m_Green[g], m_Blue[b] );
Vec3toColorRGBExp32( median, pAvgColor );
}
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?