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.

876 lines
29 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: particle system code
  4. //
  5. //===========================================================================//
  6. #include "tier0/platform.h"
  7. #include "particles/particles.h"
  8. #include "filesystem.h"
  9. #include "tier2/tier2.h"
  10. #include "tier2/fileutils.h"
  11. #include "tier1/UtlStringMap.h"
  12. #include "tier1/strtools.h"
  13. // memdbgon must be the last include file in a .cpp file!!!
  14. #include "tier0/memdbgon.h"
  15. extern int g_nParticle_Multiplier;
  16. //-----------------------------------------------------------------------------
  17. // Emits particles immediately
  18. //-----------------------------------------------------------------------------
  19. struct InstantaneousEmitterContext_t
  20. {
  21. int m_nRemainingParticles;
  22. int m_ActualParticlesToEmit;
  23. float m_flTimeOffset;
  24. bool m_bReadScaleFactor;
  25. };
  26. class C_OP_InstantaneousEmitter : public CParticleOperatorInstance
  27. {
  28. DECLARE_PARTICLE_OPERATOR( C_OP_InstantaneousEmitter );
  29. uint32 GetWrittenAttributes( void ) const
  30. {
  31. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  32. }
  33. uint32 GetReadAttributes( void ) const
  34. {
  35. return 0;
  36. }
  37. virtual uint64 GetReadControlPointMask() const
  38. {
  39. if ( m_nScaleControlPoint >= 0 )
  40. return ( 1ULL << m_nScaleControlPoint );
  41. return 0;
  42. }
  43. virtual uint32 Emit( CParticleCollection *pParticles, float flCurStrength,
  44. void *pContext ) const;
  45. // unpack structure will be applied by creator. add extra initialization needed here
  46. virtual void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  47. {
  48. if ( m_nMinParticlesToEmit >= 0 )
  49. {
  50. if ( m_nMinParticlesToEmit > m_nParticlesToEmit )
  51. {
  52. V_swap( m_nParticlesToEmit, m_nMinParticlesToEmit );
  53. }
  54. }
  55. if ( m_nPerFrameNum < 0 )
  56. {
  57. m_nPerFrameNum = INT_MAX;
  58. }
  59. m_nScaleControlPointField = clamp( m_nScaleControlPointField, 0, 2 );
  60. }
  61. virtual void StopEmission( CParticleCollection *pParticles, void *pContext, bool bInfiniteOnly ) const
  62. {
  63. InstantaneousEmitterContext_t *pCtx = reinterpret_cast<InstantaneousEmitterContext_t *>( pContext );
  64. if ( !bInfiniteOnly )
  65. {
  66. pCtx->m_nRemainingParticles = 0;
  67. }
  68. }
  69. virtual void StartEmission( CParticleCollection *pParticles, void *pContext, bool bInfiniteOnly ) const
  70. {
  71. InstantaneousEmitterContext_t *pCtx = reinterpret_cast<InstantaneousEmitterContext_t *>( pContext );
  72. if ( !bInfiniteOnly )
  73. {
  74. pCtx->m_nRemainingParticles = pCtx->m_ActualParticlesToEmit;
  75. SkipToTime( pParticles->m_flCurTime, pParticles, pCtx );
  76. }
  77. }
  78. // Called when the SFM wants to skip forward in time
  79. virtual void SkipToTime( float flTime, CParticleCollection *pParticles, void *pContext ) const
  80. {
  81. // NOTE: This is a bit of a hack. We're saying that if we're skipping more than two seconds, that we're
  82. // probably not going to bother emitting at all. Really, this would have to know the maximum
  83. // lifetime of the child particles and only skip if past that.
  84. InstantaneousEmitterContext_t *pCtx = reinterpret_cast<InstantaneousEmitterContext_t *>( pContext );
  85. float flStartTime = m_flStartTime + pCtx->m_flTimeOffset;
  86. if ( flTime > ( flStartTime + 2.0f ) )
  87. {
  88. pCtx->m_nRemainingParticles = 0;
  89. }
  90. }
  91. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  92. {
  93. InstantaneousEmitterContext_t *pCtx = reinterpret_cast<InstantaneousEmitterContext_t *>( pContext );
  94. if ( m_nMinParticlesToEmit >= 0 )
  95. {
  96. pCtx->m_ActualParticlesToEmit = pParticles->RandomInt( m_nMinParticlesToEmit, m_nParticlesToEmit );
  97. }
  98. else
  99. {
  100. pCtx->m_ActualParticlesToEmit = m_nParticlesToEmit;
  101. }
  102. pCtx->m_nRemainingParticles = pCtx->m_ActualParticlesToEmit;
  103. pCtx->m_flTimeOffset = 0.0f;
  104. pCtx->m_bReadScaleFactor = false;
  105. }
  106. virtual void Restart( CParticleCollection *pParticles, void *pContext )
  107. {
  108. InstantaneousEmitterContext_t *pCtx = reinterpret_cast<InstantaneousEmitterContext_t *>( pContext );
  109. pCtx->m_nRemainingParticles = pCtx->m_ActualParticlesToEmit;
  110. pCtx->m_flTimeOffset = pParticles->m_flCurTime;
  111. pCtx->m_bReadScaleFactor = false;
  112. }
  113. size_t GetRequiredContextBytes( void ) const
  114. {
  115. return sizeof( InstantaneousEmitterContext_t );
  116. }
  117. virtual bool MayCreateMoreParticles( CParticleCollection *pParticles, void *pContext ) const
  118. {
  119. InstantaneousEmitterContext_t *pCtx = reinterpret_cast<InstantaneousEmitterContext_t *>( pContext );
  120. return !(pCtx->m_nRemainingParticles <= 0);
  121. }
  122. int m_nParticlesToEmit;
  123. int m_nMinParticlesToEmit;
  124. float m_flStartTime;
  125. int m_nPerFrameNum;
  126. int m_nScaleControlPoint;
  127. int m_nScaleControlPointField;
  128. };
  129. DEFINE_PARTICLE_OPERATOR( C_OP_InstantaneousEmitter, "emit_instantaneously", OPERATOR_GENERIC );
  130. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_InstantaneousEmitter )
  131. DMXELEMENT_UNPACK_FIELD( "emission_start_time", "0", float, m_flStartTime )
  132. DMXELEMENT_UNPACK_FIELD( "num_to_emit_minimum", "-1", int, m_nMinParticlesToEmit )
  133. DMXELEMENT_UNPACK_FIELD( "num_to_emit", "100", int, m_nParticlesToEmit )
  134. DMXELEMENT_UNPACK_FIELD( "maximum emission per frame", "-1", int, m_nPerFrameNum )
  135. DMXELEMENT_UNPACK_FIELD( "emission count scale control point", "-1", int, m_nScaleControlPoint )
  136. DMXELEMENT_UNPACK_FIELD( "emission count scale control point field", "0", int, m_nScaleControlPointField )
  137. END_PARTICLE_OPERATOR_UNPACK( C_OP_InstantaneousEmitter )
  138. uint32 C_OP_InstantaneousEmitter::Emit( CParticleCollection *pParticles, float flCurStrength,
  139. void *pContext ) const
  140. {
  141. // Don't emit any more if the particle system has emitted all it's supposed to.
  142. InstantaneousEmitterContext_t *pCtx = reinterpret_cast<InstantaneousEmitterContext_t *>( pContext );
  143. if ( pCtx->m_nRemainingParticles <= 0 )
  144. return 0;
  145. // Wait until we're told to start emitting
  146. float flStartTime = m_flStartTime + pCtx->m_flTimeOffset;
  147. if ( pParticles->m_flCurTime < flStartTime )
  148. return 0;
  149. if ( pCtx->m_ActualParticlesToEmit == 0 )
  150. return 0;
  151. if ( ( m_nScaleControlPoint >= 0 ) && !pCtx->m_bReadScaleFactor )
  152. {
  153. Vector vecScale;
  154. if ( flStartTime <= pParticles->m_flCurTime && flStartTime >= pParticles->m_flCurTime - pParticles->m_flPreviousDt )
  155. {
  156. pParticles->GetControlPointAtTime( m_nScaleControlPoint, flStartTime, &vecScale );
  157. }
  158. else
  159. {
  160. pParticles->GetControlPointAtPrevTime( m_nScaleControlPoint, &vecScale );
  161. }
  162. pCtx->m_ActualParticlesToEmit *= vecScale[m_nScaleControlPointField];
  163. pCtx->m_nRemainingParticles *= vecScale[m_nScaleControlPointField];
  164. pCtx->m_bReadScaleFactor = true;
  165. }
  166. pCtx->m_nRemainingParticles = max( pCtx->m_nRemainingParticles, 0 );
  167. // NOTE: Applying the scale here because I don't believe we can sample the control point
  168. // values inside
  169. // We're only allowed to emit so many particles, though..
  170. // If we run out of room, only emit the last N particles
  171. int nAllowedParticlesToEmit = pParticles->m_nMaxAllowedParticles - pParticles->m_nActiveParticles;
  172. // Cap to the maximum emission per frame
  173. int nParticlesThisFrame = min( m_nPerFrameNum, pCtx->m_nRemainingParticles );
  174. nAllowedParticlesToEmit = min( nAllowedParticlesToEmit, nParticlesThisFrame );
  175. int nActualParticlesToEmit = min( nAllowedParticlesToEmit, pCtx->m_ActualParticlesToEmit * g_nParticle_Multiplier );
  176. pCtx->m_nRemainingParticles -= nParticlesThisFrame;
  177. Assert( pCtx->m_nRemainingParticles >= 0 );
  178. if ( nActualParticlesToEmit == 0 )
  179. return 0;
  180. int nStartParticle = pParticles->m_nActiveParticles;
  181. pParticles->SetNActiveParticles( nActualParticlesToEmit + pParticles->m_nActiveParticles );
  182. // !! speed!! do sse init here
  183. for( int i = nStartParticle; i < nStartParticle + nActualParticlesToEmit; i++ )
  184. {
  185. float *pTimeStamp = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_CREATION_TIME, i );
  186. *pTimeStamp = flStartTime;
  187. }
  188. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  189. }
  190. //-----------------------------------------------------------------------------
  191. // Emits particles over time
  192. //-----------------------------------------------------------------------------
  193. struct ContinuousEmitterContext_t
  194. {
  195. float m_flTotalActualParticlesSoFar;
  196. int m_nTotalEmittedSoFar;
  197. float m_flNextEmitTime;
  198. float m_flTimeOffset;
  199. bool m_bStoppedEmission;
  200. };
  201. bool g_bDontMakeSkipToTimeTakeForever = false;
  202. class C_OP_ContinuousEmitter : public CParticleOperatorInstance
  203. {
  204. DECLARE_PARTICLE_OPERATOR( C_OP_ContinuousEmitter );
  205. uint32 GetWrittenAttributes( void ) const
  206. {
  207. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  208. }
  209. uint32 GetReadAttributes( void ) const
  210. {
  211. return 0;
  212. }
  213. virtual void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  214. {
  215. if ( m_flEmitRate < 0.0f )
  216. {
  217. m_flEmitRate = 0.0f;
  218. }
  219. if ( m_flEmissionDuration < 0.0f )
  220. {
  221. m_flEmissionDuration = 0.0f;
  222. }
  223. m_flEmitRate *= g_nParticle_Multiplier;
  224. }
  225. virtual uint32 Emit( CParticleCollection *pParticles, float flCurStrength,
  226. void *pContext ) const ;
  227. inline bool IsInfinitelyEmitting() const
  228. {
  229. return ( m_flEmissionDuration == 0.0f );
  230. }
  231. virtual void StopEmission( CParticleCollection *pParticles, void *pContext, bool bInfiniteOnly ) const
  232. {
  233. ContinuousEmitterContext_t *pCtx = reinterpret_cast<ContinuousEmitterContext_t *>( pContext );
  234. if ( !bInfiniteOnly || IsInfinitelyEmitting() )
  235. {
  236. pCtx->m_bStoppedEmission = true;
  237. }
  238. }
  239. virtual void StartEmission( CParticleCollection *pParticles, void *pContext, bool bInfiniteOnly ) const
  240. {
  241. ContinuousEmitterContext_t *pCtx = reinterpret_cast<ContinuousEmitterContext_t *>( pContext );
  242. if ( !bInfiniteOnly || IsInfinitelyEmitting() )
  243. {
  244. pCtx->m_bStoppedEmission = false;
  245. SkipToTime( pParticles->m_flCurTime, pParticles, pCtx );
  246. }
  247. }
  248. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  249. {
  250. ContinuousEmitterContext_t *pCtx = reinterpret_cast<ContinuousEmitterContext_t *>( pContext );
  251. pCtx->m_flNextEmitTime = m_flStartTime;
  252. pCtx->m_flTotalActualParticlesSoFar = 0.0f;
  253. pCtx->m_nTotalEmittedSoFar = 0;
  254. pCtx->m_flTimeOffset = 0.0f;
  255. pCtx->m_bStoppedEmission = false;
  256. }
  257. virtual void Restart( CParticleCollection *pParticles, void *pContext )
  258. {
  259. if ( !IsInfinitelyEmitting() )
  260. {
  261. ContinuousEmitterContext_t *pCtx = reinterpret_cast<ContinuousEmitterContext_t *>( pContext );
  262. pCtx->m_flNextEmitTime = pParticles->m_flCurTime + m_flStartTime;
  263. pCtx->m_flTotalActualParticlesSoFar = 0.0f;
  264. pCtx->m_nTotalEmittedSoFar = 0;
  265. pCtx->m_flTimeOffset = pParticles->m_flCurTime;
  266. }
  267. }
  268. // Called when the SFM wants to skip forward in time
  269. // Currently hacked for save/load pre-sim - correct solution is to serialize rather
  270. // than skip-to-time and simulate
  271. virtual void SkipToTime( float flTime, CParticleCollection *pParticles, void *pContext ) const
  272. {
  273. ContinuousEmitterContext_t *pCtx = reinterpret_cast<ContinuousEmitterContext_t *>( pContext );
  274. float flStartTime = m_flStartTime + pCtx->m_flTimeOffset;
  275. if ( flTime <= flStartTime )
  276. return;
  277. float flControlPointScale = pParticles->GetHighestControlPoint();
  278. flControlPointScale *= m_flEmissionScale;
  279. float flEmissionRate = m_flEmitRate;
  280. float flEmitStrength;
  281. if ( pParticles->CheckIfOperatorShouldRun( this, &flEmitStrength ) )
  282. {
  283. flEmissionRate *= flEmitStrength;
  284. }
  285. if ( flControlPointScale != 0.0f )
  286. {
  287. flEmissionRate *= flControlPointScale;
  288. }
  289. float flPrevDrawTime = pParticles->m_flCurTime - flTime;
  290. float flCurrDrawTime = pParticles->m_flCurTime;
  291. if ( !IsInfinitelyEmitting() )
  292. {
  293. if ( flPrevDrawTime < flStartTime )
  294. {
  295. flPrevDrawTime = flStartTime;
  296. }
  297. //if ( flCurrDrawTime > flStartTime + m_flEmissionDuration )
  298. //{
  299. // flCurrDrawTime = flStartTime + m_flEmissionDuration;
  300. //}
  301. }
  302. float flDeltaTime = flCurrDrawTime - flPrevDrawTime;
  303. flDeltaTime = min( flDeltaTime, 4.f );
  304. flPrevDrawTime = flCurrDrawTime - flDeltaTime;
  305. //disabled for now
  306. pCtx->m_flTotalActualParticlesSoFar = flDeltaTime * flEmissionRate;
  307. //if ( !IsInfinitelyEmitting() )
  308. // pCtx->m_flTotalActualParticlesSoFar = min( pCtx->m_ActualParticlesToEmit, pCtx->m_flTotalActualParticlesSoFar );
  309. pCtx->m_nTotalEmittedSoFar = 0;
  310. //simulate a bunch
  311. int nActualParticlesToEmit = floor (pCtx->m_flTotalActualParticlesSoFar);
  312. int nStartParticle = pParticles->m_nActiveParticles;
  313. if ( pParticles->m_nMaxAllowedParticles < nStartParticle + nActualParticlesToEmit )
  314. {
  315. nActualParticlesToEmit = pParticles->m_nMaxAllowedParticles - nStartParticle;
  316. }
  317. pParticles->SetNActiveParticles( nActualParticlesToEmit + pParticles->m_nActiveParticles );
  318. float flTimeStampStep = ( flDeltaTime ) / ( nActualParticlesToEmit );
  319. float flTimeStep = flPrevDrawTime + flTimeStampStep;
  320. // Set the particle creation time to the exact sub-frame particle emission time
  321. // !! speed!! do sse init here
  322. for( int i = nStartParticle; i < nStartParticle + nActualParticlesToEmit; i++ )
  323. {
  324. float *pTimeStamp = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_CREATION_TIME, i );
  325. flTimeStep = min( flTimeStep, flCurrDrawTime );
  326. *pTimeStamp = flTimeStep;
  327. flTimeStep += flTimeStampStep;
  328. }
  329. if ( !g_bDontMakeSkipToTimeTakeForever )
  330. {
  331. flPrevDrawTime = max( flPrevDrawTime, flCurrDrawTime - pParticles->m_pDef->m_flNoDrawTimeToGoToSleep );
  332. pParticles->m_flCurTime = flPrevDrawTime;
  333. pParticles->m_fl4CurTime = ReplicateX4( flPrevDrawTime );
  334. for( float i = flPrevDrawTime; i < flCurrDrawTime; i += 0.1 )
  335. {
  336. pParticles->Simulate( .1, false );
  337. }
  338. }
  339. }
  340. size_t GetRequiredContextBytes( void ) const
  341. {
  342. return sizeof( ContinuousEmitterContext_t );
  343. }
  344. virtual bool MayCreateMoreParticles( CParticleCollection *pParticles, void *pContext ) const
  345. {
  346. ContinuousEmitterContext_t *pCtx = reinterpret_cast<ContinuousEmitterContext_t *>( pContext );
  347. if ( pCtx->m_bStoppedEmission )
  348. return false;
  349. if ( m_flEmitRate <= 0.0f )
  350. return false;
  351. float flStartTime = m_flStartTime + pCtx->m_flTimeOffset;
  352. if ( m_flEmissionDuration != 0.0f && ( pParticles->m_flCurTime - pParticles->m_flDt ) > ( flStartTime + m_flEmissionDuration ) )
  353. return false;
  354. return true;
  355. }
  356. float m_flEmissionDuration;
  357. float m_flStartTime;
  358. float m_flEmitRate;
  359. float m_flTimePerEmission;
  360. float m_flEmissionScale;
  361. bool m_bScalePerParticle;
  362. };
  363. DEFINE_PARTICLE_OPERATOR( C_OP_ContinuousEmitter, "emit_continuously", OPERATOR_GENERIC );
  364. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_ContinuousEmitter )
  365. DMXELEMENT_UNPACK_FIELD( "emission_start_time", "0", float, m_flStartTime )
  366. DMXELEMENT_UNPACK_FIELD( "emission_rate", "100", float, m_flEmitRate )
  367. DMXELEMENT_UNPACK_FIELD( "emission_duration", "0", float, m_flEmissionDuration )
  368. DMXELEMENT_UNPACK_FIELD( "scale emission to used control points", "0.0", float, m_flEmissionScale )
  369. DMXELEMENT_UNPACK_FIELD( "use parent particles for emission scaling", "0", bool, m_bScalePerParticle )
  370. END_PARTICLE_OPERATOR_UNPACK( C_OP_ContinuousEmitter )
  371. uint32 C_OP_ContinuousEmitter::Emit( CParticleCollection *pParticles, float flCurStrength,
  372. void *pContext ) const
  373. {
  374. // Have we emitted all the particles we're going to emit?
  375. // NOTE: Using C_OP_ContinuousEmitter:: avoids a virtual function call
  376. ContinuousEmitterContext_t *pCtx = reinterpret_cast<ContinuousEmitterContext_t *>( pContext );
  377. //Allows for dynamic scaling via changes in number of control points.
  378. float flControlPointScale = pParticles->GetHighestControlPoint();
  379. //The emission scale here allows for a scalar value per controlpoint, like 2 or .25...
  380. flControlPointScale *= m_flEmissionScale;
  381. //Global strength scale brought in by operator fade in/fade out/oscillate
  382. float flEmissionRate = m_flEmitRate * flCurStrength;
  383. if ( flControlPointScale != 0.0f || m_bScalePerParticle )
  384. {
  385. if ( m_bScalePerParticle )
  386. {
  387. if ( pParticles->m_pParent )
  388. {
  389. flControlPointScale = pParticles->m_pParent->m_nActiveParticles * m_flEmissionScale;
  390. }
  391. else
  392. {
  393. flControlPointScale = m_flEmissionScale;
  394. }
  395. }
  396. flEmissionRate *= flControlPointScale;
  397. }
  398. if ( flEmissionRate == 0.0f )
  399. return 0;
  400. if ( !C_OP_ContinuousEmitter::MayCreateMoreParticles( pParticles, pContext ) )
  401. return 0;
  402. float flStartTime = m_flStartTime + pCtx->m_flTimeOffset;
  403. if ( pParticles->m_flCurTime < flStartTime )
  404. return 0;
  405. Assert( flEmissionRate != 0.0f );
  406. // determine our previous and current draw times and clamp them to start time and emission duration
  407. float flPrevDrawTime = pParticles->m_flCurTime - pParticles->m_flDt;
  408. float flCurrDrawTime = pParticles->m_flCurTime;
  409. if ( !IsInfinitelyEmitting() )
  410. {
  411. if ( flPrevDrawTime < flStartTime )
  412. {
  413. flPrevDrawTime = flStartTime;
  414. }
  415. if ( flCurrDrawTime > flStartTime + m_flEmissionDuration )
  416. {
  417. flCurrDrawTime = flStartTime + m_flEmissionDuration;
  418. }
  419. }
  420. float flDeltaTime = flCurrDrawTime - flPrevDrawTime;
  421. //Calculate emission rate by delta time from last frame to determine number of particles to emit this frame as a fractional float
  422. float flActualParticlesToEmit = flEmissionRate * flDeltaTime;
  423. //Add emitted particle to float counter to allow for fractional emission
  424. pCtx->m_flTotalActualParticlesSoFar += flActualParticlesToEmit;
  425. //Floor float accumulated value and subtract whole int emitted so far from the result to determine total whole particles to emit this frame
  426. int nParticlesToEmit = floor ( pCtx->m_flTotalActualParticlesSoFar ) - pCtx->m_nTotalEmittedSoFar;
  427. //Add emitted particles to running int total.
  428. pCtx->m_nTotalEmittedSoFar += nParticlesToEmit;
  429. if ( nParticlesToEmit == 0 )
  430. return 0;
  431. // We're only allowed to emit so many particles, though..
  432. // If we run out of room, only emit the last N particles
  433. int nActualParticlesToEmit = nParticlesToEmit;
  434. int nAllowedParticlesToEmit = pParticles->m_nMaxAllowedParticles - pParticles->m_nActiveParticles;
  435. if ( nAllowedParticlesToEmit < nParticlesToEmit )
  436. {
  437. nActualParticlesToEmit = nAllowedParticlesToEmit;
  438. //flStartEmissionTime = pCtx->m_flNextEmitTime - flTimePerEmission * nActualParticlesToEmit;
  439. }
  440. if ( nActualParticlesToEmit == 0 )
  441. return 0;
  442. int nStartParticle = pParticles->m_nActiveParticles;
  443. pParticles->SetNActiveParticles( nActualParticlesToEmit + pParticles->m_nActiveParticles );
  444. float flTimeStampStep = ( flDeltaTime ) / ( nActualParticlesToEmit );
  445. float flTimeStep = flPrevDrawTime + flTimeStampStep;
  446. // Set the particle creation time to the exact sub-frame particle emission time
  447. // !! speed!! do sse init here
  448. for( int i = nStartParticle; i < nStartParticle + nActualParticlesToEmit; i++ )
  449. {
  450. float *pTimeStamp = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_CREATION_TIME, i );
  451. flTimeStep = min( flTimeStep, flCurrDrawTime );
  452. *pTimeStamp = flTimeStep;
  453. flTimeStep += flTimeStampStep;
  454. }
  455. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  456. }
  457. //-----------------------------------------------------------------------------
  458. // Noise Emitter
  459. //-----------------------------------------------------------------------------
  460. struct NoiseEmitterContext_t
  461. {
  462. float m_flTotalActualParticlesSoFar;
  463. int m_nTotalEmittedSoFar;
  464. float m_flNextEmitTime;
  465. float m_flTimeOffset;
  466. bool m_bStoppedEmission;
  467. };
  468. class C_OP_NoiseEmitter : public CParticleOperatorInstance
  469. {
  470. DECLARE_PARTICLE_OPERATOR( C_OP_NoiseEmitter );
  471. uint32 GetWrittenAttributes( void ) const
  472. {
  473. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  474. }
  475. uint32 GetReadAttributes( void ) const
  476. {
  477. return 0;
  478. }
  479. virtual void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  480. {
  481. if ( m_flEmitRate < 0.0f )
  482. {
  483. m_flEmitRate = 0.0f;
  484. }
  485. if ( m_flEmissionDuration < 0.0f )
  486. {
  487. m_flEmissionDuration = 0.0f;
  488. }
  489. m_flEmitRate *= g_nParticle_Multiplier;
  490. }
  491. virtual uint32 Emit( CParticleCollection *pParticles, float flCurStrength,
  492. void *pContext ) const ;
  493. inline bool IsInfinitelyEmitting() const
  494. {
  495. return ( m_flEmissionDuration == 0.0f );
  496. }
  497. virtual void StopEmission( CParticleCollection *pParticles, void *pContext, bool bInfiniteOnly ) const
  498. {
  499. NoiseEmitterContext_t *pCtx = reinterpret_cast<NoiseEmitterContext_t *>( pContext );
  500. if ( !bInfiniteOnly || IsInfinitelyEmitting() )
  501. {
  502. pCtx->m_bStoppedEmission = true;
  503. }
  504. }
  505. virtual void StartEmission( CParticleCollection *pParticles, void *pContext, bool bInfiniteOnly ) const
  506. {
  507. NoiseEmitterContext_t *pCtx = reinterpret_cast<NoiseEmitterContext_t *>( pContext );
  508. if ( !bInfiniteOnly || IsInfinitelyEmitting() )
  509. {
  510. pCtx->m_bStoppedEmission = false;
  511. SkipToTime( pParticles->m_flCurTime, pParticles, pCtx );
  512. }
  513. }
  514. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  515. {
  516. NoiseEmitterContext_t *pCtx = reinterpret_cast<NoiseEmitterContext_t *>( pContext );
  517. pCtx->m_flNextEmitTime = m_flStartTime;
  518. pCtx->m_flTotalActualParticlesSoFar = 1.0f;
  519. pCtx->m_nTotalEmittedSoFar = 0;
  520. pCtx->m_flTimeOffset = 0.0f;
  521. pCtx->m_bStoppedEmission = false;
  522. }
  523. virtual void Restart( CParticleCollection *pParticles, void *pContext )
  524. {
  525. if ( !IsInfinitelyEmitting() )
  526. {
  527. NoiseEmitterContext_t *pCtx = reinterpret_cast<NoiseEmitterContext_t *>( pContext );
  528. pCtx->m_flNextEmitTime = m_flStartTime + pParticles->m_flCurTime;
  529. pCtx->m_flTotalActualParticlesSoFar = 1.0f;
  530. pCtx->m_nTotalEmittedSoFar = 0;
  531. pCtx->m_flTimeOffset = pParticles->m_flCurTime;
  532. }
  533. }
  534. // Called when the SFM wants to skip forward in time
  535. virtual void SkipToTime( float flTime, CParticleCollection *pParticles, void *pContext ) const
  536. {
  537. NoiseEmitterContext_t *pCtx = reinterpret_cast<NoiseEmitterContext_t *>( pContext );
  538. float flStartTime = m_flStartTime + pCtx->m_flTimeOffset;
  539. if ( flTime <= flStartTime )
  540. return;
  541. float flControlPointScale = pParticles->GetHighestControlPoint();
  542. flControlPointScale *= m_flEmissionScale;
  543. float flEmissionRate = m_flEmitRate;
  544. float flEmitStrength;
  545. if ( pParticles->CheckIfOperatorShouldRun( this, &flEmitStrength ) )
  546. {
  547. flEmissionRate *= flEmitStrength;
  548. }
  549. if ( flControlPointScale != 0.0f )
  550. {
  551. flEmissionRate *= flControlPointScale;
  552. }
  553. pCtx->m_flTotalActualParticlesSoFar = ( pParticles->m_flCurTime - flStartTime ) * flEmissionRate + 1;
  554. //if ( !IsInfinitelyEmitting() )
  555. // pCtx->m_flTotalActualParticlesSoFar = min( pCtx->m_ActualParticlesToEmit, pCtx->m_flTotalActualParticlesSoFar );
  556. pCtx->m_nTotalEmittedSoFar = 0;
  557. }
  558. size_t GetRequiredContextBytes( void ) const
  559. {
  560. return sizeof( NoiseEmitterContext_t );
  561. }
  562. virtual bool MayCreateMoreParticles( CParticleCollection *pParticles, void *pContext ) const
  563. {
  564. NoiseEmitterContext_t *pCtx = reinterpret_cast<NoiseEmitterContext_t *>( pContext );
  565. if ( pCtx->m_bStoppedEmission )
  566. return false;
  567. if ( m_flEmitRate <= 0.0f )
  568. return false;
  569. float flStartTime = m_flStartTime + pCtx->m_flTimeOffset;
  570. if ( m_flEmissionDuration != 0.0f && ( pParticles->m_flCurTime - pParticles->m_flDt ) > ( flStartTime + m_flEmissionDuration ) )
  571. return false;
  572. return true;
  573. }
  574. float m_flEmissionDuration;
  575. float m_flStartTime;
  576. float m_flEmitRate;
  577. float m_flTimePerEmission;
  578. float m_flEmissionScale;
  579. bool m_bAbsVal, m_bAbsValInv;
  580. float m_flOffset;
  581. float m_flOutputMin;
  582. float m_flOutputMax;
  583. float m_flNoiseScale, m_flNoiseScaleLoc;
  584. Vector m_vecOffsetLoc;
  585. float m_flWorldTimeScale;
  586. };
  587. DEFINE_PARTICLE_OPERATOR( C_OP_NoiseEmitter, "emit noise", OPERATOR_GENERIC );
  588. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_NoiseEmitter )
  589. DMXELEMENT_UNPACK_FIELD( "emission_start_time", "0", float, m_flStartTime )
  590. DMXELEMENT_UNPACK_FIELD( "emission_duration", "0", float, m_flEmissionDuration )
  591. DMXELEMENT_UNPACK_FIELD( "scale emission to used control points", "0.0", float, m_flEmissionScale )
  592. DMXELEMENT_UNPACK_FIELD( "time noise coordinate scale","0.1",float,m_flNoiseScale)
  593. //DMXELEMENT_UNPACK_FIELD( "spatial noise coordinate scale","0.001",float,m_flNoiseScaleLoc)
  594. DMXELEMENT_UNPACK_FIELD( "time coordinate offset","0", float, m_flOffset )
  595. //DMXELEMENT_UNPACK_FIELD( "spatial coordinate offset","0 0 0", Vector, m_vecOffsetLoc )
  596. DMXELEMENT_UNPACK_FIELD( "absolute value","0", bool, m_bAbsVal )
  597. DMXELEMENT_UNPACK_FIELD( "invert absolute value","0", bool, m_bAbsValInv )
  598. DMXELEMENT_UNPACK_FIELD( "emission minimum","0", float, m_flOutputMin )
  599. DMXELEMENT_UNPACK_FIELD( "emission maximum","100", float, m_flOutputMax )
  600. DMXELEMENT_UNPACK_FIELD( "world time noise coordinate scale","0", float, m_flWorldTimeScale )
  601. END_PARTICLE_OPERATOR_UNPACK( C_OP_NoiseEmitter )
  602. uint32 C_OP_NoiseEmitter::Emit( CParticleCollection *pParticles, float flCurStrength,
  603. void *pContext ) const
  604. {
  605. // Have we emitted all the particles we're going to emit?
  606. // NOTE: Using C_OP_ContinuousEmitter:: avoids a virtual function call
  607. NoiseEmitterContext_t *pCtx = reinterpret_cast<NoiseEmitterContext_t *>( pContext );
  608. //Allows for dynamic scaling via changes in number of control points.
  609. float flControlPointScale = pParticles->GetHighestControlPoint();
  610. //The emission scale here allows for a scalar value per controlpoint, like 2 or .25...
  611. flControlPointScale *= m_flEmissionScale;
  612. float flAbsScale;
  613. int nAbsVal;
  614. nAbsVal = 0xffffffff;
  615. flAbsScale = 0.5;
  616. if ( m_bAbsVal )
  617. {
  618. nAbsVal = 0x7fffffff;
  619. flAbsScale = 1.0;
  620. }
  621. float fMin = m_flOutputMin;
  622. float fMax = m_flOutputMax;
  623. float CoordScale = m_flNoiseScale;
  624. //float CoordScaleLoc = m_flNoiseScaleLoc;
  625. float ValueScale, ValueBase;
  626. Vector Coord, CoordLoc, CoordWorldTime;
  627. //CoordLoc.x = pxyz[0];
  628. //CoordLoc.y = pxyz[4];
  629. //CoordLoc.z = pxyz[8];
  630. //CoordLoc += m_vecOffsetLoc;
  631. float Offset = m_flOffset;
  632. Coord = Vector ( (pParticles->m_flCurTime + Offset), (pParticles->m_flCurTime + Offset), (pParticles->m_flCurTime + Offset) );
  633. Coord *= CoordScale;
  634. //CoordLoc *= CoordScaleLoc;
  635. //Coord += CoordLoc;
  636. CoordWorldTime = Vector( (Plat_MSTime() * m_flWorldTimeScale), (Plat_MSTime() * m_flWorldTimeScale), (Plat_MSTime() * m_flWorldTimeScale) );
  637. Coord += CoordWorldTime;
  638. fltx4 flNoise128;
  639. FourVectors fvNoise;
  640. fvNoise.DuplicateVector( Coord );
  641. flNoise128 = NoiseSIMD( fvNoise );
  642. float flNoise = SubFloat( flNoise128, 0 );
  643. *( (int *) &flNoise) &= nAbsVal;
  644. ValueScale = ( flAbsScale *( fMax - fMin ) );
  645. ValueBase = ( fMin+ ( ( 1.0 - flAbsScale ) *( fMax - fMin ) ) );
  646. if ( m_bAbsValInv )
  647. {
  648. flNoise = 1.0 - flNoise;
  649. }
  650. float flInitialNoise = ( ValueBase + ( ValueScale * flNoise ) );
  651. flInitialNoise = clamp(flInitialNoise, 0.0f, (float) INT_MAX );
  652. //Global strength scale brought in by operator fade in/fade out/oscillate
  653. float flEmissionRate = flInitialNoise * flCurStrength;
  654. if ( flControlPointScale != 0.0f )
  655. {
  656. flEmissionRate *= flControlPointScale;
  657. }
  658. if ( flEmissionRate == 0.0f )
  659. return 0;
  660. if ( !C_OP_NoiseEmitter::MayCreateMoreParticles( pParticles, pContext ) )
  661. return 0;
  662. float flStartTime = m_flStartTime + pCtx->m_flTimeOffset;
  663. if ( pParticles->m_flCurTime < flStartTime )
  664. return 0;
  665. Assert( flEmissionRate != 0.0f );
  666. // determine our previous and current draw times and clamp them to start time and emission duration
  667. float flPrevDrawTime = pParticles->m_flCurTime - pParticles->m_flDt;
  668. float flCurrDrawTime = pParticles->m_flCurTime;
  669. if ( !IsInfinitelyEmitting() )
  670. {
  671. if ( flPrevDrawTime < flStartTime )
  672. {
  673. flPrevDrawTime = flStartTime;
  674. }
  675. if ( flCurrDrawTime > flStartTime + m_flEmissionDuration )
  676. {
  677. flCurrDrawTime = flStartTime + m_flEmissionDuration;
  678. }
  679. }
  680. float flDeltaTime = flCurrDrawTime - flPrevDrawTime;
  681. //Calculate emission rate by delta time from last frame to determine number of particles to emit this frame as a fractional float
  682. float flActualParticlesToEmit = flEmissionRate * flDeltaTime;
  683. //Add emitted particle to float counter to allow for fractional emission
  684. pCtx->m_flTotalActualParticlesSoFar += flActualParticlesToEmit;
  685. //Floor float accumulated value and subtract whole int emitted so far from the result to determine total whole particles to emit this frame
  686. int nParticlesToEmit = floor ( pCtx->m_flTotalActualParticlesSoFar ) - pCtx->m_nTotalEmittedSoFar;
  687. //Add emitted particles to running int total.
  688. pCtx->m_nTotalEmittedSoFar += nParticlesToEmit;
  689. if ( nParticlesToEmit == 0 )
  690. return 0;
  691. // We're only allowed to emit so many particles, though..
  692. // If we run out of room, only emit the last N particles
  693. int nActualParticlesToEmit = nParticlesToEmit;
  694. int nAllowedParticlesToEmit = pParticles->m_nMaxAllowedParticles - pParticles->m_nActiveParticles;
  695. if ( nAllowedParticlesToEmit < nParticlesToEmit )
  696. {
  697. nActualParticlesToEmit = nAllowedParticlesToEmit;
  698. //flStartEmissionTime = pCtx->m_flNextEmitTime - flTimePerEmission * nActualParticlesToEmit;
  699. }
  700. if ( nActualParticlesToEmit == 0 )
  701. return 0;
  702. int nStartParticle = pParticles->m_nActiveParticles;
  703. pParticles->SetNActiveParticles( nActualParticlesToEmit + pParticles->m_nActiveParticles );
  704. float flTimeStampStep = ( flCurrDrawTime - flPrevDrawTime ) / ( nActualParticlesToEmit );
  705. float flTimeStep = flPrevDrawTime + flTimeStampStep;
  706. // Set the particle creation time to the exact sub-frame particle emission time
  707. // !! speed!! do sse init here
  708. for( int i = nStartParticle; i < nStartParticle + nActualParticlesToEmit; i++ )
  709. {
  710. float *pTimeStamp = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_CREATION_TIME, i );
  711. flTimeStep = min( flTimeStep, flCurrDrawTime );
  712. *pTimeStamp = flTimeStep;
  713. flTimeStep += flTimeStampStep;
  714. }
  715. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  716. }
  717. void AddBuiltInParticleEmitters( void )
  718. {
  719. REGISTER_PARTICLE_OPERATOR( FUNCTION_EMITTER, C_OP_ContinuousEmitter );
  720. REGISTER_PARTICLE_OPERATOR( FUNCTION_EMITTER, C_OP_InstantaneousEmitter );
  721. REGISTER_PARTICLE_OPERATOR( FUNCTION_EMITTER, C_OP_NoiseEmitter );
  722. }