mirror of
https://github.com/nillerusr/source-engine.git
synced 2024-12-22 14:16:50 +00:00
vtf: 7.5 version support ( fixes #83 )
This commit is contained in:
parent
6bc71d1491
commit
eb78802b5d
@ -784,6 +784,50 @@ bool ResampleRGB323232F( const ResampleInfo_t& info )
|
|||||||
return true;
|
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
|
// Generates mipmap levels
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -459,6 +459,7 @@ namespace ImageLoader
|
|||||||
bool ResampleRGBA8888( const ResampleInfo_t &info );
|
bool ResampleRGBA8888( const ResampleInfo_t &info );
|
||||||
bool ResampleRGBA16161616( const ResampleInfo_t &info );
|
bool ResampleRGBA16161616( const ResampleInfo_t &info );
|
||||||
bool ResampleRGB323232F( 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,
|
void ConvertNormalMapRGBA8888ToDUDVMapUVLX8888( const unsigned char *src, int width, int height,
|
||||||
unsigned char *dst_ );
|
unsigned char *dst_ );
|
||||||
|
@ -440,7 +440,7 @@ bool GetVTFPreload360Data( const char *pDebugName, CUtlBuffer &fileBufferIn, CUt
|
|||||||
|
|
||||||
// version number for the disk texture cache
|
// version number for the disk texture cache
|
||||||
#define VTF_MAJOR_VERSION 7
|
#define VTF_MAJOR_VERSION 7
|
||||||
#define VTF_MINOR_VERSION 4
|
#define VTF_MINOR_VERSION 5
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// !!!!CRITICAL!!!! BEFORE YOU CHANGE THE FORMAT
|
// !!!!CRITICAL!!!! BEFORE YOU CHANGE THE FORMAT
|
||||||
|
128
vtf/vtf.cpp
128
vtf/vtf.cpp
@ -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.
|
|
||||||
// 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)
|
// 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
|
// 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; )
|
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 );
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user