Counter Strike : Global Offensive Source Code
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.

2105 lines
52 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #if defined( _WIN32 ) && !defined( _X360 )
  7. #define WIN_32_LEAN_AND_MEAN
  8. #include <windows.h>
  9. #define VA_COMMIT_FLAGS MEM_COMMIT
  10. #define VA_RESERVE_FLAGS MEM_RESERVE
  11. #elif defined( _X360 )
  12. #undef Verify
  13. #define VA_COMMIT_FLAGS (MEM_COMMIT|MEM_NOZERO|MEM_LARGE_PAGES)
  14. #define VA_RESERVE_FLAGS (MEM_RESERVE|MEM_LARGE_PAGES)
  15. #endif
  16. #include "materialsystem/imaterialvar.h"
  17. #include "materialsystem/imaterialsystem.h"
  18. #include "materialsystem/itexture.h"
  19. #include "materialsystem/imaterialproxyfactory.h"
  20. #include <string.h>
  21. #include "materialsystem_global.h"
  22. #include <stdlib.h>
  23. #include "shaderapi/ishaderapi.h"
  24. #include "imaterialinternal.h"
  25. #include "utlsymbol.h"
  26. #include "mempool.h"
  27. #include "itextureinternal.h"
  28. #include "tier0/dbg.h"
  29. #include "tier0/vprof.h"
  30. #include "tier1/callqueue.h"
  31. #include "mathlib/vmatrix.h"
  32. #include "tier1/strtools.h"
  33. #include "tier1/keyvalues.h"
  34. #include "tier1/mempool.h"
  35. #include "texturemanager.h"
  36. #include "cdll_int.h"
  37. #include "tier1/utlmap.h"
  38. #define MATERIALVAR_CHAR_BUF_SIZE 512
  39. #if !defined( _X360 )
  40. #pragma pack (1)
  41. #endif
  42. //-----------------------------------------------------------------------------
  43. // Material var custom allocator
  44. //-----------------------------------------------------------------------------
  45. #ifdef _X360
  46. #define USE_MV_POOL
  47. #endif
  48. #ifdef USE_MV_POOL
  49. #define SIZEOF_MATVAR 40
  50. #define MAX_MATVARS ( 256*1024 )
  51. #define MV_PAGE_SIZE (64*1024)
  52. #define MV_NUM_PER_PAGE ( (64*1024) / SIZEOF_MATVAR )
  53. #define MV_SIZE_BUFFER ((MAX_MATVARS/MV_NUM_PER_PAGE)*MV_PAGE_SIZE)
  54. #define MV_NUM_PAGES ( MV_SIZE_BUFFER/MV_PAGE_SIZE )
  55. #define MV_NOT_COMMITTED ( (MVFreeBlock_t *)~0 )
  56. byte *g_pMVData = (byte *)VirtualAlloc( NULL, MV_NUM_PAGES * MV_PAGE_SIZE, VA_RESERVE_FLAGS, PAGE_NOACCESS );
  57. CThreadFastMutex g_MVDataMutex; // we never normally alloc & free during levels, and there's not much contention, so a mutex is fine
  58. struct MVFreeBlock_t
  59. {
  60. MVFreeBlock_t *pNext;
  61. byte pad[SIZEOF_MATVAR - sizeof(MVFreeBlock_t *)];
  62. };
  63. struct MVFreeHeader_t
  64. {
  65. MVFreeHeader_t() : pHead(MV_NOT_COMMITTED), nBlocks(MV_NUM_PER_PAGE) {}
  66. MVFreeBlock_t *pHead;
  67. int nBlocks;
  68. };
  69. MVFreeHeader_t g_MVFreeLists[MV_NUM_PAGES];
  70. int g_nMVAllocated;
  71. void DumpAllMaterialVars( void );
  72. void MVDumpHeap()
  73. {
  74. AUTO_LOCK( g_MVDataMutex );
  75. Msg( "MaterialVar heap:\n" );
  76. int sum = 0, pages = 0;
  77. for ( int i = 0; i < MV_NUM_PAGES; i++ )
  78. {
  79. sum += MV_NUM_PER_PAGE - g_MVFreeLists[i].nBlocks;
  80. Msg( " Page %3d: %d vars%s\n", i, MV_NUM_PER_PAGE - g_MVFreeLists[i].nBlocks, ( g_MVFreeLists[i].pHead == MV_NOT_COMMITTED ) ? " (decommitted)" : "" );
  81. if ( g_MVFreeLists[i].pHead != MV_NOT_COMMITTED )
  82. pages++;
  83. }
  84. if ( sum != g_nMVAllocated )
  85. {
  86. Msg( "\n************************** MaterialVar heap inconsistency! **************************\n\n" );
  87. }
  88. Msg( "Total of %d materialvars (%d logical bytes, %d actual bytes\n", g_nMVAllocated, g_nMVAllocated * SIZEOF_MATVAR, pages * MV_PAGE_SIZE );
  89. // Now dump individual materialvars, grouped by owning material:
  90. DumpAllMaterialVars();
  91. }
  92. bool MVInternallyAllocated( void * p )
  93. {
  94. return ( p >= g_pMVData && p < g_pMVData + MV_NUM_PAGES * MV_PAGE_SIZE );
  95. }
  96. MVFreeBlock_t *MVCommitAlloc( int iPage )
  97. {
  98. MVFreeBlock_t *pCur, *pLimit;
  99. MVFreeBlock_t *pBlock = (MVFreeBlock_t *)VirtualAlloc( g_pMVData + ( iPage * MV_PAGE_SIZE ), MV_PAGE_SIZE, VA_COMMIT_FLAGS, PAGE_READWRITE );
  100. pCur = g_MVFreeLists[iPage].pHead = pBlock + 1;
  101. pLimit = pBlock + ( MV_NUM_PER_PAGE - 1 );
  102. while ( pCur < pLimit )
  103. {
  104. pCur->pNext = pCur + 1;
  105. pCur++;
  106. }
  107. pLimit->pNext = NULL;
  108. g_MVFreeLists[iPage].nBlocks = ( MV_NUM_PER_PAGE - 1 );
  109. g_nMVAllocated++;
  110. return pBlock;
  111. }
  112. int MVFindBestPage()
  113. {
  114. AUTO_LOCK( g_MVDataMutex );
  115. int i;
  116. int iFirstUncommitted = -1;
  117. int iBestPage = -1;
  118. #ifdef MV_MOST_FULL
  119. // Most full page
  120. int nInMostFull = INT_MAX;
  121. for ( i = 0; i < MV_NUM_PAGES; i++ )
  122. {
  123. if ( g_MVFreeLists[i].pHead != MV_NOT_COMMITTED )
  124. {
  125. if ( g_MVFreeLists[i].nBlocks && g_MVFreeLists[i].nBlocks < nInMostFull )
  126. {
  127. iBestPage = i;
  128. nInMostFull = g_MVFreeLists[i].nBlocks;
  129. }
  130. }
  131. else if ( iFirstUncommitted == -1 )
  132. {
  133. iFirstUncommitted = i;
  134. }
  135. }
  136. #else
  137. // Lowest page
  138. for ( i = 0; i < MV_NUM_PAGES; i++ )
  139. {
  140. if ( g_MVFreeLists[i].pHead != MV_NOT_COMMITTED )
  141. {
  142. if ( g_MVFreeLists[i].nBlocks )
  143. {
  144. iBestPage = i;
  145. break;
  146. }
  147. }
  148. else if ( iFirstUncommitted == -1 )
  149. {
  150. iFirstUncommitted = i;
  151. }
  152. }
  153. #endif
  154. if ( iBestPage != -1 )
  155. {
  156. return iBestPage;
  157. }
  158. return iFirstUncommitted;
  159. }
  160. void *MVAlloc()
  161. {
  162. AUTO_LOCK( g_MVDataMutex );
  163. int iBestPage = MVFindBestPage();
  164. if ( iBestPage != -1 )
  165. {
  166. MVFreeBlock_t *pBlock = NULL;
  167. if ( g_MVFreeLists[iBestPage].pHead != MV_NOT_COMMITTED )
  168. {
  169. pBlock = g_MVFreeLists[iBestPage].pHead;
  170. g_MVFreeLists[iBestPage].pHead = pBlock->pNext;
  171. g_MVFreeLists[iBestPage].nBlocks--;
  172. g_nMVAllocated++;
  173. }
  174. else
  175. {
  176. pBlock = MVCommitAlloc( iBestPage );
  177. }
  178. return pBlock;
  179. }
  180. return malloc( SIZEOF_MATVAR );
  181. }
  182. void MVFree( void *p )
  183. {
  184. if ( MVInternallyAllocated( p ) )
  185. {
  186. AUTO_LOCK( g_MVDataMutex );
  187. MVFreeBlock_t *pBlock = (MVFreeBlock_t *)p;
  188. int iPage = ( ( (byte *)pBlock - g_pMVData ) / MV_PAGE_SIZE );
  189. pBlock->pNext = g_MVFreeLists[iPage].pHead;
  190. g_MVFreeLists[iPage].pHead = pBlock;
  191. g_MVFreeLists[iPage].nBlocks++;
  192. g_nMVAllocated--;
  193. }
  194. else
  195. {
  196. free( p );
  197. }
  198. }
  199. void *MVRelocate( void *p )
  200. {
  201. AUTO_LOCK( g_MVDataMutex );
  202. MVFreeBlock_t *pBlockOld = (MVFreeBlock_t *)p;
  203. MVFreeBlock_t *pBlockNew = pBlockOld;
  204. int iCurPage = ( ( (byte *)pBlockOld - g_pMVData ) / MV_PAGE_SIZE );
  205. #ifdef MV_MOST_FULL
  206. if ( g_MVFreeLists[iCurPage].nBlocks == 0 )
  207. {
  208. return p;
  209. }
  210. #else
  211. if ( iCurPage <= g_nMVAllocated/MV_NUM_PER_PAGE )
  212. {
  213. return p;
  214. }
  215. #endif
  216. int iBestPage = MVFindBestPage();
  217. bool bMove;
  218. #ifdef MV_MOST_FULL
  219. bMove = ( iBestPage != iCurPage );
  220. #else
  221. bMove = ( iBestPage <= iCurPage );
  222. #endif
  223. if ( bMove )
  224. {
  225. if ( g_MVFreeLists[iBestPage].pHead != MV_NOT_COMMITTED )
  226. {
  227. pBlockNew = g_MVFreeLists[iBestPage].pHead;
  228. g_MVFreeLists[iBestPage].pHead = pBlockNew->pNext;
  229. g_MVFreeLists[iBestPage].nBlocks--;
  230. g_nMVAllocated++;
  231. }
  232. else
  233. {
  234. pBlockNew = MVCommitAlloc( iBestPage );
  235. }
  236. }
  237. if ( pBlockNew != pBlockOld )
  238. {
  239. memcpy( pBlockNew, pBlockOld, SIZEOF_MATVAR );
  240. MVFree( pBlockOld );
  241. }
  242. return pBlockNew;
  243. }
  244. void MVDecommitUnusedPages()
  245. {
  246. AUTO_LOCK( g_MVDataMutex );
  247. for ( int i = 0; i < MV_NUM_PAGES; i++ )
  248. {
  249. if ( g_MVFreeLists[i].pHead != MV_NOT_COMMITTED && g_MVFreeLists[i].nBlocks == MV_NUM_PER_PAGE )
  250. {
  251. VirtualFree( g_pMVData + ( i * MV_PAGE_SIZE ), MV_PAGE_SIZE, MEM_DECOMMIT );
  252. g_MVFreeLists[i].pHead = MV_NOT_COMMITTED;
  253. }
  254. }
  255. }
  256. CON_COMMAND( mv_decommit, "" )
  257. {
  258. MVDecommitUnusedPages();
  259. }
  260. CON_COMMAND( mv_status, "" )
  261. {
  262. MVDumpHeap();
  263. }
  264. #else
  265. void *MVRelocate( void *p )
  266. {
  267. return p;
  268. }
  269. void MVDecommitUnusedPages()
  270. {
  271. }
  272. bool MVInternallyAllocated( void * p )
  273. {
  274. return false;
  275. }
  276. void MVDumpHeap()
  277. {
  278. }
  279. #endif
  280. //-----------------------------------------------------------------------------
  281. struct MaterialVarMatrix_t
  282. {
  283. VMatrix m_Matrix;
  284. bool m_bIsIdent;
  285. };
  286. class CMaterialVar : public IMaterialVar
  287. {
  288. public:
  289. // stuff from IMaterialVar
  290. virtual const char * GetName( void ) const;
  291. virtual MaterialVarSym_t GetNameAsSymbol() const;
  292. virtual void SetFloatValue( float val );
  293. virtual void SetIntValue( int val );
  294. virtual void SetStringValue( const char *val );
  295. virtual const char * GetStringValue( void ) const;
  296. virtual void SetMatrixValue( VMatrix const& matrix );
  297. virtual VMatrix const& GetMatrixValue( );
  298. virtual bool MatrixIsIdentity( void ) const;
  299. virtual void SetVecValue( const float* pVal, int numComps );
  300. virtual void SetVecValue( float x, float y );
  301. virtual void SetVecValue( float x, float y, float z );
  302. virtual void SetVecValue( float x, float y, float z, float w );
  303. void SetVecValueInternal( const Vector4D &vec, int nComps );
  304. virtual void SetVecComponentValue( float fVal, int nComponent );
  305. virtual void GetLinearVecValue( float *val, int numComps ) const;
  306. virtual void SetFourCCValue( FourCC type, void *pData );
  307. virtual void GetFourCCValue( FourCC *type, void **ppData );
  308. virtual int GetIntValueInternal( void ) const;
  309. virtual float GetFloatValueInternal( void ) const;
  310. virtual float const* GetVecValueInternal( ) const;
  311. virtual void GetVecValueInternal( float *val, int numcomps ) const;
  312. virtual int VectorSizeInternal() const;
  313. // revisit: is this a good interface for textures?
  314. virtual ITexture * GetTextureValue( void );
  315. virtual bool IsTextureValueInternalEnvCubemap( void ) const;
  316. virtual void SetTextureValue( ITexture * );
  317. virtual IMaterial * GetMaterialValue( void );
  318. virtual void SetMaterialValue( IMaterial * );
  319. virtual operator ITexture *() { return GetTextureValue(); }
  320. virtual bool IsDefined() const;
  321. virtual void SetUndefined();
  322. virtual void CopyFrom( IMaterialVar *pMaterialVar );
  323. void Init( void )
  324. {
  325. m_nNumVectorComps = 4;
  326. m_VecVal.Init();
  327. m_pStringVal = NULL;
  328. m_intVal = 0;
  329. m_nTempIndex = 0xFF;
  330. m_bFakeMaterialVar = false;
  331. m_Type = MATERIAL_VAR_TYPE_INT;
  332. }
  333. // stuff that is only visible inside of the material system
  334. CMaterialVar();
  335. CMaterialVar( IMaterial* pMaterial, const char *key, VMatrix const& matrix );
  336. CMaterialVar( IMaterial* pMaterial, const char *key, const char *val );
  337. CMaterialVar( IMaterial* pMaterial, const char *key, float* pVal, int numcomps );
  338. CMaterialVar( IMaterial* pMaterial, const char *key, float val );
  339. CMaterialVar( IMaterial* pMaterial, const char *key, int val );
  340. CMaterialVar( IMaterial* pMaterial, const char *key );
  341. virtual ~CMaterialVar();
  342. virtual void SetValueAutodetectType( const char *val );
  343. virtual IMaterial * GetOwningMaterial() { return m_pMaterial; }
  344. #ifdef USE_MV_POOL
  345. // Fixed-size allocator
  346. inline void* operator new( size_t size ) { return MVAlloc(); }
  347. inline void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine ) { return MVAlloc(); }
  348. inline void operator delete( void* p ) { MVFree(p); }
  349. inline void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine ) { MVFree(p); }
  350. #else
  351. DECLARE_FIXEDSIZE_ALLOCATOR( CMaterialVar );
  352. #endif
  353. private:
  354. // Cleans up material var data
  355. void CleanUpData();
  356. // NOTE: Dummy vars have no backlink so we have to check the pointer here
  357. void VarChanged();
  358. #ifndef NO_TOOLFRAMEWORK
  359. void RecordToolMessage();
  360. #endif
  361. // class data
  362. static char s_CharBuf[MATERIALVAR_CHAR_BUF_SIZE];
  363. static ITextureInternal *m_dummyTexture;
  364. // Owning material....
  365. IMaterialInternal* m_pMaterial;
  366. // Only using one of these at a time...
  367. struct FourCC_t
  368. {
  369. FourCC m_FourCC;
  370. void *m_pFourCCData;
  371. };
  372. FourCC_t *AllocFourCC();
  373. union
  374. {
  375. IMaterialInternal* m_pMaterialValue;
  376. ITextureInternal *m_pTexture;
  377. MaterialVarMatrix_t* m_pMatrix;
  378. FourCC_t *m_pFourCC;
  379. };
  380. };
  381. // Has to exist *after* fixed size allocator declaration
  382. #include "tier0/memdbgon.h"
  383. typedef CMaterialVar *CMaterialVarPtr;
  384. #ifndef USE_MV_POOL
  385. DEFINE_FIXEDSIZE_ALLOCATOR( CMaterialVar, 1024, true );
  386. #endif
  387. // Stores symbols for the material vars
  388. static CUtlSymbolTableMT s_MaterialVarSymbols( 0, 32, true );
  389. static bool g_bDeleteUnreferencedTexturesEnabled = false;
  390. //-----------------------------------------------------------------------------
  391. // Used to make GetIntValue thread safe from within proxy calls
  392. //-----------------------------------------------------------------------------
  393. static CMaterialVar s_pTempMaterialVar[254];
  394. static MaterialVarMatrix_t s_pTempMatrix[254];
  395. static bool s_bEnableThreadedAccess = false;
  396. static int s_nTempVarsUsed = 0;
  397. //-----------------------------------------------------------------------------
  398. // Dump materialvars
  399. //-----------------------------------------------------------------------------
  400. #ifdef USE_MV_POOL
  401. bool MaterialVarLessFunc( IMaterial *const &a, IMaterial *const &b )
  402. {
  403. if ( a == b ) return 0;
  404. return ( V_stricmp( (a ? a->GetName() : "[UNKNOWN]"), (b ? b->GetName() : "[UNKNOWN]") ) < 0 );
  405. }
  406. void DumpAllMaterialVars( void )
  407. {
  408. CUtlMap< IMaterial*, int > matcounts( MaterialVarLessFunc );
  409. int numvars = 0;
  410. for ( int page = 0; page < MV_NUM_PAGES; page++ )
  411. {
  412. if ( g_MVFreeLists[page].pHead == MV_NOT_COMMITTED )
  413. continue;
  414. MVFreeBlock_t *block = (MVFreeBlock_t *)(g_pMVData + ( page * MV_PAGE_SIZE ));
  415. for ( int i = 0; i < MV_NUM_PER_PAGE; i++ )
  416. {
  417. if ( block->pNext && !MVInternallyAllocated( block->pNext ) )\
  418. {
  419. // not in the freelist
  420. CMaterialVar *var = (CMaterialVar *)block;
  421. IMaterial *mat = var->GetOwningMaterial();
  422. //Msg( " -- %40s | %s\n", (mat?mat->GetName():"[UNKNOWN]"), var->GetName() );
  423. int idx = matcounts.Find( mat );
  424. if ( idx == matcounts.InvalidIndex() )
  425. matcounts.Insert( mat, 1 );
  426. else
  427. matcounts.Element(idx)++;
  428. numvars++;
  429. }
  430. block++;
  431. }
  432. }
  433. //Msg("\n ==== Total %d materialvars:\n", numvars );
  434. for ( int j = matcounts.FirstInorder(); j != matcounts.InvalidIndex(); j = matcounts.NextInorder(j) )
  435. {
  436. IMaterial *mat = matcounts.Key(j);
  437. Msg( " -- %4d %s\n", matcounts.Element(j), (mat?mat->GetName():"[UNKNOWN]") );
  438. }
  439. Msg("\n ==== Total %d materialvars in %d materials\n", numvars, matcounts.Count() );
  440. }
  441. #endif // USE_MV_POOL
  442. //-----------------------------------------------------------------------------
  443. // Global methods related to material vars
  444. //-----------------------------------------------------------------------------
  445. void EnableThreadedMaterialVarAccess( bool bEnable, IMaterialVar **ppParams, int nVarCount )
  446. {
  447. if ( s_bEnableThreadedAccess == bEnable )
  448. return;
  449. s_bEnableThreadedAccess = bEnable;
  450. if ( !s_bEnableThreadedAccess )
  451. {
  452. // Necessary to free up reference counts
  453. for ( int i = 0; i < s_nTempVarsUsed; ++i )
  454. {
  455. s_pTempMaterialVar[i].SetUndefined();
  456. }
  457. for ( int i = 0; i < nVarCount; ++i )
  458. {
  459. ppParams[i]->SetTempIndex( 0xFF );
  460. }
  461. s_nTempVarsUsed = 0;
  462. }
  463. }
  464. //-----------------------------------------------------------------------------
  465. // Purpose: Static method
  466. // Input : enable -
  467. //-----------------------------------------------------------------------------
  468. void IMaterialVar::DeleteUnreferencedTextures( bool enable )
  469. {
  470. g_bDeleteUnreferencedTexturesEnabled = enable;
  471. }
  472. //-----------------------------------------------------------------------------
  473. // class factory methods
  474. //-----------------------------------------------------------------------------
  475. IMaterialVar* IMaterialVar::Create( IMaterial* pMaterial, const char* pKey, VMatrix const& matrix )
  476. {
  477. return new CMaterialVar( pMaterial, pKey, matrix );
  478. }
  479. IMaterialVar* IMaterialVar::Create( IMaterial* pMaterial, const char* pKey, const char* pVal )
  480. {
  481. return new CMaterialVar( pMaterial, pKey, pVal );
  482. }
  483. IMaterialVar* IMaterialVar::Create( IMaterial* pMaterial, const char* pKey, float* pVal, int numComps )
  484. {
  485. return new CMaterialVar( pMaterial, pKey, pVal, numComps );
  486. }
  487. IMaterialVar* IMaterialVar::Create( IMaterial* pMaterial, const char* pKey, float val )
  488. {
  489. return new CMaterialVar( pMaterial, pKey, val );
  490. }
  491. IMaterialVar* IMaterialVar::Create( IMaterial* pMaterial, const char* pKey, int val )
  492. {
  493. return new CMaterialVar( pMaterial, pKey, val );
  494. }
  495. IMaterialVar* IMaterialVar::Create( IMaterial* pMaterial, const char* pKey )
  496. {
  497. return new CMaterialVar( pMaterial, pKey );
  498. }
  499. void IMaterialVar::Destroy( IMaterialVar* pVar )
  500. {
  501. if (pVar)
  502. {
  503. CMaterialVar* pVarImp = static_cast<CMaterialVar*>(pVar);
  504. delete pVarImp;
  505. }
  506. }
  507. MaterialVarSym_t IMaterialVar::GetSymbol( const char* pName )
  508. {
  509. if (!pName)
  510. return UTL_INVAL_SYMBOL;
  511. char temp[1024];
  512. Q_strncpy( temp, pName, sizeof( temp ) );
  513. Q_strlower( temp );
  514. return s_MaterialVarSymbols.AddString( temp );
  515. }
  516. MaterialVarSym_t IMaterialVar::FindSymbol( const char* pName )
  517. {
  518. if (!pName)
  519. return UTL_INVAL_SYMBOL;
  520. return s_MaterialVarSymbols.Find( pName );
  521. }
  522. bool IMaterialVar::SymbolMatches( const char* pName, MaterialVarSym_t symbol )
  523. {
  524. return !Q_stricmp( s_MaterialVarSymbols.String(symbol), pName );
  525. }
  526. //-----------------------------------------------------------------------------
  527. // class globals
  528. //-----------------------------------------------------------------------------
  529. char CMaterialVar::s_CharBuf[MATERIALVAR_CHAR_BUF_SIZE];
  530. //-----------------------------------------------------------------------------
  531. // constructors
  532. //-----------------------------------------------------------------------------
  533. inline CMaterialVar::FourCC_t *CMaterialVar::AllocFourCC()
  534. {
  535. return new FourCC_t;
  536. }
  537. //-----------------------------------------------------------------------------
  538. // NOTE: This constructor is only used by the "fake" material vars
  539. // used to get thread mode working
  540. //-----------------------------------------------------------------------------
  541. CMaterialVar::CMaterialVar()
  542. {
  543. Init();
  544. m_pMaterial = NULL;
  545. m_bFakeMaterialVar = true;
  546. }
  547. //-------------------------------------
  548. CMaterialVar::CMaterialVar( IMaterial* pMaterial, const char *pKey, VMatrix const& matrix )
  549. {
  550. #ifdef POOL_MATVARS
  551. COMPILE_TIME_ASSERT( sizeof(CMaterialVar) == SIZEOF_MATVAR );
  552. if ( sizeof(CMaterialVar) != SIZEOF_MATVAR )
  553. {
  554. Error( "( sizeof(CMaterialVar) != SIZEOF_MATVAR )\n" );
  555. }
  556. #endif
  557. Init();
  558. Assert( pKey );
  559. m_pMaterial = static_cast<IMaterialInternal*>(pMaterial);
  560. m_Name = GetSymbol( pKey );
  561. Assert( m_Name != UTL_INVAL_SYMBOL );
  562. m_Type = MATERIAL_VAR_TYPE_MATRIX;
  563. m_pMatrix = new MaterialVarMatrix_t;
  564. Assert( m_pMatrix );
  565. MatrixCopy( matrix, m_pMatrix->m_Matrix );
  566. m_pMatrix->m_bIsIdent = matrix.IsIdentity();
  567. m_intVal = 0;
  568. m_VecVal.Init();
  569. }
  570. CMaterialVar::CMaterialVar( IMaterial* pMaterial, const char *pKey, const char *pVal )
  571. {
  572. Init();
  573. Assert( pVal && pKey );
  574. m_pMaterial = static_cast<IMaterialInternal*>(pMaterial);
  575. m_Name = GetSymbol( pKey );
  576. Assert( m_Name != UTL_INVAL_SYMBOL );
  577. int len = Q_strlen( pVal ) + 1;
  578. m_pStringVal = new char[ len ];
  579. Q_strncpy( m_pStringVal, pVal, len );
  580. m_Type = MATERIAL_VAR_TYPE_STRING;
  581. m_VecVal[0] = m_VecVal[1] = m_VecVal[2] = m_VecVal[3] = atof( m_pStringVal );
  582. m_intVal = int( atof( m_pStringVal ) );
  583. }
  584. CMaterialVar::CMaterialVar( IMaterial* pMaterial, const char *pKey, float* pVal, int numComps )
  585. {
  586. Init();
  587. Assert( pVal && pKey && (numComps <= 4) );
  588. m_pMaterial = static_cast<IMaterialInternal*>(pMaterial);;
  589. m_Name = GetSymbol( pKey );
  590. Assert( m_Name != UTL_INVAL_SYMBOL );
  591. m_Type = MATERIAL_VAR_TYPE_VECTOR;
  592. memcpy( m_VecVal.Base(), pVal, numComps * sizeof(float) );
  593. for (int i = numComps; i < 4; ++i)
  594. m_VecVal[i] = 0.0f;
  595. m_intVal = ( int ) m_VecVal[0];
  596. m_nNumVectorComps = numComps;
  597. }
  598. CMaterialVar::CMaterialVar( IMaterial* pMaterial, const char *pKey, float val )
  599. {
  600. Init();
  601. m_pMaterial = static_cast<IMaterialInternal*>(pMaterial);
  602. m_Name = GetSymbol( pKey );
  603. Assert( m_Name != UTL_INVAL_SYMBOL );
  604. m_Type = MATERIAL_VAR_TYPE_FLOAT;
  605. m_VecVal[0] = m_VecVal[1] = m_VecVal[2] = m_VecVal[3] = val;
  606. m_intVal = (int) val;
  607. }
  608. CMaterialVar::CMaterialVar( IMaterial* pMaterial, const char *pKey, int val )
  609. {
  610. Init();
  611. m_pMaterial = static_cast<IMaterialInternal*>(pMaterial);
  612. m_Name = GetSymbol( pKey );
  613. Assert( m_Name != UTL_INVAL_SYMBOL );
  614. m_Type = MATERIAL_VAR_TYPE_INT;
  615. m_VecVal[0] = m_VecVal[1] = m_VecVal[2] = m_VecVal[3] = (float) val;
  616. m_intVal = val;
  617. }
  618. CMaterialVar::CMaterialVar( IMaterial* pMaterial, const char *pKey )
  619. {
  620. Init();
  621. m_pMaterial = static_cast<IMaterialInternal*>(pMaterial);
  622. m_Name = GetSymbol( pKey );
  623. Assert( m_Name != UTL_INVAL_SYMBOL );
  624. m_Type = MATERIAL_VAR_TYPE_UNDEFINED;
  625. }
  626. //-----------------------------------------------------------------------------
  627. // destructor
  628. //-----------------------------------------------------------------------------
  629. CMaterialVar::~CMaterialVar()
  630. {
  631. CleanUpData();
  632. }
  633. //-----------------------------------------------------------------------------
  634. // Cleans up material var allocated data if necessary
  635. //-----------------------------------------------------------------------------
  636. void CMaterialVar::CleanUpData()
  637. {
  638. switch ( m_Type )
  639. {
  640. case MATERIAL_VAR_TYPE_STRING:
  641. delete [] m_pStringVal;
  642. break;
  643. case MATERIAL_VAR_TYPE_TEXTURE:
  644. // garymcthack
  645. if( !IsTextureInternalEnvCubemap( m_pTexture ) )
  646. {
  647. m_pTexture->DecrementReferenceCount();
  648. if ( g_bDeleteUnreferencedTexturesEnabled )
  649. {
  650. m_pTexture->DeleteIfUnreferenced();
  651. }
  652. }
  653. break;
  654. case MATERIAL_VAR_TYPE_MATERIAL:
  655. if( m_pMaterialValue != NULL )
  656. {
  657. m_pMaterialValue->DecrementReferenceCount();
  658. }
  659. break;
  660. case MATERIAL_VAR_TYPE_MATRIX:
  661. delete m_pMatrix;
  662. break;
  663. case MATERIAL_VAR_TYPE_FOURCC:
  664. delete m_pFourCC;
  665. break;
  666. case MATERIAL_VAR_TYPE_VECTOR:
  667. case MATERIAL_VAR_TYPE_INT:
  668. case MATERIAL_VAR_TYPE_FLOAT:
  669. default:
  670. break;
  671. }
  672. }
  673. //-----------------------------------------------------------------------------
  674. // name + type
  675. //-----------------------------------------------------------------------------
  676. MaterialVarSym_t CMaterialVar::GetNameAsSymbol() const
  677. {
  678. return m_Name;
  679. }
  680. const char *CMaterialVar::GetName( ) const
  681. {
  682. if( !m_Name.IsValid() )
  683. {
  684. Warning( "m_pName is NULL for CMaterialVar\n" );
  685. return "";
  686. }
  687. return s_MaterialVarSymbols.String( m_Name );
  688. }
  689. //-----------------------------------------------------------------------------
  690. // Thread-safe versions
  691. //-----------------------------------------------------------------------------
  692. int CMaterialVar::GetIntValueInternal( void ) const
  693. {
  694. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  695. if ( pCallQueue && !m_bFakeMaterialVar )
  696. {
  697. if ( !s_bEnableThreadedAccess )
  698. {
  699. //DevMsg( 2, "Non-thread safe call to CMaterialVar %s!\n", GetName() );
  700. }
  701. if ( m_nTempIndex != 0xFF )
  702. return s_pTempMaterialVar[m_nTempIndex].GetIntValueInternal();
  703. }
  704. // Set methods for float and vector update this
  705. return m_intVal;
  706. }
  707. float CMaterialVar::GetFloatValueInternal( void ) const
  708. {
  709. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  710. if ( pCallQueue && !m_bFakeMaterialVar )
  711. {
  712. if ( !s_bEnableThreadedAccess )
  713. {
  714. //DevMsg( 2, "Non-thread safe call to CMaterialVar %s!\n", GetName() );
  715. }
  716. if ( m_nTempIndex != 0xFF )
  717. return s_pTempMaterialVar[m_nTempIndex].GetFloatValueInternal();
  718. }
  719. return m_VecVal[0];
  720. }
  721. float const* CMaterialVar::GetVecValueInternal( ) const
  722. {
  723. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  724. if ( pCallQueue && !m_bFakeMaterialVar )
  725. {
  726. if ( !s_bEnableThreadedAccess )
  727. {
  728. //DevMsg( 2, "Non-thread safe call to CMaterialVar %s!\n", GetName() );
  729. }
  730. if ( m_nTempIndex != 0xFF )
  731. return s_pTempMaterialVar[m_nTempIndex].GetVecValueInternal();
  732. }
  733. return m_VecVal.Base();
  734. }
  735. void CMaterialVar::GetVecValueInternal( float *val, int numcomps ) const
  736. {
  737. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  738. if ( pCallQueue && !m_bFakeMaterialVar )
  739. {
  740. if ( !s_bEnableThreadedAccess )
  741. {
  742. //DevMsg( 2, "Non-thread safe call to CMaterialVar %s!\n", GetName() );
  743. }
  744. if ( m_nTempIndex != 0xFF )
  745. {
  746. s_pTempMaterialVar[m_nTempIndex].GetVecValueInternal( val, numcomps );
  747. return;
  748. }
  749. }
  750. Assert( ( numcomps >0 ) && ( numcomps <= 4 ) );
  751. for( int i=0 ; i < numcomps; i++ )
  752. {
  753. val[i] = m_VecVal[ i ];
  754. }
  755. }
  756. int CMaterialVar::VectorSizeInternal() const
  757. {
  758. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  759. if ( pCallQueue && !m_bFakeMaterialVar )
  760. {
  761. if ( !s_bEnableThreadedAccess )
  762. {
  763. //DevMsg( 2, "Non-thread safe call to CMaterialVar %s!\n", GetName() );
  764. }
  765. if ( m_nTempIndex != 0xFF )
  766. return s_pTempMaterialVar[m_nTempIndex].VectorSizeInternal( );
  767. }
  768. return m_nNumVectorComps;
  769. }
  770. // Don't want to be grabbing the dummy var and changing it's value. That usually means badness.
  771. #define ASSERT_NOT_DUMMY_VAR() AssertMsg( m_bFakeMaterialVar || ( V_stricmp( GetName(), "$dummyvar" ) != 0 ), "TRYING TO MODIFY $dummyvar, WHICH IS BAD, MMMKAY!" )
  772. //-----------------------------------------------------------------------------
  773. // float
  774. //-----------------------------------------------------------------------------
  775. void CMaterialVar::SetFloatValue( float val )
  776. {
  777. ASSERT_NOT_DUMMY_VAR();
  778. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  779. if ( !m_bFakeMaterialVar && pCallQueue )
  780. {
  781. if ( s_bEnableThreadedAccess )
  782. {
  783. if ( m_nTempIndex == 0xFF )
  784. {
  785. m_nTempIndex = s_nTempVarsUsed++;
  786. }
  787. s_pTempMaterialVar[m_nTempIndex].SetFloatValue( val );
  788. }
  789. pCallQueue->QueueCall( this, &CMaterialVar::SetFloatValue, val );
  790. return;
  791. }
  792. // Suppress all this if we're not actually changing anything
  793. if ((m_Type == MATERIAL_VAR_TYPE_FLOAT) && (m_VecVal[0] == val))
  794. {
  795. #ifndef NO_TOOLFRAMEWORK
  796. RecordToolMessage();
  797. #endif
  798. return;
  799. }
  800. CleanUpData();
  801. m_VecVal[0] = m_VecVal[1] = m_VecVal[2] = m_VecVal[3] = val;
  802. m_intVal = (int) val;
  803. m_Type = MATERIAL_VAR_TYPE_FLOAT;
  804. VarChanged();
  805. }
  806. //-----------------------------------------------------------------------------
  807. // int
  808. //-----------------------------------------------------------------------------
  809. void CMaterialVar::SetIntValue( int val )
  810. {
  811. ASSERT_NOT_DUMMY_VAR();
  812. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  813. if ( !m_bFakeMaterialVar && pCallQueue )
  814. {
  815. if ( s_bEnableThreadedAccess )
  816. {
  817. if ( m_nTempIndex == 0xFF )
  818. {
  819. m_nTempIndex = s_nTempVarsUsed++;
  820. }
  821. s_pTempMaterialVar[m_nTempIndex].SetIntValue( val );
  822. }
  823. pCallQueue->QueueCall( this, &CMaterialVar::SetIntValue, val );
  824. return;
  825. }
  826. // Suppress all this if we're not actually changing anything
  827. if ((m_Type == MATERIAL_VAR_TYPE_INT) && (m_intVal == val))
  828. {
  829. #ifndef NO_TOOLFRAMEWORK
  830. RecordToolMessage();
  831. #endif
  832. return;
  833. }
  834. CleanUpData();
  835. m_intVal = val;
  836. m_VecVal[0] = m_VecVal[1] = m_VecVal[2] = m_VecVal[3] = (float) val;
  837. m_Type = MATERIAL_VAR_TYPE_INT;
  838. VarChanged();
  839. }
  840. //-----------------------------------------------------------------------------
  841. // string
  842. //-----------------------------------------------------------------------------
  843. const char *CMaterialVar::GetStringValue( void ) const
  844. {
  845. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  846. if ( pCallQueue && !m_bFakeMaterialVar )
  847. {
  848. if ( !s_bEnableThreadedAccess )
  849. {
  850. //DevMsg( 2, "Non-thread safe call to CMaterialVar %s!\n", GetName() );
  851. }
  852. if ( m_nTempIndex != 0xFF )
  853. return s_pTempMaterialVar[m_nTempIndex].GetStringValue();
  854. }
  855. switch( m_Type )
  856. {
  857. case MATERIAL_VAR_TYPE_STRING:
  858. return m_pStringVal;
  859. case MATERIAL_VAR_TYPE_INT:
  860. Q_snprintf( s_CharBuf, sizeof( s_CharBuf ), "%d", m_intVal );
  861. return s_CharBuf;
  862. case MATERIAL_VAR_TYPE_FLOAT:
  863. Q_snprintf( s_CharBuf, sizeof( s_CharBuf ), "%f", m_VecVal[0] );
  864. return s_CharBuf;
  865. case MATERIAL_VAR_TYPE_VECTOR:
  866. {
  867. s_CharBuf[0] = '[';
  868. s_CharBuf[1] = ' ';
  869. int len = 2;
  870. for (int i = 0; i < m_nNumVectorComps; ++i)
  871. {
  872. if (len < sizeof( s_CharBuf ))
  873. {
  874. Q_snprintf( s_CharBuf + len, sizeof( s_CharBuf ) - len, "%f ", m_VecVal[i] );
  875. len += strlen( s_CharBuf + len );
  876. }
  877. }
  878. if (len < sizeof( s_CharBuf ) - 1)
  879. {
  880. s_CharBuf[len] = ']';
  881. s_CharBuf[len+1] = '\0';
  882. }
  883. else
  884. {
  885. s_CharBuf[sizeof( s_CharBuf )-1] = '\0';
  886. }
  887. return s_CharBuf;
  888. }
  889. case MATERIAL_VAR_TYPE_MATRIX:
  890. {
  891. s_CharBuf[0] = '[';
  892. s_CharBuf[1] = ' ';
  893. int len = 2;
  894. for (int i = 0; i < 4; ++i)
  895. {
  896. for (int j = 0; j < 4; ++j)
  897. {
  898. if (len < sizeof( s_CharBuf ))
  899. len += Q_snprintf( s_CharBuf + len, sizeof( s_CharBuf ) - len, "%.3f ", m_pMatrix->m_Matrix[j][i] );
  900. }
  901. }
  902. if (len < sizeof( s_CharBuf ) - 1)
  903. {
  904. s_CharBuf[len] = ']';
  905. s_CharBuf[len+1] = '\0';
  906. }
  907. else
  908. {
  909. s_CharBuf[sizeof( s_CharBuf )-1] = '\0';
  910. }
  911. return s_CharBuf;
  912. }
  913. case MATERIAL_VAR_TYPE_TEXTURE:
  914. // check for env_cubemap
  915. if( IsTextureInternalEnvCubemap( m_pTexture ) )
  916. {
  917. return "env_cubemap";
  918. }
  919. else
  920. {
  921. Q_snprintf( s_CharBuf, sizeof( s_CharBuf ), "%s", m_pTexture->GetName() );
  922. return s_CharBuf;
  923. }
  924. case MATERIAL_VAR_TYPE_MATERIAL:
  925. Q_snprintf( s_CharBuf, sizeof( s_CharBuf ), "%s", m_pMaterialValue->GetName() );
  926. return s_CharBuf;
  927. case MATERIAL_VAR_TYPE_UNDEFINED:
  928. return "<UNDEFINED>";
  929. default:
  930. Warning( "CMaterialVar::GetStringValue: Unknown material var type\n" );
  931. return "";
  932. }
  933. }
  934. void CMaterialVar::SetStringValue( const char *val )
  935. {
  936. ASSERT_NOT_DUMMY_VAR();
  937. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  938. if ( !m_bFakeMaterialVar && pCallQueue )
  939. {
  940. if ( s_bEnableThreadedAccess )
  941. {
  942. if ( m_nTempIndex == 0xFF )
  943. {
  944. m_nTempIndex = s_nTempVarsUsed++;
  945. }
  946. s_pTempMaterialVar[m_nTempIndex].SetStringValue( val );
  947. }
  948. pCallQueue->QueueCall( this, &CMaterialVar::SetStringValue, CUtlEnvelope<const char *>(val) );
  949. return;
  950. }
  951. CleanUpData();
  952. int len = Q_strlen( val ) + 1;
  953. m_pStringVal = new char[len];
  954. Q_strncpy( m_pStringVal, val, len );
  955. m_Type = MATERIAL_VAR_TYPE_STRING;
  956. m_intVal = atoi( val );
  957. m_VecVal[0] = m_VecVal[1] = m_VecVal[2] = m_VecVal[3] = atof( m_pStringVal );
  958. VarChanged();
  959. }
  960. void CMaterialVar::SetFourCCValue( FourCC type, void *pData )
  961. {
  962. ASSERT_NOT_DUMMY_VAR();
  963. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  964. if ( !m_bFakeMaterialVar && pCallQueue )
  965. {
  966. if ( s_bEnableThreadedAccess )
  967. {
  968. if ( m_nTempIndex == 0xFF )
  969. {
  970. m_nTempIndex = s_nTempVarsUsed++;
  971. }
  972. s_pTempMaterialVar[m_nTempIndex].SetFourCCValue( type, pData );
  973. }
  974. pCallQueue->QueueCall( this, &CMaterialVar::SetFourCCValue, type, pData );
  975. return;
  976. }
  977. // Suppress all this if we're not actually changing anything
  978. if ((m_Type == MATERIAL_VAR_TYPE_FOURCC) && m_pFourCC->m_FourCC == type && m_pFourCC->m_pFourCCData == pData )
  979. {
  980. #ifndef NO_TOOLFRAMEWORK
  981. RecordToolMessage();
  982. #endif
  983. return;
  984. }
  985. CleanUpData();
  986. m_pFourCC = AllocFourCC();
  987. m_pFourCC->m_FourCC = type;
  988. m_pFourCC->m_pFourCCData = pData;
  989. m_Type = MATERIAL_VAR_TYPE_FOURCC;
  990. m_VecVal.Init();
  991. m_intVal = 0;
  992. VarChanged();
  993. }
  994. void CMaterialVar::GetFourCCValue( FourCC *type, void **ppData )
  995. {
  996. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  997. if ( pCallQueue && !m_bFakeMaterialVar )
  998. {
  999. if ( !s_bEnableThreadedAccess )
  1000. {
  1001. //DevMsg( 2, "Non-thread safe call to CMaterialVar %s!\n", GetName() );
  1002. }
  1003. if ( m_nTempIndex != 0xFF )
  1004. return s_pTempMaterialVar[m_nTempIndex].GetFourCCValue( type, ppData );
  1005. }
  1006. if( m_Type == MATERIAL_VAR_TYPE_FOURCC )
  1007. {
  1008. *type = m_pFourCC->m_FourCC;
  1009. *ppData = m_pFourCC->m_pFourCCData;
  1010. }
  1011. else
  1012. {
  1013. *type = FOURCC_UNKNOWN;
  1014. *ppData = 0;
  1015. static int bitchCount;
  1016. if( bitchCount < 10 )
  1017. {
  1018. Warning( "CMaterialVar::GetVecValue: trying to get a vec value for %s which is of type %d\n",
  1019. GetName(), ( int )m_Type );
  1020. bitchCount++;
  1021. }
  1022. }
  1023. }
  1024. bool CMaterialVar::IsTextureValueInternalEnvCubemap( void ) const
  1025. {
  1026. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  1027. if ( pCallQueue && !m_bFakeMaterialVar )
  1028. {
  1029. if ( !s_bEnableThreadedAccess )
  1030. {
  1031. //DevMsg( 2, "Non-thread safe call to CMaterialVar %s!\n", GetName() );
  1032. }
  1033. if ( m_nTempIndex != 0xFF )
  1034. return s_pTempMaterialVar[m_nTempIndex].IsTextureValueInternalEnvCubemap( );
  1035. }
  1036. if( m_pMaterial )
  1037. {
  1038. m_pMaterial->Precache();
  1039. }
  1040. if( m_Type == MATERIAL_VAR_TYPE_TEXTURE )
  1041. {
  1042. if ( IsTextureInternalEnvCubemap( m_pTexture ) )
  1043. return true;
  1044. }
  1045. return false;
  1046. }
  1047. //-----------------------------------------------------------------------------
  1048. // texture
  1049. //-----------------------------------------------------------------------------
  1050. ITexture *CMaterialVar::GetTextureValue( void )
  1051. {
  1052. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  1053. if ( pCallQueue && !m_bFakeMaterialVar )
  1054. {
  1055. if ( !s_bEnableThreadedAccess )
  1056. {
  1057. //DevMsg( 2, "Non-thread safe call to CMaterialVar %s!\n", GetName() );
  1058. }
  1059. if ( m_nTempIndex != 0xFF )
  1060. return s_pTempMaterialVar[m_nTempIndex].GetTextureValue( );
  1061. }
  1062. ITexture *retVal = NULL;
  1063. if( m_pMaterial )
  1064. {
  1065. m_pMaterial->Precache();
  1066. }
  1067. if( m_Type == MATERIAL_VAR_TYPE_TEXTURE )
  1068. {
  1069. if ( !IsTextureInternalEnvCubemap( m_pTexture ) )
  1070. {
  1071. retVal = static_cast<ITexture *>( m_pTexture );
  1072. }
  1073. else
  1074. {
  1075. retVal = MaterialSystem()->GetLocalCubemap();
  1076. }
  1077. if( !retVal )
  1078. {
  1079. static int bitchCount = 0;
  1080. if( bitchCount < 10 )
  1081. {
  1082. Warning( "Invalid texture value in CMaterialVar::GetTextureValue\n" );
  1083. bitchCount++;
  1084. }
  1085. }
  1086. }
  1087. else
  1088. {
  1089. static int bitchCount = 0;
  1090. if( bitchCount < 10 )
  1091. {
  1092. Warning( "Requesting texture value from var \"%s\" which is "
  1093. "not a texture value (material: %s)\n", GetName(),
  1094. m_pMaterial ? m_pMaterial->GetName() : "NULL material" );
  1095. bitchCount++;
  1096. }
  1097. }
  1098. if( !retVal )
  1099. {
  1100. retVal = TextureManager()->ErrorTexture();
  1101. }
  1102. return retVal;
  1103. }
  1104. void CMaterialVar::SetTextureValue( ITexture *texture )
  1105. {
  1106. ASSERT_NOT_DUMMY_VAR();
  1107. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  1108. if ( !m_bFakeMaterialVar && pCallQueue )
  1109. {
  1110. // FIXME (toml): deal with reference count
  1111. if ( s_bEnableThreadedAccess )
  1112. {
  1113. if ( m_nTempIndex == 0xFF )
  1114. {
  1115. m_nTempIndex = s_nTempVarsUsed++;
  1116. }
  1117. s_pTempMaterialVar[m_nTempIndex].SetTextureValue( texture );
  1118. }
  1119. pCallQueue->QueueCall( this, &CMaterialVar::SetTextureValue, texture );
  1120. return;
  1121. }
  1122. ITextureInternal* pTexImp = static_cast<ITextureInternal *>( texture );
  1123. // Suppress all this if we're not actually changing anything
  1124. if ((m_Type == MATERIAL_VAR_TYPE_TEXTURE) && (m_pTexture == pTexImp))
  1125. {
  1126. #ifndef NO_TOOLFRAMEWORK
  1127. RecordToolMessage();
  1128. #endif
  1129. return;
  1130. }
  1131. if( !IsTextureInternalEnvCubemap( pTexImp ) )
  1132. {
  1133. pTexImp->IncrementReferenceCount();
  1134. }
  1135. CleanUpData();
  1136. m_pTexture = pTexImp;
  1137. m_Type = MATERIAL_VAR_TYPE_TEXTURE;
  1138. m_intVal = 0;
  1139. m_VecVal.Init();
  1140. VarChanged();
  1141. }
  1142. //-----------------------------------------------------------------------------
  1143. // material
  1144. //-----------------------------------------------------------------------------
  1145. IMaterial *CMaterialVar::GetMaterialValue( void )
  1146. {
  1147. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  1148. if ( pCallQueue && !m_bFakeMaterialVar )
  1149. {
  1150. if ( !s_bEnableThreadedAccess )
  1151. {
  1152. //DevMsg( 2, "Non-thread safe call to CMaterialVar %s!\n", GetName() );
  1153. }
  1154. if ( m_nTempIndex != 0xFF )
  1155. return s_pTempMaterialVar[m_nTempIndex].GetMaterialValue( );
  1156. }
  1157. IMaterial *retVal = NULL;
  1158. if( m_pMaterial )
  1159. {
  1160. m_pMaterial->Precache();
  1161. }
  1162. if( m_Type == MATERIAL_VAR_TYPE_MATERIAL )
  1163. {
  1164. retVal = static_cast<IMaterial *>( m_pMaterialValue );
  1165. }
  1166. else
  1167. {
  1168. static int bitchCount = 0;
  1169. if( bitchCount < 10 )
  1170. {
  1171. Warning( "Requesting material value from var \"%s\" which is "
  1172. "not a material value (material: %s)\n", GetName(),
  1173. m_pMaterial ? m_pMaterial->GetName() : "NULL material" );
  1174. bitchCount++;
  1175. }
  1176. }
  1177. return retVal;
  1178. }
  1179. void CMaterialVar::SetMaterialValue( IMaterial *pMaterial )
  1180. {
  1181. ASSERT_NOT_DUMMY_VAR();
  1182. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  1183. if ( !m_bFakeMaterialVar && pCallQueue )
  1184. {
  1185. // FIXME (toml): deal with reference count
  1186. if ( s_bEnableThreadedAccess )
  1187. {
  1188. if ( m_nTempIndex == 0xFF )
  1189. {
  1190. m_nTempIndex = s_nTempVarsUsed++;
  1191. }
  1192. s_pTempMaterialVar[m_nTempIndex].SetMaterialValue( pMaterial );
  1193. }
  1194. pCallQueue->QueueCall( this, &CMaterialVar::SetMaterialValue, pMaterial );
  1195. return;
  1196. }
  1197. //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
  1198. if( pMaterial )
  1199. pMaterial = ((IMaterialInternal *)pMaterial)->GetRealTimeVersion();
  1200. IMaterialInternal* pMaterialImp = static_cast<IMaterialInternal *>( pMaterial );
  1201. // Suppress all this if we're not actually changing anything
  1202. if ((m_Type == MATERIAL_VAR_TYPE_MATERIAL) && (m_pMaterialValue == pMaterialImp))
  1203. {
  1204. #ifndef NO_TOOLFRAMEWORK
  1205. RecordToolMessage();
  1206. #endif
  1207. return;
  1208. }
  1209. if( pMaterialImp != NULL )
  1210. {
  1211. pMaterialImp->IncrementReferenceCount();
  1212. }
  1213. CleanUpData();
  1214. m_pMaterialValue = pMaterialImp;
  1215. m_Type = MATERIAL_VAR_TYPE_MATERIAL;
  1216. m_intVal = 0;
  1217. m_VecVal.Init();
  1218. VarChanged();
  1219. }
  1220. //-----------------------------------------------------------------------------
  1221. // Vector
  1222. //-----------------------------------------------------------------------------
  1223. void CMaterialVar::GetLinearVecValue( float *pVal, int numComps ) const
  1224. {
  1225. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  1226. if ( pCallQueue && !m_bFakeMaterialVar )
  1227. {
  1228. if ( !s_bEnableThreadedAccess )
  1229. {
  1230. //DevMsg( 2, "Non-thread safe call to CMaterialVar %s!\n", GetName() );
  1231. }
  1232. if ( m_nTempIndex != 0xFF )
  1233. return s_pTempMaterialVar[m_nTempIndex].GetLinearVecValue( pVal, numComps );
  1234. }
  1235. Assert( numComps <= 4 );
  1236. switch( m_Type )
  1237. {
  1238. case MATERIAL_VAR_TYPE_VECTOR:
  1239. {
  1240. for ( int i = 0; i < numComps; ++i )
  1241. {
  1242. pVal[i] = GammaToLinear( m_VecVal[i] );
  1243. }
  1244. }
  1245. break;
  1246. case MATERIAL_VAR_TYPE_INT:
  1247. {
  1248. for ( int i = 0; i < numComps; ++i )
  1249. {
  1250. pVal[i] = GammaToLinear( m_intVal );
  1251. }
  1252. }
  1253. break;
  1254. case MATERIAL_VAR_TYPE_FLOAT:
  1255. {
  1256. for ( int i = 0; i < numComps; ++i )
  1257. {
  1258. pVal[i] = GammaToLinear( m_VecVal[0] );
  1259. }
  1260. }
  1261. break;
  1262. case MATERIAL_VAR_TYPE_MATRIX:
  1263. case MATERIAL_VAR_TYPE_UNDEFINED:
  1264. {
  1265. for ( int i = 0; i < numComps; ++i )
  1266. {
  1267. pVal[i] = 0.0f;
  1268. }
  1269. }
  1270. break;
  1271. default:
  1272. Warning( "CMaterialVar::GetVecValue: trying to get a vec value for %s which is of type %d\n",
  1273. GetName(), ( int )m_Type );
  1274. break;
  1275. }
  1276. }
  1277. void CMaterialVar::SetVecValueInternal( const Vector4D &vec, int nComps )
  1278. {
  1279. ASSERT_NOT_DUMMY_VAR();
  1280. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  1281. if ( !m_bFakeMaterialVar && pCallQueue )
  1282. {
  1283. if ( s_bEnableThreadedAccess )
  1284. {
  1285. if ( m_nTempIndex == 0xFF )
  1286. {
  1287. m_nTempIndex = s_nTempVarsUsed++;
  1288. }
  1289. s_pTempMaterialVar[m_nTempIndex].SetVecValueInternal( vec, nComps );
  1290. }
  1291. pCallQueue->QueueCall( this, &CMaterialVar::SetVecValueInternal, RefToVal( vec ), nComps );
  1292. return;
  1293. }
  1294. // Suppress all this if we're not actually changing anything
  1295. if ((m_Type == MATERIAL_VAR_TYPE_VECTOR ) && (m_VecVal == vec ) )
  1296. {
  1297. #ifndef NO_TOOLFRAMEWORK
  1298. RecordToolMessage();
  1299. #endif
  1300. return;
  1301. }
  1302. if ( m_Type != MATERIAL_VAR_TYPE_VECTOR )
  1303. {
  1304. CleanUpData();
  1305. m_Type = MATERIAL_VAR_TYPE_VECTOR;
  1306. }
  1307. Assert( nComps <= 4 );
  1308. m_nNumVectorComps = nComps;
  1309. memcpy( m_VecVal.Base(), vec.Base(), 4 * sizeof(float) );
  1310. m_intVal = ( int ) m_VecVal[0];
  1311. #ifdef _DEBUG
  1312. for (int i = m_nNumVectorComps; i < 4; ++i )
  1313. Assert( m_VecVal[i] == 0.0f );
  1314. #endif
  1315. VarChanged();
  1316. }
  1317. void CMaterialVar::SetVecValue( const float* pVal, int numComps )
  1318. {
  1319. Vector4D vec;
  1320. memcpy( vec.Base(), pVal, numComps * sizeof(float) );
  1321. for (int i = numComps; i < 4; ++i )
  1322. {
  1323. vec[i] = 0.0f;
  1324. }
  1325. SetVecValueInternal( vec, numComps);
  1326. }
  1327. void CMaterialVar::SetVecValue( float x, float y )
  1328. {
  1329. SetVecValueInternal( Vector4D( x, y, 0.0f, 0.0f ), 2 );
  1330. }
  1331. void CMaterialVar::SetVecValue( float x, float y, float z )
  1332. {
  1333. SetVecValueInternal( Vector4D( x, y, z, 0.0f ), 3 );
  1334. }
  1335. void CMaterialVar::SetVecValue( float x, float y, float z, float w )
  1336. {
  1337. SetVecValueInternal( Vector4D( x, y, z, w ), 4 );
  1338. }
  1339. void CMaterialVar::SetVecComponentValue( float fVal, int nComponent )
  1340. {
  1341. ASSERT_NOT_DUMMY_VAR();
  1342. #ifndef _CERT
  1343. // DIAF
  1344. if ( nComponent < 0 || nComponent > 3 )
  1345. {
  1346. Error( "Invalid vector component (%d) of variable %s referenced in material %s", nComponent, GetName(), GetOwningMaterial()->GetName() );
  1347. return;
  1348. }
  1349. #endif
  1350. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  1351. if ( !m_bFakeMaterialVar && pCallQueue )
  1352. {
  1353. if ( s_bEnableThreadedAccess )
  1354. {
  1355. if ( m_nTempIndex == 0xFF )
  1356. {
  1357. m_nTempIndex = s_nTempVarsUsed++;
  1358. s_pTempMaterialVar[m_nTempIndex].SetVecValue( m_VecVal.Base(), m_nNumVectorComps );
  1359. }
  1360. s_pTempMaterialVar[m_nTempIndex].SetVecComponentValue( fVal, nComponent );
  1361. }
  1362. pCallQueue->QueueCall( this, &CMaterialVar::SetVecComponentValue, fVal, nComponent );
  1363. return;
  1364. }
  1365. // Suppress all this if we're not actually changing anything
  1366. if ((m_Type == MATERIAL_VAR_TYPE_VECTOR ) && (m_VecVal[nComponent] == fVal ) )
  1367. {
  1368. #ifndef NO_TOOLFRAMEWORK
  1369. RecordToolMessage();
  1370. #endif
  1371. return;
  1372. }
  1373. if ( m_Type != MATERIAL_VAR_TYPE_VECTOR )
  1374. {
  1375. CleanUpData();
  1376. m_Type = MATERIAL_VAR_TYPE_VECTOR;
  1377. }
  1378. if( m_nNumVectorComps < nComponent )
  1379. {
  1380. //reset all undefined components to 0
  1381. for( int i = m_nNumVectorComps; i != nComponent; ++i )
  1382. m_VecVal[i] = 0.0f;
  1383. m_nNumVectorComps = nComponent;
  1384. }
  1385. m_VecVal[nComponent] = fVal;
  1386. #ifdef _DEBUG
  1387. for (int i = m_nNumVectorComps; i < 4; ++i )
  1388. Assert( m_VecVal[i] == 0.0f );
  1389. #endif
  1390. VarChanged();
  1391. }
  1392. //-----------------------------------------------------------------------------
  1393. // Matrix
  1394. //-----------------------------------------------------------------------------
  1395. VMatrix const& CMaterialVar::GetMatrixValue( )
  1396. {
  1397. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  1398. if ( pCallQueue && !m_bFakeMaterialVar )
  1399. {
  1400. if ( !s_bEnableThreadedAccess )
  1401. {
  1402. //DevMsg( 2, "Non-thread safe call to CMaterialVar %s!\n", GetName() );
  1403. }
  1404. if ( m_nTempIndex != 0xFF )
  1405. return s_pTempMaterialVar[m_nTempIndex].GetMatrixValue();
  1406. }
  1407. if (m_Type == MATERIAL_VAR_TYPE_MATRIX)
  1408. return m_pMatrix->m_Matrix;
  1409. static VMatrix identity( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 );
  1410. return identity;
  1411. }
  1412. void CMaterialVar::SetMatrixValue( VMatrix const& matrix )
  1413. {
  1414. ASSERT_NOT_DUMMY_VAR();
  1415. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  1416. if ( !m_bFakeMaterialVar && pCallQueue )
  1417. {
  1418. if ( s_bEnableThreadedAccess )
  1419. {
  1420. if ( m_nTempIndex == 0xFF )
  1421. {
  1422. m_nTempIndex = s_nTempVarsUsed++;
  1423. }
  1424. s_pTempMaterialVar[m_nTempIndex].SetMatrixValue( matrix );
  1425. }
  1426. pCallQueue->QueueCall( this, &CMaterialVar::SetMatrixValue, RefToVal( matrix ) );
  1427. return;
  1428. }
  1429. CleanUpData();
  1430. // NOTE: This is necessary because the mempool MaterialVarMatrix_t uses is not threadsafe
  1431. m_pMatrix = new MaterialVarMatrix_t;
  1432. MatrixCopy( matrix, m_pMatrix->m_Matrix );
  1433. m_Type = MATERIAL_VAR_TYPE_MATRIX;
  1434. m_pMatrix->m_bIsIdent = matrix.IsIdentity();
  1435. m_VecVal.Init();
  1436. m_intVal = ( int ) m_VecVal[0];
  1437. VarChanged();
  1438. }
  1439. bool CMaterialVar::MatrixIsIdentity( void ) const
  1440. {
  1441. if( m_Type != MATERIAL_VAR_TYPE_MATRIX )
  1442. {
  1443. return true;
  1444. }
  1445. return m_pMatrix->m_bIsIdent;
  1446. }
  1447. //-----------------------------------------------------------------------------
  1448. // Undefined
  1449. //-----------------------------------------------------------------------------
  1450. bool CMaterialVar::IsDefined() const
  1451. {
  1452. return m_Type != MATERIAL_VAR_TYPE_UNDEFINED;
  1453. }
  1454. void CMaterialVar::SetUndefined()
  1455. {
  1456. ASSERT_NOT_DUMMY_VAR();
  1457. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  1458. if ( !m_bFakeMaterialVar && pCallQueue )
  1459. {
  1460. if ( s_bEnableThreadedAccess )
  1461. {
  1462. if ( m_nTempIndex == 0xFF )
  1463. {
  1464. m_nTempIndex = s_nTempVarsUsed++;
  1465. }
  1466. s_pTempMaterialVar[m_nTempIndex].SetUndefined( );
  1467. }
  1468. pCallQueue->QueueCall( this, &CMaterialVar::SetUndefined );
  1469. return;
  1470. }
  1471. if (m_Type == MATERIAL_VAR_TYPE_UNDEFINED)
  1472. return;
  1473. CleanUpData();
  1474. m_Type = MATERIAL_VAR_TYPE_UNDEFINED;
  1475. VarChanged();
  1476. }
  1477. //-----------------------------------------------------------------------------
  1478. // Copy from another material var
  1479. //-----------------------------------------------------------------------------
  1480. void CMaterialVar::CopyFrom( IMaterialVar *pMaterialVar )
  1481. {
  1482. CMatCallQueue *pCallQueue = MaterialSystem()->GetRenderCallQueue();
  1483. if ( !m_bFakeMaterialVar && pCallQueue )
  1484. {
  1485. if ( s_bEnableThreadedAccess )
  1486. {
  1487. if ( m_nTempIndex == 0xFF )
  1488. {
  1489. m_nTempIndex = s_nTempVarsUsed++;
  1490. }
  1491. s_pTempMaterialVar[m_nTempIndex].CopyFrom( pMaterialVar );
  1492. }
  1493. pCallQueue->QueueCall( this, &CMaterialVar::CopyFrom, pMaterialVar );
  1494. return;
  1495. }
  1496. switch( pMaterialVar->GetType() )
  1497. {
  1498. case MATERIAL_VAR_TYPE_FLOAT:
  1499. SetFloatValue( pMaterialVar->GetFloatValue() );
  1500. break;
  1501. case MATERIAL_VAR_TYPE_STRING:
  1502. SetStringValue( pMaterialVar->GetStringValue() );
  1503. break;
  1504. case MATERIAL_VAR_TYPE_VECTOR:
  1505. SetVecValue( pMaterialVar->GetVecValue(), pMaterialVar->VectorSize() );
  1506. break;
  1507. case MATERIAL_VAR_TYPE_TEXTURE:
  1508. SetTextureValue( pMaterialVar->GetTextureValue() );
  1509. break;
  1510. case MATERIAL_VAR_TYPE_INT:
  1511. SetIntValue( pMaterialVar->GetIntValue() );
  1512. break;
  1513. case MATERIAL_VAR_TYPE_FOURCC:
  1514. {
  1515. FourCC fourCC;
  1516. void *pData;
  1517. pMaterialVar->GetFourCCValue( &fourCC, &pData );
  1518. SetFourCCValue( fourCC, pData );
  1519. }
  1520. break;
  1521. case MATERIAL_VAR_TYPE_UNDEFINED:
  1522. SetUndefined();
  1523. break;
  1524. case MATERIAL_VAR_TYPE_MATRIX:
  1525. SetMatrixValue( pMaterialVar->GetMatrixValue() );
  1526. break;
  1527. case MATERIAL_VAR_TYPE_MATERIAL:
  1528. SetMaterialValue( pMaterialVar->GetMaterialValue() );
  1529. break;
  1530. default:
  1531. Assert(0);
  1532. }
  1533. }
  1534. #ifndef NO_TOOLFRAMEWORK
  1535. // record tool message
  1536. void CMaterialVar::RecordToolMessage()
  1537. {
  1538. if ( !m_pMaterial )
  1539. return;
  1540. IClientMaterialSystem *pClientMaterialSystem = MaterialSystem()->GetClientMaterialSystemInterface();
  1541. if ( !pClientMaterialSystem )
  1542. return;
  1543. HTOOLHANDLE hEntity = pClientMaterialSystem->GetCurrentRecordingEntity();
  1544. if ( hEntity == HTOOLHANDLE_INVALID )
  1545. return;
  1546. KeyValues *msg = new KeyValues( "material_proxy_state" );
  1547. msg->SetString( "mtlName", m_pMaterial->GetName() );
  1548. msg->SetString( "groupName", m_pMaterial->GetTextureGroupName() );
  1549. switch ( GetType() )
  1550. {
  1551. case MATERIAL_VAR_TYPE_FLOAT:
  1552. msg->SetFloat( GetName(), GetFloatValue() );
  1553. break;
  1554. case MATERIAL_VAR_TYPE_INT:
  1555. msg->SetInt( GetName(), GetIntValue() );
  1556. break;
  1557. case MATERIAL_VAR_TYPE_STRING:
  1558. msg->SetString( GetName(), GetStringValue() );
  1559. break;
  1560. case MATERIAL_VAR_TYPE_VECTOR:
  1561. {
  1562. char str[ 256 ];
  1563. const float *pVal = GetVecValue();
  1564. int dim = VectorSize();
  1565. switch ( dim )
  1566. {
  1567. case 2:
  1568. V_snprintf( str, sizeof( str ), "vector2d: %f %f", pVal[ 0 ], pVal[ 1 ] );
  1569. break;
  1570. case 3:
  1571. V_snprintf( str, sizeof( str ), "vector3d: %f %f %f", pVal[ 0 ], pVal[ 1 ], pVal[ 2 ] );
  1572. break;
  1573. case 4:
  1574. V_snprintf( str, sizeof( str ), "vector4d: %f %f %f %f", pVal[ 0 ], pVal[ 1 ], pVal[ 2 ], pVal[ 3 ] );
  1575. break;
  1576. default:
  1577. Assert( 0 );
  1578. *str = 0;
  1579. }
  1580. msg->SetString( GetName(), str );
  1581. }
  1582. break;
  1583. case MATERIAL_VAR_TYPE_MATRIX:
  1584. {
  1585. char str[ 256 ];
  1586. const VMatrix &matrix = GetMatrixValue();
  1587. const float *pVal = matrix.Base();
  1588. V_snprintf( str, sizeof( str ),
  1589. "matrix: %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f",
  1590. pVal[ 0 ], pVal[ 1 ], pVal[ 2 ], pVal[ 3 ],
  1591. pVal[ 4 ], pVal[ 5 ], pVal[ 6 ], pVal[ 7 ],
  1592. pVal[ 8 ], pVal[ 9 ], pVal[ 10 ], pVal[ 11 ],
  1593. pVal[ 12 ], pVal[ 13 ], pVal[ 14 ], pVal[ 15 ] );
  1594. msg->SetString( GetName(), str );
  1595. }
  1596. break;
  1597. case MATERIAL_VAR_TYPE_FOURCC:
  1598. Assert( 0 ); // JDTODO
  1599. // fall-through intentional (until this case is implemented)
  1600. case MATERIAL_VAR_TYPE_TEXTURE:
  1601. // V_snprintf( str, sizeof( str ), "texture: %x", pVar->GetTextureValue() );
  1602. // msg->SetString( pVarName, str );
  1603. // fall-through intentional (until this case is implemented)
  1604. case MATERIAL_VAR_TYPE_MATERIAL:
  1605. // V_snprintf( str, sizeof( str ), "material: %x", pVar->GetMaterialValue() );
  1606. // msg->SetString( pVarName, str );
  1607. // fall-through intentional (until this case is implemented)
  1608. case MATERIAL_VAR_TYPE_UNDEFINED:
  1609. // Assert( 0 ); // these appear to be (mostly? all?) textures, although I don't know why they're not caught by the texture case above...
  1610. // fall-through intentional (until this case is implemented)
  1611. default:
  1612. Assert( 0 );
  1613. msg->deleteThis();
  1614. return;
  1615. }
  1616. pClientMaterialSystem->PostToolMessage( hEntity, msg );
  1617. msg->deleteThis();
  1618. }
  1619. #endif
  1620. void CMaterialVar::VarChanged()
  1621. {
  1622. if ( !m_pMaterial )
  1623. return;
  1624. m_pMaterial->ReportVarChanged( this );
  1625. #ifndef NO_TOOLFRAMEWORK
  1626. RecordToolMessage();
  1627. #endif
  1628. }
  1629. //-----------------------------------------------------------------------------
  1630. // Parser utilities
  1631. //-----------------------------------------------------------------------------
  1632. static inline bool IsWhitespace( char c )
  1633. {
  1634. return c == ' ' || c == '\t';
  1635. }
  1636. static inline bool IsEndline( char c )
  1637. {
  1638. return c == '\n' || c == '\0';
  1639. }
  1640. static inline bool IsVector( const char* v )
  1641. {
  1642. while (IsWhitespace(*v))
  1643. {
  1644. ++v;
  1645. if (IsEndline(*v))
  1646. return false;
  1647. }
  1648. return *v == '[' || *v == '{';
  1649. }
  1650. //-----------------------------------------------------------------------------
  1651. // Creates a vector material var
  1652. //-----------------------------------------------------------------------------
  1653. static int ParseVectorFromKeyValueString( const char *pString, float vecVal[4] )
  1654. {
  1655. const char* pScan = pString;
  1656. bool divideBy255 = false;
  1657. // skip whitespace
  1658. while( IsWhitespace(*pScan) )
  1659. {
  1660. ++pScan;
  1661. }
  1662. if( *pScan == '{' )
  1663. {
  1664. divideBy255 = true;
  1665. }
  1666. else
  1667. {
  1668. Assert( *pScan == '[' );
  1669. }
  1670. // skip the '['
  1671. ++pScan;
  1672. int i;
  1673. for( i = 0; i < 4; i++ )
  1674. {
  1675. // skip whitespace
  1676. while( IsWhitespace(*pScan) )
  1677. {
  1678. ++pScan;
  1679. }
  1680. if( IsEndline(*pScan) || *pScan == ']' || *pScan == '}' )
  1681. {
  1682. if (*pScan != ']' && *pScan != '}')
  1683. {
  1684. Warning( "no ']' or '}' found in vector key in ParseVectorFromKeyValueString\n" );
  1685. }
  1686. // allow for vec2's, etc.
  1687. vecVal[i] = 0.0f;
  1688. break;
  1689. }
  1690. char* pEnd;
  1691. vecVal[i] = strtod( pScan, &pEnd );
  1692. if (pScan == pEnd)
  1693. {
  1694. Warning( "error parsing vector element in ParseVectorFromKeyValueString\n" );
  1695. return 0;
  1696. }
  1697. pScan = pEnd;
  1698. }
  1699. if( divideBy255 )
  1700. {
  1701. vecVal[0] *= ( 1.0f / 255.0f );
  1702. vecVal[1] *= ( 1.0f / 255.0f );
  1703. vecVal[2] *= ( 1.0f / 255.0f );
  1704. vecVal[3] *= ( 1.0f / 255.0f );
  1705. }
  1706. return i;
  1707. }
  1708. void CMaterialVar::SetValueAutodetectType( const char *val )
  1709. {
  1710. ASSERT_NOT_DUMMY_VAR();
  1711. int len = Q_strlen( val );
  1712. // Here, let's determine if we got a float or an int....
  1713. char* pIEnd; // pos where int scan ended
  1714. char* pFEnd; // pos where float scan ended
  1715. const char* pSEnd = val + len ; // pos where token ends
  1716. int ival = strtol( val, &pIEnd, 10 );
  1717. float fval = (float)strtod( val, &pFEnd );
  1718. if ( ( pFEnd > pIEnd ) && ( pFEnd == pSEnd ) )
  1719. {
  1720. SetFloatValue( fval );
  1721. return;
  1722. }
  1723. if ( pIEnd == pSEnd )
  1724. {
  1725. SetIntValue( ival );
  1726. return;
  1727. }
  1728. // Isn't an int or a float.
  1729. // Is it a matrix?
  1730. VMatrix mat;
  1731. int count = sscanf( val, " [ %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f ]",
  1732. &mat.m[0][0], &mat.m[0][1], &mat.m[0][2], &mat.m[0][3],
  1733. &mat.m[1][0], &mat.m[1][1], &mat.m[1][2], &mat.m[1][3],
  1734. &mat.m[2][0], &mat.m[2][1], &mat.m[2][2], &mat.m[2][3],
  1735. &mat.m[3][0], &mat.m[3][1], &mat.m[3][2], &mat.m[3][3] );
  1736. if (count == 16)
  1737. {
  1738. SetMatrixValue( mat );
  1739. return;
  1740. }
  1741. Vector2D scale, center;
  1742. float angle;
  1743. Vector2D translation;
  1744. //scan for pre-rotation scale and translation with assumed center syntax
  1745. count = sscanf( val, " scale %f %f translate %f %f rotate %f",
  1746. &scale.x, &scale.y, &translation.x, &translation.y, &angle );
  1747. if (count == 5)
  1748. {
  1749. VMatrix temp;
  1750. MatrixBuildTranslation( mat, translation.x - 0.5, translation.y - 0.5, 0.0f );
  1751. MatrixBuildScale( temp, scale.x, scale.y, 1.0f );
  1752. MatrixMultiply( mat, temp, mat );
  1753. MatrixBuildRotateZ( temp, angle );
  1754. MatrixMultiply( mat, temp, mat );
  1755. Vector2D vOffset;
  1756. vOffset.Init( 0.5f / ( scale.x != 0 ? scale.x : 1.0 ), 0.5f / ( scale.y != 0 ? scale.y : 1.0 ) );
  1757. Vector2DRotate( vOffset, -angle, vOffset );
  1758. MatrixBuildTranslation( temp, vOffset.x, vOffset.y, 0.0f );
  1759. MatrixMultiply( mat, temp, mat );
  1760. SetMatrixValue( mat );
  1761. return;
  1762. }
  1763. count = sscanf( val, " center %f %f scale %f %f rotate %f translate %f %f",
  1764. &center.x, &center.y, &scale.x, &scale.y, &angle, &translation.x, &translation.y );
  1765. if (count == 7)
  1766. {
  1767. VMatrix temp;
  1768. MatrixBuildTranslation( mat, -center.x, -center.y, 0.0f );
  1769. MatrixBuildScale( temp, scale.x, scale.y, 1.0f );
  1770. MatrixMultiply( temp, mat, mat );
  1771. MatrixBuildRotateZ( temp, angle );
  1772. MatrixMultiply( temp, mat, mat );
  1773. MatrixBuildTranslation( temp, center.x + translation.x, center.y + translation.y, 0.0f );
  1774. MatrixMultiply( temp, mat, mat );
  1775. SetMatrixValue( mat );
  1776. return;
  1777. }
  1778. if( IsVector( val ) )
  1779. {
  1780. float vecVal[4];
  1781. int nDim = ParseVectorFromKeyValueString( val, vecVal );
  1782. if ( nDim > 0 )
  1783. {
  1784. SetVecValue( vecVal, nDim );
  1785. return;
  1786. }
  1787. }
  1788. SetStringValue( val );
  1789. }
  1790. void CompactMaterialVars( IMaterialVar **ppMaterialVars, int nVars )
  1791. {
  1792. for ( int i = 0; i < nVars; i++ )
  1793. {
  1794. if ( MVInternallyAllocated( ppMaterialVars[i] ) )
  1795. {
  1796. ppMaterialVars[i] = (IMaterialVar *)MVRelocate( ppMaterialVars[i] );
  1797. }
  1798. }
  1799. }
  1800. void CompactMaterialVarHeap()
  1801. {
  1802. MVDecommitUnusedPages();
  1803. }