|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
#include <windows.h>
#include "materialsystem/imaterialproxyfactory.h"
#include "materialsystem/imaterialvar.h"
#include "materialsystem/imaterialproxy.h"
class C_BaseEntity;
// Copied and bastardized a few material proxy classes from the TF client dll. The purpose here is
// to make TF materials for paintable items show the default paint color (using the SelectFirstIfNotZero proxy)
// and to completely hide the burn detail texture (fake BurnLevel proxy).
// Implemented a lame material proxy factory that only knows about these two proxies.
//-----------------------------------------------------------------------------
// Helper class to deal with floating point inputs
//-----------------------------------------------------------------------------
class CFloatInput { public: bool Init( IMaterial *pMaterial, KeyValues *pKeyValues, const char *pKeyName, float flDefault = 0.0f ); float GetFloat() const;
private: float m_flValue; IMaterialVar *m_pFloatVar; int m_FloatVecComp; };
bool CFloatInput::Init( IMaterial *pMaterial, KeyValues *pKeyValues, const char *pKeyName, float flDefault ) { m_pFloatVar = NULL; KeyValues *pSection = pKeyValues->FindKey( pKeyName ); if (pSection) { if (pSection->GetDataType() == KeyValues::TYPE_STRING) { const char *pVarName = pSection->GetString();
// Look for numbers...
float flValue; int nCount = sscanf( pVarName, "%f", &flValue ); if (nCount == 1) { m_flValue = flValue; return true; }
// Look for array specification...
char pTemp[256]; if (strchr(pVarName, '[')) { // strip off the array...
Q_strncpy( pTemp, pVarName, 256 ); char *pArray = strchr( pTemp, '[' ); *pArray++ = 0;
char* pIEnd; m_FloatVecComp = strtol( pArray, &pIEnd, 10 );
// Use the version without the array...
pVarName = pTemp; } else { m_FloatVecComp = -1; }
bool bFoundVar; m_pFloatVar = pMaterial->FindVar( pVarName, &bFoundVar, true ); if (!bFoundVar) return false; } else { m_flValue = pSection->GetFloat(); } } else { m_flValue = flDefault; } return true; }
float CFloatInput::GetFloat() const { if (!m_pFloatVar) return m_flValue;
if( m_FloatVecComp < 0 ) return m_pFloatVar->GetFloatValue();
int iVecSize = m_pFloatVar->VectorSize(); if ( m_FloatVecComp >= iVecSize ) return 0;
float v[4]; m_pFloatVar->GetVecValue( v, iVecSize ); return v[m_FloatVecComp]; }
//-----------------------------------------------------------------------------
//
// Result proxy; a result (with vector friendliness)
//
//-----------------------------------------------------------------------------
class CResultProxy : public IMaterialProxy { public: CResultProxy(); virtual ~CResultProxy(); virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); virtual void Release( void ) { delete this; } virtual IMaterial *GetMaterial();
protected: C_BaseEntity *BindArgToEntity( void *pArg ); void SetFloatResult( float result );
IMaterialVar* m_pResult; int m_ResultVecComp; };
CResultProxy::CResultProxy() : m_pResult(0) { }
CResultProxy::~CResultProxy() { }
bool CResultProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) { char const* pResult = pKeyValues->GetString( "resultVar" ); if( !pResult ) return false;
// Look for array specification...
char pTemp[256]; if (strchr(pResult, '[')) { // strip off the array...
Q_strncpy( pTemp, pResult, 256 ); char *pArray = strchr( pTemp, '[' ); *pArray++ = 0;
char* pIEnd; m_ResultVecComp = strtol( pArray, &pIEnd, 10 );
// Use the version without the array...
pResult = pTemp; } else { m_ResultVecComp = -1; }
bool foundVar; m_pResult = pMaterial->FindVar( pResult, &foundVar, true ); if( !foundVar ) return false;
return true; }
//-----------------------------------------------------------------------------
// A little code to allow us to set single components of vectors
//-----------------------------------------------------------------------------
void CResultProxy::SetFloatResult( float result ) { if (m_pResult->GetType() == MATERIAL_VAR_TYPE_VECTOR) { if ( m_ResultVecComp >= 0 ) { m_pResult->SetVecComponentValue( result, m_ResultVecComp ); } else { float v[4]; int vecSize = m_pResult->VectorSize();
for (int i = 0; i < vecSize; ++i) v[i] = result;
m_pResult->SetVecValue( v, vecSize ); } } else { m_pResult->SetFloatValue( result ); } }
C_BaseEntity *CResultProxy::BindArgToEntity( void *pArg ) { return NULL; /*
IClientRenderable *pRend = (IClientRenderable *)pArg; return pRend->GetIClientUnknown()->GetBaseEntity(); */ }
IMaterial *CResultProxy::GetMaterial() { return m_pResult->GetOwningMaterial(); }
//-----------------------------------------------------------------------------
//
// Base functional proxy; two sources (one is optional) and a result
//
//-----------------------------------------------------------------------------
class CFunctionProxy : public CResultProxy { public: CFunctionProxy(); virtual ~CFunctionProxy(); virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
protected: void ComputeResultType( MaterialVarType_t& resultType, int& vecSize );
IMaterialVar* m_pSrc1; IMaterialVar* m_pSrc2; };
CFunctionProxy::CFunctionProxy() : m_pSrc1(0), m_pSrc2(0) { }
CFunctionProxy::~CFunctionProxy() { }
bool CFunctionProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) { if (!CResultProxy::Init( pMaterial, pKeyValues )) return false;
char const* pSrcVar1 = pKeyValues->GetString( "srcVar1" ); if( !pSrcVar1 ) return false;
bool foundVar; m_pSrc1 = pMaterial->FindVar( pSrcVar1, &foundVar, true ); if( !foundVar ) return false;
// Source 2 is optional, some math ops may be single-input
char const* pSrcVar2 = pKeyValues->GetString( "srcVar2" ); if( pSrcVar2 && (*pSrcVar2) ) { m_pSrc2 = pMaterial->FindVar( pSrcVar2, &foundVar, true ); if( !foundVar ) return false; } else { m_pSrc2 = 0; }
return true; }
void CFunctionProxy::ComputeResultType( MaterialVarType_t& resultType, int& vecSize ) { // Feh, this is ugly. Basically, don't change the result type
// unless it's undefined.
resultType = m_pResult->GetType(); if (resultType == MATERIAL_VAR_TYPE_VECTOR) { if (m_ResultVecComp >= 0) resultType = MATERIAL_VAR_TYPE_FLOAT; vecSize = m_pResult->VectorSize(); } else if (resultType == MATERIAL_VAR_TYPE_UNDEFINED) { resultType = m_pSrc1->GetType(); if (resultType == MATERIAL_VAR_TYPE_VECTOR) { vecSize = m_pSrc1->VectorSize(); } else if ((resultType == MATERIAL_VAR_TYPE_UNDEFINED) && m_pSrc2) { resultType = m_pSrc2->GetType(); if (resultType == MATERIAL_VAR_TYPE_VECTOR) { vecSize = m_pSrc2->VectorSize(); } } } }
class CFakeBurnLevelProxy : public CResultProxy { public: virtual void OnBind( void *pC_BaseEntity ) { // Slam burn level to 0 to avoid the burn detail texture showing through in modelbrowser.
Assert( m_pResult ); if ( m_pResult ) { m_pResult->SetFloatValue( 0.0f ); } } };
//-----------------------------------------------------------------------------
// Selects the first var value if it's non-zero, otherwise goes with the second
//-----------------------------------------------------------------------------
class CSelectFirstIfNonZeroProxy : public CFunctionProxy { public: virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues ); virtual void OnBind( void *pC_BaseEntity ); };
bool CSelectFirstIfNonZeroProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues ) { // Requires 2 args..
bool ok = CFunctionProxy::Init( pMaterial, pKeyValues ); ok = ok && m_pSrc2; return ok; }
void CSelectFirstIfNonZeroProxy::OnBind( void *pC_BaseEntity ) { Assert( m_pSrc1 && m_pSrc2 && m_pResult );
MaterialVarType_t resultType; int vecSize; ComputeResultType( resultType, vecSize );
switch( resultType ) { case MATERIAL_VAR_TYPE_VECTOR: { Vector a, b; m_pSrc1->GetVecValue( a.Base(), vecSize ); m_pSrc2->GetVecValue( b.Base(), vecSize );
if ( !a.IsZero() ) { m_pResult->SetVecValue( a.Base(), vecSize ); } else { m_pResult->SetVecValue( b.Base(), vecSize ); } } break;
case MATERIAL_VAR_TYPE_FLOAT: if ( m_pSrc1->GetFloatValue() ) { SetFloatResult( m_pSrc1->GetFloatValue() ); } else { SetFloatResult( m_pSrc2->GetFloatValue() ); } break;
case MATERIAL_VAR_TYPE_INT: if ( m_pSrc1->GetIntValue() ) { m_pResult->SetFloatValue( m_pSrc1->GetIntValue() ); } else { m_pResult->SetFloatValue( m_pSrc2->GetIntValue() ); } break; } }
class CModelBrowserMaterialProxyFactory : public IMaterialProxyFactory { public: virtual IMaterialProxy *CreateProxy( const char *proxyName ) { if ( V_stricmp( proxyName, "SelectFirstIfNonZero" ) == 0 ) { return new CSelectFirstIfNonZeroProxy; } else if ( V_stricmp( proxyName, "BurnLevel" ) == 0 ) { return new CFakeBurnLevelProxy; } return NULL; }
virtual void DeleteProxy( IMaterialProxy *pProxy ) { if ( pProxy ) { pProxy->Release(); } } };
|