413 lines
9.0 KiB
C
413 lines
9.0 KiB
C
|
//========= 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();
|
||
|
}
|
||
|
}
|
||
|
};
|