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.

785 lines
22 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Material Modify control entity.
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "proxyentity.h"
  8. #include "materialsystem/imaterial.h"
  9. #include "materialsystem/imaterialvar.h"
  10. #include "materialsystem/itexture.h"
  11. #include "iviewrender.h"
  12. #include "texture_group_names.h"
  13. #include "baseanimatedtextureproxy.h"
  14. #include "imaterialproxydict.h"
  15. // memdbgon must be the last include file in a .cpp file!!!
  16. #include "tier0/memdbgon.h"
  17. #define MATERIAL_MODIFY_STRING_SIZE 255
  18. #define MATERIAL_MODIFY_ANIMATION_UNSET -1
  19. // Must match MaterialModifyControl.cpp
  20. enum MaterialModifyMode_t
  21. {
  22. MATERIAL_MODIFY_MODE_NONE = 0,
  23. MATERIAL_MODIFY_MODE_SETVAR = 1,
  24. MATERIAL_MODIFY_MODE_ANIM_SEQUENCE = 2,
  25. MATERIAL_MODIFY_MODE_FLOAT_LERP = 3,
  26. };
  27. ConVar debug_materialmodifycontrol_client( "debug_materialmodifycontrol_client", "0" );
  28. struct materialanimcommands_t
  29. {
  30. int iFrameStart;
  31. int iFrameEnd;
  32. bool bWrap;
  33. float flFrameRate;
  34. };
  35. struct materialfloatlerpcommands_t
  36. {
  37. int flStartValue;
  38. int flEndValue;
  39. float flTransitionTime;
  40. };
  41. //------------------------------------------------------------------------------
  42. // FIXME: This really should inherit from something more lightweight
  43. //------------------------------------------------------------------------------
  44. class C_MaterialModifyControl : public C_BaseEntity
  45. {
  46. public:
  47. DECLARE_CLASS( C_MaterialModifyControl, C_BaseEntity );
  48. C_MaterialModifyControl();
  49. void OnPreDataChanged( DataUpdateType_t updateType );
  50. void OnDataChanged( DataUpdateType_t updateType );
  51. bool ShouldDraw();
  52. IMaterial *GetMaterial( void ) { return m_pMaterial; }
  53. const char *GetMaterialVariableName( void ) { return m_szMaterialVar; }
  54. const char *GetMaterialVariableValue( void ) { return m_szMaterialVarValue; }
  55. DECLARE_CLIENTCLASS();
  56. // Animated texture and Float Lerp usage
  57. bool HasNewAnimationCommands( void ) { return m_bHasNewAnimationCommands; }
  58. void ClearAnimationCommands( void ) { m_bHasNewAnimationCommands = false; }
  59. // Animated texture usage
  60. void GetAnimationCommands( materialanimcommands_t *pCommands );
  61. // FloatLerp usage
  62. void GetFloatLerpCommands( materialfloatlerpcommands_t *pCommands );
  63. void SetAnimationStartTime( float flTime )
  64. {
  65. m_flAnimationStartTime = flTime;
  66. }
  67. float GetAnimationStartTime( void ) const
  68. {
  69. return m_flAnimationStartTime;
  70. }
  71. MaterialModifyMode_t GetModifyMode( void ) const
  72. {
  73. return ( MaterialModifyMode_t)m_nModifyMode;
  74. }
  75. private:
  76. char m_szMaterialName[MATERIAL_MODIFY_STRING_SIZE];
  77. char m_szMaterialVar[MATERIAL_MODIFY_STRING_SIZE];
  78. char m_szMaterialVarValue[MATERIAL_MODIFY_STRING_SIZE];
  79. IMaterial *m_pMaterial;
  80. bool m_bHasNewAnimationCommands;
  81. // Animation commands from the server
  82. int m_iFrameStart;
  83. int m_iFrameEnd;
  84. bool m_bWrap;
  85. float m_flFramerate;
  86. bool m_bNewAnimCommandsSemaphore;
  87. bool m_bOldAnimCommandsSemaphore;
  88. // Float lerp commands from the server
  89. float m_flFloatLerpStartValue;
  90. float m_flFloatLerpEndValue;
  91. float m_flFloatLerpTransitionTime;
  92. bool m_bFloatLerpWrap;
  93. float m_flAnimationStartTime;
  94. int m_nModifyMode;
  95. };
  96. IMPLEMENT_CLIENTCLASS_DT(C_MaterialModifyControl, DT_MaterialModifyControl, CMaterialModifyControl)
  97. RecvPropString( RECVINFO( m_szMaterialName ) ),
  98. RecvPropString( RECVINFO( m_szMaterialVar ) ),
  99. RecvPropString( RECVINFO( m_szMaterialVarValue ) ),
  100. RecvPropInt( RECVINFO(m_iFrameStart) ),
  101. RecvPropInt( RECVINFO(m_iFrameEnd) ),
  102. RecvPropInt( RECVINFO(m_bWrap) ),
  103. RecvPropFloat( RECVINFO(m_flFramerate) ),
  104. RecvPropInt( RECVINFO(m_bNewAnimCommandsSemaphore) ),
  105. RecvPropFloat( RECVINFO(m_flFloatLerpStartValue) ),
  106. RecvPropFloat( RECVINFO(m_flFloatLerpEndValue) ),
  107. RecvPropFloat( RECVINFO(m_flFloatLerpTransitionTime) ),
  108. RecvPropInt( RECVINFO(m_bFloatLerpWrap) ),
  109. RecvPropInt( RECVINFO(m_nModifyMode) ),
  110. END_RECV_TABLE()
  111. //------------------------------------------------------------------------------
  112. // Purpose:
  113. //------------------------------------------------------------------------------
  114. C_MaterialModifyControl::C_MaterialModifyControl()
  115. {
  116. m_pMaterial = NULL;
  117. m_bOldAnimCommandsSemaphore = false;
  118. }
  119. //-----------------------------------------------------------------------------
  120. // Purpose:
  121. //-----------------------------------------------------------------------------
  122. void C_MaterialModifyControl::OnPreDataChanged( DataUpdateType_t updateType )
  123. {
  124. BaseClass::OnPreDataChanged( updateType );
  125. m_bOldAnimCommandsSemaphore = m_bNewAnimCommandsSemaphore;
  126. }
  127. //------------------------------------------------------------------------------
  128. // Purpose:
  129. //------------------------------------------------------------------------------
  130. void C_MaterialModifyControl::OnDataChanged( DataUpdateType_t updateType )
  131. {
  132. if( updateType == DATA_UPDATE_CREATED )
  133. {
  134. m_pMaterial = materials->FindMaterial( m_szMaterialName, TEXTURE_GROUP_OTHER );
  135. // Clear out our variables
  136. m_bHasNewAnimationCommands = true;
  137. }
  138. // Detect changes in the anim commands
  139. if ( m_bNewAnimCommandsSemaphore != m_bOldAnimCommandsSemaphore )
  140. {
  141. m_bHasNewAnimationCommands = true;
  142. }
  143. }
  144. //-----------------------------------------------------------------------------
  145. // Purpose:
  146. //-----------------------------------------------------------------------------
  147. void C_MaterialModifyControl::GetAnimationCommands( materialanimcommands_t *pCommands )
  148. {
  149. pCommands->iFrameStart = m_iFrameStart;
  150. pCommands->iFrameEnd = m_iFrameEnd;
  151. pCommands->bWrap = m_bWrap;
  152. pCommands->flFrameRate = m_flFramerate;
  153. }
  154. //-----------------------------------------------------------------------------
  155. // Purpose:
  156. //-----------------------------------------------------------------------------
  157. void C_MaterialModifyControl::GetFloatLerpCommands( materialfloatlerpcommands_t *pCommands )
  158. {
  159. pCommands->flStartValue = m_flFloatLerpStartValue;
  160. pCommands->flEndValue = m_flFloatLerpEndValue;
  161. pCommands->flTransitionTime = m_flFloatLerpTransitionTime;
  162. }
  163. //------------------------------------------------------------------------------
  164. // Purpose: We don't draw.
  165. //------------------------------------------------------------------------------
  166. bool C_MaterialModifyControl::ShouldDraw()
  167. {
  168. return false;
  169. }
  170. //=============================================================================
  171. //
  172. // THE MATERIALMODIFYPROXY ITSELF
  173. //
  174. class CMaterialModifyProxy : public CBaseAnimatedTextureProxy
  175. {
  176. public:
  177. CMaterialModifyProxy();
  178. virtual ~CMaterialModifyProxy();
  179. virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
  180. virtual void OnBind( void *pEntity );
  181. virtual IMaterial *GetMaterial();
  182. private:
  183. void OnBindSetVar( C_MaterialModifyControl *pControl );
  184. void OnBindAnimatedTexture( C_MaterialModifyControl *pControl );
  185. void OnBindFloatLerp( C_MaterialModifyControl *pControl );
  186. float GetAnimationStartTime( void* pArg );
  187. void AnimationWrapped( void* pArg );
  188. IMaterial *m_pMaterial;
  189. // texture animation stuff
  190. int m_iFrameStart;
  191. int m_iFrameEnd;
  192. bool m_bReachedEnd;
  193. bool m_bCustomWrap;
  194. float m_flCustomFramerate;
  195. // float lerp stuff
  196. IMaterialVar *m_pMaterialVar;
  197. int m_flStartValue;
  198. int m_flEndValue;
  199. float m_flStartTime;
  200. float m_flTransitionTime;
  201. };
  202. //-----------------------------------------------------------------------------
  203. // Purpose:
  204. //-----------------------------------------------------------------------------
  205. CMaterialModifyProxy::CMaterialModifyProxy()
  206. {
  207. }
  208. //-----------------------------------------------------------------------------
  209. // Purpose:
  210. //-----------------------------------------------------------------------------
  211. CMaterialModifyProxy::~CMaterialModifyProxy()
  212. {
  213. }
  214. bool CMaterialModifyProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
  215. {
  216. // set var stuff
  217. m_pMaterial = pMaterial;
  218. // float lerp stuff
  219. m_flStartValue = MATERIAL_MODIFY_ANIMATION_UNSET;
  220. m_flEndValue = MATERIAL_MODIFY_ANIMATION_UNSET;
  221. // animated stuff
  222. // m_pMaterial = pMaterial;
  223. // m_iFrameStart = MATERIAL_MODIFY_ANIMATION_UNSET;
  224. // m_iFrameEnd = MATERIAL_MODIFY_ANIMATION_UNSET;
  225. // m_bReachedEnd = false;
  226. // return CBaseAnimatedTextureProxy::Init( pMaterial, pKeyValues );
  227. return true;
  228. }
  229. void CMaterialModifyProxy::OnBind( void *pEntity )
  230. {
  231. // Get the modified material vars from the entity input
  232. IClientRenderable *pRend = (IClientRenderable *)pEntity;
  233. if ( pRend )
  234. {
  235. C_BaseEntity *pBaseEntity = pRend->GetIClientUnknown()->GetBaseEntity();
  236. if ( pBaseEntity )
  237. {
  238. if( debug_materialmodifycontrol_client.GetBool() )
  239. {
  240. // DevMsg( 1, "%s\n", pBaseEntity->GetDebugName() );
  241. }
  242. int numChildren = 0;
  243. bool gotOne = false;
  244. for ( C_BaseEntity *pChild = pBaseEntity->FirstMoveChild(); pChild; pChild = pChild->NextMovePeer() )
  245. {
  246. numChildren++;
  247. C_MaterialModifyControl *pControl = dynamic_cast<C_MaterialModifyControl*>( pChild );
  248. if ( !pControl )
  249. continue;
  250. if( debug_materialmodifycontrol_client.GetBool() )
  251. {
  252. // DevMsg( 1, "pControl: 0x%p\n", pControl );
  253. }
  254. switch( pControl->GetModifyMode() )
  255. {
  256. case MATERIAL_MODIFY_MODE_NONE:
  257. break;
  258. case MATERIAL_MODIFY_MODE_SETVAR:
  259. gotOne = true;
  260. OnBindSetVar( pControl );
  261. break;
  262. case MATERIAL_MODIFY_MODE_ANIM_SEQUENCE:
  263. OnBindAnimatedTexture( pControl );
  264. break;
  265. case MATERIAL_MODIFY_MODE_FLOAT_LERP:
  266. OnBindFloatLerp( pControl );
  267. break;
  268. default:
  269. Assert( 0 );
  270. break;
  271. }
  272. }
  273. if( gotOne )
  274. {
  275. // DevMsg( 1, "numChildren: %d\n", numChildren );
  276. }
  277. }
  278. }
  279. }
  280. IMaterial *CMaterialModifyProxy::GetMaterial()
  281. {
  282. return m_pMaterial;
  283. }
  284. //-----------------------------------------------------------------------------
  285. // Purpose:
  286. //-----------------------------------------------------------------------------
  287. void CMaterialModifyProxy::OnBindSetVar( C_MaterialModifyControl *pControl )
  288. {
  289. IMaterial *pMaterial = pControl->GetMaterial();
  290. if( !pMaterial )
  291. {
  292. Assert( 0 );
  293. return;
  294. }
  295. if ( pMaterial != m_pMaterial )
  296. {
  297. // Warning( "\t%s!=%s\n", pMaterial->GetName(), m_pMaterial->GetName() );
  298. return;
  299. }
  300. bool bFound;
  301. IMaterialVar *pMaterialVar = pMaterial->FindVar( pControl->GetMaterialVariableName(), &bFound, false );
  302. if ( !bFound )
  303. return;
  304. if( Q_strcmp( pControl->GetMaterialVariableValue(), "" ) )
  305. {
  306. // const char *pMaterialName = m_pMaterial->GetName();
  307. // const char *pMaterialVarName = pMaterialVar->GetName();
  308. // const char *pMaterialVarValue = pControl->GetMaterialVariableValue();
  309. // if( debug_materialmodifycontrol_client.GetBool()
  310. // && Q_stristr( m_pMaterial->GetName(), "faceandhair" )
  311. // && Q_stristr( pMaterialVar->GetName(), "self" )
  312. // )
  313. // {
  314. // static int count = 0;
  315. // DevMsg( 1, "CMaterialModifyProxy::OnBindSetVar \"%s\" %s=%s %d pControl=0x%p\n",
  316. // m_pMaterial->GetName(), pMaterialVar->GetName(), pControl->GetMaterialVariableValue(), count++, pControl );
  317. // }
  318. pMaterialVar->SetValueAutodetectType( pControl->GetMaterialVariableValue() );
  319. }
  320. }
  321. //-----------------------------------------------------------------------------
  322. // Does the dirty deed
  323. //-----------------------------------------------------------------------------
  324. void CMaterialModifyProxy::OnBindAnimatedTexture( C_MaterialModifyControl *pControl )
  325. {
  326. assert ( m_AnimatedTextureVar );
  327. if( m_AnimatedTextureVar->GetType() != MATERIAL_VAR_TYPE_TEXTURE )
  328. return;
  329. ITexture *pTexture;
  330. pTexture = m_AnimatedTextureVar->GetTextureValue();
  331. if ( !pControl )
  332. return;
  333. if ( pControl->HasNewAnimationCommands() )
  334. {
  335. // Read the data from the modify entity
  336. materialanimcommands_t sCommands;
  337. pControl->GetAnimationCommands( &sCommands );
  338. m_iFrameStart = sCommands.iFrameStart;
  339. m_iFrameEnd = sCommands.iFrameEnd;
  340. m_bCustomWrap = sCommands.bWrap;
  341. m_flCustomFramerate = sCommands.flFrameRate;
  342. m_bReachedEnd = false;
  343. m_flStartTime = gpGlobals->curtime;
  344. pControl->ClearAnimationCommands();
  345. }
  346. // Init all the vars based on whether we're using the base material settings,
  347. // or the custom ones from the entity input.
  348. int numFrames;
  349. bool bWrapAnimation;
  350. float flFrameRate;
  351. int iLastFrame;
  352. // Do we have a custom frame section from the server?
  353. if ( m_iFrameStart != MATERIAL_MODIFY_ANIMATION_UNSET )
  354. {
  355. if ( m_iFrameEnd == MATERIAL_MODIFY_ANIMATION_UNSET )
  356. {
  357. m_iFrameEnd = pTexture->GetNumAnimationFrames();
  358. }
  359. numFrames = (m_iFrameEnd - m_iFrameStart) + 1;
  360. bWrapAnimation = m_bCustomWrap;
  361. flFrameRate = m_flCustomFramerate;
  362. iLastFrame = (m_iFrameEnd - 1);
  363. }
  364. else
  365. {
  366. numFrames = pTexture->GetNumAnimationFrames();
  367. bWrapAnimation = m_WrapAnimation;
  368. flFrameRate = m_FrameRate;
  369. iLastFrame = (numFrames - 1);
  370. }
  371. // Have we already reached the end? If so, stay there.
  372. if ( m_bReachedEnd && !bWrapAnimation )
  373. {
  374. m_AnimatedTextureFrameNumVar->SetIntValue( iLastFrame );
  375. return;
  376. }
  377. // NOTE: Must not use relative time based methods here
  378. // because the bind proxy can be called many times per frame.
  379. // Prevent multiple Wrap callbacks to be sent for no wrap mode
  380. float startTime;
  381. if ( m_iFrameStart != MATERIAL_MODIFY_ANIMATION_UNSET )
  382. {
  383. startTime = m_flStartTime;
  384. }
  385. else
  386. {
  387. startTime = GetAnimationStartTime(pControl);
  388. }
  389. float deltaTime = gpGlobals->curtime - startTime;
  390. float prevTime = deltaTime - gpGlobals->frametime;
  391. // Clamp..
  392. if (deltaTime < 0.0f)
  393. deltaTime = 0.0f;
  394. if (prevTime < 0.0f)
  395. prevTime = 0.0f;
  396. float frame = flFrameRate * deltaTime;
  397. float prevFrame = flFrameRate * prevTime;
  398. int intFrame = ((int)frame) % numFrames;
  399. int intPrevFrame = ((int)prevFrame) % numFrames;
  400. if ( m_iFrameStart != MATERIAL_MODIFY_ANIMATION_UNSET )
  401. {
  402. intFrame += m_iFrameStart;
  403. intPrevFrame += m_iFrameStart;
  404. }
  405. // Report wrap situation...
  406. if (intPrevFrame > intFrame)
  407. {
  408. m_bReachedEnd = true;
  409. if (bWrapAnimation)
  410. {
  411. AnimationWrapped( pControl );
  412. }
  413. else
  414. {
  415. // Only sent the wrapped message once.
  416. // when we're in non-wrapping mode
  417. if (prevFrame < numFrames)
  418. AnimationWrapped( pControl );
  419. intFrame = numFrames - 1;
  420. }
  421. }
  422. m_AnimatedTextureFrameNumVar->SetIntValue( intFrame );
  423. }
  424. //-----------------------------------------------------------------------------
  425. // Purpose:
  426. //-----------------------------------------------------------------------------
  427. float CMaterialModifyProxy::GetAnimationStartTime( void* pArg )
  428. {
  429. IClientRenderable *pRend = (IClientRenderable *)pArg;
  430. if (!pRend)
  431. return 0.0f;
  432. C_BaseEntity* pEntity = pRend->GetIClientUnknown()->GetBaseEntity();
  433. if (pEntity)
  434. {
  435. return pEntity->GetTextureAnimationStartTime();
  436. }
  437. return 0.0f;
  438. }
  439. //-----------------------------------------------------------------------------
  440. // Purpose:
  441. //-----------------------------------------------------------------------------
  442. void CMaterialModifyProxy::AnimationWrapped( void* pArg )
  443. {
  444. IClientRenderable *pRend = (IClientRenderable *)pArg;
  445. if (!pRend)
  446. return;
  447. C_BaseEntity* pEntity = pRend->GetIClientUnknown()->GetBaseEntity();
  448. if (pEntity)
  449. {
  450. pEntity->TextureAnimationWrapped();
  451. }
  452. }
  453. //-----------------------------------------------------------------------------
  454. // Does the dirty deed
  455. //-----------------------------------------------------------------------------
  456. void CMaterialModifyProxy::OnBindFloatLerp( C_MaterialModifyControl *pControl )
  457. {
  458. if ( !pControl )
  459. return;
  460. if ( pControl->HasNewAnimationCommands() )
  461. {
  462. pControl->SetAnimationStartTime( gpGlobals->curtime );
  463. pControl->ClearAnimationCommands();
  464. }
  465. // Read the data from the modify entity
  466. materialfloatlerpcommands_t sCommands;
  467. pControl->GetFloatLerpCommands( &sCommands );
  468. m_flStartValue = sCommands.flStartValue;
  469. m_flEndValue = sCommands.flEndValue;
  470. m_flTransitionTime = sCommands.flTransitionTime;
  471. m_flStartTime = pControl->GetAnimationStartTime();
  472. bool bFound;
  473. m_pMaterialVar = m_pMaterial->FindVar( pControl->GetMaterialVariableName(), &bFound, false );
  474. if( bFound )
  475. {
  476. float currentValue;
  477. if( m_flTransitionTime > 0.0f )
  478. {
  479. currentValue = m_flStartValue + ( m_flEndValue - m_flStartValue ) * clamp( ( ( gpGlobals->curtime - m_flStartTime ) / m_flTransitionTime ), 0.0f, 1.0f );
  480. }
  481. else
  482. {
  483. currentValue = m_flEndValue;
  484. }
  485. if( debug_materialmodifycontrol_client.GetBool() && Q_stristr( m_pMaterial->GetName(), "faceandhair" ) && Q_stristr( m_pMaterialVar->GetName(), "warp" ) )
  486. {
  487. static int count = 0;
  488. DevMsg( 1, "CMaterialFloatLerpProxy::OnBind \"%s\" %s=%f %d\n", m_pMaterial->GetName(), m_pMaterialVar->GetName(), currentValue, count++ );
  489. }
  490. m_pMaterialVar->SetFloatValue( currentValue );
  491. }
  492. }
  493. //=============================================================================
  494. //
  495. // MATERIALMODIFYANIMATED PROXY
  496. //
  497. class CMaterialModifyAnimatedProxy : public CBaseAnimatedTextureProxy
  498. {
  499. public:
  500. CMaterialModifyAnimatedProxy() {};
  501. virtual ~CMaterialModifyAnimatedProxy() {};
  502. virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
  503. virtual void OnBind( void *pEntity );
  504. virtual float GetAnimationStartTime( void* pBaseEntity );
  505. virtual void AnimationWrapped( void* pC_BaseEntity );
  506. private:
  507. IMaterial *m_pMaterial;
  508. int m_iFrameStart;
  509. int m_iFrameEnd;
  510. bool m_bReachedEnd;
  511. float m_flStartTime;
  512. bool m_bCustomWrap;
  513. float m_flCustomFramerate;
  514. };
  515. //-----------------------------------------------------------------------------
  516. // Purpose:
  517. //-----------------------------------------------------------------------------
  518. bool CMaterialModifyAnimatedProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
  519. {
  520. m_pMaterial = pMaterial;
  521. m_iFrameStart = MATERIAL_MODIFY_ANIMATION_UNSET;
  522. m_iFrameEnd = MATERIAL_MODIFY_ANIMATION_UNSET;
  523. m_bReachedEnd = false;
  524. return CBaseAnimatedTextureProxy::Init( pMaterial, pKeyValues );
  525. }
  526. //-----------------------------------------------------------------------------
  527. // Does the dirty deed
  528. //-----------------------------------------------------------------------------
  529. void CMaterialModifyAnimatedProxy::OnBind( void *pEntity )
  530. {
  531. assert ( m_AnimatedTextureVar );
  532. if( m_AnimatedTextureVar->GetType() != MATERIAL_VAR_TYPE_TEXTURE )
  533. return;
  534. ITexture *pTexture;
  535. pTexture = m_AnimatedTextureVar->GetTextureValue();
  536. // Get the modified material vars from the entity input
  537. IClientRenderable *pRend = (IClientRenderable *)pEntity;
  538. if ( pRend )
  539. {
  540. C_BaseEntity *pBaseEntity = pRend->GetIClientUnknown()->GetBaseEntity();
  541. if ( pBaseEntity )
  542. {
  543. for ( C_BaseEntity *pChild = pBaseEntity->FirstMoveChild(); pChild; pChild = pChild->NextMovePeer() )
  544. {
  545. C_MaterialModifyControl *pControl = dynamic_cast<C_MaterialModifyControl*>( pChild );
  546. if ( !pControl )
  547. continue;
  548. if ( !pControl->HasNewAnimationCommands() )
  549. continue;
  550. // Read the data from the modify entity
  551. materialanimcommands_t sCommands;
  552. pControl->GetAnimationCommands( &sCommands );
  553. m_iFrameStart = sCommands.iFrameStart;
  554. m_iFrameEnd = sCommands.iFrameEnd;
  555. m_bCustomWrap = sCommands.bWrap;
  556. m_flCustomFramerate = sCommands.flFrameRate;
  557. m_bReachedEnd = false;
  558. m_flStartTime = gpGlobals->curtime;
  559. pControl->ClearAnimationCommands();
  560. }
  561. }
  562. }
  563. // Init all the vars based on whether we're using the base material settings,
  564. // or the custom ones from the entity input.
  565. int numFrames;
  566. bool bWrapAnimation;
  567. float flFrameRate;
  568. int iLastFrame;
  569. // Do we have a custom frame section from the server?
  570. if ( m_iFrameStart != MATERIAL_MODIFY_ANIMATION_UNSET )
  571. {
  572. if ( m_iFrameEnd == MATERIAL_MODIFY_ANIMATION_UNSET )
  573. {
  574. m_iFrameEnd = pTexture->GetNumAnimationFrames();
  575. }
  576. numFrames = (m_iFrameEnd - m_iFrameStart) + 1;
  577. bWrapAnimation = m_bCustomWrap;
  578. flFrameRate = m_flCustomFramerate;
  579. iLastFrame = (m_iFrameEnd - 1);
  580. }
  581. else
  582. {
  583. numFrames = pTexture->GetNumAnimationFrames();
  584. bWrapAnimation = m_WrapAnimation;
  585. flFrameRate = m_FrameRate;
  586. iLastFrame = (numFrames - 1);
  587. }
  588. // Have we already reached the end? If so, stay there.
  589. if ( m_bReachedEnd && !bWrapAnimation )
  590. {
  591. m_AnimatedTextureFrameNumVar->SetIntValue( iLastFrame );
  592. return;
  593. }
  594. // NOTE: Must not use relative time based methods here
  595. // because the bind proxy can be called many times per frame.
  596. // Prevent multiple Wrap callbacks to be sent for no wrap mode
  597. float startTime;
  598. if ( m_iFrameStart != MATERIAL_MODIFY_ANIMATION_UNSET )
  599. {
  600. startTime = m_flStartTime;
  601. }
  602. else
  603. {
  604. startTime = GetAnimationStartTime(pEntity);
  605. }
  606. float deltaTime = gpGlobals->curtime - startTime;
  607. float prevTime = deltaTime - gpGlobals->frametime;
  608. // Clamp..
  609. if (deltaTime < 0.0f)
  610. deltaTime = 0.0f;
  611. if (prevTime < 0.0f)
  612. prevTime = 0.0f;
  613. float frame = flFrameRate * deltaTime;
  614. float prevFrame = flFrameRate * prevTime;
  615. int intFrame = ((int)frame) % numFrames;
  616. int intPrevFrame = ((int)prevFrame) % numFrames;
  617. if ( m_iFrameStart != MATERIAL_MODIFY_ANIMATION_UNSET )
  618. {
  619. intFrame += m_iFrameStart;
  620. intPrevFrame += m_iFrameStart;
  621. }
  622. // Report wrap situation...
  623. if (intPrevFrame > intFrame)
  624. {
  625. m_bReachedEnd = true;
  626. if (bWrapAnimation)
  627. {
  628. AnimationWrapped( pEntity );
  629. }
  630. else
  631. {
  632. // Only sent the wrapped message once.
  633. // when we're in non-wrapping mode
  634. if (prevFrame < numFrames)
  635. AnimationWrapped( pEntity );
  636. intFrame = numFrames - 1;
  637. }
  638. }
  639. m_AnimatedTextureFrameNumVar->SetIntValue( intFrame );
  640. }
  641. //-----------------------------------------------------------------------------
  642. // Purpose:
  643. //-----------------------------------------------------------------------------
  644. float CMaterialModifyAnimatedProxy::GetAnimationStartTime( void* pArg )
  645. {
  646. IClientRenderable *pRend = (IClientRenderable *)pArg;
  647. if (!pRend)
  648. return 0.0f;
  649. C_BaseEntity* pEntity = pRend->GetIClientUnknown()->GetBaseEntity();
  650. if (pEntity)
  651. {
  652. return pEntity->GetTextureAnimationStartTime();
  653. }
  654. return 0.0f;
  655. }
  656. //-----------------------------------------------------------------------------
  657. // Purpose:
  658. //-----------------------------------------------------------------------------
  659. void CMaterialModifyAnimatedProxy::AnimationWrapped( void* pArg )
  660. {
  661. IClientRenderable *pRend = (IClientRenderable *)pArg;
  662. if (!pRend)
  663. return;
  664. C_BaseEntity* pEntity = pRend->GetIClientUnknown()->GetBaseEntity();
  665. if (pEntity)
  666. {
  667. pEntity->TextureAnimationWrapped();
  668. }
  669. }
  670. EXPOSE_MATERIAL_PROXY( CMaterialModifyProxy, MaterialModify );
  671. EXPOSE_MATERIAL_PROXY( CMaterialModifyAnimatedProxy, MaterialModifyAnimated );