?? incremental.cpp
字號(hào):
#include "incremental.h"
#include "lightmap.h"
static bool g_bFileError = false;
// -------------------------------------------------------------------------------- //
// Static helpers.
// -------------------------------------------------------------------------------- //
static bool CompareLights( dworldlight_t *a, dworldlight_t *b )
{
static float flEpsilon = 1e-7;
bool a1 = VectorsAreEqual( a->origin, b->origin, flEpsilon );
bool a2 = VectorsAreEqual( a->intensity, b->intensity, 1.1f ); // intensities are huge numbers
bool a3 = VectorsAreEqual( a->normal, b->normal, flEpsilon );
bool a4 = fabs( a->constant_attn - b->constant_attn ) < flEpsilon;
bool a5 = fabs( a->linear_attn - b->linear_attn ) < flEpsilon;
bool a6 = fabs( a->quadratic_attn - b->quadratic_attn ) < flEpsilon;
bool a7 = fabs( float( a->flags - b->flags ) ) < flEpsilon;
bool a8 = fabs( a->stopdot - b->stopdot ) < flEpsilon;
bool a9 = fabs( a->stopdot2 - b->stopdot2 ) < flEpsilon;
bool a10 = fabs( a->exponent - b->exponent ) < flEpsilon;
bool a11 = fabs( a->radius - b->radius ) < flEpsilon;
return a1 && a2 && a3 && a4 && a5 && a6 && a7 && a8 && a9 && a10 && a11;
}
long FileOpen( char const *pFilename, bool bRead )
{
g_bFileError = false;
return (long)g_pFileSystem->Open( pFilename, bRead ? "rb" : "wb" );
}
void FileClose( long fp )
{
if( fp )
g_pFileSystem->Close( (FILE*)fp );
}
// Returns true if there was an error reading from the file.
bool FileError()
{
return g_bFileError;
}
static inline void FileRead( long fp, void *pOut, int size )
{
if( g_bFileError || g_pFileSystem->Read( pOut, size, (FileHandle_t)fp ) != size )
{
g_bFileError = true;
memset( pOut, 0, size );
}
}
template<class T>
static inline void FileRead( long fp, T &out )
{
FileRead( fp, &out, sizeof(out) );
}
static inline void FileWrite( long fp, void const *pData, int size )
{
if( g_bFileError || g_pFileSystem->Write( pData, size, (FileHandle_t)fp ) != size )
{
g_bFileError = true;
}
}
template<class T>
static inline void FileWrite( long fp, T out )
{
FileWrite( fp, &out, sizeof(out) );
}
IIncremental* GetIncremental()
{
static CIncremental inc;
return &inc;
}
// -------------------------------------------------------------------------------- //
// CIncremental.
// -------------------------------------------------------------------------------- //
CIncremental::CIncremental()
{
m_TotalMemory = 0;
m_pIncrementalFilename = NULL;
m_pBSPFilename = NULL;
m_bSuccessfulRun = false;
}
CIncremental::~CIncremental()
{
}
bool CIncremental::Init( char const *pBSPFilename, char const *pIncrementalFilename )
{
m_pBSPFilename = pBSPFilename;
m_pIncrementalFilename = pIncrementalFilename;
return true;
}
bool CIncremental::PrepareForLighting()
{
if( !m_pBSPFilename )
return false;
// Clear the touched faces list.
m_FacesTouched.SetSize( numfaces );
memset( m_FacesTouched.Base(), 0, numfaces );
// If we haven't done a complete successful run yet, then we either haven't
// loaded the lights, or a run was aborted and our lights are half-done so we
// should reload them.
if( !m_bSuccessfulRun )
LoadIncrementalFile();
// unmatched = a list of the lights we have
CUtlLinkedList<int,int> unmatched;
for( int i=m_Lights.Head(); i != m_Lights.InvalidIndex(); i = m_Lights.Next(i) )
unmatched.AddToTail( i );
// Match the light lists and get rid of lights that we already have all the data for.
directlight_t *pNext;
directlight_t **pPrev = &activelights;
for( directlight_t *dl=activelights; dl != NULL; dl = pNext )
{
pNext = dl->next;
//float flClosest = 3000000000;
//CIncLight *pClosest = 0;
// Look for this light in our light list.
int iNextUnmatched, iUnmatched;
for( iUnmatched=unmatched.Head(); iUnmatched != unmatched.InvalidIndex(); iUnmatched = iNextUnmatched )
{
iNextUnmatched = unmatched.Next( iUnmatched );
CIncLight *pLight = m_Lights[ unmatched[iUnmatched] ];
//float flTest = (pLight->m_Light.origin - dl->light.origin).Length();
//if( flTest < flClosest )
//{
// flClosest = flTest;
// pClosest = pLight;
//}
if( CompareLights( &dl->light, &pLight->m_Light ) )
{
unmatched.Remove( iUnmatched );
// Ok, we have this light's data already, yay!
// Get rid of it from the active light list.
*pPrev = dl->next;
free( dl );
dl = 0;
break;
}
}
//bool bTest=false;
//if(bTest)
// CompareLights( &dl->light, &pClosest->m_Light );
if( iUnmatched == unmatched.InvalidIndex() )
pPrev = &dl->next;
}
// Remove any of our lights that were unmatched.
for( int iUnmatched=unmatched.Head(); iUnmatched != unmatched.InvalidIndex(); iUnmatched = unmatched.Next( iUnmatched ) )
{
CIncLight *pLight = m_Lights[ unmatched[iUnmatched] ];
// First tag faces that it touched so they get recomposited.
for( unsigned short iFace=pLight->m_LightFaces.Head(); iFace != pLight->m_LightFaces.InvalidIndex(); iFace = pLight->m_LightFaces.Next( iFace ) )
{
m_FacesTouched[ pLight->m_LightFaces[iFace]->m_FaceIndex ] = 1;
}
delete pLight;
m_Lights.Remove( unmatched[iUnmatched] );
}
// Now add a light structure for each new light.
AddLightsForActiveLights();
return true;
}
bool CIncremental::ReadIncrementalHeader( long fp, CIncrementalHeader *pHeader )
{
int version;
FileRead( fp, version );
if( version != INCREMENTALFILE_VERSION )
return false;
int nFaces;
FileRead( fp, nFaces );
pHeader->m_FaceLightmapSizes.SetSize( nFaces );
FileRead( fp, pHeader->m_FaceLightmapSizes.Base(), sizeof(CIncrementalHeader::CLMSize) * nFaces );
return !FileError();
}
bool CIncremental::WriteIncrementalHeader( long fp )
{
int version = INCREMENTALFILE_VERSION;
FileWrite( fp, version );
int nFaces = numfaces;
FileWrite( fp, nFaces );
CIncrementalHeader hdr;
hdr.m_FaceLightmapSizes.SetSize( nFaces );
for( int i=0; i < nFaces; i++ )
{
hdr.m_FaceLightmapSizes[i].m_Width = dfaces[i].m_LightmapTextureSizeInLuxels[0];
hdr.m_FaceLightmapSizes[i].m_Height = dfaces[i].m_LightmapTextureSizeInLuxels[1];
}
FileWrite( fp, hdr.m_FaceLightmapSizes.Base(), sizeof(CIncrementalHeader::CLMSize) * nFaces );
return !FileError();
}
bool CIncremental::IsIncrementalFileValid()
{
long fp = FileOpen( m_pIncrementalFilename, true );
if( !fp )
return false;
bool bValid = false;
CIncrementalHeader hdr;
if( ReadIncrementalHeader( fp, &hdr ) )
{
// If the number of faces is the same and their lightmap sizes are the same,
// then this file is considered a legitimate incremental file.
if( hdr.m_FaceLightmapSizes.Count() == numfaces )
{
int i;
for( i=0; i < numfaces; i++ )
{
if( hdr.m_FaceLightmapSizes[i].m_Width != dfaces[i].m_LightmapTextureSizeInLuxels[0] ||
hdr.m_FaceLightmapSizes[i].m_Height != dfaces[i].m_LightmapTextureSizeInLuxels[1] )
{
break;
}
}
// Were all faces valid?
if( i == numfaces )
bValid = true;
}
}
FileClose( fp );
return bValid && !FileError();
}
void CIncremental::AddLightToFace(
IncrementalLightID lightID,
int iFace,
int iSample,
int lmSize,
float dot,
int iThread )
{
// If we're not being used, don't do anything.
if( !m_pIncrementalFilename )
return;
CIncLight *pLight = m_Lights[lightID];
// Check for the 99.99% case in which the face already exists.
CLightFace *pFace;
if( pLight->m_pCachedFaces[iThread] && pLight->m_pCachedFaces[iThread]->m_FaceIndex == iFace )
{
pFace = pLight->m_pCachedFaces[iThread];
}
else
{
bool bNew;
EnterCriticalSection( &pLight->m_CS );
pFace = pLight->FindOrCreateLightFace( iFace, lmSize, &bNew );
LeaveCriticalSection( &pLight->m_CS );
pLight->m_pCachedFaces[iThread] = pFace;
if( bNew )
m_TotalMemory += pFace->m_LightValues.Count() * sizeof( pFace->m_LightValues[0] );
}
// Add this into the light's data.
pFace->m_LightValues[iSample].m_Dot = dot;
}
unsigned short DecodeCharOrShort( CUtlBuffer *pIn )
{
unsigned short val = pIn->GetUnsignedChar();
if( val & 0x80 )
{
val = ((val & 0x7F) << 8) | pIn->GetUnsignedChar();
}
return val;
}
void EncodeCharOrShort( CUtlBuffer *pBuf, unsigned short val )
{
if( (val & 0xFF80) == 0 )
{
pBuf->PutUnsignedChar( (unsigned char)val );
}
else
{
if( val > 32767 )
val = 32767;
pBuf->PutUnsignedChar( (val >> 8) | 0x80 );
pBuf->PutUnsignedChar( val & 0xFF );
}
}
void DecompressLightData( CUtlBuffer *pIn, CUtlVector<CLightValue> *pOut )
{
int iOut = 0;
while( pIn->TellGet() < pIn->TellPut() )
{
unsigned char runLength = pIn->GetUnsignedChar();
unsigned short usVal = DecodeCharOrShort( pIn );
while( runLength > 0 )
{
--runLength;
pOut->Element(iOut).m_Dot = usVal;
++iOut;
}
}
}
#ifdef _WIN32
#pragma warning (disable:4701)
#endif
void CompressLightData(
CLightValue const *pValues,
int nValues,
CUtlBuffer *pBuf )
{
unsigned char runLength=0;
unsigned short flLastValue;
for( int i=0; i < nValues; i++ )
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -