From f56bb35301836e56582a575a75864392a0177875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20P=2E=20Tjern=C3=B8?= Date: Mon, 2 Dec 2013 19:31:46 -0800 Subject: Fix line endings. WHAMMY. --- mp/src/utils/vrad/incremental.cpp | 1532 ++++++++++++++++++------------------- 1 file changed, 766 insertions(+), 766 deletions(-) (limited to 'mp/src/utils/vrad/incremental.cpp') diff --git a/mp/src/utils/vrad/incremental.cpp b/mp/src/utils/vrad/incremental.cpp index 9dd877e0..ad46d04d 100644 --- a/mp/src/utils/vrad/incremental.cpp +++ b/mp/src/utils/vrad/incremental.cpp @@ -1,766 +1,766 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -// $NoKeywords: $ -// -//=============================================================================// -#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 -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 -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 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 = g_pFaces[i].m_LightmapTextureSizeInLuxels[0]; - hdr.m_FaceLightmapSizes[i].m_Height = g_pFaces[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 != g_pFaces[i].m_LightmapTextureSizeInLuxels[0] || - hdr.m_FaceLightmapSizes[i].m_Height != g_pFaces[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 *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++ ) - { - unsigned short flCurValue = (unsigned short)pValues[i].m_Dot; - - if( i == 0 ) - { - flLastValue = flCurValue; - runLength = 1; - } - else if( flCurValue == flLastValue && runLength < 255 ) - { - ++runLength; - } - else - { - pBuf->PutUnsignedChar( runLength ); - EncodeCharOrShort( pBuf, flLastValue ); - - flLastValue = flCurValue; - runLength = 1; - } - } - - // Write the end.. - if( runLength ) - { - pBuf->PutUnsignedChar( runLength ); - EncodeCharOrShort( pBuf, flLastValue ); - } -} - -#ifdef _WIN32 -#pragma warning (default:4701) -#endif - -void MultiplyValues( CUtlVector &values, float scale ) -{ - for( int i=0; i < values.Count(); i++ ) - values[i].m_Dot *= scale; -} - - -void CIncremental::FinishFace( - IncrementalLightID lightID, - int iFace, - int iThread ) -{ - 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]; - - // Compress the data. - MultiplyValues( pFace->m_LightValues, pLight->m_flMaxIntensity ); - - pFace->m_CompressedData.SeekPut( CUtlBuffer::SEEK_HEAD, 0 ); - CompressLightData( - pFace->m_LightValues.Base(), - pFace->m_LightValues.Count(), - &pFace->m_CompressedData ); - -#if 0 - // test decompression - CUtlVector test; - test.SetSize( 2048 ); - pFace->m_CompressedData.SeekGet( CUtlBuffer::SEEK_HEAD, 0 ); - DecompressLightData( &pFace->m_CompressedData, &test ); -#endif - - if( pFace->m_CompressedData.TellPut() == 0 ) - { - // No contribution.. delete this face from the light. - EnterCriticalSection( &pLight->m_CS ); - pLight->m_LightFaces.Remove( pFace->m_LightFacesIndex ); - delete pFace; - LeaveCriticalSection( &pLight->m_CS ); - } - else - { - // Discard the uncompressed data. - pFace->m_LightValues.Purge(); - m_FacesTouched[ pFace->m_FaceIndex ] = 1; - } - } -} - - -bool CIncremental::Finalize() -{ - // If we're not being used, don't do anything. - if( !m_pIncrementalFilename || !m_pBSPFilename ) - return false; - - CUtlVector faceLights; - LinkLightsToFaces( faceLights ); - - Vector faceLight[(MAX_LIGHTMAP_DIM_WITHOUT_BORDER+2) * (MAX_LIGHTMAP_DIM_WITHOUT_BORDER+2)]; - CUtlVector faceLightValues; - faceLightValues.SetSize( (MAX_LIGHTMAP_DIM_WITHOUT_BORDER+2) * (MAX_LIGHTMAP_DIM_WITHOUT_BORDER+2) ); - - // Only update the faces we've touched. - for( int facenum = 0; facenum < numfaces; facenum++ ) - { - if( !m_FacesTouched[facenum] || !faceLights[facenum].Count() ) - continue; - - int w = g_pFaces[facenum].m_LightmapTextureSizeInLuxels[0]+1; - int h = g_pFaces[facenum].m_LightmapTextureSizeInLuxels[1]+1; - int nLuxels = w * h; - assert( nLuxels <= sizeof(faceLight) / sizeof(faceLight[0]) ); - - // Clear the lighting for this face. - memset( faceLight, 0, nLuxels * sizeof(Vector) ); - - // Composite all the light contributions. - for( int iFace=0; iFace < faceLights[facenum].Count(); iFace++ ) - { - CLightFace *pFace = faceLights[facenum][iFace]; - - pFace->m_CompressedData.SeekGet( CUtlBuffer::SEEK_HEAD, 0 ); - DecompressLightData( &pFace->m_CompressedData, &faceLightValues ); - - for( int iSample=0; iSample < nLuxels; iSample++ ) - { - float flDot = faceLightValues[iSample].m_Dot; - if( flDot ) - { - VectorMA( - faceLight[iSample], - flDot / pFace->m_pLight->m_flMaxIntensity, - pFace->m_pLight->m_Light.intensity, - faceLight[iSample] ); - } - } - } - - // Convert to the floating-point representation in the BSP file. - Vector *pSrc = faceLight; - unsigned char *pDest = &(*pdlightdata)[ g_pFaces[facenum].lightofs ]; - - for( int iSample=0; iSample < nLuxels; iSample++ ) - { - VectorToColorRGBExp32( *pSrc, *( ColorRGBExp32 *)pDest ); - pDest += 4; - pSrc++; - } - } - - m_bSuccessfulRun = true; - return true; -} - - -void CIncremental::GetFacesTouched( CUtlVector &touched ) -{ - touched.CopyArray( m_FacesTouched.Base(), m_FacesTouched.Count() ); -} - - -bool CIncremental::Serialize() -{ - if( !SaveIncrementalFile() ) - return false; - - WriteBSPFile( (char*)m_pBSPFilename ); - return true; -} - - -void CIncremental::Term() -{ - m_Lights.PurgeAndDeleteElements(); - m_TotalMemory = 0; -} - - -void CIncremental::AddLightsForActiveLights() -{ - // Create our lights. - for( directlight_t *dl=activelights; dl != NULL; dl = dl->next ) - { - CIncLight *pLight = new CIncLight; - dl->m_IncrementalID = m_Lights.AddToTail( pLight ); - - // Copy the light information. - pLight->m_Light = dl->light; - pLight->m_flMaxIntensity = max( dl->light.intensity[0], max( dl->light.intensity[1], dl->light.intensity[2] ) ); - } -} - - -bool CIncremental::LoadIncrementalFile() -{ - Term(); - - if( !IsIncrementalFileValid() ) - return false; - - long fp = FileOpen( m_pIncrementalFilename, true ); - if( !fp ) - return false; - - // Read the header. - CIncrementalHeader hdr; - if( !ReadIncrementalHeader( fp, &hdr ) ) - { - FileClose( fp ); - return false; - } - - - // Read the lights. - int nLights; - FileRead( fp, nLights ); - for( int iLight=0; iLight < nLights; iLight++ ) - { - CIncLight *pLight = new CIncLight; - m_Lights.AddToTail( pLight ); - - FileRead( fp, pLight->m_Light ); - pLight->m_flMaxIntensity = - max( pLight->m_Light.intensity.x, - max( pLight->m_Light.intensity.y, pLight->m_Light.intensity.z ) ); - - int nFaces; - FileRead( fp, nFaces ); - assert( nFaces < 70000 ); - - for( int iFace=0; iFace < nFaces; iFace++ ) - { - CLightFace *pFace = new CLightFace; - pLight->m_LightFaces.AddToTail( pFace ); - - pFace->m_pLight = pLight; - FileRead( fp, pFace->m_FaceIndex ); - - int dataSize; - FileRead( fp, dataSize ); - - pFace->m_CompressedData.SeekPut( CUtlBuffer::SEEK_HEAD, 0 ); - while( dataSize ) - { - --dataSize; - - unsigned char ucData; - FileRead( fp, ucData ); - - pFace->m_CompressedData.PutUnsignedChar( ucData ); - } - } - } - - - FileClose( fp ); - return !FileError(); -} - - -bool CIncremental::SaveIncrementalFile() -{ - long fp = FileOpen( m_pIncrementalFilename, false ); - if( !fp ) - return false; - - if( !WriteIncrementalHeader( fp ) ) - { - FileClose( fp ); - return false; - } - - // Write the lights. - int nLights = m_Lights.Count(); - FileWrite( fp, nLights ); - for( int iLight=m_Lights.Head(); iLight != m_Lights.InvalidIndex(); iLight = m_Lights.Next( iLight ) ) - { - CIncLight *pLight = m_Lights[iLight]; - - FileWrite( fp, pLight->m_Light ); - - int nFaces = pLight->m_LightFaces.Count(); - FileWrite( fp, nFaces ); - for( int iFace=pLight->m_LightFaces.Head(); iFace != pLight->m_LightFaces.InvalidIndex(); iFace = pLight->m_LightFaces.Next( iFace ) ) - { - CLightFace *pFace = pLight->m_LightFaces[iFace]; - - FileWrite( fp, pFace->m_FaceIndex ); - - int dataSize = pFace->m_CompressedData.TellPut(); - FileWrite( fp, dataSize ); - - pFace->m_CompressedData.SeekGet( CUtlBuffer::SEEK_HEAD, 0 ); - while( dataSize ) - { - --dataSize; - FileWrite( fp, pFace->m_CompressedData.GetUnsignedChar() ); - } - } - } - - - FileClose( fp ); - return !FileError(); -} - - -void CIncremental::LinkLightsToFaces( CUtlVector &faceLights ) -{ - faceLights.SetSize( numfaces ); - - for( int iLight=m_Lights.Head(); iLight != m_Lights.InvalidIndex(); iLight = m_Lights.Next( iLight ) ) - { - CIncLight *pLight = m_Lights[iLight]; - - for( int iFace=pLight->m_LightFaces.Head(); iFace != pLight->m_LightFaces.InvalidIndex(); iFace = pLight->m_LightFaces.Next( iFace ) ) - { - CLightFace *pFace = pLight->m_LightFaces[iFace]; - - if( m_FacesTouched[pFace->m_FaceIndex] ) - faceLights[ pFace->m_FaceIndex ].AddToTail( pFace ); - } - } -} - - -// ------------------------------------------------------------------ // -// CIncLight -// ------------------------------------------------------------------ // - -CIncLight::CIncLight() -{ - memset( m_pCachedFaces, 0, sizeof(m_pCachedFaces) ); - InitializeCriticalSection( &m_CS ); -} - - -CIncLight::~CIncLight() -{ - m_LightFaces.PurgeAndDeleteElements(); - DeleteCriticalSection( &m_CS ); -} - - -CLightFace* CIncLight::FindOrCreateLightFace( int iFace, int lmSize, bool *bNew ) -{ - if( bNew ) - *bNew = false; - - - // Look for it. - for( int i=m_LightFaces.Head(); i != m_LightFaces.InvalidIndex(); i=m_LightFaces.Next(i) ) - { - CLightFace *pFace = m_LightFaces[i]; - - if( pFace->m_FaceIndex == iFace ) - { - assert( pFace->m_LightValues.Count() == lmSize ); - return pFace; - } - } - - // Ok, create one. - CLightFace *pFace = new CLightFace; - pFace->m_LightFacesIndex = m_LightFaces.AddToTail( pFace ); - pFace->m_pLight = this; - - pFace->m_FaceIndex = iFace; - pFace->m_LightValues.SetSize( lmSize ); - memset( pFace->m_LightValues.Base(), 0, sizeof( CLightValue ) * lmSize ); - - if( bNew ) - *bNew = true; - - return pFace; -} - - +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#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 +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 +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 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 = g_pFaces[i].m_LightmapTextureSizeInLuxels[0]; + hdr.m_FaceLightmapSizes[i].m_Height = g_pFaces[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 != g_pFaces[i].m_LightmapTextureSizeInLuxels[0] || + hdr.m_FaceLightmapSizes[i].m_Height != g_pFaces[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 *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++ ) + { + unsigned short flCurValue = (unsigned short)pValues[i].m_Dot; + + if( i == 0 ) + { + flLastValue = flCurValue; + runLength = 1; + } + else if( flCurValue == flLastValue && runLength < 255 ) + { + ++runLength; + } + else + { + pBuf->PutUnsignedChar( runLength ); + EncodeCharOrShort( pBuf, flLastValue ); + + flLastValue = flCurValue; + runLength = 1; + } + } + + // Write the end.. + if( runLength ) + { + pBuf->PutUnsignedChar( runLength ); + EncodeCharOrShort( pBuf, flLastValue ); + } +} + +#ifdef _WIN32 +#pragma warning (default:4701) +#endif + +void MultiplyValues( CUtlVector &values, float scale ) +{ + for( int i=0; i < values.Count(); i++ ) + values[i].m_Dot *= scale; +} + + +void CIncremental::FinishFace( + IncrementalLightID lightID, + int iFace, + int iThread ) +{ + 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]; + + // Compress the data. + MultiplyValues( pFace->m_LightValues, pLight->m_flMaxIntensity ); + + pFace->m_CompressedData.SeekPut( CUtlBuffer::SEEK_HEAD, 0 ); + CompressLightData( + pFace->m_LightValues.Base(), + pFace->m_LightValues.Count(), + &pFace->m_CompressedData ); + +#if 0 + // test decompression + CUtlVector test; + test.SetSize( 2048 ); + pFace->m_CompressedData.SeekGet( CUtlBuffer::SEEK_HEAD, 0 ); + DecompressLightData( &pFace->m_CompressedData, &test ); +#endif + + if( pFace->m_CompressedData.TellPut() == 0 ) + { + // No contribution.. delete this face from the light. + EnterCriticalSection( &pLight->m_CS ); + pLight->m_LightFaces.Remove( pFace->m_LightFacesIndex ); + delete pFace; + LeaveCriticalSection( &pLight->m_CS ); + } + else + { + // Discard the uncompressed data. + pFace->m_LightValues.Purge(); + m_FacesTouched[ pFace->m_FaceIndex ] = 1; + } + } +} + + +bool CIncremental::Finalize() +{ + // If we're not being used, don't do anything. + if( !m_pIncrementalFilename || !m_pBSPFilename ) + return false; + + CUtlVector faceLights; + LinkLightsToFaces( faceLights ); + + Vector faceLight[(MAX_LIGHTMAP_DIM_WITHOUT_BORDER+2) * (MAX_LIGHTMAP_DIM_WITHOUT_BORDER+2)]; + CUtlVector faceLightValues; + faceLightValues.SetSize( (MAX_LIGHTMAP_DIM_WITHOUT_BORDER+2) * (MAX_LIGHTMAP_DIM_WITHOUT_BORDER+2) ); + + // Only update the faces we've touched. + for( int facenum = 0; facenum < numfaces; facenum++ ) + { + if( !m_FacesTouched[facenum] || !faceLights[facenum].Count() ) + continue; + + int w = g_pFaces[facenum].m_LightmapTextureSizeInLuxels[0]+1; + int h = g_pFaces[facenum].m_LightmapTextureSizeInLuxels[1]+1; + int nLuxels = w * h; + assert( nLuxels <= sizeof(faceLight) / sizeof(faceLight[0]) ); + + // Clear the lighting for this face. + memset( faceLight, 0, nLuxels * sizeof(Vector) ); + + // Composite all the light contributions. + for( int iFace=0; iFace < faceLights[facenum].Count(); iFace++ ) + { + CLightFace *pFace = faceLights[facenum][iFace]; + + pFace->m_CompressedData.SeekGet( CUtlBuffer::SEEK_HEAD, 0 ); + DecompressLightData( &pFace->m_CompressedData, &faceLightValues ); + + for( int iSample=0; iSample < nLuxels; iSample++ ) + { + float flDot = faceLightValues[iSample].m_Dot; + if( flDot ) + { + VectorMA( + faceLight[iSample], + flDot / pFace->m_pLight->m_flMaxIntensity, + pFace->m_pLight->m_Light.intensity, + faceLight[iSample] ); + } + } + } + + // Convert to the floating-point representation in the BSP file. + Vector *pSrc = faceLight; + unsigned char *pDest = &(*pdlightdata)[ g_pFaces[facenum].lightofs ]; + + for( int iSample=0; iSample < nLuxels; iSample++ ) + { + VectorToColorRGBExp32( *pSrc, *( ColorRGBExp32 *)pDest ); + pDest += 4; + pSrc++; + } + } + + m_bSuccessfulRun = true; + return true; +} + + +void CIncremental::GetFacesTouched( CUtlVector &touched ) +{ + touched.CopyArray( m_FacesTouched.Base(), m_FacesTouched.Count() ); +} + + +bool CIncremental::Serialize() +{ + if( !SaveIncrementalFile() ) + return false; + + WriteBSPFile( (char*)m_pBSPFilename ); + return true; +} + + +void CIncremental::Term() +{ + m_Lights.PurgeAndDeleteElements(); + m_TotalMemory = 0; +} + + +void CIncremental::AddLightsForActiveLights() +{ + // Create our lights. + for( directlight_t *dl=activelights; dl != NULL; dl = dl->next ) + { + CIncLight *pLight = new CIncLight; + dl->m_IncrementalID = m_Lights.AddToTail( pLight ); + + // Copy the light information. + pLight->m_Light = dl->light; + pLight->m_flMaxIntensity = max( dl->light.intensity[0], max( dl->light.intensity[1], dl->light.intensity[2] ) ); + } +} + + +bool CIncremental::LoadIncrementalFile() +{ + Term(); + + if( !IsIncrementalFileValid() ) + return false; + + long fp = FileOpen( m_pIncrementalFilename, true ); + if( !fp ) + return false; + + // Read the header. + CIncrementalHeader hdr; + if( !ReadIncrementalHeader( fp, &hdr ) ) + { + FileClose( fp ); + return false; + } + + + // Read the lights. + int nLights; + FileRead( fp, nLights ); + for( int iLight=0; iLight < nLights; iLight++ ) + { + CIncLight *pLight = new CIncLight; + m_Lights.AddToTail( pLight ); + + FileRead( fp, pLight->m_Light ); + pLight->m_flMaxIntensity = + max( pLight->m_Light.intensity.x, + max( pLight->m_Light.intensity.y, pLight->m_Light.intensity.z ) ); + + int nFaces; + FileRead( fp, nFaces ); + assert( nFaces < 70000 ); + + for( int iFace=0; iFace < nFaces; iFace++ ) + { + CLightFace *pFace = new CLightFace; + pLight->m_LightFaces.AddToTail( pFace ); + + pFace->m_pLight = pLight; + FileRead( fp, pFace->m_FaceIndex ); + + int dataSize; + FileRead( fp, dataSize ); + + pFace->m_CompressedData.SeekPut( CUtlBuffer::SEEK_HEAD, 0 ); + while( dataSize ) + { + --dataSize; + + unsigned char ucData; + FileRead( fp, ucData ); + + pFace->m_CompressedData.PutUnsignedChar( ucData ); + } + } + } + + + FileClose( fp ); + return !FileError(); +} + + +bool CIncremental::SaveIncrementalFile() +{ + long fp = FileOpen( m_pIncrementalFilename, false ); + if( !fp ) + return false; + + if( !WriteIncrementalHeader( fp ) ) + { + FileClose( fp ); + return false; + } + + // Write the lights. + int nLights = m_Lights.Count(); + FileWrite( fp, nLights ); + for( int iLight=m_Lights.Head(); iLight != m_Lights.InvalidIndex(); iLight = m_Lights.Next( iLight ) ) + { + CIncLight *pLight = m_Lights[iLight]; + + FileWrite( fp, pLight->m_Light ); + + int nFaces = pLight->m_LightFaces.Count(); + FileWrite( fp, nFaces ); + for( int iFace=pLight->m_LightFaces.Head(); iFace != pLight->m_LightFaces.InvalidIndex(); iFace = pLight->m_LightFaces.Next( iFace ) ) + { + CLightFace *pFace = pLight->m_LightFaces[iFace]; + + FileWrite( fp, pFace->m_FaceIndex ); + + int dataSize = pFace->m_CompressedData.TellPut(); + FileWrite( fp, dataSize ); + + pFace->m_CompressedData.SeekGet( CUtlBuffer::SEEK_HEAD, 0 ); + while( dataSize ) + { + --dataSize; + FileWrite( fp, pFace->m_CompressedData.GetUnsignedChar() ); + } + } + } + + + FileClose( fp ); + return !FileError(); +} + + +void CIncremental::LinkLightsToFaces( CUtlVector &faceLights ) +{ + faceLights.SetSize( numfaces ); + + for( int iLight=m_Lights.Head(); iLight != m_Lights.InvalidIndex(); iLight = m_Lights.Next( iLight ) ) + { + CIncLight *pLight = m_Lights[iLight]; + + for( int iFace=pLight->m_LightFaces.Head(); iFace != pLight->m_LightFaces.InvalidIndex(); iFace = pLight->m_LightFaces.Next( iFace ) ) + { + CLightFace *pFace = pLight->m_LightFaces[iFace]; + + if( m_FacesTouched[pFace->m_FaceIndex] ) + faceLights[ pFace->m_FaceIndex ].AddToTail( pFace ); + } + } +} + + +// ------------------------------------------------------------------ // +// CIncLight +// ------------------------------------------------------------------ // + +CIncLight::CIncLight() +{ + memset( m_pCachedFaces, 0, sizeof(m_pCachedFaces) ); + InitializeCriticalSection( &m_CS ); +} + + +CIncLight::~CIncLight() +{ + m_LightFaces.PurgeAndDeleteElements(); + DeleteCriticalSection( &m_CS ); +} + + +CLightFace* CIncLight::FindOrCreateLightFace( int iFace, int lmSize, bool *bNew ) +{ + if( bNew ) + *bNew = false; + + + // Look for it. + for( int i=m_LightFaces.Head(); i != m_LightFaces.InvalidIndex(); i=m_LightFaces.Next(i) ) + { + CLightFace *pFace = m_LightFaces[i]; + + if( pFace->m_FaceIndex == iFace ) + { + assert( pFace->m_LightValues.Count() == lmSize ); + return pFace; + } + } + + // Ok, create one. + CLightFace *pFace = new CLightFace; + pFace->m_LightFacesIndex = m_LightFaces.AddToTail( pFace ); + pFace->m_pLight = this; + + pFace->m_FaceIndex = iFace; + pFace->m_LightValues.SetSize( lmSize ); + memset( pFace->m_LightValues.Base(), 0, sizeof( CLightValue ) * lmSize ); + + if( bNew ) + *bNew = true; + + return pFace; +} + + -- cgit v1.2.3