You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
412 lines
9.0 KiB
412 lines
9.0 KiB
//========= 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(); |
|
} |
|
} |
|
};
|
|
|