mirror of
https://github.com/nillerusr/source-engine.git
synced 2024-12-22 14:16:50 +00:00
665 lines
18 KiB
C++
665 lines
18 KiB
C++
//========= 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
|
|
|