summaryrefslogtreecommitdiff
path: root/vtf/vtf_x360.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /vtf/vtf_x360.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'vtf/vtf_x360.cpp')
-rw-r--r--vtf/vtf_x360.cpp347
1 files changed, 347 insertions, 0 deletions
diff --git a/vtf/vtf_x360.cpp b/vtf/vtf_x360.cpp
new file mode 100644
index 0000000..d4a8e56
--- /dev/null
+++ b/vtf/vtf_x360.cpp
@@ -0,0 +1,347 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: The 360 VTF file format I/O class to help simplify access to 360 VTF files.
+// 360 Formatted VTF's are stored ascending 1x1 up to NxN. Disk format and unserialized
+// formats are expected to be the same.
+//
+//=====================================================================================//
+
+#include "bitmap/imageformat.h"
+#include "cvtf.h"
+#include "utlbuffer.h"
+#include "tier0/dbg.h"
+#include "tier0/mem.h"
+#include "tier2/fileutils.h"
+#include "byteswap.h"
+#include "filesystem.h"
+#include "mathlib/mathlib.h"
+#include "tier1/lzmaDecoder.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------------
+// Callback for UpdateOrCreate utility function - swaps a vtf file.
+//-----------------------------------------------------------------------------
+static bool VTFCreateCallback( const char *pSourceName, const char *pTargetName, const char *pPathID, void *pExtraData )
+{
+ // Generate the file
+ CUtlBuffer sourceBuf;
+ CUtlBuffer targetBuf;
+ bool bOk = g_pFullFileSystem->ReadFile( pSourceName, pPathID, sourceBuf );
+ if ( bOk )
+ {
+ bOk = ConvertVTFTo360Format( pSourceName, sourceBuf, targetBuf, NULL );
+ if ( bOk )
+ {
+ bOk = g_pFullFileSystem->WriteFile( pTargetName, pPathID, targetBuf );
+ }
+ }
+
+ if ( !bOk )
+ {
+ Warning( "Failed to create %s\n", pTargetName );
+ }
+ return bOk;
+}
+
+//-----------------------------------------------------------------------------
+// Calls utility function to create .360 version of a vtf file.
+//-----------------------------------------------------------------------------
+int CVTFTexture::UpdateOrCreate( const char *pFilename, const char *pPathID, bool bForce )
+{
+ return ::UpdateOrCreate( pFilename, NULL, 0, pPathID, VTFCreateCallback, bForce, NULL );
+}
+
+//-----------------------------------------------------------------------------
+// Determine size of file, possibly smaller if skipping top mip levels.
+//-----------------------------------------------------------------------------
+int CVTFTexture::FileSize( bool bPreloadOnly, int nMipSkipCount ) const
+{
+ if ( bPreloadOnly )
+ {
+ // caller wants size of preload
+ return m_iPreloadDataSize;
+ }
+
+ const ResourceEntryInfo *pEntryInfo = FindResourceEntryInfo( VTF_LEGACY_RSRC_IMAGE );
+ if ( !pEntryInfo )
+ {
+ // has to exist
+ Assert( 0 );
+ return 0;
+ }
+ int iImageDataOffset = pEntryInfo->resData;
+
+ if ( m_iCompressedSize )
+ {
+ // file is compressed, mip skipping is non-applicable at this stage
+ return iImageDataOffset + m_iCompressedSize;
+ }
+
+ // caller gets file size, possibly truncated due to mip skipping
+ int nFaceSize = ComputeFaceSize( nMipSkipCount );
+ return iImageDataOffset + m_nFrameCount * m_nFaceCount * nFaceSize;
+}
+
+//-----------------------------------------------------------------------------
+// Unserialization of image data from buffer
+//-----------------------------------------------------------------------------
+bool CVTFTexture::LoadImageData( CUtlBuffer &buf, bool bBufferIsVolatile, int nMipSkipCount )
+{
+ ResourceEntryInfo *pEntryInfo = FindResourceEntryInfo( VTF_LEGACY_RSRC_IMAGE );
+ if ( !pEntryInfo )
+ {
+ // has to exist
+ Assert( 0 );
+ return false;
+ }
+ int iImageDataOffset = pEntryInfo->resData;
+
+ // Fix up the mip count + size based on how many mip levels we skip...
+ if ( nMipSkipCount > 0 )
+ {
+ if ( nMipSkipCount >= m_nMipCount )
+ {
+ nMipSkipCount = 0;
+ }
+ ComputeMipLevelDimensions( nMipSkipCount, &m_nWidth, &m_nHeight, &m_nDepth );
+ m_nMipCount -= nMipSkipCount;
+ m_nMipSkipCount += nMipSkipCount;
+ }
+
+ int iImageSize = ComputeFaceSize();
+ iImageSize = m_nFrameCount * m_nFaceCount * iImageSize;
+
+ // seek to start of image data
+ // The mip levels are stored on disk ascending from smallest (1x1) to largest (NxN) to allow for picmip truncated reads
+ buf.SeekGet( CUtlBuffer::SEEK_HEAD, iImageDataOffset );
+
+ CLZMA lzma;
+ if ( m_iCompressedSize )
+ {
+ unsigned char *pCompressedData = (unsigned char *)buf.PeekGet();
+ if ( !lzma.IsCompressed( pCompressedData ) )
+ {
+ // huh? header says it was compressed
+ Assert( 0 );
+ return false;
+ }
+
+ // have to decode entire image
+ unsigned int originalSize = lzma.GetActualSize( pCompressedData );
+ AllocateImageData( originalSize );
+ unsigned int outputLength = lzma.Uncompress( pCompressedData, m_pImageData );
+ return ( outputLength == originalSize );
+ }
+
+ bool bOK;
+ if ( bBufferIsVolatile )
+ {
+ AllocateImageData( iImageSize );
+ buf.Get( m_pImageData, iImageSize );
+ bOK = buf.IsValid();
+ }
+ else
+ {
+ // safe to alias
+ m_pImageData = (unsigned char *)buf.PeekGet( iImageSize, 0 );
+ bOK = ( m_pImageData != NULL );
+ }
+
+ return bOK;
+}
+
+//-----------------------------------------------------------------------------
+// Unserialization
+//-----------------------------------------------------------------------------
+bool CVTFTexture::ReadHeader( CUtlBuffer &buf, VTFFileHeaderX360_t &header )
+{
+ memset( &header, 0, sizeof( VTFFileHeaderX360_t ) );
+ buf.GetObjects( &header );
+ if ( !buf.IsValid() )
+ {
+ Warning( "*** Error getting header from a X360 VTF file.\n" );
+ return false;
+ }
+
+ // Validity check
+ if ( Q_strncmp( header.fileTypeString, "VTFX", 4 ) )
+ {
+ Warning( "*** Tried to load a PC VTF file as a X360 VTF file!\n" );
+ return false;
+ }
+
+ if ( header.version[0] != VTF_X360_MAJOR_VERSION && header.version[1] != VTF_X360_MINOR_VERSION )
+ {
+ Warning( "*** Encountered X360 VTF file with an invalid version!\n" );
+ return false;
+ }
+
+ if ( ( header.flags & TEXTUREFLAGS_ENVMAP ) && ( header.width != header.height ) )
+ {
+ Warning( "*** Encountered X360 VTF non-square cubemap!\n" );
+ return false;
+ }
+
+ if ( ( header.flags & TEXTUREFLAGS_ENVMAP ) && ( header.depth != 1 ) )
+ {
+ Warning( "*** Encountered X360 VTF volume texture cubemap!\n" );
+ return false;
+ }
+
+ if ( header.width <= 0 || header.height <= 0 || header.depth <= 0 )
+ {
+ Warning( "*** Encountered X360 VTF invalid texture size!\n" );
+ return false;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Unserialization. Can optionally alias image components to a non-volatile buffer,
+// which prevents unecessary copies. Disk format and memory format of the image
+// components are explicitly the same.
+//-----------------------------------------------------------------------------
+bool CVTFTexture::UnserializeFromBuffer( CUtlBuffer &buf, bool bBufferIsVolatile, bool bHeaderOnly, bool bPreloadOnly, int nMipSkipCount )
+{
+ VTFFileHeaderX360_t header;
+ ResourceEntryInfo *pEntryInfo;
+
+ if ( !ReadHeader( buf, header ) )
+ {
+ return false;
+ }
+
+ // must first release any prior owned memory or reset aliases, otherwise corruption if types intermingled
+ ReleaseImageMemory();
+ ReleaseResources();
+
+ m_nVersion[0] = header.version[0];
+ m_nVersion[1] = header.version[1];
+
+ m_nWidth = header.width;
+ m_nHeight = header.height;
+ m_nDepth = header.depth;
+ m_Format = header.imageFormat;
+ m_nFlags = header.flags;
+ m_nFrameCount = header.numFrames;
+ m_nFaceCount = ( m_nFlags & TEXTUREFLAGS_ENVMAP ) ? CUBEMAP_FACE_COUNT-1 : 1;
+ m_nMipCount = ComputeMipCount();
+ m_nMipSkipCount = header.mipSkipCount;
+ m_vecReflectivity = header.reflectivity;
+ m_flBumpScale = header.bumpScale;
+ m_iPreloadDataSize = header.preloadDataSize;
+ m_iCompressedSize = header.compressedSize;
+
+ m_LowResImageFormat = IMAGE_FORMAT_RGB888;
+ if ( header.lowResImageSample[3] )
+ {
+ // nonzero denotes validity of color value
+ m_nLowResImageWidth = 1;
+ m_nLowResImageHeight = 1;
+ *(unsigned int *)m_LowResImageSample = *(unsigned int *)header.lowResImageSample;
+ }
+ else
+ {
+ m_nLowResImageWidth = 0;
+ m_nLowResImageHeight = 0;
+ *(unsigned int *)m_LowResImageSample = 0;
+ }
+
+ // 360 always has the image resource
+ Assert( header.numResources >= 1 );
+ m_arrResourcesInfo.SetCount( header.numResources );
+ m_arrResourcesData.SetCount( header.numResources );
+
+ // Read the dictionary of resources info
+ buf.Get( m_arrResourcesInfo.Base(), m_arrResourcesInfo.Count() * sizeof( ResourceEntryInfo ) );
+ if ( !buf.IsValid() )
+ {
+ return false;
+ }
+
+ pEntryInfo = FindResourceEntryInfo( VTF_LEGACY_RSRC_IMAGE );
+ if ( !pEntryInfo )
+ {
+ // not optional, has to be present
+ Assert( 0 );
+ return false;
+ }
+
+ if ( bHeaderOnly )
+ {
+ // caller wants header components only
+ // resource data chunks are NOT unserialized!
+ return true;
+ }
+
+ if ( !LoadNewResources( buf ) )
+ {
+ return false;
+ }
+
+ if ( bPreloadOnly )
+ {
+ // caller wants preload portion only, everything up to the image
+ return true;
+ }
+
+ if ( !LoadImageData( buf, bBufferIsVolatile, nMipSkipCount ) )
+ {
+ return false;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Discard image data to free up memory.
+//-----------------------------------------------------------------------------
+void CVTFTexture::ReleaseImageMemory()
+{
+ // valid sizes identify locally owned memory
+ if ( m_nImageAllocSize )
+ {
+ delete [] m_pImageData;
+ m_nImageAllocSize = 0;
+ }
+
+ // block pointers could be owned or aliased, always clear
+ // ensures other caller's don't free an aliased pointer
+ m_pImageData = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Attributes...
+//-----------------------------------------------------------------------------
+bool CVTFTexture::IsPreTiled() const
+{
+ return false;
+}
+
+int CVTFTexture::MappingWidth() const
+{
+ return m_nWidth << m_nMipSkipCount;
+}
+
+int CVTFTexture::MappingHeight() const
+{
+ return m_nHeight << m_nMipSkipCount;
+}
+
+int CVTFTexture::MappingDepth() const
+{
+ return m_nDepth << m_nMipSkipCount;
+}
+
+int CVTFTexture::MipSkipCount() const
+{
+ return m_nMipSkipCount;
+}
+
+unsigned char *CVTFTexture::LowResImageSample()
+{
+ return &m_LowResImageSample[0];
+}