summaryrefslogtreecommitdiff
path: root/materialsystem/checkmaterials.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'materialsystem/checkmaterials.cpp')
-rw-r--r--materialsystem/checkmaterials.cpp664
1 files changed, 664 insertions, 0 deletions
diff --git a/materialsystem/checkmaterials.cpp b/materialsystem/checkmaterials.cpp
new file mode 100644
index 0000000..30432f8
--- /dev/null
+++ b/materialsystem/checkmaterials.cpp
@@ -0,0 +1,664 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "pch_materialsystem.h"
+
+// NOTE: currently this file is marked as "exclude from build"
+
+//#define _CHECK_MATERIALS_FOR_PROBLEMS 1
+#ifdef _CHECK_MATERIALS_FOR_PROBLEMS
+#include "vtf/vtf.h"
+#include "tier1/utlbuffer.h"
+#include "tier1/utlstring.h"
+void CheckMateralsInDirectoryRecursive( const char *pRoot, const char *pDirectory );
+#endif
+
+#ifdef _CHECK_MATERIALS_FOR_PROBLEMS
+
+//-----------------------------------------------------------------------------
+// Does a texture have alpha?
+//-----------------------------------------------------------------------------
+static bool DoesTextureUseAlpha( const char *pTextureName, const char *pMaterialName )
+{
+ if ( IsX360() )
+ {
+ // not supporting
+ return false;
+ }
+
+ // Special textures start with '_'..
+ if ( pTextureName[0] == '_' )
+ return false;
+
+ // The texture name doubles as the relative file name
+ // It's assumed to have already been set by this point
+ // Compute the cache name
+ char pCacheFileName[MATERIAL_MAX_PATH];
+ Q_snprintf( pCacheFileName, sizeof( pCacheFileName ), "materials/%s.vtf", pTextureName );
+
+ CUtlBuffer buf;
+ FileHandle_t fileHandle = g_pFullFileSystem->Open( pCacheFileName, "rb" );
+ if ( fileHandle == FILESYSTEM_INVALID_HANDLE)
+ {
+ Warning( "Material \"%s\": can't open texture \"%s\"\n", pMaterialName, pCacheFileName );
+ return false;
+ }
+
+ // Check the .vtf for an alpha channel
+ IVTFTexture *pVTFTexture = CreateVTFTexture();
+
+ int nHeaderSize = VTFFileHeaderSize( VTF_MAJOR_VERSION );
+ buf.EnsureCapacity( nHeaderSize );
+
+ // read the header first.. it's faster!!
+ g_pFullFileSystem->Read( buf.Base(), nHeaderSize, fileHandle );
+ buf.SeekPut( CUtlBuffer::SEEK_HEAD, nHeaderSize );
+
+ // Unserialize the header
+ bool bUsesAlpha = false;
+
+ if (!pVTFTexture->Unserialize( buf, true ))
+ {
+ Warning( "Error reading material \"%s\"\n", pCacheFileName );
+ g_pFullFileSystem->Close(fileHandle);
+ }
+ else
+ {
+ if ( pVTFTexture->Flags() & (TEXTUREFLAGS_ONEBITALPHA | TEXTUREFLAGS_EIGHTBITALPHA) )
+ {
+ bUsesAlpha = true;
+ }
+ }
+
+ DestroyVTFTexture( pVTFTexture );
+ g_pFullFileSystem->Close( fileHandle );
+ return bUsesAlpha;
+}
+
+
+//-----------------------------------------------------------------------------
+// Does a texture have alpha?
+//-----------------------------------------------------------------------------
+static bool DoesTextureUseNormal( const char *pTextureName, const char *pMaterialName, bool &bUsesAlpha, bool &bIsCompressed, int &nSizeInBytes )
+{
+ nSizeInBytes = 0;
+ bUsesAlpha = false;
+
+ if ( IsX360() )
+ {
+ // not supporting
+ return false;
+ }
+
+ // Special textures start with '_'..
+ if ( !pTextureName || ( pTextureName[0] == '_' ) || ( pTextureName[0] == 0 ) )
+ return false;
+
+ // The texture name doubles as the relative file name
+ // It's assumed to have already been set by this point
+ // Compute the cache name
+ char pCacheFileName[MATERIAL_MAX_PATH];
+ Q_snprintf( pCacheFileName, sizeof( pCacheFileName ), "materials/%s.vtf", pTextureName );
+
+ CUtlBuffer buf;
+ FileHandle_t fileHandle = g_pFullFileSystem->Open( pCacheFileName, "rb" );
+ if ( fileHandle == FILESYSTEM_INVALID_HANDLE)
+ {
+// Warning( "Material \"%s\": can't open texture \"%s\"\n", pMaterialName, pCacheFileName );
+ return false;
+ }
+
+ // Check the .vtf for an alpha channel
+ IVTFTexture *pVTFTexture = CreateVTFTexture();
+
+ int nHeaderSize = VTFFileHeaderSize( VTF_MAJOR_VERSION );
+ buf.EnsureCapacity( nHeaderSize );
+
+ // read the header first.. it's faster!!
+ g_pFullFileSystem->Read( buf.Base(), nHeaderSize, fileHandle );
+ buf.SeekPut( CUtlBuffer::SEEK_HEAD, nHeaderSize );
+
+ // Unserialize the header
+ bool bUsesNormal = false;
+ if ( !pVTFTexture->Unserialize( buf, true ) )
+ {
+ Warning( "Error reading material \"%s\"\n", pCacheFileName );
+ }
+ else
+ {
+ if ( pVTFTexture->Flags() & TEXTUREFLAGS_NORMAL )
+ {
+ bUsesAlpha = false;
+ bUsesNormal = true;
+ bIsCompressed = ImageLoader::IsCompressed( pVTFTexture->Format() ) || ( pVTFTexture->Format() == IMAGE_FORMAT_A8 );
+ nSizeInBytes = pVTFTexture->ComputeTotalSize();
+ if ( pVTFTexture->Flags() & (TEXTUREFLAGS_ONEBITALPHA | TEXTUREFLAGS_EIGHTBITALPHA) )
+ {
+ bUsesAlpha = true;
+ }
+ }
+ }
+
+ DestroyVTFTexture( pVTFTexture );
+ g_pFullFileSystem->Close( fileHandle );
+ return bUsesNormal;
+}
+
+
+//-----------------------------------------------------------------------------
+// Is this a real texture
+//-----------------------------------------------------------------------------
+static bool IsTexture( const char *pTextureName )
+{
+ // Special textures start with '_'..
+ if ( pTextureName[0] == '_' )
+ return false;
+
+ // The texture name doubles as the relative file name
+ // It's assumed to have already been set by this point
+ // Compute the cache name
+ char pCacheFileName[MATERIAL_MAX_PATH];
+ Q_snprintf( pCacheFileName, sizeof( pCacheFileName ), "materials/%s.vtf", pTextureName );
+
+ FileHandle_t fileHandle = g_pFullFileSystem->Open( pCacheFileName, "rb" );
+ if ( fileHandle == FILESYSTEM_INVALID_HANDLE)
+ return false;
+
+ g_pFullFileSystem->Close( fileHandle );
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Scan material + all subsections for key
+//-----------------------------------------------------------------------------
+static float MaterialFloatKeyValue( KeyValues *pKeyValues, const char *pKeyName, float flDefault )
+{
+ float flValue = pKeyValues->GetFloat( pKeyName, flDefault );
+ if ( flValue != flDefault )
+ return flValue;
+
+ for( KeyValues *pSubKey = pKeyValues->GetFirstTrueSubKey(); pSubKey; pSubKey = pSubKey->GetNextTrueSubKey() )
+ {
+ float flValue = MaterialFloatKeyValue( pSubKey, pKeyName, flDefault );
+ if ( flValue != flDefault )
+ return flValue;
+ }
+
+ return flDefault;
+}
+
+int ParseVectorFromKeyValueString( KeyValues *pKeyValue, const char *pMaterialName, float vecVal[4] );
+
+static bool AsVectorsEqual( int nDim1, float *pVector1, int nDim2, float *pVector2 )
+{
+ if ( nDim1 != nDim2 )
+ return false;
+
+ for ( int i = 0; i < nDim1; ++i )
+ {
+ if ( fabs( pVector1[i] - pVector2[i] ) > 1e-3 )
+ return false;
+ }
+
+ return true;
+}
+
+static bool MaterialVectorKeyValue( KeyValues *pKeyValues, const char *pKeyName, int nDefaultDim, float *pDefault, int *pDim, float *pVector )
+{
+ int nDim;
+ float retVal[4];
+
+ KeyValues *pValue = pKeyValues->FindKey( pKeyName );
+ if ( pValue )
+ {
+ switch( pValue->GetDataType() )
+ {
+ case KeyValues::TYPE_INT:
+ {
+ int nInt = pValue->GetInt();
+ for ( int i = 0; i < 4; ++i )
+ {
+ retVal[i] = nInt;
+ }
+ if ( !AsVectorsEqual( nDefaultDim, pDefault, nDefaultDim, retVal ) )
+ {
+ *pDim = nDefaultDim;
+ memcpy( pVector, retVal, nDefaultDim * sizeof(float) );
+ return true;
+ }
+ }
+ break;
+
+ case KeyValues::TYPE_FLOAT:
+ {
+ float flFloat = pValue->GetFloat();
+ for ( int i = 0; i < 4; ++i )
+ {
+ retVal[i] = flFloat;
+ }
+ if ( !AsVectorsEqual( nDefaultDim, pDefault, nDefaultDim, retVal ) )
+ {
+ *pDim = nDefaultDim;
+ memcpy( pVector, retVal, nDefaultDim * sizeof(float) );
+ return true;
+ }
+ }
+ break;
+
+ case KeyValues::TYPE_STRING:
+ {
+ nDim = ParseVectorFromKeyValueString( pValue, "", retVal );
+ if ( !AsVectorsEqual( nDefaultDim, pDefault, nDim, retVal ) )
+ {
+ *pDim = nDim;
+ memcpy( pVector, retVal, nDim * sizeof(float) );
+ return true;
+ }
+ }
+ break;
+ }
+ }
+
+ for( KeyValues *pSubKey = pKeyValues->GetFirstTrueSubKey(); pSubKey; pSubKey = pSubKey->GetNextTrueSubKey() )
+ {
+ if ( MaterialVectorKeyValue( pSubKey, pKeyName, nDefaultDim, pDefault, &nDim, retVal ) )
+ {
+ *pDim = nDim;
+ memcpy( pVector, retVal, nDim * sizeof(float) );
+ return true;
+ }
+ }
+
+ *pDim = nDefaultDim;
+ memcpy( pVector, pDefault, nDefaultDim * sizeof(float) );
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Scan material + all subsections for key
+//-----------------------------------------------------------------------------
+static bool DoesMaterialHaveKey( KeyValues *pKeyValues, const char *pKeyName )
+{
+ if ( pKeyValues->GetString( pKeyName, NULL ) != NULL )
+ return true;
+
+ for( KeyValues *pSubKey = pKeyValues->GetFirstTrueSubKey(); pSubKey; pSubKey = pSubKey->GetNextTrueSubKey() )
+ {
+ if ( DoesMaterialHaveKey( pSubKey, pKeyName ) )
+ return true;
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Scan all materials for errors
+//-----------------------------------------------------------------------------
+static int s_nNormalBytes;
+static int s_nNormalCompressedBytes;
+static int s_nNormalPalettizedBytes;
+static int s_nNormalWithAlphaBytes;
+static int s_nNormalWithAlphaCompressedBytes;
+
+struct VTFInfo_t
+{
+ CUtlString m_VTFName;
+ bool m_bFoundInVMT;
+};
+
+void CheckKeyValues( KeyValues *pKeyValues, CUtlVector<VTFInfo_t> &vtf )
+{
+ for ( KeyValues *pSubKey = pKeyValues->GetFirstValue(); pSubKey; pSubKey = pSubKey->GetNextValue() )
+ {
+ if ( pSubKey->GetDataType() != KeyValues::TYPE_STRING )
+ continue;
+
+ if ( IsTexture( pSubKey->GetString() ) )
+ {
+ int nLen = Q_strlen( pSubKey->GetString() ) + 1;
+ char *pTemp = (char*)_alloca( nLen );
+ memcpy( pTemp, pSubKey->GetString(), nLen );
+ Q_FixSlashes( pTemp );
+
+ int nCount = vtf.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ if ( Q_stricmp( vtf[i].m_VTFName, pTemp ) )
+ continue;
+ vtf[i].m_bFoundInVMT = true;
+ break;
+ }
+ }
+ }
+
+ for ( KeyValues *pSubKey = pKeyValues->GetFirstTrueSubKey(); pSubKey; pSubKey = pSubKey->GetNextTrueSubKey() )
+ {
+ CheckKeyValues( pSubKey, vtf );
+ }
+}
+
+void CheckMaterial( KeyValues *pKeyValues, const char *pRoot, const char *pFileName, CUtlVector<VTFInfo_t> &vtf )
+{
+ const char *pShaderName = pKeyValues->GetName();
+/*
+ if ( Q_stristr( pShaderName, "Water" ) ||
+ Q_stristr( pShaderName, "Eyeball" ) ||
+ Q_stristr( pShaderName, "Shadow" ) ||
+ Q_stristr( pShaderName, "Refract" ) ||
+ Q_stristr( pShaderName, "Predator" ) ||
+ Q_stristr( pShaderName, "ParticleSphere" ) ||
+ Q_stristr( pShaderName, "DebugLuxels" ) ||
+ Q_stristr( pShaderName, "GooInGlass" ) ||
+ Q_stristr( pShaderName, "Modulate" ) ||
+ Q_stristr( pShaderName, "UnlitTwoTexture" ) ||
+ Q_stristr( pShaderName, "Cloud" ) ||
+ Q_stristr( pShaderName, "WorldVertexTransition" ) ||
+ Q_stristr( pShaderName, "DecalModulate" ) ||
+ Q_stristr( pShaderName, "DecalBaseTimesLightmapAlphaBlendSelfIllum" ) ||
+ Q_stristr( pShaderName, "Sprite" ) )
+ {
+ return;
+ }
+
+ // Check for alpha channels
+ const char *pBaseTextureName = pKeyValues->GetString( "$basetexture", NULL );
+ if ( pBaseTextureName != NULL )
+ {
+ if ( DoesTextureUseAlpha( pBaseTextureName, pFileName ) )
+ {
+ float flAlpha = MaterialFloatKeyValue( pKeyValues, "$alpha", 1.0f );
+ bool bHasVertexAlpha = DoesMaterialHaveKey( pKeyValues, "$vertexalpha" ); // Modulation always happens here whether we want it to or not
+ bool bHasAlphaTest = DoesMaterialHaveKey( pKeyValues, "$alphatest" );
+ bool bHasTranslucent = DoesMaterialHaveKey( pKeyValues, "$translucent" );
+ bool bHasSelfIllum = DoesMaterialHaveKey( pKeyValues, "$selfillum" );
+ bool bHasBaseAlphaEnvMapMask = DoesMaterialHaveKey( pKeyValues, "$basealphaenvmapmask" );
+ if ( (flAlpha == 1.0f) && !bHasVertexAlpha && !bHasAlphaTest && !bHasTranslucent && !bHasSelfIllum && !bHasBaseAlphaEnvMapMask )
+ {
+ Warning("Material \"%s\": BASETEXTURE \"%s\"\n", pFileName, pBaseTextureName );
+ }
+ }
+ }
+*/
+
+/*
+// Check for bump, spec, and no normalmapalphaenvmapmask
+ const char *pBumpmapName = pKeyValues->GetString( "$bumpmap", NULL );
+ if ( pBumpmapName != NULL )
+ {
+ if ( DoesTextureUseAlpha( pBumpmapName, pFileName ) )
+ {
+ bool bHasEnvmap = DoesMaterialHaveKey( pKeyValues, "$envmap" );
+ bool bHasNormalMapAlphaEnvMapMask = DoesMaterialHaveKey( pKeyValues, "$normalmapalphaenvmapmask" );
+ if ( !bHasEnvmap || !bHasNormalMapAlphaEnvMapMask )
+ {
+ Warning("Material \"%s\": BUMPMAP \"%s\"\n", pFileName, pBumpmapName );
+ }
+ }
+ }
+*/
+
+/*
+ if ( !Q_stristr( pShaderName, "LightmappedGeneric" ) &&
+ !Q_stristr( pShaderName, "VertexLitGeneric" ) )
+ {
+ return;
+ }
+
+ if ( DoesMaterialHaveKey( pKeyValues, "$envmap" ) && DoesMaterialHaveKey( pKeyValues, "$bumpmap" ) )
+ {
+ int nDim;
+ float retVal[4];
+ float defaultVal[4] = { 1, 1, 1, 1 };
+
+ if ( MaterialVectorKeyValue( pKeyValues, "$envmaptint", 3, defaultVal, &nDim, retVal ) )
+ {
+ Warning("ENVMAP + ENVMAPTINT : Material \"%s\"\n", pFileName );
+ }
+// else
+// {
+// Warning("ENVMAP only: Material \"%s\"\n", pFileName );
+// }
+ }
+ */
+
+/*
+ if ( !Q_stristr( pShaderName, "Refract" ) )
+ {
+ return;
+ }
+
+ if ( !DoesMaterialHaveKey( pKeyValues, "$envmap" ) )
+ {
+ bool bUsesAlpha, bIsCompressed, bIsPalettized;
+ int nSizeInBytes;
+ if ( DoesTextureUseNormal( pKeyValues->GetString( "$normalmap" ),
+ pFileName, bUsesAlpha, bIsCompressed, bIsPalettized, nSizeInBytes ) )
+ {
+ if ( bIsCompressed )
+ {
+ Warning("Bad : Material compressed \"%s\"\n", pFileName );
+ }
+ else
+ {
+ Warning("Bad : Material \"%s\"\n", pFileName );
+ }
+ }
+ }
+*/
+
+/*
+ if ( !Q_stristr( pShaderName, "WorldTwoTextureBlend" ) )
+ {
+ return;
+ }
+
+ if ( DoesMaterialHaveKey( pKeyValues, "$envmap" ) ||
+ DoesMaterialHaveKey( pKeyValues, "$parallaxmap" ) ||
+ DoesMaterialHaveKey( pKeyValues, "$bumpmap" ) ||
+ DoesMaterialHaveKey( pKeyValues, "$vertexcolor" ) ||
+ DoesMaterialHaveKey( pKeyValues, "$basetexture2" )
+ )
+ {
+ Warning("Bad : Material \"%s\"\n", pFileName );
+ }
+*/
+
+ for ( KeyValues *pSubKey = pKeyValues->GetFirstValue(); pSubKey; pSubKey = pSubKey->GetNextValue() )
+ {
+// Msg( " Checking %s\n", pSubKey->GetString() );
+ if ( pSubKey->GetDataType() != KeyValues::TYPE_STRING )
+ continue;
+
+ bool bUsesAlpha, bIsCompressed;
+ int nSizeInBytes;
+ if ( DoesTextureUseNormal( pSubKey->GetString(), pFileName, bUsesAlpha, bIsCompressed, nSizeInBytes ) )
+ {
+ if ( bUsesAlpha )
+ {
+ if ( bIsCompressed )
+ {
+ s_nNormalWithAlphaCompressedBytes += nSizeInBytes;
+ }
+ else
+ {
+ s_nNormalWithAlphaBytes += nSizeInBytes;
+ Msg( "Normal texture w alpha uncompressed %s\n", pSubKey->GetString() );
+ }
+ }
+ else
+ {
+ if ( bIsCompressed )
+ {
+ s_nNormalCompressedBytes += nSizeInBytes;
+ }
+ else
+ {
+ s_nNormalBytes += nSizeInBytes;
+ }
+ }
+ }
+ }
+
+/*
+ if ( !Q_stristr( pShaderName, "VertexLitGeneric" ) )
+ return;
+
+ if ( !DoesMaterialHaveKey( pKeyValues, "$envmap" ) && DoesMaterialHaveKey( pKeyValues, "$bumpmap" ) )
+ {
+ Warning("BUMPMAP + no ENVMAP : Material \"%s\"\n", pFileName );
+ }
+*/
+
+// CheckKeyValues( pKeyValues, vtf );
+}
+
+//-----------------------------------------------------------------------------
+// Build list of all VTFs
+//-----------------------------------------------------------------------------
+void CheckVTFInDirectoryRecursive( const char *pRoot, const char *pDirectory, CUtlVector< VTFInfo_t > &vtf )
+{
+#define BUF_SIZE 1024
+ char buf[BUF_SIZE];
+ WIN32_FIND_DATA wfd;
+ HANDLE findHandle;
+
+ sprintf( buf, "%s/%s/*.vtf", pRoot, pDirectory );
+
+ findHandle = FindFirstFile( buf, &wfd );
+ if ( findHandle != INVALID_HANDLE_VALUE )
+ {
+ do
+ {
+ int i = vtf.AddToTail( );
+
+ char buf[MAX_PATH];
+ char buf2[MAX_PATH];
+ Q_snprintf( buf, MAX_PATH, "%s/%s", pDirectory, wfd.cFileName );
+ Q_FixSlashes( buf );
+
+ Q_StripExtension( buf, buf2, sizeof(buf2) );
+ Assert( !Q_strnicmp( buf2, "materials\\", 10 ) );
+
+ vtf[i].m_VTFName = &buf2[10];
+ vtf[i].m_bFoundInVMT = false;
+
+ } while ( FindNextFile ( findHandle, &wfd ) );
+
+ FindClose ( findHandle );
+ }
+
+ // do subdirectories
+ sprintf( buf, "%s/%s/*.*", pRoot, pDirectory );
+ findHandle = FindFirstFile( buf, &wfd );
+ if ( findHandle != INVALID_HANDLE_VALUE )
+ {
+ do
+ {
+ if( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
+ {
+ if( ( strcmp( wfd.cFileName, ".." ) == 0 ) ||
+ ( strcmp( wfd.cFileName, "." ) == 0 ) )
+ {
+ continue;
+ }
+
+ char buf[MAX_PATH];
+ Q_snprintf( buf, MAX_PATH, "%s/%s", pDirectory, wfd.cFileName );
+ CheckVTFInDirectoryRecursive( pRoot, buf, vtf );
+ }
+ } while ( FindNextFile ( findHandle, &wfd ) );
+ FindClose ( findHandle );
+ }
+
+#undef BUF_SIZE
+}
+
+
+//-----------------------------------------------------------------------------
+// Scan all materials for errors
+//-----------------------------------------------------------------------------
+void _CheckMateralsInDirectoryRecursive( const char *pRoot, const char *pDirectory, CUtlVector< VTFInfo_t > &vtf )
+{
+#define BUF_SIZE 1024
+ char buf[BUF_SIZE];
+ WIN32_FIND_DATA wfd;
+ HANDLE findHandle;
+
+ sprintf( buf, "%s/%s/*.vmt", pRoot, pDirectory );
+ findHandle = FindFirstFile( buf, &wfd );
+ if ( findHandle != INVALID_HANDLE_VALUE )
+ {
+ do
+ {
+ KeyValues * vmtKeyValues = new KeyValues("vmt");
+
+ char pFileName[MAX_PATH];
+ Q_snprintf( pFileName, sizeof( pFileName ), "%s/%s", pDirectory, wfd.cFileName );
+ if ( !vmtKeyValues->LoadFromFile( g_pFullFileSystem, pFileName, "GAME" ) )
+ {
+ Warning( "CheckMateralsInDirectoryRecursive: can't open \"%s\"\n", pFileName );
+ continue;
+ }
+
+ CheckMaterial( vmtKeyValues, pRoot, pFileName, vtf );
+
+ vmtKeyValues->deleteThis();
+
+ } while ( FindNextFile ( findHandle, &wfd ) );
+
+ FindClose ( findHandle );
+ }
+
+ // do subdirectories
+ sprintf( buf, "%s/%s/*.*", pRoot, pDirectory );
+ findHandle = FindFirstFile( buf, &wfd );
+ if ( findHandle != INVALID_HANDLE_VALUE )
+ {
+ do
+ {
+ if( wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
+ {
+ if( ( strcmp( wfd.cFileName, ".." ) == 0 ) ||
+ ( strcmp( wfd.cFileName, "." ) == 0 ) )
+ {
+ continue;
+ }
+
+ char buf[MAX_PATH];
+ Q_snprintf( buf, MAX_PATH, "%s/%s", pDirectory, wfd.cFileName );
+ _CheckMateralsInDirectoryRecursive( pRoot, buf, vtf );
+ }
+ } while ( FindNextFile ( findHandle, &wfd ) );
+ FindClose ( findHandle );
+ }
+
+// Msg( "Normal only %d/%d/%d Normal w alpha %d/%d\n", s_nNormalBytes, s_nNormalPalettizedBytes, s_nNormalCompressedBytes, s_nNormalWithAlphaBytes, s_nNormalWithAlphaCompressedBytes );
+#undef BUF_SIZE
+}
+
+void CheckMateralsInDirectoryRecursive( const char *pRoot, const char *pDirectory )
+{
+ CUtlVector< VTFInfo_t > vtfNames;
+// CheckVTFInDirectoryRecursive( pRoot, pDirectory, vtfNames );
+ _CheckMateralsInDirectoryRecursive( pRoot, pDirectory, vtfNames );
+
+ /*
+ int nCount = vtfNames.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ if ( !vtfNames[i].m_bFoundInVMT )
+ {
+ Msg( "Unused VTF %s\n", vtfNames[i].m_VTFName );
+ }
+ }
+ */
+}
+
+#endif // _CHECK_MATERIALS_FOR_PROBLEMS
+