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.

304 lines
8.9 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "cbase.h"
  8. #include "c_baseanimating.h"
  9. #include "particlemgr.h"
  10. #include "materialsystem/imaterialvar.h"
  11. #include "cl_animevent.h"
  12. #include "particle_util.h"
  13. // memdbgon must be the last include file in a .cpp file!!!
  14. #include "tier0/memdbgon.h"
  15. //-----------------------------------------------------------------------------
  16. // An entity which emits other entities at points
  17. //-----------------------------------------------------------------------------
  18. class C_EnvParticleScript : public C_BaseAnimating, public IParticleEffect
  19. {
  20. public:
  21. DECLARE_CLASS( C_EnvParticleScript, C_BaseAnimating );
  22. DECLARE_CLIENTCLASS();
  23. C_EnvParticleScript();
  24. // IParticleEffect overrides.
  25. public:
  26. virtual bool ShouldSimulate() const { return m_bSimulate; }
  27. virtual void SetShouldSimulate( bool bSim ) { m_bSimulate = bSim; }
  28. virtual void RenderParticles( CParticleRenderIterator *pIterator );
  29. virtual void SimulateParticles( CParticleSimulateIterator *pIterator );
  30. virtual const Vector &GetSortOrigin();
  31. // C_BaseAnimating overrides
  32. public:
  33. // NOTE: Ths enclosed particle effect binding will do all the drawing
  34. // But we have to return true, unlike other particle systems, for the animation events to work
  35. virtual bool ShouldDraw() { return true; }
  36. virtual int DrawModel( int flags ) { return 0; }
  37. virtual int GetFxBlend( void ) { return 0; }
  38. virtual void FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options );
  39. virtual void OnPreDataChanged( DataUpdateType_t updateType );
  40. virtual void OnDataChanged( DataUpdateType_t updateType );
  41. private:
  42. // Creates, destroys particles attached to an attachment
  43. void CreateParticle( const char *pAttachmentName, const char *pSpriteName );
  44. void DestroyAllParticles( const char *pAttachmentName );
  45. void DestroyAllParticles( );
  46. private:
  47. struct ParticleScriptParticle_t : public Particle
  48. {
  49. int m_nAttachment;
  50. float m_flSize;
  51. };
  52. CParticleEffectBinding m_ParticleEffect;
  53. float m_flMaxParticleSize;
  54. int m_nOldSequence;
  55. float m_flSequenceScale;
  56. bool m_bSimulate;
  57. };
  58. REGISTER_EFFECT( C_EnvParticleScript );
  59. //-----------------------------------------------------------------------------
  60. // Datatable
  61. //-----------------------------------------------------------------------------
  62. IMPLEMENT_CLIENTCLASS_DT( C_EnvParticleScript, DT_EnvParticleScript, CEnvParticleScript )
  63. RecvPropFloat( RECVINFO(m_flSequenceScale) ),
  64. END_RECV_TABLE()
  65. //-----------------------------------------------------------------------------
  66. // Constructor
  67. //-----------------------------------------------------------------------------
  68. C_EnvParticleScript::C_EnvParticleScript()
  69. {
  70. m_flMaxParticleSize = 0.0f;
  71. m_bSimulate = true;
  72. }
  73. //-----------------------------------------------------------------------------
  74. // Check for changed sequence numbers
  75. //-----------------------------------------------------------------------------
  76. void C_EnvParticleScript::OnPreDataChanged( DataUpdateType_t updateType )
  77. {
  78. BaseClass::OnPreDataChanged( updateType );
  79. m_nOldSequence = GetSequence();
  80. }
  81. //-----------------------------------------------------------------------------
  82. // Starts up the particle system
  83. //-----------------------------------------------------------------------------
  84. void C_EnvParticleScript::OnDataChanged( DataUpdateType_t updateType )
  85. {
  86. BaseClass::OnDataChanged( updateType );
  87. if(updateType == DATA_UPDATE_CREATED)
  88. {
  89. ParticleMgr()->AddEffect( &m_ParticleEffect, this );
  90. }
  91. if ( m_nOldSequence != GetSequence() )
  92. {
  93. DestroyAllParticles();
  94. }
  95. }
  96. //-----------------------------------------------------------------------------
  97. // Creates, destroys particles attached to an attachment
  98. //-----------------------------------------------------------------------------
  99. void C_EnvParticleScript::CreateParticle( const char *pAttachmentName, const char *pSpriteName )
  100. {
  101. // Find the attachment
  102. int nAttachment = LookupAttachment( pAttachmentName );
  103. if ( nAttachment <= 0 )
  104. return;
  105. // Get the sprite materials
  106. PMaterialHandle hMat = m_ParticleEffect.FindOrAddMaterial( pSpriteName );
  107. ParticleScriptParticle_t *pParticle =
  108. (ParticleScriptParticle_t*)m_ParticleEffect.AddParticle(sizeof(ParticleScriptParticle_t), hMat);
  109. if ( pParticle == NULL )
  110. return;
  111. // Get the sprite size from the material's materialvars
  112. bool bFound = false;
  113. IMaterialVar *pMaterialVar = NULL;
  114. IMaterial *pMaterial = ParticleMgr()->PMaterialToIMaterial( hMat );
  115. if ( pMaterial )
  116. {
  117. pMaterialVar = pMaterial->FindVar( "$spritesize", &bFound, false );
  118. }
  119. if ( bFound )
  120. {
  121. pParticle->m_flSize = pMaterialVar->GetFloatValue();
  122. }
  123. else
  124. {
  125. pParticle->m_flSize = 100.0f;
  126. }
  127. // Make sure the particle cull size reflects our particles
  128. if ( pParticle->m_flSize > m_flMaxParticleSize )
  129. {
  130. m_flMaxParticleSize = pParticle->m_flSize;
  131. m_ParticleEffect.SetParticleCullRadius( m_flMaxParticleSize );
  132. }
  133. // Place the particle on the attachment specified
  134. pParticle->m_nAttachment = nAttachment;
  135. QAngle vecAngles;
  136. GetAttachment( nAttachment, pParticle->m_Pos, vecAngles );
  137. if ( m_flSequenceScale != 1.0f )
  138. {
  139. pParticle->m_Pos -= GetAbsOrigin();
  140. pParticle->m_Pos *= m_flSequenceScale;
  141. pParticle->m_Pos += GetAbsOrigin();
  142. }
  143. }
  144. void C_EnvParticleScript::DestroyAllParticles( const char *pAttachmentName )
  145. {
  146. int nAttachment = LookupAttachment( pAttachmentName );
  147. if ( nAttachment <= 0 )
  148. return;
  149. int nCount = m_ParticleEffect.GetNumActiveParticles();
  150. Particle** ppParticles = (Particle**)stackalloc( nCount * sizeof(Particle*) );
  151. int nActualCount = m_ParticleEffect.GetActiveParticleList( nCount, ppParticles );
  152. Assert( nActualCount == nCount );
  153. for ( int i = 0; i < nActualCount; ++i )
  154. {
  155. ParticleScriptParticle_t *pParticle = (ParticleScriptParticle_t*)ppParticles[i];
  156. if ( pParticle->m_nAttachment == nAttachment )
  157. {
  158. // Mark for deletion
  159. pParticle->m_nAttachment = -1;
  160. }
  161. }
  162. }
  163. void C_EnvParticleScript::DestroyAllParticles( )
  164. {
  165. int nCount = m_ParticleEffect.GetNumActiveParticles();
  166. Particle** ppParticles = (Particle**)stackalloc( nCount * sizeof(Particle*) );
  167. int nActualCount = m_ParticleEffect.GetActiveParticleList( nCount, ppParticles );
  168. Assert( nActualCount == nCount );
  169. for ( int i = 0; i < nActualCount; ++i )
  170. {
  171. ParticleScriptParticle_t *pParticle = (ParticleScriptParticle_t*)ppParticles[i];
  172. // Mark for deletion
  173. pParticle->m_nAttachment = -1;
  174. }
  175. }
  176. //-----------------------------------------------------------------------------
  177. // The animation events will create particles on the attachment points
  178. //-----------------------------------------------------------------------------
  179. void C_EnvParticleScript::FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options )
  180. {
  181. // Handle events to create + destroy particles
  182. switch( event )
  183. {
  184. case CL_EVENT_SPRITEGROUP_CREATE:
  185. {
  186. char pAttachmentName[256];
  187. char pSpriteName[256];
  188. int nArgs = sscanf( options, "%255s %255s", pAttachmentName, pSpriteName );
  189. if ( nArgs == 2 )
  190. {
  191. CreateParticle( pAttachmentName, pSpriteName );
  192. }
  193. }
  194. return;
  195. case CL_EVENT_SPRITEGROUP_DESTROY:
  196. {
  197. char pAttachmentName[256];
  198. int nArgs = sscanf( options, "%255s", pAttachmentName );
  199. if ( nArgs == 1 )
  200. {
  201. DestroyAllParticles( pAttachmentName );
  202. }
  203. }
  204. return;
  205. }
  206. // Fall back
  207. BaseClass::FireEvent( origin, angles, event, options );
  208. }
  209. //-----------------------------------------------------------------------------
  210. // Simulate the particles
  211. //-----------------------------------------------------------------------------
  212. void C_EnvParticleScript::RenderParticles( CParticleRenderIterator *pIterator )
  213. {
  214. const ParticleScriptParticle_t* pParticle = (const ParticleScriptParticle_t*)pIterator->GetFirst();
  215. while ( pParticle )
  216. {
  217. Vector vecRenderPos;
  218. TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, vecRenderPos );
  219. float sortKey = vecRenderPos.z;
  220. Vector color( 1, 1, 1 );
  221. RenderParticle_ColorSize( pIterator->GetParticleDraw(), vecRenderPos, color, 1.0f, pParticle->m_flSize );
  222. pParticle = (const ParticleScriptParticle_t*)pIterator->GetNext( sortKey );
  223. }
  224. }
  225. void C_EnvParticleScript::SimulateParticles( CParticleSimulateIterator *pIterator )
  226. {
  227. ParticleScriptParticle_t* pParticle = (ParticleScriptParticle_t*)pIterator->GetFirst();
  228. while ( pParticle )
  229. {
  230. // Here's how we retire particles
  231. if ( pParticle->m_nAttachment == -1 )
  232. {
  233. pIterator->RemoveParticle( pParticle );
  234. }
  235. else
  236. {
  237. // Move the particle to the attachment point
  238. QAngle vecAngles;
  239. GetAttachment( pParticle->m_nAttachment, pParticle->m_Pos, vecAngles );
  240. if ( m_flSequenceScale != 1.0f )
  241. {
  242. pParticle->m_Pos -= GetAbsOrigin();
  243. pParticle->m_Pos *= m_flSequenceScale;
  244. pParticle->m_Pos += GetAbsOrigin();
  245. }
  246. }
  247. pParticle = (ParticleScriptParticle_t*)pIterator->GetNext();
  248. }
  249. }
  250. const Vector &C_EnvParticleScript::GetSortOrigin()
  251. {
  252. return GetAbsOrigin();
  253. }