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.

250 lines
7.8 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "baseparticleentity.h"
  9. #include "entityparticletrail_shared.h"
  10. #include "particlemgr.h"
  11. #include "particle_util.h"
  12. #include "particles_simple.h"
  13. // memdbgon must be the last include file in a .cpp file!!!
  14. #include "tier0/memdbgon.h"
  15. //-----------------------------------------------------------------------------
  16. // Entity particle trail, client-side implementation
  17. //-----------------------------------------------------------------------------
  18. class C_EntityParticleTrail : public C_BaseParticleEntity
  19. {
  20. public:
  21. DECLARE_CLIENTCLASS();
  22. DECLARE_CLASS( C_EntityParticleTrail, C_BaseParticleEntity );
  23. C_EntityParticleTrail( );
  24. ~C_EntityParticleTrail( );
  25. // C_BaseEntity
  26. virtual void OnDataChanged( DataUpdateType_t updateType );
  27. // IParticleEffect
  28. void Update( float fTimeDelta );
  29. virtual void RenderParticles( CParticleRenderIterator *pIterator );
  30. virtual void SimulateParticles( CParticleSimulateIterator *pIterator );
  31. private:
  32. C_EntityParticleTrail( const C_EntityParticleTrail & ); // not defined, not accessible
  33. void Start( );
  34. void AddParticle( float flInitialDeltaTime, const Vector &vecMins, const Vector &vecMaxs, const matrix3x4_t &boxToWorld );
  35. int m_iMaterialName;
  36. EntityParticleTrailInfo_t m_Info;
  37. EHANDLE m_hConstraintEntity;
  38. PMaterialHandle m_hMaterial;
  39. TimedEvent m_teParticleSpawn;
  40. };
  41. //-----------------------------------------------------------------------------
  42. // Networking
  43. //-----------------------------------------------------------------------------
  44. IMPLEMENT_CLIENTCLASS_DT( C_EntityParticleTrail, DT_EntityParticleTrail, CEntityParticleTrail )
  45. RecvPropInt(RECVINFO(m_iMaterialName)),
  46. RecvPropDataTable( RECVINFO_DT( m_Info ), 0, &REFERENCE_RECV_TABLE(DT_EntityParticleTrailInfo) ),
  47. RecvPropEHandle(RECVINFO(m_hConstraintEntity)),
  48. END_RECV_TABLE()
  49. //-----------------------------------------------------------------------------
  50. // Purpose:
  51. //-----------------------------------------------------------------------------
  52. C_EntityParticleTrail::C_EntityParticleTrail( void )
  53. {
  54. }
  55. C_EntityParticleTrail::~C_EntityParticleTrail()
  56. {
  57. ParticleMgr()->RemoveEffect( &m_ParticleEffect );
  58. }
  59. //-----------------------------------------------------------------------------
  60. // On data changed
  61. //-----------------------------------------------------------------------------
  62. void C_EntityParticleTrail::OnDataChanged( DataUpdateType_t updateType )
  63. {
  64. BaseClass::OnDataChanged( updateType );
  65. if ( updateType == DATA_UPDATE_CREATED )
  66. {
  67. Start( );
  68. }
  69. }
  70. //-----------------------------------------------------------------------------
  71. // Purpose:
  72. // Input : *pParticleMgr -
  73. // *pArgs -
  74. //-----------------------------------------------------------------------------
  75. void C_EntityParticleTrail::Start( )
  76. {
  77. if( ParticleMgr()->AddEffect( &m_ParticleEffect, this ) == false )
  78. return;
  79. const char *pMaterialName = GetMaterialNameFromIndex( m_iMaterialName );
  80. if ( !pMaterialName )
  81. return;
  82. m_hMaterial = ParticleMgr()->GetPMaterial( pMaterialName );
  83. m_teParticleSpawn.Init( 150 );
  84. }
  85. //-----------------------------------------------------------------------------
  86. // Purpose:
  87. //-----------------------------------------------------------------------------
  88. void C_EntityParticleTrail::AddParticle( float flInitialDeltaTime, const Vector &vecMins, const Vector &vecMaxs, const matrix3x4_t &boxToWorld )
  89. {
  90. // Select a random point somewhere in the hitboxes of the entity.
  91. Vector vecLocalPosition, vecWorldPosition;
  92. vecLocalPosition.x = Lerp( random->RandomFloat( 0.0f, 1.0f ), vecMins.x, vecMaxs.x );
  93. vecLocalPosition.y = Lerp( random->RandomFloat( 0.0f, 1.0f ), vecMins.y, vecMaxs.y );
  94. vecLocalPosition.z = Lerp( random->RandomFloat( 0.0f, 1.0f ), vecMins.z, vecMaxs.z );
  95. VectorTransform( vecLocalPosition, boxToWorld, vecWorldPosition );
  96. // Don't emit the particle unless it's inside the model
  97. if ( m_hConstraintEntity.Get() )
  98. {
  99. Ray_t ray;
  100. trace_t tr;
  101. ray.Init( vecWorldPosition, vecWorldPosition );
  102. enginetrace->ClipRayToEntity( ray, MASK_ALL, m_hConstraintEntity, &tr );
  103. if ( !tr.startsolid )
  104. return;
  105. }
  106. // Make a new particle
  107. SimpleParticle *pParticle = (SimpleParticle *)m_ParticleEffect.AddParticle( sizeof(SimpleParticle), m_hMaterial );
  108. if ( pParticle == NULL )
  109. return;
  110. pParticle->m_Pos = vecWorldPosition;
  111. pParticle->m_flRoll = Helper_RandomInt( 0, 360 );
  112. pParticle->m_flRollDelta = Helper_RandomFloat( -2.0f, 2.0f );
  113. pParticle->m_flLifetime = flInitialDeltaTime;
  114. pParticle->m_flDieTime = m_Info.m_flLifetime;
  115. pParticle->m_uchColor[0] = 64;
  116. pParticle->m_uchColor[1] = 140;
  117. pParticle->m_uchColor[2] = 225;
  118. pParticle->m_uchStartAlpha = Helper_RandomInt( 64, 64 );
  119. pParticle->m_uchEndAlpha = 0;
  120. pParticle->m_uchStartSize = m_Info.m_flStartSize;
  121. pParticle->m_uchEndSize = m_Info.m_flEndSize;
  122. pParticle->m_vecVelocity = vec3_origin;
  123. VectorMA( pParticle->m_Pos, flInitialDeltaTime, pParticle->m_vecVelocity, pParticle->m_Pos );
  124. }
  125. //-----------------------------------------------------------------------------
  126. // Purpose:
  127. // Input : fTimeDelta -
  128. //-----------------------------------------------------------------------------
  129. void C_EntityParticleTrail::Update( float fTimeDelta )
  130. {
  131. float tempDelta = fTimeDelta;
  132. studiohdr_t *pStudioHdr;
  133. mstudiohitboxset_t *set;
  134. matrix3x4_t *hitboxbones[MAXSTUDIOBONES];
  135. C_BaseEntity *pMoveParent = GetMoveParent();
  136. if ( !pMoveParent )
  137. return;
  138. C_BaseAnimating *pAnimating = pMoveParent->GetBaseAnimating();
  139. if (!pAnimating)
  140. goto trailNoHitboxes;
  141. if ( !pAnimating->HitboxToWorldTransforms( hitboxbones ) )
  142. goto trailNoHitboxes;
  143. pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() );
  144. if (!pStudioHdr)
  145. goto trailNoHitboxes;
  146. set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() );
  147. if ( !set )
  148. goto trailNoHitboxes;
  149. //Add new particles
  150. while ( m_teParticleSpawn.NextEvent( tempDelta ) )
  151. {
  152. int nHitbox = random->RandomInt( 0, set->numhitboxes - 1 );
  153. mstudiobbox_t *pBox = set->pHitbox(nHitbox);
  154. AddParticle( tempDelta, pBox->bbmin, pBox->bbmax, *hitboxbones[pBox->bone] );
  155. }
  156. return;
  157. trailNoHitboxes:
  158. while ( m_teParticleSpawn.NextEvent( tempDelta ) )
  159. {
  160. AddParticle( tempDelta, pMoveParent->CollisionProp()->OBBMins(), pMoveParent->CollisionProp()->OBBMaxs(), pMoveParent->EntityToWorldTransform() );
  161. }
  162. }
  163. inline void C_EntityParticleTrail::RenderParticles( CParticleRenderIterator *pIterator )
  164. {
  165. const SimpleParticle *pParticle = (const SimpleParticle*)pIterator->GetFirst();
  166. while ( pParticle )
  167. {
  168. float t = pParticle->m_flLifetime / pParticle->m_flDieTime;
  169. // Render
  170. Vector tPos;
  171. TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, tPos );
  172. float sortKey = tPos.z;
  173. Vector color = Vector( pParticle->m_uchColor[0] / 255.0f, pParticle->m_uchColor[1] / 255.0f, pParticle->m_uchColor[2] / 255.0f );
  174. float alpha = Lerp( t, pParticle->m_uchStartAlpha / 255.0f, pParticle->m_uchEndAlpha / 255.0f );
  175. float flSize = Lerp( t, pParticle->m_uchStartSize, pParticle->m_uchEndSize );
  176. // Render it
  177. RenderParticle_ColorSize( pIterator->GetParticleDraw(), tPos, color, alpha, flSize );
  178. pParticle = (const SimpleParticle*)pIterator->GetNext( sortKey );
  179. }
  180. }
  181. inline void C_EntityParticleTrail::SimulateParticles( CParticleSimulateIterator *pIterator )
  182. {
  183. SimpleParticle *pParticle = (SimpleParticle*)pIterator->GetFirst();
  184. while ( pParticle )
  185. {
  186. // Update position
  187. float flTimeDelta = pIterator->GetTimeDelta();
  188. pParticle->m_Pos += pParticle->m_vecVelocity * flTimeDelta;
  189. // NOTE: I'm overloading "die time" to be the actual start time.
  190. pParticle->m_flLifetime += flTimeDelta;
  191. if ( pParticle->m_flLifetime >= pParticle->m_flDieTime )
  192. pIterator->RemoveParticle( pParticle );
  193. pParticle = (SimpleParticle*)pIterator->GetNext();
  194. }
  195. }