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.

367 lines
9.6 KiB

  1. //========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "fx.h"
  9. #include "c_func_dust.h"
  10. #include "func_dust_shared.h"
  11. #include "c_te_particlesystem.h"
  12. #include "env_wind_shared.h"
  13. #include "engine/IEngineTrace.h"
  14. #include "tier0/vprof.h"
  15. #include "particles_ez.h"
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include "tier0/memdbgon.h"
  18. IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_Func_Dust, DT_Func_Dust, CFunc_Dust )
  19. RecvPropInt( RECVINFO(m_Color), 0, RecvProxy_Int32ToColor32 ),
  20. RecvPropInt( RECVINFO(m_SpawnRate) ),
  21. RecvPropFloat( RECVINFO(m_flSizeMin) ),
  22. RecvPropFloat( RECVINFO(m_flSizeMax) ),
  23. RecvPropInt( RECVINFO(m_LifetimeMin) ),
  24. RecvPropInt( RECVINFO(m_LifetimeMax) ),
  25. RecvPropInt( RECVINFO(m_DustFlags) ),
  26. RecvPropInt( RECVINFO(m_SpeedMax) ),
  27. RecvPropInt( RECVINFO(m_DistMax) ),
  28. RecvPropInt( RECVINFO( m_nModelIndex ) ),
  29. RecvPropFloat( RECVINFO( m_FallSpeed ) ),
  30. RecvPropBool( RECVINFO( m_bAffectedByWind ) ),
  31. RecvPropDataTable( RECVINFO_DT( m_Collision ), 0, &REFERENCE_RECV_TABLE(DT_CollisionProperty) ),
  32. END_RECV_TABLE()
  33. // ------------------------------------------------------------------------------------ //
  34. // CDustEffect implementation.
  35. // ------------------------------------------------------------------------------------ //
  36. #define DUST_ACCEL 50
  37. void CDustEffect::RenderParticles( CParticleRenderIterator *pIterator )
  38. {
  39. const CFuncDustParticle *pParticle = (const CFuncDustParticle*)pIterator->GetFirst();
  40. while ( pParticle )
  41. {
  42. // Velocity.
  43. float flAlpha;
  44. if( m_pDust->m_DustFlags & DUSTFLAGS_FROZEN )
  45. {
  46. flAlpha = 1;
  47. }
  48. else
  49. {
  50. // Alpha.
  51. float flAngle = (pParticle->m_flLifetime / pParticle->m_flDieTime) * M_PI * 2;
  52. flAlpha = sin( flAngle - (M_PI * 0.5f) ) * 0.5f + 0.5f;
  53. }
  54. Vector tPos;
  55. TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, tPos );
  56. float sortKey = (int) tPos.z;
  57. if( -tPos.z <= m_pDust->m_DistMax )
  58. {
  59. flAlpha *= 1 + (tPos.z / m_pDust->m_DistMax);
  60. // Draw it.
  61. float flSize = pParticle->m_flSize;
  62. if( m_pDust->m_DustFlags & DUSTFLAGS_SCALEMOTES )
  63. flSize *= -tPos.z;
  64. RenderParticle_Color255Size(
  65. pIterator->GetParticleDraw(),
  66. tPos,
  67. Vector( m_pDust->m_Color.r, m_pDust->m_Color.g, m_pDust->m_Color.b ),
  68. flAlpha * m_pDust->m_Color.a,
  69. flSize
  70. );
  71. }
  72. pParticle = (const CFuncDustParticle*)pIterator->GetNext( sortKey );
  73. }
  74. }
  75. void CDustEffect::SimulateParticles( CParticleSimulateIterator *pIterator )
  76. {
  77. Vector vecWind;
  78. if ( m_pDust->m_bAffectedByWind )
  79. GetWindspeedAtTime( gpGlobals->curtime, vecWind );
  80. else
  81. vecWind = Vector( 0, 0, 0 );
  82. CFuncDustParticle *pParticle = (CFuncDustParticle*)pIterator->GetFirst();
  83. while ( pParticle )
  84. {
  85. // Velocity.
  86. if( !(m_pDust->m_DustFlags & DUSTFLAGS_FROZEN) )
  87. {
  88. // Kill the particle?
  89. pParticle->m_flLifetime += pIterator->GetTimeDelta();
  90. if( pParticle->m_flLifetime >= pParticle->m_flDieTime )
  91. {
  92. pIterator->RemoveParticle( pParticle );
  93. }
  94. else
  95. {
  96. for ( int i = 0 ; i < 2 ; i++ )
  97. {
  98. if ( pParticle->m_vVelocity[i] < vecWind[i] )
  99. {
  100. pParticle->m_vVelocity[i] += ( gpGlobals->frametime * DUST_ACCEL );
  101. // clamp
  102. if ( pParticle->m_vVelocity[i] > vecWind[i] )
  103. pParticle->m_vVelocity[i] = vecWind[i];
  104. }
  105. else if (pParticle->m_vVelocity[i] > vecWind[i] )
  106. {
  107. pParticle->m_vVelocity[i] -= ( gpGlobals->frametime * DUST_ACCEL );
  108. // clamp.
  109. if ( pParticle->m_vVelocity[i] < vecWind[i] )
  110. pParticle->m_vVelocity[i] = vecWind[i];
  111. }
  112. }
  113. // Apply velocity.
  114. pParticle->m_Pos.MulAdd( pParticle->m_Pos, pParticle->m_vVelocity, pIterator->GetTimeDelta() );
  115. }
  116. }
  117. pParticle = (CFuncDustParticle*)pIterator->GetNext();
  118. }
  119. }
  120. // ------------------------------------------------------------------------------------ //
  121. // C_Func_Dust implementation.
  122. // ------------------------------------------------------------------------------------ //
  123. C_Func_Dust::C_Func_Dust() : m_Effect( "C_Func_Dust" )
  124. {
  125. m_Effect.m_pDust = this;
  126. m_Effect.SetDynamicallyAllocated( false ); // So it doesn't try to delete itself.
  127. }
  128. C_Func_Dust::~C_Func_Dust()
  129. {
  130. }
  131. void C_Func_Dust::OnDataChanged( DataUpdateType_t updateType )
  132. {
  133. BaseClass::OnDataChanged( updateType );
  134. if( updateType == DATA_UPDATE_CREATED )
  135. {
  136. m_hMaterial = m_Effect.GetPMaterial( "particle/sparkles" );
  137. m_Effect.SetSortOrigin( WorldSpaceCenter( ) );
  138. // Let us think each frame.
  139. SetNextClientThink( CLIENT_THINK_ALWAYS );
  140. // If we're setup to be frozen, just make a bunch of particles initially.
  141. if( m_DustFlags & DUSTFLAGS_FROZEN )
  142. {
  143. for( int i=0; i < m_SpawnRate; i++ )
  144. {
  145. AttemptSpawnNewParticle();
  146. }
  147. }
  148. }
  149. m_Spawner.Init( m_SpawnRate ); // N particles per second
  150. }
  151. void C_Func_Dust::ClientThink()
  152. {
  153. // If frozen, don't make new particles.
  154. if( m_DustFlags & DUSTFLAGS_FROZEN )
  155. return;
  156. // Spawn particles?
  157. if( m_DustFlags & DUSTFLAGS_ON )
  158. {
  159. float flDelta = MIN( gpGlobals->frametime, 0.1f );
  160. while( m_Spawner.NextEvent( flDelta ) )
  161. {
  162. AttemptSpawnNewParticle();
  163. }
  164. }
  165. // Tell the particle manager our bbox.
  166. Vector vWorldMins, vWorldMaxs;
  167. CollisionProp()->WorldSpaceAABB( &vWorldMins, &vWorldMaxs );
  168. vWorldMins -= Vector( m_flSizeMax, m_flSizeMax, m_flSizeMax );
  169. vWorldMaxs += Vector( m_flSizeMax, m_flSizeMax, m_flSizeMax );
  170. m_Effect.GetBinding().SetBBox( vWorldMins, vWorldMaxs );
  171. }
  172. bool C_Func_Dust::ShouldDraw()
  173. {
  174. return false;
  175. }
  176. void C_Func_Dust::AttemptSpawnNewParticle()
  177. {
  178. // Find a random spot inside our bmodel.
  179. static int nTests=10;
  180. for( int iTest=0; iTest < nTests; iTest++ )
  181. {
  182. Vector vPercent = RandomVector( 0, 1 );
  183. Vector vTest = WorldAlignMins() + (WorldAlignMaxs() - WorldAlignMins()) * vPercent;
  184. int contents = enginetrace->GetPointContents_Collideable( GetCollideable(), vTest );
  185. if( contents & CONTENTS_SOLID )
  186. {
  187. CFuncDustParticle *pParticle = (CFuncDustParticle*)m_Effect.AddParticle( 10, m_hMaterial, vTest );
  188. if( pParticle )
  189. {
  190. pParticle->m_vVelocity = RandomVector( -m_SpeedMax, m_SpeedMax );
  191. pParticle->m_vVelocity.z -= m_FallSpeed;
  192. pParticle->m_flLifetime = 0;
  193. pParticle->m_flDieTime = RandomFloat( m_LifetimeMin, m_LifetimeMax );
  194. if( m_DustFlags & DUSTFLAGS_SCALEMOTES )
  195. pParticle->m_flSize = RandomFloat( m_flSizeMin/10000.0f, m_flSizeMax/10000.0f );
  196. else
  197. pParticle->m_flSize = RandomFloat( m_flSizeMin, m_flSizeMax );
  198. pParticle->m_Color = m_Color;
  199. }
  200. break;
  201. }
  202. }
  203. }
  204. //
  205. // Dust
  206. //
  207. //-----------------------------------------------------------------------------
  208. // Spew out dust!
  209. //-----------------------------------------------------------------------------
  210. void FX_Dust( const Vector &vecOrigin, const Vector &vecDirection, float flSize, float flSpeed )
  211. {
  212. VPROF_BUDGET( "FX_Dust", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  213. int numPuffs = (flSize*0.5f);
  214. if ( numPuffs < 1 )
  215. numPuffs = 1;
  216. if ( numPuffs > 32 )
  217. numPuffs = 32;
  218. float speed = flSpeed * 0.1f;
  219. if ( speed < 0 )
  220. speed = 1.0f;
  221. if (speed > 48.0f )
  222. speed = 48.0f;
  223. //FIXME: Better sampling area
  224. Vector offset = vecOrigin + ( vecDirection * flSize );
  225. //Find area ambient light color and use it to tint smoke
  226. Vector worldLight = WorldGetLightForPoint( offset, true );
  227. // Throw puffs
  228. SimpleParticle particle;
  229. for ( int i = 0; i < numPuffs; i++ )
  230. {
  231. offset.Random( -(flSize*0.25f), flSize*0.25f );
  232. offset += vecOrigin + ( vecDirection * flSize );
  233. particle.m_Pos = offset;
  234. particle.m_flLifetime = 0.0f;
  235. particle.m_flDieTime = random->RandomFloat( 0.4f, 1.0f );
  236. particle.m_vecVelocity = vecDirection * random->RandomFloat( speed*0.5f, speed ) * i;
  237. particle.m_vecVelocity[2] = 0.0f;
  238. int color = random->RandomInt( 48, 64 );
  239. particle.m_uchColor[0] = (color+16) + ( worldLight[0] * (float) color );
  240. particle.m_uchColor[1] = (color+8) + ( worldLight[1] * (float) color );
  241. particle.m_uchColor[2] = color + ( worldLight[2] * (float) color );
  242. particle.m_uchStartAlpha= random->RandomInt( 64, 128 );
  243. particle.m_uchEndAlpha = 0;
  244. particle.m_uchStartSize = random->RandomInt( 2, 8 );
  245. particle.m_uchEndSize = random->RandomInt( 24, 48 );
  246. particle.m_flRoll = random->RandomInt( 0, 360 );
  247. particle.m_flRollDelta = random->RandomFloat( -0.5f, 0.5f );
  248. AddSimpleParticle( &particle, g_Mat_DustPuff[random->RandomInt(0,1)] );
  249. }
  250. }
  251. class C_TEDust: public C_TEParticleSystem
  252. {
  253. public:
  254. DECLARE_CLASS( C_TEDust, C_TEParticleSystem );
  255. DECLARE_CLIENTCLASS();
  256. C_TEDust();
  257. virtual ~C_TEDust();
  258. public:
  259. virtual void PostDataUpdate( DataUpdateType_t updateType );
  260. virtual bool ShouldDraw() { return true; }
  261. public:
  262. float m_flSize;
  263. float m_flSpeed;
  264. Vector m_vecDirection;
  265. protected:
  266. void GetDustColor( Vector &color );
  267. };
  268. IMPLEMENT_CLIENTCLASS_EVENT_DT( C_TEDust, DT_TEDust, CTEDust )
  269. RecvPropFloat(RECVINFO(m_flSize)),
  270. RecvPropFloat(RECVINFO(m_flSpeed)),
  271. RecvPropVector(RECVINFO(m_vecDirection)),
  272. END_RECV_TABLE()
  273. //==================================================
  274. // C_TEDust
  275. //==================================================
  276. C_TEDust::C_TEDust()
  277. {
  278. }
  279. C_TEDust::~C_TEDust()
  280. {
  281. }
  282. //-----------------------------------------------------------------------------
  283. // Purpose:
  284. // Input : bNewEntity - whether or not to start a new entity
  285. //-----------------------------------------------------------------------------
  286. void C_TEDust::PostDataUpdate( DataUpdateType_t updateType )
  287. {
  288. FX_Dust( m_vecOrigin, m_vecDirection, m_flSize, m_flSpeed );
  289. }
  290. void TE_Dust( IRecipientFilter& filter, float delay,
  291. const Vector &pos, const Vector &dir, float size, float speed )
  292. {
  293. FX_Dust( pos, dir, size, speed );
  294. }