//----------------------------------------------------------------------------- // Patches the $envmap for a material and all its dependents, returns true if any patching happened //----------------------------------------------------------------------------- static bool PatchEnvmapForMaterialAndDependents( const char *pMaterialName, const PatchInfo_t &info, const char *pCubemapTexture ) { // Do *NOT* patch the material if there is an $envmap specified and it's not 'env_cubemap' // FIXME: It's theoretically ok to patch the material if $envmap is not specified, // because we're using the 'replace' block, which will only add the env_cubemap if // $envmap is specified in the source material. But it will fail if someone adds // a specific non-env_cubemap $envmap to the source material at a later point. Bleah // See if we have an $envmap to patch bool bShouldPatchEnvCubemap = DoesMaterialHaveKeyValuePair( pMaterialName, "$envmap", "env_cubemap" ); // See if we have a dependent material to patch bool bDependentMaterialPatched = false; const char *pDependentMaterialVar = NULL; const char *pDependentMaterial = FindDependentMaterial( pMaterialName, &pDependentMaterialVar ); if ( pDependentMaterial ) { bDependentMaterialPatched = PatchEnvmapForMaterialAndDependents( pDependentMaterial, info, pCubemapTexture ); } // If we have neither to patch, we're done if ( !bShouldPatchEnvCubemap && !bDependentMaterialPatched ) return false; // Otherwise we have to make a patched version of ourselves char pPatchedMaterialName[1024]; GeneratePatchedName( pMaterialName, info, true, pPatchedMaterialName, 1024 ); MaterialPatchInfo_t pPatchInfo[2]; int nPatchCount = 0; if ( bShouldPatchEnvCubemap ) { pPatchInfo[nPatchCount].m_pKey = "$envmap"; pPatchInfo[nPatchCount].m_pRequiredOriginalValue = "env_cubemap"; pPatchInfo[nPatchCount].m_pValue = pCubemapTexture; ++nPatchCount; } char pDependentPatchedMaterialName[1024]; if ( bDependentMaterialPatched ) { // FIXME: Annoying! I either have to pass back the patched dependent material name // or reconstruct it. Both are sucky. GeneratePatchedName( pDependentMaterial, info, true, pDependentPatchedMaterialName, 1024 ); pPatchInfo[nPatchCount].m_pKey = pDependentMaterialVar; pPatchInfo[nPatchCount].m_pValue = pDependentPatchedMaterialName; ++nPatchCount; } CreateMaterialPatch( pMaterialName, pPatchedMaterialName, nPatchCount, pPatchInfo, PATCH_REPLACE ); return true; }
//----------------------------------------------------------------------------- // 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/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; }