|
|
@ -190,7 +190,11 @@ IVTFTexture *CreateVTFTexture() |
|
|
|
|
|
|
|
|
|
|
|
void DestroyVTFTexture( IVTFTexture *pTexture ) |
|
|
|
void DestroyVTFTexture( IVTFTexture *pTexture ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
delete pTexture; |
|
|
|
CVTFTexture *pTex = static_cast<CVTFTexture*>(pTexture); |
|
|
|
|
|
|
|
if ( pTex ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
delete pTex; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
@ -220,6 +224,7 @@ int VTFFileHeaderSize( int nMajorVersion, int nMinorVersion ) |
|
|
|
return sizeof( VTFFileHeaderV7_2_t ); |
|
|
|
return sizeof( VTFFileHeaderV7_2_t ); |
|
|
|
case 3: |
|
|
|
case 3: |
|
|
|
return sizeof( VTFFileHeaderV7_3_t ) + sizeof( ResourceEntryInfo ) * MAX_RSRC_DICTIONARY_ENTRIES; |
|
|
|
return sizeof( VTFFileHeaderV7_3_t ) + sizeof( ResourceEntryInfo ) * MAX_RSRC_DICTIONARY_ENTRIES; |
|
|
|
|
|
|
|
case 4: |
|
|
|
case VTF_MINOR_VERSION: |
|
|
|
case VTF_MINOR_VERSION: |
|
|
|
int size1 = sizeof( VTFFileHeader_t ); |
|
|
|
int size1 = sizeof( VTFFileHeader_t ); |
|
|
|
int size2 = sizeof( ResourceEntryInfo ) * MAX_RSRC_DICTIONARY_ENTRIES; |
|
|
|
int size2 = sizeof( ResourceEntryInfo ) * MAX_RSRC_DICTIONARY_ENTRIES; |
|
|
@ -388,10 +393,14 @@ bool CVTFTexture::Init( int nWidth, int nHeight, int nDepth, ImageFormat fmt, in |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if ( !IsMultipleOf4( nWidth ) || !IsMultipleOf4( nHeight ) || !IsMultipleOf4( nDepth ) ) |
|
|
|
if ( ( fmt == IMAGE_FORMAT_DXT1 ) || ( fmt == IMAGE_FORMAT_DXT3 ) || ( fmt == IMAGE_FORMAT_DXT5 ) || |
|
|
|
|
|
|
|
( fmt == IMAGE_FORMAT_DXT1_RUNTIME ) || ( fmt == IMAGE_FORMAT_DXT5_RUNTIME ) ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
Warning( "Image dimensions must be multiple of 4!\n" ); |
|
|
|
if ( !IsMultipleOf4( nWidth ) || !IsMultipleOf4( nHeight ) || !IsMultipleOf4( nDepth ) ) |
|
|
|
return false; |
|
|
|
{ |
|
|
|
|
|
|
|
Warning( "Image dimensions must be multiple of 4!\n" ); |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if ( fmt == IMAGE_FORMAT_DEFAULT ) |
|
|
|
if ( fmt == IMAGE_FORMAT_DEFAULT ) |
|
|
@ -676,89 +685,65 @@ bool CVTFTexture::LoadImageData( CUtlBuffer &buf, const VTFFileHeader_t &header, |
|
|
|
int iImageSize = ComputeFaceSize(); |
|
|
|
int iImageSize = ComputeFaceSize(); |
|
|
|
iImageSize *= m_nFaceCount * m_nFrameCount; |
|
|
|
iImageSize *= m_nFaceCount * m_nFrameCount; |
|
|
|
|
|
|
|
|
|
|
|
// For backwards compatibility, we don't read in the spheremap fallback on
|
|
|
|
|
|
|
|
// older format .VTF files...
|
|
|
|
|
|
|
|
int nFacesToRead = m_nFaceCount; |
|
|
|
|
|
|
|
if ( IsCubeMap() ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if ((header.version[0] == 7) && (header.version[1] < 1)) |
|
|
|
|
|
|
|
nFacesToRead = 6; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Even if we are preloading partial data, always do the full allocation here. We'll use LOD clamping to ensure we only
|
|
|
|
|
|
|
|
// reference data that is available.
|
|
|
|
|
|
|
|
if ( !AllocateImageData( iImageSize ) ) |
|
|
|
if ( !AllocateImageData( iImageSize ) ) |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
|
|
// We may only have part of the data available--if so we will stream in the rest later.
|
|
|
|
// NOTE: The mip levels are stored ascending from smallest (1x1) to largest (NxN)
|
|
|
|
// If we have the data available but we're ignoring it (for example during development), then we
|
|
|
|
// in order to allow for truncated reads of the minimal required data
|
|
|
|
// need to skip over the data we're ignoring below, otherwise we'll be sad pandas.
|
|
|
|
|
|
|
|
bool bMipDataPresent = true; |
|
|
|
|
|
|
|
int nFirstAvailableMip = 0; |
|
|
|
|
|
|
|
int nLastAvailableMip = m_nMipCount - 1; |
|
|
|
|
|
|
|
TextureStreamSettings_t const *pStreamSettings = ( TextureStreamSettings_t const * ) GetResourceData( VTF_RSRC_TEXTURE_STREAM_SETTINGS, NULL ); |
|
|
|
|
|
|
|
if ( pStreamSettings ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
nFirstAvailableMip = Max( 0, pStreamSettings->m_firstAvailableMip - nSkipMipLevels ); |
|
|
|
|
|
|
|
nLastAvailableMip = Max( 0, pStreamSettings->m_lastAvailableMip - nSkipMipLevels ); |
|
|
|
|
|
|
|
bMipDataPresent = false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// If we have coarse mips but not the fine mips (yet)
|
|
|
|
|
|
|
|
if ( ( header.flags & TEXTUREFLAGS_STREAMABLE ) == TEXTUREFLAGS_STREAMABLE_COARSE ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
nFirstAvailableMip = Max( 0, Max( nFirstAvailableMip, STREAMING_START_MIPMAP ) - nSkipMipLevels ); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ( header.flags & TEXTUREFLAGS_STREAMABLE_FINE ) |
|
|
|
// NOTE: I checked in a bad version 4 where it stripped out the spheremap.
|
|
|
|
|
|
|
|
// To make it all work, need to check for that bad case.
|
|
|
|
|
|
|
|
bool bNoSkip = false; |
|
|
|
|
|
|
|
if ( IsCubeMap() && ( header.version[0] == 7 ) && ( header.version[1] == 4 ) ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
// Don't need to subtract nSkipMipLevels: m_nMipCount has subtracted that above--assuming this assert doesn't fire.
|
|
|
|
int nBytesRemaining = buf.TellMaxPut() - buf.TellGet(); |
|
|
|
Assert( m_nMipCount == header.numMipLevels - nSkipMipLevels ); |
|
|
|
int nFileSize = ComputeFaceSize( nSkipMipLevels ) * m_nFaceCount * m_nFrameCount; |
|
|
|
nLastAvailableMip = Min( nLastAvailableMip, STREAMING_START_MIPMAP - 1 ); |
|
|
|
if ( nBytesRemaining == nFileSize ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
bNoSkip = true; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Valid settings?
|
|
|
|
int nGet = buf.TellGet(); |
|
|
|
Assert( nFirstAvailableMip >= 0 && nFirstAvailableMip <= nLastAvailableMip && nLastAvailableMip < m_nMipCount ); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Store the clamp settings
|
|
|
|
retryCubemapLoad: |
|
|
|
m_nFinestMipmapLevel = nFirstAvailableMip; |
|
|
|
|
|
|
|
m_nCoarsestMipmapLevel = nLastAvailableMip; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// NOTE: The mip levels are stored ascending from smallest (1x1) to largest (NxN)
|
|
|
|
|
|
|
|
// in order to allow for truncated reads of the minimal required data
|
|
|
|
|
|
|
|
for (int iMip = m_nMipCount; --iMip >= 0; ) |
|
|
|
for (int iMip = m_nMipCount; --iMip >= 0; ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
// NOTE: This is for older versions...
|
|
|
|
// NOTE: This is for older versions...
|
|
|
|
if (header.numMipLevels - nSkipMipLevels <= iMip) |
|
|
|
if ( header.numMipLevels - nSkipMipLevels <= iMip ) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
int iMipSize = ComputeMipSize( iMip ); |
|
|
|
int iMipSize = ComputeMipSize( iMip ); |
|
|
|
|
|
|
|
|
|
|
|
// Skip over any levels we don't have data for--we'll get them later.
|
|
|
|
|
|
|
|
if ( iMip > nLastAvailableMip || iMip < nFirstAvailableMip ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
// If the data is there but we're ignoring it, need to update the get pointer.
|
|
|
|
|
|
|
|
if ( bMipDataPresent ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
for ( int iFrame = 0; iFrame < m_nFrameCount; ++iFrame ) |
|
|
|
|
|
|
|
for ( int iFace = 0; iFace < nFacesToRead; ++iFace ) |
|
|
|
|
|
|
|
buf.SeekGet( CUtlBuffer::SEEK_CURRENT, iMipSize ); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int iFrame = 0; iFrame < m_nFrameCount; ++iFrame) |
|
|
|
for (int iFrame = 0; iFrame < m_nFrameCount; ++iFrame) |
|
|
|
{ |
|
|
|
{ |
|
|
|
for (int iFace = 0; iFace < nFacesToRead; ++iFace) |
|
|
|
for (int iFace = 0; iFace < m_nFaceCount; ++iFace) |
|
|
|
{ |
|
|
|
{ |
|
|
|
// printf("\n tex %p mip %i frame %i face %i size %i buf offset %i", this, iMip, iFrame, iFace, iMipSize, buf.TellGet() );
|
|
|
|
// printf("\n tex %p mip %i frame %i face %i size %i buf offset %i", this, iMip, iFrame, iFace, iMipSize, buf.TellGet() );
|
|
|
|
unsigned char *pMipBits = ImageData( iFrame, iFace, iMip ); |
|
|
|
unsigned char *pMipBits = ImageData( iFrame, iFace, iMip ); |
|
|
|
buf.Get( pMipBits, iMipSize ); |
|
|
|
buf.Get( pMipBits, iMipSize ); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Strip out the spheremap in older versions
|
|
|
|
|
|
|
|
if ( IsCubeMap() && !bNoSkip && ( header.version[0] == 7 ) && ( header.version[1] >= 1 ) && ( header.version[1] < 5 ) ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
buf.SeekGet( CUtlBuffer::SEEK_CURRENT, iMipSize ); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return buf.IsValid(); |
|
|
|
bool bOk = buf.IsValid(); |
|
|
|
|
|
|
|
if ( !bOk && IsCubeMap() && ( header.version[0] == 7 ) && ( header.version[1] <= 4 ) ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if ( !bNoSkip ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
bNoSkip = true; |
|
|
|
|
|
|
|
buf.SeekGet( CUtlBuffer::SEEK_HEAD, nGet ); |
|
|
|
|
|
|
|
goto retryCubemapLoad; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Warning( "** Encountered stale cubemap! Please rebuild the following vtf:\n" ); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return bOk; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void *CVTFTexture::SetResourceData( uint32 eType, void const *pData, size_t nNumBytes ) |
|
|
|
void *CVTFTexture::SetResourceData( uint32 eType, void const *pData, size_t nNumBytes ) |
|
|
@ -912,7 +897,7 @@ bool CVTFTexture::SetupByteSwap( CUtlBuffer &buf ) |
|
|
|
static bool ReadHeaderFromBufferPastBaseHeader( CUtlBuffer &buf, VTFFileHeader_t &header ) |
|
|
|
static bool ReadHeaderFromBufferPastBaseHeader( CUtlBuffer &buf, VTFFileHeader_t &header ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
unsigned char *pBuf = (unsigned char*)(&header) + sizeof(VTFFileBaseHeader_t); |
|
|
|
unsigned char *pBuf = (unsigned char*)(&header) + sizeof(VTFFileBaseHeader_t); |
|
|
|
if ( header.version[1] == VTF_MINOR_VERSION ) |
|
|
|
if ( header.version[1] <= VTF_MINOR_VERSION && header.version[1] >= 4 ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
buf.Get( pBuf, sizeof(VTFFileHeader_t) - sizeof(VTFFileBaseHeader_t) ); |
|
|
|
buf.Get( pBuf, sizeof(VTFFileHeader_t) - sizeof(VTFFileBaseHeader_t) ); |
|
|
|
} |
|
|
|
} |
|
|
@ -974,7 +959,7 @@ bool CVTFTexture::ReadHeader( CUtlBuffer &buf, VTFFileHeader_t &header ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
m_Swap.SwapFieldsToTargetEndian( (VTFFileHeaderV7_3_t*)buf.PeekGet() ); |
|
|
|
m_Swap.SwapFieldsToTargetEndian( (VTFFileHeaderV7_3_t*)buf.PeekGet() ); |
|
|
|
} |
|
|
|
} |
|
|
|
else if ( baseHeader.version[1] == VTF_MINOR_VERSION ) |
|
|
|
else if ( baseHeader.version[1] >= 4 && baseHeader.version[1] <= VTF_MINOR_VERSION ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
m_Swap.SwapFieldsToTargetEndian( (VTFFileHeader_t*)buf.PeekGet() ); |
|
|
|
m_Swap.SwapFieldsToTargetEndian( (VTFFileHeader_t*)buf.PeekGet() ); |
|
|
|
} |
|
|
|
} |
|
|
@ -1021,6 +1006,7 @@ bool CVTFTexture::ReadHeader( CUtlBuffer &buf, VTFFileHeader_t &header ) |
|
|
|
case 3: |
|
|
|
case 3: |
|
|
|
header.flags &= VERSIONED_VTF_FLAGS_MASK_7_3; |
|
|
|
header.flags &= VERSIONED_VTF_FLAGS_MASK_7_3; |
|
|
|
// fall-through
|
|
|
|
// fall-through
|
|
|
|
|
|
|
|
case 4: |
|
|
|
case VTF_MINOR_VERSION: |
|
|
|
case VTF_MINOR_VERSION: |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
@ -2528,7 +2514,7 @@ void CVTFTexture::GenerateMipmaps() |
|
|
|
// return;
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
Assert( m_Format == IMAGE_FORMAT_RGBA8888 || m_Format == IMAGE_FORMAT_RGB323232F ); |
|
|
|
Assert( m_Format == IMAGE_FORMAT_RGBA8888 || m_Format == IMAGE_FORMAT_RGB323232F || m_Format == IMAGE_FORMAT_RGBA32323232F ); |
|
|
|
|
|
|
|
|
|
|
|
// FIXME: Should we be doing anything special for normalmaps other than a final normalization pass?
|
|
|
|
// FIXME: Should we be doing anything special for normalmaps other than a final normalization pass?
|
|
|
|
ImageLoader::ResampleInfo_t info; |
|
|
|
ImageLoader::ResampleInfo_t info; |
|
|
@ -2667,7 +2653,11 @@ void CVTFTexture::GenerateMipmaps() |
|
|
|
info.m_pSrc = pSrcLevel; |
|
|
|
info.m_pSrc = pSrcLevel; |
|
|
|
info.m_pDest = pDstLevel; |
|
|
|
info.m_pDest = pDstLevel; |
|
|
|
ComputeMipLevelDimensions( nSrcMipLevel, &info.m_nSrcWidth, &info.m_nSrcHeight, &info.m_nSrcDepth ); |
|
|
|
ComputeMipLevelDimensions( nSrcMipLevel, &info.m_nSrcWidth, &info.m_nSrcHeight, &info.m_nSrcDepth ); |
|
|
|
if( m_Format == IMAGE_FORMAT_RGB323232F ) |
|
|
|
if( m_Format == IMAGE_FORMAT_RGBA32323232F ) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
ImageLoader::ResampleRGBA32323232F( info ); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if( m_Format == IMAGE_FORMAT_RGB323232F ) |
|
|
|
{ |
|
|
|
{ |
|
|
|
ImageLoader::ResampleRGB323232F( info ); |
|
|
|
ImageLoader::ResampleRGB323232F( info ); |
|
|
|
} |
|
|
|
} |
|
|
|