vtf: 7.5 version support ( fixes #83 )

This commit is contained in:
nillerusr 2022-07-28 14:32:38 +03:00
parent 6bc71d1491
commit eb78802b5d
4 changed files with 105 additions and 70 deletions

View File

@ -784,6 +784,50 @@ bool ResampleRGB323232F( const ResampleInfo_t& info )
return true;
}
bool ResampleRGBA32323232F( const ResampleInfo_t& info )
{
// HDRFIXME: This is some lame shit right here. (We need to get NICE working, etc, etc.)
// Make sure everything is power of two.
Assert( ( info.m_nSrcWidth & ( info.m_nSrcWidth - 1 ) ) == 0 );
Assert( ( info.m_nSrcHeight & ( info.m_nSrcHeight - 1 ) ) == 0 );
Assert( ( info.m_nDestWidth & ( info.m_nDestWidth - 1 ) ) == 0 );
Assert( ( info.m_nDestHeight & ( info.m_nDestHeight - 1 ) ) == 0 );
// Make sure that we aren't upscaling the image. . .we don't support that very well.
Assert( info.m_nSrcWidth >= info.m_nDestWidth );
Assert( info.m_nSrcHeight >= info.m_nDestHeight );
int nSampleWidth = info.m_nSrcWidth / info.m_nDestWidth;
int nSampleHeight = info.m_nSrcHeight / info.m_nDestHeight;
float *pSrc = ( float * )info.m_pSrc;
float *pDst = ( float * )info.m_pDest;
for( int y = 0; y < info.m_nDestHeight; y++ )
{
for( int x = 0; x < info.m_nDestWidth; x++ )
{
float accum[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
for( int nSampleY = 0; nSampleY < nSampleHeight; nSampleY++ )
{
for( int nSampleX = 0; nSampleX < nSampleWidth; nSampleX++ )
{
accum[0] += pSrc[((x*nSampleWidth+nSampleX)+(y*nSampleHeight+nSampleY)*info.m_nSrcWidth)*4+0];
accum[1] += pSrc[((x*nSampleWidth+nSampleX)+(y*nSampleHeight+nSampleY)*info.m_nSrcWidth)*4+1];
accum[2] += pSrc[((x*nSampleWidth+nSampleX)+(y*nSampleHeight+nSampleY)*info.m_nSrcWidth)*4+2];
accum[3] += pSrc[((x*nSampleWidth+nSampleX)+(y*nSampleHeight+nSampleY)*info.m_nSrcWidth)*4+3];
}
}
for( int i = 0; i < 4; i++ )
{
accum[i] /= ( nSampleWidth * nSampleHeight );
pDst[(x+y*info.m_nDestWidth)*4+i] = accum[i];
}
}
}
return true;
}
//-----------------------------------------------------------------------------
// Generates mipmap levels
//-----------------------------------------------------------------------------

View File

@ -459,6 +459,7 @@ namespace ImageLoader
bool ResampleRGBA8888( const ResampleInfo_t &info );
bool ResampleRGBA16161616( const ResampleInfo_t &info );
bool ResampleRGB323232F( const ResampleInfo_t &info );
bool ResampleRGBA32323232F( const ResampleInfo_t& info );
void ConvertNormalMapRGBA8888ToDUDVMapUVLX8888( const unsigned char *src, int width, int height,
unsigned char *dst_ );

View File

@ -440,7 +440,7 @@ bool GetVTFPreload360Data( const char *pDebugName, CUtlBuffer &fileBufferIn, CUt
// version number for the disk texture cache
#define VTF_MAJOR_VERSION 7
#define VTF_MINOR_VERSION 4
#define VTF_MINOR_VERSION 5
//-----------------------------------------------------------------------------
// !!!!CRITICAL!!!! BEFORE YOU CHANGE THE FORMAT

View File

@ -190,7 +190,11 @@ IVTFTexture *CreateVTFTexture()
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 );
case 3:
return sizeof( VTFFileHeaderV7_3_t ) + sizeof( ResourceEntryInfo ) * MAX_RSRC_DICTIONARY_ENTRIES;
case 4:
case VTF_MINOR_VERSION:
int size1 = sizeof( VTFFileHeader_t );
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" );
return false;
if ( !IsMultipleOf4( nWidth ) || !IsMultipleOf4( nHeight ) || !IsMultipleOf4( nDepth ) )
{
Warning( "Image dimensions must be multiple of 4!\n" );
return false;
}
}
if ( fmt == IMAGE_FORMAT_DEFAULT )
@ -676,89 +685,65 @@ bool CVTFTexture::LoadImageData( CUtlBuffer &buf, const VTFFileHeader_t &header,
int iImageSize = ComputeFaceSize();
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 ) )
return false;
// We may only have part of the data available--if so we will stream in the rest later.
// If we have the data available but we're ignoring it (for example during development), then we
// 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 )
{
// Don't need to subtract nSkipMipLevels: m_nMipCount has subtracted that above--assuming this assert doesn't fire.
Assert( m_nMipCount == header.numMipLevels - nSkipMipLevels );
nLastAvailableMip = Min( nLastAvailableMip, STREAMING_START_MIPMAP - 1 );
}
// Valid settings?
Assert( nFirstAvailableMip >= 0 && nFirstAvailableMip <= nLastAvailableMip && nLastAvailableMip < m_nMipCount );
// Store the clamp settings
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
// 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 ) )
{
int nBytesRemaining = buf.TellMaxPut() - buf.TellGet();
int nFileSize = ComputeFaceSize( nSkipMipLevels ) * m_nFaceCount * m_nFrameCount;
if ( nBytesRemaining == nFileSize )
{
bNoSkip = true;
}
}
int nGet = buf.TellGet();
retryCubemapLoad:
for (int iMip = m_nMipCount; --iMip >= 0; )
{
// NOTE: This is for older versions...
if (header.numMipLevels - nSkipMipLevels <= iMip)
if ( header.numMipLevels - nSkipMipLevels <= iMip )
continue;
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 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() );
unsigned char *pMipBits = ImageData( iFrame, iFace, iMip );
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 )
@ -912,7 +897,7 @@ bool CVTFTexture::SetupByteSwap( CUtlBuffer &buf )
static bool ReadHeaderFromBufferPastBaseHeader( CUtlBuffer &buf, VTFFileHeader_t &header )
{
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) );
}
@ -974,7 +959,7 @@ bool CVTFTexture::ReadHeader( CUtlBuffer &buf, VTFFileHeader_t &header )
{
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() );
}
@ -1021,6 +1006,7 @@ bool CVTFTexture::ReadHeader( CUtlBuffer &buf, VTFFileHeader_t &header )
case 3:
header.flags &= VERSIONED_VTF_FLAGS_MASK_7_3;
// fall-through
case 4:
case VTF_MINOR_VERSION:
break;
}
@ -2528,7 +2514,7 @@ void CVTFTexture::GenerateMipmaps()
// 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?
ImageLoader::ResampleInfo_t info;
@ -2667,7 +2653,11 @@ void CVTFTexture::GenerateMipmaps()
info.m_pSrc = pSrcLevel;
info.m_pDest = pDstLevel;
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 );
}