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.

1631 lines
42 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "materialsystem/imaterialvar.h"
  7. #include "materialsystem/imaterialsystem.h"
  8. #include "materialsystem/itexture.h"
  9. #include <string.h>
  10. #include "materialsystem_global.h"
  11. #include <stdlib.h>
  12. #include "shaderapi/ishaderapi.h"
  13. #include "imaterialinternal.h"
  14. #include "utlsymbol.h"
  15. #include "mempool.h"
  16. #include "itextureinternal.h"
  17. #include "tier0/dbg.h"
  18. #include "tier1/callqueue.h"
  19. #include "mathlib/vmatrix.h"
  20. #include "tier1/strtools.h"
  21. #include "texturemanager.h"
  22. #define MATERIALVAR_CHAR_BUF_SIZE 512
  23. #if !defined( _X360 )
  24. #pragma pack (1)
  25. #endif
  26. ConVar mat_texture_tracking( "mat_texture_tracking", IsDebug() ? "1" : "0" );
  27. CUtlMap<ITexture*, CInterlockedInt> s_TextureRefList( DefLessFunc( ITexture* ) );
  28. CUtlMap<ITexture*, CInterlockedInt> *g_pTextureRefList = &s_TextureRefList;
  29. struct MaterialVarMatrix_t
  30. {
  31. VMatrix m_Matrix;
  32. bool m_bIsIdent;
  33. };
  34. class CMaterialVar : public IMaterialVar
  35. {
  36. public:
  37. // stuff from IMaterialVar
  38. virtual const char * GetName( void ) const;
  39. virtual MaterialVarSym_t GetNameAsSymbol() const;
  40. virtual void SetFloatValue( float val );
  41. virtual void SetIntValue( int val );
  42. virtual void SetStringValue( const char *val );
  43. virtual const char * GetStringValue( void ) const;
  44. virtual void SetMatrixValue( VMatrix const& matrix );
  45. virtual VMatrix const& GetMatrixValue( );
  46. virtual bool MatrixIsIdentity( void ) const;
  47. virtual void SetVecValue( const float* pVal, int numComps );
  48. virtual void SetVecValue( float x, float y );
  49. virtual void SetVecValue( float x, float y, float z );
  50. virtual void SetVecValue( float x, float y, float z, float w );
  51. void SetVecValueInternal( const Vector4D &vec, int nComps );
  52. virtual void SetVecComponentValue( float fVal, int nComponent );
  53. virtual void GetLinearVecValue( float *val, int numComps ) const;
  54. virtual void SetFourCCValue( FourCC type, void *pData );
  55. virtual void GetFourCCValue( FourCC *type, void **ppData );
  56. virtual int GetIntValueInternal( void ) const;
  57. virtual float GetFloatValueInternal( void ) const;
  58. virtual float const* GetVecValueInternal( ) const;
  59. virtual void GetVecValueInternal( float *val, int numcomps ) const;
  60. virtual int VectorSizeInternal() const;
  61. // revisit: is this a good interface for textures?
  62. virtual ITexture * GetTextureValue( void );
  63. virtual void SetTextureValue( ITexture * );
  64. void SetTextureValueQueued( ITexture *texture );
  65. virtual IMaterial * GetMaterialValue( void );
  66. virtual void SetMaterialValue( IMaterial * );
  67. virtual operator ITexture *() { return GetTextureValue(); }
  68. virtual bool IsDefined() const;
  69. virtual void SetUndefined();
  70. virtual void CopyFrom( IMaterialVar *pMaterialVar );
  71. FORCEINLINE void Init( void )
  72. {
  73. m_nNumVectorComps = 4;
  74. m_VecVal.Init();
  75. m_pStringVal = NULL;
  76. m_intVal = 0;
  77. m_nTempIndex = 0xFF;
  78. m_bFakeMaterialVar = false;
  79. m_Type = MATERIAL_VAR_TYPE_INT;
  80. }
  81. // stuff that is only visible inside of the material system
  82. CMaterialVar();
  83. CMaterialVar( IMaterial* pMaterial, const char *key, VMatrix const& matrix );
  84. CMaterialVar( IMaterial* pMaterial, const char *key, const char *val );
  85. CMaterialVar( IMaterial* pMaterial, const char *key, float* pVal, int numcomps );
  86. CMaterialVar( IMaterial* pMaterial, const char *key, float val );
  87. CMaterialVar( IMaterial* pMaterial, const char *key, int val );
  88. CMaterialVar( IMaterial* pMaterial, const char *key );
  89. virtual ~CMaterialVar();
  90. virtual void SetValueAutodetectType( const char *val );
  91. virtual IMaterial * GetOwningMaterial() { return m_pMaterial; }
  92. private:
  93. // Cleans up material var data
  94. CMaterialVar *AllocThreadVar();
  95. void CleanUpData();
  96. // NOTE: Dummy vars have no backlink so we have to check the pointer here
  97. void VarChanged() { if ( m_pMaterial ) m_pMaterial->ReportVarChanged(this); }
  98. // class data
  99. static char s_CharBuf[MATERIALVAR_CHAR_BUF_SIZE];
  100. static ITextureInternal *m_dummyTexture;
  101. // Fixed-size allocator
  102. #ifdef NO_SBH // not needed if tier0 small block heap enabled
  103. DECLARE_FIXEDSIZE_ALLOCATOR( CMaterialVar );
  104. #endif
  105. // Owning material....
  106. IMaterialInternal* m_pMaterial;
  107. // Only using one of these at a time...
  108. struct FourCC_t
  109. {
  110. FourCC m_FourCC;
  111. void *m_pFourCCData;
  112. };
  113. FourCC_t *AllocFourCC();
  114. union
  115. {
  116. IMaterialInternal* m_pMaterialValue;
  117. ITextureInternal *m_pTexture;
  118. MaterialVarMatrix_t* m_pMatrix;
  119. FourCC_t *m_pFourCC;
  120. };
  121. };
  122. // Has to exist *after* fixed size allocator declaration
  123. #include "tier0/memdbgon.h"
  124. typedef CMaterialVar *CMaterialVarPtr;
  125. #ifdef NO_SBH // not needed if tier0 small block heap enabled
  126. DEFINE_FIXEDSIZE_ALLOCATOR( CMaterialVar, 1024, true );
  127. #endif
  128. // Stores symbols for the material vars
  129. static CUtlSymbolTableMT s_MaterialVarSymbols( 0, 32, true );
  130. static bool g_bDeleteUnreferencedTexturesEnabled = false;
  131. //-----------------------------------------------------------------------------
  132. // Used to make GetIntValue thread safe from within proxy calls
  133. //-----------------------------------------------------------------------------
  134. static CMaterialVar s_pTempMaterialVar[254];
  135. static MaterialVarMatrix_t s_pTempMatrix[254];
  136. static bool s_bEnableThreadedAccess = false;
  137. static int s_nTempVarsUsed = 0;
  138. static int s_nOverflowTempVars = 0;
  139. //-----------------------------------------------------------------------------
  140. // Global methods related to material vars
  141. //-----------------------------------------------------------------------------
  142. void EnableThreadedMaterialVarAccess( bool bEnable, IMaterialVar **ppParams, int nVarCount )
  143. {
  144. if ( s_bEnableThreadedAccess == bEnable )
  145. return;
  146. s_bEnableThreadedAccess = bEnable;
  147. if ( !s_bEnableThreadedAccess )
  148. {
  149. // Necessary to free up reference counts
  150. Assert( s_nTempVarsUsed <= Q_ARRAYSIZE(s_pTempMaterialVar) );
  151. for ( int i = 0; i < s_nTempVarsUsed; ++i )
  152. {
  153. s_pTempMaterialVar[i].SetUndefined();
  154. }
  155. for ( int i = 0; i < nVarCount; ++i )
  156. {
  157. ppParams[i]->SetTempIndex( 0xFF );
  158. }
  159. s_nTempVarsUsed = 0;
  160. if ( s_nOverflowTempVars )
  161. {
  162. Warning("Overflowed %d temp material vars!\n", s_nOverflowTempVars );
  163. s_nOverflowTempVars = 0;
  164. }
  165. }
  166. }
  167. CMaterialVar *CMaterialVar::AllocThreadVar()
  168. {
  169. if ( s_bEnableThreadedAccess )
  170. {
  171. if ( m_nTempIndex == 0xFF )
  172. {
  173. if ( s_nTempVarsUsed >= Q_ARRAYSIZE(s_pTempMaterialVar) )
  174. {
  175. s_nOverflowTempVars++;
  176. return NULL;
  177. }
  178. m_nTempIndex = s_nTempVarsUsed++;
  179. }
  180. return &s_pTempMaterialVar[m_nTempIndex];
  181. }
  182. return NULL;
  183. }
  184. //-----------------------------------------------------------------------------
  185. // Purpose: Static method
  186. // Input : enable -
  187. //-----------------------------------------------------------------------------
  188. void IMaterialVar::DeleteUnreferencedTextures( bool enable )
  189. {
  190. g_bDeleteUnreferencedTexturesEnabled = enable;
  191. }
  192. //-----------------------------------------------------------------------------
  193. // class factory methods
  194. //-----------------------------------------------------------------------------
  195. IMaterialVar* IMaterialVar::Create( IMaterial* pMaterial, const char* pKey, VMatrix const& matrix )
  196. {
  197. return new CMaterialVar( pMaterial, pKey, matrix );
  198. }
  199. IMaterialVar* IMaterialVar::Create( IMaterial* pMaterial, const char* pKey, const char* pVal )
  200. {
  201. return new CMaterialVar( pMaterial, pKey, pVal );
  202. }
  203. IMaterialVar* IMaterialVar::Create( IMaterial* pMaterial, const char* pKey, float* pVal, int numComps )
  204. {
  205. return new CMaterialVar( pMaterial, pKey, pVal, numComps );
  206. }
  207. IMaterialVar* IMaterialVar::Create( IMaterial* pMaterial, const char* pKey, float val )
  208. {
  209. return new CMaterialVar( pMaterial, pKey, val );
  210. }
  211. IMaterialVar* IMaterialVar::Create( IMaterial* pMaterial, const char* pKey, int val )
  212. {
  213. return new CMaterialVar( pMaterial, pKey, val );
  214. }
  215. IMaterialVar* IMaterialVar::Create( IMaterial* pMaterial, const char* pKey )
  216. {
  217. return new CMaterialVar( pMaterial, pKey );
  218. }
  219. void IMaterialVar::Destroy( IMaterialVar* pVar )
  220. {
  221. if (pVar)
  222. {
  223. CMaterialVar* pVarImp = static_cast<CMaterialVar*>(pVar);
  224. delete pVarImp;
  225. }
  226. }
  227. MaterialVarSym_t IMaterialVar::GetSymbol( const char* pName )
  228. {
  229. if (!pName)
  230. return UTL_INVAL_SYMBOL;
  231. char temp[1024];
  232. Q_strncpy( temp, pName, sizeof( temp ) );
  233. Q_strlower( temp );
  234. return s_MaterialVarSymbols.AddString( temp );
  235. }
  236. MaterialVarSym_t IMaterialVar::FindSymbol( const char* pName )
  237. {
  238. if (!pName)
  239. return UTL_INVAL_SYMBOL;
  240. return s_MaterialVarSymbols.Find( pName );
  241. }
  242. bool IMaterialVar::SymbolMatches( const char* pName, MaterialVarSym_t symbol )
  243. {
  244. return !Q_stricmp( s_MaterialVarSymbols.String(symbol), pName );
  245. }
  246. //-----------------------------------------------------------------------------
  247. // class globals
  248. //-----------------------------------------------------------------------------
  249. char CMaterialVar::s_CharBuf[MATERIALVAR_CHAR_BUF_SIZE];
  250. //-----------------------------------------------------------------------------
  251. // constructors
  252. //-----------------------------------------------------------------------------
  253. inline CMaterialVar::FourCC_t *CMaterialVar::AllocFourCC()
  254. {
  255. return new FourCC_t;
  256. }
  257. //-----------------------------------------------------------------------------
  258. // NOTE: This constructor is only used by the "fake" material vars
  259. // used to get thread mode working
  260. //-----------------------------------------------------------------------------
  261. CMaterialVar::CMaterialVar()
  262. {
  263. Init();
  264. m_pMaterial = NULL;
  265. m_bFakeMaterialVar = true;
  266. }
  267. //-------------------------------------
  268. CMaterialVar::CMaterialVar( IMaterial* pMaterial, const char *pKey, VMatrix const& matrix )
  269. {
  270. Init();
  271. Assert( pKey );
  272. m_pMaterial = static_cast<IMaterialInternal*>(pMaterial);
  273. m_Name = GetSymbol( pKey );
  274. Assert( m_Name != UTL_INVAL_SYMBOL );
  275. m_Type = MATERIAL_VAR_TYPE_MATRIX;
  276. m_pMatrix = new MaterialVarMatrix_t;
  277. Assert( m_pMatrix );
  278. MatrixCopy( matrix, m_pMatrix->m_Matrix );
  279. m_pMatrix->m_bIsIdent = matrix.IsIdentity();
  280. m_intVal = 0;
  281. m_VecVal.Init();
  282. }
  283. CMaterialVar::CMaterialVar( IMaterial* pMaterial, const char *pKey, const char *pVal )
  284. {
  285. Init();
  286. Assert( pVal && pKey );
  287. m_pMaterial = static_cast<IMaterialInternal*>(pMaterial);
  288. m_Name = GetSymbol( pKey );
  289. Assert( m_Name != UTL_INVAL_SYMBOL );
  290. int len = Q_strlen( pVal ) + 1;
  291. m_pStringVal = new char[ len ];
  292. Q_strncpy( m_pStringVal, pVal, len );
  293. m_Type = MATERIAL_VAR_TYPE_STRING;
  294. m_VecVal[0] = m_VecVal[1] = m_VecVal[2] = m_VecVal[3] = atof( m_pStringVal );
  295. m_intVal = int( atof( m_pStringVal ) );
  296. }
  297. CMaterialVar::CMaterialVar( IMaterial* pMaterial, const char *pKey, float* pVal, int numComps )
  298. {
  299. Init();
  300. Assert( pVal && pKey && (numComps <= 4) );
  301. m_pMaterial = static_cast<IMaterialInternal*>(pMaterial);;
  302. m_Name = GetSymbol( pKey );
  303. Assert( m_Name != UTL_INVAL_SYMBOL );
  304. m_Type = MATERIAL_VAR_TYPE_VECTOR;
  305. memcpy( m_VecVal.Base(), pVal, numComps * sizeof(float) );
  306. for (int i = numComps; i < 4; ++i)
  307. m_VecVal[i] = 0.0f;
  308. m_intVal = ( int ) m_VecVal[0];
  309. m_nNumVectorComps = numComps;
  310. }
  311. CMaterialVar::CMaterialVar( IMaterial* pMaterial, const char *pKey, float val )
  312. {
  313. Init();
  314. m_pMaterial = static_cast<IMaterialInternal*>(pMaterial);
  315. m_Name = GetSymbol( pKey );
  316. Assert( m_Name != UTL_INVAL_SYMBOL );
  317. m_Type = MATERIAL_VAR_TYPE_FLOAT;
  318. m_VecVal[0] = m_VecVal[1] = m_VecVal[2] = m_VecVal[3] = val;
  319. m_intVal = (int) val;
  320. }
  321. CMaterialVar::CMaterialVar( IMaterial* pMaterial, const char *pKey, int val )
  322. {
  323. Init();
  324. m_pMaterial = static_cast<IMaterialInternal*>(pMaterial);
  325. m_Name = GetSymbol( pKey );
  326. Assert( m_Name != UTL_INVAL_SYMBOL );
  327. m_Type = MATERIAL_VAR_TYPE_INT;
  328. m_VecVal[0] = m_VecVal[1] = m_VecVal[2] = m_VecVal[3] = (float) val;
  329. m_intVal = val;
  330. }
  331. CMaterialVar::CMaterialVar( IMaterial* pMaterial, const char *pKey )
  332. {
  333. Init();
  334. m_pMaterial = static_cast<IMaterialInternal*>(pMaterial);
  335. m_Name = GetSymbol( pKey );
  336. Assert( m_Name != UTL_INVAL_SYMBOL );
  337. m_Type = MATERIAL_VAR_TYPE_UNDEFINED;
  338. }
  339. //-----------------------------------------------------------------------------
  340. // destructor
  341. //-----------------------------------------------------------------------------
  342. CMaterialVar::~CMaterialVar()
  343. {
  344. CleanUpData();
  345. }
  346. //-----------------------------------------------------------------------------
  347. // Cleans up material var allocated data if necessary
  348. //-----------------------------------------------------------------------------
  349. void CMaterialVar::CleanUpData()
  350. {
  351. switch ( m_Type )
  352. {
  353. case MATERIAL_VAR_TYPE_STRING:
  354. delete [] m_pStringVal;
  355. m_pStringVal = NULL;
  356. break;
  357. case MATERIAL_VAR_TYPE_TEXTURE:
  358. // garymcthack
  359. if( m_pTexture && !IsTextureInternalEnvCubemap( m_pTexture ) )
  360. {
  361. m_pTexture->DecrementReferenceCount();
  362. if ( g_bDeleteUnreferencedTexturesEnabled )
  363. {
  364. m_pTexture->DeleteIfUnreferenced();
  365. }
  366. m_pTexture = NULL;
  367. }
  368. break;
  369. case MATERIAL_VAR_TYPE_MATERIAL:
  370. if( m_pMaterialValue != NULL )
  371. {
  372. m_pMaterialValue->DecrementReferenceCount();
  373. m_pMaterialValue = NULL;
  374. }
  375. break;
  376. case MATERIAL_VAR_TYPE_MATRIX:
  377. delete m_pMatrix;
  378. m_pMatrix = NULL;
  379. break;
  380. case MATERIAL_VAR_TYPE_FOURCC:
  381. delete m_pFourCC;
  382. m_pFourCC = NULL;
  383. break;
  384. case MATERIAL_VAR_TYPE_VECTOR:
  385. case MATERIAL_VAR_TYPE_INT:
  386. case MATERIAL_VAR_TYPE_FLOAT:
  387. default:
  388. break;
  389. }
  390. }
  391. //-----------------------------------------------------------------------------
  392. // name + type
  393. //-----------------------------------------------------------------------------
  394. MaterialVarSym_t CMaterialVar::GetNameAsSymbol() const
  395. {
  396. return m_Name;
  397. }
  398. const char *CMaterialVar::GetName( ) const
  399. {
  400. if( !m_Name.IsValid() )
  401. {
  402. Warning( "m_pName is NULL for CMaterialVar\n" );
  403. return "";
  404. }
  405. return s_MaterialVarSymbols.String( m_Name );
  406. }
  407. //-----------------------------------------------------------------------------
  408. // Thread-safe versions
  409. //-----------------------------------------------------------------------------
  410. int CMaterialVar::GetIntValueInternal( void ) const
  411. {
  412. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  413. if ( pCallQueue && !m_bFakeMaterialVar )
  414. {
  415. if ( !s_bEnableThreadedAccess )
  416. {
  417. //DevMsg( 2, "Non-thread safe call to CMaterialVar %s!\n", GetName() );
  418. }
  419. if ( m_nTempIndex != 0xFF )
  420. return s_pTempMaterialVar[m_nTempIndex].GetIntValueInternal();
  421. }
  422. // Set methods for float and vector update this
  423. return m_intVal;
  424. }
  425. float CMaterialVar::GetFloatValueInternal( void ) const
  426. {
  427. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  428. if ( pCallQueue && !m_bFakeMaterialVar )
  429. {
  430. if ( !s_bEnableThreadedAccess )
  431. {
  432. //DevMsg( 2, "Non-thread safe call to CMaterialVar %s!\n", GetName() );
  433. }
  434. if ( m_nTempIndex != 0xFF )
  435. return s_pTempMaterialVar[m_nTempIndex].GetFloatValueInternal();
  436. }
  437. return m_VecVal[0];
  438. }
  439. float const* CMaterialVar::GetVecValueInternal( ) const
  440. {
  441. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  442. if ( pCallQueue && !m_bFakeMaterialVar )
  443. {
  444. if ( !s_bEnableThreadedAccess )
  445. {
  446. //DevMsg( 2, "Non-thread safe call to CMaterialVar %s!\n", GetName() );
  447. }
  448. if ( m_nTempIndex != 0xFF )
  449. return s_pTempMaterialVar[m_nTempIndex].GetVecValueInternal();
  450. }
  451. return m_VecVal.Base();
  452. }
  453. void CMaterialVar::GetVecValueInternal( float *val, int numcomps ) const
  454. {
  455. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  456. if ( pCallQueue && !m_bFakeMaterialVar )
  457. {
  458. if ( !s_bEnableThreadedAccess )
  459. {
  460. //DevMsg( 2, "Non-thread safe call to CMaterialVar %s!\n", GetName() );
  461. }
  462. if ( m_nTempIndex != 0xFF )
  463. {
  464. s_pTempMaterialVar[m_nTempIndex].GetVecValueInternal( val, numcomps );
  465. return;
  466. }
  467. }
  468. Assert( ( numcomps >0 ) && ( numcomps <= 4 ) );
  469. for( int i=0 ; i < numcomps; i++ )
  470. {
  471. val[i] = m_VecVal[ i ];
  472. }
  473. }
  474. int CMaterialVar::VectorSizeInternal() const
  475. {
  476. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  477. if ( pCallQueue && !m_bFakeMaterialVar )
  478. {
  479. if ( !s_bEnableThreadedAccess )
  480. {
  481. //DevMsg( 2, "Non-thread safe call to CMaterialVar %s!\n", GetName() );
  482. }
  483. if ( m_nTempIndex != 0xFF )
  484. return s_pTempMaterialVar[m_nTempIndex].VectorSizeInternal( );
  485. }
  486. return m_nNumVectorComps;
  487. }
  488. // Don't want to be grabbing the dummy var and changing it's value. That usually means badness.
  489. #define ASSERT_NOT_DUMMY_VAR() AssertMsg( m_bFakeMaterialVar || ( V_stricmp( GetName(), "$dummyvar" ) != 0 ), "TRYING TO MODIFY $dummyvar, WHICH IS BAD, MMMKAY!" )
  490. //-----------------------------------------------------------------------------
  491. // float
  492. //-----------------------------------------------------------------------------
  493. void CMaterialVar::SetFloatValue( float val )
  494. {
  495. ASSERT_NOT_DUMMY_VAR();
  496. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  497. if ( !m_bFakeMaterialVar && pCallQueue )
  498. {
  499. CMaterialVar *pThreadVar = AllocThreadVar();
  500. if ( pThreadVar )
  501. {
  502. pThreadVar->SetFloatValue( val );
  503. }
  504. pCallQueue->QueueCall( this, &CMaterialVar::SetFloatValue, val );
  505. return;
  506. }
  507. // Suppress all this if we're not actually changing anything
  508. if ((m_Type == MATERIAL_VAR_TYPE_FLOAT) && (m_VecVal[0] == val))
  509. return;
  510. // Gotta flush if we've changed state and this is the current material
  511. if ( !m_bFakeMaterialVar && m_pMaterial && (m_pMaterial == ( IMaterialInternal* )MaterialSystem()->GetCurrentMaterial()))
  512. g_pShaderAPI->FlushBufferedPrimitives();
  513. CleanUpData();
  514. m_VecVal[0] = m_VecVal[1] = m_VecVal[2] = m_VecVal[3] = val;
  515. m_intVal = (int) val;
  516. m_Type = MATERIAL_VAR_TYPE_FLOAT;
  517. VarChanged();
  518. }
  519. //-----------------------------------------------------------------------------
  520. // int
  521. //-----------------------------------------------------------------------------
  522. void CMaterialVar::SetIntValue( int val )
  523. {
  524. ASSERT_NOT_DUMMY_VAR();
  525. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  526. if ( !m_bFakeMaterialVar && pCallQueue )
  527. {
  528. CMaterialVar *pThreadVar = AllocThreadVar();
  529. if ( pThreadVar )
  530. {
  531. pThreadVar->SetIntValue( val );
  532. }
  533. pCallQueue->QueueCall( this, &CMaterialVar::SetIntValue, val );
  534. return;
  535. }
  536. // Suppress all this if we're not actually changing anything
  537. if ((m_Type == MATERIAL_VAR_TYPE_INT) && (m_intVal == val))
  538. return;
  539. // Gotta flush if we've changed state and this is the current material
  540. if ( !m_bFakeMaterialVar && m_pMaterial && (m_pMaterial == ( IMaterialInternal* )MaterialSystem()->GetCurrentMaterial()))
  541. g_pShaderAPI->FlushBufferedPrimitives();
  542. CleanUpData();
  543. m_intVal = val;
  544. m_VecVal[0] = m_VecVal[1] = m_VecVal[2] = m_VecVal[3] = (float) val;
  545. m_Type = MATERIAL_VAR_TYPE_INT;
  546. VarChanged();
  547. }
  548. //-----------------------------------------------------------------------------
  549. // string
  550. //-----------------------------------------------------------------------------
  551. const char *CMaterialVar::GetStringValue( void ) const
  552. {
  553. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  554. if ( pCallQueue && !m_bFakeMaterialVar )
  555. {
  556. if ( !s_bEnableThreadedAccess )
  557. {
  558. //DevMsg( 2, "Non-thread safe call to CMaterialVar %s!\n", GetName() );
  559. }
  560. if ( m_nTempIndex != 0xFF )
  561. return s_pTempMaterialVar[m_nTempIndex].GetStringValue();
  562. }
  563. switch( m_Type )
  564. {
  565. case MATERIAL_VAR_TYPE_STRING:
  566. return m_pStringVal;
  567. case MATERIAL_VAR_TYPE_INT:
  568. Q_snprintf( s_CharBuf, sizeof( s_CharBuf ), "%d", m_intVal );
  569. return s_CharBuf;
  570. case MATERIAL_VAR_TYPE_FLOAT:
  571. Q_snprintf( s_CharBuf, sizeof( s_CharBuf ), "%f", m_VecVal[0] );
  572. return s_CharBuf;
  573. case MATERIAL_VAR_TYPE_VECTOR:
  574. {
  575. s_CharBuf[0] = '[';
  576. s_CharBuf[1] = ' ';
  577. int len = 2;
  578. for (int i = 0; i < m_nNumVectorComps; ++i)
  579. {
  580. if (len < sizeof( s_CharBuf ))
  581. {
  582. Q_snprintf( s_CharBuf + len, sizeof( s_CharBuf ) - len, "%f ", m_VecVal[i] );
  583. len += strlen( s_CharBuf + len );
  584. }
  585. }
  586. if (len < sizeof( s_CharBuf ) - 1)
  587. {
  588. s_CharBuf[len] = ']';
  589. s_CharBuf[len+1] = '\0';
  590. }
  591. else
  592. {
  593. s_CharBuf[sizeof( s_CharBuf )-1] = '\0';
  594. }
  595. return s_CharBuf;
  596. }
  597. case MATERIAL_VAR_TYPE_MATRIX:
  598. {
  599. s_CharBuf[0] = '[';
  600. s_CharBuf[1] = ' ';
  601. int len = 2;
  602. for (int i = 0; i < 4; ++i)
  603. {
  604. for (int j = 0; j < 4; ++j)
  605. {
  606. if (len < sizeof( s_CharBuf ))
  607. len += Q_snprintf( s_CharBuf + len, sizeof( s_CharBuf ) - len, "%.3f ", m_pMatrix->m_Matrix[j][i] );
  608. }
  609. }
  610. if (len < sizeof( s_CharBuf ) - 1)
  611. {
  612. s_CharBuf[len] = ']';
  613. s_CharBuf[len+1] = '\0';
  614. }
  615. else
  616. {
  617. s_CharBuf[sizeof( s_CharBuf )-1] = '\0';
  618. }
  619. return s_CharBuf;
  620. }
  621. case MATERIAL_VAR_TYPE_TEXTURE:
  622. // check for env_cubemap
  623. if( IsTextureInternalEnvCubemap( m_pTexture ) )
  624. {
  625. return "env_cubemap";
  626. }
  627. else
  628. {
  629. Q_snprintf( s_CharBuf, sizeof( s_CharBuf ), "%s", m_pTexture->GetName() );
  630. return s_CharBuf;
  631. }
  632. case MATERIAL_VAR_TYPE_MATERIAL:
  633. Q_snprintf( s_CharBuf, sizeof( s_CharBuf ), "%s", ( m_pMaterialValue ? m_pMaterialValue->GetName() : "" ) );
  634. return s_CharBuf;
  635. case MATERIAL_VAR_TYPE_UNDEFINED:
  636. return "<UNDEFINED>";
  637. default:
  638. Warning( "CMaterialVar::GetStringValue: Unknown material var type\n" );
  639. return "";
  640. }
  641. }
  642. void CMaterialVar::SetStringValue( const char *val )
  643. {
  644. ASSERT_NOT_DUMMY_VAR();
  645. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  646. if ( !m_bFakeMaterialVar && pCallQueue )
  647. {
  648. CMaterialVar *pThreadVar = AllocThreadVar();
  649. if ( pThreadVar )
  650. {
  651. pThreadVar->SetStringValue( val );
  652. }
  653. pCallQueue->QueueCall( this, &CMaterialVar::SetStringValue, CUtlEnvelope<const char *>(val) );
  654. return;
  655. }
  656. // Gotta flush if we've changed state and this is the current material
  657. if ( !m_bFakeMaterialVar && m_pMaterial && (m_pMaterial == ( IMaterialInternal* )MaterialSystem()->GetCurrentMaterial()))
  658. g_pShaderAPI->FlushBufferedPrimitives();
  659. CleanUpData();
  660. int len = Q_strlen( val ) + 1;
  661. m_pStringVal = new char[len];
  662. Q_strncpy( m_pStringVal, val, len );
  663. m_Type = MATERIAL_VAR_TYPE_STRING;
  664. m_intVal = atoi( val );
  665. m_VecVal[0] = m_VecVal[1] = m_VecVal[2] = m_VecVal[3] = atof( m_pStringVal );
  666. VarChanged();
  667. }
  668. void CMaterialVar::SetFourCCValue( FourCC type, void *pData )
  669. {
  670. ASSERT_NOT_DUMMY_VAR();
  671. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  672. if ( !m_bFakeMaterialVar && pCallQueue )
  673. {
  674. CMaterialVar *pThreadVar = AllocThreadVar();
  675. if ( pThreadVar )
  676. {
  677. pThreadVar->SetFourCCValue( type, pData );
  678. }
  679. pCallQueue->QueueCall( this, &CMaterialVar::SetFourCCValue, type, pData );
  680. return;
  681. }
  682. // Suppress all this if we're not actually changing anything
  683. if ((m_Type == MATERIAL_VAR_TYPE_FOURCC) && m_pFourCC->m_FourCC == type && m_pFourCC->m_pFourCCData == pData )
  684. return;
  685. // Gotta flush if we've changed state and this is the current material
  686. if ( !m_bFakeMaterialVar && m_pMaterial && (m_pMaterial == ( IMaterialInternal* )MaterialSystem()->GetCurrentMaterial()))
  687. g_pShaderAPI->FlushBufferedPrimitives();
  688. CleanUpData();
  689. m_pFourCC = AllocFourCC();
  690. m_pFourCC->m_FourCC = type;
  691. m_pFourCC->m_pFourCCData = pData;
  692. m_Type = MATERIAL_VAR_TYPE_FOURCC;
  693. m_VecVal.Init();
  694. m_intVal = 0;
  695. VarChanged();
  696. }
  697. void CMaterialVar::GetFourCCValue( FourCC *type, void **ppData )
  698. {
  699. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  700. if ( pCallQueue && !m_bFakeMaterialVar )
  701. {
  702. if ( !s_bEnableThreadedAccess )
  703. {
  704. //DevMsg( 2, "Non-thread safe call to CMaterialVar %s!\n", GetName() );
  705. }
  706. if ( m_nTempIndex != 0xFF )
  707. return s_pTempMaterialVar[m_nTempIndex].GetFourCCValue( type, ppData );
  708. }
  709. if( m_Type == MATERIAL_VAR_TYPE_FOURCC )
  710. {
  711. *type = m_pFourCC->m_FourCC;
  712. *ppData = m_pFourCC->m_pFourCCData;
  713. }
  714. else
  715. {
  716. *type = FOURCC_UNKNOWN;
  717. *ppData = 0;
  718. static int bitchCount;
  719. if( bitchCount < 10 )
  720. {
  721. Warning( "CMaterialVar::GetVecValue: trying to get a vec value for %s which is of type %d\n",
  722. GetName(), ( int )m_Type );
  723. bitchCount++;
  724. }
  725. }
  726. }
  727. //-----------------------------------------------------------------------------
  728. // texture
  729. //-----------------------------------------------------------------------------
  730. ITexture *CMaterialVar::GetTextureValue( void )
  731. {
  732. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  733. if ( pCallQueue && !m_bFakeMaterialVar )
  734. {
  735. if ( !s_bEnableThreadedAccess )
  736. {
  737. //DevMsg( 2, "Non-thread safe call to CMaterialVar %s!\n", GetName() );
  738. }
  739. if ( m_nTempIndex != 0xFF )
  740. return s_pTempMaterialVar[m_nTempIndex].GetTextureValue( );
  741. }
  742. ITexture *retVal = NULL;
  743. if( m_pMaterial )
  744. {
  745. m_pMaterial->Precache();
  746. }
  747. if( m_Type == MATERIAL_VAR_TYPE_TEXTURE )
  748. {
  749. if ( !IsTextureInternalEnvCubemap( m_pTexture ) )
  750. {
  751. retVal = static_cast<ITexture *>( m_pTexture );
  752. }
  753. else
  754. {
  755. retVal = MaterialSystem()->GetLocalCubemap();
  756. }
  757. if( !retVal )
  758. {
  759. static int bitchCount = 0;
  760. if( bitchCount < 10 )
  761. {
  762. Warning( "Invalid texture value in CMaterialVar::GetTextureValue\n" );
  763. bitchCount++;
  764. }
  765. }
  766. }
  767. else
  768. {
  769. static int bitchCount = 0;
  770. if( bitchCount < 10 )
  771. {
  772. Warning( "Requesting texture value from var \"%s\" which is "
  773. "not a texture value (material: %s)\n", GetName(),
  774. m_pMaterial ? m_pMaterial->GetName() : "NULL material" );
  775. bitchCount++;
  776. }
  777. }
  778. if( !retVal )
  779. {
  780. retVal = TextureManager()->ErrorTexture();
  781. }
  782. return retVal;
  783. }
  784. void CMaterialVar::SetTextureValueQueued( ITexture *texture )
  785. {
  786. SetTextureValue( texture );
  787. // Matches IncrementReferenceCount in SetTextureValue
  788. if ( texture )
  789. texture->DecrementReferenceCount();
  790. // Debug
  791. if ( mat_texture_tracking.GetBool() )
  792. {
  793. int iIndex = g_pTextureRefList->Find( texture );
  794. Assert( iIndex != g_pTextureRefList->InvalidIndex() );
  795. g_pTextureRefList->Element( iIndex )--;
  796. }
  797. }
  798. static bool s_bInitTextureRefList = false;
  799. void CMaterialVar::SetTextureValue( ITexture *texture )
  800. {
  801. if ( !s_bInitTextureRefList )
  802. {
  803. g_pTextureRefList->SetLessFunc( DefLessFunc( ITexture* ) );
  804. s_bInitTextureRefList = true;
  805. }
  806. // Avoid the garymcthack in CShaderSystem::LoadCubeMap by ensuring we're not using
  807. // the internal env cubemap.
  808. if ( ThreadInMainThread() && !IsTextureInternalEnvCubemap( static_cast<ITextureInternal*>( texture ) ) )
  809. {
  810. ITextureInternal* pTexInternal = assert_cast<ITextureInternal *>( texture );
  811. TextureManager()->RequestAllMipmaps( pTexInternal );
  812. }
  813. ASSERT_NOT_DUMMY_VAR();
  814. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  815. if ( !m_bFakeMaterialVar && pCallQueue )
  816. {
  817. // FIXME (toml): deal with reference count
  818. CMaterialVar *pThreadVar = AllocThreadVar();
  819. if ( pThreadVar )
  820. {
  821. pThreadVar->SetTextureValue( texture );
  822. }
  823. // Matches DecrementReferenceCount in SetTextureValueQueued
  824. if ( texture )
  825. texture->IncrementReferenceCount();
  826. // Debug!
  827. if ( mat_texture_tracking.GetBool() )
  828. {
  829. int iIndex = g_pTextureRefList->Find( texture );
  830. if ( iIndex == g_pTextureRefList->InvalidIndex() )
  831. {
  832. g_pTextureRefList->Insert( texture, 1 );
  833. }
  834. else
  835. {
  836. g_pTextureRefList->Element( iIndex )++;
  837. }
  838. }
  839. pCallQueue->QueueCall( this, &CMaterialVar::SetTextureValueQueued, texture );
  840. return;
  841. }
  842. ITextureInternal* pTexImp = static_cast<ITextureInternal *>( texture );
  843. // Suppress all this if we're not actually changing anything
  844. if ((m_Type == MATERIAL_VAR_TYPE_TEXTURE) && (m_pTexture == pTexImp))
  845. return;
  846. // Gotta flush if we've changed state and this is the current material
  847. if ( !m_bFakeMaterialVar && m_pMaterial && (m_pMaterial == MaterialSystem()->GetCurrentMaterial()))
  848. g_pShaderAPI->FlushBufferedPrimitives();
  849. if( pTexImp && !IsTextureInternalEnvCubemap( pTexImp ) )
  850. {
  851. pTexImp->IncrementReferenceCount();
  852. }
  853. CleanUpData();
  854. m_pTexture = pTexImp;
  855. m_Type = MATERIAL_VAR_TYPE_TEXTURE;
  856. m_intVal = 0;
  857. m_VecVal.Init();
  858. VarChanged();
  859. }
  860. //-----------------------------------------------------------------------------
  861. // material
  862. //-----------------------------------------------------------------------------
  863. IMaterial *CMaterialVar::GetMaterialValue( void )
  864. {
  865. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  866. if ( pCallQueue && !m_bFakeMaterialVar )
  867. {
  868. if ( !s_bEnableThreadedAccess )
  869. {
  870. //DevMsg( 2, "Non-thread safe call to CMaterialVar %s!\n", GetName() );
  871. }
  872. if ( m_nTempIndex != 0xFF )
  873. return s_pTempMaterialVar[m_nTempIndex].GetMaterialValue( );
  874. }
  875. IMaterial *retVal = NULL;
  876. if( m_pMaterial )
  877. {
  878. m_pMaterial->Precache();
  879. }
  880. if( m_Type == MATERIAL_VAR_TYPE_MATERIAL )
  881. {
  882. retVal = static_cast<IMaterial *>( m_pMaterialValue );
  883. }
  884. else
  885. {
  886. static int bitchCount = 0;
  887. if( bitchCount < 10 )
  888. {
  889. Warning( "Requesting material value from var \"%s\" which is "
  890. "not a material value (material: %s)\n", GetName(),
  891. m_pMaterial ? m_pMaterial->GetName() : "NULL material" );
  892. bitchCount++;
  893. }
  894. }
  895. return retVal;
  896. }
  897. void CMaterialVar::SetMaterialValue( IMaterial *pMaterial )
  898. {
  899. ASSERT_NOT_DUMMY_VAR();
  900. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  901. if ( !m_bFakeMaterialVar && pCallQueue )
  902. {
  903. // FIXME (toml): deal with reference count
  904. CMaterialVar *pThreadVar = AllocThreadVar();
  905. if ( pThreadVar )
  906. {
  907. pThreadVar->SetMaterialValue( pMaterial );
  908. }
  909. pCallQueue->QueueCall( this, &CMaterialVar::SetMaterialValue, pMaterial );
  910. return;
  911. }
  912. //HACKHACK: Only use the realtime material as the material value since converting it every time it's loaded could be forgotten, and chance of game code usage is low
  913. if( pMaterial )
  914. pMaterial = ((IMaterialInternal *)pMaterial)->GetRealTimeVersion();
  915. IMaterialInternal* pMaterialImp = static_cast<IMaterialInternal *>( pMaterial );
  916. // Suppress all this if we're not actually changing anything
  917. if ((m_Type == MATERIAL_VAR_TYPE_MATERIAL) && (m_pMaterialValue == pMaterialImp))
  918. return;
  919. // Gotta flush if we've changed state and this is the current material
  920. if ( !m_bFakeMaterialVar && m_pMaterial && (m_pMaterial == MaterialSystem()->GetCurrentMaterial()))
  921. {
  922. g_pShaderAPI->FlushBufferedPrimitives();
  923. }
  924. if( pMaterialImp != NULL )
  925. {
  926. pMaterialImp->IncrementReferenceCount();
  927. }
  928. CleanUpData();
  929. m_pMaterialValue = pMaterialImp;
  930. m_Type = MATERIAL_VAR_TYPE_MATERIAL;
  931. m_intVal = 0;
  932. m_VecVal.Init();
  933. VarChanged();
  934. }
  935. //-----------------------------------------------------------------------------
  936. // Vector
  937. //-----------------------------------------------------------------------------
  938. void CMaterialVar::GetLinearVecValue( float *pVal, int numComps ) const
  939. {
  940. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  941. if ( pCallQueue && !m_bFakeMaterialVar )
  942. {
  943. if ( !s_bEnableThreadedAccess )
  944. {
  945. //DevMsg( 2, "Non-thread safe call to CMaterialVar %s!\n", GetName() );
  946. }
  947. if ( m_nTempIndex != 0xFF )
  948. return s_pTempMaterialVar[m_nTempIndex].GetLinearVecValue( pVal, numComps );
  949. }
  950. Assert( numComps <= 4 );
  951. switch( m_Type )
  952. {
  953. case MATERIAL_VAR_TYPE_VECTOR:
  954. {
  955. for ( int i = 0; i < numComps; ++i )
  956. {
  957. pVal[i] = GammaToLinear( m_VecVal[i] );
  958. }
  959. }
  960. break;
  961. case MATERIAL_VAR_TYPE_INT:
  962. {
  963. for ( int i = 0; i < numComps; ++i )
  964. {
  965. pVal[i] = GammaToLinear( m_intVal );
  966. }
  967. }
  968. break;
  969. case MATERIAL_VAR_TYPE_FLOAT:
  970. {
  971. for ( int i = 0; i < numComps; ++i )
  972. {
  973. pVal[i] = GammaToLinear( m_VecVal[0] );
  974. }
  975. }
  976. break;
  977. case MATERIAL_VAR_TYPE_MATRIX:
  978. case MATERIAL_VAR_TYPE_UNDEFINED:
  979. {
  980. for ( int i = 0; i < numComps; ++i )
  981. {
  982. pVal[i] = 0.0f;
  983. }
  984. }
  985. break;
  986. default:
  987. Warning( "CMaterialVar::GetVecValue: trying to get a vec value for %s which is of type %d\n",
  988. GetName(), ( int )m_Type );
  989. break;
  990. }
  991. }
  992. void CMaterialVar::SetVecValueInternal( const Vector4D &vec, int nComps )
  993. {
  994. ASSERT_NOT_DUMMY_VAR();
  995. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  996. if ( !m_bFakeMaterialVar && pCallQueue )
  997. {
  998. CMaterialVar *pThreadVar = AllocThreadVar();
  999. if ( pThreadVar )
  1000. {
  1001. pThreadVar->SetVecValueInternal( vec, nComps );
  1002. }
  1003. pCallQueue->QueueCall( this, &CMaterialVar::SetVecValueInternal, RefToVal( vec ), nComps );
  1004. return;
  1005. }
  1006. // Suppress all this if we're not actually changing anything
  1007. if ((m_Type == MATERIAL_VAR_TYPE_VECTOR ) && (m_VecVal == vec ) )
  1008. return;
  1009. // Gotta flush if we've changed state and this is the current material
  1010. if ( !m_bFakeMaterialVar && m_pMaterial && (m_pMaterial == MaterialSystem()->GetCurrentMaterial()))
  1011. g_pShaderAPI->FlushBufferedPrimitives();
  1012. if ( m_Type != MATERIAL_VAR_TYPE_VECTOR )
  1013. {
  1014. CleanUpData();
  1015. m_Type = MATERIAL_VAR_TYPE_VECTOR;
  1016. }
  1017. Assert( nComps <= 4 );
  1018. m_nNumVectorComps = nComps;
  1019. memcpy( m_VecVal.Base(), vec.Base(), 4 * sizeof(float) );
  1020. m_intVal = ( int ) m_VecVal[0];
  1021. #ifdef _DEBUG
  1022. for (int i = m_nNumVectorComps; i < 4; ++i )
  1023. Assert( m_VecVal[i] == 0.0f );
  1024. #endif
  1025. VarChanged();
  1026. }
  1027. void CMaterialVar::SetVecValue( const float* pVal, int numComps )
  1028. {
  1029. Vector4D vec;
  1030. memcpy( vec.Base(), pVal, numComps * sizeof(float) );
  1031. for (int i = numComps; i < 4; ++i )
  1032. {
  1033. vec[i] = 0.0f;
  1034. }
  1035. SetVecValueInternal( vec, numComps);
  1036. }
  1037. void CMaterialVar::SetVecValue( float x, float y )
  1038. {
  1039. SetVecValueInternal( Vector4D( x, y, 0.0f, 0.0f ), 2 );
  1040. }
  1041. void CMaterialVar::SetVecValue( float x, float y, float z )
  1042. {
  1043. SetVecValueInternal( Vector4D( x, y, z, 0.0f ), 3 );
  1044. }
  1045. void CMaterialVar::SetVecValue( float x, float y, float z, float w )
  1046. {
  1047. SetVecValueInternal( Vector4D( x, y, z, w ), 4 );
  1048. }
  1049. void CMaterialVar::SetVecComponentValue( float fVal, int nComponent )
  1050. {
  1051. ASSERT_NOT_DUMMY_VAR();
  1052. #ifndef _CERT
  1053. // DIAF
  1054. if ( nComponent < 0 || nComponent > 3 )
  1055. {
  1056. Error( "Invalid vector component (%d) of variable %s referenced in material %s", nComponent, GetName(), GetOwningMaterial()->GetName() );
  1057. return;
  1058. }
  1059. #endif
  1060. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  1061. if ( !m_bFakeMaterialVar && pCallQueue )
  1062. {
  1063. if ( s_bEnableThreadedAccess )
  1064. {
  1065. bool bInit = ( m_nTempIndex == 0xFF ) ? true : false;
  1066. CMaterialVar *pThreadVar = AllocThreadVar();
  1067. if ( pThreadVar )
  1068. {
  1069. if ( bInit )
  1070. {
  1071. pThreadVar->SetVecValue( m_VecVal.Base(), m_nNumVectorComps );
  1072. }
  1073. pThreadVar->SetVecComponentValue( fVal, nComponent );
  1074. }
  1075. }
  1076. pCallQueue->QueueCall( this, &CMaterialVar::SetVecComponentValue, fVal, nComponent );
  1077. return;
  1078. }
  1079. // Suppress all this if we're not actually changing anything
  1080. if ((m_Type == MATERIAL_VAR_TYPE_VECTOR ) && (m_VecVal[nComponent] == fVal ) )
  1081. return;
  1082. // Gotta flush if we've changed state and this is the current material
  1083. if ( !m_bFakeMaterialVar && m_pMaterial && (m_pMaterial == MaterialSystem()->GetCurrentMaterial()))
  1084. g_pShaderAPI->FlushBufferedPrimitives();
  1085. if ( m_Type != MATERIAL_VAR_TYPE_VECTOR )
  1086. {
  1087. CleanUpData();
  1088. m_Type = MATERIAL_VAR_TYPE_VECTOR;
  1089. }
  1090. Assert( nComponent <= 3 );
  1091. if( m_nNumVectorComps < nComponent )
  1092. {
  1093. //reset all undefined components to 0
  1094. for( int i = m_nNumVectorComps; i != nComponent; ++i )
  1095. m_VecVal[i] = 0.0f;
  1096. m_nNumVectorComps = nComponent;
  1097. }
  1098. m_VecVal[nComponent] = fVal;
  1099. #ifdef _DEBUG
  1100. for (int i = m_nNumVectorComps; i < 4; ++i )
  1101. Assert( m_VecVal[i] == 0.0f );
  1102. #endif
  1103. VarChanged();
  1104. }
  1105. //-----------------------------------------------------------------------------
  1106. // Matrix
  1107. //-----------------------------------------------------------------------------
  1108. VMatrix const& CMaterialVar::GetMatrixValue( )
  1109. {
  1110. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  1111. if ( pCallQueue && !m_bFakeMaterialVar )
  1112. {
  1113. if ( !s_bEnableThreadedAccess )
  1114. {
  1115. //DevMsg( 2, "Non-thread safe call to CMaterialVar %s!\n", GetName() );
  1116. }
  1117. if ( m_nTempIndex != 0xFF )
  1118. return s_pTempMaterialVar[m_nTempIndex].GetMatrixValue();
  1119. }
  1120. if (m_Type == MATERIAL_VAR_TYPE_MATRIX)
  1121. return m_pMatrix->m_Matrix;
  1122. static VMatrix identity( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 );
  1123. return identity;
  1124. }
  1125. void CMaterialVar::SetMatrixValue( VMatrix const& matrix )
  1126. {
  1127. ASSERT_NOT_DUMMY_VAR();
  1128. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  1129. if ( !m_bFakeMaterialVar && pCallQueue )
  1130. {
  1131. CMaterialVar *pThreadVar = AllocThreadVar();
  1132. if ( pThreadVar )
  1133. {
  1134. pThreadVar->SetMatrixValue( matrix );
  1135. }
  1136. pCallQueue->QueueCall( this, &CMaterialVar::SetMatrixValue, RefToVal( matrix ) );
  1137. return;
  1138. }
  1139. // Gotta flush if we've changed state and this is the current material
  1140. if ( !m_bFakeMaterialVar && m_pMaterial && (m_pMaterial == MaterialSystem()->GetCurrentMaterial()))
  1141. g_pShaderAPI->FlushBufferedPrimitives();
  1142. CleanUpData();
  1143. // NOTE: This is necessary because the mempool MaterialVarMatrix_t uses is not threadsafe
  1144. m_pMatrix = new MaterialVarMatrix_t;
  1145. MatrixCopy( matrix, m_pMatrix->m_Matrix );
  1146. m_Type = MATERIAL_VAR_TYPE_MATRIX;
  1147. m_pMatrix->m_bIsIdent = matrix.IsIdentity();
  1148. m_VecVal.Init();
  1149. m_intVal = ( int ) m_VecVal[0];
  1150. VarChanged();
  1151. }
  1152. bool CMaterialVar::MatrixIsIdentity( void ) const
  1153. {
  1154. if( m_Type != MATERIAL_VAR_TYPE_MATRIX )
  1155. {
  1156. return true;
  1157. }
  1158. return m_pMatrix->m_bIsIdent;
  1159. }
  1160. //-----------------------------------------------------------------------------
  1161. // Undefined
  1162. //-----------------------------------------------------------------------------
  1163. bool CMaterialVar::IsDefined() const
  1164. {
  1165. return m_Type != MATERIAL_VAR_TYPE_UNDEFINED;
  1166. }
  1167. void CMaterialVar::SetUndefined()
  1168. {
  1169. ASSERT_NOT_DUMMY_VAR();
  1170. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  1171. if ( !m_bFakeMaterialVar && pCallQueue )
  1172. {
  1173. CMaterialVar *pThreadVar = AllocThreadVar();
  1174. if ( pThreadVar )
  1175. {
  1176. pThreadVar->SetUndefined( );
  1177. }
  1178. pCallQueue->QueueCall( this, &CMaterialVar::SetUndefined );
  1179. return;
  1180. }
  1181. if (m_Type == MATERIAL_VAR_TYPE_UNDEFINED)
  1182. return;
  1183. // Gotta flush if we've changed state and this is the current material
  1184. if ( !m_bFakeMaterialVar && m_pMaterial && (m_pMaterial == MaterialSystem()->GetCurrentMaterial()))
  1185. g_pShaderAPI->FlushBufferedPrimitives();
  1186. CleanUpData();
  1187. m_Type = MATERIAL_VAR_TYPE_UNDEFINED;
  1188. VarChanged();
  1189. }
  1190. //-----------------------------------------------------------------------------
  1191. // Copy from another material var
  1192. //-----------------------------------------------------------------------------
  1193. void CMaterialVar::CopyFrom( IMaterialVar *pMaterialVar )
  1194. {
  1195. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  1196. if ( !m_bFakeMaterialVar && pCallQueue )
  1197. {
  1198. CMaterialVar *pThreadVar = AllocThreadVar();
  1199. if ( pThreadVar )
  1200. {
  1201. pThreadVar->CopyFrom( pMaterialVar );
  1202. }
  1203. pCallQueue->QueueCall( this, &CMaterialVar::CopyFrom, pMaterialVar );
  1204. return;
  1205. }
  1206. switch( pMaterialVar->GetType() )
  1207. {
  1208. case MATERIAL_VAR_TYPE_FLOAT:
  1209. SetFloatValue( pMaterialVar->GetFloatValue() );
  1210. break;
  1211. case MATERIAL_VAR_TYPE_STRING:
  1212. SetStringValue( pMaterialVar->GetStringValue() );
  1213. break;
  1214. case MATERIAL_VAR_TYPE_VECTOR:
  1215. SetVecValue( pMaterialVar->GetVecValue(), pMaterialVar->VectorSize() );
  1216. break;
  1217. case MATERIAL_VAR_TYPE_TEXTURE:
  1218. SetTextureValue( pMaterialVar->GetTextureValue() );
  1219. break;
  1220. case MATERIAL_VAR_TYPE_INT:
  1221. SetIntValue( pMaterialVar->GetIntValue() );
  1222. break;
  1223. case MATERIAL_VAR_TYPE_FOURCC:
  1224. {
  1225. FourCC fourCC;
  1226. void *pData;
  1227. pMaterialVar->GetFourCCValue( &fourCC, &pData );
  1228. SetFourCCValue( fourCC, pData );
  1229. }
  1230. break;
  1231. case MATERIAL_VAR_TYPE_UNDEFINED:
  1232. SetUndefined();
  1233. break;
  1234. case MATERIAL_VAR_TYPE_MATRIX:
  1235. SetMatrixValue( pMaterialVar->GetMatrixValue() );
  1236. break;
  1237. case MATERIAL_VAR_TYPE_MATERIAL:
  1238. SetMaterialValue( pMaterialVar->GetMaterialValue() );
  1239. break;
  1240. default:
  1241. Assert(0);
  1242. }
  1243. }
  1244. //-----------------------------------------------------------------------------
  1245. // Parser utilities
  1246. //-----------------------------------------------------------------------------
  1247. static inline bool IsWhitespace( char c )
  1248. {
  1249. return c == ' ' || c == '\t';
  1250. }
  1251. static inline bool IsEndline( char c )
  1252. {
  1253. return c == '\n' || c == '\0';
  1254. }
  1255. static inline bool IsVector( const char* v )
  1256. {
  1257. while (IsWhitespace(*v))
  1258. {
  1259. ++v;
  1260. if (IsEndline(*v))
  1261. return false;
  1262. }
  1263. return *v == '[' || *v == '{';
  1264. }
  1265. //-----------------------------------------------------------------------------
  1266. // Creates a vector material var
  1267. //-----------------------------------------------------------------------------
  1268. static int ParseVectorFromKeyValueString( const char *pString, float vecVal[4] )
  1269. {
  1270. const char* pScan = pString;
  1271. bool divideBy255 = false;
  1272. // skip whitespace
  1273. while( IsWhitespace(*pScan) )
  1274. {
  1275. ++pScan;
  1276. }
  1277. if( *pScan == '{' )
  1278. {
  1279. divideBy255 = true;
  1280. }
  1281. else
  1282. {
  1283. Assert( *pScan == '[' );
  1284. }
  1285. // skip the '['
  1286. ++pScan;
  1287. int i;
  1288. for( i = 0; i < 4; i++ )
  1289. {
  1290. // skip whitespace
  1291. while( IsWhitespace(*pScan) )
  1292. {
  1293. ++pScan;
  1294. }
  1295. if( IsEndline(*pScan) || *pScan == ']' || *pScan == '}' )
  1296. {
  1297. if (*pScan != ']' && *pScan != '}')
  1298. {
  1299. Warning( "no ']' or '}' found in vector key in ParseVectorFromKeyValueString\n" );
  1300. }
  1301. // allow for vec2's, etc.
  1302. vecVal[i] = 0.0f;
  1303. break;
  1304. }
  1305. char* pEnd;
  1306. vecVal[i] = strtod( pScan, &pEnd );
  1307. if (pScan == pEnd)
  1308. {
  1309. Warning( "error parsing vector element in ParseVectorFromKeyValueString\n" );
  1310. return 0;
  1311. }
  1312. pScan = pEnd;
  1313. }
  1314. if( divideBy255 )
  1315. {
  1316. vecVal[0] *= ( 1.0f / 255.0f );
  1317. vecVal[1] *= ( 1.0f / 255.0f );
  1318. vecVal[2] *= ( 1.0f / 255.0f );
  1319. vecVal[3] *= ( 1.0f / 255.0f );
  1320. }
  1321. return i;
  1322. }
  1323. void CMaterialVar::SetValueAutodetectType( const char *val )
  1324. {
  1325. ASSERT_NOT_DUMMY_VAR();
  1326. int len = Q_strlen( val );
  1327. // Here, let's determine if we got a float or an int....
  1328. char* pIEnd; // pos where int scan ended
  1329. char* pFEnd; // pos where float scan ended
  1330. const char* pSEnd = val + len ; // pos where token ends
  1331. int ival = strtol( val, &pIEnd, 10 );
  1332. float fval = (float)strtod( val, &pFEnd );
  1333. if ( ( pFEnd > pIEnd ) && ( pFEnd == pSEnd ) )
  1334. {
  1335. SetFloatValue( fval );
  1336. return;
  1337. }
  1338. if ( pIEnd == pSEnd )
  1339. {
  1340. SetIntValue( ival );
  1341. return;
  1342. }
  1343. // Isn't an int or a float.
  1344. // Is it a matrix?
  1345. VMatrix mat;
  1346. int count = sscanf( val, " [ %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f ]",
  1347. &mat.m[0][0], &mat.m[0][1], &mat.m[0][2], &mat.m[0][3],
  1348. &mat.m[1][0], &mat.m[1][1], &mat.m[1][2], &mat.m[1][3],
  1349. &mat.m[2][0], &mat.m[2][1], &mat.m[2][2], &mat.m[2][3],
  1350. &mat.m[3][0], &mat.m[3][1], &mat.m[3][2], &mat.m[3][3] );
  1351. if (count == 16)
  1352. {
  1353. SetMatrixValue( mat );
  1354. return;
  1355. }
  1356. Vector2D scale, center;
  1357. float angle;
  1358. Vector2D translation;
  1359. count = sscanf( val, " center %f %f scale %f %f rotate %f translate %f %f",
  1360. &center.x, &center.y, &scale.x, &scale.y, &angle, &translation.x, &translation.y );
  1361. if (count == 7)
  1362. {
  1363. VMatrix temp;
  1364. MatrixBuildTranslation( mat, -center.x, -center.y, 0.0f );
  1365. MatrixBuildScale( temp, scale.x, scale.y, 1.0f );
  1366. MatrixMultiply( temp, mat, mat );
  1367. MatrixBuildRotateZ( temp, angle );
  1368. MatrixMultiply( temp, mat, mat );
  1369. MatrixBuildTranslation( temp, center.x + translation.x, center.y + translation.y, 0.0f );
  1370. MatrixMultiply( temp, mat, mat );
  1371. SetMatrixValue( mat );
  1372. return;
  1373. }
  1374. if( IsVector( val ) )
  1375. {
  1376. float vecVal[4];
  1377. int nDim = ParseVectorFromKeyValueString( val, vecVal );
  1378. if ( nDim > 0 )
  1379. {
  1380. SetVecValue( vecVal, nDim );
  1381. return;
  1382. }
  1383. }
  1384. SetStringValue( val );
  1385. }