summaryrefslogtreecommitdiff
path: root/vguimatsurface/TextureDictionary.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 /vguimatsurface/TextureDictionary.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'vguimatsurface/TextureDictionary.cpp')
-rw-r--r--vguimatsurface/TextureDictionary.cpp991
1 files changed, 991 insertions, 0 deletions
diff --git a/vguimatsurface/TextureDictionary.cpp b/vguimatsurface/TextureDictionary.cpp
new file mode 100644
index 0000000..d8fe072
--- /dev/null
+++ b/vguimatsurface/TextureDictionary.cpp
@@ -0,0 +1,991 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Contains all texture state for the material system surface to use
+//
+//===========================================================================//
+
+#include "bitmap/imageformat.h"
+#include "TextureDictionary.h"
+#include "utllinkedlist.h"
+#include "checksum_crc.h"
+#include "materialsystem/imaterial.h"
+#include "vguimatsurface.h"
+#include "materialsystem/imaterialsystem.h"
+#include "tier0/dbg.h"
+#include "KeyValues.h"
+#include "pixelwriter.h"
+#include "materialsystem/imaterialvar.h"
+#include "materialsystem/itexture.h"
+#include "vtf/vtf.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#define TEXTURE_ID_UNKNOWN -1
+
+class CMatSystemTexture;
+
+// Case-sensitive string checksum
+static CRC32_t Texture_CRCName( const char *string )
+{
+ CRC32_t crc;
+
+ CRC32_Init( &crc );
+ CRC32_ProcessBuffer( &crc, (void *)string, strlen( string ) );
+ CRC32_Final( &crc );
+
+ return crc;
+}
+
+class CFontTextureRegen;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CMatSystemTexture
+{
+public:
+ CMatSystemTexture( void );
+ ~CMatSystemTexture( void );
+
+ void SetId( int id ) { m_ID = id; };
+
+ CRC32_t GetCRC() const;
+ void SetCRC( CRC32_t val );
+
+ void SetMaterial( const char *pFileName );
+ void SetMaterial( IMaterial *pMaterial );
+
+ void SetTexture( ITexture *pTexture ) { SafeAssign( &m_pOverrideTexture, pTexture ); }
+
+ // This is used when we want different rendering state sharing the same procedural texture (fonts)
+ void ReferenceOtherProcedural( CMatSystemTexture *pTexture, IMaterial *pMaterial );
+
+ IMaterial *GetMaterial() { return m_pMaterial; }
+ int Width() const { return m_iWide; }
+ int Height() const { return m_iTall; }
+
+ bool IsProcedural( void ) const;
+ void SetProcedural( bool proc );
+
+ bool IsReference() const { return m_Flags & TEXTURE_IS_REFERENCE; }
+
+ void SetTextureRGBA( const char* rgba, int wide, int tall, ImageFormat format, bool bFixupTextCoordsForDimensions );
+ void SetSubTextureRGBA( int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall );
+ void SetSubTextureRGBAEx( int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat imageFormat );
+ void UpdateSubTextureRGBA( int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat imageFormat );
+
+ float m_s0, m_t0, m_s1, m_t1;
+
+private:
+ void CreateRegen( int nWidth, int nHeight, ImageFormat format );
+ void ReleaseRegen( void );
+ void CleanUpMaterial();
+
+ ITexture *GetTextureValue( void );
+
+private:
+ enum
+ {
+ TEXTURE_IS_PROCEDURAL = 0x1,
+ TEXTURE_IS_REFERENCE = 0x2
+ };
+
+ CRC32_t m_crcFile;
+ IMaterial *m_pMaterial;
+ ITexture *m_pTexture;
+ ITexture *m_pOverrideTexture;
+
+ int m_iWide;
+ int m_iTall;
+ int m_iInputWide;
+ int m_iInputTall;
+ int m_ID;
+ int m_Flags;
+ CFontTextureRegen *m_pRegen;
+};
+
+
+//-----------------------------------------------------------------------------
+// A class that manages textures used by the material system surface
+//-----------------------------------------------------------------------------
+class CTextureDictionary : public ITextureDictionary
+{
+public:
+ CTextureDictionary( void );
+
+ // Create, destroy textures
+ int CreateTexture( bool procedural = false );
+ int CreateTextureByTexture( ITexture *pTexture, bool procedural = true ) OVERRIDE;
+ void DestroyTexture( int id );
+ void DestroyAllTextures();
+
+ // Is this a valid id?
+ bool IsValidId( int id ) const;
+
+ // Binds a material to a texture
+ virtual void BindTextureToFile( int id, const char *pFileName );
+ virtual void BindTextureToMaterial( int id, IMaterial *pMaterial );
+ virtual void BindTextureToMaterialReference( int id, int referenceId, IMaterial *pMaterial );
+
+ // Texture info
+ IMaterial *GetTextureMaterial( int id );
+ void GetTextureSize(int id, int& iWide, int& iTall );
+ void GetTextureTexCoords( int id, float &s0, float &t0, float &s1, float &t1 );
+
+ void SetTextureRGBA( int id, const char* rgba, int wide, int tall );
+ void SetTextureRGBAEx( int id, const char* rgba, int wide, int tall, ImageFormat format, bool bFixupTextCoordsForDimensions );
+ void SetSubTextureRGBA( int id, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall );
+ void SetSubTextureRGBAEx( int id, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat imageFormat );
+ void UpdateSubTextureRGBA( int id, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat imageFormat );
+
+ int FindTextureIdForTextureFile( char const *pFileName );
+
+public:
+ CMatSystemTexture *GetTexture( int id );
+
+private:
+ CUtlLinkedList< CMatSystemTexture, unsigned short > m_Textures;
+};
+
+static CTextureDictionary s_TextureDictionary;
+
+
+//-----------------------------------------------------------------------------
+// A texture regenerator that holds onto the bits at all times
+//-----------------------------------------------------------------------------
+class CFontTextureRegen : public ITextureRegenerator
+{
+public:
+ CFontTextureRegen( int nWidth, int nHeight, ImageFormat format )
+ {
+ m_nFormat = format;
+ m_nWidth = nWidth;
+ m_nHeight = nHeight;
+
+ if ( IsPC() )
+ {
+ int size = ImageLoader::GetMemRequired( m_nWidth, m_nHeight, 1, m_nFormat, false );
+ m_pTextureBits = new unsigned char[size];
+ memset( m_pTextureBits, 0, size );
+ }
+ else
+ {
+ // will be allocated as needed
+ m_pTextureBits = NULL;
+ }
+ }
+
+ ~CFontTextureRegen( void )
+ {
+ DeleteTextureBits();
+ }
+
+ void UpdateBackingBits( Rect_t &subRect, const unsigned char *pBits, Rect_t &uploadRect, ImageFormat format )
+ {
+ int size = ImageLoader::GetMemRequired( m_nWidth, m_nHeight, 1, m_nFormat, false );
+ if ( IsPC() )
+ {
+ if ( !m_pTextureBits )
+ return;
+ }
+ else
+ {
+ Assert( !m_pTextureBits );
+ m_pTextureBits = new unsigned char[size];
+ memset( m_pTextureBits, 0, size );
+ }
+
+ // Copy subrect into backing bits storage
+ // source data is expected to be in same format as backing bits
+ int y;
+ if ( ImageLoader::SizeInBytes( m_nFormat ) == 4 )
+ {
+ bool bIsInputFullRect = ( subRect.width != uploadRect.width || subRect.height != uploadRect.height );
+ Assert( (subRect.x >= 0) && (subRect.y >= 0) );
+ Assert( (subRect.x + subRect.width <= m_nWidth) && (subRect.y + subRect.height <= m_nHeight) );
+ for ( y=0; y < subRect.height; ++y )
+ {
+ int idx = ( (subRect.y + y) * m_nWidth + subRect.x ) << 2;
+ unsigned int *pDst = (unsigned int*)(&m_pTextureBits[ idx ]);
+ int offset = bIsInputFullRect ? (subRect.y+y)*uploadRect.width + subRect.x : y*uploadRect.width;
+ const unsigned int *pSrc = (const unsigned int *)(&pBits[ offset << 2 ]);
+ ImageLoader::ConvertImageFormat( (const unsigned char *)pSrc, format,(unsigned char *)pDst, m_nFormat, subRect.width, 1 );
+ }
+ }
+ else
+ {
+ // cannot subrect copy when format is not RGBA
+ if ( subRect.width != m_nWidth || subRect.height != m_nHeight )
+ {
+ Assert( 0 );
+ return;
+ }
+ Q_memcpy( m_pTextureBits, pBits, size );
+ }
+ }
+
+ virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pSubRect )
+ {
+ if ( !m_pTextureBits )
+ return;
+
+ Assert( (pVTFTexture->Width() == m_nWidth) && (pVTFTexture->Height() == m_nHeight) );
+
+ int nFormatBytes = ImageLoader::SizeInBytes( m_nFormat );
+ if ( nFormatBytes == 4 )
+ {
+ if ( m_nFormat == pVTFTexture->Format() )
+ {
+ int ymax = pSubRect->y + pSubRect->height;
+ for( int y = pSubRect->y; y < ymax; ++y )
+ {
+ // copy each row across for the update
+ char *pchData = (char *)pVTFTexture->ImageData( 0, 0, 0, 0, y ) + pSubRect->x *nFormatBytes;
+ int size = ImageLoader::GetMemRequired( pSubRect->width, 1, 1, m_nFormat, false );
+ V_memcpy( pchData, m_pTextureBits + (y * m_nWidth + pSubRect->x) * nFormatBytes, size );
+ }
+ }
+ else
+ {
+ // formats don't match so do a pixel by pixel swizel
+ CPixelWriter pixelWriter;
+ pixelWriter.SetPixelMemory(
+ pVTFTexture->Format(),
+ pVTFTexture->ImageData( 0, 0, 0 ),
+ pVTFTexture->RowSizeInBytes( 0 ) );
+
+ // Now upload the part we've been asked for
+ int xmax = pSubRect->x + pSubRect->width;
+ int ymax = pSubRect->y + pSubRect->height;
+ int x, y;
+
+ for( y = pSubRect->y; y < ymax; ++y )
+ {
+ pixelWriter.Seek( pSubRect->x, y );
+ unsigned char *rgba = &m_pTextureBits[ (y * m_nWidth + pSubRect->x) * nFormatBytes ];
+
+ for ( x=pSubRect->x; x < xmax; ++x )
+ {
+ pixelWriter.WritePixel( rgba[0], rgba[1], rgba[2], rgba[3] );
+ rgba += nFormatBytes;
+ }
+ }
+ }
+ }
+ else
+ {
+ // cannot subrect copy when format is not RGBA
+ if ( pSubRect->width != m_nWidth || pSubRect->height != m_nHeight )
+ {
+ Assert( 0 );
+ return;
+ }
+ int size = ImageLoader::GetMemRequired( m_nWidth, m_nHeight, 1, m_nFormat, false );
+ Q_memcpy( pVTFTexture->ImageData( 0, 0, 0 ), m_pTextureBits, size );
+ }
+ }
+
+ virtual void Release()
+ {
+ // Called by the material system when this needs to go away
+ DeleteTextureBits();
+ }
+
+ void DeleteTextureBits()
+ {
+ if ( m_pTextureBits )
+ {
+ delete [] m_pTextureBits;
+ m_pTextureBits = NULL;
+ }
+ }
+
+private:
+ unsigned char *m_pTextureBits;
+ short m_nWidth;
+ short m_nHeight;
+ ImageFormat m_nFormat;
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CMatSystemTexture::CMatSystemTexture( void )
+{
+ m_pMaterial = NULL;
+ m_pTexture = NULL;
+ m_pOverrideTexture = NULL;
+ m_crcFile = (CRC32_t)0;
+ m_iWide = m_iTall = 0;
+ m_s0 = m_t0 = 0;
+ m_s1 = m_t1 = 1;
+
+ m_Flags = 0;
+ m_pRegen = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CMatSystemTexture::~CMatSystemTexture( void )
+{
+ if ( m_pOverrideTexture )
+ {
+ m_pOverrideTexture->Release();
+ m_pOverrideTexture->DeleteIfUnreferenced();
+ m_pOverrideTexture = NULL;
+ }
+
+ CleanUpMaterial();
+}
+
+bool CMatSystemTexture::IsProcedural( void ) const
+{
+ return (m_Flags & TEXTURE_IS_PROCEDURAL) != 0;
+}
+
+void CMatSystemTexture::SetProcedural( bool proc )
+{
+ if (proc)
+ {
+ m_Flags |= TEXTURE_IS_PROCEDURAL;
+ }
+ else
+ {
+ m_Flags &= ~TEXTURE_IS_PROCEDURAL;
+ }
+}
+
+void CMatSystemTexture::CleanUpMaterial()
+{
+ if ( m_pMaterial )
+ {
+ // causes the underlying texture (if unreferenced) to be deleted as well
+ m_pMaterial->DecrementReferenceCount();
+ m_pMaterial->DeleteIfUnreferenced();
+ m_pMaterial = NULL;
+ }
+
+ if ( m_pTexture )
+ {
+ m_pTexture->SetTextureRegenerator( NULL );
+ m_pTexture->DecrementReferenceCount();
+ m_pTexture->DeleteIfUnreferenced();
+ m_pTexture = NULL;
+ }
+
+ ReleaseRegen();
+}
+
+void CMatSystemTexture::CreateRegen( int nWidth, int nHeight, ImageFormat format )
+{
+ Assert( IsProcedural() );
+
+ if ( !m_pRegen )
+ {
+ m_pRegen = new CFontTextureRegen( nWidth, nHeight, format );
+ }
+}
+
+void CMatSystemTexture::ReleaseRegen( void )
+{
+ if (m_pRegen)
+ {
+ if (!IsReference())
+ {
+ delete m_pRegen;
+ }
+
+ m_pRegen = NULL;
+ }
+}
+
+void CMatSystemTexture::SetTextureRGBA( const char *rgba, int wide, int tall, ImageFormat format, bool bFixupTextCoords )
+{
+ Assert( IsProcedural() );
+ if ( !IsProcedural() )
+ return;
+
+ if ( !m_pMaterial )
+ {
+ int width = wide;
+ int height = tall;
+
+ // find the minimum power-of-two to fit this in
+ int i;
+ for ( i = 0; i < 32 ; i++ )
+ {
+ width = (1<<i);
+ if (width >= wide)
+ {
+ break;
+ }
+ }
+
+ for (i = 0; i < 32; i++ )
+ {
+ height= (1<<i);
+ if (height >= tall)
+ {
+ break;
+ }
+ }
+
+ // create a procedural material to fit this texture into
+ static int nTextureId = 0;
+ char pTextureName[64];
+ Q_snprintf( pTextureName, sizeof( pTextureName ), "__vgui_texture_%d", nTextureId );
+ ++nTextureId;
+
+ ITexture *pTexture = g_pMaterialSystem->CreateProceduralTexture(
+ pTextureName,
+ TEXTURE_GROUP_VGUI,
+ width,
+ height,
+ format,
+ TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT |
+ TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_NOLOD |
+ TEXTUREFLAGS_PROCEDURAL | TEXTUREFLAGS_SINGLECOPY | TEXTUREFLAGS_POINTSAMPLE );
+
+ KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
+ pVMTKeyValues->SetInt( "$vertexcolor", 1 );
+ pVMTKeyValues->SetInt( "$vertexalpha", 1 );
+ pVMTKeyValues->SetInt( "$ignorez", 1 );
+ pVMTKeyValues->SetInt( "$no_fullbright", 1 );
+ pVMTKeyValues->SetInt( "$translucent", 1 );
+ pVMTKeyValues->SetString( "$basetexture", pTextureName );
+
+ IMaterial *pMaterial = g_pMaterialSystem->CreateMaterial( pTextureName, pVMTKeyValues );
+ pMaterial->Refresh();
+
+ // Has to happen after the refresh
+ pTexture->DecrementReferenceCount();
+
+ SetMaterial( pMaterial );
+ m_iInputTall = tall;
+ m_iInputWide = wide;
+ if ( bFixupTextCoords && ( wide != width || tall != height ) )
+ {
+ m_s1 = (double)wide / width;
+ m_t1 = (double)tall / height;
+ }
+
+ // undo the extra +1 refCount
+ pMaterial->DecrementReferenceCount();
+ }
+
+ Assert( wide <= m_iWide );
+ Assert( tall <= m_iTall );
+
+ // Just replace the whole thing
+ SetSubTextureRGBAEx( 0, 0, (const unsigned char *)rgba, wide, tall, format );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+ITexture *CMatSystemTexture::GetTextureValue( void )
+{
+ Assert( IsProcedural() );
+ if ( !m_pMaterial )
+ return NULL;
+
+ if ( m_pOverrideTexture )
+ return m_pOverrideTexture;
+
+ return m_pTexture;
+}
+
+void CMatSystemTexture::SetSubTextureRGBA( int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall )
+{
+ SetSubTextureRGBAEx( drawX, drawY, rgba, subTextureWide, subTextureTall, IMAGE_FORMAT_RGBA8888 );
+}
+
+void CMatSystemTexture::SetSubTextureRGBAEx( int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat format )
+{
+ ITexture *pTexture = GetTextureValue();
+ if ( !pTexture )
+ return;
+
+ Assert( IsProcedural() );
+ if ( !IsProcedural() )
+ return;
+
+ Assert( drawX < m_iWide );
+ Assert( drawY < m_iTall );
+ Assert( drawX + subTextureWide <= m_iWide );
+ Assert( drawY + subTextureTall <= m_iTall );
+
+ Assert( m_pRegen );
+
+ Assert( rgba );
+
+ Rect_t subRect;
+ subRect.x = drawX;
+ subRect.y = drawY;
+ subRect.width = subTextureWide;
+ subRect.height = subTextureTall;
+
+ Rect_t textureSize;
+ textureSize.x = 0;
+ textureSize.y = 0;
+ textureSize.width = subTextureWide;
+ textureSize.height = subTextureTall;
+
+
+ m_pRegen->UpdateBackingBits( subRect, rgba, textureSize, format );
+ pTexture->Download( &subRect );
+
+ if ( IsX360() )
+ {
+ // xboxissue - no need to persist "backing bits", saves memory
+ // the texture (commonly font page) "backing bits" are allocated during UpdateBackingBits() which get blitted
+ // into by procedural regeneration in preparation for download() which then subrect blits
+ // out of and into target texture (d3d upload)
+ // the "backing bits" are then no longer required
+ m_pRegen->DeleteTextureBits();
+ }
+}
+
+void CMatSystemTexture::UpdateSubTextureRGBA( int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat imageFormat )
+{
+ ITexture *pTexture = GetTextureValue();
+ if ( !pTexture )
+ return;
+
+ Assert( IsProcedural() );
+ if ( !IsProcedural() )
+ return;
+
+ Assert( drawX < m_iWide );
+ Assert( drawY < m_iTall );
+ Assert( drawX + subTextureWide <= m_iWide );
+ Assert( drawY + subTextureTall <= m_iTall );
+
+ Assert( m_pRegen );
+
+ Assert( rgba );
+
+ Rect_t subRect;
+ subRect.x = drawX;
+ subRect.y = drawY;
+ subRect.width = subTextureWide;
+ subRect.height = subTextureTall;
+
+ Rect_t textureSize;
+ textureSize.x = 0;
+ textureSize.y = 0;
+ textureSize.width = m_iInputWide;
+ textureSize.height = m_iInputTall;
+
+ m_pRegen->UpdateBackingBits( subRect, rgba, textureSize, imageFormat );
+ pTexture->Download( &subRect );
+
+ if ( IsX360() )
+ {
+ // xboxissue - no need to persist "backing bits", saves memory
+ // the texture (commonly font page) "backing bits" are allocated during UpdateBackingBits() which get blitted
+ // into by procedural regeneration in preparation for download() which then subrect blits
+ // out of and into target texture (d3d upload)
+ // the "backing bits" are then no longer required
+ m_pRegen->DeleteTextureBits();
+ }
+}
+
+
+
+void CMatSystemTexture::SetCRC( CRC32_t val )
+{
+ m_crcFile = val;
+}
+
+CRC32_t CMatSystemTexture::GetCRC() const
+{
+ return m_crcFile;
+}
+
+void CMatSystemTexture::SetMaterial( IMaterial *pMaterial )
+{
+ // Decrement references to old texture
+ CleanUpMaterial();
+
+ m_pMaterial = pMaterial;
+
+ if (!m_pMaterial)
+ {
+ m_iWide = m_iTall = 0;
+ m_s0 = m_t0 = 0.0f;
+ m_s1 = m_t1 = 1.0f;
+ return;
+ }
+
+ // Increment its reference count
+ m_pMaterial->IncrementReferenceCount();
+
+ // Compute texture size
+ m_iWide = m_pMaterial->GetMappingWidth();
+ m_iTall = m_pMaterial->GetMappingHeight();
+
+ // Compute texture coordinates
+ float flPixelCenterX = 0.0f;
+ float flPixelCenterY = 0.0f;
+
+ if ( m_iWide > 0.0f && m_iTall > 0.0f)
+ {
+ flPixelCenterX = 0.5f / m_iWide;
+ flPixelCenterY = 0.5f / m_iTall;
+ }
+
+ m_s0 = flPixelCenterX;
+ m_t0 = flPixelCenterY;
+
+ // FIXME: Old code used +, it should be - yes?!??!
+ m_s1 = 1.0 - flPixelCenterX;
+ m_t1 = 1.0 - flPixelCenterY;
+
+ if ( IsProcedural() )
+ {
+ bool bFound;
+ IMaterialVar *tv = m_pMaterial->FindVar( "$baseTexture", &bFound );
+ if ( bFound && tv->IsTexture() )
+ {
+ m_pTexture = tv->GetTextureValue();
+ if ( m_pTexture )
+ {
+ m_pTexture->IncrementReferenceCount();
+
+ // Upload new data
+ CreateRegen( m_iWide, m_iTall, m_pTexture->GetImageFormat() );
+ m_pTexture->SetTextureRegenerator( m_pRegen );
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// This is used when we want different rendering state sharing the same procedural texture (fonts)
+//-----------------------------------------------------------------------------
+void CMatSystemTexture::ReferenceOtherProcedural( CMatSystemTexture *pTexture, IMaterial *pMaterial )
+{
+ // Decrement references to old texture
+ CleanUpMaterial();
+
+ Assert( pTexture->IsProcedural() );
+
+ m_Flags |= TEXTURE_IS_REFERENCE;
+
+ m_pMaterial = pMaterial;
+
+ if (!m_pMaterial)
+ {
+ m_iWide = m_iTall = 0;
+ m_s0 = m_t0 = 0.0f;
+ m_s1 = m_t1 = 1.0f;
+ return;
+ }
+
+ m_iWide = pTexture->m_iWide;
+ m_iTall = pTexture->m_iTall;
+ m_s0 = pTexture->m_s0;
+ m_t0 = pTexture->m_t0;
+ m_s1 = pTexture->m_s1;
+ m_t1 = pTexture->m_t1;
+
+ Assert( (pMaterial->GetMappingWidth() == m_iWide) && (pMaterial->GetMappingHeight() == m_iTall) );
+
+ // Increment its reference count
+ m_pMaterial->IncrementReferenceCount();
+
+ bool bFound;
+ IMaterialVar *tv = m_pMaterial->FindVar( "$baseTexture", &bFound );
+ if ( bFound )
+ {
+ m_pTexture = tv->GetTextureValue();
+ if ( m_pTexture )
+ {
+ m_pTexture->IncrementReferenceCount();
+ Assert( m_pTexture == pTexture->m_pTexture );
+
+ // Reference, but do *not* create a new one!!!
+ m_pRegen = pTexture->m_pRegen;
+ }
+ }
+}
+
+void CMatSystemTexture::SetMaterial( const char *pFileName )
+{
+ // Get a pointer to the new material
+ IMaterial *pMaterial = g_pMaterialSystem->FindMaterial( pFileName, TEXTURE_GROUP_VGUI );
+
+ if ( IsErrorMaterial( pMaterial ) )
+ {
+ if (IsOSX())
+ {
+ printf( "\n ##### Missing Vgui material %s\n", pFileName );
+ }
+ Msg( "--- Missing Vgui material %s\n", pFileName );
+ }
+
+ SetMaterial( pMaterial );
+}
+
+//-----------------------------------------------------------------------------
+// Singleton instance
+//-----------------------------------------------------------------------------
+ITextureDictionary *TextureDictionary()
+{
+ return &s_TextureDictionary;
+}
+
+CTextureDictionary::CTextureDictionary( void )
+{
+ // First entry is bogus texture
+ m_Textures.AddToTail();
+}
+
+//-----------------------------------------------------------------------------
+// Create, destroy textures
+//-----------------------------------------------------------------------------
+int CTextureDictionary::CreateTexture( bool procedural /*=false*/ )
+{
+ int idx = m_Textures.AddToTail();
+ CMatSystemTexture &texture = m_Textures[idx];
+ texture.SetProcedural( procedural );
+ texture.SetId( idx );
+
+ return idx;
+}
+
+int CTextureDictionary::CreateTextureByTexture( ITexture *pTexture, bool procedural /*= true*/ )
+{
+ int idx = m_Textures.AddToTail();
+ CMatSystemTexture &texture = m_Textures[idx];
+ texture.SetProcedural( procedural );
+ texture.SetId( idx );
+ texture.SetTexture( pTexture );
+
+ return idx;
+}
+
+void CTextureDictionary::DestroyTexture( int id )
+{
+ if ( m_Textures.Count() <= 1 )
+ {
+ // TextureDictionary already destroyed all the textures before this (something destructed late in shutdown)
+ return;
+ }
+
+ if (id != INVALID_TEXTURE_ID)
+ {
+ Assert( id != m_Textures.InvalidIndex() );
+ m_Textures.Remove( (unsigned short)id );
+ }
+}
+
+void CTextureDictionary::DestroyAllTextures()
+{
+ m_Textures.RemoveAll();
+ // First entry is bogus texture
+ m_Textures.AddToTail();
+ CMatSystemTexture &texture = m_Textures[0];
+ texture.SetId( 0 );
+}
+
+void CTextureDictionary::SetTextureRGBA( int id, const char* rgba, int wide, int tall )
+{
+ SetTextureRGBAEx( id, rgba, wide, tall, IMAGE_FORMAT_RGBA8888, false );
+}
+
+void CTextureDictionary::SetTextureRGBAEx( int id, const char* rgba, int wide, int tall, ImageFormat format, bool bFixupTextCoordsForDimensions )
+{
+ if (!IsValidId(id))
+ {
+ Msg( "SetTextureRGBA: Invalid texture id %i\n", id );
+ return;
+ }
+ CMatSystemTexture &texture = m_Textures[id];
+ texture.SetTextureRGBA( rgba, wide, tall, format, bFixupTextCoordsForDimensions );
+}
+
+void CTextureDictionary::SetSubTextureRGBA( int id, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall )
+{
+ SetSubTextureRGBAEx( id, drawX, drawY, rgba, subTextureWide, subTextureTall, IMAGE_FORMAT_RGBA8888 );
+}
+
+
+void CTextureDictionary::SetSubTextureRGBAEx( int id, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat format )
+{
+ if (!IsValidId(id))
+ {
+ Msg( "SetSubTextureRGBA: Invalid texture id %i\n", id );
+ return;
+ }
+
+ CMatSystemTexture &texture = m_Textures[id];
+ texture.SetSubTextureRGBAEx( drawX, drawY, rgba, subTextureWide, subTextureTall, format );
+}
+
+
+void CTextureDictionary::UpdateSubTextureRGBA( int id, int drawX, int drawY, unsigned const char *rgba, int subTextureWide, int subTextureTall, ImageFormat imageFormat )
+{
+ if (!IsValidId(id))
+ {
+ Msg( "UpdateSubTextureRGBA: Invalid texture id %i\n", id );
+ return;
+ }
+
+ CMatSystemTexture &texture = m_Textures[id];
+ texture.UpdateSubTextureRGBA( drawX, drawY, rgba, subTextureWide, subTextureTall, imageFormat );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns true if the id is valid
+//-----------------------------------------------------------------------------
+bool CTextureDictionary::IsValidId( int id ) const
+{
+ Assert( id != 0 );
+ if ( id == 0 )
+ return false;
+
+ return m_Textures.IsValidIndex( id );
+}
+
+
+//-----------------------------------------------------------------------------
+// Binds a file to a particular texture
+//-----------------------------------------------------------------------------
+void CTextureDictionary::BindTextureToFile( int id, const char *pFileName )
+{
+ if (!IsValidId(id))
+ {
+ Msg( "BindTextureToFile: Invalid texture id for file %s\n", pFileName );
+ return;
+ }
+
+ CMatSystemTexture &texture = m_Textures[id];
+
+ // Reload from file if the material was never loaded, or if the filename has changed at all
+ CRC32_t fileNameCRC = Texture_CRCName( pFileName );
+ if ( !texture.GetMaterial() || fileNameCRC != texture.GetCRC() )
+ {
+ // New texture name
+ texture.SetCRC( fileNameCRC );
+ texture.SetMaterial( pFileName );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Binds a material to a texture
+//-----------------------------------------------------------------------------
+void CTextureDictionary::BindTextureToMaterial( int id, IMaterial *pMaterial )
+{
+ if (!IsValidId(id))
+ {
+ Msg( "BindTextureToFile: Invalid texture id %d\n", id );
+ return;
+ }
+
+ CMatSystemTexture &texture = m_Textures[id];
+ texture.SetMaterial( pMaterial );
+}
+
+
+//-----------------------------------------------------------------------------
+// Binds a material to a texture reference
+//-----------------------------------------------------------------------------
+void CTextureDictionary::BindTextureToMaterialReference( int id, int referenceId, IMaterial *pMaterial )
+{
+ if (!IsValidId(id) || !IsValidId(referenceId))
+ {
+ Msg( "BindTextureToFile: Invalid texture ids %d %d\n", id, referenceId );
+ return;
+ }
+
+ CMatSystemTexture &texture = m_Textures[id];
+ CMatSystemTexture &textureSource = m_Textures[referenceId];
+ texture.ReferenceOtherProcedural( &textureSource, pMaterial );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the material associated with an id
+//-----------------------------------------------------------------------------
+IMaterial *CTextureDictionary::GetTextureMaterial( int id )
+{
+ if (!IsValidId(id))
+ return NULL;
+
+ return m_Textures[id].GetMaterial();
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the material size associated with an id
+//-----------------------------------------------------------------------------
+void CTextureDictionary::GetTextureSize(int id, int& iWide, int& iTall )
+{
+ if (!IsValidId(id))
+ {
+ iWide = iTall = 0;
+ return;
+ }
+
+ iWide = m_Textures[id].Width();
+ iTall = m_Textures[id].Height();
+}
+
+void CTextureDictionary::GetTextureTexCoords( int id, float &s0, float &t0, float &s1, float &t1 )
+{
+ if (!IsValidId(id))
+ {
+ s0 = t0 = 0.0f;
+ s1 = t1 = 1.0f;
+ return;
+ }
+
+ s0 = m_Textures[id].m_s0;
+ t0 = m_Textures[id].m_t0;
+ s1 = m_Textures[id].m_s1;
+ t1 = m_Textures[id].m_t1;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : id -
+// Output : CMatSystemTexture
+//-----------------------------------------------------------------------------
+CMatSystemTexture *CTextureDictionary::GetTexture( int id )
+{
+ if (!IsValidId(id))
+ return NULL;
+
+ return &m_Textures[ id ];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pFileName -
+//-----------------------------------------------------------------------------
+int CTextureDictionary::FindTextureIdForTextureFile( char const *pFileName )
+{
+ for ( int i = m_Textures.Head(); i != m_Textures.InvalidIndex(); i = m_Textures.Next( i ) )
+ {
+ CMatSystemTexture *tex = &m_Textures[i];
+ if ( !tex )
+ continue;
+
+ IMaterial *mat = tex->GetMaterial();
+ if ( !mat )
+ continue;
+
+ if ( !stricmp( mat->GetName(), pFileName ) )
+ return i;
+ }
+
+ return -1;
+}