aboutsummaryrefslogtreecommitdiff
path: root/mp/src/utils/vbsp/materialpatch.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/utils/vbsp/materialpatch.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/utils/vbsp/materialpatch.cpp')
-rw-r--r--mp/src/utils/vbsp/materialpatch.cpp880
1 files changed, 440 insertions, 440 deletions
diff --git a/mp/src/utils/vbsp/materialpatch.cpp b/mp/src/utils/vbsp/materialpatch.cpp
index e05b979d..96a30edb 100644
--- a/mp/src/utils/vbsp/materialpatch.cpp
+++ b/mp/src/utils/vbsp/materialpatch.cpp
@@ -1,440 +1,440 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//
-//=============================================================================//
-#include "vbsp.h"
-#include "UtlBuffer.h"
-#include "utlsymbol.h"
-#include "utlrbtree.h"
-#include "KeyValues.h"
-#include "bsplib.h"
-#include "materialpatch.h"
-#include "tier1/strtools.h"
-
-// case insensitive
-static CUtlSymbolTable s_SymbolTable( 0, 32, true );
-
-struct NameTranslationLookup_t
-{
- CUtlSymbol m_OriginalFileName;
- CUtlSymbol m_PatchFileName;
-};
-
-static bool NameTranslationLessFunc( NameTranslationLookup_t const& src1,
- NameTranslationLookup_t const& src2 )
-{
- return src1.m_PatchFileName < src2.m_PatchFileName;
-}
-
-CUtlRBTree<NameTranslationLookup_t, int> s_MapPatchedMatToOriginalMat( 0, 256, NameTranslationLessFunc );
-
-void AddNewTranslation( const char *pOriginalMaterialName, const char *pNewMaterialName )
-{
- NameTranslationLookup_t newEntry;
-
- newEntry.m_OriginalFileName = s_SymbolTable.AddString( pOriginalMaterialName );
- newEntry.m_PatchFileName = s_SymbolTable.AddString( pNewMaterialName );
-
- s_MapPatchedMatToOriginalMat.Insert( newEntry );
-}
-
-const char *GetOriginalMaterialNameForPatchedMaterial( const char *pPatchMaterialName )
-{
- const char *pRetName = NULL;
- int id;
- NameTranslationLookup_t lookup;
- lookup.m_PatchFileName = s_SymbolTable.AddString( pPatchMaterialName );
- do
- {
- id = s_MapPatchedMatToOriginalMat.Find( lookup );
- if( id >= 0 )
- {
- NameTranslationLookup_t &found = s_MapPatchedMatToOriginalMat[id];
- lookup.m_PatchFileName = found.m_OriginalFileName;
- pRetName = s_SymbolTable.String( found.m_OriginalFileName );
- }
- } while( id >= 0 );
- if( !pRetName )
- {
- // This isn't a patched material, so just return the original name.
- return pPatchMaterialName;
- }
- return pRetName;
-}
-
-
-void CreateMaterialPatchRecursive( KeyValues *pOriginalKeyValues, KeyValues *pPatchKeyValues, int nKeys, const MaterialPatchInfo_t *pInfo )
-{
- int i;
- for( i = 0; i < nKeys; i++ )
- {
- const char *pVal = pOriginalKeyValues->GetString( pInfo[i].m_pKey, NULL );
- if( !pVal )
- continue;
- if( pInfo[i].m_pRequiredOriginalValue && Q_stricmp( pVal, pInfo[i].m_pRequiredOriginalValue ) != 0 )
- continue;
- pPatchKeyValues->SetString( pInfo[i].m_pKey, pInfo[i].m_pValue );
- }
- KeyValues *pScan;
- for( pScan = pOriginalKeyValues->GetFirstTrueSubKey(); pScan; pScan = pScan->GetNextTrueSubKey() )
- {
- CreateMaterialPatchRecursive( pScan, pPatchKeyValues->FindKey( pScan->GetName(), true ), nKeys, pInfo );
- }
-}
-
-//-----------------------------------------------------------------------------
-// A version which allows you to patch multiple key values
-//-----------------------------------------------------------------------------
-void CreateMaterialPatch( const char *pOriginalMaterialName, const char *pNewMaterialName,
- int nKeys, const MaterialPatchInfo_t *pInfo, MaterialPatchType_t nPatchType )
-{
- char pOldVMTFile[ 512 ];
- char pNewVMTFile[ 512 ];
-
- AddNewTranslation( pOriginalMaterialName, pNewMaterialName );
-
- Q_snprintf( pOldVMTFile, 512, "materials/%s.vmt", pOriginalMaterialName );
- Q_snprintf( pNewVMTFile, 512, "materials/%s.vmt", pNewMaterialName );
-
-// printf( "Creating material patch file %s which points at %s\n", newVMTFile, oldVMTFile );
-
- KeyValues *kv = new KeyValues( "patch" );
- if ( !kv )
- {
- Error( "Couldn't allocate KeyValues for %s!!!", pNewMaterialName );
- }
-
- kv->SetString( "include", pOldVMTFile );
-
- const char *pSectionName = (nPatchType == PATCH_INSERT) ? "insert" : "replace";
- KeyValues *section = kv->FindKey( pSectionName, true );
-
- if( nPatchType == PATCH_REPLACE )
- {
- char name[512];
- Q_snprintf( name, 512, "materials/%s.vmt", GetOriginalMaterialNameForPatchedMaterial( pOriginalMaterialName ) );
- KeyValues *origkv = new KeyValues( "blah" );
-
- if ( !origkv->LoadFromFile( g_pFileSystem, name ) )
- {
- origkv->deleteThis();
- Assert( 0 );
- return;
- }
-
- CreateMaterialPatchRecursive( origkv, section, nKeys, pInfo );
- origkv->deleteThis();
- }
- else
- {
- for ( int i = 0; i < nKeys; ++i )
- {
- section->SetString( pInfo[i].m_pKey, pInfo[i].m_pValue );
- }
- }
-
- // Write patched .vmt into a memory buffer
- CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
- kv->RecursiveSaveToFile( buf, 0 );
-
- // Add to pak file for this .bsp
- AddBufferToPak( GetPakFile(), pNewVMTFile, (void*)buf.Base(), buf.TellPut(), true );
-
- // Cleanup
- kv->deleteThis();
-}
-
-
-//-----------------------------------------------------------------------------
-// Patches a single keyvalue in a material
-//-----------------------------------------------------------------------------
-void CreateMaterialPatch( const char *pOriginalMaterialName, const char *pNewMaterialName,
- const char *pNewKey, const char *pNewValue, MaterialPatchType_t nPatchType )
-{
- MaterialPatchInfo_t info;
- info.m_pKey = pNewKey;
- info.m_pValue = pNewValue;
- CreateMaterialPatch( pOriginalMaterialName, pNewMaterialName, 1, &info, nPatchType );
-}
-
-
-//-----------------------------------------------------------------------------
-// Scan material + all subsections for key
-//-----------------------------------------------------------------------------
-static bool DoesMaterialHaveKey( KeyValues *pKeyValues, const char *pKeyName )
-{
- const char *pVal;
- pVal = pKeyValues->GetString( pKeyName, NULL );
- if ( pVal != NULL )
- return true;
-
- for( KeyValues *pSubKey = pKeyValues->GetFirstTrueSubKey(); pSubKey; pSubKey = pSubKey->GetNextTrueSubKey() )
- {
- if ( DoesMaterialHaveKey( pSubKey, pKeyName) )
- return true;
- }
-
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// Scan material + all subsections for key/value pair
-//-----------------------------------------------------------------------------
-static bool DoesMaterialHaveKeyValuePair( KeyValues *pKeyValues, const char *pKeyName, const char *pSearchValue )
-{
- const char *pVal;
- pVal = pKeyValues->GetString( pKeyName, NULL );
- if ( pVal != NULL && ( Q_stricmp( pSearchValue, pVal ) == 0 ) )
- return true;
-
- for( KeyValues *pSubKey = pKeyValues->GetFirstTrueSubKey(); pSubKey; pSubKey = pSubKey->GetNextTrueSubKey() )
- {
- if ( DoesMaterialHaveKeyValuePair( pSubKey, pKeyName, pSearchValue ) )
- return true;
- }
-
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// Scan material + all subsections for key
-//-----------------------------------------------------------------------------
-bool DoesMaterialHaveKey( const char *pMaterialName, const char *pKeyName )
-{
- char name[512];
- Q_snprintf( name, 512, "materials/%s.vmt", GetOriginalMaterialNameForPatchedMaterial( pMaterialName ) );
- KeyValues *kv = new KeyValues( "blah" );
-
- if ( !kv->LoadFromFile( g_pFileSystem, name ) )
- {
- kv->deleteThis();
- return NULL;
- }
-
- bool retVal = DoesMaterialHaveKey( kv, pKeyName );
-
- kv->deleteThis();
- return retVal;
-}
-
-//-----------------------------------------------------------------------------
-// Scan material + all subsections for key/value pair
-//-----------------------------------------------------------------------------
-bool DoesMaterialHaveKeyValuePair( const char *pMaterialName, const char *pKeyName, const char *pSearchValue )
-{
- char name[512];
- Q_snprintf( name, 512, "materials/%s.vmt", GetOriginalMaterialNameForPatchedMaterial( pMaterialName ) );
- KeyValues *kv = new KeyValues( "blah" );
-
- if ( !kv->LoadFromFile( g_pFileSystem, name ) )
- {
- kv->deleteThis();
- return NULL;
- }
-
- bool retVal = DoesMaterialHaveKeyValuePair( kv, pKeyName, pSearchValue );
-
- kv->deleteThis();
- return retVal;
-}
-
-//-----------------------------------------------------------------------------
-// Gets a material value from a material. Ignores all patches
-//-----------------------------------------------------------------------------
-bool GetValueFromMaterial( const char *pMaterialName, const char *pKey, char *pValue, int len )
-{
- char name[512];
- Q_snprintf( name, 512, "materials/%s.vmt", GetOriginalMaterialNameForPatchedMaterial( pMaterialName ) );
- KeyValues *kv = new KeyValues( "blah" );
-
- if ( !kv->LoadFromFile( g_pFileSystem, name ) )
- {
-// Assert( 0 );
- kv->deleteThis();
- return NULL;
- }
-
- const char *pTmpValue = kv->GetString( pKey, NULL );
- if( pTmpValue )
- {
- Q_strncpy( pValue, pTmpValue, len );
- }
-
- kv->deleteThis();
- return ( pTmpValue != NULL );
-}
-
-
-//-----------------------------------------------------------------------------
-// Finds the original material associated with a patched material
-//-----------------------------------------------------------------------------
-MaterialSystemMaterial_t FindOriginalMaterial( const char *materialName, bool *pFound, bool bComplain )
-{
- MaterialSystemMaterial_t matID;
- matID = FindMaterial( GetOriginalMaterialNameForPatchedMaterial( materialName ), pFound, bComplain );
- return matID;
-}
-
-
-//-----------------------------------------------------------------------------
-// Load keyvalues from the local pack file, or from a file
-//-----------------------------------------------------------------------------
-bool LoadKeyValuesFromPackOrFile( const char *pFileName, KeyValues *pKeyValues )
-{
- CUtlBuffer buf;
- if ( ReadFileFromPak( GetPakFile(), pFileName, true, buf ) )
- {
- return pKeyValues->LoadFromBuffer( pFileName, buf );
- }
-
- return pKeyValues->LoadFromFile( g_pFileSystem, pFileName );
-}
-
-
-//-----------------------------------------------------------------------------
-// VMT parser
-//-----------------------------------------------------------------------------
-static void InsertKeyValues( KeyValues &dst, KeyValues& src, bool bCheckForExistence )
-{
- KeyValues *pSrcVar = src.GetFirstSubKey();
- while( pSrcVar )
- {
- if ( !bCheckForExistence || dst.FindKey( pSrcVar->GetName() ) )
- {
- switch( pSrcVar->GetDataType() )
- {
- case KeyValues::TYPE_STRING:
- dst.SetString( pSrcVar->GetName(), pSrcVar->GetString() );
- break;
- case KeyValues::TYPE_INT:
- dst.SetInt( pSrcVar->GetName(), pSrcVar->GetInt() );
- break;
- case KeyValues::TYPE_FLOAT:
- dst.SetFloat( pSrcVar->GetName(), pSrcVar->GetFloat() );
- break;
- case KeyValues::TYPE_PTR:
- dst.SetPtr( pSrcVar->GetName(), pSrcVar->GetPtr() );
- break;
- }
- }
- pSrcVar = pSrcVar->GetNextKey();
- }
-}
-
-static void ExpandPatchFile( KeyValues &keyValues )
-{
- int nCount = 0;
- while( nCount < 10 && stricmp( keyValues.GetName(), "patch" ) == 0 )
- {
-// WriteKeyValuesToFile( "patch.txt", keyValues );
- const char *pIncludeFileName = keyValues.GetString( "include" );
- if( !pIncludeFileName )
- return;
-
- KeyValues * includeKeyValues = new KeyValues( "vmt" );
- int nBufLen = Q_strlen( pIncludeFileName ) + Q_strlen( "materials/.vmt" ) + 1;
- char *pFileName = ( char * )stackalloc( nBufLen );
- Q_strncpy( pFileName, pIncludeFileName, nBufLen );
- bool bSuccess = LoadKeyValuesFromPackOrFile( pFileName, includeKeyValues );
- if ( !bSuccess )
- {
- includeKeyValues->deleteThis();
- return;
- }
-
- KeyValues *pInsertSection = keyValues.FindKey( "insert" );
- if( pInsertSection )
- {
- InsertKeyValues( *includeKeyValues, *pInsertSection, false );
- keyValues = *includeKeyValues;
- }
-
- KeyValues *pReplaceSection = keyValues.FindKey( "replace" );
- if( pReplaceSection )
- {
- InsertKeyValues( *includeKeyValues, *pReplaceSection, true );
- keyValues = *includeKeyValues;
- }
-
- // Could add other commands here, like "delete", "rename", etc.
-
- includeKeyValues->deleteThis();
- nCount++;
- }
-
- if( nCount >= 10 )
- {
- Warning( "Infinite recursion in patch file?\n" );
- }
-}
-
-KeyValues *LoadMaterialKeyValues( const char *pMaterialName, unsigned int nFlags )
-{
- // Load the underlying file
- KeyValues *kv = new KeyValues( "blah" );
-
- char pFullMaterialName[512];
- Q_snprintf( pFullMaterialName, 512, "materials/%s.vmt", pMaterialName );
- if ( !LoadKeyValuesFromPackOrFile( pFullMaterialName, kv ) )
- {
- // Assert( 0 );
- kv->deleteThis();
- return NULL;
- }
-
- if( nFlags & LOAD_MATERIAL_KEY_VALUES_FLAGS_EXPAND_PATCH )
- {
- ExpandPatchFile( *kv );
- }
-
- return kv;
-}
-
-void WriteMaterialKeyValuesToPak( const char *pMaterialName, KeyValues *kv )
-{
- char pFullMaterialName[512];
- Q_snprintf( pFullMaterialName, 512, "materials/%s.vmt", pMaterialName );
-
- // Write patched .vmt into a memory buffer
- CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
- kv->RecursiveSaveToFile( buf, 0 );
-
- // Add to pak file for this .bsp
- AddBufferToPak( GetPakFile(), pFullMaterialName, (void*)buf.Base(), buf.TellPut(), true );
-
- // Cleanup
- kv->deleteThis();
-}
-
-
-//-----------------------------------------------------------------------------
-// Gets a keyvalue from a *patched* material
-//-----------------------------------------------------------------------------
-bool GetValueFromPatchedMaterial( const char *pMaterialName, const char *pKey, char *pValue, int len )
-{
- // Load the underlying file so that we can check if env_cubemap is in there.
- KeyValues *kv = new KeyValues( "blah" );
-
- char pFullMaterialName[512];
- Q_snprintf( pFullMaterialName, 512, "materials/%s.vmt", pMaterialName );
- if ( !LoadKeyValuesFromPackOrFile( pFullMaterialName, kv ) )
- {
-// Assert( 0 );
- kv->deleteThis();
- return NULL;
- }
-
- ExpandPatchFile( *kv );
-
- const char *pTmpValue = kv->GetString( pKey, NULL );
- if( pTmpValue )
- {
- Q_strncpy( pValue, pTmpValue, len );
- }
-
- kv->deleteThis();
- return ( pTmpValue != NULL );
-}
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#include "vbsp.h"
+#include "UtlBuffer.h"
+#include "utlsymbol.h"
+#include "utlrbtree.h"
+#include "KeyValues.h"
+#include "bsplib.h"
+#include "materialpatch.h"
+#include "tier1/strtools.h"
+
+// case insensitive
+static CUtlSymbolTable s_SymbolTable( 0, 32, true );
+
+struct NameTranslationLookup_t
+{
+ CUtlSymbol m_OriginalFileName;
+ CUtlSymbol m_PatchFileName;
+};
+
+static bool NameTranslationLessFunc( NameTranslationLookup_t const& src1,
+ NameTranslationLookup_t const& src2 )
+{
+ return src1.m_PatchFileName < src2.m_PatchFileName;
+}
+
+CUtlRBTree<NameTranslationLookup_t, int> s_MapPatchedMatToOriginalMat( 0, 256, NameTranslationLessFunc );
+
+void AddNewTranslation( const char *pOriginalMaterialName, const char *pNewMaterialName )
+{
+ NameTranslationLookup_t newEntry;
+
+ newEntry.m_OriginalFileName = s_SymbolTable.AddString( pOriginalMaterialName );
+ newEntry.m_PatchFileName = s_SymbolTable.AddString( pNewMaterialName );
+
+ s_MapPatchedMatToOriginalMat.Insert( newEntry );
+}
+
+const char *GetOriginalMaterialNameForPatchedMaterial( const char *pPatchMaterialName )
+{
+ const char *pRetName = NULL;
+ int id;
+ NameTranslationLookup_t lookup;
+ lookup.m_PatchFileName = s_SymbolTable.AddString( pPatchMaterialName );
+ do
+ {
+ id = s_MapPatchedMatToOriginalMat.Find( lookup );
+ if( id >= 0 )
+ {
+ NameTranslationLookup_t &found = s_MapPatchedMatToOriginalMat[id];
+ lookup.m_PatchFileName = found.m_OriginalFileName;
+ pRetName = s_SymbolTable.String( found.m_OriginalFileName );
+ }
+ } while( id >= 0 );
+ if( !pRetName )
+ {
+ // This isn't a patched material, so just return the original name.
+ return pPatchMaterialName;
+ }
+ return pRetName;
+}
+
+
+void CreateMaterialPatchRecursive( KeyValues *pOriginalKeyValues, KeyValues *pPatchKeyValues, int nKeys, const MaterialPatchInfo_t *pInfo )
+{
+ int i;
+ for( i = 0; i < nKeys; i++ )
+ {
+ const char *pVal = pOriginalKeyValues->GetString( pInfo[i].m_pKey, NULL );
+ if( !pVal )
+ continue;
+ if( pInfo[i].m_pRequiredOriginalValue && Q_stricmp( pVal, pInfo[i].m_pRequiredOriginalValue ) != 0 )
+ continue;
+ pPatchKeyValues->SetString( pInfo[i].m_pKey, pInfo[i].m_pValue );
+ }
+ KeyValues *pScan;
+ for( pScan = pOriginalKeyValues->GetFirstTrueSubKey(); pScan; pScan = pScan->GetNextTrueSubKey() )
+ {
+ CreateMaterialPatchRecursive( pScan, pPatchKeyValues->FindKey( pScan->GetName(), true ), nKeys, pInfo );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// A version which allows you to patch multiple key values
+//-----------------------------------------------------------------------------
+void CreateMaterialPatch( const char *pOriginalMaterialName, const char *pNewMaterialName,
+ int nKeys, const MaterialPatchInfo_t *pInfo, MaterialPatchType_t nPatchType )
+{
+ char pOldVMTFile[ 512 ];
+ char pNewVMTFile[ 512 ];
+
+ AddNewTranslation( pOriginalMaterialName, pNewMaterialName );
+
+ Q_snprintf( pOldVMTFile, 512, "materials/%s.vmt", pOriginalMaterialName );
+ Q_snprintf( pNewVMTFile, 512, "materials/%s.vmt", pNewMaterialName );
+
+// printf( "Creating material patch file %s which points at %s\n", newVMTFile, oldVMTFile );
+
+ KeyValues *kv = new KeyValues( "patch" );
+ if ( !kv )
+ {
+ Error( "Couldn't allocate KeyValues for %s!!!", pNewMaterialName );
+ }
+
+ kv->SetString( "include", pOldVMTFile );
+
+ const char *pSectionName = (nPatchType == PATCH_INSERT) ? "insert" : "replace";
+ KeyValues *section = kv->FindKey( pSectionName, true );
+
+ if( nPatchType == PATCH_REPLACE )
+ {
+ char name[512];
+ Q_snprintf( name, 512, "materials/%s.vmt", GetOriginalMaterialNameForPatchedMaterial( pOriginalMaterialName ) );
+ KeyValues *origkv = new KeyValues( "blah" );
+
+ if ( !origkv->LoadFromFile( g_pFileSystem, name ) )
+ {
+ origkv->deleteThis();
+ Assert( 0 );
+ return;
+ }
+
+ CreateMaterialPatchRecursive( origkv, section, nKeys, pInfo );
+ origkv->deleteThis();
+ }
+ else
+ {
+ for ( int i = 0; i < nKeys; ++i )
+ {
+ section->SetString( pInfo[i].m_pKey, pInfo[i].m_pValue );
+ }
+ }
+
+ // Write patched .vmt into a memory buffer
+ CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
+ kv->RecursiveSaveToFile( buf, 0 );
+
+ // Add to pak file for this .bsp
+ AddBufferToPak( GetPakFile(), pNewVMTFile, (void*)buf.Base(), buf.TellPut(), true );
+
+ // Cleanup
+ kv->deleteThis();
+}
+
+
+//-----------------------------------------------------------------------------
+// Patches a single keyvalue in a material
+//-----------------------------------------------------------------------------
+void CreateMaterialPatch( const char *pOriginalMaterialName, const char *pNewMaterialName,
+ const char *pNewKey, const char *pNewValue, MaterialPatchType_t nPatchType )
+{
+ MaterialPatchInfo_t info;
+ info.m_pKey = pNewKey;
+ info.m_pValue = pNewValue;
+ CreateMaterialPatch( pOriginalMaterialName, pNewMaterialName, 1, &info, nPatchType );
+}
+
+
+//-----------------------------------------------------------------------------
+// Scan material + all subsections for key
+//-----------------------------------------------------------------------------
+static bool DoesMaterialHaveKey( KeyValues *pKeyValues, const char *pKeyName )
+{
+ const char *pVal;
+ pVal = pKeyValues->GetString( pKeyName, NULL );
+ if ( pVal != NULL )
+ return true;
+
+ for( KeyValues *pSubKey = pKeyValues->GetFirstTrueSubKey(); pSubKey; pSubKey = pSubKey->GetNextTrueSubKey() )
+ {
+ if ( DoesMaterialHaveKey( pSubKey, pKeyName) )
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Scan material + all subsections for key/value pair
+//-----------------------------------------------------------------------------
+static bool DoesMaterialHaveKeyValuePair( KeyValues *pKeyValues, const char *pKeyName, const char *pSearchValue )
+{
+ const char *pVal;
+ pVal = pKeyValues->GetString( pKeyName, NULL );
+ if ( pVal != NULL && ( Q_stricmp( pSearchValue, pVal ) == 0 ) )
+ return true;
+
+ for( KeyValues *pSubKey = pKeyValues->GetFirstTrueSubKey(); pSubKey; pSubKey = pSubKey->GetNextTrueSubKey() )
+ {
+ if ( DoesMaterialHaveKeyValuePair( pSubKey, pKeyName, pSearchValue ) )
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Scan material + all subsections for key
+//-----------------------------------------------------------------------------
+bool DoesMaterialHaveKey( const char *pMaterialName, const char *pKeyName )
+{
+ char name[512];
+ Q_snprintf( name, 512, "materials/%s.vmt", GetOriginalMaterialNameForPatchedMaterial( pMaterialName ) );
+ KeyValues *kv = new KeyValues( "blah" );
+
+ if ( !kv->LoadFromFile( g_pFileSystem, name ) )
+ {
+ kv->deleteThis();
+ return NULL;
+ }
+
+ bool retVal = DoesMaterialHaveKey( kv, pKeyName );
+
+ kv->deleteThis();
+ return retVal;
+}
+
+//-----------------------------------------------------------------------------
+// Scan material + all subsections for key/value pair
+//-----------------------------------------------------------------------------
+bool DoesMaterialHaveKeyValuePair( const char *pMaterialName, const char *pKeyName, const char *pSearchValue )
+{
+ char name[512];
+ Q_snprintf( name, 512, "materials/%s.vmt", GetOriginalMaterialNameForPatchedMaterial( pMaterialName ) );
+ KeyValues *kv = new KeyValues( "blah" );
+
+ if ( !kv->LoadFromFile( g_pFileSystem, name ) )
+ {
+ kv->deleteThis();
+ return NULL;
+ }
+
+ bool retVal = DoesMaterialHaveKeyValuePair( kv, pKeyName, pSearchValue );
+
+ kv->deleteThis();
+ return retVal;
+}
+
+//-----------------------------------------------------------------------------
+// Gets a material value from a material. Ignores all patches
+//-----------------------------------------------------------------------------
+bool GetValueFromMaterial( const char *pMaterialName, const char *pKey, char *pValue, int len )
+{
+ char name[512];
+ Q_snprintf( name, 512, "materials/%s.vmt", GetOriginalMaterialNameForPatchedMaterial( pMaterialName ) );
+ KeyValues *kv = new KeyValues( "blah" );
+
+ if ( !kv->LoadFromFile( g_pFileSystem, name ) )
+ {
+// Assert( 0 );
+ kv->deleteThis();
+ return NULL;
+ }
+
+ const char *pTmpValue = kv->GetString( pKey, NULL );
+ if( pTmpValue )
+ {
+ Q_strncpy( pValue, pTmpValue, len );
+ }
+
+ kv->deleteThis();
+ return ( pTmpValue != NULL );
+}
+
+
+//-----------------------------------------------------------------------------
+// Finds the original material associated with a patched material
+//-----------------------------------------------------------------------------
+MaterialSystemMaterial_t FindOriginalMaterial( const char *materialName, bool *pFound, bool bComplain )
+{
+ MaterialSystemMaterial_t matID;
+ matID = FindMaterial( GetOriginalMaterialNameForPatchedMaterial( materialName ), pFound, bComplain );
+ return matID;
+}
+
+
+//-----------------------------------------------------------------------------
+// Load keyvalues from the local pack file, or from a file
+//-----------------------------------------------------------------------------
+bool LoadKeyValuesFromPackOrFile( const char *pFileName, KeyValues *pKeyValues )
+{
+ CUtlBuffer buf;
+ if ( ReadFileFromPak( GetPakFile(), pFileName, true, buf ) )
+ {
+ return pKeyValues->LoadFromBuffer( pFileName, buf );
+ }
+
+ return pKeyValues->LoadFromFile( g_pFileSystem, pFileName );
+}
+
+
+//-----------------------------------------------------------------------------
+// VMT parser
+//-----------------------------------------------------------------------------
+static void InsertKeyValues( KeyValues &dst, KeyValues& src, bool bCheckForExistence )
+{
+ KeyValues *pSrcVar = src.GetFirstSubKey();
+ while( pSrcVar )
+ {
+ if ( !bCheckForExistence || dst.FindKey( pSrcVar->GetName() ) )
+ {
+ switch( pSrcVar->GetDataType() )
+ {
+ case KeyValues::TYPE_STRING:
+ dst.SetString( pSrcVar->GetName(), pSrcVar->GetString() );
+ break;
+ case KeyValues::TYPE_INT:
+ dst.SetInt( pSrcVar->GetName(), pSrcVar->GetInt() );
+ break;
+ case KeyValues::TYPE_FLOAT:
+ dst.SetFloat( pSrcVar->GetName(), pSrcVar->GetFloat() );
+ break;
+ case KeyValues::TYPE_PTR:
+ dst.SetPtr( pSrcVar->GetName(), pSrcVar->GetPtr() );
+ break;
+ }
+ }
+ pSrcVar = pSrcVar->GetNextKey();
+ }
+}
+
+static void ExpandPatchFile( KeyValues &keyValues )
+{
+ int nCount = 0;
+ while( nCount < 10 && stricmp( keyValues.GetName(), "patch" ) == 0 )
+ {
+// WriteKeyValuesToFile( "patch.txt", keyValues );
+ const char *pIncludeFileName = keyValues.GetString( "include" );
+ if( !pIncludeFileName )
+ return;
+
+ KeyValues * includeKeyValues = new KeyValues( "vmt" );
+ int nBufLen = Q_strlen( pIncludeFileName ) + Q_strlen( "materials/.vmt" ) + 1;
+ char *pFileName = ( char * )stackalloc( nBufLen );
+ Q_strncpy( pFileName, pIncludeFileName, nBufLen );
+ bool bSuccess = LoadKeyValuesFromPackOrFile( pFileName, includeKeyValues );
+ if ( !bSuccess )
+ {
+ includeKeyValues->deleteThis();
+ return;
+ }
+
+ KeyValues *pInsertSection = keyValues.FindKey( "insert" );
+ if( pInsertSection )
+ {
+ InsertKeyValues( *includeKeyValues, *pInsertSection, false );
+ keyValues = *includeKeyValues;
+ }
+
+ KeyValues *pReplaceSection = keyValues.FindKey( "replace" );
+ if( pReplaceSection )
+ {
+ InsertKeyValues( *includeKeyValues, *pReplaceSection, true );
+ keyValues = *includeKeyValues;
+ }
+
+ // Could add other commands here, like "delete", "rename", etc.
+
+ includeKeyValues->deleteThis();
+ nCount++;
+ }
+
+ if( nCount >= 10 )
+ {
+ Warning( "Infinite recursion in patch file?\n" );
+ }
+}
+
+KeyValues *LoadMaterialKeyValues( const char *pMaterialName, unsigned int nFlags )
+{
+ // Load the underlying file
+ KeyValues *kv = new KeyValues( "blah" );
+
+ char pFullMaterialName[512];
+ Q_snprintf( pFullMaterialName, 512, "materials/%s.vmt", pMaterialName );
+ if ( !LoadKeyValuesFromPackOrFile( pFullMaterialName, kv ) )
+ {
+ // Assert( 0 );
+ kv->deleteThis();
+ return NULL;
+ }
+
+ if( nFlags & LOAD_MATERIAL_KEY_VALUES_FLAGS_EXPAND_PATCH )
+ {
+ ExpandPatchFile( *kv );
+ }
+
+ return kv;
+}
+
+void WriteMaterialKeyValuesToPak( const char *pMaterialName, KeyValues *kv )
+{
+ char pFullMaterialName[512];
+ Q_snprintf( pFullMaterialName, 512, "materials/%s.vmt", pMaterialName );
+
+ // Write patched .vmt into a memory buffer
+ CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
+ kv->RecursiveSaveToFile( buf, 0 );
+
+ // Add to pak file for this .bsp
+ AddBufferToPak( GetPakFile(), pFullMaterialName, (void*)buf.Base(), buf.TellPut(), true );
+
+ // Cleanup
+ kv->deleteThis();
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets a keyvalue from a *patched* material
+//-----------------------------------------------------------------------------
+bool GetValueFromPatchedMaterial( const char *pMaterialName, const char *pKey, char *pValue, int len )
+{
+ // Load the underlying file so that we can check if env_cubemap is in there.
+ KeyValues *kv = new KeyValues( "blah" );
+
+ char pFullMaterialName[512];
+ Q_snprintf( pFullMaterialName, 512, "materials/%s.vmt", pMaterialName );
+ if ( !LoadKeyValuesFromPackOrFile( pFullMaterialName, kv ) )
+ {
+// Assert( 0 );
+ kv->deleteThis();
+ return NULL;
+ }
+
+ ExpandPatchFile( *kv );
+
+ const char *pTmpValue = kv->GetString( pKey, NULL );
+ if( pTmpValue )
+ {
+ Q_strncpy( pValue, pTmpValue, len );
+ }
+
+ kv->deleteThis();
+ return ( pTmpValue != NULL );
+}