Team Fortress 2 Source Code as on 22/4/2020
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

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. #include <windows.h>
  3. #include "materialsystem/imaterialproxyfactory.h"
  4. #include "materialsystem/imaterialvar.h"
  5. #include "materialsystem/imaterialproxy.h"
  6. class C_BaseEntity;
  7. // Copied and bastardized a few material proxy classes from the TF client dll. The purpose here is
  8. // to make TF materials for paintable items show the default paint color (using the SelectFirstIfNotZero proxy)
  9. // and to completely hide the burn detail texture (fake BurnLevel proxy).
  10. // Implemented a lame material proxy factory that only knows about these two proxies.
  11. //-----------------------------------------------------------------------------
  12. // Helper class to deal with floating point inputs
  13. //-----------------------------------------------------------------------------
  14. class CFloatInput
  15. {
  16. public:
  17. bool Init( IMaterial *pMaterial, KeyValues *pKeyValues, const char *pKeyName, float flDefault = 0.0f );
  18. float GetFloat() const;
  19. private:
  20. float m_flValue;
  21. IMaterialVar *m_pFloatVar;
  22. int m_FloatVecComp;
  23. };
  24. bool CFloatInput::Init( IMaterial *pMaterial, KeyValues *pKeyValues, const char *pKeyName, float flDefault )
  25. {
  26. m_pFloatVar = NULL;
  27. KeyValues *pSection = pKeyValues->FindKey( pKeyName );
  28. if (pSection)
  29. {
  30. if (pSection->GetDataType() == KeyValues::TYPE_STRING)
  31. {
  32. const char *pVarName = pSection->GetString();
  33. // Look for numbers...
  34. float flValue;
  35. int nCount = sscanf( pVarName, "%f", &flValue );
  36. if (nCount == 1)
  37. {
  38. m_flValue = flValue;
  39. return true;
  40. }
  41. // Look for array specification...
  42. char pTemp[256];
  43. if (strchr(pVarName, '['))
  44. {
  45. // strip off the array...
  46. Q_strncpy( pTemp, pVarName, 256 );
  47. char *pArray = strchr( pTemp, '[' );
  48. *pArray++ = 0;
  49. char* pIEnd;
  50. m_FloatVecComp = strtol( pArray, &pIEnd, 10 );
  51. // Use the version without the array...
  52. pVarName = pTemp;
  53. }
  54. else
  55. {
  56. m_FloatVecComp = -1;
  57. }
  58. bool bFoundVar;
  59. m_pFloatVar = pMaterial->FindVar( pVarName, &bFoundVar, true );
  60. if (!bFoundVar)
  61. return false;
  62. }
  63. else
  64. {
  65. m_flValue = pSection->GetFloat();
  66. }
  67. }
  68. else
  69. {
  70. m_flValue = flDefault;
  71. }
  72. return true;
  73. }
  74. float CFloatInput::GetFloat() const
  75. {
  76. if (!m_pFloatVar)
  77. return m_flValue;
  78. if( m_FloatVecComp < 0 )
  79. return m_pFloatVar->GetFloatValue();
  80. int iVecSize = m_pFloatVar->VectorSize();
  81. if ( m_FloatVecComp >= iVecSize )
  82. return 0;
  83. float v[4];
  84. m_pFloatVar->GetVecValue( v, iVecSize );
  85. return v[m_FloatVecComp];
  86. }
  87. //-----------------------------------------------------------------------------
  88. //
  89. // Result proxy; a result (with vector friendliness)
  90. //
  91. //-----------------------------------------------------------------------------
  92. class CResultProxy : public IMaterialProxy
  93. {
  94. public:
  95. CResultProxy();
  96. virtual ~CResultProxy();
  97. virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
  98. virtual void Release( void ) { delete this; }
  99. virtual IMaterial *GetMaterial();
  100. protected:
  101. C_BaseEntity *BindArgToEntity( void *pArg );
  102. void SetFloatResult( float result );
  103. IMaterialVar* m_pResult;
  104. int m_ResultVecComp;
  105. };
  106. CResultProxy::CResultProxy() : m_pResult(0)
  107. {
  108. }
  109. CResultProxy::~CResultProxy()
  110. {
  111. }
  112. bool CResultProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
  113. {
  114. char const* pResult = pKeyValues->GetString( "resultVar" );
  115. if( !pResult )
  116. return false;
  117. // Look for array specification...
  118. char pTemp[256];
  119. if (strchr(pResult, '['))
  120. {
  121. // strip off the array...
  122. Q_strncpy( pTemp, pResult, 256 );
  123. char *pArray = strchr( pTemp, '[' );
  124. *pArray++ = 0;
  125. char* pIEnd;
  126. m_ResultVecComp = strtol( pArray, &pIEnd, 10 );
  127. // Use the version without the array...
  128. pResult = pTemp;
  129. }
  130. else
  131. {
  132. m_ResultVecComp = -1;
  133. }
  134. bool foundVar;
  135. m_pResult = pMaterial->FindVar( pResult, &foundVar, true );
  136. if( !foundVar )
  137. return false;
  138. return true;
  139. }
  140. //-----------------------------------------------------------------------------
  141. // A little code to allow us to set single components of vectors
  142. //-----------------------------------------------------------------------------
  143. void CResultProxy::SetFloatResult( float result )
  144. {
  145. if (m_pResult->GetType() == MATERIAL_VAR_TYPE_VECTOR)
  146. {
  147. if ( m_ResultVecComp >= 0 )
  148. {
  149. m_pResult->SetVecComponentValue( result, m_ResultVecComp );
  150. }
  151. else
  152. {
  153. float v[4];
  154. int vecSize = m_pResult->VectorSize();
  155. for (int i = 0; i < vecSize; ++i)
  156. v[i] = result;
  157. m_pResult->SetVecValue( v, vecSize );
  158. }
  159. }
  160. else
  161. {
  162. m_pResult->SetFloatValue( result );
  163. }
  164. }
  165. C_BaseEntity *CResultProxy::BindArgToEntity( void *pArg )
  166. {
  167. return NULL;
  168. /*
  169. IClientRenderable *pRend = (IClientRenderable *)pArg;
  170. return pRend->GetIClientUnknown()->GetBaseEntity();
  171. */
  172. }
  173. IMaterial *CResultProxy::GetMaterial()
  174. {
  175. return m_pResult->GetOwningMaterial();
  176. }
  177. //-----------------------------------------------------------------------------
  178. //
  179. // Base functional proxy; two sources (one is optional) and a result
  180. //
  181. //-----------------------------------------------------------------------------
  182. class CFunctionProxy : public CResultProxy
  183. {
  184. public:
  185. CFunctionProxy();
  186. virtual ~CFunctionProxy();
  187. virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
  188. protected:
  189. void ComputeResultType( MaterialVarType_t& resultType, int& vecSize );
  190. IMaterialVar* m_pSrc1;
  191. IMaterialVar* m_pSrc2;
  192. };
  193. CFunctionProxy::CFunctionProxy() : m_pSrc1(0), m_pSrc2(0)
  194. {
  195. }
  196. CFunctionProxy::~CFunctionProxy()
  197. {
  198. }
  199. bool CFunctionProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
  200. {
  201. if (!CResultProxy::Init( pMaterial, pKeyValues ))
  202. return false;
  203. char const* pSrcVar1 = pKeyValues->GetString( "srcVar1" );
  204. if( !pSrcVar1 )
  205. return false;
  206. bool foundVar;
  207. m_pSrc1 = pMaterial->FindVar( pSrcVar1, &foundVar, true );
  208. if( !foundVar )
  209. return false;
  210. // Source 2 is optional, some math ops may be single-input
  211. char const* pSrcVar2 = pKeyValues->GetString( "srcVar2" );
  212. if( pSrcVar2 && (*pSrcVar2) )
  213. {
  214. m_pSrc2 = pMaterial->FindVar( pSrcVar2, &foundVar, true );
  215. if( !foundVar )
  216. return false;
  217. }
  218. else
  219. {
  220. m_pSrc2 = 0;
  221. }
  222. return true;
  223. }
  224. void CFunctionProxy::ComputeResultType( MaterialVarType_t& resultType, int& vecSize )
  225. {
  226. // Feh, this is ugly. Basically, don't change the result type
  227. // unless it's undefined.
  228. resultType = m_pResult->GetType();
  229. if (resultType == MATERIAL_VAR_TYPE_VECTOR)
  230. {
  231. if (m_ResultVecComp >= 0)
  232. resultType = MATERIAL_VAR_TYPE_FLOAT;
  233. vecSize = m_pResult->VectorSize();
  234. }
  235. else if (resultType == MATERIAL_VAR_TYPE_UNDEFINED)
  236. {
  237. resultType = m_pSrc1->GetType();
  238. if (resultType == MATERIAL_VAR_TYPE_VECTOR)
  239. {
  240. vecSize = m_pSrc1->VectorSize();
  241. }
  242. else if ((resultType == MATERIAL_VAR_TYPE_UNDEFINED) && m_pSrc2)
  243. {
  244. resultType = m_pSrc2->GetType();
  245. if (resultType == MATERIAL_VAR_TYPE_VECTOR)
  246. {
  247. vecSize = m_pSrc2->VectorSize();
  248. }
  249. }
  250. }
  251. }
  252. class CFakeBurnLevelProxy : public CResultProxy
  253. {
  254. public:
  255. virtual void OnBind( void *pC_BaseEntity )
  256. {
  257. // Slam burn level to 0 to avoid the burn detail texture showing through in modelbrowser.
  258. Assert( m_pResult );
  259. if ( m_pResult )
  260. {
  261. m_pResult->SetFloatValue( 0.0f );
  262. }
  263. }
  264. };
  265. //-----------------------------------------------------------------------------
  266. // Selects the first var value if it's non-zero, otherwise goes with the second
  267. //-----------------------------------------------------------------------------
  268. class CSelectFirstIfNonZeroProxy : public CFunctionProxy
  269. {
  270. public:
  271. virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
  272. virtual void OnBind( void *pC_BaseEntity );
  273. };
  274. bool CSelectFirstIfNonZeroProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
  275. {
  276. // Requires 2 args..
  277. bool ok = CFunctionProxy::Init( pMaterial, pKeyValues );
  278. ok = ok && m_pSrc2;
  279. return ok;
  280. }
  281. void CSelectFirstIfNonZeroProxy::OnBind( void *pC_BaseEntity )
  282. {
  283. Assert( m_pSrc1 && m_pSrc2 && m_pResult );
  284. MaterialVarType_t resultType;
  285. int vecSize;
  286. ComputeResultType( resultType, vecSize );
  287. switch( resultType )
  288. {
  289. case MATERIAL_VAR_TYPE_VECTOR:
  290. {
  291. Vector a, b;
  292. m_pSrc1->GetVecValue( a.Base(), vecSize );
  293. m_pSrc2->GetVecValue( b.Base(), vecSize );
  294. if ( !a.IsZero() )
  295. {
  296. m_pResult->SetVecValue( a.Base(), vecSize );
  297. }
  298. else
  299. {
  300. m_pResult->SetVecValue( b.Base(), vecSize );
  301. }
  302. }
  303. break;
  304. case MATERIAL_VAR_TYPE_FLOAT:
  305. if ( m_pSrc1->GetFloatValue() )
  306. {
  307. SetFloatResult( m_pSrc1->GetFloatValue() );
  308. }
  309. else
  310. {
  311. SetFloatResult( m_pSrc2->GetFloatValue() );
  312. }
  313. break;
  314. case MATERIAL_VAR_TYPE_INT:
  315. if ( m_pSrc1->GetIntValue() )
  316. {
  317. m_pResult->SetFloatValue( m_pSrc1->GetIntValue() );
  318. }
  319. else
  320. {
  321. m_pResult->SetFloatValue( m_pSrc2->GetIntValue() );
  322. }
  323. break;
  324. }
  325. }
  326. class CModelBrowserMaterialProxyFactory : public IMaterialProxyFactory
  327. {
  328. public:
  329. virtual IMaterialProxy *CreateProxy( const char *proxyName )
  330. {
  331. if ( V_stricmp( proxyName, "SelectFirstIfNonZero" ) == 0 )
  332. {
  333. return new CSelectFirstIfNonZeroProxy;
  334. }
  335. else if ( V_stricmp( proxyName, "BurnLevel" ) == 0 )
  336. {
  337. return new CFakeBurnLevelProxy;
  338. }
  339. return NULL;
  340. }
  341. virtual void DeleteProxy( IMaterialProxy *pProxy )
  342. {
  343. if ( pProxy )
  344. {
  345. pProxy->Release();
  346. }
  347. }
  348. };