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.

9635 lines
320 KiB

  1. //===== Copyright (c) 1996-2006, 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 "tier2/renderutils.h"
  12. #include "tier1/UtlStringMap.h"
  13. #include "tier1/strtools.h"
  14. #include "studio.h"
  15. #include "bspflags.h"
  16. #include "tier0/vprof.h"
  17. // memdbgon must be the last include file in a .cpp file!!!
  18. #include "tier0/memdbgon.h"
  19. #if MEASURE_PARTICLE_PERF
  20. #if VPROF_LEVEL > 0
  21. #define START_OP float flOpStartTime = Plat_FloatTime(); VPROF_ENTER_SCOPE(pOp->GetDefinition()->GetName())
  22. #else
  23. #define START_OP float flOpStartTime = Plat_FloatTime();
  24. #endif
  25. #if VPROF_LEVEL > 0
  26. #define END_OP if ( 1 ) { \
  27. float flETime = Plat_FloatTime() - flOpStartTime; \
  28. IParticleOperatorDefinition *pDef = (IParticleOperatorDefinition *) pOp->GetDefinition(); \
  29. pDef->RecordExecutionTime( flETime ); \
  30. } \
  31. VPROF_EXIT_SCOPE()
  32. #else
  33. #define END_OP if ( 1 ) { \
  34. float flETime = Plat_FloatTime() - flOpStartTime; \
  35. IParticleOperatorDefinition *pDef = (IParticleOperatorDefinition *) pOp->GetDefinition(); \
  36. pDef->RecordExecutionTime( flETime ); \
  37. }
  38. #endif
  39. #else
  40. #define START_OP
  41. #define END_OP
  42. #endif
  43. //-----------------------------------------------------------------------------
  44. // Standard movement operator
  45. //-----------------------------------------------------------------------------
  46. class C_OP_BasicMovement : public CParticleOperatorInstance
  47. {
  48. DECLARE_PARTICLE_OPERATOR( C_OP_BasicMovement );
  49. uint32 GetWrittenAttributes( void ) const
  50. {
  51. return PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_XYZ_MASK;
  52. }
  53. uint32 GetReadAttributes( void ) const
  54. {
  55. return 0;
  56. }
  57. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  58. Vector m_Gravity;
  59. float m_fDrag;
  60. int m_nMaxConstraintPasses;
  61. };
  62. DEFINE_PARTICLE_OPERATOR( C_OP_BasicMovement, "Movement Basic", OPERATOR_GENERIC );
  63. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_BasicMovement )
  64. DMXELEMENT_UNPACK_FIELD( "gravity", "0 0 0", Vector, m_Gravity )
  65. DMXELEMENT_UNPACK_FIELD( "drag", "0", float, m_fDrag )
  66. DMXELEMENT_UNPACK_FIELD( "max constraint passes", "3", int, m_nMaxConstraintPasses )
  67. END_PARTICLE_OPERATOR_UNPACK( C_OP_BasicMovement )
  68. #define MAXIMUM_NUMBER_OF_CONSTRAINTS 100
  69. //#define CHECKALL 1
  70. #ifdef NDEBUG
  71. #define CHECKSYSTEM( p ) 0
  72. #else
  73. #ifdef CHECKALL
  74. static void CHECKSYSTEM( CParticleCollection *pParticles )
  75. {
  76. // Assert( pParticles->m_nActiveParticles <= pParticles->m_pDef->m_nMaxParticles );
  77. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  78. {
  79. const float *xyz = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_XYZ, i );
  80. const float *xyz_prev = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  81. Assert( IsFinite( xyz[0] ) );
  82. Assert( IsFinite( xyz[4] ) );
  83. Assert( IsFinite( xyz[8] ) );
  84. Assert( IsFinite( xyz_prev[0] ) );
  85. Assert( IsFinite( xyz_prev[4] ) );
  86. Assert( IsFinite( xyz_prev[8] ) );
  87. }
  88. }
  89. #else
  90. #define CHECKSYSTEM( p ) 0
  91. #endif
  92. #endif
  93. void C_OP_BasicMovement::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  94. {
  95. C4VAttributeWriteIterator prev_xyz( PARTICLE_ATTRIBUTE_PREV_XYZ, pParticles );
  96. C4VAttributeWriteIterator xyz( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  97. // fltx4 adj_dt = ReplicateX4( (1.0-m_fDrag) * ( pParticles->m_flDt / pParticles->m_flPreviousDt ) );
  98. fltx4 adj_dt = ReplicateX4( ( pParticles->m_flDt / pParticles->m_flPreviousDt ) * ExponentialDecay( ( 1.0f - fpmax(0.0, m_fDrag)), (1.0f / 30.0f), pParticles->m_flDt ) );
  99. size_t nForceStride=0;
  100. Vector acc = m_Gravity;
  101. fltx4 accFactorX = ReplicateX4( acc.x );
  102. fltx4 accFactorY = ReplicateX4( acc.y );
  103. fltx4 accFactorZ = ReplicateX4( acc.z );
  104. int nAccumulators = pParticles->m_pDef->m_ForceGenerators.Count();
  105. FourVectors PerParticleForceAccumulator[MAX_PARTICLES_IN_A_SYSTEM / 4]; // xbox fixme - memory
  106. FourVectors *pAccOut = PerParticleForceAccumulator;
  107. if (nAccumulators)
  108. {
  109. // we do have per particle force accumulators
  110. nForceStride = 1;
  111. int nblocks = pParticles->m_nPaddedActiveParticles;
  112. for(int i=0;i<nblocks;i++)
  113. {
  114. pAccOut->x = accFactorX;
  115. pAccOut->y = accFactorY;
  116. pAccOut->z = accFactorZ;
  117. pAccOut++;
  118. }
  119. // now, call all force accumulators
  120. for(int i=0;i < nAccumulators ; i++ )
  121. {
  122. float flStrength;
  123. CParticleOperatorInstance *pOp = pParticles->m_pDef->m_ForceGenerators[i];
  124. if ( pParticles->CheckIfOperatorShouldRun( pOp, &flStrength ))
  125. {
  126. START_OP;
  127. pParticles->m_pDef->m_ForceGenerators[i]->AddForces(
  128. PerParticleForceAccumulator,
  129. pParticles,
  130. nblocks,
  131. flStrength,
  132. pParticles->m_pOperatorContextData +
  133. pParticles->m_pDef->m_nForceGeneratorsCtxOffsets[i] );
  134. END_OP;
  135. }
  136. }
  137. }
  138. else
  139. {
  140. pAccOut->x = accFactorX;
  141. pAccOut->y = accFactorY;
  142. pAccOut->z = accFactorZ;
  143. // we just have gravity
  144. }
  145. CHECKSYSTEM( pParticles );
  146. fltx4 DtSquared = ReplicateX4( pParticles->m_flDt * pParticles->m_flDt );
  147. int ctr = pParticles->m_nPaddedActiveParticles;
  148. FourVectors *pAccIn = PerParticleForceAccumulator;
  149. do
  150. {
  151. fltx4 accFactorX = MulSIMD( pAccIn->x, DtSquared );
  152. fltx4 accFactorY = MulSIMD( pAccIn->y, DtSquared );
  153. fltx4 accFactorZ = MulSIMD( pAccIn->z, DtSquared );
  154. // we will write prev xyz, and swap prev and cur at the end
  155. prev_xyz->x = AddSIMD( xyz->x,
  156. AddSIMD( accFactorX, MulSIMD( adj_dt, SubSIMD( xyz->x, prev_xyz->x ) ) ) );
  157. prev_xyz->y = AddSIMD( xyz->y,
  158. AddSIMD( accFactorY, MulSIMD( adj_dt, SubSIMD( xyz->y, prev_xyz->y ) ) ) );
  159. prev_xyz->z = AddSIMD( xyz->z,
  160. AddSIMD( accFactorZ, MulSIMD( adj_dt, SubSIMD( xyz->z, prev_xyz->z ) ) ) );
  161. CHECKSYSTEM( pParticles );
  162. ++prev_xyz;
  163. ++xyz;
  164. pAccIn += nForceStride;
  165. } while (--ctr);
  166. CHECKSYSTEM( pParticles );
  167. pParticles->SwapPosAndPrevPos();
  168. // now, enforce constraints
  169. int nConstraints = pParticles->m_pDef->m_Constraints.Count();
  170. if ( nConstraints && pParticles->m_nPaddedActiveParticles )
  171. {
  172. bool bConstraintSatisfied[ MAXIMUM_NUMBER_OF_CONSTRAINTS ];
  173. bool bFinalConstraint[ MAXIMUM_NUMBER_OF_CONSTRAINTS ];
  174. for(int i=0;i<nConstraints; i++)
  175. {
  176. bFinalConstraint[i] = pParticles->m_pDef->m_Constraints[i]->IsFinalConstaint();
  177. bConstraintSatisfied[i] = false;
  178. pParticles->m_pDef->m_Constraints[i]->SetupConstraintPerFrameData(
  179. pParticles, pParticles->m_pOperatorContextData +
  180. pParticles->m_pDef->m_nConstraintsCtxOffsets[i] );
  181. }
  182. // constraints get to see their own per psystem per op random #s
  183. for(int p=0; p < m_nMaxConstraintPasses ; p++ )
  184. {
  185. // int nSaveOffset=pParticles->m_nOperatorRandomSampleOffset;
  186. for(int i=0;i<nConstraints; i++)
  187. {
  188. // pParticles->m_nOperatorRandomSampleOffset += 23;
  189. if ( ! bConstraintSatisfied[i] )
  190. {
  191. CParticleOperatorInstance *pOp = pParticles->m_pDef->m_Constraints[i];
  192. bConstraintSatisfied[i] = true;
  193. float flStrength;
  194. if ( ( !bFinalConstraint[i] ) && ( pParticles->CheckIfOperatorShouldRun( pOp, &flStrength ) ) )
  195. {
  196. START_OP;
  197. bool bDidSomething = pOp->EnforceConstraint(
  198. 0, pParticles->m_nPaddedActiveParticles, pParticles,
  199. pParticles->m_pOperatorContextData +
  200. pParticles->m_pDef->m_nConstraintsCtxOffsets[i],
  201. pParticles->m_nActiveParticles );
  202. END_OP;
  203. CHECKSYSTEM( pParticles );
  204. if ( bDidSomething )
  205. {
  206. // other constraints now not satisfied, maybe
  207. for( int j=0; j<nConstraints; j++)
  208. {
  209. if ( i != j )
  210. {
  211. bConstraintSatisfied[ j ] = false;
  212. }
  213. }
  214. }
  215. }
  216. }
  217. }
  218. // pParticles->m_nOperatorRandomSampleOffset = nSaveOffset;
  219. }
  220. // now, run final constraints
  221. for(int i=0;i<nConstraints; i++)
  222. {
  223. CParticleOperatorInstance *pOp = pParticles->m_pDef->m_Constraints[i];
  224. float flStrength;
  225. if ( ( bFinalConstraint[i] ) &&
  226. ( pParticles->CheckIfOperatorShouldRun( pOp, &flStrength ) ) )
  227. {
  228. START_OP;
  229. pOp->EnforceConstraint(
  230. 0, pParticles->m_nPaddedActiveParticles, pParticles,
  231. pParticles->m_pOperatorContextData +
  232. pParticles->m_pDef->m_nConstraintsCtxOffsets[i],
  233. pParticles->m_nActiveParticles );
  234. END_OP;
  235. CHECKSYSTEM( pParticles );
  236. }
  237. }
  238. }
  239. CHECKSYSTEM( pParticles );
  240. }
  241. //-----------------------------------------------------------------------------
  242. // Fade and kill operator
  243. //-----------------------------------------------------------------------------
  244. class C_OP_FadeAndKill : public CParticleOperatorInstance
  245. {
  246. DECLARE_PARTICLE_OPERATOR( C_OP_FadeAndKill );
  247. uint32 GetWrittenAttributes( void ) const
  248. {
  249. return PARTICLE_ATTRIBUTE_ALPHA_MASK;
  250. }
  251. uint32 GetReadAttributes( void ) const
  252. {
  253. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK;
  254. }
  255. uint32 GetReadInitialAttributes( void ) const
  256. {
  257. return PARTICLE_ATTRIBUTE_ALPHA_MASK;
  258. }
  259. uint32 GetFilter( void ) const
  260. {
  261. return FILTER_LIFE_DURATION_MASK | FILTER_COLOR_AND_OPACITY_MASK;
  262. }
  263. virtual void InitParams( CParticleSystemDefinition *pDef );
  264. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  265. float m_flStartFadeInTime;
  266. float m_flEndFadeInTime;
  267. float m_flStartFadeOutTime;
  268. float m_flEndFadeOutTime;
  269. float m_flStartAlpha;
  270. float m_flEndAlpha;
  271. };
  272. DEFINE_PARTICLE_OPERATOR( C_OP_FadeAndKill, "Alpha Fade and Decay", OPERATOR_GENERIC );
  273. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_FadeAndKill )
  274. DMXELEMENT_UNPACK_FIELD( "start_alpha","1", float, m_flStartAlpha )
  275. DMXELEMENT_UNPACK_FIELD( "end_alpha","0", float, m_flEndAlpha )
  276. DMXELEMENT_UNPACK_FIELD( "start_fade_in_time","0", float, m_flStartFadeInTime )
  277. DMXELEMENT_UNPACK_FIELD( "end_fade_in_time","0.5", float, m_flEndFadeInTime )
  278. DMXELEMENT_UNPACK_FIELD( "start_fade_out_time","0.5", float, m_flStartFadeOutTime )
  279. DMXELEMENT_UNPACK_FIELD( "end_fade_out_time","1", float, m_flEndFadeOutTime )
  280. END_PARTICLE_OPERATOR_UNPACK( C_OP_FadeAndKill )
  281. void C_OP_FadeAndKill::InitParams( CParticleSystemDefinition *pDef )
  282. {
  283. // Cache off and validate values
  284. if ( m_flEndFadeInTime < m_flStartFadeInTime )
  285. {
  286. m_flEndFadeInTime = m_flStartFadeInTime;
  287. }
  288. if ( m_flEndFadeOutTime < m_flStartFadeOutTime )
  289. {
  290. m_flEndFadeOutTime = m_flStartFadeOutTime;
  291. }
  292. if ( m_flStartFadeOutTime < m_flStartFadeInTime )
  293. {
  294. V_swap( m_flStartFadeInTime, m_flStartFadeOutTime );
  295. }
  296. if ( m_flEndFadeOutTime < m_flEndFadeInTime )
  297. {
  298. V_swap( m_flEndFadeInTime, m_flEndFadeOutTime );
  299. }
  300. }
  301. void C_OP_FadeAndKill::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  302. {
  303. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  304. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  305. CM128InitialAttributeIterator pInitialAlpha( PARTICLE_ATTRIBUTE_ALPHA, pParticles );
  306. CM128AttributeWriteIterator pAlpha( PARTICLE_ATTRIBUTE_ALPHA, pParticles );
  307. fltx4 fl4StartFadeInTime = ReplicateX4( m_flStartFadeInTime );
  308. fltx4 fl4StartFadeOutTime = ReplicateX4( m_flStartFadeOutTime );
  309. fltx4 fl4EndFadeInTime = ReplicateX4( m_flEndFadeInTime );
  310. fltx4 fl4EndFadeOutTime = ReplicateX4( m_flEndFadeOutTime );
  311. fltx4 fl4EndAlpha = ReplicateX4( m_flEndAlpha );
  312. fltx4 fl4StartAlpha = ReplicateX4( m_flStartAlpha );
  313. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  314. int nLimit = pParticles->m_nPaddedActiveParticles << 2;
  315. fltx4 fl4FadeInDuration = ReplicateX4( m_flEndFadeInTime - m_flStartFadeInTime );
  316. fltx4 fl4OOFadeInDuration = ReciprocalEstSIMD( fl4FadeInDuration );
  317. fltx4 fl4FadeOutDuration = ReplicateX4( m_flEndFadeOutTime - m_flStartFadeOutTime );
  318. fltx4 fl4OOFadeOutDuration = ReciprocalEstSIMD( fl4FadeOutDuration );
  319. for ( int i = 0; i < nLimit; i+= 4 )
  320. {
  321. fltx4 fl4Age = SubSIMD( fl4CurTime, *pCreationTime );
  322. fltx4 fl4ParticleLifeTime = *pLifeDuration;
  323. bi32x4 fl4KillMask = CmpGeSIMD( fl4Age, *pLifeDuration ); // takes care of lifeduration = 0 div 0
  324. fl4Age = MulSIMD( fl4Age, ReciprocalEstSIMD( fl4ParticleLifeTime ) ); // age 0..1
  325. bi32x4 fl4FadingInMask = AndNotSIMD( fl4KillMask,
  326. AndSIMD(
  327. CmpLeSIMD( fl4StartFadeInTime, fl4Age ), CmpGtSIMD(fl4EndFadeInTime, fl4Age ) ) );
  328. bi32x4 fl4FadingOutMask = AndNotSIMD( fl4KillMask,
  329. AndSIMD(
  330. CmpLeSIMD( fl4StartFadeOutTime, fl4Age ), CmpGtSIMD(fl4EndFadeOutTime, fl4Age ) ) );
  331. if ( IsAnyTrue( fl4FadingInMask ) )
  332. {
  333. fltx4 fl4Goal = MulSIMD( *pInitialAlpha, fl4StartAlpha );
  334. fltx4 fl4NewAlpha = SimpleSplineRemapValWithDeltasClamped( fl4Age, fl4StartFadeInTime, fl4FadeInDuration, fl4OOFadeInDuration,
  335. fl4Goal, SubSIMD( *pInitialAlpha, fl4Goal ) );
  336. *pAlpha = MaskedAssign( fl4FadingInMask, fl4NewAlpha, *pAlpha );
  337. }
  338. if ( IsAnyTrue( fl4FadingOutMask ) )
  339. {
  340. fltx4 fl4Goal = MulSIMD( *pInitialAlpha, fl4EndAlpha );
  341. fltx4 fl4NewAlpha = SimpleSplineRemapValWithDeltasClamped( fl4Age, fl4StartFadeOutTime, fl4FadeOutDuration, fl4OOFadeOutDuration,
  342. *pInitialAlpha, SubSIMD( fl4Goal, *pInitialAlpha ) );
  343. *pAlpha = MaskedAssign( fl4FadingOutMask, fl4NewAlpha, *pAlpha );
  344. }
  345. if ( IsAnyTrue( fl4KillMask ) )
  346. {
  347. int nMask = TestSignSIMD( fl4KillMask );
  348. if ( nMask & 1 )
  349. pParticles->KillParticle( i );
  350. if ( nMask & 2 )
  351. pParticles->KillParticle( i + 1 );
  352. if ( nMask & 4 )
  353. pParticles->KillParticle( i + 2 );
  354. if ( nMask & 8 )
  355. pParticles->KillParticle( i + 3 );
  356. }
  357. ++pCreationTime;
  358. ++pLifeDuration;
  359. ++pInitialAlpha;
  360. ++pAlpha;
  361. }
  362. }
  363. //-----------------------------------------------------------------------------
  364. // Fade and kill operator for tracers.
  365. //
  366. // Before killing a particle, this operator will interpolate the last
  367. // frame's data so that the particle reaches its end point before
  368. // disappearing.
  369. //-----------------------------------------------------------------------------
  370. class C_OP_FadeAndKillForTracers : public CParticleOperatorInstance
  371. {
  372. DECLARE_PARTICLE_OPERATOR( C_OP_FadeAndKillForTracers );
  373. uint32 GetWrittenAttributes( void ) const
  374. {
  375. return PARTICLE_ATTRIBUTE_ALPHA_MASK | PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_TRAIL_LENGTH_MASK;
  376. }
  377. uint32 GetReadAttributes( void ) const
  378. {
  379. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK | PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_TRAIL_LENGTH_MASK;
  380. }
  381. uint32 GetReadInitialAttributes( void ) const
  382. {
  383. return PARTICLE_ATTRIBUTE_ALPHA_MASK;
  384. }
  385. uint32 GetFilter( void ) const
  386. {
  387. return FILTER_LIFE_DURATION_MASK | FILTER_COLOR_AND_OPACITY_MASK;
  388. }
  389. virtual void InitParams( CParticleSystemDefinition *pDef );
  390. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  391. float m_flStartFadeInTime;
  392. float m_flEndFadeInTime;
  393. float m_flStartFadeOutTime;
  394. float m_flEndFadeOutTime;
  395. float m_flStartAlpha;
  396. float m_flEndAlpha;
  397. };
  398. DEFINE_PARTICLE_OPERATOR( C_OP_FadeAndKillForTracers, "Alpha Fade and Decay for Tracers", OPERATOR_GENERIC );
  399. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_FadeAndKillForTracers )
  400. DMXELEMENT_UNPACK_FIELD( "start_alpha","1", float, m_flStartAlpha )
  401. DMXELEMENT_UNPACK_FIELD( "end_alpha","0", float, m_flEndAlpha )
  402. DMXELEMENT_UNPACK_FIELD( "start_fade_in_time","0", float, m_flStartFadeInTime )
  403. DMXELEMENT_UNPACK_FIELD( "end_fade_in_time","0.5", float, m_flEndFadeInTime )
  404. DMXELEMENT_UNPACK_FIELD( "start_fade_out_time","0.5", float, m_flStartFadeOutTime )
  405. DMXELEMENT_UNPACK_FIELD( "end_fade_out_time","1", float, m_flEndFadeOutTime )
  406. END_PARTICLE_OPERATOR_UNPACK( C_OP_FadeAndKillForTracers )
  407. void C_OP_FadeAndKillForTracers::InitParams( CParticleSystemDefinition *pDef )
  408. {
  409. // Cache off and validate values
  410. if ( m_flEndFadeInTime < m_flStartFadeInTime )
  411. {
  412. m_flEndFadeInTime = m_flStartFadeInTime;
  413. }
  414. if ( m_flEndFadeOutTime < m_flStartFadeOutTime )
  415. {
  416. m_flEndFadeOutTime = m_flStartFadeOutTime;
  417. }
  418. if ( m_flStartFadeOutTime < m_flStartFadeInTime )
  419. {
  420. V_swap( m_flStartFadeInTime, m_flStartFadeOutTime );
  421. }
  422. if ( m_flEndFadeOutTime < m_flEndFadeInTime )
  423. {
  424. V_swap( m_flEndFadeInTime, m_flEndFadeOutTime );
  425. }
  426. }
  427. void C_OP_FadeAndKillForTracers::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  428. {
  429. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  430. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  431. CM128InitialAttributeIterator pInitialAlpha( PARTICLE_ATTRIBUTE_ALPHA, pParticles );
  432. CM128AttributeWriteIterator pAlpha( PARTICLE_ATTRIBUTE_ALPHA, pParticles );
  433. fltx4 fl4StartFadeInTime = ReplicateX4( m_flStartFadeInTime );
  434. fltx4 fl4StartFadeOutTime = ReplicateX4( m_flStartFadeOutTime );
  435. fltx4 fl4EndFadeInTime = ReplicateX4( m_flEndFadeInTime );
  436. fltx4 fl4EndFadeOutTime = ReplicateX4( m_flEndFadeOutTime );
  437. fltx4 fl4EndAlpha = ReplicateX4( m_flEndAlpha );
  438. fltx4 fl4StartAlpha = ReplicateX4( m_flStartAlpha );
  439. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  440. int nLimit = pParticles->m_nPaddedActiveParticles << 2;
  441. fltx4 fl4FadeInDuration = ReplicateX4( m_flEndFadeInTime - m_flStartFadeInTime );
  442. fltx4 fl4OOFadeInDuration = ReciprocalEstSIMD( fl4FadeInDuration );
  443. fltx4 fl4FadeOutDuration = ReplicateX4( m_flEndFadeOutTime - m_flStartFadeOutTime );
  444. fltx4 fl4OOFadeOutDuration = ReciprocalEstSIMD( fl4FadeOutDuration );
  445. for ( int i = 0; i < nLimit; i+= 4 )
  446. {
  447. fltx4 fl4Age = SubSIMD( fl4CurTime, *pCreationTime );
  448. fltx4 fl4ParticleLifeTime = *pLifeDuration;
  449. bi32x4 fl4KillMask = CmpGeSIMD( fl4Age, *pLifeDuration ); // takes care of lifeduration = 0 div 0
  450. fl4Age = MulSIMD( fl4Age, ReciprocalEstSIMD( fl4ParticleLifeTime ) ); // age 0..1
  451. bi32x4 fl4FadingInMask = AndNotSIMD( fl4KillMask,
  452. AndSIMD(
  453. CmpLeSIMD( fl4StartFadeInTime, fl4Age ), CmpGtSIMD(fl4EndFadeInTime, fl4Age ) ) );
  454. bi32x4 fl4FadingOutMask = AndNotSIMD( fl4KillMask,
  455. AndSIMD(
  456. CmpLeSIMD( fl4StartFadeOutTime, fl4Age ), CmpGtSIMD(fl4EndFadeOutTime, fl4Age ) ) );
  457. if ( IsAnyTrue( fl4FadingInMask ) )
  458. {
  459. fltx4 fl4Goal = MulSIMD( *pInitialAlpha, fl4StartAlpha );
  460. fltx4 fl4NewAlpha = SimpleSplineRemapValWithDeltasClamped( fl4Age, fl4StartFadeInTime, fl4FadeInDuration, fl4OOFadeInDuration,
  461. fl4Goal, SubSIMD( *pInitialAlpha, fl4Goal ) );
  462. *pAlpha = MaskedAssign( fl4FadingInMask, fl4NewAlpha, *pAlpha );
  463. }
  464. if ( IsAnyTrue( fl4FadingOutMask ) )
  465. {
  466. fltx4 fl4Goal = MulSIMD( *pInitialAlpha, fl4EndAlpha );
  467. fltx4 fl4NewAlpha = SimpleSplineRemapValWithDeltasClamped( fl4Age, fl4StartFadeOutTime, fl4FadeOutDuration, fl4OOFadeOutDuration,
  468. *pInitialAlpha, SubSIMD( fl4Goal, *pInitialAlpha ) );
  469. *pAlpha = MaskedAssign( fl4FadingOutMask, fl4NewAlpha, *pAlpha );
  470. }
  471. if ( IsAnyTrue( fl4KillMask ) )
  472. {
  473. fltx4 fl4PreviousTime = ReplicateX4( pParticles->m_flCurTime - pParticles->m_flDt );
  474. fltx4 fl4PreviousAge = SubSIMD( fl4PreviousTime, *pCreationTime );
  475. bi32x4 fl4PreviousKillMask = CmpGeSIMD( fl4PreviousAge, *pLifeDuration );
  476. fltx4 fl4PartialDT = SubSIMD( *pLifeDuration, fl4PreviousAge );
  477. int nMask = TestSignSIMD( fl4KillMask );
  478. int nPreviousMask = TestSignSIMD( fl4PreviousKillMask );
  479. int nKillMask = nMask & nPreviousMask;
  480. bi32x4 fl4UpdateMask = AndSIMD( CmpLtSIMD( fl4PreviousAge, fl4ParticleLifeTime ), fl4KillMask );
  481. C4VAttributeIterator pPosition( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  482. C4VAttributeIterator pPreviousPosition( PARTICLE_ATTRIBUTE_PREV_XYZ, pParticles );
  483. fltx4 fl4FractionalTime = DivSIMD( fl4PartialDT, ReplicateX4( pParticles->m_flDt ) );
  484. FourVectors fvPosition = *pPosition;
  485. FourVectors fvPreviousPosition = *pPreviousPosition;
  486. FourVectors fvInterpolatedPosition = Madd( fvPosition - fvPreviousPosition, fl4FractionalTime, fvPreviousPosition );
  487. CM128AttributeIterator pTrailLength( PARTICLE_ATTRIBUTE_TRAIL_LENGTH, pParticles );
  488. fltx4 fl4OldTrailLength = *pTrailLength;
  489. fltx4 fl4TrailLength = MulSIMD( fl4FractionalTime, fl4OldTrailLength );
  490. C4VAttributeWriteIterator pWritePosition( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  491. CM128AttributeWriteIterator pWriteTrailLength( PARTICLE_ATTRIBUTE_TRAIL_LENGTH, pParticles );
  492. fvInterpolatedPosition = MaskedAssign( fl4UpdateMask, fvInterpolatedPosition, fvPosition );
  493. fl4TrailLength = MaskedAssign( fl4UpdateMask, fl4TrailLength, fl4OldTrailLength );
  494. *pWritePosition = fvInterpolatedPosition;
  495. *pWriteTrailLength = fl4TrailLength;
  496. if ( nKillMask & 1 )
  497. pParticles->KillParticle( i );
  498. if ( nKillMask & 2 )
  499. pParticles->KillParticle( i + 1 );
  500. if ( nKillMask & 4 )
  501. pParticles->KillParticle( i + 2 );
  502. if ( nKillMask & 8 )
  503. pParticles->KillParticle( i + 3 );
  504. }
  505. ++pCreationTime;
  506. ++pLifeDuration;
  507. ++pInitialAlpha;
  508. ++pAlpha;
  509. }
  510. }
  511. //-----------------------------------------------------------------------------
  512. // Fade In Operator
  513. //-----------------------------------------------------------------------------
  514. class C_OP_FadeIn : public CParticleOperatorInstance
  515. {
  516. DECLARE_PARTICLE_OPERATOR( C_OP_FadeIn );
  517. uint32 GetWrittenAttributes( void ) const
  518. {
  519. return PARTICLE_ATTRIBUTE_ALPHA_MASK;
  520. }
  521. uint32 GetReadAttributes( void ) const
  522. {
  523. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK | PARTICLE_ATTRIBUTE_PARTICLE_ID_MASK;
  524. }
  525. uint32 GetReadInitialAttributes( void ) const
  526. {
  527. return PARTICLE_ATTRIBUTE_ALPHA_MASK;
  528. }
  529. template<bool bRandom> FORCEINLINE void OperateInternal( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  530. template<bool bRandom, bool bProportional> FORCEINLINE void OperateInternal( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  531. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  532. float m_flFadeInTimeMin;
  533. float m_flFadeInTimeMax;
  534. float m_flFadeInTimeExp;
  535. bool m_bProportional;
  536. };
  537. DEFINE_PARTICLE_OPERATOR( C_OP_FadeIn, "Alpha Fade In Random", OPERATOR_GENERIC );
  538. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_FadeIn )
  539. DMXELEMENT_UNPACK_FIELD( "fade in time min",".25", float, m_flFadeInTimeMin )
  540. DMXELEMENT_UNPACK_FIELD( "fade in time max",".25", float, m_flFadeInTimeMax )
  541. DMXELEMENT_UNPACK_FIELD( "fade in time exponent","1", float, m_flFadeInTimeExp )
  542. DMXELEMENT_UNPACK_FIELD( "proportional 0/1","1", bool, m_bProportional )
  543. END_PARTICLE_OPERATOR_UNPACK( C_OP_FadeIn )
  544. template<bool bRandom, bool bProportional> FORCEINLINE void C_OP_FadeIn::OperateInternal( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  545. {
  546. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  547. CM128InitialAttributeIterator pInitialAlpha( PARTICLE_ATTRIBUTE_ALPHA, pParticles );
  548. CM128AttributeWriteIterator pAlpha( PARTICLE_ATTRIBUTE_ALPHA, pParticles );
  549. C4IAttributeIterator pParticleID( PARTICLE_ATTRIBUTE_PARTICLE_ID, pParticles );
  550. int nRandomOffset = pParticles->OperatorRandomSampleOffset();
  551. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  552. int nCtr = pParticles->m_nPaddedActiveParticles;
  553. fltx4 fl4FadeTimeMin = ReplicateX4( m_flFadeInTimeMin );
  554. int nSSEFixedExponent;
  555. fltx4 fl4FadeTimeWidth;
  556. CM128AttributeIterator pLifeDuration;
  557. if ( bRandom )
  558. {
  559. fl4FadeTimeWidth = ReplicateX4( m_flFadeInTimeMax - m_flFadeInTimeMin );
  560. nSSEFixedExponent = m_flFadeInTimeExp * 4.0;
  561. }
  562. if ( bProportional )
  563. {
  564. pLifeDuration.Init( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  565. }
  566. do
  567. {
  568. // Find particle age
  569. fltx4 fl4LifeTime = SubSIMD( fl4CurTime, *pCreationTime );
  570. fltx4 fl4FadeInTime;
  571. if ( bRandom )
  572. {
  573. fl4FadeInTime= Pow_FixedPoint_Exponent_SIMD(
  574. pParticles->RandomFloat( *pParticleID, nRandomOffset ),
  575. nSSEFixedExponent);
  576. fl4FadeInTime = AddSIMD( fl4FadeTimeMin, MulSIMD( fl4FadeTimeWidth, fl4FadeInTime ) );
  577. }
  578. else
  579. {
  580. fl4FadeInTime = fl4FadeTimeMin;
  581. }
  582. if ( bProportional )
  583. {
  584. // change particle age to a percentage of longevity
  585. fl4LifeTime =
  586. MaxSIMD( Four_Zeros,
  587. MinSIMD( Four_Ones,
  588. MulSIMD( fl4LifeTime, ReciprocalEstSIMD( *pLifeDuration ) ) ) );
  589. ++pLifeDuration;
  590. }
  591. bi32x4 fl4ApplyMask = CmpGtSIMD( fl4FadeInTime, fl4LifeTime );
  592. if ( IsAnyTrue( fl4ApplyMask ) )
  593. {
  594. // Fading in
  595. fltx4 fl4NewAlpha =
  596. SimpleSplineRemapValWithDeltasClamped(
  597. fl4LifeTime, Four_Zeros,
  598. fl4FadeInTime, ReciprocalEstSIMD( fl4FadeInTime ),
  599. Four_Zeros, *pInitialAlpha );
  600. *( pAlpha ) = MaskedAssign( fl4ApplyMask, fl4NewAlpha, *( pAlpha ) );
  601. }
  602. ++pCreationTime;
  603. ++pInitialAlpha;
  604. ++pAlpha;
  605. ++pParticleID;
  606. } while( --nCtr );
  607. }
  608. template<bool bRandom> FORCEINLINE void C_OP_FadeIn::OperateInternal( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  609. {
  610. if ( m_bProportional )
  611. {
  612. OperateInternal<bRandom, true>( pParticles, flStrength, pContext );
  613. }
  614. else
  615. {
  616. OperateInternal<bRandom, false>( pParticles, flStrength, pContext );
  617. }
  618. }
  619. void C_OP_FadeIn::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  620. {
  621. if ( m_flFadeInTimeMin != m_flFadeInTimeMax )
  622. {
  623. OperateInternal<true>( pParticles, flStrength, pContext );
  624. }
  625. else
  626. {
  627. OperateInternal<false>( pParticles, flStrength, pContext );
  628. }
  629. }
  630. //-----------------------------------------------------------------------------
  631. // Fade Out Operator
  632. //-----------------------------------------------------------------------------
  633. class C_OP_FadeOut : public CParticleOperatorInstance
  634. {
  635. DECLARE_PARTICLE_OPERATOR( C_OP_FadeOut );
  636. uint32 GetWrittenAttributes( void ) const
  637. {
  638. return PARTICLE_ATTRIBUTE_ALPHA_MASK;
  639. }
  640. uint32 GetReadAttributes( void ) const
  641. {
  642. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK | PARTICLE_ATTRIBUTE_PARTICLE_ID_MASK;
  643. }
  644. uint32 GetReadInitialAttributes( void ) const
  645. {
  646. return PARTICLE_ATTRIBUTE_ALPHA_MASK;
  647. }
  648. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  649. template<bool bRandomize, bool bProportional, bool bApplyBias> void OperateInternal( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  650. template<bool bRandomize> void OperateInternal( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  651. template<bool bRandomize, bool bProportional> void OperateInternal( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  652. void InitParams( CParticleSystemDefinition *pDef );
  653. float m_flFadeOutTimeMin;
  654. float m_flFadeOutTimeMax;
  655. float m_flFadeOutTimeExp;
  656. float m_flFadeBias;
  657. fltx4 m_fl4BiasParam;
  658. bool m_bProportional;
  659. bool m_bEaseInAndOut;
  660. bool m_bRandomize;
  661. typedef void ( C_OP_FadeOut::*OPERATE_FUNCTION )( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  662. OPERATE_FUNCTION m_pOpFunction;
  663. };
  664. DEFINE_PARTICLE_OPERATOR( C_OP_FadeOut, "Alpha Fade Out Random", OPERATOR_GENERIC );
  665. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_FadeOut )
  666. DMXELEMENT_UNPACK_FIELD( "fade out time min",".25", float, m_flFadeOutTimeMin )
  667. DMXELEMENT_UNPACK_FIELD( "fade out time max",".25", float, m_flFadeOutTimeMax )
  668. DMXELEMENT_UNPACK_FIELD( "fade out time exponent","1", float, m_flFadeOutTimeExp )
  669. DMXELEMENT_UNPACK_FIELD( "proportional 0/1","1", bool, m_bProportional )
  670. DMXELEMENT_UNPACK_FIELD( "ease in and out","1", bool, m_bEaseInAndOut )
  671. DMXELEMENT_UNPACK_FIELD( "fade bias", "0.5", float, m_flFadeBias )
  672. END_PARTICLE_OPERATOR_UNPACK( C_OP_FadeOut )
  673. template<bool bRandomize, bool bProportional, bool bApplyBias> void C_OP_FadeOut::OperateInternal( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  674. {
  675. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  676. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  677. CM128InitialAttributeIterator pInitialAlpha( PARTICLE_ATTRIBUTE_ALPHA, pParticles );
  678. CM128AttributeWriteIterator pAlpha( PARTICLE_ATTRIBUTE_ALPHA, pParticles );
  679. int nRandomOffset;
  680. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  681. int nCtr = pParticles->m_nPaddedActiveParticles;
  682. int nSSEFixedExponent;
  683. fltx4 FadeTimeMin = ReplicateX4( m_flFadeOutTimeMin );
  684. fltx4 FadeTimeWidth;
  685. fltx4 fl4FadeOutTime;
  686. C4IAttributeIterator pParticleID;
  687. if ( bRandomize )
  688. {
  689. FadeTimeWidth = ReplicateX4( m_flFadeOutTimeMax - m_flFadeOutTimeMin );
  690. nSSEFixedExponent = m_flFadeOutTimeExp*4.0;
  691. nRandomOffset = pParticles->OperatorRandomSampleOffset();
  692. pParticleID.Init( PARTICLE_ATTRIBUTE_PARTICLE_ID, pParticles );
  693. }
  694. else
  695. {
  696. if ( bProportional )
  697. {
  698. FadeTimeMin = SubSIMD( Four_Ones, FadeTimeMin );
  699. }
  700. }
  701. do
  702. {
  703. if ( bRandomize )
  704. {
  705. fl4FadeOutTime = Pow_FixedPoint_Exponent_SIMD(
  706. pParticles->RandomFloat( *pParticleID, nRandomOffset ),
  707. nSSEFixedExponent );
  708. fl4FadeOutTime = AddSIMD( FadeTimeMin, MulSIMD( FadeTimeWidth, fl4FadeOutTime ) );
  709. if ( bProportional )
  710. {
  711. fl4FadeOutTime = SubSIMD( Four_Ones, fl4FadeOutTime );
  712. }
  713. }
  714. else
  715. {
  716. fl4FadeOutTime = FadeTimeMin;
  717. }
  718. fltx4 fl4Lifespan;
  719. // Find our life percentage
  720. fltx4 fl4LifeTime = SubSIMD( fl4CurTime, *pCreationTime );
  721. fltx4 fl4LifeDuration = *pLifeDuration;
  722. if ( bProportional )
  723. {
  724. fl4LifeTime = MulSIMD( fl4LifeTime, ReciprocalEstSIMD( fl4LifeDuration ) );
  725. fl4Lifespan = SubSIMD ( Four_Ones, fl4FadeOutTime );
  726. }
  727. else
  728. {
  729. fl4FadeOutTime = SubSIMD( fl4LifeDuration, fl4FadeOutTime );
  730. fl4Lifespan = SubSIMD( fl4LifeDuration, fl4FadeOutTime ) ;
  731. }
  732. bi32x4 ApplyMask = CmpLtSIMD( fl4FadeOutTime, fl4LifeTime );
  733. if ( IsAnyTrue( ApplyMask ) )
  734. {
  735. // Fading out
  736. fltx4 NewAlpha;
  737. if ( m_bEaseInAndOut )
  738. {
  739. NewAlpha = SimpleSplineRemapValWithDeltasClamped(
  740. fl4LifeTime, fl4FadeOutTime,
  741. fl4Lifespan, ReciprocalEstSIMD( fl4Lifespan ),
  742. *pInitialAlpha, SubSIMD ( Four_Zeros, *pInitialAlpha ) );
  743. NewAlpha = MaxSIMD( Four_Zeros, NewAlpha );
  744. }
  745. else
  746. {
  747. fltx4 fl4Frac = MulSIMD( SubSIMD( fl4LifeTime, fl4FadeOutTime ), ReciprocalEstSIMD( fl4Lifespan ) );
  748. fl4Frac = MinSIMD( Four_Ones, MaxSIMD( Four_Zeros, fl4Frac ) );
  749. if ( bApplyBias )
  750. {
  751. fl4Frac = BiasSIMD( fl4Frac, m_fl4BiasParam );
  752. }
  753. fl4Frac = SubSIMD( Four_Ones, fl4Frac );
  754. NewAlpha = MulSIMD( *pInitialAlpha, fl4Frac );
  755. }
  756. *( pAlpha ) = MaskedAssign( ApplyMask, NewAlpha, *( pAlpha ) );
  757. }
  758. ++pCreationTime;
  759. ++pLifeDuration;
  760. ++pInitialAlpha;
  761. ++pAlpha;
  762. if ( bRandomize )
  763. {
  764. ++pParticleID;
  765. }
  766. } while( --nCtr );
  767. }
  768. template<bool bRandomize, bool bProportional> void C_OP_FadeOut::OperateInternal( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  769. {
  770. if ( m_flFadeBias == 0.5 )
  771. {
  772. OperateInternal<bRandomize, bProportional, false>( pParticles, flStrength, pContext );
  773. }
  774. else
  775. {
  776. OperateInternal<bRandomize, bProportional, true>( pParticles, flStrength, pContext );
  777. }
  778. }
  779. template<bool bRandomize> void C_OP_FadeOut::OperateInternal( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  780. {
  781. if ( m_bProportional )
  782. {
  783. OperateInternal< bRandomize, false>( pParticles, flStrength, pContext );
  784. }
  785. else
  786. {
  787. OperateInternal< bRandomize, false>( pParticles, flStrength, pContext );
  788. }
  789. }
  790. void C_OP_FadeOut::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  791. {
  792. ( this->*m_pOpFunction )( pParticles, flStrength, pContext );
  793. }
  794. void C_OP_FadeOut::InitParams( CParticleSystemDefinition *pDef )
  795. {
  796. float flBias = ( m_flFadeBias != 0.0f ) ? m_flFadeBias : 0.5f;
  797. m_fl4BiasParam = PreCalcBiasParameter( ReplicateX4( flBias ) );
  798. m_bRandomize = ( m_flFadeOutTimeMin != m_flFadeOutTimeMax );
  799. if ( m_bRandomize && ( m_flFadeOutTimeMin == 0.0f ) )
  800. {
  801. m_flFadeOutTimeMin = m_flFadeOutTimeMax = FLT_EPSILON;
  802. }
  803. // determine function ptr
  804. static OPERATE_FUNCTION s_pDispatchTable[8] = {
  805. &C_OP_FadeOut::OperateInternal< false, false, false >,
  806. &C_OP_FadeOut::OperateInternal< false, false, true >,
  807. &C_OP_FadeOut::OperateInternal< false, true, false >,
  808. &C_OP_FadeOut::OperateInternal< false, true, true >,
  809. &C_OP_FadeOut::OperateInternal< true, false, false >,
  810. &C_OP_FadeOut::OperateInternal< true, false, true >,
  811. &C_OP_FadeOut::OperateInternal< true, true, false >,
  812. &C_OP_FadeOut::OperateInternal< true, true, true > };
  813. int nIndex =
  814. 1 * ( ( m_flFadeBias == 0.5 ) ? 1 : 0 ) +
  815. 2 * ( m_bProportional ? 1 : 0 ) +
  816. 4 * ( m_bRandomize ? 1 : 0 );
  817. m_pOpFunction = s_pDispatchTable[nIndex];
  818. }
  819. //-----------------------------------------------------------------------------
  820. // Fade In Operator - fast version
  821. //-----------------------------------------------------------------------------
  822. class C_OP_FadeInSimple : public CParticleOperatorInstance
  823. {
  824. DECLARE_PARTICLE_OPERATOR( C_OP_FadeInSimple );
  825. uint32 GetWrittenAttributes( void ) const
  826. {
  827. return PARTICLE_ATTRIBUTE_ALPHA_MASK;
  828. }
  829. uint32 GetReadAttributes( void ) const
  830. {
  831. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK ;
  832. }
  833. uint32 GetReadInitialAttributes( void ) const
  834. {
  835. return PARTICLE_ATTRIBUTE_ALPHA_MASK;
  836. }
  837. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  838. float m_flFadeInTime;
  839. };
  840. DEFINE_PARTICLE_OPERATOR( C_OP_FadeInSimple, "Alpha Fade In Simple", OPERATOR_GENERIC );
  841. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_FadeInSimple )
  842. DMXELEMENT_UNPACK_FIELD( "proportional fade in time",".25", float, m_flFadeInTime )
  843. END_PARTICLE_OPERATOR_UNPACK( C_OP_FadeInSimple )
  844. void C_OP_FadeInSimple::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  845. {
  846. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  847. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  848. CM128InitialAttributeIterator pInitialAlpha( PARTICLE_ATTRIBUTE_ALPHA, pParticles );
  849. CM128AttributeWriteIterator pAlpha( PARTICLE_ATTRIBUTE_ALPHA, pParticles );
  850. fltx4 CurTime = pParticles->m_fl4CurTime;
  851. int nCtr = pParticles->m_nPaddedActiveParticles;
  852. fltx4 fl4FadeInTime = ReplicateX4( m_flFadeInTime );
  853. do
  854. {
  855. // Find our life percentage
  856. fltx4 fl4LifeTime = SubSIMD( CurTime, *pCreationTime );
  857. fl4LifeTime = MaxSIMD( Four_Zeros, MinSIMD( Four_Ones,
  858. MulSIMD( fl4LifeTime, ReciprocalEstSIMD( *pLifeDuration ) ) ) );
  859. bi32x4 ApplyMask = CmpGtSIMD( fl4FadeInTime, fl4LifeTime );
  860. if ( IsAnyTrue( ApplyMask ) )
  861. {
  862. // Fading in
  863. fltx4 NewAlpha =
  864. SimpleSplineRemapValWithDeltasClamped(
  865. fl4LifeTime, Four_Zeros,
  866. fl4FadeInTime, ReciprocalEstSIMD( fl4FadeInTime ),
  867. Four_Zeros, *pInitialAlpha );
  868. *( pAlpha ) = MaskedAssign( ApplyMask, NewAlpha, *( pAlpha ) );
  869. }
  870. ++pCreationTime;
  871. ++pLifeDuration;
  872. ++pInitialAlpha;
  873. ++pAlpha;
  874. } while( --nCtr );
  875. }
  876. //-----------------------------------------------------------------------------
  877. // Fade Out Operator - fast version
  878. //-----------------------------------------------------------------------------
  879. class C_OP_FadeOutSimple : public CParticleOperatorInstance
  880. {
  881. DECLARE_PARTICLE_OPERATOR( C_OP_FadeOut );
  882. uint32 GetWrittenAttributes( void ) const
  883. {
  884. return PARTICLE_ATTRIBUTE_ALPHA_MASK;
  885. }
  886. uint32 GetReadAttributes( void ) const
  887. {
  888. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK ;
  889. }
  890. uint32 GetReadInitialAttributes( void ) const
  891. {
  892. return PARTICLE_ATTRIBUTE_ALPHA_MASK;
  893. }
  894. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  895. float m_flFadeOutTime;
  896. };
  897. DEFINE_PARTICLE_OPERATOR( C_OP_FadeOutSimple, "Alpha Fade Out Simple", OPERATOR_GENERIC );
  898. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_FadeOutSimple )
  899. DMXELEMENT_UNPACK_FIELD( "proportional fade out time",".25", float, m_flFadeOutTime )
  900. END_PARTICLE_OPERATOR_UNPACK( C_OP_FadeOutSimple )
  901. void C_OP_FadeOutSimple::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  902. {
  903. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  904. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  905. CM128InitialAttributeIterator pInitialAlpha( PARTICLE_ATTRIBUTE_ALPHA, pParticles );
  906. CM128AttributeWriteIterator pAlpha( PARTICLE_ATTRIBUTE_ALPHA, pParticles );
  907. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  908. int nCtr = pParticles->m_nPaddedActiveParticles;
  909. fltx4 fl4FadeOutTime= ReplicateX4( 1.0f - m_flFadeOutTime );
  910. fltx4 fl4Fadespan = ReplicateX4( m_flFadeOutTime );
  911. do
  912. {
  913. // Find our life percentage
  914. fltx4 fl4LifeTime = SubSIMD( fl4CurTime, *pCreationTime );
  915. fltx4 fl4LifeDuration = *pLifeDuration;
  916. fl4LifeTime = MulSIMD( fl4LifeTime, ReciprocalEstSIMD( fl4LifeDuration ) );
  917. bi32x4 ApplyMask = CmpLtSIMD( fl4FadeOutTime, fl4LifeTime );
  918. if ( IsAnyTrue( ApplyMask ) )
  919. {
  920. // Fading out
  921. fltx4 NewAlpha;
  922. fltx4 fl4Frac = MulSIMD( SubSIMD( fl4LifeTime, fl4FadeOutTime ), ReciprocalEstSIMD( fl4Fadespan ) );
  923. fl4Frac = MinSIMD( Four_Ones, MaxSIMD( Four_Zeros, fl4Frac ) );
  924. fl4Frac = SimpleSpline( fl4Frac );
  925. fl4Frac = SubSIMD( Four_Ones, fl4Frac );
  926. NewAlpha = MulSIMD( *pInitialAlpha, fl4Frac );
  927. *pAlpha = MaskedAssign( ApplyMask, MinSIMD( NewAlpha, *pAlpha), *pAlpha );
  928. }
  929. ++pCreationTime;
  930. ++pLifeDuration;
  931. ++pInitialAlpha;
  932. ++pAlpha;
  933. } while( --nCtr );
  934. }
  935. //-----------------------------------------------------------------------------
  936. // Clamp Scalar Operator
  937. //-----------------------------------------------------------------------------
  938. class C_OP_ClampScalar : public CParticleOperatorInstance
  939. {
  940. DECLARE_PARTICLE_OPERATOR( C_OP_ClampScalar );
  941. uint32 GetWrittenAttributes( void ) const
  942. {
  943. return 1 << m_nFieldOutput;
  944. }
  945. uint32 GetReadAttributes( void ) const
  946. {
  947. return 0;
  948. }
  949. uint32 GetFilter( void ) const
  950. {
  951. return FILTER_PARAMETER_REMAPPING_MASK;
  952. }
  953. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  954. int m_nFieldOutput;
  955. float m_flOutputMin;
  956. float m_flOutputMax;
  957. };
  958. DEFINE_PARTICLE_OPERATOR( C_OP_ClampScalar, "Clamp Scalar", OPERATOR_GENERIC );
  959. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_ClampScalar )
  960. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "3", int, m_nFieldOutput, "intchoice particlefield_scalar" )
  961. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  962. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  963. END_PARTICLE_OPERATOR_UNPACK( C_OP_ClampScalar )
  964. void C_OP_ClampScalar::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  965. {
  966. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  967. {
  968. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, i );
  969. float flOutput = clamp( *pOutput, m_flOutputMin, m_flOutputMax );
  970. *pOutput = Lerp (flStrength, *pOutput, flOutput);
  971. }
  972. }
  973. //-----------------------------------------------------------------------------
  974. // Clamp Vector Operator
  975. //-----------------------------------------------------------------------------
  976. class C_OP_ClampVector : public CParticleOperatorInstance
  977. {
  978. DECLARE_PARTICLE_OPERATOR( C_OP_ClampVector );
  979. uint32 GetWrittenAttributes( void ) const
  980. {
  981. return 1 << m_nFieldOutput;
  982. }
  983. uint32 GetReadAttributes( void ) const
  984. {
  985. return 0;
  986. }
  987. uint32 GetFilter( void ) const
  988. {
  989. return FILTER_PARAMETER_REMAPPING_MASK;
  990. }
  991. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  992. int m_nFieldOutput;
  993. Vector m_vecOutputMin;
  994. Vector m_vecOutputMax;
  995. };
  996. DEFINE_PARTICLE_OPERATOR( C_OP_ClampVector, "Clamp Vector", OPERATOR_GENERIC );
  997. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_ClampVector )
  998. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "0", int, m_nFieldOutput, "intchoice particlefield_vector" )
  999. DMXELEMENT_UNPACK_FIELD( "output minimum","0 0 0", Vector, m_vecOutputMin )
  1000. DMXELEMENT_UNPACK_FIELD( "output maximum","1 1 1", Vector, m_vecOutputMax )
  1001. END_PARTICLE_OPERATOR_UNPACK( C_OP_ClampVector )
  1002. void C_OP_ClampVector::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  1003. {
  1004. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  1005. {
  1006. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, i );
  1007. Vector vecOutput, vecOrg;
  1008. SetVectorFromAttribute( vecOutput, pOutput);
  1009. vecOrg = vecOutput;
  1010. vecOutput.x = clamp( vecOutput.x, m_vecOutputMin.x, m_vecOutputMax.x );
  1011. vecOutput.y = clamp( vecOutput.y, m_vecOutputMin.y, m_vecOutputMax.y );
  1012. vecOutput.z = clamp( vecOutput.z, m_vecOutputMin.z, m_vecOutputMax.z );
  1013. vecOutput = VectorLerp( vecOrg, vecOutput, flStrength );
  1014. SetVectorAttribute( pOutput, vecOutput );
  1015. }
  1016. }
  1017. //-----------------------------------------------------------------------------
  1018. // Oscillating Scalar operator
  1019. // performs an oscillation operation on any scalar (fade, radius, etc.)
  1020. //-----------------------------------------------------------------------------
  1021. class C_OP_OscillateScalar : public CParticleOperatorInstance
  1022. {
  1023. DECLARE_PARTICLE_OPERATOR( C_OP_OscillateScalar );
  1024. uint32 GetWrittenAttributes( void ) const
  1025. {
  1026. return 1 << m_nField;
  1027. }
  1028. uint32 GetReadAttributes( void ) const
  1029. {
  1030. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK |
  1031. PARTICLE_ATTRIBUTE_PARTICLE_ID_MASK;
  1032. }
  1033. uint32 GetFilter( void ) const
  1034. {
  1035. return FILTER_PARAMETER_REMAPPING_MASK;
  1036. }
  1037. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  1038. float m_RateMin;
  1039. float m_RateMax;
  1040. float m_FrequencyMin;
  1041. float m_FrequencyMax;
  1042. int m_nField;
  1043. bool m_bProportional, m_bProportionalOp;
  1044. float m_flStartTime_min;
  1045. float m_flStartTime_max;
  1046. float m_flEndTime_min;
  1047. float m_flEndTime_max;
  1048. float m_flOscMult;
  1049. float m_flOscAdd;
  1050. };
  1051. DEFINE_PARTICLE_OPERATOR( C_OP_OscillateScalar, "Oscillate Scalar", OPERATOR_GENERIC );
  1052. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_OscillateScalar )
  1053. DMXELEMENT_UNPACK_FIELD_USERDATA( "oscillation field", "7", int, m_nField, "intchoice particlefield_scalar" )
  1054. DMXELEMENT_UNPACK_FIELD( "oscillation rate min", "0", float, m_RateMin )
  1055. DMXELEMENT_UNPACK_FIELD( "oscillation rate max", "0", float, m_RateMax )
  1056. DMXELEMENT_UNPACK_FIELD( "oscillation frequency min", "1", float, m_FrequencyMin )
  1057. DMXELEMENT_UNPACK_FIELD( "oscillation frequency max", "1", float, m_FrequencyMax )
  1058. DMXELEMENT_UNPACK_FIELD( "proportional 0/1", "1", bool, m_bProportional )
  1059. DMXELEMENT_UNPACK_FIELD( "start time min", "0", float, m_flStartTime_min )
  1060. DMXELEMENT_UNPACK_FIELD( "start time max", "0", float, m_flStartTime_max )
  1061. DMXELEMENT_UNPACK_FIELD( "end time min", "1", float, m_flEndTime_min )
  1062. DMXELEMENT_UNPACK_FIELD( "end time max", "1", float, m_flEndTime_max )
  1063. DMXELEMENT_UNPACK_FIELD( "start/end proportional", "1", bool, m_bProportionalOp )
  1064. DMXELEMENT_UNPACK_FIELD( "oscillation multiplier", "2", float, m_flOscMult )
  1065. DMXELEMENT_UNPACK_FIELD( "oscillation start phase", ".5", float, m_flOscAdd )
  1066. END_PARTICLE_OPERATOR_UNPACK( C_OP_OscillateScalar )
  1067. void C_OP_OscillateScalar::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  1068. {
  1069. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  1070. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  1071. C4IAttributeIterator pParticleId ( PARTICLE_ATTRIBUTE_PARTICLE_ID, pParticles );
  1072. CM128AttributeWriteIterator pOscField ( m_nField, pParticles) ;
  1073. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  1074. int nRandomOffset = pParticles->OperatorRandomSampleOffset();
  1075. fltx4 fl4OscVal;
  1076. fltx4 fl4ScaleFactor = ReplicateX4( flStrength * pParticles->m_flDt );
  1077. fltx4 fl4CosFactorMultiplier = ReplicateX4( m_flOscMult );
  1078. fltx4 fl4CosFactorAdd = ReplicateX4( m_flOscAdd );
  1079. fltx4 fl4CosFactor = AddSIMD( MulSIMD( fl4CosFactorMultiplier, fl4CurTime ), fl4CosFactorAdd );
  1080. fltx4 fl4CosFactorProp = fl4CosFactorMultiplier;
  1081. fltx4 fl4StartTimeMin = ReplicateX4( m_flStartTime_min );
  1082. fltx4 fl4StartTimeWidth = ReplicateX4( m_flStartTime_max - m_flStartTime_min );
  1083. fltx4 fl4EndTimeMin = ReplicateX4( m_flEndTime_min );
  1084. fltx4 fl4EndTimeWidth = ReplicateX4( m_flEndTime_max - m_flEndTime_min );
  1085. fltx4 fl4FrequencyMin = ReplicateX4( m_FrequencyMin );
  1086. fltx4 fl4FrequencyWidth = ReplicateX4( m_FrequencyMax - m_FrequencyMin );
  1087. fltx4 fl4RateMin = ReplicateX4( m_RateMin );
  1088. fltx4 fl4RateWidth = ReplicateX4( m_RateMax - m_RateMin );
  1089. int nCtr = pParticles->m_nPaddedActiveParticles;
  1090. do
  1091. {
  1092. fltx4 fl4LifeDuration = *pLifeDuration;
  1093. bi32x4 fl4GoodMask = CmpGtSIMD( fl4LifeDuration, Four_Zeros );
  1094. fltx4 fl4LifeTime;
  1095. if ( m_bProportionalOp )
  1096. {
  1097. fl4LifeTime = MulSIMD( SubSIMD( fl4CurTime, *pCreationTime ), ReciprocalEstSIMD( fl4LifeDuration ) ); // maybe need accurate div here?
  1098. }
  1099. else
  1100. {
  1101. fl4LifeTime = SubSIMD( fl4CurTime, *pCreationTime );
  1102. }
  1103. fltx4 fl4StartTime= pParticles->RandomFloat( *pParticleId, nRandomOffset + 11);
  1104. fl4StartTime = AddSIMD( fl4StartTimeMin, MulSIMD( fl4StartTimeWidth, fl4StartTime ) );
  1105. fltx4 fl4EndTime= pParticles->RandomFloat( *pParticleId, nRandomOffset + 12);
  1106. fl4EndTime = AddSIMD( fl4EndTimeMin, MulSIMD( fl4EndTimeWidth, fl4EndTime ) );
  1107. fl4GoodMask = AndSIMD( fl4GoodMask, CmpGeSIMD( fl4LifeTime, fl4StartTime ) );
  1108. fl4GoodMask = AndSIMD( fl4GoodMask, CmpLtSIMD( fl4LifeTime, fl4EndTime ) );
  1109. if ( IsAnyTrue( fl4GoodMask ) )
  1110. {
  1111. fltx4 fl4Frequency = pParticles->RandomFloat( *pParticleId, nRandomOffset );
  1112. fl4Frequency = AddSIMD( fl4FrequencyMin, MulSIMD( fl4FrequencyWidth, fl4Frequency ) );
  1113. fltx4 fl4Rate= pParticles->RandomFloat( *pParticleId, nRandomOffset + 1);
  1114. fl4Rate = AddSIMD( fl4RateMin, MulSIMD( fl4RateWidth, fl4Rate ) );
  1115. fltx4 fl4Cos;
  1116. if ( m_bProportional )
  1117. {
  1118. fl4LifeTime = MulSIMD( SubSIMD( fl4CurTime, *pCreationTime ), ReciprocalEstSIMD( fl4LifeDuration ) );
  1119. fl4Cos = AddSIMD( MulSIMD( fl4CosFactorProp, MulSIMD( fl4LifeTime, fl4Frequency )), fl4CosFactorAdd );
  1120. }
  1121. else
  1122. {
  1123. fl4Cos = MulSIMD( fl4CosFactor, fl4Frequency );
  1124. }
  1125. fltx4 fl4OscMultiplier = MulSIMD( fl4Rate, fl4ScaleFactor);
  1126. fl4OscVal = AddSIMD ( *pOscField, MulSIMD ( fl4OscMultiplier, SinEst01SIMD( fl4Cos ) ) );
  1127. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & ( 1 << m_nField ) )
  1128. {
  1129. *pOscField = MaskedAssign( fl4GoodMask,
  1130. MaxSIMD( MinSIMD( fl4OscVal, Four_Ones), Four_Zeros ), *pOscField );
  1131. }
  1132. else
  1133. {
  1134. *pOscField = MaskedAssign( fl4GoodMask, fl4OscVal, *pOscField );
  1135. }
  1136. }
  1137. ++pCreationTime;
  1138. ++pLifeDuration;
  1139. ++pOscField;
  1140. ++pParticleId;
  1141. } while (--nCtr );
  1142. };
  1143. //-----------------------------------------------------------------------------
  1144. // Oscillating Scalar Simple operator
  1145. // performs an oscillation operation on any scalar (fade, radius, etc.)
  1146. // Simple version is fast but has few options
  1147. //-----------------------------------------------------------------------------
  1148. class C_OP_OscillateScalarSimple : public CParticleOperatorInstance
  1149. {
  1150. DECLARE_PARTICLE_OPERATOR( C_OP_OscillateScalarSimple );
  1151. float m_Rate;
  1152. float m_Frequency;
  1153. int m_nField;
  1154. float m_flOscMult;
  1155. float m_flOscAdd;
  1156. fltx4 m_fl4MinCmp, m_fl4MaxCmp;
  1157. uint32 GetWrittenAttributes( void ) const
  1158. {
  1159. return 1 << m_nField;
  1160. }
  1161. uint32 GetReadAttributes( void ) const
  1162. {
  1163. return 0;
  1164. }
  1165. uint32 GetFilter( void ) const
  1166. {
  1167. return FILTER_PARAMETER_REMAPPING_MASK;
  1168. }
  1169. virtual void InitParams(CParticleSystemDefinition *pDef )
  1170. {
  1171. // Set values to clamp against at init rather than branching inside the per-particle loop
  1172. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & ( 1 << m_nField ) )
  1173. {
  1174. m_fl4MinCmp = Four_Zeros;
  1175. m_fl4MaxCmp = Four_Ones;
  1176. }
  1177. else if ( ATTRIBUTES_WHICH_ARE_SIZE & ( 1 << m_nField ) )
  1178. {
  1179. m_fl4MinCmp = Four_Zeros;
  1180. m_fl4MaxCmp = Four_FLT_MAX;
  1181. }
  1182. else
  1183. {
  1184. m_fl4MinCmp = Four_Negative_FLT_MAX;
  1185. m_fl4MaxCmp = Four_FLT_MAX;
  1186. }
  1187. }
  1188. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  1189. };
  1190. DEFINE_PARTICLE_OPERATOR( C_OP_OscillateScalarSimple, "Oscillate Scalar Simple", OPERATOR_GENERIC );
  1191. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_OscillateScalarSimple )
  1192. DMXELEMENT_UNPACK_FIELD_USERDATA( "oscillation field", "7", int, m_nField, "intchoice particlefield_scalar" )
  1193. DMXELEMENT_UNPACK_FIELD( "oscillation rate", "0", float, m_Rate )
  1194. DMXELEMENT_UNPACK_FIELD( "oscillation frequency", "1", float, m_Frequency )
  1195. DMXELEMENT_UNPACK_FIELD( "oscillation multiplier", "2", float, m_flOscMult )
  1196. DMXELEMENT_UNPACK_FIELD( "oscillation start phase", ".5", float, m_flOscAdd )
  1197. END_PARTICLE_OPERATOR_UNPACK( C_OP_OscillateScalarSimple )
  1198. void C_OP_OscillateScalarSimple::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  1199. {
  1200. CM128AttributeWriteIterator pOscField ( m_nField, pParticles) ;
  1201. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  1202. fltx4 fl4OscVal;
  1203. fltx4 fl4ScaleFactor = ReplicateX4( flStrength * pParticles->m_flDt );
  1204. fltx4 fl4CosFactorMultiplier = ReplicateX4( m_flOscMult );
  1205. fltx4 fl4CosFactorAdd = ReplicateX4( m_flOscAdd );
  1206. fltx4 fl4CosFactor = AddSIMD( MulSIMD( fl4CosFactorMultiplier, fl4CurTime ), fl4CosFactorAdd );
  1207. fltx4 fl4Frequency = ReplicateX4( m_Frequency );
  1208. fltx4 fl4Rate= ReplicateX4( m_Rate );
  1209. fltx4 fl4OscMultiplier = MulSIMD( fl4Rate, fl4ScaleFactor);
  1210. fltx4 fl4Cos = MulSIMD( fl4CosFactor, fl4Frequency );
  1211. int nCtr = pParticles->m_nPaddedActiveParticles;
  1212. fltx4 fl4OscillateAmt = MulSIMD( fl4OscMultiplier, SinEst01SIMD( fl4Cos ) );
  1213. do
  1214. {
  1215. fl4OscVal = AddSIMD ( *pOscField, fl4OscillateAmt );
  1216. *pOscField = MaxSIMD( MinSIMD( fl4OscVal, m_fl4MaxCmp), m_fl4MinCmp );
  1217. ++pOscField;
  1218. } while (--nCtr );
  1219. };
  1220. //-----------------------------------------------------------------------------
  1221. // Oscillating Vector operator
  1222. // performs an oscillation operation on any vector (location, tint)
  1223. //-----------------------------------------------------------------------------
  1224. class C_OP_OscillateVector : public CParticleOperatorInstance
  1225. {
  1226. DECLARE_PARTICLE_OPERATOR( C_OP_OscillateVector );
  1227. uint32 GetWrittenAttributes( void ) const
  1228. {
  1229. return 1 << m_nField;
  1230. }
  1231. uint32 GetReadAttributes( void ) const
  1232. {
  1233. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK |
  1234. PARTICLE_ATTRIBUTE_PARTICLE_ID_MASK;
  1235. }
  1236. uint32 GetFilter( void ) const
  1237. {
  1238. return FILTER_PARAMETER_REMAPPING_MASK;
  1239. }
  1240. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  1241. Vector m_RateMin;
  1242. Vector m_RateMax;
  1243. Vector m_FrequencyMin;
  1244. Vector m_FrequencyMax;
  1245. int m_nField;
  1246. bool m_bProportional, m_bProportionalOp;
  1247. bool m_bAccelerator;
  1248. float m_flStartTime_min;
  1249. float m_flStartTime_max;
  1250. float m_flEndTime_min;
  1251. float m_flEndTime_max;
  1252. float m_flOscMult;
  1253. float m_flOscAdd;
  1254. };
  1255. DEFINE_PARTICLE_OPERATOR( C_OP_OscillateVector, "Oscillate Vector", OPERATOR_GENERIC );
  1256. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_OscillateVector )
  1257. DMXELEMENT_UNPACK_FIELD_USERDATA( "oscillation field", "0", int, m_nField, "intchoice particlefield_vector" )
  1258. DMXELEMENT_UNPACK_FIELD( "oscillation rate min", "0 0 0", Vector, m_RateMin )
  1259. DMXELEMENT_UNPACK_FIELD( "oscillation rate max", "0 0 0", Vector, m_RateMax )
  1260. DMXELEMENT_UNPACK_FIELD( "oscillation frequency min", "1 1 1", Vector, m_FrequencyMin )
  1261. DMXELEMENT_UNPACK_FIELD( "oscillation frequency max", "1 1 1", Vector, m_FrequencyMax )
  1262. DMXELEMENT_UNPACK_FIELD( "proportional 0/1", "1", bool, m_bProportional )
  1263. DMXELEMENT_UNPACK_FIELD( "start time min", "0", float, m_flStartTime_min )
  1264. DMXELEMENT_UNPACK_FIELD( "start time max", "0", float, m_flStartTime_max )
  1265. DMXELEMENT_UNPACK_FIELD( "end time min", "1", float, m_flEndTime_min )
  1266. DMXELEMENT_UNPACK_FIELD( "end time max", "1", float, m_flEndTime_max )
  1267. DMXELEMENT_UNPACK_FIELD( "start/end proportional", "1", bool, m_bProportionalOp )
  1268. DMXELEMENT_UNPACK_FIELD( "oscillation multiplier", "2", float, m_flOscMult )
  1269. DMXELEMENT_UNPACK_FIELD( "oscillation start phase", ".5", float, m_flOscAdd )
  1270. END_PARTICLE_OPERATOR_UNPACK( C_OP_OscillateVector )
  1271. void C_OP_OscillateVector::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  1272. {
  1273. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  1274. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  1275. C4IAttributeIterator pParticleId ( PARTICLE_ATTRIBUTE_PARTICLE_ID, pParticles );
  1276. C4VAttributeWriteIterator pOscField ( m_nField, pParticles) ;
  1277. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  1278. int nRandomOffset = pParticles->OperatorRandomSampleOffset();
  1279. FourVectors fvOscVal;
  1280. fltx4 fl4ScaleFactor = ReplicateX4( flStrength * pParticles->m_flDt );
  1281. fltx4 fl4CosFactorMultiplier = ReplicateX4( m_flOscMult );
  1282. fltx4 fl4CosFactorAdd = ReplicateX4( m_flOscAdd );
  1283. fltx4 fl4CosFactor = AddSIMD( MulSIMD( fl4CosFactorMultiplier, fl4CurTime ), fl4CosFactorAdd );
  1284. fltx4 fl4CosFactorProp = fl4CosFactorMultiplier;
  1285. fltx4 fl4StartTimeMin = ReplicateX4( m_flStartTime_min );
  1286. fltx4 fl4StartTimeWidth = ReplicateX4( m_flStartTime_max - m_flStartTime_min );
  1287. fltx4 fl4EndTimeMin = ReplicateX4( m_flEndTime_min );
  1288. fltx4 fl4EndTimeWidth = ReplicateX4( m_flEndTime_max - m_flEndTime_min );
  1289. FourVectors fvFrequencyMin;
  1290. fvFrequencyMin.DuplicateVector( m_FrequencyMin );
  1291. FourVectors fvFrequencyWidth;
  1292. fvFrequencyWidth.DuplicateVector( m_FrequencyMax - m_FrequencyMin );
  1293. FourVectors fvRateMin;
  1294. fvRateMin.DuplicateVector( m_RateMin );
  1295. FourVectors fvRateWidth;
  1296. fvRateWidth.DuplicateVector( m_RateMax - m_RateMin );
  1297. int nCtr = pParticles->m_nPaddedActiveParticles;
  1298. do
  1299. {
  1300. fltx4 fl4LifeDuration = *pLifeDuration;
  1301. bi32x4 fl4GoodMask = CmpGtSIMD( fl4LifeDuration, Four_Zeros );
  1302. fltx4 fl4LifeTime;
  1303. if ( m_bProportionalOp )
  1304. {
  1305. fl4LifeTime = MulSIMD( SubSIMD( fl4CurTime, *pCreationTime ), ReciprocalEstSIMD( fl4LifeDuration ) ); // maybe need accurate div here?
  1306. }
  1307. else
  1308. {
  1309. fl4LifeTime = SubSIMD( fl4CurTime, *pCreationTime );
  1310. }
  1311. fltx4 fl4StartTime= pParticles->RandomFloat( *pParticleId, nRandomOffset + 11);
  1312. fl4StartTime = AddSIMD( fl4StartTimeMin, MulSIMD( fl4StartTimeWidth, fl4StartTime ) );
  1313. fltx4 fl4EndTime= pParticles->RandomFloat( *pParticleId, nRandomOffset + 12);
  1314. fl4EndTime = AddSIMD( fl4EndTimeMin, MulSIMD( fl4EndTimeWidth, fl4EndTime ) );
  1315. fl4GoodMask = AndSIMD( fl4GoodMask, CmpGeSIMD( fl4LifeTime, fl4StartTime ) );
  1316. fl4GoodMask = AndSIMD( fl4GoodMask, CmpLtSIMD( fl4LifeTime, fl4EndTime ) );
  1317. if ( IsAnyTrue( fl4GoodMask ) )
  1318. {
  1319. FourVectors fvFrequency;
  1320. fvFrequency.x = pParticles->RandomFloat( *pParticleId, nRandomOffset + 8 );
  1321. fvFrequency.y = pParticles->RandomFloat( *pParticleId, nRandomOffset + 12 );
  1322. fvFrequency.z = pParticles->RandomFloat( *pParticleId, nRandomOffset + 15 );
  1323. fvFrequency.VProduct( fvFrequencyWidth );
  1324. fvFrequency += fvFrequencyMin;
  1325. FourVectors fvRate;
  1326. fvRate.x = pParticles->RandomFloat( *pParticleId, nRandomOffset + 3);
  1327. fvRate.y = pParticles->RandomFloat( *pParticleId, nRandomOffset + 7);
  1328. fvRate.z = pParticles->RandomFloat( *pParticleId, nRandomOffset + 9);
  1329. //fvRate = AddSIMD( fvRateMin, MulSIMD( fvRateWidth, fvRate ) );
  1330. fvRate.VProduct( fvRateWidth );
  1331. fvRate += fvRateMin;
  1332. FourVectors fvCos;
  1333. if ( m_bProportional )
  1334. {
  1335. fl4LifeTime = MulSIMD( SubSIMD( fl4CurTime, *pCreationTime ), ReciprocalEstSIMD( fl4LifeDuration ) );
  1336. fvCos.x = AddSIMD( MulSIMD( fl4CosFactorProp, MulSIMD( fvFrequency.x, fl4LifeTime )), fl4CosFactorAdd );
  1337. fvCos.y = AddSIMD( MulSIMD( fl4CosFactorProp, MulSIMD( fvFrequency.y, fl4LifeTime )), fl4CosFactorAdd );
  1338. fvCos.z = AddSIMD( MulSIMD( fl4CosFactorProp, MulSIMD( fvFrequency.z, fl4LifeTime )), fl4CosFactorAdd );
  1339. }
  1340. else
  1341. {
  1342. //fvCos = MulSIMD( fl4CosFactor, fvFrequency );
  1343. fvCos.x = MulSIMD( fvFrequency.x, fl4CosFactor );
  1344. fvCos.y = MulSIMD( fvFrequency.y, fl4CosFactor );
  1345. fvCos.z = MulSIMD( fvFrequency.z, fl4CosFactor );
  1346. }
  1347. FourVectors fvOscMultiplier;
  1348. fvOscMultiplier.x = MulSIMD( fvRate.x, fl4ScaleFactor);
  1349. fvOscMultiplier.y = MulSIMD( fvRate.y, fl4ScaleFactor);
  1350. fvOscMultiplier.z = MulSIMD( fvRate.z, fl4ScaleFactor);
  1351. FourVectors fvOutput = *pOscField;
  1352. fvOscVal.x = AddSIMD ( fvOutput.x, MulSIMD ( fvOscMultiplier.x, SinEst01SIMD( fvCos.x ) ) );
  1353. fvOscVal.y = AddSIMD ( fvOutput.y, MulSIMD ( fvOscMultiplier.y, SinEst01SIMD( fvCos.y ) ) );
  1354. fvOscVal.z = AddSIMD ( fvOutput.z, MulSIMD ( fvOscMultiplier.z, SinEst01SIMD( fvCos.z ) ) );
  1355. if ( m_nField == 6)
  1356. {
  1357. pOscField->x = MaskedAssign( fl4GoodMask,
  1358. MaxSIMD( MinSIMD( fvOscVal.x, Four_Ones), Four_Zeros ), fvOutput.x );
  1359. pOscField->y = MaskedAssign( fl4GoodMask,
  1360. MaxSIMD( MinSIMD( fvOscVal.y, Four_Ones), Four_Zeros ), fvOutput.y );
  1361. pOscField->z = MaskedAssign( fl4GoodMask,
  1362. MaxSIMD( MinSIMD( fvOscVal.z, Four_Ones), Four_Zeros ), fvOutput.z );
  1363. }
  1364. else
  1365. {
  1366. pOscField->x = MaskedAssign( fl4GoodMask, fvOscVal.x, fvOutput.x );
  1367. pOscField->y = MaskedAssign( fl4GoodMask, fvOscVal.y, fvOutput.y );
  1368. pOscField->z = MaskedAssign( fl4GoodMask, fvOscVal.z, fvOutput.z );
  1369. }
  1370. }
  1371. ++pCreationTime;
  1372. ++pLifeDuration;
  1373. ++pOscField;
  1374. ++pParticleId;
  1375. } while (--nCtr );
  1376. };
  1377. //-----------------------------------------------------------------------------
  1378. // Oscillating Vector Simple operator
  1379. // performs an oscillation operation on any vector (location, tint)
  1380. // Simple version eliminates a bunch of options for speed
  1381. //-----------------------------------------------------------------------------
  1382. class C_OP_OscillateVectorSimple : public CParticleOperatorInstance
  1383. {
  1384. DECLARE_PARTICLE_OPERATOR( C_OP_OscillateVectorSimple );
  1385. uint32 GetWrittenAttributes( void ) const
  1386. {
  1387. return 1 << m_nField;
  1388. }
  1389. uint32 GetReadAttributes( void ) const
  1390. {
  1391. return 0;
  1392. }
  1393. uint32 GetFilter( void ) const
  1394. {
  1395. return FILTER_NOT_SPECIAL_MASK;
  1396. }
  1397. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  1398. Vector m_Rate;
  1399. Vector m_Frequency;
  1400. int m_nField;
  1401. float m_flOscMult;
  1402. float m_flOscAdd;
  1403. };
  1404. DEFINE_PARTICLE_OPERATOR( C_OP_OscillateVectorSimple, "Oscillate Vector Simple", OPERATOR_GENERIC );
  1405. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_OscillateVectorSimple )
  1406. DMXELEMENT_UNPACK_FIELD_USERDATA( "oscillation field", "0", int, m_nField, "intchoice particlefield_vector" )
  1407. DMXELEMENT_UNPACK_FIELD( "oscillation rate", "0 0 0", Vector, m_Rate )
  1408. DMXELEMENT_UNPACK_FIELD( "oscillation frequency", "1 1 1", Vector, m_Frequency )
  1409. DMXELEMENT_UNPACK_FIELD( "oscillation multiplier", "2", float, m_flOscMult )
  1410. DMXELEMENT_UNPACK_FIELD( "oscillation start phase", ".5", float, m_flOscAdd )
  1411. END_PARTICLE_OPERATOR_UNPACK( C_OP_OscillateVectorSimple )
  1412. void C_OP_OscillateVectorSimple::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  1413. {
  1414. C4VAttributeWriteIterator pOscField ( m_nField, pParticles) ;
  1415. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  1416. FourVectors fvOscVal;
  1417. fltx4 fl4ScaleFactor = ReplicateX4( flStrength * pParticles->m_flDt );
  1418. fltx4 fl4CosFactorMultiplier = ReplicateX4( m_flOscMult );
  1419. fltx4 fl4CosFactorAdd = ReplicateX4( m_flOscAdd );
  1420. fltx4 fl4CosFactor = AddSIMD( MulSIMD( fl4CosFactorMultiplier, fl4CurTime ), fl4CosFactorAdd );
  1421. FourVectors fvFrequency;
  1422. fvFrequency.DuplicateVector( m_Frequency );
  1423. FourVectors fvRate;
  1424. fvRate.DuplicateVector( m_Rate );
  1425. FourVectors fvCos;
  1426. fvCos.x = MulSIMD( fvFrequency.x, fl4CosFactor );
  1427. fvCos.y = MulSIMD( fvFrequency.y, fl4CosFactor );
  1428. fvCos.z = MulSIMD( fvFrequency.z, fl4CosFactor );
  1429. FourVectors fvOscMultiplier;
  1430. fvOscMultiplier.x = MulSIMD( fvRate.x, fl4ScaleFactor);
  1431. fvOscMultiplier.y = MulSIMD( fvRate.y, fl4ScaleFactor);
  1432. fvOscMultiplier.z = MulSIMD( fvRate.z, fl4ScaleFactor);
  1433. int nCtr = pParticles->m_nPaddedActiveParticles;
  1434. FourVectors fvOscillateAmt;
  1435. fvOscillateAmt.x = MulSIMD ( fvOscMultiplier.x, SinEst01SIMD( fvCos.x ) );
  1436. fvOscillateAmt.y = MulSIMD ( fvOscMultiplier.y, SinEst01SIMD( fvCos.y ) );
  1437. fvOscillateAmt.z = MulSIMD ( fvOscMultiplier.z, SinEst01SIMD( fvCos.z ) );
  1438. if ( ATTRIBUTES_WHICH_ARE_COLOR_AND_OPACITY & ( 1 << m_nField ))
  1439. {
  1440. do
  1441. {
  1442. FourVectors fvOscVal = *pOscField;
  1443. fvOscVal += fvOscillateAmt;
  1444. pOscField->x = MaxSIMD( MinSIMD( fvOscVal.x, Four_Ones), Four_Zeros );
  1445. pOscField->y = MaxSIMD( MinSIMD( fvOscVal.y, Four_Ones), Four_Zeros );
  1446. pOscField->z = MaxSIMD( MinSIMD( fvOscVal.z, Four_Ones), Four_Zeros );
  1447. ++pOscField;
  1448. } while (--nCtr );
  1449. }
  1450. else
  1451. {
  1452. do
  1453. {
  1454. *pOscField += fvOscillateAmt;
  1455. ++pOscField;
  1456. } while (--nCtr );
  1457. }
  1458. };
  1459. //-----------------------------------------------------------------------------
  1460. // Difference Between Previous Particle Operator
  1461. //-----------------------------------------------------------------------------
  1462. class C_OP_DifferencePreviousParticle : public CParticleOperatorInstance
  1463. {
  1464. DECLARE_PARTICLE_OPERATOR( C_OP_DifferencePreviousParticle );
  1465. uint32 GetWrittenAttributes( void ) const
  1466. {
  1467. return 1 << m_nFieldOutput;
  1468. }
  1469. uint32 GetReadAttributes( void ) const
  1470. {
  1471. return 1 << m_nFieldInput;
  1472. }
  1473. uint32 GetFilter( void ) const
  1474. {
  1475. return FILTER_PARAMETER_REMAPPING_MASK;
  1476. }
  1477. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  1478. int m_nFieldInput;
  1479. int m_nFieldOutput;
  1480. float m_flInputMin;
  1481. float m_flInputMax;
  1482. float m_flOutputMin;
  1483. float m_flOutputMax;
  1484. bool m_bScaleInitialRange;
  1485. bool m_bActiveRange;
  1486. bool m_bSetPreviousParticle;
  1487. };
  1488. DEFINE_PARTICLE_OPERATOR( C_OP_DifferencePreviousParticle, "Remap Difference of Sequential Particle Vector to Scalar", OPERATOR_GENERIC );
  1489. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_DifferencePreviousParticle )
  1490. DMXELEMENT_UNPACK_FIELD( "difference minimum","0", float, m_flInputMin )
  1491. DMXELEMENT_UNPACK_FIELD( "difference maximum","128", float, m_flInputMax )
  1492. DMXELEMENT_UNPACK_FIELD_USERDATA( "input field", "0", int, m_nFieldInput, "intchoice particlefield_vector" )
  1493. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "3", int, m_nFieldOutput, "intchoice particlefield_scalar" )
  1494. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  1495. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  1496. DMXELEMENT_UNPACK_FIELD( "output is scalar of initial random range","0", bool, m_bScaleInitialRange )
  1497. DMXELEMENT_UNPACK_FIELD( "only active within specified difference","0", bool, m_bActiveRange )
  1498. DMXELEMENT_UNPACK_FIELD( "also set ouput to previous particle","0", bool, m_bSetPreviousParticle )
  1499. END_PARTICLE_OPERATOR_UNPACK( C_OP_DifferencePreviousParticle )
  1500. void C_OP_DifferencePreviousParticle::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  1501. {
  1502. // clamp the result to 0 and 1 if it's alpha
  1503. float flMin=m_flOutputMin;
  1504. float flMax=m_flOutputMax;
  1505. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & ( 1 << m_nFieldOutput ) )
  1506. {
  1507. flMin = clamp(m_flOutputMin, 0.0f, 1.0f );
  1508. flMax = clamp(m_flOutputMax, 0.0f, 1.0f );
  1509. }
  1510. Vector vecPreviousVal = vec3_invalid;
  1511. int nPreviousParticleNumber = 0;
  1512. // FIXME: SSE-ize
  1513. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  1514. {
  1515. const float *pInput = pParticles->GetFloatAttributePtr(m_nFieldInput, i );
  1516. if ( vecPreviousVal != vec3_invalid )
  1517. {
  1518. Vector vecPosition2 = Vector(pInput[0], pInput[4], pInput[8]);
  1519. float flDistance = vecPreviousVal.DistTo( vecPosition2 );
  1520. if ( m_bActiveRange && ( flDistance < m_flInputMin || flDistance > m_flInputMax ) )
  1521. {
  1522. continue;
  1523. }
  1524. float flOutput = RemapValClamped( flDistance, m_flInputMin, m_flInputMax, flMin, flMax );
  1525. float flOutput2 = flOutput;
  1526. if ( m_bScaleInitialRange )
  1527. {
  1528. const float *pInitialOutput = pParticles->GetFloatAttributePtr( m_nFieldOutput, i );
  1529. flOutput = *pInitialOutput * flOutput;
  1530. }
  1531. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, i );
  1532. float *pOutput2 = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, nPreviousParticleNumber );
  1533. *pOutput = flOutput;
  1534. if ( m_bSetPreviousParticle )
  1535. *pOutput2 *= flOutput2;
  1536. }
  1537. SetVectorFromAttribute( vecPreviousVal, pInput );
  1538. nPreviousParticleNumber = i;
  1539. }
  1540. }
  1541. //-----------------------------------------------------------------------------
  1542. // Remap Scalar Operator
  1543. //-----------------------------------------------------------------------------
  1544. class C_OP_RemapScalar : public CParticleOperatorInstance
  1545. {
  1546. DECLARE_PARTICLE_OPERATOR( C_OP_RemapScalar );
  1547. uint32 GetWrittenAttributes( void ) const
  1548. {
  1549. return 1 << m_nFieldOutput;
  1550. }
  1551. uint32 GetReadAttributes( void ) const
  1552. {
  1553. return 1 << m_nFieldInput;
  1554. }
  1555. uint32 GetFilter( void ) const
  1556. {
  1557. return FILTER_PARAMETER_REMAPPING_MASK;
  1558. }
  1559. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  1560. int m_nFieldInput;
  1561. int m_nFieldOutput;
  1562. float m_flInputMin;
  1563. float m_flInputMax;
  1564. float m_flOutputMin;
  1565. float m_flOutputMax;
  1566. };
  1567. DEFINE_PARTICLE_OPERATOR( C_OP_RemapScalar, "Remap Scalar", OPERATOR_GENERIC );
  1568. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RemapScalar )
  1569. DMXELEMENT_UNPACK_FIELD_USERDATA( "input field", "7", int, m_nFieldInput, "intchoice particlefield_scalar" )
  1570. DMXELEMENT_UNPACK_FIELD( "input minimum","0", float, m_flInputMin )
  1571. DMXELEMENT_UNPACK_FIELD( "input maximum","1", float, m_flInputMax )
  1572. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "3", int, m_nFieldOutput, "intchoice particlefield_scalar" )
  1573. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  1574. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  1575. END_PARTICLE_OPERATOR_UNPACK( C_OP_RemapScalar )
  1576. void C_OP_RemapScalar::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  1577. {
  1578. // clamp the result to 0 and 1 if it's alpha
  1579. float flMin=m_flOutputMin;
  1580. float flMax=m_flOutputMax;
  1581. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & ( 1 << m_nFieldOutput ) )
  1582. {
  1583. flMin = clamp(m_flOutputMin, 0.0f, 1.0f );
  1584. flMax = clamp(m_flOutputMax, 0.0f, 1.0f );
  1585. }
  1586. // FIXME: SSE-ize
  1587. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  1588. {
  1589. const float *pInput = pParticles->GetFloatAttributePtr( m_nFieldInput, i );
  1590. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, i );
  1591. float flOutput = RemapValClamped( *pInput, m_flInputMin, m_flInputMax, flMin, flMax );
  1592. *pOutput = Lerp (flStrength, *pOutput, flOutput);
  1593. }
  1594. }
  1595. //-----------------------------------------------------------------------------
  1596. // Lerp Scalar Operator
  1597. //-----------------------------------------------------------------------------
  1598. class C_OP_LerpScalar : public CParticleOperatorInstance
  1599. {
  1600. DECLARE_PARTICLE_OPERATOR( C_OP_LerpScalar );
  1601. uint32 GetWrittenAttributes( void ) const
  1602. {
  1603. return 1 << m_nFieldOutput;
  1604. }
  1605. uint32 GetReadAttributes( void ) const
  1606. {
  1607. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK;
  1608. }
  1609. uint32 GetReadInitialAttributes( void ) const
  1610. {
  1611. return 1 << m_nFieldOutput;
  1612. }
  1613. uint32 GetFilter( void ) const
  1614. {
  1615. return FILTER_PARAMETER_REMAPPING_MASK;
  1616. }
  1617. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  1618. int m_nFieldOutput;
  1619. float m_flOutput;
  1620. float m_flStartTime;
  1621. float m_flEndTime;
  1622. };
  1623. DEFINE_PARTICLE_OPERATOR( C_OP_LerpScalar, "Lerp Initial Scalar", OPERATOR_GENERIC );
  1624. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_LerpScalar )
  1625. DMXELEMENT_UNPACK_FIELD( "start time","0", float, m_flStartTime )
  1626. DMXELEMENT_UNPACK_FIELD( "end time","1", float, m_flEndTime )
  1627. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "3", int, m_nFieldOutput, "intchoice particlefield_scalar" )
  1628. DMXELEMENT_UNPACK_FIELD( "value to lerp to","1", float, m_flOutput )
  1629. END_PARTICLE_OPERATOR_UNPACK( C_OP_LerpScalar )
  1630. void C_OP_LerpScalar::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  1631. {
  1632. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  1633. {
  1634. const float *pCt = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, i );
  1635. const float *pLifespan = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_LIFE_DURATION, i );
  1636. float flAge = ( pParticles->m_flCurTime - *pCt ) / ( *pLifespan + FLT_EPSILON );
  1637. if ( flAge < m_flStartTime || flAge > m_flEndTime )
  1638. continue;
  1639. const float *pInput = pParticles->GetInitialFloatAttributePtr( m_nFieldOutput, i );
  1640. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, i );
  1641. float flOutput = RemapValClamped( flAge, m_flStartTime, m_flEndTime, *pInput, m_flOutput );
  1642. *pOutput = Lerp (flStrength, *pOutput, flOutput);
  1643. }
  1644. }
  1645. struct LerpEndcapContext_t
  1646. {
  1647. float m_flEndCapStartTime;
  1648. };
  1649. //-----------------------------------------------------------------------------
  1650. // Lerp EndCap Scalar Operator
  1651. //-----------------------------------------------------------------------------
  1652. class C_OP_LerpEndCapScalar : public CParticleOperatorInstance
  1653. {
  1654. DECLARE_PARTICLE_OPERATOR( C_OP_LerpEndCapScalar );
  1655. uint32 GetWrittenAttributes( void ) const
  1656. {
  1657. return 1 << m_nFieldOutput;
  1658. }
  1659. uint32 GetReadAttributes( void ) const
  1660. {
  1661. return 0;
  1662. }
  1663. uint32 GetReadInitialAttributes( void ) const
  1664. {
  1665. return 1 << m_nFieldOutput;
  1666. }
  1667. uint32 GetFilter( void ) const
  1668. {
  1669. return FILTER_PARAMETER_REMAPPING_MASK;
  1670. }
  1671. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  1672. {
  1673. LerpEndcapContext_t *pCtx=reinterpret_cast<LerpEndcapContext_t *>( pContext );
  1674. pCtx->m_flEndCapStartTime = -FLT_MAX;
  1675. }
  1676. size_t GetRequiredContextBytes( void ) const
  1677. {
  1678. return sizeof( LerpEndcapContext_t );
  1679. }
  1680. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  1681. int m_nFieldOutput;
  1682. float m_flOutput;
  1683. float m_flLerpTime;
  1684. };
  1685. DEFINE_PARTICLE_OPERATOR( C_OP_LerpEndCapScalar, "Lerp EndCap Scalar", OPERATOR_GENERIC );
  1686. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_LerpEndCapScalar )
  1687. DMXELEMENT_UNPACK_FIELD( "lerp time","1", float, m_flLerpTime )
  1688. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "3", int, m_nFieldOutput, "intchoice particlefield_scalar" )
  1689. DMXELEMENT_UNPACK_FIELD( "value to lerp to","1", float, m_flOutput )
  1690. END_PARTICLE_OPERATOR_UNPACK( C_OP_LerpEndCapScalar )
  1691. void C_OP_LerpEndCapScalar::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  1692. {
  1693. LerpEndcapContext_t *pCtx=reinterpret_cast<LerpEndcapContext_t *>( pContext );
  1694. if ( pParticles->m_bInEndCap)
  1695. {
  1696. if ( pCtx->m_flEndCapStartTime < 0.0f )
  1697. {
  1698. // Mark when we went into our EndCap
  1699. pCtx->m_flEndCapStartTime = pParticles->m_flCurTime;
  1700. // Set our "initial" value to our current value at the point of entering endcap so we can lerp against something meaningful
  1701. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  1702. {
  1703. float *pInput = pParticles->GetInitialFloatAttributePtrForWrite( m_nFieldOutput, i );
  1704. const float *pOutput = pParticles->GetFloatAttributePtr( m_nFieldOutput, i );
  1705. *pInput = *pOutput;
  1706. }
  1707. }
  1708. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  1709. {
  1710. float flAge = ( pParticles->m_flCurTime - pCtx->m_flEndCapStartTime ) / ( m_flLerpTime + FLT_EPSILON );
  1711. if ( flAge > 1.0f )
  1712. continue;
  1713. const float *pInput = pParticles->GetInitialFloatAttributePtr( m_nFieldOutput, i );
  1714. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, i );
  1715. float flOutput = RemapValClamped( flAge, 0.0f, 1.0f, *pInput, m_flOutput );
  1716. *pOutput = Lerp (flStrength, *pOutput, flOutput);
  1717. }
  1718. }
  1719. }
  1720. //-----------------------------------------------------------------------------
  1721. // Lerp EndCap Vector Operator
  1722. //-----------------------------------------------------------------------------
  1723. class C_OP_LerpEndCapVector : public CParticleOperatorInstance
  1724. {
  1725. DECLARE_PARTICLE_OPERATOR( C_OP_LerpEndCapVector );
  1726. uint32 GetWrittenAttributes( void ) const
  1727. {
  1728. return 1 << m_nFieldOutput;
  1729. }
  1730. uint32 GetReadAttributes( void ) const
  1731. {
  1732. return 0;
  1733. }
  1734. uint32 GetReadInitialAttributes( void ) const
  1735. {
  1736. return 1 << m_nFieldOutput;
  1737. }
  1738. uint32 GetFilter( void ) const
  1739. {
  1740. return FILTER_PARAMETER_REMAPPING_MASK;
  1741. }
  1742. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  1743. {
  1744. LerpEndcapContext_t *pCtx=reinterpret_cast<LerpEndcapContext_t *>( pContext );
  1745. pCtx->m_flEndCapStartTime = -FLT_MAX;
  1746. }
  1747. size_t GetRequiredContextBytes( void ) const
  1748. {
  1749. return sizeof( LerpEndcapContext_t );
  1750. }
  1751. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  1752. int m_nFieldOutput;
  1753. Vector m_vecOutput;
  1754. float m_flLerpTime;
  1755. };
  1756. DEFINE_PARTICLE_OPERATOR( C_OP_LerpEndCapVector, "Lerp EndCap Vector", OPERATOR_GENERIC );
  1757. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_LerpEndCapVector )
  1758. DMXELEMENT_UNPACK_FIELD( "lerp time","1", float, m_flLerpTime )
  1759. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "0", int, m_nFieldOutput, "intchoice particlefield_vector" )
  1760. DMXELEMENT_UNPACK_FIELD( "value to lerp to","0 0 0", Vector, m_vecOutput )
  1761. END_PARTICLE_OPERATOR_UNPACK( C_OP_LerpEndCapVector )
  1762. void C_OP_LerpEndCapVector::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  1763. {
  1764. LerpEndcapContext_t *pCtx=reinterpret_cast<LerpEndcapContext_t *>( pContext );
  1765. if ( pParticles->m_bInEndCap)
  1766. {
  1767. if ( pCtx->m_flEndCapStartTime < 0.0f )
  1768. {
  1769. // Mark when we went into our EndCap
  1770. pCtx->m_flEndCapStartTime = pParticles->m_flCurTime;
  1771. // Set our "initial" value to our current value at the point of entering endcap so we can lerp against something meaningful
  1772. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  1773. {
  1774. float *pInput = pParticles->GetInitialFloatAttributePtrForWrite( m_nFieldOutput, i );
  1775. const float *pOutput = pParticles->GetFloatAttributePtr( m_nFieldOutput, i );
  1776. *pInput = *pOutput;
  1777. }
  1778. }
  1779. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  1780. {
  1781. float flAge = ( pParticles->m_flCurTime - pCtx->m_flEndCapStartTime ) / ( m_flLerpTime + FLT_EPSILON );
  1782. if ( flAge > 1.0f )
  1783. continue;
  1784. const float *pInput = pParticles->GetInitialFloatAttributePtr( m_nFieldOutput, i );
  1785. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, i );
  1786. flAge *= flStrength;
  1787. Vector vecStart;
  1788. SetVectorFromAttribute( vecStart, pInput );
  1789. VectorLerp( vecStart, m_vecOutput, flAge, vecStart );
  1790. SetVectorAttribute( pOutput, vecStart );
  1791. }
  1792. }
  1793. }
  1794. //-----------------------------------------------------------------------------
  1795. // Lerp Vector Operator
  1796. //-----------------------------------------------------------------------------
  1797. class C_OP_LerpVector : public CParticleOperatorInstance
  1798. {
  1799. DECLARE_PARTICLE_OPERATOR( C_OP_LerpVector );
  1800. uint32 GetWrittenAttributes( void ) const
  1801. {
  1802. return 1 << m_nFieldOutput;
  1803. }
  1804. uint32 GetReadAttributes( void ) const
  1805. {
  1806. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK;
  1807. }
  1808. uint32 GetReadInitialAttributes( void ) const
  1809. {
  1810. return 1 << m_nFieldOutput;
  1811. }
  1812. uint32 GetFilter( void ) const
  1813. {
  1814. return FILTER_PARAMETER_REMAPPING_MASK;
  1815. }
  1816. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  1817. int m_nFieldOutput;
  1818. Vector m_vecOutput;
  1819. float m_flStartTime;
  1820. float m_flEndTime;
  1821. };
  1822. DEFINE_PARTICLE_OPERATOR( C_OP_LerpVector, "Lerp Initial Vector", OPERATOR_GENERIC );
  1823. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_LerpVector )
  1824. DMXELEMENT_UNPACK_FIELD( "start time","0", float, m_flStartTime )
  1825. DMXELEMENT_UNPACK_FIELD( "end time","1", float, m_flEndTime )
  1826. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "0", int, m_nFieldOutput, "intchoice particlefield_vector" )
  1827. DMXELEMENT_UNPACK_FIELD( "value to lerp to","0 0 0", Vector, m_vecOutput )
  1828. END_PARTICLE_OPERATOR_UNPACK( C_OP_LerpVector )
  1829. void C_OP_LerpVector::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  1830. {
  1831. // FIXME: SSE-ize
  1832. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  1833. {
  1834. const float *pCt = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, i );
  1835. const float *pLifespan = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_LIFE_DURATION, i );
  1836. float flAge = ( pParticles->m_flCurTime - *pCt ) / ( *pLifespan + FLT_EPSILON );
  1837. if ( flAge < m_flStartTime || flAge > m_flEndTime )
  1838. continue;
  1839. const float *pInput = pParticles->GetInitialFloatAttributePtr( m_nFieldOutput, i );
  1840. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, i );
  1841. float flPercent = RemapValClamped( flAge, m_flStartTime, m_flEndTime, 0.0, 1.0 );
  1842. flPercent *= flStrength;
  1843. Vector vecStart;
  1844. SetVectorFromAttribute( vecStart, pInput );
  1845. VectorLerp( vecStart, m_vecOutput, flPercent, vecStart );
  1846. SetVectorAttribute( pOutput, vecStart );
  1847. }
  1848. }
  1849. //-----------------------------------------------------------------------------
  1850. // Remap Speed Operator
  1851. //-----------------------------------------------------------------------------
  1852. class C_OP_RemapSpeed : public CParticleOperatorInstance
  1853. {
  1854. DECLARE_PARTICLE_OPERATOR( C_OP_RemapSpeed );
  1855. uint32 GetWrittenAttributes( void ) const
  1856. {
  1857. return 1 << m_nFieldOutput;
  1858. }
  1859. uint32 GetReadAttributes( void ) const
  1860. {
  1861. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  1862. }
  1863. uint32 GetReadInitialAttributes( void ) const
  1864. {
  1865. return 1 << m_nFieldOutput;
  1866. }
  1867. uint32 GetFilter( void ) const
  1868. {
  1869. return FILTER_PARAMETER_REMAPPING_MASK;
  1870. }
  1871. virtual void InitParams(CParticleSystemDefinition *pDef )
  1872. {
  1873. m_flInputMin = MAX(MIN_PARTICLE_SPEED, m_flInputMin);
  1874. m_flInputMax = MAX(MIN_PARTICLE_SPEED, m_flInputMax);
  1875. }
  1876. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  1877. int m_nFieldOutput;
  1878. float m_flInputMin;
  1879. float m_flInputMax;
  1880. float m_flOutputMin;
  1881. float m_flOutputMax;
  1882. bool m_bScaleInitialRange;
  1883. bool m_bScaleCurrent;
  1884. };
  1885. DEFINE_PARTICLE_OPERATOR( C_OP_RemapSpeed, "Remap Speed to Scalar", OPERATOR_GENERIC );
  1886. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RemapSpeed )
  1887. DMXELEMENT_UNPACK_FIELD( "input minimum","0", float, m_flInputMin )
  1888. DMXELEMENT_UNPACK_FIELD( "input maximum","1", float, m_flInputMax )
  1889. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "3", int, m_nFieldOutput, "intchoice particlefield_scalar" )
  1890. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  1891. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  1892. DMXELEMENT_UNPACK_FIELD( "output is scalar of initial random range","0", bool, m_bScaleInitialRange )
  1893. DMXELEMENT_UNPACK_FIELD( "output is scalar of current value","0", bool, m_bScaleCurrent )
  1894. END_PARTICLE_OPERATOR_UNPACK( C_OP_RemapSpeed );
  1895. void C_OP_RemapSpeed::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  1896. {
  1897. // clamp the result to 0 and 1 if it's alpha
  1898. fltx4 flMin = ReplicateX4( m_flOutputMin );
  1899. fltx4 flMax = ReplicateX4( m_flOutputMax );
  1900. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & ( 1 << m_nFieldOutput ) )
  1901. {
  1902. flMin = ReplicateX4( clamp(m_flOutputMin, 0.0f, 1.0f ) );
  1903. flMax = ReplicateX4( clamp(m_flOutputMax, 0.0f, 1.0f ) );
  1904. }
  1905. fltx4 fl4Dt = ReplicateX4( pParticles->m_flDt );
  1906. fltx4 fl4InputMin = ReplicateX4( m_flInputMin );
  1907. fltx4 fl4InputMax = ReplicateX4( m_flInputMax );
  1908. fltx4 fl4Strength = ReplicateX4( flStrength );
  1909. C4VAttributeIterator pXYZ( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  1910. C4VAttributeIterator pPrevXYZ( PARTICLE_ATTRIBUTE_PREV_XYZ, pParticles );
  1911. CM128AttributeWriteIterator pOutput (m_nFieldOutput, pParticles);
  1912. CM128InitialAttributeIterator pInitialOutput ( m_nFieldOutput, pParticles );
  1913. for ( int i = 0; i < pParticles->m_nPaddedActiveParticles; i++ )
  1914. {
  1915. fltx4 fl4Speed = DivSIMD ( (*pXYZ - *pPrevXYZ).length(), fl4Dt );
  1916. fltx4 fl4Output = RemapValClampedSIMD( fl4Speed, fl4InputMin, fl4InputMax, flMin, flMax );
  1917. if ( m_bScaleInitialRange )
  1918. {
  1919. fl4Output = MulSIMD( *pInitialOutput, fl4Output );
  1920. }
  1921. if ( m_bScaleCurrent )
  1922. {
  1923. fl4Output = MulSIMD( *pOutput, fl4Output );
  1924. }
  1925. *pOutput = LerpSIMD( fl4Strength, *pOutput, fl4Output );
  1926. ++pXYZ;
  1927. ++pPrevXYZ;
  1928. ++pOutput;
  1929. ++pInitialOutput;
  1930. }
  1931. }
  1932. //-----------------------------------------------------------------------------
  1933. // Remap Speed to CP Operator
  1934. //-----------------------------------------------------------------------------
  1935. class C_OP_RemapSpeedtoCP : public CParticleOperatorInstance
  1936. {
  1937. DECLARE_PARTICLE_OPERATOR( C_OP_RemapSpeedtoCP );
  1938. uint32 GetWrittenAttributes( void ) const
  1939. {
  1940. return 0;
  1941. }
  1942. uint32 GetReadAttributes( void ) const
  1943. {
  1944. return 0;
  1945. }
  1946. uint32 GetFilter( void ) const
  1947. {
  1948. return FILTER_CONTROL_POINTS_MASK;
  1949. }
  1950. virtual uint64 GetReadControlPointMask() const
  1951. {
  1952. return ( 1ULL << m_nInControlPointNumber ) | ( 1ULL << m_nOutControlPointNumber );
  1953. }
  1954. bool ShouldRunBeforeEmitters( void ) const
  1955. {
  1956. return true;
  1957. }
  1958. virtual void InitParams(CParticleSystemDefinition *pDef )
  1959. {
  1960. // Safety for bogus input->output feedback loop
  1961. if ( m_nInControlPointNumber == m_nOutControlPointNumber )
  1962. m_nOutControlPointNumber = -1;
  1963. }
  1964. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  1965. int m_nInControlPointNumber;
  1966. int m_nOutControlPointNumber;
  1967. int m_nField;
  1968. float m_flInputMin;
  1969. float m_flInputMax;
  1970. float m_flOutputMin;
  1971. float m_flOutputMax;
  1972. };
  1973. DEFINE_PARTICLE_OPERATOR( C_OP_RemapSpeedtoCP, "Remap CP Speed to CP", OPERATOR_GENERIC );
  1974. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RemapSpeedtoCP )
  1975. DMXELEMENT_UNPACK_FIELD( "input control point", "0", int, m_nInControlPointNumber )
  1976. DMXELEMENT_UNPACK_FIELD( "input minimum","0", float, m_flInputMin )
  1977. DMXELEMENT_UNPACK_FIELD( "input maximum","1", float, m_flInputMax )
  1978. DMXELEMENT_UNPACK_FIELD( "output control point", "-1", int, m_nOutControlPointNumber )
  1979. DMXELEMENT_UNPACK_FIELD( "Output field 0-2 X/Y/Z","0", int, m_nField )
  1980. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  1981. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  1982. END_PARTICLE_OPERATOR_UNPACK( C_OP_RemapSpeedtoCP );
  1983. void C_OP_RemapSpeedtoCP::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  1984. {
  1985. if ( m_nOutControlPointNumber >= 0 )
  1986. {
  1987. Vector vecPrevPos;
  1988. pParticles->GetControlPointAtPrevTime( m_nInControlPointNumber, &vecPrevPos );
  1989. Vector vecDelta;
  1990. vecDelta = pParticles->GetControlPointAtCurrentTime( m_nInControlPointNumber ) - vecPrevPos;
  1991. float flSpeed = vecDelta.Length() / pParticles->m_flPreviousDt;
  1992. float flOutput = RemapValClamped( flSpeed, m_flInputMin, m_flInputMax, m_flOutputMin, m_flOutputMax );
  1993. Vector vecControlPoint = pParticles->GetControlPointAtCurrentTime( m_nOutControlPointNumber );
  1994. vecControlPoint[m_nField] = flOutput;
  1995. pParticles->SetControlPoint( m_nOutControlPointNumber, vecControlPoint );
  1996. }
  1997. }
  1998. //-----------------------------------------------------------------------------
  1999. // Remap Speed to CP Operator
  2000. //-----------------------------------------------------------------------------
  2001. class C_OP_RemapModelVolumetoCP : public CParticleOperatorInstance
  2002. {
  2003. DECLARE_PARTICLE_OPERATOR( C_OP_RemapModelVolumetoCP );
  2004. uint32 GetWrittenAttributes( void ) const
  2005. {
  2006. return 0;
  2007. }
  2008. uint32 GetReadAttributes( void ) const
  2009. {
  2010. return 0;
  2011. }
  2012. uint32 GetFilter( void ) const
  2013. {
  2014. return FILTER_CONTROL_POINTS_MASK;
  2015. }
  2016. virtual uint64 GetReadControlPointMask() const
  2017. {
  2018. return ( 1ULL << m_nInControlPointNumber ) | ( 1ULL << m_nOutControlPointNumber );
  2019. }
  2020. bool ShouldRunBeforeEmitters( void ) const
  2021. {
  2022. return true;
  2023. }
  2024. virtual void InitParams(CParticleSystemDefinition *pDef )
  2025. {
  2026. // Safety for bogus input->output feedback loop
  2027. if ( m_nInControlPointNumber == m_nOutControlPointNumber )
  2028. m_nOutControlPointNumber = -1;
  2029. }
  2030. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  2031. int m_nInControlPointNumber;
  2032. int m_nOutControlPointNumber;
  2033. float m_flInputMin;
  2034. float m_flInputMax;
  2035. float m_flOutputMin;
  2036. float m_flOutputMax;
  2037. };
  2038. DEFINE_PARTICLE_OPERATOR( C_OP_RemapModelVolumetoCP, "Remap Model Volume to CP", OPERATOR_GENERIC );
  2039. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RemapModelVolumetoCP )
  2040. DMXELEMENT_UNPACK_FIELD( "input control point", "0", int, m_nInControlPointNumber )
  2041. DMXELEMENT_UNPACK_FIELD( "input volume minimum in cubic units","0", float, m_flInputMin )
  2042. DMXELEMENT_UNPACK_FIELD( "input volume maximum in cubic units","128", float, m_flInputMax )
  2043. DMXELEMENT_UNPACK_FIELD( "output control point", "-1", int, m_nOutControlPointNumber )
  2044. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  2045. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  2046. END_PARTICLE_OPERATOR_UNPACK( C_OP_RemapModelVolumetoCP );
  2047. void C_OP_RemapModelVolumetoCP::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  2048. {
  2049. if ( m_nOutControlPointNumber >= 0 )
  2050. {
  2051. Vector vecMax, vecMin;
  2052. g_pParticleSystemMgr->Query()->GetControllingObjectOBBox( pParticles, m_nInControlPointNumber, vecMin, vecMax );
  2053. Vector vecVolume = vecMax - vecMin;
  2054. float flVolume = vecVolume.x * vecVolume.y * vecVolume.z;
  2055. flVolume = pow( flVolume, 0.33333333f );
  2056. float flOutput = RemapValClamped( flVolume, m_flInputMin, m_flInputMax, m_flOutputMin, m_flOutputMax );
  2057. pParticles->SetControlPoint( m_nOutControlPointNumber, Vector( flOutput, 0, 0 ));
  2058. }
  2059. }
  2060. //-----------------------------------------------------------------------------
  2061. // Remap Speed to CP Operator
  2062. //-----------------------------------------------------------------------------
  2063. class C_OP_RemapBoundingVolumetoCP : public CParticleOperatorInstance
  2064. {
  2065. DECLARE_PARTICLE_OPERATOR( C_OP_RemapBoundingVolumetoCP );
  2066. uint32 GetWrittenAttributes( void ) const
  2067. {
  2068. return 0;
  2069. }
  2070. uint32 GetReadAttributes( void ) const
  2071. {
  2072. return 0;
  2073. }
  2074. uint32 GetFilter( void ) const
  2075. {
  2076. return FILTER_CONTROL_POINTS_MASK;
  2077. }
  2078. virtual uint64 GetReadControlPointMask() const
  2079. {
  2080. return 1ULL << m_nOutControlPointNumber;
  2081. }
  2082. bool ShouldRunBeforeEmitters( void ) const
  2083. {
  2084. return true;
  2085. }
  2086. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  2087. int m_nOutControlPointNumber;
  2088. float m_flInputMin;
  2089. float m_flInputMax;
  2090. float m_flOutputMin;
  2091. float m_flOutputMax;
  2092. };
  2093. DEFINE_PARTICLE_OPERATOR( C_OP_RemapBoundingVolumetoCP, "Remap Particle BBox Volume to CP", OPERATOR_GENERIC );
  2094. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RemapBoundingVolumetoCP )
  2095. DMXELEMENT_UNPACK_FIELD( "input volume minimum in cubic units","0", float, m_flInputMin )
  2096. DMXELEMENT_UNPACK_FIELD( "input volume maximum in cubic units","128", float, m_flInputMax )
  2097. DMXELEMENT_UNPACK_FIELD( "output control point", "-1", int, m_nOutControlPointNumber )
  2098. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  2099. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  2100. END_PARTICLE_OPERATOR_UNPACK( C_OP_RemapBoundingVolumetoCP );
  2101. void C_OP_RemapBoundingVolumetoCP::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  2102. {
  2103. if ( m_nOutControlPointNumber >= 0 )
  2104. {
  2105. Vector vecMax, vecMin;
  2106. pParticles->GetBounds( &vecMin, &vecMax );
  2107. Vector vecVolume = vecMax - vecMin;
  2108. float flVolume = vecVolume.x * vecVolume.y * vecVolume.z;
  2109. flVolume = pow( flVolume, 0.33333333f );
  2110. float flOutput = RemapValClamped( flVolume, m_flInputMin, m_flInputMax, m_flOutputMin, m_flOutputMax );
  2111. pParticles->SetControlPoint( m_nOutControlPointNumber, Vector( flOutput, 0, 0 ));
  2112. }
  2113. }
  2114. //-----------------------------------------------------------------------------
  2115. // Remap Field Average to CP Operator
  2116. //-----------------------------------------------------------------------------
  2117. class C_OP_RemapAverageScalarValuetoCP : public CParticleOperatorInstance
  2118. {
  2119. DECLARE_PARTICLE_OPERATOR( C_OP_RemapAverageScalarValuetoCP );
  2120. uint32 GetWrittenAttributes( void ) const
  2121. {
  2122. return 0;
  2123. }
  2124. uint32 GetReadAttributes( void ) const
  2125. {
  2126. return 1 << m_nField;
  2127. }
  2128. uint32 GetFilter( void ) const
  2129. {
  2130. return FILTER_CONTROL_POINTS_MASK;
  2131. }
  2132. virtual uint64 GetReadControlPointMask() const
  2133. {
  2134. return 1ULL << m_nOutControlPointNumber;
  2135. }
  2136. bool ShouldRunBeforeEmitters( void ) const
  2137. {
  2138. return true;
  2139. }
  2140. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  2141. int m_nOutControlPointNumber;
  2142. int m_nField;
  2143. float m_flInputMin;
  2144. float m_flInputMax;
  2145. float m_flOutputMin;
  2146. float m_flOutputMax;
  2147. };
  2148. DEFINE_PARTICLE_OPERATOR( C_OP_RemapAverageScalarValuetoCP, "Remap Average Scalar Value to CP", OPERATOR_GENERIC );
  2149. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RemapAverageScalarValuetoCP )
  2150. DMXELEMENT_UNPACK_FIELD_USERDATA( "Scalar field", "3", int, m_nField, "intchoice particlefield_scalar" )
  2151. DMXELEMENT_UNPACK_FIELD( "input volume minimum","0", float, m_flInputMin )
  2152. DMXELEMENT_UNPACK_FIELD( "input volume maximum","1", float, m_flInputMax )
  2153. DMXELEMENT_UNPACK_FIELD( "output control point", "1", int, m_nOutControlPointNumber )
  2154. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  2155. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  2156. END_PARTICLE_OPERATOR_UNPACK( C_OP_RemapAverageScalarValuetoCP );
  2157. void C_OP_RemapAverageScalarValuetoCP::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  2158. {
  2159. float flAvgValue = 0.0f;
  2160. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  2161. {
  2162. const float *Field = pParticles->GetFloatAttributePtr( m_nField, i );
  2163. flAvgValue += *Field;
  2164. }
  2165. flAvgValue = ( flAvgValue / pParticles->m_nActiveParticles );
  2166. float flOutput = RemapValClamped( flAvgValue, m_flInputMin, m_flInputMax, m_flOutputMin, m_flOutputMax );
  2167. pParticles->SetControlPoint( m_nOutControlPointNumber, Vector( flOutput, 0, 0 ));
  2168. }
  2169. //-----------------------------------------------------------------------------
  2170. // Ramp Scalar Linear - changes a scalar value at a set rate
  2171. //-----------------------------------------------------------------------------
  2172. class C_OP_RampScalarLinear : public CParticleOperatorInstance
  2173. {
  2174. DECLARE_PARTICLE_OPERATOR( C_OP_RampScalarLinear );
  2175. uint32 GetWrittenAttributes( void ) const
  2176. {
  2177. return 1 << m_nField;
  2178. }
  2179. uint32 GetReadAttributes( void ) const
  2180. {
  2181. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK
  2182. | PARTICLE_ATTRIBUTE_PARTICLE_ID_MASK;
  2183. }
  2184. uint32 GetFilter( void ) const
  2185. {
  2186. return FILTER_PARAMETER_REMAPPING_MASK;
  2187. }
  2188. virtual void InitParams(CParticleSystemDefinition *pDef )
  2189. {
  2190. m_bUsesStartEnd = !( m_flStartTime_min == 0 && m_flStartTime_max == 0 && m_flEndTime_min == 1 && m_flEndTime_max == 1 && m_bProportionalOp );
  2191. // Set values to clamp against at init rather than branching inside the per-particle loop
  2192. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & ( 1 << m_nField ) )
  2193. {
  2194. m_fl4MinCmp = Four_Zeros;
  2195. m_fl4MaxCmp = Four_Ones;
  2196. }
  2197. else if ( ATTRIBUTES_WHICH_ARE_SIZE & ( 1 << m_nField ) )
  2198. {
  2199. m_fl4MinCmp = Four_Zeros;
  2200. m_fl4MaxCmp = Four_FLT_MAX;
  2201. }
  2202. else
  2203. {
  2204. m_fl4MinCmp = Four_Negative_FLT_MAX;
  2205. m_fl4MaxCmp = Four_FLT_MAX;
  2206. }
  2207. }
  2208. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  2209. float m_RateMin;
  2210. float m_RateMax;
  2211. float m_flStartTime_min;
  2212. float m_flStartTime_max;
  2213. float m_flEndTime_min;
  2214. float m_flEndTime_max;
  2215. fltx4 m_fl4MinCmp;
  2216. fltx4 m_fl4MaxCmp;
  2217. int m_nField;
  2218. bool m_bProportionalOp;
  2219. bool m_bUsesStartEnd;
  2220. };
  2221. DEFINE_PARTICLE_OPERATOR( C_OP_RampScalarLinear, "Ramp Scalar Linear Random", OPERATOR_GENERIC );
  2222. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RampScalarLinear )
  2223. DMXELEMENT_UNPACK_FIELD_USERDATA( "ramp field", "3", int, m_nField, "intchoice particlefield_scalar" )
  2224. DMXELEMENT_UNPACK_FIELD( "ramp rate min", "0", float, m_RateMin )
  2225. DMXELEMENT_UNPACK_FIELD( "ramp rate max", "0", float, m_RateMax )
  2226. DMXELEMENT_UNPACK_FIELD( "start time min", "0", float, m_flStartTime_min )
  2227. DMXELEMENT_UNPACK_FIELD( "start time max", "0", float, m_flStartTime_max )
  2228. DMXELEMENT_UNPACK_FIELD( "end time min", "1", float, m_flEndTime_min )
  2229. DMXELEMENT_UNPACK_FIELD( "end time max", "1", float, m_flEndTime_max )
  2230. DMXELEMENT_UNPACK_FIELD( "start/end proportional", "1", bool, m_bProportionalOp )
  2231. END_PARTICLE_OPERATOR_UNPACK( C_OP_RampScalarLinear )
  2232. void C_OP_RampScalarLinear::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  2233. {
  2234. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  2235. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  2236. C4IAttributeIterator pParticleId ( PARTICLE_ATTRIBUTE_PARTICLE_ID, pParticles );
  2237. CM128AttributeWriteIterator pRampField ( m_nField, pParticles) ;
  2238. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  2239. int nRandomOffset = pParticles->OperatorRandomSampleOffset();
  2240. fltx4 fl4ScaleFactor = ReplicateX4( flStrength * pParticles->m_flDt );
  2241. fltx4 fl4StartTimeMin = ReplicateX4( m_flStartTime_min );
  2242. fltx4 fl4StartTimeWidth = ReplicateX4( m_flStartTime_max - m_flStartTime_min );
  2243. fltx4 fl4EndTimeMin = ReplicateX4( m_flEndTime_min );
  2244. fltx4 fl4EndTimeWidth = ReplicateX4( m_flEndTime_max - m_flEndTime_min );
  2245. fltx4 fl4RateMin = ReplicateX4( m_RateMin );
  2246. fltx4 fl4RateWidth = ReplicateX4( m_RateMax - m_RateMin );
  2247. int nCtr = pParticles->m_nPaddedActiveParticles;
  2248. do
  2249. {
  2250. fltx4 fl4LifeDuration = *pLifeDuration;
  2251. bi32x4 fl4GoodMask = CmpGtSIMD( fl4LifeDuration, Four_Zeros );
  2252. if ( m_bUsesStartEnd )
  2253. {
  2254. fltx4 fl4LifeTime;
  2255. if ( m_bProportionalOp )
  2256. {
  2257. fl4LifeTime = MulSIMD( SubSIMD( fl4CurTime, *pCreationTime ), ReciprocalEstSIMD( fl4LifeDuration ) ); // maybe need accurate div here?
  2258. }
  2259. else
  2260. {
  2261. fl4LifeTime = SubSIMD( fl4CurTime, *pCreationTime );
  2262. }
  2263. fltx4 fl4StartTime= pParticles->RandomFloat( *pParticleId, nRandomOffset + 11);
  2264. fl4StartTime = AddSIMD( fl4StartTimeMin, MulSIMD( fl4StartTimeWidth, fl4StartTime ) );
  2265. fltx4 fl4EndTime= pParticles->RandomFloat( *pParticleId, nRandomOffset + 12);
  2266. fl4EndTime = AddSIMD( fl4EndTimeMin, MulSIMD( fl4EndTimeWidth, fl4EndTime ) );
  2267. fl4GoodMask = AndSIMD( fl4GoodMask, CmpGeSIMD( fl4LifeTime, fl4StartTime ) );
  2268. fl4GoodMask = AndSIMD( fl4GoodMask, CmpLtSIMD( fl4LifeTime, fl4EndTime ) );
  2269. }
  2270. if ( IsAnyTrue( fl4GoodMask ) )
  2271. {
  2272. fltx4 fl4Rate = AddSIMD( fl4RateMin, MulSIMD( fl4RateWidth, pParticles->RandomFloat( *pParticleId, nRandomOffset ) ) );
  2273. fltx4 fl4RampVal = AddSIMD ( *pRampField, MulSIMD( fl4Rate, fl4ScaleFactor) );
  2274. *pRampField = MaskedAssign( fl4GoodMask,
  2275. MaxSIMD( MinSIMD( fl4RampVal, m_fl4MaxCmp), m_fl4MinCmp ), *pRampField );
  2276. }
  2277. ++pCreationTime;
  2278. ++pLifeDuration;
  2279. ++pRampField;
  2280. ++pParticleId;
  2281. } while (--nCtr );
  2282. };
  2283. //-----------------------------------------------------------------------------
  2284. // Ramp Scalar Spline - ease in/out a scalar value over a curve with definable bias
  2285. //-----------------------------------------------------------------------------
  2286. class C_OP_RampScalarSpline : public CParticleOperatorInstance
  2287. {
  2288. DECLARE_PARTICLE_OPERATOR( C_OP_RampScalarSpline );
  2289. uint32 GetWrittenAttributes( void ) const
  2290. {
  2291. return 1 << m_nField;
  2292. }
  2293. uint32 GetReadAttributes( void ) const
  2294. {
  2295. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK
  2296. | PARTICLE_ATTRIBUTE_PARTICLE_ID_MASK;
  2297. }
  2298. uint32 GetFilter( void ) const
  2299. {
  2300. return FILTER_PARAMETER_REMAPPING_MASK;
  2301. }
  2302. virtual void InitParams(CParticleSystemDefinition *pDef )
  2303. {
  2304. // Set values to clamp against at init rather than branching inside the per-particle loop
  2305. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & ( 1 << m_nField ) )
  2306. {
  2307. m_fl4MinCmp = Four_Zeros;
  2308. m_fl4MaxCmp = Four_Ones;
  2309. }
  2310. else if ( ATTRIBUTES_WHICH_ARE_SIZE & ( 1 << m_nField ) )
  2311. {
  2312. m_fl4MinCmp = Four_Zeros;
  2313. m_fl4MaxCmp = Four_FLT_MAX;
  2314. }
  2315. else
  2316. {
  2317. m_fl4MinCmp = Four_Negative_FLT_MAX;
  2318. m_fl4MaxCmp = Four_FLT_MAX;
  2319. }
  2320. }
  2321. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  2322. float m_RateMin;
  2323. float m_RateMax;
  2324. float m_flStartTime_min;
  2325. float m_flStartTime_max;
  2326. float m_flEndTime_min;
  2327. float m_flEndTime_max;
  2328. float m_flBias;
  2329. fltx4 m_fl4MinCmp;
  2330. fltx4 m_fl4MaxCmp;
  2331. int m_nField;
  2332. bool m_bProportionalOp;
  2333. bool m_bEaseOut;
  2334. };
  2335. DEFINE_PARTICLE_OPERATOR( C_OP_RampScalarSpline, "Ramp Scalar Spline Random", OPERATOR_GENERIC );
  2336. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RampScalarSpline )
  2337. DMXELEMENT_UNPACK_FIELD_USERDATA( "ramp field", "3", int, m_nField, "intchoice particlefield_scalar" )
  2338. DMXELEMENT_UNPACK_FIELD( "ramp rate min", "0", float, m_RateMin )
  2339. DMXELEMENT_UNPACK_FIELD( "ramp rate max", "0", float, m_RateMax )
  2340. DMXELEMENT_UNPACK_FIELD( "start time min", "0", float, m_flStartTime_min )
  2341. DMXELEMENT_UNPACK_FIELD( "start time max", "0", float, m_flStartTime_max )
  2342. DMXELEMENT_UNPACK_FIELD( "end time min", "1", float, m_flEndTime_min )
  2343. DMXELEMENT_UNPACK_FIELD( "end time max", "1", float, m_flEndTime_max )
  2344. DMXELEMENT_UNPACK_FIELD( "start/end proportional", "1", bool, m_bProportionalOp )
  2345. DMXELEMENT_UNPACK_FIELD( "ease out", "0", bool, m_bEaseOut )
  2346. DMXELEMENT_UNPACK_FIELD( "bias", ".5", float, m_flBias )
  2347. END_PARTICLE_OPERATOR_UNPACK( C_OP_RampScalarSpline )
  2348. void C_OP_RampScalarSpline::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  2349. {
  2350. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  2351. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  2352. C4IAttributeIterator pParticleId ( PARTICLE_ATTRIBUTE_PARTICLE_ID, pParticles );
  2353. CM128AttributeWriteIterator pRampField ( m_nField, pParticles) ;
  2354. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  2355. int nRandomOffset = pParticles->OperatorRandomSampleOffset();
  2356. fltx4 fl4ScaleFactor = ReplicateX4( flStrength * pParticles->m_flDt );
  2357. fltx4 fl4StartTimeMin = ReplicateX4( m_flStartTime_min );
  2358. fltx4 fl4StartTimeWidth = ReplicateX4( m_flStartTime_max - m_flStartTime_min );
  2359. fltx4 fl4EndTimeMin = ReplicateX4( m_flEndTime_min );
  2360. fltx4 fl4EndTimeWidth = ReplicateX4( m_flEndTime_max - m_flEndTime_min );
  2361. fltx4 fl4RateMin = ReplicateX4( m_RateMin );
  2362. fltx4 fl4RateWidth = ReplicateX4( m_RateMax - m_RateMin );
  2363. int nCtr = pParticles->m_nPaddedActiveParticles;
  2364. fltx4 fl4Bias = PreCalcBiasParameter ( ReplicateX4( m_flBias ) ) ;
  2365. do
  2366. {
  2367. fltx4 fl4LifeDuration = *pLifeDuration;
  2368. bi32x4 fl4GoodMask = CmpGtSIMD( fl4LifeDuration, Four_Zeros );
  2369. fltx4 fl4LifeTime;
  2370. fltx4 fl4StartTime= pParticles->RandomFloat( *pParticleId, nRandomOffset + 11);
  2371. fl4StartTime = AddSIMD( fl4StartTimeMin, MulSIMD( fl4StartTimeWidth, fl4StartTime ) );
  2372. fltx4 fl4EndTime= pParticles->RandomFloat( *pParticleId, nRandomOffset + 12);
  2373. fl4EndTime = AddSIMD( fl4EndTimeMin, MulSIMD( fl4EndTimeWidth, fl4EndTime ) );
  2374. if ( m_bProportionalOp )
  2375. {
  2376. fl4LifeTime = MulSIMD( SubSIMD( fl4CurTime, *pCreationTime ), ReciprocalEstSIMD( fl4LifeDuration ) );
  2377. }
  2378. else
  2379. {
  2380. fl4LifeTime = SubSIMD( fl4CurTime, *pCreationTime );
  2381. }
  2382. fl4GoodMask = AndSIMD( fl4GoodMask, CmpGeSIMD( fl4LifeTime, fl4StartTime ) );
  2383. fl4GoodMask = AndSIMD( fl4GoodMask, CmpLtSIMD( fl4LifeTime, fl4EndTime ) );
  2384. if ( IsAnyTrue( fl4GoodMask ) )
  2385. {
  2386. fltx4 fl4Rate = AddSIMD( fl4RateMin, MulSIMD( fl4RateWidth, pParticles->RandomFloat( *pParticleId, nRandomOffset ) ) );
  2387. fltx4 ooInRange = DivSIMD( Four_Ones, AddSIMD (Four_Epsilons, SubSIMD( fl4EndTime, fl4StartTime ) ) );
  2388. fltx4 fl4Spline = MulSIMD( SubSIMD( fl4LifeTime, fl4StartTime ), ooInRange );
  2389. fl4Spline = MinSIMD( Four_Ones, MaxSIMD( Four_Zeros, fl4Spline ) );
  2390. if ( m_bEaseOut )
  2391. {
  2392. bi32x4 fl4EaseOutMask = CmpGtSIMD( fl4Spline, Four_PointFives );
  2393. fl4Spline = MaskedAssign( fl4EaseOutMask, SubSIMD( Four_Ones, fl4Spline), fl4Spline );
  2394. fl4Spline = MulSIMD( Four_Twos, fl4Spline );
  2395. }
  2396. fl4Spline = BiasSIMD( fl4Spline, fl4Bias );
  2397. fltx4 fl4RampVal = AddSIMD ( *pRampField, MulSIMD( fl4Rate, MulSIMD( fl4Spline, fl4ScaleFactor ) ) );
  2398. *pRampField = MaskedAssign( fl4GoodMask,
  2399. MaxSIMD( MinSIMD( fl4RampVal, m_fl4MaxCmp), m_fl4MinCmp ), *pRampField );
  2400. }
  2401. ++pCreationTime;
  2402. ++pLifeDuration;
  2403. ++pRampField;
  2404. ++pParticleId;
  2405. } while (--nCtr );
  2406. };
  2407. //-----------------------------------------------------------------------------
  2408. // Ramp Scalar Linear Simple - linear ramp of scalar value - fast version
  2409. //-----------------------------------------------------------------------------
  2410. class C_OP_RampScalarLinearSimple : public CParticleOperatorInstance
  2411. {
  2412. DECLARE_PARTICLE_OPERATOR( C_OP_RampScalarLinearSimple );
  2413. uint32 GetWrittenAttributes( void ) const
  2414. {
  2415. return 1 << m_nField;
  2416. }
  2417. uint32 GetReadAttributes( void ) const
  2418. {
  2419. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK;
  2420. }
  2421. uint32 GetFilter( void ) const
  2422. {
  2423. return FILTER_PARAMETER_REMAPPING_MASK;
  2424. }
  2425. virtual void InitParams(CParticleSystemDefinition *pDef )
  2426. {
  2427. // Set values to clamp against at init rather than branching inside the per-particle loop
  2428. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & ( 1 << m_nField ) )
  2429. {
  2430. m_fl4MinCmp = Four_Zeros;
  2431. m_fl4MaxCmp = Four_Ones;
  2432. }
  2433. else if ( ATTRIBUTES_WHICH_ARE_SIZE & ( 1 << m_nField ) )
  2434. {
  2435. m_fl4MinCmp = Four_Zeros;
  2436. m_fl4MaxCmp = Four_FLT_MAX;
  2437. }
  2438. else
  2439. {
  2440. m_fl4MinCmp = Four_Negative_FLT_MAX;
  2441. m_fl4MaxCmp = Four_FLT_MAX;
  2442. }
  2443. }
  2444. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  2445. float m_Rate;
  2446. float m_flStartTime;
  2447. float m_flEndTime;
  2448. fltx4 m_fl4MinCmp;
  2449. fltx4 m_fl4MaxCmp;
  2450. int m_nField;
  2451. };
  2452. DEFINE_PARTICLE_OPERATOR( C_OP_RampScalarLinearSimple, "Ramp Scalar Linear Simple", OPERATOR_GENERIC );
  2453. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RampScalarLinearSimple )
  2454. DMXELEMENT_UNPACK_FIELD_USERDATA( "ramp field", "3", int, m_nField, "intchoice particlefield_scalar" )
  2455. DMXELEMENT_UNPACK_FIELD( "ramp rate", "0", float, m_Rate )
  2456. DMXELEMENT_UNPACK_FIELD( "start time", "0", float, m_flStartTime )
  2457. DMXELEMENT_UNPACK_FIELD( "end time", "1", float, m_flEndTime )
  2458. END_PARTICLE_OPERATOR_UNPACK( C_OP_RampScalarLinearSimple )
  2459. void C_OP_RampScalarLinearSimple::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  2460. {
  2461. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  2462. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  2463. CM128AttributeWriteIterator pRampField ( m_nField, pParticles) ;
  2464. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  2465. fltx4 fl4ScaleFactor = ReplicateX4( flStrength * pParticles->m_flDt );
  2466. fltx4 fl4StartTime = ReplicateX4( m_flStartTime );
  2467. fltx4 fl4EndTime = ReplicateX4( m_flEndTime );
  2468. fltx4 fl4Rate = ReplicateX4( m_Rate );
  2469. int nCtr = pParticles->m_nPaddedActiveParticles;
  2470. do
  2471. {
  2472. fltx4 fl4LifeDuration = *pLifeDuration;
  2473. bi32x4 fl4GoodMask = CmpGtSIMD( fl4LifeDuration, Four_Zeros );
  2474. fltx4 fl4LifeTime;
  2475. fl4LifeTime = MulSIMD( SubSIMD( fl4CurTime, *pCreationTime ), ReciprocalEstSIMD( fl4LifeDuration ) );
  2476. fl4GoodMask = AndSIMD( fl4GoodMask, CmpGeSIMD( fl4LifeTime, fl4StartTime ) );
  2477. fl4GoodMask = AndSIMD( fl4GoodMask, CmpLtSIMD( fl4LifeTime, fl4EndTime ) );
  2478. if ( IsAnyTrue( fl4GoodMask ) )
  2479. {
  2480. fltx4 fl4RampVal = AddSIMD ( *pRampField, MulSIMD( fl4Rate, fl4ScaleFactor ) );
  2481. *pRampField = MaskedAssign( fl4GoodMask,
  2482. MaxSIMD( MinSIMD( fl4RampVal, m_fl4MaxCmp), m_fl4MinCmp ), *pRampField );
  2483. }
  2484. ++pCreationTime;
  2485. ++pLifeDuration;
  2486. ++pRampField;
  2487. } while (--nCtr );
  2488. };
  2489. //-----------------------------------------------------------------------------
  2490. // Ramp Scalar Spline Simple - ease in/out a scalar value - fast version
  2491. //-----------------------------------------------------------------------------
  2492. class C_OP_RampScalarSplineSimple : public CParticleOperatorInstance
  2493. {
  2494. DECLARE_PARTICLE_OPERATOR( C_OP_RampScalarSplineSimple );
  2495. uint32 GetWrittenAttributes( void ) const
  2496. {
  2497. return 1 << m_nField;
  2498. }
  2499. uint32 GetReadAttributes( void ) const
  2500. {
  2501. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK;
  2502. }
  2503. uint32 GetFilter( void ) const
  2504. {
  2505. return FILTER_PARAMETER_REMAPPING_MASK;
  2506. }
  2507. virtual void InitParams(CParticleSystemDefinition *pDef )
  2508. {
  2509. // Set values to clamp against at init rather than branching inside the per-particle loop
  2510. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & ( 1 << m_nField ) )
  2511. {
  2512. m_fl4MinCmp = Four_Zeros;
  2513. m_fl4MaxCmp = Four_Ones;
  2514. }
  2515. else if ( ATTRIBUTES_WHICH_ARE_SIZE & ( 1 << m_nField ) )
  2516. {
  2517. m_fl4MinCmp = Four_Zeros;
  2518. m_fl4MaxCmp = Four_FLT_MAX;
  2519. }
  2520. else
  2521. {
  2522. m_fl4MinCmp = Four_Negative_FLT_MAX;
  2523. m_fl4MaxCmp = Four_FLT_MAX;
  2524. }
  2525. }
  2526. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  2527. float m_Rate;
  2528. float m_flStartTime;
  2529. float m_flEndTime;
  2530. fltx4 m_fl4MinCmp;
  2531. fltx4 m_fl4MaxCmp;
  2532. int m_nField;
  2533. bool m_bEaseOut;
  2534. };
  2535. DEFINE_PARTICLE_OPERATOR( C_OP_RampScalarSplineSimple, "Ramp Scalar Spline Simple", OPERATOR_GENERIC );
  2536. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RampScalarSplineSimple )
  2537. DMXELEMENT_UNPACK_FIELD_USERDATA( "ramp field", "3", int, m_nField, "intchoice particlefield_scalar" )
  2538. DMXELEMENT_UNPACK_FIELD( "ramp rate", "0", float, m_Rate )
  2539. DMXELEMENT_UNPACK_FIELD( "start time", "0", float, m_flStartTime )
  2540. DMXELEMENT_UNPACK_FIELD( "end time", "1", float, m_flEndTime )
  2541. DMXELEMENT_UNPACK_FIELD( "ease out", "0", bool, m_bEaseOut )
  2542. END_PARTICLE_OPERATOR_UNPACK( C_OP_RampScalarSplineSimple )
  2543. void C_OP_RampScalarSplineSimple::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  2544. {
  2545. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  2546. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  2547. CM128AttributeWriteIterator pRampField ( m_nField, pParticles) ;
  2548. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  2549. fltx4 fl4ScaleFactor = ReplicateX4( flStrength * pParticles->m_flDt );
  2550. fltx4 fl4StartTime = ReplicateX4( m_flStartTime );
  2551. fltx4 fl4EndTime = ReplicateX4( m_flEndTime );
  2552. fltx4 fl4Rate = ReplicateX4( m_Rate );
  2553. int nCtr = pParticles->m_nPaddedActiveParticles;
  2554. do
  2555. {
  2556. fltx4 fl4LifeDuration = *pLifeDuration;
  2557. bi32x4 fl4GoodMask = CmpGtSIMD( fl4LifeDuration, Four_Zeros );
  2558. fltx4 fl4LifeTime;
  2559. fl4LifeTime = MulSIMD( SubSIMD( fl4CurTime, *pCreationTime ), ReciprocalEstSIMD( fl4LifeDuration ) );
  2560. fl4GoodMask = AndSIMD( fl4GoodMask, CmpGeSIMD( fl4LifeTime, fl4StartTime ) );
  2561. fl4GoodMask = AndSIMD( fl4GoodMask, CmpLtSIMD( fl4LifeTime, fl4EndTime ) );
  2562. if ( IsAnyTrue( fl4GoodMask ) )
  2563. {
  2564. fltx4 ooInRange = DivSIMD( Four_Ones, AddSIMD (Four_Epsilons, SubSIMD( fl4EndTime, fl4StartTime ) ) );
  2565. fltx4 fl4Spline = MulSIMD( SubSIMD( fl4LifeTime, fl4StartTime ), ooInRange );
  2566. fl4Spline = MinSIMD( Four_Ones, MaxSIMD( Four_Zeros, fl4Spline ) );
  2567. if ( m_bEaseOut )
  2568. {
  2569. bi32x4 fl4EaseOutMask = CmpGtSIMD( fl4Spline, Four_PointFives );
  2570. fl4Spline = MaskedAssign( fl4EaseOutMask, SubSIMD( Four_Ones, fl4Spline), fl4Spline );
  2571. fl4Spline = MulSIMD( Four_Twos, fl4Spline );
  2572. }
  2573. fl4Spline = SimpleSpline( fl4Spline );
  2574. fltx4 fl4RampVal = AddSIMD ( *pRampField, MulSIMD( fl4Rate, MulSIMD( fl4Spline, fl4ScaleFactor ) ) );
  2575. *pRampField = MaskedAssign( fl4GoodMask,
  2576. MaxSIMD( MinSIMD( fl4RampVal, m_fl4MaxCmp), m_fl4MinCmp ), *pRampField );
  2577. }
  2578. ++pCreationTime;
  2579. ++pLifeDuration;
  2580. ++pRampField;
  2581. } while (--nCtr );
  2582. };
  2583. //-----------------------------------------------------------------------------
  2584. // noise Operator
  2585. //-----------------------------------------------------------------------------
  2586. class C_OP_Noise : public CParticleOperatorInstance
  2587. {
  2588. DECLARE_PARTICLE_OPERATOR( C_OP_Noise );
  2589. uint32 GetWrittenAttributes( void ) const
  2590. {
  2591. return 1 << m_nFieldOutput;
  2592. }
  2593. uint32 GetReadAttributes( void ) const
  2594. {
  2595. return PARTICLE_ATTRIBUTE_XYZ_MASK;
  2596. }
  2597. uint32 GetFilter( void ) const
  2598. {
  2599. return FILTER_PARAMETER_REMAPPING_MASK;
  2600. }
  2601. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  2602. int m_nFieldOutput;
  2603. float m_flOutputMin;
  2604. float m_flOutputMax;
  2605. fltx4 m_fl4NoiseScale;
  2606. bool m_bAdditive;
  2607. };
  2608. DEFINE_PARTICLE_OPERATOR( C_OP_Noise, "Noise Scalar", OPERATOR_GENERIC );
  2609. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_Noise )
  2610. DMXELEMENT_UNPACK_FLTX4( "noise coordinate scale", "0.1", m_fl4NoiseScale)
  2611. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "3", int, m_nFieldOutput, "intchoice particlefield_scalar" )
  2612. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  2613. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  2614. DMXELEMENT_UNPACK_FIELD( "additive","0", bool, m_bAdditive )
  2615. END_PARTICLE_OPERATOR_UNPACK( C_OP_Noise );
  2616. void C_OP_Noise::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  2617. {
  2618. CM128AttributeWriteIterator pAttr( m_nFieldOutput, pParticles );
  2619. C4VAttributeIterator pXYZ( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  2620. fltx4 CoordScale=m_fl4NoiseScale;
  2621. float fMin = m_flOutputMin;
  2622. float fMax = m_flOutputMax;
  2623. if ( ATTRIBUTES_WHICH_ARE_ANGLES & (1 << m_nFieldOutput ) )
  2624. {
  2625. fMin *= ( M_PI / 180.0f );
  2626. fMax *= ( M_PI / 180.0f );
  2627. }
  2628. // calculate coefficients. noise retuns -1..1
  2629. fltx4 ValueScale=ReplicateX4( 0.5*(fMax-fMin ) );
  2630. fltx4 ValueBase=ReplicateX4( fMin + 0.5*( fMax - fMin ) );
  2631. int nActive = pParticles->m_nPaddedActiveParticles;
  2632. if ( m_bAdditive )
  2633. {
  2634. ValueBase = MulSIMD( ValueBase, ReplicateX4( pParticles->m_flDt ) );
  2635. ValueScale = MulSIMD( ValueScale, ReplicateX4( pParticles->m_flDt ) );
  2636. do
  2637. {
  2638. FourVectors Coord = *pXYZ;
  2639. Coord *= CoordScale;
  2640. *( pAttr )=AddSIMD( *( pAttr ), AddSIMD( ValueBase, MulSIMD( ValueScale, NoiseSIMD( Coord ) ) ) );
  2641. ++pAttr;
  2642. ++pXYZ;
  2643. } while( --nActive );
  2644. }
  2645. else
  2646. {
  2647. do
  2648. {
  2649. FourVectors Coord = *pXYZ;
  2650. Coord *= CoordScale;
  2651. *( pAttr )=AddSIMD( ValueBase, MulSIMD( ValueScale, NoiseSIMD( Coord ) ) );
  2652. ++pAttr;
  2653. ++pXYZ;
  2654. } while( --nActive );
  2655. }
  2656. }
  2657. //-----------------------------------------------------------------------------
  2658. // vector noise Operator
  2659. //-----------------------------------------------------------------------------
  2660. class C_OP_VectorNoise : public CParticleOperatorInstance
  2661. {
  2662. DECLARE_PARTICLE_OPERATOR( C_OP_VectorNoise );
  2663. uint32 GetWrittenAttributes( void ) const
  2664. {
  2665. return 1 << m_nFieldOutput;
  2666. }
  2667. uint32 GetReadAttributes( void ) const
  2668. {
  2669. return PARTICLE_ATTRIBUTE_XYZ_MASK;
  2670. }
  2671. uint32 GetFilter( void ) const
  2672. {
  2673. return FILTER_PARAMETER_REMAPPING_MASK;
  2674. }
  2675. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  2676. int m_nFieldOutput;
  2677. Vector m_vecOutputMin;
  2678. Vector m_vecOutputMax;
  2679. fltx4 m_fl4NoiseScale;
  2680. bool m_bAdditive;
  2681. };
  2682. DEFINE_PARTICLE_OPERATOR( C_OP_VectorNoise, "Noise Vector", OPERATOR_GENERIC );
  2683. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_VectorNoise )
  2684. DMXELEMENT_UNPACK_FLTX4( "noise coordinate scale", "0.1", m_fl4NoiseScale)
  2685. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "6", int, m_nFieldOutput, "intchoice particlefield_vector" )
  2686. DMXELEMENT_UNPACK_FIELD( "output minimum","0 0 0", Vector, m_vecOutputMin )
  2687. DMXELEMENT_UNPACK_FIELD( "output maximum","1 1 1", Vector, m_vecOutputMax )
  2688. DMXELEMENT_UNPACK_FIELD( "additive", "0", bool, m_bAdditive)
  2689. END_PARTICLE_OPERATOR_UNPACK( C_OP_VectorNoise );
  2690. void C_OP_VectorNoise::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  2691. {
  2692. C4VAttributeWriteIterator pAttr( m_nFieldOutput, pParticles );
  2693. C4VAttributeIterator pXYZ( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  2694. fltx4 CoordScale = m_fl4NoiseScale;
  2695. // calculate coefficients. noise retuns -1..1
  2696. fltx4 ValueScaleX = ReplicateX4( 0.5*(m_vecOutputMax.x-m_vecOutputMin.x ) );
  2697. fltx4 ValueBaseX = ReplicateX4(m_vecOutputMin.x+0.5*( m_vecOutputMax.x-m_vecOutputMin.x ) );
  2698. fltx4 ValueScaleY = ReplicateX4( 0.5*(m_vecOutputMax.y-m_vecOutputMin.y ) );
  2699. fltx4 ValueBaseY = ReplicateX4(m_vecOutputMin.y+0.5*( m_vecOutputMax.y-m_vecOutputMin.y ) );
  2700. fltx4 ValueScaleZ = ReplicateX4( 0.5*(m_vecOutputMax.z-m_vecOutputMin.z ) );
  2701. fltx4 ValueBaseZ = ReplicateX4(m_vecOutputMin.z+0.5*( m_vecOutputMax.z-m_vecOutputMin.z ) );
  2702. FourVectors ofs_y;
  2703. ofs_y.DuplicateVector( Vector( 100000.5, 300000.25, 9000000.75 ) );
  2704. FourVectors ofs_z;
  2705. ofs_z.DuplicateVector( Vector( 110000.25, 310000.75, 9100000.5 ) );
  2706. int nActive = pParticles->m_nActiveParticles;
  2707. if ( m_bAdditive )
  2708. {
  2709. fltx4 fl4_dt = ReplicateX4( pParticles->m_flDt );
  2710. for( int i=0; i < nActive; i+=4 )
  2711. {
  2712. FourVectors Coord = *pXYZ;
  2713. Coord *= CoordScale;
  2714. pAttr->x=AddSIMD( pAttr->x, MulSIMD( fl4_dt, AddSIMD( ValueBaseX, MulSIMD( ValueScaleX, NoiseSIMD( Coord ) ) ) ) );
  2715. Coord += ofs_y;
  2716. pAttr->y=AddSIMD( pAttr->y, MulSIMD( fl4_dt, AddSIMD( ValueBaseY, MulSIMD( ValueScaleY, NoiseSIMD( Coord ) ) ) ) );
  2717. Coord += ofs_z;
  2718. pAttr->z=AddSIMD( pAttr->z, MulSIMD( fl4_dt, AddSIMD( ValueBaseZ, MulSIMD( ValueScaleZ, NoiseSIMD( Coord ) ) ) ) );
  2719. ++pAttr;
  2720. ++pXYZ;
  2721. }
  2722. }
  2723. else
  2724. {
  2725. for( int i=0; i < nActive; i+=4 )
  2726. {
  2727. FourVectors Coord = *pXYZ;
  2728. Coord *= CoordScale;
  2729. pAttr->x=AddSIMD( ValueBaseX, MulSIMD( ValueScaleX, NoiseSIMD( Coord ) ) );
  2730. Coord += ofs_y;
  2731. pAttr->y=AddSIMD( ValueBaseY, MulSIMD( ValueScaleY, NoiseSIMD( Coord ) ) );
  2732. Coord += ofs_z;
  2733. pAttr->z=AddSIMD( ValueBaseZ, MulSIMD( ValueScaleZ, NoiseSIMD( Coord ) ) );
  2734. ++pAttr;
  2735. ++pXYZ;
  2736. }
  2737. }
  2738. }
  2739. //-----------------------------------------------------------------------------
  2740. // Decay Operator (Lifespan limiter - kills dead particles)
  2741. //-----------------------------------------------------------------------------
  2742. class C_OP_Decay : public CParticleOperatorInstance
  2743. {
  2744. DECLARE_PARTICLE_OPERATOR( C_OP_Decay );
  2745. uint32 GetWrittenAttributes( void ) const
  2746. {
  2747. return 0;
  2748. }
  2749. uint32 GetReadAttributes( void ) const
  2750. {
  2751. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK;
  2752. }
  2753. uint32 GetFilter( void ) const
  2754. {
  2755. return FILTER_LIFE_DURATION_MASK;
  2756. }
  2757. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  2758. };
  2759. DEFINE_PARTICLE_OPERATOR( C_OP_Decay, "Lifespan Decay", OPERATOR_GENERIC );
  2760. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_Decay )
  2761. END_PARTICLE_OPERATOR_UNPACK( C_OP_Decay )
  2762. void C_OP_Decay::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  2763. {
  2764. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  2765. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  2766. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  2767. int nLimit = pParticles->m_nPaddedActiveParticles << 2;
  2768. for ( int i = 0; i < nLimit; i+= 4 )
  2769. {
  2770. fltx4 fl4LifeDuration = *pLifeDuration;
  2771. bi32x4 fl4KillMask = CmpLeSIMD( fl4LifeDuration, Four_Zeros );
  2772. fltx4 fl4Age = SubSIMD( fl4CurTime, *pCreationTime );
  2773. //test for low framerate problems
  2774. //fltx4 fl4Dt = ReplicateX4( pParticles->m_flDt );
  2775. //fl4Age = AddSIMD( fl4Age, fl4Dt );
  2776. //endtest
  2777. fl4KillMask = OrSIMD( fl4KillMask, CmpGeSIMD( fl4Age, fl4LifeDuration ) );
  2778. if ( IsAnyTrue( fl4KillMask ) )
  2779. {
  2780. // not especially pretty - we need to kill some particles.
  2781. int nMask = TestSignSIMD( fl4KillMask );
  2782. if ( nMask & 1 )
  2783. pParticles->KillParticle( i );
  2784. if ( nMask & 2 )
  2785. pParticles->KillParticle( i + 1 );
  2786. if ( nMask & 4 )
  2787. pParticles->KillParticle( i + 2 );
  2788. if ( nMask & 8 )
  2789. pParticles->KillParticle( i + 3 );
  2790. }
  2791. ++pCreationTime;
  2792. ++pLifeDuration;
  2793. }
  2794. }
  2795. //-----------------------------------------------------------------------------
  2796. // Lifespan Minimum Velocity Decay Operator (kills particles if they cease moving)
  2797. //-----------------------------------------------------------------------------
  2798. class C_OP_VelocityDecay : public CParticleOperatorInstance
  2799. {
  2800. DECLARE_PARTICLE_OPERATOR( C_OP_VelocityDecay );
  2801. float m_flMinVelocity;
  2802. uint32 GetWrittenAttributes( void ) const
  2803. {
  2804. return 0;
  2805. }
  2806. uint32 GetReadAttributes( void ) const
  2807. {
  2808. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  2809. }
  2810. uint32 GetFilter( void ) const
  2811. {
  2812. return FILTER_LIFE_DURATION_MASK;
  2813. }
  2814. virtual void InitParams(CParticleSystemDefinition *pDef )
  2815. {
  2816. m_flMinVelocity = MAX( MIN_PARTICLE_SPEED, m_flMinVelocity );
  2817. }
  2818. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  2819. };
  2820. DEFINE_PARTICLE_OPERATOR( C_OP_VelocityDecay, "Lifespan Minimum Velocity Decay", OPERATOR_GENERIC );
  2821. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_VelocityDecay )
  2822. DMXELEMENT_UNPACK_FIELD( "minimum velocity","1", float, m_flMinVelocity )
  2823. END_PARTICLE_OPERATOR_UNPACK( C_OP_VelocityDecay )
  2824. void C_OP_VelocityDecay::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  2825. {
  2826. fltx4 fl4MinVelocity = ReplicateX4( m_flMinVelocity );
  2827. fltx4 fl4Dt = ReplicateX4( pParticles->m_flDt );
  2828. fl4Dt = ReciprocalEstSIMD( fl4Dt );
  2829. C4VAttributeIterator pXYZ( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  2830. C4VAttributeIterator pPrevXYZ( PARTICLE_ATTRIBUTE_PREV_XYZ, pParticles );
  2831. int nLimit = pParticles->m_nPaddedActiveParticles << 2;
  2832. for ( int i = 0; i < nLimit; i+= 4 )
  2833. {
  2834. bi32x4 fl4KillMask = CmpLeSIMD( MulSIMD ( (*pXYZ - *pPrevXYZ).length(), fl4Dt ), fl4MinVelocity );
  2835. if ( IsAnyTrue( fl4KillMask ) )
  2836. {
  2837. // not especially pretty - we need to kill some particles.
  2838. int nMask = TestSignSIMD( fl4KillMask );
  2839. if ( nMask & 1 )
  2840. pParticles->KillParticle( i );
  2841. if ( nMask & 2 )
  2842. pParticles->KillParticle( i + 1 );
  2843. if ( nMask & 4 )
  2844. pParticles->KillParticle( i + 2 );
  2845. if ( nMask & 8 )
  2846. pParticles->KillParticle( i + 3 );
  2847. }
  2848. ++pXYZ;
  2849. ++pPrevXYZ;
  2850. }
  2851. }
  2852. //-----------------------------------------------------------------------------
  2853. // Lifespan Minimum Alpha Decay Operator (kills particles if they cross alpha boundary)
  2854. //-----------------------------------------------------------------------------
  2855. class C_OP_AlphaDecay : public CParticleOperatorInstance
  2856. {
  2857. DECLARE_PARTICLE_OPERATOR( C_OP_AlphaDecay );
  2858. float m_flMinAlpha;
  2859. uint32 GetWrittenAttributes( void ) const
  2860. {
  2861. return 0;
  2862. }
  2863. uint32 GetReadAttributes( void ) const
  2864. {
  2865. return PARTICLE_ATTRIBUTE_ALPHA_MASK | PARTICLE_ATTRIBUTE_ALPHA2_MASK;
  2866. }
  2867. uint32 GetFilter( void ) const
  2868. {
  2869. return FILTER_LIFE_DURATION_MASK;
  2870. }
  2871. virtual void InitParams(CParticleSystemDefinition *pDef )
  2872. {
  2873. m_flMinAlpha = MAX( 0, m_flMinAlpha );
  2874. }
  2875. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  2876. };
  2877. DEFINE_PARTICLE_OPERATOR( C_OP_AlphaDecay, "Lifespan Minimum Alpha Decay", OPERATOR_GENERIC );
  2878. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_AlphaDecay )
  2879. DMXELEMENT_UNPACK_FIELD( "minimum alpha","0", float, m_flMinAlpha )
  2880. END_PARTICLE_OPERATOR_UNPACK( C_OP_AlphaDecay )
  2881. void C_OP_AlphaDecay::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  2882. {
  2883. fltx4 fl4MinAlpha = ReplicateX4( m_flMinAlpha + FLT_EPSILON );
  2884. CM128AttributeIterator pAlpha( PARTICLE_ATTRIBUTE_ALPHA, pParticles );
  2885. CM128AttributeIterator pAlpha2( PARTICLE_ATTRIBUTE_ALPHA2, pParticles );
  2886. int nLimit = pParticles->m_nPaddedActiveParticles << 2;
  2887. for ( int i = 0; i < nLimit; i+= 4 )
  2888. {
  2889. bi32x4 fl4KillMask = CmpLeSIMD( MulSIMD( *pAlpha, *pAlpha2 ), fl4MinAlpha );
  2890. if ( IsAnyTrue( fl4KillMask ) )
  2891. {
  2892. // not especially pretty - we need to kill some particles.
  2893. int nMask = TestSignSIMD( fl4KillMask );
  2894. if ( nMask & 1 )
  2895. pParticles->KillParticle( i );
  2896. if ( nMask & 2 )
  2897. pParticles->KillParticle( i + 1 );
  2898. if ( nMask & 4 )
  2899. pParticles->KillParticle( i + 2 );
  2900. if ( nMask & 8 )
  2901. pParticles->KillParticle( i + 3 );
  2902. }
  2903. ++pAlpha;
  2904. ++pAlpha2;
  2905. }
  2906. }
  2907. //-----------------------------------------------------------------------------
  2908. // Lifespan Minimum Radius Decay Operator (kills particles if they cross radius boundary)
  2909. //-----------------------------------------------------------------------------
  2910. class C_OP_RadiusDecay : public CParticleOperatorInstance
  2911. {
  2912. DECLARE_PARTICLE_OPERATOR( C_OP_RadiusDecay );
  2913. float m_flMinRadius;
  2914. uint32 GetWrittenAttributes( void ) const
  2915. {
  2916. return 0;
  2917. }
  2918. uint32 GetReadAttributes( void ) const
  2919. {
  2920. return PARTICLE_ATTRIBUTE_RADIUS_MASK;
  2921. }
  2922. uint32 GetFilter( void ) const
  2923. {
  2924. return FILTER_LIFE_DURATION_MASK;
  2925. }
  2926. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  2927. };
  2928. DEFINE_PARTICLE_OPERATOR( C_OP_RadiusDecay, "Lifespan Minimum Radius Decay", OPERATOR_GENERIC );
  2929. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RadiusDecay )
  2930. DMXELEMENT_UNPACK_FIELD( "minimum radius","1", float, m_flMinRadius )
  2931. END_PARTICLE_OPERATOR_UNPACK( C_OP_RadiusDecay )
  2932. void C_OP_RadiusDecay::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  2933. {
  2934. fltx4 fl4MinRadius = ReplicateX4( m_flMinRadius );
  2935. CM128AttributeIterator pRadius( PARTICLE_ATTRIBUTE_RADIUS, pParticles );
  2936. int nLimit = pParticles->m_nPaddedActiveParticles << 2;
  2937. for ( int i = 0; i < nLimit; i+= 4 )
  2938. {
  2939. bi32x4 fl4KillMask = CmpLeSIMD( *pRadius, fl4MinRadius );
  2940. if ( IsAnyTrue( fl4KillMask ) )
  2941. {
  2942. // not especially pretty - we need to kill some particles.
  2943. int nMask = TestSignSIMD( fl4KillMask );
  2944. if ( nMask & 1 )
  2945. pParticles->KillParticle( i );
  2946. if ( nMask & 2 )
  2947. pParticles->KillParticle( i + 1 );
  2948. if ( nMask & 4 )
  2949. pParticles->KillParticle( i + 2 );
  2950. if ( nMask & 8 )
  2951. pParticles->KillParticle( i + 3 );
  2952. }
  2953. ++pRadius;
  2954. }
  2955. }
  2956. //-----------------------------------------------------------------------------
  2957. // Decay Maintain Count Operator (Kills particles if they go beyond specified number)
  2958. //-----------------------------------------------------------------------------
  2959. class C_OP_DecayMaintainCount : public CParticleOperatorInstance
  2960. {
  2961. DECLARE_PARTICLE_OPERATOR( C_OP_DecayMaintainCount );
  2962. struct C_OP_MaintainCountContext_t
  2963. {
  2964. int m_nPendingDecay;
  2965. };
  2966. uint32 GetWrittenAttributes( void ) const
  2967. {
  2968. return PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK;
  2969. }
  2970. uint32 GetReadAttributes( void ) const
  2971. {
  2972. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  2973. }
  2974. uint32 GetFilter( void ) const
  2975. {
  2976. return FILTER_LIFE_DURATION_MASK;
  2977. }
  2978. virtual void InitParams(CParticleSystemDefinition *pDef )
  2979. {
  2980. m_nScaleControlPoint = clamp( m_nScaleControlPoint, -1, MAX_PARTICLE_CONTROL_POINTS );
  2981. m_nScaleControlPointField = clamp( m_nScaleControlPointField, 0, 2 );
  2982. }
  2983. size_t GetRequiredContextBytes( void ) const
  2984. {
  2985. return sizeof( C_OP_MaintainCountContext_t );
  2986. }
  2987. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  2988. {
  2989. C_OP_MaintainCountContext_t *pCtx=reinterpret_cast<C_OP_MaintainCountContext_t *>( pContext );
  2990. pCtx->m_nPendingDecay = 0;
  2991. }
  2992. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  2993. int m_nParticlesToMaintain;
  2994. int m_nScaleControlPoint;
  2995. int m_nScaleControlPointField;
  2996. float m_flDecayDelay;
  2997. };
  2998. DEFINE_PARTICLE_OPERATOR( C_OP_DecayMaintainCount, "Lifespan Maintain Count Decay", OPERATOR_GENERIC );
  2999. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_DecayMaintainCount )
  3000. DMXELEMENT_UNPACK_FIELD( "count to maintain", "100", int, m_nParticlesToMaintain )
  3001. DMXELEMENT_UNPACK_FIELD( "decay delay", "0", float, m_flDecayDelay )
  3002. DMXELEMENT_UNPACK_FIELD( "maintain count scale control point", "-1", int, m_nScaleControlPoint )
  3003. DMXELEMENT_UNPACK_FIELD( "maintain count scale control point field", "0", int, m_nScaleControlPointField )
  3004. END_PARTICLE_OPERATOR_UNPACK( C_OP_DecayMaintainCount )
  3005. void C_OP_DecayMaintainCount::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  3006. {
  3007. C_OP_MaintainCountContext_t *pCtx=reinterpret_cast<C_OP_MaintainCountContext_t *>( pContext );
  3008. int nActualParticlesToMaintain = m_nParticlesToMaintain;
  3009. if ( ( m_nScaleControlPoint >= 0 ) )
  3010. {
  3011. nActualParticlesToMaintain = MIN( pParticles->m_pDef->m_nMaxParticles, m_nParticlesToMaintain * pParticles->GetControlPointAtCurrentTime(m_nScaleControlPoint)[m_nScaleControlPointField] );
  3012. }
  3013. int nParticleKillQueue = 0;
  3014. if ( pParticles->m_nActiveParticles > nActualParticlesToMaintain )
  3015. {
  3016. nParticleKillQueue = pParticles->m_nActiveParticles - nActualParticlesToMaintain;
  3017. nParticleKillQueue -= pCtx->m_nPendingDecay;
  3018. }
  3019. //else
  3020. //{
  3021. // pCtx->m_nPendingDecay = 0;
  3022. //}
  3023. const float *pCreationTime;
  3024. float *pLifeDuration;
  3025. float flLifeTime;
  3026. // FIXME: SSE-ize
  3027. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  3028. {
  3029. pCreationTime = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, i );
  3030. pLifeDuration = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_LIFE_DURATION, i );
  3031. flLifeTime = pParticles->m_flCurTime - *pCreationTime;
  3032. if ( flLifeTime > *pLifeDuration )
  3033. {
  3034. pParticles->KillParticle( i );
  3035. nParticleKillQueue--;
  3036. pCtx->m_nPendingDecay = MAX( 0, pCtx->m_nPendingDecay - 1 );
  3037. }
  3038. else if ( nParticleKillQueue > 0 && ( *pLifeDuration > pParticles->m_flCurTime + m_flDecayDelay ) )
  3039. {
  3040. *pLifeDuration = pParticles->m_flCurTime + m_flDecayDelay - *pCreationTime;
  3041. nParticleKillQueue--;
  3042. pCtx->m_nPendingDecay++;
  3043. }
  3044. }
  3045. }
  3046. //-----------------------------------------------------------------------------
  3047. // Random Cull Operator - Randomly culls particles before their lifespan
  3048. //-----------------------------------------------------------------------------
  3049. class C_OP_Cull : public CParticleOperatorInstance
  3050. {
  3051. float m_flCullPerc;
  3052. float m_flCullStart;
  3053. float m_flCullEnd;
  3054. float m_flCullExp;
  3055. DECLARE_PARTICLE_OPERATOR( C_OP_Cull );
  3056. uint32 GetWrittenAttributes( void ) const
  3057. {
  3058. return 0;
  3059. }
  3060. uint32 GetFilter( void ) const
  3061. {
  3062. return FILTER_LIFE_DURATION_MASK;
  3063. }
  3064. uint32 GetReadAttributes( void ) const
  3065. {
  3066. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK;
  3067. }
  3068. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  3069. };
  3070. DEFINE_PARTICLE_OPERATOR( C_OP_Cull, "Cull Random", OPERATOR_GENERIC );
  3071. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_Cull )
  3072. DMXELEMENT_UNPACK_FIELD( "Cull Start Time", "0", float, m_flCullStart )
  3073. DMXELEMENT_UNPACK_FIELD( "Cull End Time", "1", float, m_flCullEnd )
  3074. DMXELEMENT_UNPACK_FIELD( "Cull Time Exponent", "1", float, m_flCullExp )
  3075. DMXELEMENT_UNPACK_FIELD( "Cull Percentage", "0.5", float, m_flCullPerc )
  3076. END_PARTICLE_OPERATOR_UNPACK( C_OP_Cull )
  3077. void C_OP_Cull::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  3078. {
  3079. const float *pCreationTime;
  3080. const float *pLifeDuration;
  3081. float flLifeTime;
  3082. // FIXME: SSE-ize
  3083. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  3084. {
  3085. pCreationTime = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, i );
  3086. pLifeDuration = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_LIFE_DURATION, i );
  3087. float flCullRank = pParticles->RandomFloat( 0.0f, 1.0f);
  3088. float flCullTime = pParticles->RandomFloatExp( m_flCullStart, m_flCullEnd, m_flCullExp );
  3089. if ( flCullRank > ( m_flCullPerc * flStrength ) )
  3090. {
  3091. continue;
  3092. }
  3093. // Find our life percentage
  3094. flLifeTime = clamp( ( pParticles->m_flCurTime - *pCreationTime ) / ( *pLifeDuration ), 0.0f, 1.0f );
  3095. if ( flLifeTime >= m_flCullStart && flLifeTime <= m_flCullEnd && flLifeTime >= flCullTime )
  3096. {
  3097. pParticles->KillParticle( i );
  3098. }
  3099. }
  3100. }
  3101. //-----------------------------------------------------------------------------
  3102. // generic spin operator
  3103. //-----------------------------------------------------------------------------
  3104. class CGeneralSpin : public CParticleOperatorInstance
  3105. {
  3106. protected:
  3107. virtual int GetAttributeToSpin( void ) const =0;
  3108. uint32 GetWrittenAttributes( void ) const
  3109. {
  3110. if ( m_nSpinRateDegrees != 0.0 )
  3111. return (1 << GetAttributeToSpin() );
  3112. return 0;
  3113. }
  3114. uint32 GetReadAttributes( void ) const
  3115. {
  3116. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK;
  3117. }
  3118. virtual void InitParams( CParticleSystemDefinition *pDef )
  3119. {
  3120. m_fSpinRateRadians = (float) m_nSpinRateDegrees * ( M_PI / 180.0f );
  3121. m_fSpinRateMinRadians = (float) m_nSpinRateMinDegrees * ( M_PI / 180.0f );
  3122. }
  3123. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  3124. int m_nSpinRateDegrees;
  3125. int m_nSpinRateMinDegrees;
  3126. float m_fSpinRateRadians;
  3127. float m_fSpinRateStopTime;
  3128. float m_fSpinRateMinRadians;
  3129. };
  3130. void CGeneralSpin::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  3131. {
  3132. float fCurSpinRate = m_fSpinRateRadians * flStrength;
  3133. if ( fCurSpinRate == 0.0 )
  3134. return;
  3135. bool bIsInterpolating = pParticles->IsUsingInterpolatedRendering();
  3136. float dt = pParticles->m_flDt;
  3137. float drot = dt * fabs( fCurSpinRate * 2.0f * M_PI );
  3138. if ( m_fSpinRateStopTime == 0.0f )
  3139. {
  3140. drot = fmod( drot, (float)(2.0f * M_PI) );
  3141. }
  3142. if ( fCurSpinRate < 0.0f )
  3143. {
  3144. drot = -drot;
  3145. }
  3146. fltx4 Rot_Add = ReplicateX4( drot );
  3147. fltx4 Pi_2 = ReplicateX4( 2.0*M_PI );
  3148. fltx4 nPi_2 = ReplicateX4( -2.0*M_PI );
  3149. // FIXME: This is wrong
  3150. fltx4 minSpeedRadians = ReplicateX4( dt * fabs( m_fSpinRateMinRadians * 2.0f * M_PI ) );
  3151. fltx4 now = pParticles->m_fl4CurTime;
  3152. fltx4 SpinRateStopTime = ReplicateX4( m_fSpinRateStopTime );
  3153. CM128AttributeIterator pCreationTimeStamp( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  3154. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  3155. CM128AttributeWriteIterator pRot( GetAttributeToSpin(), pParticles );
  3156. int nActive = pParticles->m_nActiveParticles;
  3157. for( int i=0; i < nActive; i+=4 )
  3158. {
  3159. // HACK: Rather than redo this, I'm simply remapping the stop time into the percentage of lifetime, rather than seconds
  3160. fltx4 LifeSpan = *pLifeDuration;
  3161. fltx4 SpinFadePerc = Four_Zeros;
  3162. fltx4 OOSpinFadeRate = Four_Zeros;
  3163. if ( m_fSpinRateStopTime )
  3164. {
  3165. SpinFadePerc = MulSIMD( LifeSpan, SpinRateStopTime );
  3166. OOSpinFadeRate = DivSIMD( Four_Ones, SpinFadePerc );
  3167. }
  3168. fltx4 Age = SubSIMD( now, *pCreationTimeStamp );
  3169. fltx4 RScale = MaxSIMD( Four_Zeros,
  3170. SubSIMD( Four_Ones, MulSIMD( Age, OOSpinFadeRate ) ) );
  3171. // Cap the rotation at a minimum speed
  3172. fltx4 deltaRot = MulSIMD( Rot_Add, RScale );
  3173. bi32x4 Tooslow = CmpLeSIMD( deltaRot, minSpeedRadians );
  3174. deltaRot = OrSIMD( AndSIMD( Tooslow, minSpeedRadians ), AndNotSIMD( Tooslow, deltaRot ) );
  3175. fltx4 NewRot = AddSIMD( *pRot, deltaRot );
  3176. if ( ! bIsInterpolating )
  3177. {
  3178. // if we are interpolating, wrapping the angle around will cause interpolation errors.
  3179. // I don't think we actually need to wrap, but I'll only avoid it when interpolation
  3180. // (not a default) is on for safety's sake.
  3181. //now, cap at +/- 2*pi
  3182. bi32x4 Toobig = CmpGeSIMD( NewRot, Pi_2 );
  3183. bi32x4 Toosmall = CmpLeSIMD( NewRot, nPi_2 );
  3184. NewRot = OrSIMD( AndSIMD( Toobig, SubSIMD( NewRot, Pi_2 ) ),
  3185. AndNotSIMD( Toobig, NewRot ) );
  3186. NewRot = OrSIMD( AndSIMD( Toosmall, AddSIMD( NewRot, Pi_2 ) ),
  3187. AndNotSIMD( Toosmall, NewRot ) );
  3188. }
  3189. *( pRot )= NewRot;
  3190. ++pRot;
  3191. ++pCreationTimeStamp;
  3192. ++pLifeDuration;
  3193. }
  3194. }
  3195. //-----------------------------------------------------------------------------
  3196. // generic spin operator, version 2. Uses rotation_speed
  3197. //-----------------------------------------------------------------------------
  3198. class CSpinUpdateBase : public CParticleOperatorInstance
  3199. {
  3200. protected:
  3201. virtual int GetAttributeToSpin( void ) const =0;
  3202. virtual int GetSpinSpeedAttribute( void ) const =0;
  3203. uint32 GetWrittenAttributes( void ) const
  3204. {
  3205. return (1 << GetAttributeToSpin() );
  3206. }
  3207. uint32 GetReadAttributes( void ) const
  3208. {
  3209. return ( 1 << GetAttributeToSpin() ) | ( 1 << GetSpinSpeedAttribute() ) |
  3210. PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  3211. }
  3212. uint32 GetFilter( void ) const
  3213. {
  3214. return FILTER_ROTATION_MASK;
  3215. }
  3216. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  3217. };
  3218. void CSpinUpdateBase::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  3219. {
  3220. CM128AttributeIterator pCreationTimeStamp( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  3221. CM128AttributeIterator pRotationSpeed( GetSpinSpeedAttribute(), pParticles );
  3222. CM128AttributeWriteIterator pRot( GetAttributeToSpin(), pParticles );
  3223. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  3224. fltx4 fl4Dt = ReplicateX4( pParticles->m_flDt );
  3225. fltx4 fl4ScaleFactor = ReplicateX4( flStrength );
  3226. int nActive = pParticles->m_nActiveParticles;
  3227. for( int i=0; i < nActive; i += 4 )
  3228. {
  3229. fltx4 fl4SimTime = MinSIMD( fl4Dt, SubSIMD( fl4CurTime, *pCreationTimeStamp ) );
  3230. fl4SimTime = MulSIMD( fl4SimTime, fl4ScaleFactor );
  3231. *pRot = MaddSIMD( fl4SimTime, *pRotationSpeed, *pRot );
  3232. ++pRot;
  3233. ++pRotationSpeed;
  3234. ++pCreationTimeStamp;
  3235. }
  3236. }
  3237. class C_OP_Spin : public CGeneralSpin
  3238. {
  3239. DECLARE_PARTICLE_OPERATOR( C_OP_Spin );
  3240. int GetAttributeToSpin( void ) const
  3241. {
  3242. return PARTICLE_ATTRIBUTE_ROTATION;
  3243. }
  3244. };
  3245. DEFINE_PARTICLE_OPERATOR( C_OP_Spin, "Rotation Spin Roll", OPERATOR_GENERIC );
  3246. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_Spin )
  3247. DMXELEMENT_UNPACK_FIELD( "spin_rate_degrees", "0", int, m_nSpinRateDegrees )
  3248. DMXELEMENT_UNPACK_FIELD( "spin_stop_time", "0", float, m_fSpinRateStopTime )
  3249. DMXELEMENT_UNPACK_FIELD( "spin_rate_min", "0", int, m_nSpinRateMinDegrees )
  3250. END_PARTICLE_OPERATOR_UNPACK( C_OP_Spin )
  3251. class C_OP_SpinUpdate : public CSpinUpdateBase
  3252. {
  3253. DECLARE_PARTICLE_OPERATOR( C_OP_SpinUpdate );
  3254. virtual int GetAttributeToSpin( void ) const
  3255. {
  3256. return PARTICLE_ATTRIBUTE_ROTATION;
  3257. }
  3258. virtual int GetSpinSpeedAttribute( void ) const
  3259. {
  3260. return PARTICLE_ATTRIBUTE_ROTATION_SPEED;
  3261. }
  3262. };
  3263. DEFINE_PARTICLE_OPERATOR( C_OP_SpinUpdate, "Rotation Basic", OPERATOR_GENERIC );
  3264. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_SpinUpdate )
  3265. END_PARTICLE_OPERATOR_UNPACK( C_OP_SpinUpdate )
  3266. class C_OP_SpinYaw : public CGeneralSpin
  3267. {
  3268. DECLARE_PARTICLE_OPERATOR( C_OP_SpinYaw );
  3269. int GetAttributeToSpin( void ) const
  3270. {
  3271. return PARTICLE_ATTRIBUTE_YAW;
  3272. }
  3273. };
  3274. DEFINE_PARTICLE_OPERATOR( C_OP_SpinYaw, "Rotation Spin Yaw", OPERATOR_GENERIC );
  3275. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_SpinYaw )
  3276. DMXELEMENT_UNPACK_FIELD( "yaw_rate_degrees", "0", int, m_nSpinRateDegrees )
  3277. DMXELEMENT_UNPACK_FIELD( "yaw_stop_time", "0", float, m_fSpinRateStopTime )
  3278. DMXELEMENT_UNPACK_FIELD( "yaw_rate_min", "0", int, m_nSpinRateMinDegrees )
  3279. END_PARTICLE_OPERATOR_UNPACK( C_OP_SpinYaw )
  3280. //-----------------------------------------------------------------------------
  3281. // Size changing operator
  3282. //-----------------------------------------------------------------------------
  3283. class C_OP_InterpolateRadius : public CParticleOperatorInstance
  3284. {
  3285. DECLARE_PARTICLE_OPERATOR( C_OP_InterpolateRadius );
  3286. uint32 GetReadInitialAttributes( void ) const
  3287. {
  3288. return PARTICLE_ATTRIBUTE_RADIUS_MASK;
  3289. }
  3290. uint32 GetWrittenAttributes( void ) const
  3291. {
  3292. return PARTICLE_ATTRIBUTE_RADIUS_MASK;
  3293. }
  3294. uint32 GetReadAttributes( void ) const
  3295. {
  3296. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK;
  3297. }
  3298. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  3299. void InitParams( CParticleSystemDefinition *pDef )
  3300. {
  3301. m_flBias = ( m_flBias != 0.0f ) ? m_flBias : 0.5f;
  3302. m_fl4BiasParam = PreCalcBiasParameter( ReplicateX4( m_flBias ) );
  3303. }
  3304. float m_flStartTime;
  3305. float m_flEndTime;
  3306. float m_flStartScale;
  3307. float m_flEndScale;
  3308. bool m_bEaseInAndOut;
  3309. float m_flBias;
  3310. fltx4 m_fl4BiasParam;
  3311. };
  3312. DEFINE_PARTICLE_OPERATOR( C_OP_InterpolateRadius, "Radius Scale", OPERATOR_GENERIC );
  3313. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_InterpolateRadius )
  3314. DMXELEMENT_UNPACK_FIELD( "start_time", "0", float, m_flStartTime )
  3315. DMXELEMENT_UNPACK_FIELD( "end_time", "1", float, m_flEndTime )
  3316. DMXELEMENT_UNPACK_FIELD( "radius_start_scale", "1", float, m_flStartScale )
  3317. DMXELEMENT_UNPACK_FIELD( "radius_end_scale", "1", float, m_flEndScale )
  3318. DMXELEMENT_UNPACK_FIELD( "ease_in_and_out", "0", bool, m_bEaseInAndOut )
  3319. DMXELEMENT_UNPACK_FIELD( "scale_bias", "0.5", float, m_flBias )
  3320. END_PARTICLE_OPERATOR_UNPACK( C_OP_InterpolateRadius )
  3321. void C_OP_InterpolateRadius::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  3322. {
  3323. if ( m_flEndTime <= m_flStartTime )
  3324. return;
  3325. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  3326. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  3327. CM128AttributeWriteIterator pRadius( PARTICLE_ATTRIBUTE_RADIUS, pParticles );
  3328. CM128InitialAttributeIterator pInitialRadius( PARTICLE_ATTRIBUTE_RADIUS, pParticles );
  3329. fltx4 fl4StartTime = ReplicateX4( m_flStartTime );
  3330. fltx4 fl4EndTime = ReplicateX4( m_flEndTime );
  3331. fltx4 fl4OOTimeWidth = ReciprocalSIMD( SubSIMD( fl4EndTime, fl4StartTime ) );
  3332. fltx4 fl4ScaleWidth = ReplicateX4( m_flEndScale - m_flStartScale );
  3333. fltx4 fl4StartScale = ReplicateX4( m_flStartScale );
  3334. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  3335. int nCtr = pParticles->m_nPaddedActiveParticles;
  3336. if ( m_bEaseInAndOut )
  3337. {
  3338. do
  3339. {
  3340. fltx4 fl4LifeDuration = *pLifeDuration;
  3341. bi32x4 fl4GoodMask = CmpGtSIMD( fl4LifeDuration, Four_Zeros );
  3342. fltx4 fl4LifeTime = MulSIMD( SubSIMD( fl4CurTime, *pCreationTime ), ReciprocalEstSIMD( fl4LifeDuration ) ); // maybe need accurate div here?
  3343. fl4GoodMask = AndSIMD( fl4GoodMask, CmpGeSIMD( fl4LifeTime, fl4StartTime ) );
  3344. fl4GoodMask = AndSIMD( fl4GoodMask, CmpLtSIMD( fl4LifeTime, fl4EndTime ) );
  3345. if ( IsAnyTrue( fl4GoodMask ) )
  3346. {
  3347. fltx4 fl4FadeWindow = MulSIMD( SubSIMD( fl4LifeTime, fl4StartTime ), fl4OOTimeWidth );
  3348. fl4FadeWindow = AddSIMD( fl4StartScale, MulSIMD( SimpleSpline( fl4FadeWindow ), fl4ScaleWidth ) );
  3349. // !!speed!! - can anyone really tell the diff between spline and lerp here?
  3350. *pRadius = MaskedAssign(
  3351. fl4GoodMask, MulSIMD( *pInitialRadius, fl4FadeWindow ), *pRadius );
  3352. }
  3353. ++pCreationTime;
  3354. ++pLifeDuration;
  3355. ++pRadius;
  3356. ++pInitialRadius;
  3357. } while (--nCtr );
  3358. }
  3359. else
  3360. {
  3361. if ( m_flBias == 0.5f ) // no bias case
  3362. {
  3363. do
  3364. {
  3365. fltx4 fl4LifeDuration = *pLifeDuration;
  3366. bi32x4 fl4GoodMask = CmpGtSIMD( fl4LifeDuration, Four_Zeros );
  3367. fltx4 fl4LifeTime = MulSIMD( SubSIMD( fl4CurTime, *pCreationTime ), ReciprocalEstSIMD( fl4LifeDuration ) ); // maybe need accurate div here?
  3368. fl4GoodMask = AndSIMD( fl4GoodMask, CmpGeSIMD( fl4LifeTime, fl4StartTime ) );
  3369. fl4GoodMask = AndSIMD( fl4GoodMask, CmpLtSIMD( fl4LifeTime, fl4EndTime ) );
  3370. if ( IsAnyTrue( fl4GoodMask ) )
  3371. {
  3372. fltx4 fl4FadeWindow = MulSIMD( SubSIMD( fl4LifeTime, fl4StartTime ), fl4OOTimeWidth );
  3373. fl4FadeWindow = AddSIMD( fl4StartScale, MulSIMD( fl4FadeWindow, fl4ScaleWidth ) );
  3374. *pRadius = MaskedAssign( fl4GoodMask, MulSIMD( *pInitialRadius, fl4FadeWindow ), *pRadius );
  3375. }
  3376. ++pCreationTime;
  3377. ++pLifeDuration;
  3378. ++pRadius;
  3379. ++pInitialRadius;
  3380. } while (--nCtr );
  3381. }
  3382. else
  3383. {
  3384. // use rational approximation to bias
  3385. do
  3386. {
  3387. fltx4 fl4LifeDuration = *pLifeDuration;
  3388. bi32x4 fl4GoodMask = CmpGtSIMD( fl4LifeDuration, Four_Zeros );
  3389. fltx4 fl4LifeTime = MulSIMD( SubSIMD( fl4CurTime, *pCreationTime ), ReciprocalEstSIMD( fl4LifeDuration ) ); // maybe need accurate div here?
  3390. fl4GoodMask = AndSIMD( fl4GoodMask, CmpGeSIMD( fl4LifeTime, fl4StartTime ) );
  3391. fl4GoodMask = AndSIMD( fl4GoodMask, CmpLtSIMD( fl4LifeTime, fl4EndTime ) );
  3392. if ( IsAnyTrue( fl4GoodMask ) )
  3393. {
  3394. fltx4 fl4FadeWindow = MulSIMD( SubSIMD( fl4LifeTime, fl4StartTime ), fl4OOTimeWidth );
  3395. fl4FadeWindow = AddSIMD( fl4StartScale, MulSIMD( BiasSIMD( fl4FadeWindow, m_fl4BiasParam ), fl4ScaleWidth ) );
  3396. *pRadius = MaskedAssign(
  3397. fl4GoodMask,
  3398. MulSIMD( *pInitialRadius, fl4FadeWindow ), *pRadius );
  3399. }
  3400. ++pCreationTime;
  3401. ++pLifeDuration;
  3402. ++pRadius;
  3403. ++pInitialRadius;
  3404. } while (--nCtr );
  3405. }
  3406. }
  3407. }
  3408. //-----------------------------------------------------------------------------
  3409. // Color Fade
  3410. //-----------------------------------------------------------------------------
  3411. class C_OP_ColorInterpolate : public CParticleOperatorInstance
  3412. {
  3413. DECLARE_PARTICLE_OPERATOR( C_OP_ColorInterpolate );
  3414. uint32 GetReadInitialAttributes( void ) const
  3415. {
  3416. return (1 << m_nFieldOutput );
  3417. }
  3418. uint32 GetWrittenAttributes( void ) const
  3419. {
  3420. return (1 << m_nFieldOutput );
  3421. }
  3422. uint32 GetReadAttributes( void ) const
  3423. {
  3424. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK;
  3425. }
  3426. virtual void InitParams( CParticleSystemDefinition *pDef )
  3427. {
  3428. m_flColorFade[0] = m_ColorFade[0] / 255.0f;
  3429. m_flColorFade[1] = m_ColorFade[1] / 255.0f;
  3430. m_flColorFade[2] = m_ColorFade[2] / 255.0f;
  3431. }
  3432. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  3433. Color m_ColorFade;
  3434. float m_flColorFade[3];
  3435. float m_flFadeStartTime;
  3436. float m_flFadeEndTime;
  3437. int m_nFieldOutput;
  3438. bool m_bEaseInOut;
  3439. };
  3440. void C_OP_ColorInterpolate::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  3441. {
  3442. C4VAttributeWriteIterator pColor( m_nFieldOutput, pParticles );
  3443. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  3444. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  3445. C4VInitialAttributeIterator pInitialColor( m_nFieldOutput, pParticles );
  3446. if ( m_flFadeEndTime == m_flFadeStartTime )
  3447. return;
  3448. fltx4 ooInRange = ReplicateX4( 1.0 / ( m_flFadeEndTime - m_flFadeStartTime ) );
  3449. fltx4 curTime = pParticles->m_fl4CurTime;
  3450. fltx4 lowRange = ReplicateX4( m_flFadeStartTime );
  3451. fltx4 targetR = ReplicateX4( m_flColorFade[0] );
  3452. fltx4 targetG = ReplicateX4( m_flColorFade[1] );
  3453. fltx4 targetB = ReplicateX4( m_flColorFade[2] );
  3454. int nCtr = pParticles->m_nPaddedActiveParticles;
  3455. if ( m_bEaseInOut )
  3456. {
  3457. do
  3458. {
  3459. bi32x4 goodMask = CmpGtSIMD( *pLifeDuration, Four_Zeros );
  3460. if ( IsAnyTrue( goodMask ) )
  3461. {
  3462. fltx4 flLifeTime = DivSIMD( SubSIMD( curTime, *pCreationTime ), *pLifeDuration );
  3463. fltx4 T = MulSIMD( SubSIMD( flLifeTime, lowRange ), ooInRange );
  3464. T = MinSIMD( Four_Ones, MaxSIMD( Four_Zeros, T ) );
  3465. T = SimpleSpline( T );
  3466. pColor->x = MaskedAssign( goodMask, AddSIMD( pInitialColor->x, MulSIMD( T, SubSIMD( targetR, pInitialColor->x ) ) ), pColor->x );
  3467. pColor->y = MaskedAssign( goodMask, AddSIMD( pInitialColor->y, MulSIMD( T, SubSIMD( targetG, pInitialColor->y ) ) ), pColor->y );
  3468. pColor->z = MaskedAssign( goodMask, AddSIMD( pInitialColor->z, MulSIMD( T, SubSIMD( targetB, pInitialColor->z ) ) ), pColor->z );
  3469. }
  3470. ++pColor;
  3471. ++pCreationTime;
  3472. ++pLifeDuration;
  3473. ++pInitialColor;
  3474. } while( --nCtr );
  3475. }
  3476. else
  3477. {
  3478. do
  3479. {
  3480. bi32x4 goodMask = CmpGtSIMD( *pLifeDuration, Four_Zeros );
  3481. if ( IsAnyTrue( goodMask ) )
  3482. {
  3483. fltx4 flLifeTime = DivSIMD( SubSIMD( curTime, *pCreationTime ), *pLifeDuration );
  3484. fltx4 T = MulSIMD( SubSIMD( flLifeTime, lowRange ), ooInRange );
  3485. T = MinSIMD( Four_Ones, MaxSIMD( Four_Zeros, T ) );
  3486. pColor->x = MaskedAssign( goodMask, AddSIMD( pInitialColor->x, MulSIMD( T, SubSIMD( targetR, pInitialColor->x ) ) ), pColor->x );
  3487. pColor->y = MaskedAssign( goodMask, AddSIMD( pInitialColor->y, MulSIMD( T, SubSIMD( targetG, pInitialColor->y ) ) ), pColor->y );
  3488. pColor->z = MaskedAssign( goodMask, AddSIMD( pInitialColor->z, MulSIMD( T, SubSIMD( targetB, pInitialColor->z ) ) ), pColor->z );
  3489. }
  3490. ++pColor;
  3491. ++pCreationTime;
  3492. ++pLifeDuration;
  3493. ++pInitialColor;
  3494. } while( --nCtr );
  3495. }
  3496. }
  3497. DEFINE_PARTICLE_OPERATOR( C_OP_ColorInterpolate, "Color Fade", OPERATOR_GENERIC );
  3498. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_ColorInterpolate )
  3499. DMXELEMENT_UNPACK_FIELD( "color_fade", "255 255 255 255", Color, m_ColorFade )
  3500. DMXELEMENT_UNPACK_FIELD( "fade_start_time", "0", float, m_flFadeStartTime )
  3501. DMXELEMENT_UNPACK_FIELD( "fade_end_time", "1", float, m_flFadeEndTime )
  3502. DMXELEMENT_UNPACK_FIELD( "ease_in_and_out", "1", bool, m_bEaseInOut )
  3503. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "6", int, m_nFieldOutput, "intchoice particlefield_vector" )
  3504. END_PARTICLE_OPERATOR_UNPACK( C_OP_ColorInterpolate )
  3505. //-----------------------------------------------------------------------------
  3506. // Position Lock to Control Point
  3507. // Locks all particles to the specified control point
  3508. // Useful for making particles move with their emitter and so forth
  3509. //-----------------------------------------------------------------------------
  3510. class C_OP_PositionLock : public CParticleOperatorInstance
  3511. {
  3512. DECLARE_PARTICLE_OPERATOR( C_OP_PositionLock );
  3513. struct C_OP_PositionLockContext_t
  3514. {
  3515. Vector m_vPrevPosition;
  3516. matrix3x4_t m_matPrevTransform;
  3517. };
  3518. int m_nControlPointNumber;
  3519. Vector m_vPrevPosition;
  3520. float m_flStartTime_min;
  3521. float m_flStartTime_max;
  3522. float m_flStartTime_exp;
  3523. float m_flEndTime_min;
  3524. float m_flEndTime_max;
  3525. float m_flEndTime_exp;
  3526. float m_flRange;
  3527. bool m_bLockRot;
  3528. uint32 GetWrittenAttributes( void ) const
  3529. {
  3530. return PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_XYZ_MASK;
  3531. }
  3532. uint32 GetReadAttributes( void ) const
  3533. {
  3534. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK |
  3535. PARTICLE_ATTRIBUTE_PARTICLE_ID_MASK;
  3536. }
  3537. virtual uint64 GetReadControlPointMask() const
  3538. {
  3539. return 1ULL << m_nControlPointNumber;
  3540. }
  3541. void InitParams( CParticleSystemDefinition *pDef )
  3542. {
  3543. m_nControlPointNumber = MAX( 0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nControlPointNumber ) );
  3544. }
  3545. size_t GetRequiredContextBytes( void ) const
  3546. {
  3547. return sizeof( C_OP_PositionLockContext_t );
  3548. }
  3549. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  3550. {
  3551. C_OP_PositionLockContext_t *pCtx=reinterpret_cast<C_OP_PositionLockContext_t *>( pContext );
  3552. pCtx->m_vPrevPosition = vec3_origin;
  3553. pParticles->GetControlPointTransformAtTime( m_nControlPointNumber, pParticles->m_flCurTime, &pCtx->m_matPrevTransform );
  3554. }
  3555. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  3556. };
  3557. DEFINE_PARTICLE_OPERATOR( C_OP_PositionLock , "Movement Lock to Control Point", OPERATOR_GENERIC );
  3558. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_PositionLock )
  3559. DMXELEMENT_UNPACK_FIELD( "control_point_number", "0", int, m_nControlPointNumber )
  3560. DMXELEMENT_UNPACK_FIELD( "start_fadeout_min", "1", float, m_flStartTime_min )
  3561. DMXELEMENT_UNPACK_FIELD( "start_fadeout_max", "1", float, m_flStartTime_max )
  3562. DMXELEMENT_UNPACK_FIELD( "start_fadeout_exponent", "1", float, m_flStartTime_exp )
  3563. DMXELEMENT_UNPACK_FIELD( "end_fadeout_min", "1", float, m_flEndTime_min )
  3564. DMXELEMENT_UNPACK_FIELD( "end_fadeout_max", "1", float, m_flEndTime_max )
  3565. DMXELEMENT_UNPACK_FIELD( "end_fadeout_exponent", "1", float, m_flEndTime_exp )
  3566. DMXELEMENT_UNPACK_FIELD( "distance fade range", "0", float, m_flRange )
  3567. DMXELEMENT_UNPACK_FIELD( "lock rotation", "0", bool, m_bLockRot )
  3568. END_PARTICLE_OPERATOR_UNPACK( C_OP_PositionLock )
  3569. #ifdef OLD_NON_SSE_POSLOCK_FOR_TESTING
  3570. void C_OP_PositionLock::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  3571. {
  3572. Vector vecControlPoint = pParticles->GetControlPointAtCurrentTime( m_nControlPointNumber );
  3573. // At initialization, set prevposition to the control point to prevent random placements/velocities
  3574. C_OP_PositionLockContext_t *pCtx=reinterpret_cast<C_OP_PositionLockContext_t *>( pContext );
  3575. if ( pCtx->m_vPrevPosition == Vector (0, 0, 0) )
  3576. {
  3577. pCtx->m_vPrevPosition = vecControlPoint;
  3578. }
  3579. // Control point movement delta
  3580. int nRandomOffset = pParticles->OperatorRandomSampleOffset();
  3581. // FIXME: SSE-ize
  3582. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  3583. {
  3584. Vector vecPrevCPPos = pCtx->m_vPrevPosition;
  3585. const float *pCreationTime;
  3586. const float *pLifeDuration;
  3587. pCreationTime = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, i );
  3588. pLifeDuration = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_LIFE_DURATION, i );
  3589. float flLifeTime = *pLifeDuration != 0.0f ? clamp( ( pParticles->m_flCurTime - *pCreationTime ) / ( *pLifeDuration ), 0.0f, 1.0f ) : 0.0f;
  3590. if ( *pCreationTime >= ( pParticles->m_flCurTime - pParticles->m_flDt ) )
  3591. {
  3592. pParticles->GetControlPointAtTime( m_nControlPointNumber, *pCreationTime, &vecPrevCPPos );
  3593. }
  3594. Vector vDelta = vecControlPoint - vecPrevCPPos;
  3595. vDelta *= flStrength;
  3596. // clamp activity to start/end time
  3597. int nParticleId = *pParticles->GetIntAttributePtr( PARTICLE_ATTRIBUTE_PARTICLE_ID, i );
  3598. float flStartTime = pParticles->RandomFloatExp( nParticleId + nRandomOffset + 9, m_flStartTime_min, m_flStartTime_max, m_flStartTime_exp );
  3599. float flEndTime = pParticles->RandomFloatExp( nParticleId + nRandomOffset + 10, m_flEndTime_min, m_flEndTime_max, m_flEndTime_exp );
  3600. // bias attachedness by fadeout
  3601. float flLockScale = SimpleSplineRemapValClamped( flLifeTime, flStartTime, flEndTime, 1.0f, 0.0f );
  3602. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, i );
  3603. float *xyz_prev = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  3604. Vector vecParticlePosition, vecParticlePosition_prev ;
  3605. SetVectorFromAttribute( vecParticlePosition, xyz );
  3606. SetVectorFromAttribute( vecParticlePosition_prev, xyz_prev );
  3607. float flDampenAmount = 1;
  3608. if ( m_flRange != 0 )
  3609. {
  3610. Vector ofs;
  3611. ofs = (vecParticlePosition + ( vDelta * flLockScale ) ) - vecControlPoint;
  3612. float flDistance = ofs.Length();
  3613. flDampenAmount = SimpleSplineRemapValClamped( flDistance, 0, m_flRange, 1.0f, 0.0f );
  3614. flDampenAmount = Bias( flDampenAmount, .2 );
  3615. }
  3616. Vector vParticleDelta = vDelta * flLockScale * flDampenAmount;
  3617. vecParticlePosition += vParticleDelta;
  3618. vecParticlePosition_prev += vParticleDelta;
  3619. SetVectorAttribute( xyz, vecParticlePosition );
  3620. SetVectorAttribute( xyz_prev, vecParticlePosition_prev );
  3621. }
  3622. // Store off the control point position for the next delta computation
  3623. pCtx->m_vPrevPosition = vecControlPoint;
  3624. };
  3625. #else
  3626. void C_OP_PositionLock::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  3627. {
  3628. Vector vecControlPoint = pParticles->GetControlPointAtCurrentTime( m_nControlPointNumber );
  3629. matrix3x4_t matCurrentTransform;
  3630. pParticles->GetControlPointTransformAtTime( m_nControlPointNumber, pParticles->m_flCurTime, &matCurrentTransform );
  3631. // At initialization, set prevposition to the control point to prevent random placements/velocities
  3632. C_OP_PositionLockContext_t *pCtx=reinterpret_cast<C_OP_PositionLockContext_t *>( pContext );
  3633. if ( pCtx->m_vPrevPosition == Vector (0, 0, 0) )
  3634. {
  3635. pCtx->m_vPrevPosition = vecControlPoint;
  3636. pParticles->GetControlPointTransformAtTime( m_nControlPointNumber, pParticles->m_flCurTime, &pCtx->m_matPrevTransform );
  3637. }
  3638. else
  3639. {
  3640. if ( ( !m_bLockRot && pCtx->m_vPrevPosition == vecControlPoint ) || ( m_bLockRot && MatricesAreEqual ( matCurrentTransform, pCtx->m_matPrevTransform ) ))
  3641. return;
  3642. }
  3643. Vector vDelta;
  3644. matrix3x4_t matTransformLock;
  3645. if ( m_bLockRot )
  3646. {
  3647. matrix3x4_t matPrev;
  3648. MatrixInvert( pCtx->m_matPrevTransform, matPrev );
  3649. MatrixMultiply( matCurrentTransform, matPrev, matTransformLock);
  3650. }
  3651. int nContext = GetSIMDRandContext();
  3652. // Control point movement delta - not full transform
  3653. vDelta = vecControlPoint - pCtx->m_vPrevPosition;
  3654. vDelta *= flStrength;
  3655. FourVectors v4Delta;
  3656. v4Delta.DuplicateVector( vDelta );
  3657. FourVectors v4ControlPoint;
  3658. v4ControlPoint.DuplicateVector( vecControlPoint );
  3659. C4VAttributeWriteIterator pXYZ( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  3660. C4VAttributeWriteIterator pPrevXYZ( PARTICLE_ATTRIBUTE_PREV_XYZ, pParticles );
  3661. fltx4 fl4_Dt = ReplicateX4( pParticles->m_flDt );
  3662. int nCtr = pParticles->m_nPaddedActiveParticles;
  3663. bool bUseRange = ( m_flRange != 0.0 );
  3664. fltx4 fl4OORange = Four_Ones;
  3665. if ( bUseRange )
  3666. fl4OORange = ReplicateX4( 1.0 / m_flRange );
  3667. fltx4 fl4BiasParm = PreCalcBiasParameter( ReplicateX4( 0.2 ) );
  3668. if ( m_flStartTime_min >= 1.0 ) // always locked on
  3669. {
  3670. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  3671. do
  3672. {
  3673. fltx4 fl4ParticleAge = SubSIMD( pParticles->m_fl4CurTime, *pCreationTime);
  3674. fltx4 fl4CreationFrameBias = MinSIMD( fl4ParticleAge, fl4_Dt );
  3675. fl4CreationFrameBias = MulSIMD( DivSIMD( Four_Ones, fl4_Dt ), fl4CreationFrameBias );
  3676. FourVectors v4ScaledDelta = v4Delta;
  3677. v4ScaledDelta *= fl4CreationFrameBias;
  3678. fltx4 fl4LockStrength = ReplicateX4( flStrength );
  3679. // ok, some of these particles should be moved
  3680. if ( bUseRange )
  3681. {
  3682. FourVectors ofs = *pXYZ;
  3683. ofs += v4ScaledDelta;
  3684. ofs -= v4ControlPoint;
  3685. fltx4 fl4Dist = ofs.length();
  3686. fl4Dist = BiasSIMD( MinSIMD( Four_Ones, MulSIMD( fl4Dist, fl4OORange ) ), fl4BiasParm );
  3687. v4ScaledDelta *= SubSIMD( Four_Ones, fl4Dist );
  3688. fl4LockStrength = SubSIMD( Four_Ones, MulSIMD ( fl4Dist, fl4LockStrength ) );
  3689. }
  3690. if ( m_bLockRot )
  3691. {
  3692. fl4LockStrength = MulSIMD( fl4LockStrength, fl4CreationFrameBias );
  3693. FourVectors fvCurPos = *pXYZ;
  3694. FourVectors fvPrevPos = *pPrevXYZ;
  3695. fvCurPos.TransformBy( matTransformLock );
  3696. fvPrevPos.TransformBy( matTransformLock );
  3697. fvCurPos -= *pXYZ;
  3698. fvCurPos *= fl4LockStrength;
  3699. fvPrevPos -= *pPrevXYZ;
  3700. fvPrevPos *= fl4LockStrength;
  3701. *(pXYZ) += fvCurPos;
  3702. *(pPrevXYZ) += fvPrevPos;
  3703. }
  3704. else
  3705. {
  3706. *(pXYZ) += v4ScaledDelta;
  3707. *(pPrevXYZ) += v4ScaledDelta;
  3708. }
  3709. ++pCreationTime;
  3710. ++pXYZ;
  3711. ++pPrevXYZ;
  3712. } while ( --nCtr );
  3713. }
  3714. else
  3715. {
  3716. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  3717. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  3718. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  3719. fltx4 fl4StartRange = ReplicateX4( m_flStartTime_max - m_flStartTime_min );
  3720. fltx4 fl4StartBias = ReplicateX4( m_flStartTime_min );
  3721. fltx4 fl4EndRange = ReplicateX4( m_flEndTime_max - m_flEndTime_min );
  3722. fltx4 fl4EndBias = ReplicateX4( m_flEndTime_min );
  3723. int nSSEStartExponent = m_flStartTime_exp * 4.0;
  3724. int nSSEEndExponent = m_flEndTime_exp * 4.0;
  3725. do
  3726. {
  3727. fltx4 fl4LifeTime = SubSIMD( fl4CurTime, *pCreationTime );
  3728. fltx4 fl4CreationFrameBias = MinSIMD( fl4LifeTime, fl4_Dt );
  3729. fl4CreationFrameBias = MulSIMD( DivSIMD( Four_Ones, fl4_Dt ), fl4CreationFrameBias );
  3730. FourVectors v4ScaledDelta = v4Delta;
  3731. v4ScaledDelta *= fl4CreationFrameBias;
  3732. fl4LifeTime = MaxSIMD( Four_Zeros, MinSIMD( Four_Ones,
  3733. MulSIMD( fl4LifeTime, ReciprocalEstSIMD( *pLifeDuration ) ) ) );
  3734. fltx4 fl4StartTime = Pow_FixedPoint_Exponent_SIMD( RandSIMD( nContext ), nSSEStartExponent );
  3735. fl4StartTime = AddSIMD( fl4StartBias, MulSIMD( fl4StartTime, fl4StartRange ) );
  3736. fltx4 fl4EndTime = Pow_FixedPoint_Exponent_SIMD( RandSIMD( nContext ), nSSEEndExponent );
  3737. fl4EndTime = AddSIMD( fl4EndBias, MulSIMD( fl4EndTime, fl4EndRange ) );
  3738. // now, determine "lockedness"
  3739. fltx4 fl4LockScale = DivSIMD( SubSIMD( fl4LifeTime, fl4StartTime ), SubSIMD( fl4EndTime, fl4StartTime ) );
  3740. fl4LockScale = SubSIMD( Four_Ones, MaxSIMD( Four_Zeros, MinSIMD( Four_Ones, fl4LockScale ) ) );
  3741. if ( IsAnyTrue( CmpGtSIMD( fl4LockScale, Four_Zeros ) ) )
  3742. {
  3743. //fl4LockScale = MulSIMD( fl4LockScale, fl4CreationFrameBias );
  3744. v4ScaledDelta *= fl4LockScale;
  3745. fltx4 fl4LockStrength = fl4LockScale ;
  3746. // ok, some of these particles should be moved
  3747. if ( bUseRange )
  3748. {
  3749. FourVectors ofs = *pXYZ;
  3750. ofs += v4ScaledDelta;
  3751. ofs -= v4ControlPoint;
  3752. fltx4 fl4Dist = ofs.length();
  3753. fl4Dist = BiasSIMD( MinSIMD( Four_Ones, MulSIMD( fl4Dist, fl4OORange ) ), fl4BiasParm );
  3754. v4ScaledDelta *= SubSIMD( Four_Ones, fl4Dist );
  3755. fl4LockStrength = SubSIMD( Four_Ones, MulSIMD ( fl4Dist, fl4LockStrength ) );
  3756. }
  3757. if ( m_bLockRot )
  3758. {
  3759. fl4LockStrength = MulSIMD( fl4LockStrength, fl4CreationFrameBias );
  3760. FourVectors fvCurPos = *pXYZ;
  3761. FourVectors fvPrevPos = *pPrevXYZ;
  3762. fvCurPos.TransformBy( matTransformLock );
  3763. fvPrevPos.TransformBy( matTransformLock );
  3764. fvCurPos -= *pXYZ;
  3765. fvCurPos *= fl4LockStrength;
  3766. fvPrevPos -= *pPrevXYZ;
  3767. fvPrevPos *= fl4LockStrength;
  3768. *(pXYZ) += fvCurPos;
  3769. *(pPrevXYZ) += fvPrevPos;
  3770. }
  3771. else
  3772. {
  3773. *(pXYZ) += v4ScaledDelta;
  3774. *(pPrevXYZ) += v4ScaledDelta;
  3775. }
  3776. }
  3777. ++pCreationTime;
  3778. ++pLifeDuration;
  3779. ++pXYZ;
  3780. ++pPrevXYZ;
  3781. } while ( --nCtr );
  3782. }
  3783. // Store off the control point position for the next delta computation
  3784. pCtx->m_vPrevPosition = vecControlPoint;
  3785. pCtx->m_matPrevTransform = matCurrentTransform;
  3786. ReleaseSIMDRandContext( nContext );
  3787. };
  3788. #endif
  3789. //-----------------------------------------------------------------------------
  3790. // Controlpoint Light
  3791. // Determines particle color/fakes lighting using the influence of control
  3792. // points
  3793. //-----------------------------------------------------------------------------
  3794. class C_OP_ControlpointLight : public CParticleOperatorInstance
  3795. {
  3796. float m_flScale;
  3797. LightDesc_t m_LightNode1, m_LightNode2, m_LightNode3, m_LightNode4;
  3798. int m_nControlPoint1, m_nControlPoint2, m_nControlPoint3, m_nControlPoint4;
  3799. Vector m_vecCPOffset1, m_vecCPOffset2, m_vecCPOffset3, m_vecCPOffset4;
  3800. float m_LightFiftyDist1, m_LightZeroDist1, m_LightFiftyDist2, m_LightZeroDist2,
  3801. m_LightFiftyDist3, m_LightZeroDist3, m_LightFiftyDist4, m_LightZeroDist4;
  3802. Color m_LightColor1, m_LightColor2, m_LightColor3, m_LightColor4;
  3803. bool m_bLightType1, m_bLightType2, m_bLightType3, m_bLightType4, m_bLightDynamic1,
  3804. m_bLightDynamic2, m_bLightDynamic3, m_bLightDynamic4, m_bUseNormal, m_bUseHLambert,
  3805. m_bLightActive1, m_bLightActive2, m_bLightActive3, m_bLightActive4,
  3806. m_bClampLowerRange, m_bClampUpperRange;
  3807. DECLARE_PARTICLE_OPERATOR( C_OP_ControlpointLight );
  3808. uint32 GetReadInitialAttributes( void ) const
  3809. {
  3810. return PARTICLE_ATTRIBUTE_TINT_RGB_MASK;
  3811. }
  3812. uint32 GetWrittenAttributes( void ) const
  3813. {
  3814. return PARTICLE_ATTRIBUTE_TINT_RGB_MASK;
  3815. }
  3816. uint32 GetReadAttributes( void ) const
  3817. {
  3818. return PARTICLE_ATTRIBUTE_XYZ_MASK;
  3819. }
  3820. virtual uint64 GetReadControlPointMask() const
  3821. {
  3822. return ( 1ULL << m_nControlPoint1 ) | ( 1ULL << m_nControlPoint2 ) |
  3823. ( 1ULL << m_nControlPoint3 ) | ( 1ULL << m_nControlPoint4 );
  3824. }
  3825. virtual void InitParams( CParticleSystemDefinition *pDef )
  3826. {
  3827. m_LightNode1.m_Color[0] = m_LightColor1[0] / 255.0f;
  3828. m_LightNode1.m_Color[1] = m_LightColor1[1] / 255.0f;
  3829. m_LightNode1.m_Color[2] = m_LightColor1[2] / 255.0f;
  3830. m_LightNode2.m_Color[0] = m_LightColor2[0] / 255.0f;
  3831. m_LightNode2.m_Color[1] = m_LightColor2[1] / 255.0f;
  3832. m_LightNode2.m_Color[2] = m_LightColor2[2] / 255.0f;
  3833. m_LightNode3.m_Color[0] = m_LightColor3[0] / 255.0f;
  3834. m_LightNode3.m_Color[1] = m_LightColor3[1] / 255.0f;
  3835. m_LightNode3.m_Color[2] = m_LightColor3[2] / 255.0f;
  3836. m_LightNode4.m_Color[0] = m_LightColor4[0] / 255.0f;
  3837. m_LightNode4.m_Color[1] = m_LightColor4[1] / 255.0f;
  3838. m_LightNode4.m_Color[2] = m_LightColor4[2] / 255.0f;
  3839. m_LightNode1.m_Range = 0;
  3840. m_LightNode2.m_Range = 0;
  3841. m_LightNode3.m_Range = 0;
  3842. m_LightNode4.m_Range = 0;
  3843. m_LightNode1.m_Falloff=5.0;
  3844. m_LightNode2.m_Falloff=5.0;
  3845. m_LightNode3.m_Falloff=5.0;
  3846. m_LightNode4.m_Falloff=5.0;
  3847. m_LightNode1.m_Attenuation0 = 0;
  3848. m_LightNode1.m_Attenuation1 = 0;
  3849. m_LightNode1.m_Attenuation2 = 1;
  3850. m_LightNode2.m_Attenuation0 = 0;
  3851. m_LightNode2.m_Attenuation1 = 0;
  3852. m_LightNode2.m_Attenuation2 = 1;
  3853. m_LightNode3.m_Attenuation0 = 0;
  3854. m_LightNode3.m_Attenuation1 = 0;
  3855. m_LightNode3.m_Attenuation2 = 1;
  3856. m_LightNode4.m_Attenuation0 = 0;
  3857. m_LightNode4.m_Attenuation1 = 0;
  3858. m_LightNode4.m_Attenuation2 = 1;
  3859. if ( !m_bLightType1 )
  3860. {
  3861. m_LightNode1.m_Type = MATERIAL_LIGHT_POINT;
  3862. }
  3863. else
  3864. {
  3865. m_LightNode1.m_Type = MATERIAL_LIGHT_SPOT;
  3866. }
  3867. if ( !m_bLightType2 )
  3868. {
  3869. m_LightNode2.m_Type = MATERIAL_LIGHT_POINT;
  3870. }
  3871. else
  3872. {
  3873. m_LightNode2.m_Type = MATERIAL_LIGHT_SPOT;
  3874. }
  3875. if ( !m_bLightType3 )
  3876. {
  3877. m_LightNode3.m_Type = MATERIAL_LIGHT_POINT;
  3878. }
  3879. else
  3880. {
  3881. m_LightNode3.m_Type = MATERIAL_LIGHT_SPOT;
  3882. }
  3883. if ( !m_bLightType4 )
  3884. {
  3885. m_LightNode4.m_Type = MATERIAL_LIGHT_POINT;
  3886. }
  3887. else
  3888. {
  3889. m_LightNode4.m_Type = MATERIAL_LIGHT_SPOT;
  3890. }
  3891. if ( !m_bLightDynamic1 && ( m_LightColor1 != Color( 0, 0, 0, 255 ) ) )
  3892. {
  3893. m_bLightActive1 = true;
  3894. }
  3895. else
  3896. {
  3897. m_bLightActive1 = false;
  3898. }
  3899. if ( !m_bLightDynamic2 && ( m_LightColor2 != Color( 0, 0, 0, 255 ) ) )
  3900. {
  3901. m_bLightActive2 = true;
  3902. }
  3903. else
  3904. {
  3905. m_bLightActive2 = false;
  3906. }
  3907. if ( !m_bLightDynamic3 && ( m_LightColor3 != Color( 0, 0, 0, 255 ) ) )
  3908. {
  3909. m_bLightActive3 = true;
  3910. }
  3911. else
  3912. {
  3913. m_bLightActive3 = false;
  3914. }
  3915. if ( !m_bLightDynamic4 && ( m_LightColor4 != Color( 0, 0, 0, 255 ) ) )
  3916. {
  3917. m_bLightActive4 = true;
  3918. }
  3919. else
  3920. {
  3921. m_bLightActive4 = false;
  3922. }
  3923. m_LightNode1.SetupNewStyleAttenuation ( m_LightFiftyDist1, m_LightZeroDist1 );
  3924. m_LightNode2.SetupNewStyleAttenuation ( m_LightFiftyDist2, m_LightZeroDist2 );
  3925. m_LightNode3.SetupNewStyleAttenuation ( m_LightFiftyDist3, m_LightZeroDist3 );
  3926. m_LightNode4.SetupNewStyleAttenuation ( m_LightFiftyDist4, m_LightZeroDist4 );
  3927. }
  3928. void Render( CParticleCollection *pParticles ) const;
  3929. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  3930. };
  3931. DEFINE_PARTICLE_OPERATOR( C_OP_ControlpointLight, "Color Light from Control Point", OPERATOR_GENERIC );
  3932. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_ControlpointLight )
  3933. DMXELEMENT_UNPACK_FIELD( "Light 1 Control Point", "0", int, m_nControlPoint1 )
  3934. DMXELEMENT_UNPACK_FIELD( "Light 1 Control Point Offset", "0 0 0", Vector, m_vecCPOffset1 )
  3935. DMXELEMENT_UNPACK_FIELD( "Light 1 Type 0=Point 1=Spot", "0", bool, m_bLightType1 )
  3936. DMXELEMENT_UNPACK_FIELD( "Light 1 Color", "0 0 0 255", Color, m_LightColor1 )
  3937. DMXELEMENT_UNPACK_FIELD( "Light 1 Dynamic Light", "0", bool, m_bLightDynamic1 )
  3938. DMXELEMENT_UNPACK_FIELD( "Light 1 Direction", "0 0 0", Vector, m_LightNode1.m_Direction )
  3939. DMXELEMENT_UNPACK_FIELD( "Light 1 50% Distance", "100", float, m_LightFiftyDist1 )
  3940. DMXELEMENT_UNPACK_FIELD( "Light 1 0% Distance", "200", float, m_LightZeroDist1 )
  3941. DMXELEMENT_UNPACK_FIELD( "Light 1 Spot Inner Cone", "30.0", float, m_LightNode1.m_Theta )
  3942. DMXELEMENT_UNPACK_FIELD( "Light 1 Spot Outer Cone", "45.0", float, m_LightNode1.m_Phi )
  3943. DMXELEMENT_UNPACK_FIELD( "Light 2 Control Point", "0", int, m_nControlPoint2 )
  3944. DMXELEMENT_UNPACK_FIELD( "Light 2 Control Point Offset", "0 0 0", Vector, m_vecCPOffset2 )
  3945. DMXELEMENT_UNPACK_FIELD( "Light 2 Type 0=Point 1=Spot", "0", bool, m_bLightType2 )
  3946. DMXELEMENT_UNPACK_FIELD( "Light 2 Color", "0 0 0 255", Color, m_LightColor2 )
  3947. DMXELEMENT_UNPACK_FIELD( "Light 2 Dynamic Light", "0", bool, m_bLightDynamic2 )
  3948. DMXELEMENT_UNPACK_FIELD( "Light 2 Direction", "0 0 0", Vector, m_LightNode2.m_Direction )
  3949. DMXELEMENT_UNPACK_FIELD( "Light 2 50% Distance", "100", float, m_LightFiftyDist2 )
  3950. DMXELEMENT_UNPACK_FIELD( "Light 2 0% Distance", "200", float, m_LightZeroDist2 )
  3951. DMXELEMENT_UNPACK_FIELD( "Light 2 Spot Inner Cone", "30.0", float, m_LightNode2.m_Theta )
  3952. DMXELEMENT_UNPACK_FIELD( "Light 2 Spot Outer Cone", "45.0", float, m_LightNode2.m_Phi )
  3953. DMXELEMENT_UNPACK_FIELD( "Light 3 Control Point", "0", int, m_nControlPoint3 )
  3954. DMXELEMENT_UNPACK_FIELD( "Light 3 Control Point Offset", "0 0 0", Vector, m_vecCPOffset3 )
  3955. DMXELEMENT_UNPACK_FIELD( "Light 3 Type 0=Point 1=Spot", "0", bool, m_bLightType3 )
  3956. DMXELEMENT_UNPACK_FIELD( "Light 3 Color", "0 0 0 255", Color, m_LightColor3 )
  3957. DMXELEMENT_UNPACK_FIELD( "Light 3 Dynamic Light", "0", bool, m_bLightDynamic3 )
  3958. DMXELEMENT_UNPACK_FIELD( "Light 3 Direction", "0 0 0", Vector, m_LightNode3.m_Direction )
  3959. DMXELEMENT_UNPACK_FIELD( "Light 3 50% Distance", "100", float, m_LightFiftyDist3 )
  3960. DMXELEMENT_UNPACK_FIELD( "Light 3 0% Distance", "200", float, m_LightZeroDist3 )
  3961. DMXELEMENT_UNPACK_FIELD( "Light 3 Spot Inner Cone", "30.0", float, m_LightNode3.m_Theta )
  3962. DMXELEMENT_UNPACK_FIELD( "Light 3 Spot Outer Cone", "45.0", float, m_LightNode3.m_Phi )
  3963. DMXELEMENT_UNPACK_FIELD( "Light 4 Control Point", "0", int, m_nControlPoint4 )
  3964. DMXELEMENT_UNPACK_FIELD( "Light 4 Control Point Offset", "0 0 0", Vector, m_vecCPOffset4 )
  3965. DMXELEMENT_UNPACK_FIELD( "Light 4 Type 0=Point 1=Spot", "0", bool, m_bLightType4 )
  3966. DMXELEMENT_UNPACK_FIELD( "Light 4 Color", "0 0 0 255", Color, m_LightColor4 )
  3967. DMXELEMENT_UNPACK_FIELD( "Light 4 Dynamic Light", "0", bool, m_bLightDynamic4 )
  3968. DMXELEMENT_UNPACK_FIELD( "Light 4 Direction", "0 0 0", Vector, m_LightNode4.m_Direction )
  3969. DMXELEMENT_UNPACK_FIELD( "Light 4 50% Distance", "100", float, m_LightFiftyDist4 )
  3970. DMXELEMENT_UNPACK_FIELD( "Light 4 0% Distance", "200", float, m_LightZeroDist4 )
  3971. DMXELEMENT_UNPACK_FIELD( "Light 4 Spot Inner Cone", "30.0", float, m_LightNode4.m_Theta )
  3972. DMXELEMENT_UNPACK_FIELD( "Light 4 Spot Outer Cone", "45.0", float, m_LightNode4.m_Phi )
  3973. DMXELEMENT_UNPACK_FIELD( "Initial Color Bias", "0.0", float, m_flScale )
  3974. DMXELEMENT_UNPACK_FIELD( "Clamp Minimum Light Value to Initial Color", "0", bool, m_bClampLowerRange )
  3975. DMXELEMENT_UNPACK_FIELD( "Clamp Maximum Light Value to Initial Color", "0", bool, m_bClampUpperRange )
  3976. DMXELEMENT_UNPACK_FIELD( "Compute Normals From Control Points", "0", bool, m_bUseNormal )
  3977. DMXELEMENT_UNPACK_FIELD( "Half-Lambert Normals", "1", bool, m_bUseHLambert )
  3978. END_PARTICLE_OPERATOR_UNPACK( C_OP_ControlpointLight )
  3979. void C_OP_ControlpointLight::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  3980. {
  3981. //Set up location of each light - this needs to be done every time as the CP's can move
  3982. Vector vecLocation1, vecLocation2, vecLocation3, vecLocation4;
  3983. vecLocation1 = pParticles->GetControlPointAtCurrentTime( m_nControlPoint1 );
  3984. vecLocation2 = pParticles->GetControlPointAtCurrentTime( m_nControlPoint2 );
  3985. vecLocation3 = pParticles->GetControlPointAtCurrentTime( m_nControlPoint3 );
  3986. vecLocation4 = pParticles->GetControlPointAtCurrentTime( m_nControlPoint4 );
  3987. LightDesc_t LightNode1 = m_LightNode1;
  3988. LightDesc_t LightNode2 = m_LightNode2;
  3989. LightDesc_t LightNode3 = m_LightNode3;
  3990. LightDesc_t LightNode4 = m_LightNode3;
  3991. // Apply any offsets
  3992. LightNode1.m_Position = vecLocation1 + m_vecCPOffset1;
  3993. LightNode2.m_Position = vecLocation2 + m_vecCPOffset2;
  3994. LightNode3.m_Position = vecLocation3 + m_vecCPOffset3;
  3995. LightNode4.m_Position = vecLocation4 + m_vecCPOffset4;
  3996. C4VAttributeIterator pInitialColor( PARTICLE_ATTRIBUTE_TINT_RGB, pParticles );
  3997. C4VAttributeWriteIterator pColor( PARTICLE_ATTRIBUTE_TINT_RGB, pParticles );
  3998. C4VAttributeIterator pXYZ( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  3999. // Set up lighting conditions and attenuation
  4000. if ( m_bLightDynamic1 )
  4001. {
  4002. // Get the color and luminosity at this position
  4003. Color lc;
  4004. g_pParticleSystemMgr->Query()->GetLightingAtPoint( LightNode1.m_Position, lc );
  4005. LightNode1.m_Color[0] = lc[0] / 255.0f;
  4006. LightNode1.m_Color[1] = lc[1] / 255.0f;
  4007. LightNode1.m_Color[2] = lc[2] / 255.0f;
  4008. }
  4009. if ( m_bLightDynamic2 )
  4010. {
  4011. // Get the color and luminosity at this position
  4012. Color lc;
  4013. g_pParticleSystemMgr->Query()->GetLightingAtPoint( LightNode2.m_Position, lc );
  4014. LightNode2.m_Color[0] = lc[0] / 255.0f;
  4015. LightNode2.m_Color[1] = lc[1] / 255.0f;
  4016. LightNode2.m_Color[2] = lc[2] / 255.0f;
  4017. }
  4018. if ( m_bLightDynamic3 )
  4019. {
  4020. // Get the color and luminosity at this position
  4021. Color lc;
  4022. g_pParticleSystemMgr->Query()->GetLightingAtPoint( LightNode3.m_Position, lc );
  4023. LightNode3.m_Color[0] = lc[0] / 255.0f;
  4024. LightNode3.m_Color[1] = lc[1] / 255.0f;
  4025. LightNode3.m_Color[2] = lc[2] / 255.0f;
  4026. }
  4027. if ( m_bLightDynamic4 )
  4028. {
  4029. // Get the color and luminosity at this position
  4030. Color lc;
  4031. g_pParticleSystemMgr->Query()->GetLightingAtPoint( LightNode4.m_Position, lc );
  4032. LightNode4.m_Color[0] = lc[0] / 255.0f;
  4033. LightNode4.m_Color[1] = lc[1] / 255.0f;
  4034. LightNode4.m_Color[2] = lc[2] / 255.0f;
  4035. }
  4036. LightNode1.RecalculateDerivedValues();
  4037. LightNode2.RecalculateDerivedValues();
  4038. LightNode3.RecalculateDerivedValues();
  4039. LightNode4.RecalculateDerivedValues();
  4040. FourVectors vScale;
  4041. vScale.DuplicateVector( Vector(m_flScale, m_flScale, m_flScale) );
  4042. if ( m_bUseNormal )
  4043. {
  4044. FourVectors vCPPosition1, vCPPosition2, vCPPosition3, vCPPosition4;
  4045. //vCPPosition1.DuplicateVector( LightNode1.m_Position );
  4046. vCPPosition1.DuplicateVector( vecLocation1 );
  4047. vCPPosition2.DuplicateVector( vecLocation2 );
  4048. vCPPosition3.DuplicateVector( vecLocation3 );
  4049. vCPPosition4.DuplicateVector( vecLocation4 );
  4050. int nCtr = pParticles->m_nPaddedActiveParticles;
  4051. do
  4052. {
  4053. FourVectors vLighting = vScale;
  4054. vLighting *= *pInitialColor;
  4055. FourVectors vNormal = *pXYZ;
  4056. vNormal -= vCPPosition1;
  4057. vNormal.VectorNormalizeFast();
  4058. LightNode1.ComputeLightAtPoints( *pXYZ, vNormal, vLighting, m_bUseHLambert );
  4059. vNormal = *pXYZ;
  4060. vNormal -= vCPPosition2;
  4061. vNormal.VectorNormalizeFast();
  4062. LightNode2.ComputeLightAtPoints( *pXYZ, vNormal, vLighting, m_bUseHLambert );
  4063. vNormal = *pXYZ;
  4064. vNormal -= vCPPosition3;
  4065. vNormal.VectorNormalizeFast();
  4066. LightNode3.ComputeLightAtPoints( *pXYZ, vNormal, vLighting, m_bUseHLambert );
  4067. vNormal = *pXYZ;
  4068. vNormal -= vCPPosition4;
  4069. vNormal.VectorNormalizeFast();
  4070. LightNode4.ComputeLightAtPoints( *pXYZ, vNormal, vLighting, m_bUseHLambert );
  4071. if ( m_bClampLowerRange )
  4072. {
  4073. FourVectors vInitialClamp = *pInitialColor;
  4074. vLighting.x = MaxSIMD( vLighting.x, vInitialClamp.x );
  4075. vLighting.y = MaxSIMD( vLighting.y, vInitialClamp.y );
  4076. vLighting.z = MaxSIMD( vLighting.z, vInitialClamp.z );
  4077. }
  4078. else
  4079. {
  4080. vLighting.x = MaxSIMD( vLighting.x, Four_Zeros );
  4081. vLighting.y = MaxSIMD( vLighting.y, Four_Zeros );
  4082. vLighting.z = MaxSIMD( vLighting.z, Four_Zeros );
  4083. }
  4084. if ( m_bClampUpperRange )
  4085. {
  4086. FourVectors vInitialClamp = *pInitialColor;
  4087. vLighting.x = MinSIMD( vLighting.x, vInitialClamp.x );
  4088. vLighting.y = MinSIMD( vLighting.y, vInitialClamp.y );
  4089. vLighting.z = MinSIMD( vLighting.z, vInitialClamp.z );
  4090. }
  4091. else
  4092. {
  4093. vLighting.x = MinSIMD( vLighting.x, Four_Ones );
  4094. vLighting.y = MinSIMD( vLighting.y, Four_Ones );
  4095. vLighting.z = MinSIMD( vLighting.z, Four_Ones );
  4096. }
  4097. *pColor = vLighting;
  4098. ++pColor;
  4099. ++pXYZ;
  4100. ++pInitialColor;
  4101. } while (--nCtr);
  4102. }
  4103. else
  4104. {
  4105. int nCtr = pParticles->m_nPaddedActiveParticles;
  4106. do
  4107. {
  4108. FourVectors vLighting = vScale;
  4109. vLighting *= *pInitialColor;
  4110. LightNode1.ComputeNonincidenceLightAtPoints( *pXYZ, vLighting );
  4111. LightNode2.ComputeNonincidenceLightAtPoints( *pXYZ, vLighting );
  4112. LightNode3.ComputeNonincidenceLightAtPoints( *pXYZ, vLighting );
  4113. LightNode4.ComputeNonincidenceLightAtPoints( *pXYZ, vLighting );
  4114. if ( m_bClampLowerRange )
  4115. {
  4116. FourVectors vInitialClamp = *pInitialColor;
  4117. vLighting.x = MaxSIMD( vLighting.x, vInitialClamp.x );
  4118. vLighting.y = MaxSIMD( vLighting.y, vInitialClamp.y );
  4119. vLighting.z = MaxSIMD( vLighting.z, vInitialClamp.z );
  4120. }
  4121. else
  4122. {
  4123. vLighting.x = MaxSIMD( vLighting.x, Four_Zeros );
  4124. vLighting.y = MaxSIMD( vLighting.y, Four_Zeros );
  4125. vLighting.z = MaxSIMD( vLighting.z, Four_Zeros );
  4126. }
  4127. if ( m_bClampUpperRange )
  4128. {
  4129. FourVectors vInitialClamp = *pInitialColor;
  4130. vLighting.x = MinSIMD( vLighting.x, vInitialClamp.x );
  4131. vLighting.y = MinSIMD( vLighting.y, vInitialClamp.y );
  4132. vLighting.z = MinSIMD( vLighting.z, vInitialClamp.z );
  4133. }
  4134. else
  4135. {
  4136. vLighting.x = MinSIMD( vLighting.x, Four_Ones );
  4137. vLighting.y = MinSIMD( vLighting.y, Four_Ones );
  4138. vLighting.z = MinSIMD( vLighting.z, Four_Ones );
  4139. }
  4140. *pColor = vLighting;
  4141. ++pColor;
  4142. ++pXYZ;
  4143. ++pInitialColor;
  4144. } while (--nCtr);
  4145. }
  4146. };
  4147. //-----------------------------------------------------------------------------
  4148. // Render visualization
  4149. //-----------------------------------------------------------------------------
  4150. void C_OP_ControlpointLight::Render( CParticleCollection *pParticles ) const
  4151. {
  4152. Vector vecOrigin1 = pParticles->GetControlPointAtCurrentTime( m_nControlPoint1 );
  4153. vecOrigin1 += m_vecCPOffset1;
  4154. Vector vecOrigin2 = pParticles->GetControlPointAtCurrentTime( m_nControlPoint2 );
  4155. vecOrigin2 += m_vecCPOffset2;
  4156. Vector vecOrigin3 = pParticles->GetControlPointAtCurrentTime( m_nControlPoint3 );
  4157. vecOrigin3 += m_vecCPOffset3;
  4158. Vector vecOrigin4 = pParticles->GetControlPointAtCurrentTime( m_nControlPoint4 );
  4159. vecOrigin4 += m_vecCPOffset4;
  4160. Color LightColor1Outer;
  4161. LightColor1Outer[0] = m_LightColor1[0] / 2.0f;
  4162. LightColor1Outer[1] = m_LightColor1[1] / 2.0f;
  4163. LightColor1Outer[2] = m_LightColor1[2] / 2.0f;
  4164. LightColor1Outer[3] = 255;
  4165. Color LightColor2Outer;
  4166. LightColor2Outer[0] = m_LightColor2[0] / 2.0f;
  4167. LightColor2Outer[1] = m_LightColor2[1] / 2.0f;
  4168. LightColor2Outer[2] = m_LightColor2[2] / 2.0f;
  4169. LightColor2Outer[3] = 255;
  4170. Color LightColor3Outer;
  4171. LightColor3Outer[0] = m_LightColor3[0] / 2.0f;
  4172. LightColor3Outer[1] = m_LightColor3[1] / 2.0f;
  4173. LightColor3Outer[2] = m_LightColor3[2] / 2.0f;
  4174. LightColor3Outer[3] = 255;
  4175. Color LightColor4Outer;
  4176. LightColor4Outer[0] = m_LightColor4[0] / 2.0f;
  4177. LightColor4Outer[1] = m_LightColor4[1] / 2.0f;
  4178. LightColor4Outer[2] = m_LightColor4[2] / 2.0f;
  4179. LightColor4Outer[3] = 255;
  4180. if ( m_bLightActive1 )
  4181. {
  4182. RenderWireframeSphere( vecOrigin1, m_LightFiftyDist1, 16, 8, m_LightColor1, false );
  4183. RenderWireframeSphere( vecOrigin1, m_LightZeroDist1, 16, 8, LightColor1Outer, false );
  4184. }
  4185. if ( m_bLightActive2 )
  4186. {
  4187. RenderWireframeSphere( vecOrigin2, m_LightFiftyDist2, 16, 8, m_LightColor2, false );
  4188. RenderWireframeSphere( vecOrigin2, m_LightZeroDist2, 16, 8, LightColor2Outer, false );
  4189. }
  4190. if ( m_bLightActive3 )
  4191. {
  4192. RenderWireframeSphere( vecOrigin3, m_LightFiftyDist3, 16, 8, m_LightColor3, false );
  4193. RenderWireframeSphere( vecOrigin3, m_LightZeroDist3, 16, 8, LightColor3Outer, false );
  4194. }
  4195. if ( m_bLightActive4 )
  4196. {
  4197. RenderWireframeSphere( vecOrigin4, m_LightFiftyDist4, 16, 8, m_LightColor4, false );
  4198. RenderWireframeSphere( vecOrigin4, m_LightZeroDist4, 16, 8, LightColor4Outer, false );
  4199. }
  4200. }
  4201. // set child controlpoints - copy the positions of our particles to the control points of a child
  4202. class C_OP_SetChildControlPoints : public CParticleOperatorInstance
  4203. {
  4204. DECLARE_PARTICLE_OPERATOR( C_OP_SetChildControlPoints );
  4205. int m_nChildGroupID;
  4206. int m_nFirstControlPoint;
  4207. int m_nNumControlPoints;
  4208. int m_nFirstSourcePoint;
  4209. bool m_bSetOrientation;
  4210. uint32 GetWrittenAttributes( void ) const
  4211. {
  4212. return 0;
  4213. }
  4214. uint32 GetReadAttributes( void ) const
  4215. {
  4216. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  4217. }
  4218. uint32 GetFilter( void ) const
  4219. {
  4220. return FILTER_POSITION_AND_VELOCITY_MASK;
  4221. }
  4222. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  4223. };
  4224. DEFINE_PARTICLE_OPERATOR( C_OP_SetChildControlPoints, "Set child control points from particle positions", OPERATOR_GENERIC );
  4225. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_SetChildControlPoints )
  4226. DMXELEMENT_UNPACK_FIELD( "Group ID to affect", "0", int, m_nChildGroupID )
  4227. DMXELEMENT_UNPACK_FIELD( "First control point to set", "0", int, m_nFirstControlPoint )
  4228. DMXELEMENT_UNPACK_FIELD( "# of control points to set", "1", int, m_nNumControlPoints )
  4229. DMXELEMENT_UNPACK_FIELD( "first particle to copy", "0", int, m_nFirstSourcePoint )
  4230. DMXELEMENT_UNPACK_FIELD( "set orientation", "0", bool, m_bSetOrientation )
  4231. END_PARTICLE_OPERATOR_UNPACK( C_OP_SetChildControlPoints )
  4232. void C_OP_SetChildControlPoints::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  4233. {
  4234. int nFirst=MAX(0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nFirstControlPoint ) );
  4235. int nToSet=MIN( pParticles->m_nActiveParticles-m_nFirstSourcePoint, m_nNumControlPoints );
  4236. nToSet=MIN( nToSet, MAX_PARTICLE_CONTROL_POINTS-nFirst );
  4237. if ( nToSet )
  4238. {
  4239. for( CParticleCollection *pChild = pParticles->m_Children.m_pHead; pChild; pChild = pChild->m_pNext )
  4240. {
  4241. if ( pChild->GetGroupID() == m_nChildGroupID )
  4242. {
  4243. for( int p=0; p < nToSet; p++ )
  4244. {
  4245. const float *pXYZ = pParticles->GetFloatAttributePtr(
  4246. PARTICLE_ATTRIBUTE_XYZ, p + m_nFirstSourcePoint );
  4247. Vector cPnt( pXYZ[0], pXYZ[4], pXYZ[8] );
  4248. pChild->SetControlPoint( p+nFirst, cPnt );
  4249. if ( m_bSetOrientation )
  4250. {
  4251. const float *pXYZ_Prev = pParticles->GetFloatAttributePtr(
  4252. PARTICLE_ATTRIBUTE_PREV_XYZ, p + m_nFirstSourcePoint );
  4253. Vector vecXYZ, vecXYZPrev;
  4254. SetVectorFromAttribute( vecXYZ, pXYZ );
  4255. SetVectorFromAttribute( vecXYZPrev, pXYZ_Prev );
  4256. Vector vecFwd = vecXYZ - vecXYZPrev;
  4257. vecFwd.NormalizeInPlace();
  4258. Vector vecRight, vecUp;
  4259. VectorVectors( vecFwd, vecRight, vecUp );
  4260. pChild->SetControlPointOrientation( p+nFirst, vecFwd, vecRight, vecUp );
  4261. }
  4262. }
  4263. }
  4264. }
  4265. }
  4266. }
  4267. // set controlpoints - copy the positions of our particles to the control points of self
  4268. class C_OP_SetControlPointsToParticle : public CParticleOperatorInstance
  4269. {
  4270. DECLARE_PARTICLE_OPERATOR( C_OP_SetControlPointsToParticle );
  4271. int m_nChildGroupID;
  4272. int m_nFirstControlPoint;
  4273. int m_nNumControlPoints;
  4274. int m_nFirstSourcePoint;
  4275. bool m_bSetOrientation;
  4276. uint32 GetWrittenAttributes( void ) const
  4277. {
  4278. return 0;
  4279. }
  4280. uint32 GetReadAttributes( void ) const
  4281. {
  4282. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  4283. }
  4284. uint32 GetFilter( void ) const
  4285. {
  4286. return FILTER_POSITION_AND_VELOCITY_MASK;
  4287. }
  4288. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  4289. };
  4290. DEFINE_PARTICLE_OPERATOR( C_OP_SetControlPointsToParticle, "Set control points from particle positions", OPERATOR_GENERIC );
  4291. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_SetControlPointsToParticle )
  4292. DMXELEMENT_UNPACK_FIELD( "First control point to set", "0", int, m_nFirstControlPoint )
  4293. DMXELEMENT_UNPACK_FIELD( "# of control points to set", "1", int, m_nNumControlPoints )
  4294. DMXELEMENT_UNPACK_FIELD( "first particle to copy", "0", int, m_nFirstSourcePoint )
  4295. DMXELEMENT_UNPACK_FIELD( "set orientation", "0", bool, m_bSetOrientation )
  4296. END_PARTICLE_OPERATOR_UNPACK( C_OP_SetControlPointsToParticle )
  4297. void C_OP_SetControlPointsToParticle::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  4298. {
  4299. int nFirst=MAX(0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nFirstControlPoint ) );
  4300. int nToSet=MIN( pParticles->m_nActiveParticles-m_nFirstSourcePoint, m_nNumControlPoints );
  4301. nToSet=MIN( nToSet, MAX_PARTICLE_CONTROL_POINTS-nFirst );
  4302. if ( nToSet )
  4303. {
  4304. for( int p=0; p < nToSet; p++ )
  4305. {
  4306. const float *pXYZ = pParticles->GetFloatAttributePtr(
  4307. PARTICLE_ATTRIBUTE_XYZ, p + m_nFirstSourcePoint );
  4308. Vector cPnt( pXYZ[0], pXYZ[4], pXYZ[8] );
  4309. pParticles->SetControlPoint( p+nFirst, cPnt );
  4310. if ( m_bSetOrientation )
  4311. {
  4312. const float *pXYZ_Prev = pParticles->GetFloatAttributePtr(
  4313. PARTICLE_ATTRIBUTE_PREV_XYZ, p + m_nFirstSourcePoint );
  4314. Vector vecXYZ, vecXYZPrev;
  4315. SetVectorFromAttribute( vecXYZ, pXYZ );
  4316. SetVectorFromAttribute( vecXYZPrev, pXYZ_Prev );
  4317. Vector vecFwd = vecXYZ - vecXYZPrev;
  4318. vecFwd.NormalizeInPlace();
  4319. Vector vecRight, vecUp;
  4320. VectorVectors( vecFwd, vecRight, vecUp );
  4321. pParticles->SetControlPointOrientation( p+nFirst, vecFwd, vecRight, vecUp );
  4322. }
  4323. }
  4324. }
  4325. }
  4326. // set per child controlpoint - copy the positions of each particles to a single control point of a single child
  4327. class C_OP_SetPerChildControlPoint : public CParticleOperatorInstance
  4328. {
  4329. DECLARE_PARTICLE_OPERATOR( C_OP_SetPerChildControlPoint );
  4330. int m_nChildGroupID;
  4331. int m_nFirstControlPoint;
  4332. int m_nNumControlPoints;
  4333. int m_nFirstSourcePoint;
  4334. int m_nSkip;
  4335. bool m_bSetOrientation;
  4336. uint32 GetWrittenAttributes( void ) const
  4337. {
  4338. return 0;
  4339. }
  4340. uint32 GetReadAttributes( void ) const
  4341. {
  4342. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_PARTICLE_ID;
  4343. }
  4344. uint32 GetFilter( void ) const
  4345. {
  4346. return FILTER_POSITION_AND_VELOCITY_MASK;
  4347. }
  4348. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  4349. };
  4350. DEFINE_PARTICLE_OPERATOR( C_OP_SetPerChildControlPoint, "Set per child control point from particle positions", OPERATOR_GENERIC );
  4351. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_SetPerChildControlPoint )
  4352. DMXELEMENT_UNPACK_FIELD( "Group ID to affect", "0", int, m_nChildGroupID )
  4353. DMXELEMENT_UNPACK_FIELD( "control point to set", "0", int, m_nFirstControlPoint )
  4354. DMXELEMENT_UNPACK_FIELD( "# of children to set", "1", int, m_nNumControlPoints )
  4355. DMXELEMENT_UNPACK_FIELD( "first particle to copy", "0", int, m_nFirstSourcePoint )
  4356. DMXELEMENT_UNPACK_FIELD( "set orientation", "0", bool, m_bSetOrientation )
  4357. END_PARTICLE_OPERATOR_UNPACK( C_OP_SetPerChildControlPoint )
  4358. void C_OP_SetPerChildControlPoint::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  4359. {
  4360. int nToSet=MIN ( m_nNumControlPoints, MIN( pParticles->m_nActiveParticles-m_nFirstSourcePoint, pParticles->m_Children.Count() ) );
  4361. if ( nToSet )
  4362. {
  4363. int nCurrentPoint = m_nFirstSourcePoint;
  4364. for( CParticleCollection *pChild = pParticles->m_Children.m_pHead; pChild; pChild = pChild->m_pNext )
  4365. {
  4366. if ( pChild->GetGroupID() == m_nChildGroupID && nToSet )
  4367. {
  4368. const float *pXYZ = pParticles->GetFloatAttributePtr(
  4369. PARTICLE_ATTRIBUTE_XYZ, nCurrentPoint );
  4370. Vector cPnt( pXYZ[0], pXYZ[4], pXYZ[8] );
  4371. pChild->SetControlPoint( m_nFirstControlPoint, cPnt );
  4372. if ( m_bSetOrientation )
  4373. {
  4374. const float *pXYZ_Prev = pParticles->GetFloatAttributePtr(
  4375. PARTICLE_ATTRIBUTE_PREV_XYZ, nCurrentPoint );
  4376. Vector vecXYZ, vecXYZPrev;
  4377. SetVectorFromAttribute( vecXYZ, pXYZ );
  4378. SetVectorFromAttribute( vecXYZPrev, pXYZ_Prev );
  4379. Vector vecFwd = vecXYZ - vecXYZPrev;
  4380. vecFwd.NormalizeInPlace();
  4381. Vector vecRight, vecUp;
  4382. VectorVectors( vecFwd, vecRight, vecUp );
  4383. pChild->SetControlPointOrientation( m_nFirstControlPoint, vecFwd, vecRight, vecUp );
  4384. }
  4385. nToSet--;
  4386. nCurrentPoint++;
  4387. }
  4388. }
  4389. }
  4390. }
  4391. //-----------------------------------------------------------------------------
  4392. // Set Control Point Positions
  4393. //-----------------------------------------------------------------------------
  4394. class C_OP_SetControlPointPositions : public CParticleOperatorInstance
  4395. {
  4396. DECLARE_PARTICLE_OPERATOR( C_OP_SetControlPointPositions );
  4397. bool m_bUseWorldLocation;
  4398. int m_nCP1, m_nCP1Parent;
  4399. int m_nCP2, m_nCP2Parent;
  4400. int m_nCP3, m_nCP3Parent;
  4401. int m_nCP4, m_nCP4Parent;
  4402. Vector m_vecCP1Pos, m_vecCP2Pos, m_vecCP3Pos, m_vecCP4Pos;
  4403. int m_nHeadLocation;
  4404. uint32 GetWrittenAttributes( void ) const
  4405. {
  4406. return 0;
  4407. }
  4408. uint32 GetReadAttributes( void ) const
  4409. {
  4410. return 0;
  4411. }
  4412. uint32 GetFilter( void ) const
  4413. {
  4414. return FILTER_CONTROL_POINTS_MASK;
  4415. }
  4416. bool ShouldRunBeforeEmitters( void ) const
  4417. {
  4418. return true;
  4419. }
  4420. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  4421. virtual uint64 GetReadControlPointMask() const
  4422. {
  4423. int nRet = 0;
  4424. // these accesses are actually writes but we need them to end up in the mask
  4425. nRet |= ( 1ll << m_nCP1 ) | ( 1ll << m_nCP2 ) | ( 1ll << m_nCP3 ) | ( 1ll << m_nCP4 );
  4426. if ( m_bUseWorldLocation )
  4427. return nRet;
  4428. else
  4429. return nRet | ( 1ll << m_nHeadLocation );
  4430. }
  4431. };
  4432. DEFINE_PARTICLE_OPERATOR( C_OP_SetControlPointPositions, "Set Control Point Positions", OPERATOR_GENERIC );
  4433. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_SetControlPointPositions )
  4434. DMXELEMENT_UNPACK_FIELD( "First Control Point Number", "1", int, m_nCP1 )
  4435. DMXELEMENT_UNPACK_FIELD( "First Control Point Parent", "0", int, m_nCP1Parent )
  4436. DMXELEMENT_UNPACK_FIELD( "First Control Point Location", "128 0 0", Vector, m_vecCP1Pos )
  4437. DMXELEMENT_UNPACK_FIELD( "Second Control Point Number", "2", int, m_nCP2 )
  4438. DMXELEMENT_UNPACK_FIELD( "Second Control Point Parent", "0", int, m_nCP2Parent )
  4439. DMXELEMENT_UNPACK_FIELD( "Second Control Point Location", "0 128 0", Vector, m_vecCP2Pos )
  4440. DMXELEMENT_UNPACK_FIELD( "Third Control Point Number", "3", int, m_nCP3 )
  4441. DMXELEMENT_UNPACK_FIELD( "Third Control Point Parent", "0", int, m_nCP3Parent )
  4442. DMXELEMENT_UNPACK_FIELD( "Third Control Point Location", "-128 0 0", Vector, m_vecCP3Pos )
  4443. DMXELEMENT_UNPACK_FIELD( "Fourth Control Point Number", "4", int, m_nCP4 )
  4444. DMXELEMENT_UNPACK_FIELD( "Fourth Control Point Parent", "0", int, m_nCP4Parent )
  4445. DMXELEMENT_UNPACK_FIELD( "Fourth Control Point Location", "0 -128 0", Vector, m_vecCP4Pos )
  4446. DMXELEMENT_UNPACK_FIELD( "Set positions in world space", "0", bool, m_bUseWorldLocation )
  4447. DMXELEMENT_UNPACK_FIELD( "Control Point to offset positions from", "0", int, m_nHeadLocation )
  4448. END_PARTICLE_OPERATOR_UNPACK( C_OP_SetControlPointPositions )
  4449. void C_OP_SetControlPointPositions::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  4450. {
  4451. if ( !m_bUseWorldLocation )
  4452. {
  4453. Vector vecControlPoint = pParticles->GetControlPointAtCurrentTime( m_nHeadLocation );
  4454. matrix3x4_t mat;
  4455. pParticles->GetControlPointTransformAtTime( m_nHeadLocation, pParticles->m_flCurTime, &mat );
  4456. Vector vecTransformLocal = vec3_origin;
  4457. VectorTransform( m_vecCP1Pos, mat, vecTransformLocal );
  4458. pParticles->SetControlPoint( m_nCP1, vecTransformLocal );
  4459. pParticles->SetControlPointParent( m_nCP1, m_nCP1Parent );
  4460. VectorTransform( m_vecCP2Pos, mat, vecTransformLocal );
  4461. pParticles->SetControlPoint( m_nCP2, vecTransformLocal );
  4462. pParticles->SetControlPointParent( m_nCP2, m_nCP2Parent );
  4463. VectorTransform( m_vecCP3Pos, mat, vecTransformLocal );
  4464. pParticles->SetControlPoint( m_nCP3, vecTransformLocal );
  4465. pParticles->SetControlPointParent( m_nCP3, m_nCP3Parent );
  4466. VectorTransform( m_vecCP4Pos, mat, vecTransformLocal );
  4467. pParticles->SetControlPoint( m_nCP4, vecTransformLocal );
  4468. pParticles->SetControlPointParent( m_nCP4, m_nCP4Parent );
  4469. }
  4470. else
  4471. {
  4472. pParticles->SetControlPoint( m_nCP1, m_vecCP1Pos );
  4473. pParticles->SetControlPointParent( m_nCP1, m_nCP1Parent );
  4474. pParticles->SetControlPoint( m_nCP2, m_vecCP2Pos );
  4475. pParticles->SetControlPointParent( m_nCP2, m_nCP2Parent );
  4476. pParticles->SetControlPoint( m_nCP3, m_vecCP3Pos );
  4477. pParticles->SetControlPointParent( m_nCP3, m_nCP3Parent );
  4478. pParticles->SetControlPoint( m_nCP4, m_vecCP4Pos );
  4479. pParticles->SetControlPointParent( m_nCP4, m_nCP4Parent );
  4480. }
  4481. }
  4482. //-----------------------------------------------------------------------------
  4483. // Dampen Movement Relative to Control Point
  4484. // The closer a particle is the the assigned control point, the less
  4485. // it can move
  4486. //-----------------------------------------------------------------------------
  4487. class C_OP_DampenToCP : public CParticleOperatorInstance
  4488. {
  4489. DECLARE_PARTICLE_OPERATOR( C_OP_DampenToCP );
  4490. int m_nControlPointNumber;
  4491. float m_flRange, m_flScale;
  4492. uint32 GetWrittenAttributes( void ) const
  4493. {
  4494. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  4495. }
  4496. uint32 GetReadAttributes( void ) const
  4497. {
  4498. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK |
  4499. PARTICLE_ATTRIBUTE_PARTICLE_ID_MASK;
  4500. }
  4501. virtual uint64 GetReadControlPointMask() const
  4502. {
  4503. return ( 1ULL << m_nControlPointNumber );
  4504. }
  4505. void InitParams( CParticleSystemDefinition *pDef )
  4506. {
  4507. m_nControlPointNumber = MAX( 0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nControlPointNumber ) );
  4508. }
  4509. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  4510. };
  4511. DEFINE_PARTICLE_OPERATOR( C_OP_DampenToCP , "Movement Dampen Relative to Control Point", OPERATOR_GENERIC );
  4512. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_DampenToCP )
  4513. DMXELEMENT_UNPACK_FIELD( "control_point_number", "0", int, m_nControlPointNumber )
  4514. DMXELEMENT_UNPACK_FIELD( "falloff range", "100", float, m_flRange )
  4515. DMXELEMENT_UNPACK_FIELD( "dampen scale", "1", float, m_flScale )
  4516. END_PARTICLE_OPERATOR_UNPACK( C_OP_DampenToCP )
  4517. void C_OP_DampenToCP::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  4518. {
  4519. if ( m_flRange <= 0.0f )
  4520. return;
  4521. Vector vecControlPoint = pParticles->GetControlPointAtCurrentTime( m_nControlPointNumber );
  4522. // FIXME: SSE-ize
  4523. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  4524. {
  4525. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, i );
  4526. float *xyz_prev = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  4527. Vector vecParticlePosition, vecParticlePosition_prev, vParticleDelta ;
  4528. SetVectorFromAttribute( vecParticlePosition, xyz );
  4529. SetVectorFromAttribute( vecParticlePosition_prev, xyz_prev );
  4530. Vector ofs;
  4531. ofs = vecParticlePosition - vecControlPoint;
  4532. float flDistance = ofs.Length();
  4533. float flDampenAmount;
  4534. if ( flDistance > m_flRange )
  4535. {
  4536. continue;
  4537. }
  4538. else
  4539. {
  4540. flDampenAmount = flDistance / m_flRange;
  4541. flDampenAmount = pow( flDampenAmount, m_flScale);
  4542. }
  4543. vParticleDelta = vecParticlePosition - vecParticlePosition_prev;
  4544. Vector vParticleDampened = vParticleDelta * flDampenAmount;
  4545. vecParticlePosition = vecParticlePosition_prev + vParticleDampened;
  4546. Vector vecParticlePositionOrg;
  4547. SetVectorFromAttribute( vecParticlePositionOrg, xyz );
  4548. VectorLerp (vecParticlePositionOrg, vecParticlePosition, flStrength, vecParticlePosition );
  4549. SetVectorAttribute( xyz, vecParticlePosition );
  4550. }
  4551. };
  4552. //-----------------------------------------------------------------------------
  4553. // Distance Between CP Operator
  4554. //-----------------------------------------------------------------------------
  4555. class C_OP_DistanceBetweenCPs : public CParticleOperatorInstance
  4556. {
  4557. DECLARE_PARTICLE_OPERATOR( C_OP_DistanceBetweenCPs );
  4558. uint32 GetWrittenAttributes( void ) const
  4559. {
  4560. return 1 << m_nFieldOutput;
  4561. }
  4562. uint32 GetReadAttributes( void ) const
  4563. {
  4564. return 0;
  4565. }
  4566. uint32 GetReadInitialAttributes( void ) const
  4567. {
  4568. return 1 << m_nFieldOutput;
  4569. }
  4570. uint32 GetFilter( void ) const
  4571. {
  4572. return FILTER_PARAMETER_REMAPPING_MASK;
  4573. }
  4574. virtual uint64 GetReadControlPointMask() const
  4575. {
  4576. return ( 1ULL << m_nStartCP ) | ( 1ULL << m_nEndCP );
  4577. }
  4578. void InitParams( CParticleSystemDefinition *pDef )
  4579. {
  4580. m_nCollisionGroupNumber = g_pParticleSystemMgr->Query()->GetCollisionGroupFromName( m_CollisionGroupName );
  4581. m_nStartCP = MAX( 0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nStartCP ) );
  4582. m_nEndCP = MAX( 0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nEndCP ) );
  4583. }
  4584. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  4585. int m_nFieldOutput;
  4586. int m_nStartCP;
  4587. int m_nEndCP;
  4588. int m_nCollisionGroupNumber;
  4589. float m_flInputMin;
  4590. float m_flInputMax;
  4591. float m_flOutputMin;
  4592. float m_flOutputMax;
  4593. float m_flMaxTraceLength;
  4594. float m_flLOSScale;
  4595. char m_CollisionGroupName[128];
  4596. bool m_bLOS;
  4597. bool m_bScaleInitialRange;
  4598. bool m_bScaleCurrent;
  4599. };
  4600. DEFINE_PARTICLE_OPERATOR( C_OP_DistanceBetweenCPs, "Remap Distance Between Two Control Points to Scalar", OPERATOR_GENERIC );
  4601. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_DistanceBetweenCPs )
  4602. DMXELEMENT_UNPACK_FIELD( "distance minimum","0", float, m_flInputMin )
  4603. DMXELEMENT_UNPACK_FIELD( "distance maximum","128", float, m_flInputMax )
  4604. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "3", int, m_nFieldOutput, "intchoice particlefield_scalar" )
  4605. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  4606. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  4607. DMXELEMENT_UNPACK_FIELD( "starting control point","0", int, m_nStartCP )
  4608. DMXELEMENT_UNPACK_FIELD( "ending control point","1", int, m_nEndCP )
  4609. DMXELEMENT_UNPACK_FIELD( "ensure line of sight","0", bool, m_bLOS )
  4610. DMXELEMENT_UNPACK_FIELD_STRING( "LOS collision group", "NONE", m_CollisionGroupName )
  4611. DMXELEMENT_UNPACK_FIELD( "Maximum Trace Length", "-1", float, m_flMaxTraceLength )
  4612. DMXELEMENT_UNPACK_FIELD( "LOS Failure Scalar", "0", float, m_flLOSScale )
  4613. DMXELEMENT_UNPACK_FIELD( "output is scalar of initial random range","0", bool, m_bScaleInitialRange )
  4614. DMXELEMENT_UNPACK_FIELD( "output is scalar of current value","0", bool, m_bScaleCurrent )
  4615. END_PARTICLE_OPERATOR_UNPACK( C_OP_DistanceBetweenCPs )
  4616. void C_OP_DistanceBetweenCPs::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  4617. {
  4618. // clamp the result to 0 and 1 if it's alpha
  4619. float flMin=m_flOutputMin;
  4620. float flMax=m_flOutputMax;
  4621. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & ( 1 << m_nFieldOutput ) )
  4622. {
  4623. flMin = clamp(m_flOutputMin, 0.0f, 1.0f );
  4624. flMax = clamp(m_flOutputMax, 0.0f, 1.0f );
  4625. }
  4626. Vector vecControlPoint1 = pParticles->GetControlPointAtCurrentTime( m_nStartCP );
  4627. Vector vecControlPoint2 = pParticles->GetControlPointAtCurrentTime( m_nEndCP );
  4628. Vector vecDelta = vecControlPoint1 - vecControlPoint2;
  4629. float flDistance = vecDelta.Length();
  4630. if ( m_bLOS )
  4631. {
  4632. Vector vecEndPoint = vecControlPoint2;
  4633. if ( m_flMaxTraceLength != -1.0f && m_flMaxTraceLength < flDistance )
  4634. {
  4635. VectorNormalize(vecEndPoint);
  4636. vecEndPoint *= m_flMaxTraceLength;
  4637. vecEndPoint += vecControlPoint1;
  4638. }
  4639. CBaseTrace tr;
  4640. g_pParticleSystemMgr->Query()->TraceLine( vecControlPoint1, vecEndPoint, MASK_OPAQUE_AND_NPCS, NULL, m_nCollisionGroupNumber, &tr );
  4641. if (tr.fraction != 1.0f)
  4642. {
  4643. flDistance *= tr.fraction * m_flLOSScale;
  4644. }
  4645. }
  4646. // FIXME: SSE-ize
  4647. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  4648. {
  4649. float flOutput = RemapValClamped( flDistance, m_flInputMin, m_flInputMax, flMin, flMax );
  4650. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, i );
  4651. if ( m_bScaleInitialRange )
  4652. {
  4653. const float *pInitialOutput = pParticles->GetInitialFloatAttributePtr( m_nFieldOutput, i );
  4654. flOutput = *pInitialOutput * flOutput;
  4655. }
  4656. if ( m_bScaleCurrent )
  4657. {
  4658. flOutput *= *pOutput;
  4659. }
  4660. *pOutput = Lerp (flStrength, *pOutput, flOutput);
  4661. }
  4662. }
  4663. //-----------------------------------------------------------------------------
  4664. // Distance Between CP to CP Operator
  4665. //-----------------------------------------------------------------------------
  4666. class C_OP_DistanceBetweenCPsToCP : public CParticleOperatorInstance
  4667. {
  4668. DECLARE_PARTICLE_OPERATOR( C_OP_DistanceBetweenCPsToCP );
  4669. uint32 GetWrittenAttributes( void ) const
  4670. {
  4671. return 0;
  4672. }
  4673. uint32 GetReadAttributes( void ) const
  4674. {
  4675. return 0;
  4676. }
  4677. uint32 GetFilter( void ) const
  4678. {
  4679. return FILTER_PARAMETER_REMAPPING_MASK;
  4680. }
  4681. virtual uint64 GetReadControlPointMask() const
  4682. {
  4683. return ( 1ULL << m_nStartCP ) | ( 1ULL << m_nEndCP ) | ( 1ULL << m_nOutputCP );
  4684. }
  4685. void InitParams( CParticleSystemDefinition *pDef )
  4686. {
  4687. m_nCollisionGroupNumber = g_pParticleSystemMgr->Query()->GetCollisionGroupFromName( m_CollisionGroupName );
  4688. m_nStartCP = MAX( 0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nStartCP ) );
  4689. m_nEndCP = MAX( 0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nEndCP ) );
  4690. m_nOutputCP = MAX( 0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nOutputCP ) );
  4691. m_nOutputCPField = MAX( 0, MIN( 2, m_nOutputCPField ) );
  4692. }
  4693. bool ShouldRunBeforeEmitters( void ) const
  4694. {
  4695. return true;
  4696. }
  4697. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  4698. int m_nStartCP;
  4699. int m_nEndCP;
  4700. int m_nOutputCP;
  4701. int m_nOutputCPField;
  4702. int m_nCollisionGroupNumber;
  4703. float m_flInputMin;
  4704. float m_flInputMax;
  4705. float m_flOutputMin;
  4706. float m_flOutputMax;
  4707. float m_flMaxTraceLength;
  4708. float m_flLOSScale;
  4709. bool m_bLOS;
  4710. char m_CollisionGroupName[128];
  4711. };
  4712. DEFINE_PARTICLE_OPERATOR( C_OP_DistanceBetweenCPsToCP, "Remap Distance Between Two Control Points to CP", OPERATOR_GENERIC );
  4713. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_DistanceBetweenCPsToCP )
  4714. DMXELEMENT_UNPACK_FIELD( "distance minimum","0", float, m_flInputMin )
  4715. DMXELEMENT_UNPACK_FIELD( "distance maximum","128", float, m_flInputMax )
  4716. DMXELEMENT_UNPACK_FIELD( "output control point", "2", int, m_nOutputCP )
  4717. DMXELEMENT_UNPACK_FIELD( "output control point field", "0", int, m_nOutputCPField )
  4718. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  4719. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  4720. DMXELEMENT_UNPACK_FIELD( "starting control point","0", int, m_nStartCP )
  4721. DMXELEMENT_UNPACK_FIELD( "ending control point","1", int, m_nEndCP )
  4722. DMXELEMENT_UNPACK_FIELD( "ensure line of sight","0", bool, m_bLOS )
  4723. DMXELEMENT_UNPACK_FIELD_STRING( "LOS collision group", "NONE", m_CollisionGroupName )
  4724. DMXELEMENT_UNPACK_FIELD( "Maximum Trace Length", "-1", float, m_flMaxTraceLength )
  4725. DMXELEMENT_UNPACK_FIELD( "LOS Failure Scale", "0", float, m_flLOSScale )
  4726. END_PARTICLE_OPERATOR_UNPACK( C_OP_DistanceBetweenCPsToCP )
  4727. void C_OP_DistanceBetweenCPsToCP::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  4728. {
  4729. Vector vecControlPoint1 = pParticles->GetControlPointAtCurrentTime( m_nStartCP );
  4730. Vector vecControlPoint2 = pParticles->GetControlPointAtCurrentTime( m_nEndCP );
  4731. Vector vecDelta = vecControlPoint1 - vecControlPoint2;
  4732. float flDistance = vecDelta.Length();
  4733. if ( m_bLOS )
  4734. {
  4735. Vector vecEndPoint = vecControlPoint2;
  4736. if ( m_flMaxTraceLength != -1.0f && m_flMaxTraceLength < flDistance )
  4737. {
  4738. VectorNormalize(vecEndPoint);
  4739. vecEndPoint *= m_flMaxTraceLength;
  4740. vecEndPoint += vecControlPoint1;
  4741. }
  4742. CBaseTrace tr;
  4743. g_pParticleSystemMgr->Query()->TraceLine( vecControlPoint1, vecEndPoint, MASK_OPAQUE_AND_NPCS, NULL, m_nCollisionGroupNumber, &tr );
  4744. if (tr.fraction != 1.0f)
  4745. {
  4746. flDistance *= tr.fraction * m_flLOSScale;
  4747. }
  4748. }
  4749. flDistance = RemapValClamped( flDistance, m_flInputMin, m_flInputMax, m_flOutputMin, m_flOutputMax );
  4750. Vector vecControlPointOutput = pParticles->GetControlPointAtCurrentTime( m_nOutputCP );
  4751. vecControlPointOutput[m_nOutputCPField] = flDistance;
  4752. pParticles->SetControlPoint( m_nOutputCP, vecControlPointOutput );
  4753. }
  4754. //-----------------------------------------------------------------------------
  4755. // Percentage Between CP to Scalar Operator
  4756. //-----------------------------------------------------------------------------
  4757. class C_OP_PercentageBetweenCPs : public CParticleOperatorInstance
  4758. {
  4759. DECLARE_PARTICLE_OPERATOR( C_OP_PercentageBetweenCPs );
  4760. uint32 GetWrittenAttributes( void ) const
  4761. {
  4762. return 1 << m_nFieldOutput;
  4763. }
  4764. uint32 GetReadAttributes( void ) const
  4765. {
  4766. return PARTICLE_ATTRIBUTE_XYZ_MASK;
  4767. }
  4768. uint32 GetReadInitialAttributes( void ) const
  4769. {
  4770. return 1 << m_nFieldOutput;
  4771. }
  4772. uint32 GetFilter( void ) const
  4773. {
  4774. return FILTER_PARAMETER_REMAPPING_MASK;
  4775. }
  4776. virtual uint64 GetReadControlPointMask() const
  4777. {
  4778. return ( 1ULL << m_nStartCP ) | ( 1ULL << m_nEndCP );
  4779. }
  4780. void InitParams( CParticleSystemDefinition *pDef )
  4781. {
  4782. m_nStartCP = MAX( 0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nStartCP ) );
  4783. m_nEndCP = MAX( 0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nEndCP ) );
  4784. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & ( 1 << m_nFieldOutput ) )
  4785. {
  4786. m_flOutputMin = clamp(m_flOutputMin, 0.0f, 1.0f );
  4787. m_flOutputMax = clamp(m_flOutputMax, 0.0f, 1.0f );
  4788. }
  4789. }
  4790. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  4791. int m_nFieldOutput;
  4792. float m_flInputMin;
  4793. float m_flInputMax;
  4794. float m_flOutputMin;
  4795. float m_flOutputMax;
  4796. int m_nStartCP;
  4797. int m_nEndCP;
  4798. bool m_bScaleInitialRange;
  4799. bool m_bScaleCurrent;
  4800. bool m_bActiveRange;
  4801. bool m_bRadialCheck;
  4802. };
  4803. DEFINE_PARTICLE_OPERATOR( C_OP_PercentageBetweenCPs, "Remap Percentage Between Two Control Points to Scalar", OPERATOR_GENERIC );
  4804. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_PercentageBetweenCPs )
  4805. DMXELEMENT_UNPACK_FIELD( "percentage minimum","0", float, m_flInputMin )
  4806. DMXELEMENT_UNPACK_FIELD( "percentage maximum","1", float, m_flInputMax )
  4807. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "3", int, m_nFieldOutput, "intchoice particlefield_scalar" )
  4808. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  4809. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  4810. DMXELEMENT_UNPACK_FIELD( "starting control point","0", int, m_nStartCP )
  4811. DMXELEMENT_UNPACK_FIELD( "ending control point","1", int, m_nEndCP )
  4812. DMXELEMENT_UNPACK_FIELD( "output is scalar of initial random range","0", bool, m_bScaleInitialRange )
  4813. DMXELEMENT_UNPACK_FIELD( "output is scalar of current value","0", bool, m_bScaleCurrent )
  4814. DMXELEMENT_UNPACK_FIELD( "only active within input range","0", bool, m_bActiveRange )
  4815. DMXELEMENT_UNPACK_FIELD( "treat distance between points as radius","1", bool, m_bRadialCheck )
  4816. END_PARTICLE_OPERATOR_UNPACK( C_OP_PercentageBetweenCPs )
  4817. void C_OP_PercentageBetweenCPs::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  4818. {
  4819. Vector vecControlPoint1 = pParticles->GetControlPointAtCurrentTime( m_nStartCP );
  4820. Vector vecControlPoint2 = pParticles->GetControlPointAtCurrentTime( m_nEndCP );
  4821. C4VAttributeIterator xyz( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  4822. CM128AttributeWriteIterator pOutField( m_nFieldOutput, pParticles) ;
  4823. CM128InitialAttributeIterator pInitialValue( m_nFieldOutput, pParticles) ;
  4824. FourVectors fvControlPoint1;
  4825. FourVectors fvControlpoint2;
  4826. fvControlPoint1.DuplicateVector( pParticles->GetControlPointAtCurrentTime( m_nStartCP ) );
  4827. fvControlpoint2.DuplicateVector( pParticles->GetControlPointAtCurrentTime( m_nEndCP ) );
  4828. FourVectors fvDelta = fvControlPoint1 - fvControlpoint2;
  4829. fltx4 fl4Distance = fvDelta.length();
  4830. fltx4 fl4InputMin = ReplicateX4( m_flInputMin );
  4831. fltx4 fl4InputMax = ReplicateX4( m_flInputMax );
  4832. fltx4 fl4OutputMin = ReplicateX4( m_flOutputMin );
  4833. fltx4 fl4OutputMax = ReplicateX4( m_flOutputMax );
  4834. int nCtr = pParticles->m_nPaddedActiveParticles;
  4835. do
  4836. {
  4837. fltx4 fl4Perc;
  4838. fltx4 fl4ParticleDistance;
  4839. if ( m_bRadialCheck )
  4840. {
  4841. FourVectors fvParticleDelta;
  4842. fvParticleDelta.DuplicateVector( vecControlPoint1 );
  4843. fvParticleDelta -= *xyz;
  4844. fl4ParticleDistance = AddSIMD ( fvParticleDelta.length(), Four_Epsilons );
  4845. fl4Perc = DivSIMD( Four_Ones, DivSIMD( fl4Distance, fl4ParticleDistance ));
  4846. }
  4847. else
  4848. {
  4849. FourVectors fvClosestPoint;
  4850. xyz->CalcClosestPointOnLineSIMD( *xyz, fvControlPoint1, fvControlpoint2, fvClosestPoint, &fl4Perc );
  4851. }
  4852. fltx4 fl4Output = RemapValClampedSIMD( fl4Perc, fl4InputMin, fl4InputMax, fl4OutputMin, fl4OutputMax );
  4853. if ( m_bScaleInitialRange )
  4854. {
  4855. fl4Output = MulSIMD( fl4Output, *pInitialValue );
  4856. }
  4857. if ( m_bScaleCurrent )
  4858. {
  4859. fl4Output = MulSIMD( fl4Output, *pOutField );
  4860. }
  4861. if ( m_bActiveRange )
  4862. {
  4863. bi32x4 fl4GoodMask = CmpGeSIMD( fl4Perc, fl4InputMin );
  4864. fl4GoodMask = AndSIMD( fl4GoodMask, CmpLeSIMD( fl4Perc, fl4InputMax ) );
  4865. *pOutField = MaskedAssign( fl4GoodMask, fl4Output, *pOutField );
  4866. }
  4867. else
  4868. {
  4869. *pOutField = fl4Output;
  4870. }
  4871. ++pOutField;
  4872. ++xyz;
  4873. ++pInitialValue;
  4874. } while( --nCtr );
  4875. }
  4876. //-----------------------------------------------------------------------------
  4877. // Percentage Between CP to Vector Operator
  4878. //-----------------------------------------------------------------------------
  4879. class C_OP_PercentageBetweenCPsVector : public CParticleOperatorInstance
  4880. {
  4881. DECLARE_PARTICLE_OPERATOR( C_OP_PercentageBetweenCPsVector );
  4882. uint32 GetWrittenAttributes( void ) const
  4883. {
  4884. return 1 << m_nFieldOutput;
  4885. }
  4886. uint32 GetReadAttributes( void ) const
  4887. {
  4888. return PARTICLE_ATTRIBUTE_XYZ_MASK;
  4889. }
  4890. uint32 GetReadInitialAttributes( void ) const
  4891. {
  4892. return 1 << m_nFieldOutput;
  4893. }
  4894. uint32 GetFilter( void ) const
  4895. {
  4896. return FILTER_PARAMETER_REMAPPING_MASK;
  4897. }
  4898. virtual uint64 GetReadControlPointMask() const
  4899. {
  4900. return ( 1ULL << m_nStartCP ) | ( 1ULL << m_nEndCP );
  4901. }
  4902. void InitParams( CParticleSystemDefinition *pDef )
  4903. {
  4904. m_nStartCP = MAX( 0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nStartCP ) );
  4905. m_nEndCP = MAX( 0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nEndCP ) );
  4906. }
  4907. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  4908. int m_nFieldOutput;
  4909. float m_flInputMin;
  4910. float m_flInputMax;
  4911. Vector m_vecOutputMin;
  4912. Vector m_vecOutputMax;
  4913. int m_nStartCP;
  4914. int m_nEndCP;
  4915. bool m_bScaleInitialRange;
  4916. bool m_bScaleCurrent;
  4917. bool m_bActiveRange;
  4918. bool m_bRadialCheck;
  4919. };
  4920. DEFINE_PARTICLE_OPERATOR( C_OP_PercentageBetweenCPsVector, "Remap Percentage Between Two Control Points to Vector", OPERATOR_GENERIC );
  4921. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_PercentageBetweenCPsVector )
  4922. DMXELEMENT_UNPACK_FIELD( "percentage minimum","0", float, m_flInputMin )
  4923. DMXELEMENT_UNPACK_FIELD( "percentage maximum","1", float, m_flInputMax )
  4924. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "6", int, m_nFieldOutput, "intchoice particlefield_vector" )
  4925. DMXELEMENT_UNPACK_FIELD( "output minimum","0 0 0", Vector, m_vecOutputMin )
  4926. DMXELEMENT_UNPACK_FIELD( "output maximum","1 1 1", Vector, m_vecOutputMax )
  4927. DMXELEMENT_UNPACK_FIELD( "starting control point","0", int, m_nStartCP )
  4928. DMXELEMENT_UNPACK_FIELD( "ending control point","1", int, m_nEndCP )
  4929. DMXELEMENT_UNPACK_FIELD( "output is scalar of initial random range","0", bool, m_bScaleInitialRange )
  4930. DMXELEMENT_UNPACK_FIELD( "output is scalar of current value","0", bool, m_bScaleCurrent )
  4931. DMXELEMENT_UNPACK_FIELD( "only active within input range","0", bool, m_bActiveRange )
  4932. DMXELEMENT_UNPACK_FIELD( "treat distance between points as radius","1", bool, m_bRadialCheck )
  4933. END_PARTICLE_OPERATOR_UNPACK( C_OP_PercentageBetweenCPsVector )
  4934. void C_OP_PercentageBetweenCPsVector::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  4935. {
  4936. Vector vecControlPoint1 = pParticles->GetControlPointAtCurrentTime( m_nStartCP );
  4937. Vector vecControlPoint2 = pParticles->GetControlPointAtCurrentTime( m_nEndCP );
  4938. C4VAttributeIterator xyz( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  4939. C4VAttributeWriteIterator pOutField( m_nFieldOutput, pParticles) ;
  4940. C4VInitialAttributeIterator pInitialValue( m_nFieldOutput, pParticles) ;
  4941. FourVectors fvControlPoint1;
  4942. FourVectors fvControlpoint2;
  4943. fvControlPoint1.DuplicateVector( pParticles->GetControlPointAtCurrentTime( m_nStartCP ) );
  4944. fvControlpoint2.DuplicateVector( pParticles->GetControlPointAtCurrentTime( m_nEndCP ) );
  4945. FourVectors fvDelta = fvControlPoint1 - fvControlpoint2;
  4946. fltx4 fl4Distance = fvDelta.length();
  4947. fltx4 fl4InputMin = ReplicateX4( m_flInputMin );
  4948. fltx4 fl4InputMax = ReplicateX4( m_flInputMax );
  4949. FourVectors fvOutputMin;
  4950. FourVectors fvOutputMax;
  4951. fvOutputMin.DuplicateVector( m_vecOutputMin );
  4952. fvOutputMax.DuplicateVector( m_vecOutputMax );
  4953. int nCtr = pParticles->m_nPaddedActiveParticles;
  4954. do
  4955. {
  4956. fltx4 fl4Perc;
  4957. fltx4 fl4ParticleDistance;
  4958. if ( m_bRadialCheck )
  4959. {
  4960. FourVectors fvParticleDelta;
  4961. fvParticleDelta.DuplicateVector( vecControlPoint1 );
  4962. fvParticleDelta -= *xyz;
  4963. fl4ParticleDistance = AddSIMD ( fvParticleDelta.length(), Four_Epsilons );
  4964. fl4Perc = DivSIMD( Four_Ones, DivSIMD( fl4Distance, fl4ParticleDistance ));
  4965. }
  4966. else
  4967. {
  4968. FourVectors fvClosestPoint;
  4969. xyz->CalcClosestPointOnLineSIMD( *xyz, fvControlPoint1, fvControlpoint2, fvClosestPoint, &fl4Perc );
  4970. }
  4971. FourVectors fvOutput;
  4972. fvOutput.x = RemapValClampedSIMD( fl4Perc, fl4InputMin, fl4InputMax, fvOutputMin.x, fvOutputMax.x );
  4973. fvOutput.y = RemapValClampedSIMD( fl4Perc, fl4InputMin, fl4InputMax, fvOutputMin.y, fvOutputMax.y );
  4974. fvOutput.z = RemapValClampedSIMD( fl4Perc, fl4InputMin, fl4InputMax, fvOutputMin.z, fvOutputMax.z );
  4975. if ( m_bScaleInitialRange )
  4976. {
  4977. fvOutput *= *pInitialValue;
  4978. }
  4979. if ( m_bScaleCurrent )
  4980. {
  4981. fvOutput *= *pOutField;
  4982. }
  4983. if ( m_bActiveRange )
  4984. {
  4985. bi32x4 fl4GoodMask = CmpGeSIMD( fl4Perc, fl4InputMin );
  4986. fl4GoodMask = AndSIMD( fl4GoodMask, CmpLeSIMD( fl4Perc, fl4InputMax ) );
  4987. *pOutField = MaskedAssign( fl4GoodMask, fvOutput, *pOutField );
  4988. }
  4989. else
  4990. {
  4991. *pOutField = fvOutput;
  4992. }
  4993. ++pOutField;
  4994. ++xyz;
  4995. ++pInitialValue;
  4996. } while( --nCtr );
  4997. }
  4998. //-----------------------------------------------------------------------------
  4999. // Distance to CP Operator
  5000. //-----------------------------------------------------------------------------
  5001. class C_OP_DistanceToCP : public CParticleOperatorInstance
  5002. {
  5003. DECLARE_PARTICLE_OPERATOR( C_OP_DistanceToCP );
  5004. uint32 GetWrittenAttributes( void ) const
  5005. {
  5006. return 1 << m_nFieldOutput;
  5007. }
  5008. uint32 GetReadAttributes( void ) const
  5009. {
  5010. return PARTICLE_ATTRIBUTE_XYZ_MASK;
  5011. }
  5012. uint32 GetReadInitialAttributes( void ) const
  5013. {
  5014. return 1 << m_nFieldOutput;
  5015. }
  5016. uint32 GetFilter( void ) const
  5017. {
  5018. return FILTER_PARAMETER_REMAPPING_MASK;
  5019. }
  5020. virtual uint64 GetReadControlPointMask() const
  5021. {
  5022. return ( 1ULL << m_nStartCP );
  5023. }
  5024. void InitParams( CParticleSystemDefinition *pDef )
  5025. {
  5026. m_nCollisionGroupNumber = g_pParticleSystemMgr->Query()->GetCollisionGroupFromName( m_CollisionGroupName );
  5027. m_nStartCP = MAX( 0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nStartCP ) );
  5028. }
  5029. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  5030. int m_nFieldOutput;
  5031. float m_flInputMin;
  5032. float m_flInputMax;
  5033. float m_flOutputMin;
  5034. float m_flOutputMax;
  5035. int m_nStartCP;
  5036. bool m_bLOS;
  5037. char m_CollisionGroupName[128];
  5038. int m_nCollisionGroupNumber;
  5039. float m_flMaxTraceLength;
  5040. float m_flLOSScale;
  5041. bool m_bScaleInitialRange;
  5042. bool m_bScaleCurrent;
  5043. bool m_bActiveRange;
  5044. };
  5045. DEFINE_PARTICLE_OPERATOR( C_OP_DistanceToCP, "Remap Distance to Control Point to Scalar", OPERATOR_GENERIC );
  5046. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_DistanceToCP )
  5047. DMXELEMENT_UNPACK_FIELD( "distance minimum","0", float, m_flInputMin )
  5048. DMXELEMENT_UNPACK_FIELD( "distance maximum","128", float, m_flInputMax )
  5049. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "3", int, m_nFieldOutput, "intchoice particlefield_scalar" )
  5050. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  5051. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  5052. DMXELEMENT_UNPACK_FIELD( "control point","0", int, m_nStartCP )
  5053. DMXELEMENT_UNPACK_FIELD( "ensure line of sight","0", bool, m_bLOS )
  5054. DMXELEMENT_UNPACK_FIELD_STRING( "LOS collision group", "NONE", m_CollisionGroupName )
  5055. DMXELEMENT_UNPACK_FIELD( "Maximum Trace Length", "-1", float, m_flMaxTraceLength )
  5056. DMXELEMENT_UNPACK_FIELD( "LOS Failure Scalar", "0", float, m_flLOSScale )
  5057. DMXELEMENT_UNPACK_FIELD( "output is scalar of initial random range","0", bool, m_bScaleInitialRange )
  5058. DMXELEMENT_UNPACK_FIELD( "output is scalar of current value","0", bool, m_bScaleCurrent )
  5059. DMXELEMENT_UNPACK_FIELD( "only active within specified distance","0", bool, m_bActiveRange )
  5060. END_PARTICLE_OPERATOR_UNPACK( C_OP_DistanceToCP )
  5061. void C_OP_DistanceToCP::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  5062. {
  5063. // clamp the result to 0 and 1 if it's alpha
  5064. float flMin=m_flOutputMin;
  5065. float flMax=m_flOutputMax;
  5066. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & ( 1 << m_nFieldOutput ) )
  5067. {
  5068. flMin = clamp(m_flOutputMin, 0.0f, 1.0f );
  5069. flMax = clamp(m_flOutputMax, 0.0f, 1.0f );
  5070. }
  5071. Vector vecControlPoint1 = pParticles->GetControlPointAtCurrentTime( m_nStartCP );
  5072. // FIXME: SSE-ize
  5073. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  5074. {
  5075. Vector vecPosition2;
  5076. const float *pXYZ = pParticles->GetFloatAttributePtr(PARTICLE_ATTRIBUTE_XYZ, i );
  5077. vecPosition2 = Vector(pXYZ[0], pXYZ[4], pXYZ[8]);
  5078. Vector vecDelta = vecControlPoint1 - vecPosition2;
  5079. float flDistance = vecDelta.Length();
  5080. if ( m_bActiveRange && ( flDistance < m_flInputMin || flDistance > m_flInputMax ) )
  5081. {
  5082. continue;
  5083. }
  5084. if ( m_bLOS )
  5085. {
  5086. Vector vecEndPoint = vecPosition2;
  5087. if ( m_flMaxTraceLength != -1.0f && m_flMaxTraceLength < flDistance )
  5088. {
  5089. VectorNormalize(vecEndPoint);
  5090. vecEndPoint *= m_flMaxTraceLength;
  5091. vecEndPoint += vecControlPoint1;
  5092. }
  5093. CBaseTrace tr;
  5094. g_pParticleSystemMgr->Query()->TraceLine( vecControlPoint1, vecEndPoint, MASK_OPAQUE_AND_NPCS, NULL , m_nCollisionGroupNumber, &tr );
  5095. if (tr.fraction != 1.0f)
  5096. {
  5097. flDistance *= tr.fraction * m_flLOSScale;
  5098. }
  5099. }
  5100. float flOutput = RemapValClamped( flDistance, m_flInputMin, m_flInputMax, flMin, flMax );
  5101. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, i );
  5102. if ( m_bScaleInitialRange )
  5103. {
  5104. const float *pInitialOutput = pParticles->GetInitialFloatAttributePtr( m_nFieldOutput, i );
  5105. flOutput *= *pInitialOutput;
  5106. }
  5107. if ( m_bScaleCurrent )
  5108. {
  5109. flOutput *= *pOutput;
  5110. }
  5111. *pOutput = Lerp (flStrength, *pOutput, flOutput);
  5112. }
  5113. }
  5114. //-----------------------------------------------------------------------------
  5115. // Assign CP to Player
  5116. //-----------------------------------------------------------------------------
  5117. class C_OP_SetControlPointToPlayer : public CParticleOperatorInstance
  5118. {
  5119. DECLARE_PARTICLE_OPERATOR( C_OP_SetControlPointToPlayer );
  5120. int m_nCP1;
  5121. Vector m_vecCP1Pos;
  5122. bool m_bOrientToEyes;
  5123. uint32 GetWrittenAttributes( void ) const
  5124. {
  5125. return 0;
  5126. }
  5127. uint32 GetReadAttributes( void ) const
  5128. {
  5129. return 0;
  5130. }
  5131. uint32 GetFilter( void ) const
  5132. {
  5133. return FILTER_CONTROL_POINTS_MASK;
  5134. }
  5135. void InitParams( CParticleSystemDefinition *pDef )
  5136. {
  5137. m_nCP1 = MAX( 0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nCP1 ) );
  5138. }
  5139. bool ShouldRunBeforeEmitters( void ) const
  5140. {
  5141. return true;
  5142. }
  5143. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  5144. };
  5145. DEFINE_PARTICLE_OPERATOR( C_OP_SetControlPointToPlayer, "Set Control Point To Player", OPERATOR_GENERIC );
  5146. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_SetControlPointToPlayer )
  5147. DMXELEMENT_UNPACK_FIELD( "Control Point Number", "1", int, m_nCP1 )
  5148. DMXELEMENT_UNPACK_FIELD( "Control Point Offset", "0 0 0", Vector, m_vecCP1Pos )
  5149. DMXELEMENT_UNPACK_FIELD( "Use Eye Orientation", "0", bool, m_bOrientToEyes )
  5150. END_PARTICLE_OPERATOR_UNPACK( C_OP_SetControlPointToPlayer )
  5151. void C_OP_SetControlPointToPlayer::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  5152. {
  5153. Vector vecClientPos =g_pParticleSystemMgr->Query()->GetLocalPlayerPos();
  5154. pParticles->SetControlPoint( m_nCP1, m_vecCP1Pos + vecClientPos );
  5155. Vector vecForward;
  5156. Vector vecRight;
  5157. Vector vecUp;
  5158. g_pParticleSystemMgr->Query()->GetLocalPlayerEyeVectors( &vecForward, &vecRight, &vecUp );
  5159. if ( !m_bOrientToEyes )
  5160. {
  5161. if ( fabs( vecForward.z - 1.0f ) > 1e-3 )
  5162. {
  5163. vecForward.z = 0;
  5164. VectorNormalize( vecForward );
  5165. vecUp.Init( 0, 0, 1 );
  5166. vecRight.Init( vecForward.y, -vecForward.x, 0.0f );
  5167. }
  5168. }
  5169. pParticles->SetControlPointOrientation( m_nCP1, vecForward, vecRight, vecUp );
  5170. }
  5171. class C_OP_MoveToHitbox : public CParticleOperatorInstance
  5172. {
  5173. DECLARE_PARTICLE_OPERATOR( C_OP_MoveToHitbox );
  5174. int m_nControlPointNumber;
  5175. int m_nControlPointNumberOverride;
  5176. float m_flLifeTimeLerpStart;
  5177. float m_flLifeTimeLerpEnd;
  5178. char m_HitboxSetName[128];
  5179. uint32 GetWrittenAttributes( void ) const
  5180. {
  5181. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  5182. }
  5183. uint32 GetReadAttributes( void ) const
  5184. {
  5185. int ret= PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK |
  5186. PARTICLE_ATTRIBUTE_HITBOX_RELATIVE_XYZ_MASK | PARTICLE_ATTRIBUTE_HITBOX_INDEX_MASK;
  5187. ret |= PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  5188. return ret;
  5189. }
  5190. virtual uint64 GetReadControlPointMask() const
  5191. {
  5192. return ( 1ULL << m_nControlPointNumber );
  5193. }
  5194. void InitParams( CParticleSystemDefinition *pDef )
  5195. {
  5196. m_nControlPointNumber = MAX( 0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nControlPointNumber ) );
  5197. }
  5198. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  5199. };
  5200. DEFINE_PARTICLE_OPERATOR( C_OP_MoveToHitbox , "Movement Lerp to Hitbox", OPERATOR_GENERIC );
  5201. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_MoveToHitbox )
  5202. DMXELEMENT_UNPACK_FIELD( "control point number", "0", int, m_nControlPointNumber )
  5203. DMXELEMENT_UNPACK_FIELD( "lifetime lerp start", "0", float, m_flLifeTimeLerpStart )
  5204. DMXELEMENT_UNPACK_FIELD( "lifetime lerp end", "1", float, m_flLifeTimeLerpEnd )
  5205. DMXELEMENT_UNPACK_FIELD_STRING( "hitbox set", "effects", m_HitboxSetName )
  5206. END_PARTICLE_OPERATOR_UNPACK( C_OP_MoveToHitbox )
  5207. void C_OP_MoveToHitbox::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  5208. {
  5209. pParticles->UpdateHitBoxInfo( m_nControlPointNumber, m_HitboxSetName );
  5210. if ( pParticles->ControlPointHitBox( m_nControlPointNumber ).CurAndPrevValid() )
  5211. {
  5212. float flAgeThreshold = m_flLifeTimeLerpEnd;
  5213. if ( flAgeThreshold <= 0.0 )
  5214. flAgeThreshold = 1.0e20;
  5215. float flIScale = 0.0;
  5216. if ( m_flLifeTimeLerpEnd > m_flLifeTimeLerpStart )
  5217. flIScale = 1.0/( m_flLifeTimeLerpEnd - m_flLifeTimeLerpStart );
  5218. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  5219. {
  5220. float *pXYZ = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, i );
  5221. float *pPrevXYZ = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  5222. const float *pUVW = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_HITBOX_RELATIVE_XYZ, i );
  5223. const int nBoxIndex = *pParticles->GetIntAttributePtr( PARTICLE_ATTRIBUTE_HITBOX_INDEX, i );
  5224. float const *pCreationTime = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, i );
  5225. float flAge = pParticles->m_flCurTime -*pCreationTime;
  5226. if ( flAge < flAgeThreshold )
  5227. {
  5228. if (
  5229. ( nBoxIndex < pParticles->ControlPointHitBox( m_nControlPointNumber ).m_nNumHitBoxes ) &&
  5230. ( nBoxIndex < pParticles->ControlPointHitBox( m_nControlPointNumber ).m_nNumPrevHitBoxes ) &&
  5231. ( nBoxIndex >= 0 )
  5232. )
  5233. {
  5234. Vector vecParticlePosition;
  5235. ModelHitBoxInfo_t const &hb = pParticles->ControlPointHitBox( m_nControlPointNumber ).m_pHitBoxes[ nBoxIndex ];
  5236. vecParticlePosition.x = Lerp( pUVW[0], hb.m_vecBoxMins.x, hb.m_vecBoxMaxes.x );
  5237. vecParticlePosition.y = Lerp( pUVW[4], hb.m_vecBoxMins.y, hb.m_vecBoxMaxes.y );
  5238. vecParticlePosition.z = Lerp( pUVW[8], hb.m_vecBoxMins.z, hb.m_vecBoxMaxes.z );
  5239. Vector vecWorldPosition;
  5240. VectorTransform( vecParticlePosition, hb.m_Transform, vecWorldPosition );
  5241. if ( flAge > m_flLifeTimeLerpStart )
  5242. {
  5243. float flT = flStrength * ( ( ( flAge - m_flLifeTimeLerpStart ) * flIScale ) );
  5244. Vector vecDestPosition;
  5245. Vector xyz;
  5246. SetVectorFromAttribute( xyz, pXYZ );
  5247. VectorLerp( xyz, vecWorldPosition, flT, vecDestPosition );
  5248. SetVectorAttribute( pXYZ, vecDestPosition );
  5249. Vector prevxyz;
  5250. SetVectorFromAttribute( prevxyz, pPrevXYZ );
  5251. VectorLerp( prevxyz, vecWorldPosition, flT, vecDestPosition );
  5252. SetVectorAttribute( pPrevXYZ, vecDestPosition );
  5253. }
  5254. }
  5255. }
  5256. }
  5257. }
  5258. };
  5259. class C_OP_LockToBone : public CParticleOperatorInstance
  5260. {
  5261. DECLARE_PARTICLE_OPERATOR( C_OP_LockToBone );
  5262. int m_nControlPointNumber;
  5263. float m_flLifeTimeFadeStart;
  5264. float m_flLifeTimeFadeEnd;
  5265. char m_HitboxSetName[128];
  5266. uint32 GetWrittenAttributes( void ) const
  5267. {
  5268. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  5269. }
  5270. uint32 GetReadAttributes( void ) const
  5271. {
  5272. int ret= PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK |
  5273. PARTICLE_ATTRIBUTE_HITBOX_RELATIVE_XYZ_MASK | PARTICLE_ATTRIBUTE_HITBOX_INDEX_MASK;
  5274. ret |= PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  5275. return ret;
  5276. }
  5277. virtual uint64 GetReadControlPointMask() const
  5278. {
  5279. return ( 1ULL << m_nControlPointNumber );
  5280. }
  5281. void InitParams( CParticleSystemDefinition *pDef )
  5282. {
  5283. m_nControlPointNumber = MAX( 0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nControlPointNumber ) );
  5284. }
  5285. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  5286. };
  5287. DEFINE_PARTICLE_OPERATOR( C_OP_LockToBone , "Movement Lock to Bone", OPERATOR_GENERIC );
  5288. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_LockToBone )
  5289. DMXELEMENT_UNPACK_FIELD( "control_point_number", "0", int, m_nControlPointNumber )
  5290. DMXELEMENT_UNPACK_FIELD( "lifetime fade start", "0", float, m_flLifeTimeFadeStart )
  5291. DMXELEMENT_UNPACK_FIELD( "lifetime fade end", "0", float, m_flLifeTimeFadeEnd )
  5292. DMXELEMENT_UNPACK_FIELD_STRING( "hitbox set", "effects", m_HitboxSetName )
  5293. END_PARTICLE_OPERATOR_UNPACK( C_OP_LockToBone )
  5294. void C_OP_LockToBone::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  5295. {
  5296. pParticles->UpdateHitBoxInfo( m_nControlPointNumber, m_HitboxSetName );
  5297. if ( pParticles->ControlPointHitBox( m_nControlPointNumber ).CurAndPrevValid() )
  5298. {
  5299. float flAgeThreshold = m_flLifeTimeFadeEnd;
  5300. if ( flAgeThreshold <= 0.0 )
  5301. flAgeThreshold = 1.0e20;
  5302. float flIScale = 0.0;
  5303. if ( m_flLifeTimeFadeEnd > m_flLifeTimeFadeStart )
  5304. flIScale = 1.0/( m_flLifeTimeFadeEnd - m_flLifeTimeFadeStart );
  5305. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  5306. {
  5307. float *pXYZ = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, i );
  5308. float *pPrevXYZ = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  5309. const float *pUVW = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_HITBOX_RELATIVE_XYZ, i );
  5310. const int nBoxIndex = *pParticles->GetIntAttributePtr( PARTICLE_ATTRIBUTE_HITBOX_INDEX, i );
  5311. float const *pCreationTime = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, i );
  5312. float flAge = pParticles->m_flCurTime -*pCreationTime;
  5313. float flCreationFrameBias = MIN( flAge, pParticles->m_flDt );
  5314. flCreationFrameBias *= ( 1 / pParticles->m_flDt );
  5315. if ( flAge < flAgeThreshold )
  5316. {
  5317. if (
  5318. ( nBoxIndex < pParticles->ControlPointHitBox( m_nControlPointNumber ).m_nNumHitBoxes ) &&
  5319. ( nBoxIndex < pParticles->ControlPointHitBox( m_nControlPointNumber ).m_nNumPrevHitBoxes ) &&
  5320. ( nBoxIndex >= 0 )
  5321. )
  5322. {
  5323. Vector vecParticlePosition;
  5324. ModelHitBoxInfo_t const &hb = pParticles->ControlPointHitBox( m_nControlPointNumber ).m_pHitBoxes[ nBoxIndex ];
  5325. vecParticlePosition.x = Lerp( pUVW[0], hb.m_vecBoxMins.x, hb.m_vecBoxMaxes.x );
  5326. vecParticlePosition.y = Lerp( pUVW[4], hb.m_vecBoxMins.y, hb.m_vecBoxMaxes.y );
  5327. vecParticlePosition.z = Lerp( pUVW[8], hb.m_vecBoxMins.z, hb.m_vecBoxMaxes.z );
  5328. Vector vecWorldPosition;
  5329. VectorTransform( vecParticlePosition, hb.m_Transform, vecWorldPosition );
  5330. Vector vecPrevParticlePosition;
  5331. ModelHitBoxInfo_t phb = pParticles->ControlPointHitBox( m_nControlPointNumber ).m_pPrevBoxes[ nBoxIndex ];
  5332. vecPrevParticlePosition.x = Lerp( pUVW[0], phb.m_vecBoxMins.x, phb.m_vecBoxMaxes.x );
  5333. vecPrevParticlePosition.y = Lerp( pUVW[4], phb.m_vecBoxMins.y, phb.m_vecBoxMaxes.y );
  5334. vecPrevParticlePosition.z = Lerp( pUVW[8], phb.m_vecBoxMins.z, phb.m_vecBoxMaxes.z );
  5335. Vector vecPrevWorldPosition;
  5336. VectorTransform( vecPrevParticlePosition, phb.m_Transform, vecPrevWorldPosition );
  5337. Vector Delta = ( vecWorldPosition-vecPrevWorldPosition ) * flCreationFrameBias;
  5338. if ( flAge > m_flLifeTimeFadeStart )
  5339. Delta *= flStrength * ( 1.0- ( ( flAge - m_flLifeTimeFadeStart ) * flIScale ) );
  5340. Vector xyz;
  5341. SetVectorFromAttribute( xyz, pXYZ );
  5342. xyz += Delta;
  5343. SetVectorAttribute( pXYZ, xyz );
  5344. Vector prevxyz;
  5345. SetVectorFromAttribute( prevxyz, pPrevXYZ );
  5346. prevxyz += Delta;
  5347. SetVectorAttribute( pPrevXYZ, prevxyz );
  5348. }
  5349. }
  5350. }
  5351. }
  5352. };
  5353. //-----------------------------------------------------------------------------
  5354. // Sets control point to a specified point based on cp's
  5355. // percentage distance between two points
  5356. //-----------------------------------------------------------------------------
  5357. class C_OP_CPOffsetToPercentageBetweenCPs : public CParticleOperatorInstance
  5358. {
  5359. DECLARE_PARTICLE_OPERATOR( C_OP_CPOffsetToPercentageBetweenCPs );
  5360. uint32 GetWrittenAttributes( void ) const
  5361. {
  5362. return 0;
  5363. }
  5364. uint32 GetReadAttributes( void ) const
  5365. {
  5366. return 0;
  5367. }
  5368. uint32 GetReadInitialAttributes( void ) const
  5369. {
  5370. return 0;
  5371. }
  5372. uint32 GetFilter( void ) const
  5373. {
  5374. return FILTER_PARAMETER_REMAPPING_MASK;
  5375. }
  5376. virtual uint64 GetReadControlPointMask() const
  5377. {
  5378. return ( 1ULL << m_nStartCP ) | ( 1ULL << m_nEndCP ) | ( 1ULL << m_nOffsetCP ) | ( 1ULL << m_nOuputCP ) ;
  5379. }
  5380. void InitParams( CParticleSystemDefinition *pDef )
  5381. {
  5382. m_nStartCP = MAX( 0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nStartCP ) );
  5383. m_nEndCP = MAX( 0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nEndCP ) );
  5384. m_nOffsetCP = MAX( 0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nOffsetCP ) );
  5385. m_nOuputCP = MAX( 0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nOuputCP ) );
  5386. }
  5387. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  5388. float m_flInputMin;
  5389. float m_flInputMax;
  5390. float m_flInputBias;
  5391. int m_nStartCP;
  5392. int m_nEndCP;
  5393. int m_nOffsetCP;
  5394. int m_nOuputCP;
  5395. int m_nInputCP;
  5396. bool m_bRadialCheck;
  5397. bool m_bScaleOffset;
  5398. Vector m_vecOffset;
  5399. };
  5400. DEFINE_PARTICLE_OPERATOR( C_OP_CPOffsetToPercentageBetweenCPs, "Set CP Offset to CP Percentage Between Two Control Points", OPERATOR_GENERIC );
  5401. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_CPOffsetToPercentageBetweenCPs )
  5402. DMXELEMENT_UNPACK_FIELD( "percentage minimum","0", float, m_flInputMin )
  5403. DMXELEMENT_UNPACK_FIELD( "percentage maximum","1", float, m_flInputMax )
  5404. DMXELEMENT_UNPACK_FIELD( "percentage bias",".5", float, m_flInputBias )
  5405. DMXELEMENT_UNPACK_FIELD( "starting control point","0", int, m_nStartCP )
  5406. DMXELEMENT_UNPACK_FIELD( "ending control point","1", int, m_nEndCP )
  5407. DMXELEMENT_UNPACK_FIELD( "offset control point","2", int, m_nOffsetCP )
  5408. DMXELEMENT_UNPACK_FIELD( "input control point","3", int, m_nInputCP )
  5409. DMXELEMENT_UNPACK_FIELD( "output control point","4", int, m_nOuputCP )
  5410. DMXELEMENT_UNPACK_FIELD( "offset amount","0 0 0", Vector, m_vecOffset )
  5411. DMXELEMENT_UNPACK_FIELD( "treat distance between points as radius","1", bool, m_bRadialCheck )
  5412. DMXELEMENT_UNPACK_FIELD( "treat offset as scale of total distance","0", bool, m_bScaleOffset )
  5413. END_PARTICLE_OPERATOR_UNPACK( C_OP_CPOffsetToPercentageBetweenCPs )
  5414. void C_OP_CPOffsetToPercentageBetweenCPs::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  5415. {
  5416. Vector vecControlPoint1 = pParticles->GetControlPointAtCurrentTime( m_nStartCP );
  5417. Vector vecControlPoint2 = pParticles->GetControlPointAtCurrentTime( m_nEndCP );
  5418. Vector vecControlPointOffset = pParticles->GetControlPointAtCurrentTime( m_nOffsetCP );
  5419. Vector vecControlPointInput = pParticles->GetControlPointAtCurrentTime( m_nInputCP );
  5420. float flTotalDistance = ( vecControlPoint1 - vecControlPoint2 ).Length();
  5421. Vector vecOffsetInput = m_vecOffset;
  5422. if ( m_bScaleOffset )
  5423. vecOffsetInput *= flTotalDistance;
  5424. float flPercentage;
  5425. if ( m_bRadialCheck )
  5426. {
  5427. Vector vecCPDelta = vecControlPoint1 - vecControlPointInput;
  5428. float flDistance = vecCPDelta.Length() + FLT_EPSILON;
  5429. flPercentage = 1 / ( flTotalDistance / flDistance );
  5430. }
  5431. else
  5432. {
  5433. Vector vecClosestPoint;
  5434. CalcClosestPointOnLine( vecControlPointInput, vecControlPoint1, vecControlPoint2, vecClosestPoint, &flPercentage );
  5435. }
  5436. flPercentage = RemapValClamped( flPercentage, m_flInputMin, m_flInputMax, 0.0f, 1.0f );
  5437. flPercentage = Bias( flPercentage, m_flInputBias );
  5438. Vector vecOffsetAmt = VectorLerp( vec3_origin, vecOffsetInput, flPercentage );
  5439. Vector vecControlPointOutput = vecControlPointOffset + vecOffsetAmt;
  5440. pParticles->SetControlPoint( m_nOuputCP, vecControlPointOutput );
  5441. }
  5442. //-----------------------------------------------------------------------------
  5443. // Plane Cull Operator - cull particles on the "wrong" side of a plane
  5444. //-----------------------------------------------------------------------------
  5445. class C_OP_PlaneCull : public CParticleOperatorInstance
  5446. {
  5447. int m_nPlaneControlPoint;
  5448. Vector m_vecPlaneDirection;
  5449. float m_flPlaneOffset;
  5450. DECLARE_PARTICLE_OPERATOR( C_OP_PlaneCull );
  5451. uint32 GetWrittenAttributes( void ) const
  5452. {
  5453. return 0;
  5454. }
  5455. uint32 GetReadAttributes( void ) const
  5456. {
  5457. return PARTICLE_ATTRIBUTE_XYZ_MASK;
  5458. }
  5459. uint32 GetFilter( void ) const
  5460. {
  5461. return FILTER_LIFE_DURATION_MASK;
  5462. }
  5463. virtual uint64 GetReadControlPointMask() const
  5464. {
  5465. return ( 1ULL << m_nPlaneControlPoint );
  5466. }
  5467. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  5468. };
  5469. DEFINE_PARTICLE_OPERATOR( C_OP_PlaneCull, "Cull when crossing plane", OPERATOR_GENERIC );
  5470. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_PlaneCull )
  5471. DMXELEMENT_UNPACK_FIELD( "Control Point for point on plane", "0", int, m_nPlaneControlPoint )
  5472. DMXELEMENT_UNPACK_FIELD( "Cull plane offset", "0", float, m_flPlaneOffset )
  5473. DMXELEMENT_UNPACK_FIELD( "Plane Normal", "0 0 1", Vector, m_vecPlaneDirection )
  5474. END_PARTICLE_OPERATOR_UNPACK( C_OP_PlaneCull )
  5475. void C_OP_PlaneCull::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  5476. {
  5477. C4VAttributeIterator pXYZ( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  5478. int nLimit = pParticles->m_nPaddedActiveParticles << 2;
  5479. // setup vars
  5480. FourVectors v4N ;
  5481. v4N.DuplicateVector( m_vecPlaneDirection );
  5482. v4N.VectorNormalize();
  5483. FourVectors v4Pnt;
  5484. v4Pnt.DuplicateVector( pParticles->GetControlPointAtCurrentTime( m_nPlaneControlPoint ) );
  5485. FourVectors ofs = v4N;
  5486. ofs *= ReplicateX4( m_flPlaneOffset );
  5487. v4Pnt -= ofs;
  5488. for ( int i = 0; i < nLimit; i+= 4 )
  5489. {
  5490. FourVectors f4PlaneRel = (*pXYZ );
  5491. f4PlaneRel -= v4Pnt;
  5492. fltx4 fl4PlaneEq = ( f4PlaneRel * v4N );
  5493. if ( IsAnyNegative( fl4PlaneEq ) )
  5494. {
  5495. // not especially pretty - we need to kill some particles.
  5496. int nMask = TestSignSIMD( fl4PlaneEq );
  5497. if ( nMask & 1 )
  5498. pParticles->KillParticle( i );
  5499. if ( nMask & 2 )
  5500. pParticles->KillParticle( i + 1 );
  5501. if ( nMask & 4 )
  5502. pParticles->KillParticle( i + 2 );
  5503. if ( nMask & 8 )
  5504. pParticles->KillParticle( i + 3 );
  5505. }
  5506. ++pXYZ;
  5507. }
  5508. }
  5509. //-----------------------------------------------------------------------------
  5510. // Distance Cull Operator - cull particles on the "wrong" side of a plane
  5511. //-----------------------------------------------------------------------------
  5512. class C_OP_DistanceCull : public CParticleOperatorInstance
  5513. {
  5514. int m_nControlPoint;
  5515. Vector m_vecPointOffset;
  5516. float m_flDistance;
  5517. bool m_bCullInside;
  5518. DECLARE_PARTICLE_OPERATOR( C_OP_DistanceCull );
  5519. uint32 GetWrittenAttributes( void ) const
  5520. {
  5521. return 0;
  5522. }
  5523. uint32 GetReadAttributes( void ) const
  5524. {
  5525. return PARTICLE_ATTRIBUTE_XYZ_MASK;
  5526. }
  5527. uint32 GetFilter( void ) const
  5528. {
  5529. return FILTER_LIFE_DURATION_MASK;
  5530. }
  5531. virtual uint64 GetReadControlPointMask() const
  5532. {
  5533. return ( 1ULL << m_nControlPoint );
  5534. }
  5535. void Render( CParticleCollection *pParticles ) const;
  5536. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  5537. };
  5538. DEFINE_PARTICLE_OPERATOR( C_OP_DistanceCull, "Cull when crossing sphere", OPERATOR_GENERIC );
  5539. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_DistanceCull )
  5540. DMXELEMENT_UNPACK_FIELD( "Control Point", "0", int, m_nControlPoint )
  5541. DMXELEMENT_UNPACK_FIELD( "Cull Distance", "0", float, m_flDistance )
  5542. DMXELEMENT_UNPACK_FIELD( "Control Point offset", "0 0 0", Vector, m_vecPointOffset )
  5543. DMXELEMENT_UNPACK_FIELD( "Cull inside instead of outside", "0", bool, m_bCullInside )
  5544. END_PARTICLE_OPERATOR_UNPACK( C_OP_DistanceCull )
  5545. void C_OP_DistanceCull::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  5546. {
  5547. C4VAttributeIterator pXYZ( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  5548. int nLimit = pParticles->m_nPaddedActiveParticles << 2;
  5549. // setup vars
  5550. FourVectors v4Offset ;
  5551. v4Offset.DuplicateVector( m_vecPointOffset );
  5552. FourVectors v4CullPosition;
  5553. v4CullPosition.DuplicateVector( pParticles->GetControlPointAtCurrentTime( m_nControlPoint ) );
  5554. v4CullPosition += v4Offset;
  5555. fltx4 fl4CullDistance = ReplicateX4( m_flDistance );
  5556. for ( int i = 0; i < nLimit; i+= 4 )
  5557. {
  5558. FourVectors f4ParticlePos = (*pXYZ );
  5559. f4ParticlePos -= v4CullPosition;
  5560. fltx4 fl4DistanceTest = f4ParticlePos.length();
  5561. bi32x4 fl4CullMask;
  5562. if ( m_bCullInside )
  5563. fl4CullMask = CmpLtSIMD( fl4DistanceTest, fl4CullDistance );
  5564. else
  5565. fl4CullMask = CmpGtSIMD( fl4DistanceTest, fl4CullDistance );
  5566. if ( IsAnyTrue( fl4CullMask ) )
  5567. {
  5568. // not especially pretty - we need to kill some particles.
  5569. int nMask = TestSignSIMD( fl4CullMask );
  5570. if ( nMask & 1 )
  5571. pParticles->KillParticle( i );
  5572. if ( nMask & 2 )
  5573. pParticles->KillParticle( i + 1 );
  5574. if ( nMask & 4 )
  5575. pParticles->KillParticle( i + 2 );
  5576. if ( nMask & 8 )
  5577. pParticles->KillParticle( i + 3 );
  5578. }
  5579. ++pXYZ;
  5580. }
  5581. }
  5582. //-----------------------------------------------------------------------------
  5583. // Render visualization
  5584. //-----------------------------------------------------------------------------
  5585. void C_OP_DistanceCull::Render( CParticleCollection *pParticles ) const
  5586. {
  5587. Vector vecOrigin1 = pParticles->GetControlPointAtCurrentTime( m_nControlPoint );
  5588. vecOrigin1 += m_vecPointOffset;
  5589. RenderWireframeSphere( vecOrigin1, m_flDistance, 16, 8, Color( 255, 255, 255, 255 ), false );
  5590. }
  5591. //-----------------------------------------------------------------------------
  5592. // Model Cull Operator - cull particles inside or outside of a brush/animated model
  5593. //-----------------------------------------------------------------------------
  5594. class C_OP_ModelCull : public CParticleOperatorInstance
  5595. {
  5596. DECLARE_PARTICLE_OPERATOR( C_OP_ModelCull );
  5597. int m_nControlPointNumber;
  5598. bool m_bBoundBox;
  5599. bool m_bCullOutside;
  5600. char m_HitboxSetName[128];
  5601. uint32 GetWrittenAttributes( void ) const
  5602. {
  5603. return 0;
  5604. }
  5605. uint32 GetReadAttributes( void ) const
  5606. {
  5607. return PARTICLE_ATTRIBUTE_XYZ_MASK;
  5608. }
  5609. uint32 GetFilter( void ) const
  5610. {
  5611. return FILTER_LIFE_DURATION_MASK | FILTER_POSITION_AND_VELOCITY_MASK;
  5612. }
  5613. void InitParams( CParticleSystemDefinition *pDef )
  5614. {
  5615. m_nControlPointNumber = MAX( 0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nControlPointNumber ) );
  5616. }
  5617. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  5618. };
  5619. DEFINE_PARTICLE_OPERATOR( C_OP_ModelCull , "Cull relative to model", OPERATOR_GENERIC );
  5620. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_ModelCull )
  5621. DMXELEMENT_UNPACK_FIELD( "control_point_number", "0", int, m_nControlPointNumber )
  5622. DMXELEMENT_UNPACK_FIELD( "use only bounding box", "0", bool, m_bBoundBox )
  5623. DMXELEMENT_UNPACK_FIELD( "cull outside instead of inside", "0", bool, m_bCullOutside )
  5624. DMXELEMENT_UNPACK_FIELD_STRING( "hitbox set", "effects", m_HitboxSetName )
  5625. END_PARTICLE_OPERATOR_UNPACK( C_OP_ModelCull )
  5626. void C_OP_ModelCull::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  5627. {
  5628. if ( pParticles->ControlPoint( m_nControlPointNumber ).m_pObject != NULL )
  5629. {
  5630. pParticles->UpdateHitBoxInfo( m_nControlPointNumber, m_HitboxSetName );
  5631. if ( pParticles->ControlPointHitBox( m_nControlPointNumber ).CurAndPrevValid() )
  5632. {
  5633. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  5634. {
  5635. float *pXYZ = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, i );
  5636. Vector vecParticlePosition;
  5637. SetVectorFromAttribute( vecParticlePosition, pXYZ );
  5638. bool bInside = g_pParticleSystemMgr->Query()->IsPointInControllingObjectHitBox( pParticles, m_nControlPointNumber, vecParticlePosition, m_bBoundBox );
  5639. if ( ( bInside && m_bCullOutside ) || ( !bInside && !m_bCullOutside ))
  5640. continue;
  5641. pParticles->KillParticle(i);
  5642. }
  5643. }
  5644. }
  5645. };
  5646. //-----------------------------------------------------------------------------
  5647. // Assign CP to Center
  5648. //-----------------------------------------------------------------------------
  5649. class C_OP_SetControlPointToCenter : public CParticleOperatorInstance
  5650. {
  5651. DECLARE_PARTICLE_OPERATOR( C_OP_SetControlPointToCenter );
  5652. int m_nCP1;
  5653. Vector m_vecCP1Pos;
  5654. uint32 GetWrittenAttributes( void ) const
  5655. {
  5656. return 0;
  5657. }
  5658. uint32 GetReadAttributes( void ) const
  5659. {
  5660. return 0;
  5661. }
  5662. uint32 GetFilter( void ) const
  5663. {
  5664. return FILTER_CONTROL_POINTS_MASK;
  5665. }
  5666. void InitParams( CParticleSystemDefinition *pDef )
  5667. {
  5668. m_nCP1 = MAX( 0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nCP1 ) );
  5669. }
  5670. bool ShouldRunBeforeEmitters( void ) const
  5671. {
  5672. return true;
  5673. }
  5674. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  5675. };
  5676. DEFINE_PARTICLE_OPERATOR( C_OP_SetControlPointToCenter, "Set Control Point To Particles' Center", OPERATOR_GENERIC );
  5677. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_SetControlPointToCenter )
  5678. DMXELEMENT_UNPACK_FIELD( "Control Point Number to Set", "1", int, m_nCP1 )
  5679. DMXELEMENT_UNPACK_FIELD( "Center Offset", "0 0 0", Vector, m_vecCP1Pos )
  5680. END_PARTICLE_OPERATOR_UNPACK( C_OP_SetControlPointToCenter )
  5681. void C_OP_SetControlPointToCenter::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  5682. {
  5683. Vector vecMinBounds;
  5684. Vector vecMaxBounds;
  5685. pParticles->GetBounds( &vecMinBounds, &vecMaxBounds );
  5686. Vector vecCenter = ( ( vecMinBounds + vecMaxBounds ) / 2 );
  5687. pParticles->SetControlPoint( m_nCP1, m_vecCP1Pos + vecCenter );
  5688. }
  5689. //-----------------------------------------------------------------------------
  5690. // Velocity Match a group of particles
  5691. //-----------------------------------------------------------------------------
  5692. class C_OP_VelocityMatchingForce : public CParticleOperatorInstance
  5693. {
  5694. DECLARE_PARTICLE_OPERATOR( C_OP_VelocityMatchingForce );
  5695. float m_flDirScale;
  5696. float m_flSpdScale;
  5697. int m_nCPBroadcast;
  5698. struct VelocityMatchingForceContext_t
  5699. {
  5700. Vector m_vecAvgVelocity;
  5701. float m_flAvgSpeed;
  5702. };
  5703. uint32 GetWrittenAttributes( void ) const
  5704. {
  5705. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK ;
  5706. }
  5707. uint32 GetReadAttributes( void ) const
  5708. {
  5709. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK ;
  5710. }
  5711. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  5712. {
  5713. VelocityMatchingForceContext_t *pCtx = reinterpret_cast<VelocityMatchingForceContext_t *>( pContext );
  5714. pCtx->m_vecAvgVelocity = vec3_origin;
  5715. pCtx->m_flAvgSpeed = 0;
  5716. }
  5717. size_t GetRequiredContextBytes( void ) const
  5718. {
  5719. return sizeof( VelocityMatchingForceContext_t );
  5720. }
  5721. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  5722. };
  5723. DEFINE_PARTICLE_OPERATOR( C_OP_VelocityMatchingForce , "Movement Match Particle Velocities", OPERATOR_GENERIC );
  5724. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_VelocityMatchingForce )
  5725. DMXELEMENT_UNPACK_FIELD( "Direction Matching Strength", "0.25", float, m_flDirScale )
  5726. DMXELEMENT_UNPACK_FIELD( "Speed Matching Strength", "0.25", float, m_flSpdScale )
  5727. DMXELEMENT_UNPACK_FIELD( "Control Point to Broadcast Speed and Direction To", "-1", int, m_nCPBroadcast )
  5728. END_PARTICLE_OPERATOR_UNPACK( C_OP_VelocityMatchingForce )
  5729. void C_OP_VelocityMatchingForce::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  5730. {
  5731. VelocityMatchingForceContext_t *pCtx = reinterpret_cast<VelocityMatchingForceContext_t *>( pContext );
  5732. Vector vecVelocityAvg = vec3_origin;
  5733. float flAvgSpeed = 0;
  5734. // FIXME: SSE-ize
  5735. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  5736. {
  5737. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, i );
  5738. float *xyz_prev = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  5739. Vector vecXYZ;
  5740. Vector vecPXYZ;
  5741. SetVectorFromAttribute( vecXYZ, xyz );
  5742. SetVectorFromAttribute( vecPXYZ, xyz_prev );
  5743. Vector vecVelocityCur = ( ( vecXYZ - vecPXYZ ) / pParticles->m_flDt );
  5744. vecVelocityAvg += vecVelocityCur;
  5745. float flSpeed = vecVelocityCur.Length();
  5746. flAvgSpeed += flSpeed;
  5747. if ( pCtx->m_vecAvgVelocity != vec3_origin )
  5748. {
  5749. Vector vecScaledXYZ;
  5750. VectorNormalizeFast(vecVelocityCur);
  5751. VectorLerp( vecVelocityCur, pCtx->m_vecAvgVelocity, m_flDirScale, vecScaledXYZ );
  5752. VectorNormalizeFast(vecScaledXYZ);
  5753. flSpeed = Lerp ( m_flSpdScale, flSpeed, pCtx->m_flAvgSpeed );
  5754. vecScaledXYZ *= flSpeed;
  5755. vecScaledXYZ = ( ( vecScaledXYZ * pParticles->m_flDt ) + vecPXYZ );
  5756. SetVectorAttribute( xyz, vecScaledXYZ );
  5757. }
  5758. }
  5759. VectorNormalizeFast( vecVelocityAvg );
  5760. pCtx->m_vecAvgVelocity = vecVelocityAvg;
  5761. pCtx->m_flAvgSpeed = ( flAvgSpeed / pParticles->m_nActiveParticles );
  5762. if ( m_nCPBroadcast != -1 )
  5763. {
  5764. pParticles->SetControlPoint( m_nCPBroadcast, Vector ( pCtx->m_flAvgSpeed, pCtx->m_flAvgSpeed, pCtx->m_flAvgSpeed ) );
  5765. pParticles->SetControlPointForwardVector( m_nCPBroadcast, pCtx->m_vecAvgVelocity );
  5766. }
  5767. };
  5768. //-----------------------------------------------------------------------------
  5769. // Movement maintain offset
  5770. //-----------------------------------------------------------------------------
  5771. class C_OP_MovementMaintainOffset : public CParticleOperatorInstance
  5772. {
  5773. DECLARE_PARTICLE_OPERATOR( C_OP_MovementMaintainOffset );
  5774. Vector m_vecOffset;
  5775. int m_nCP;
  5776. bool m_bRadiusScale;
  5777. uint32 GetWrittenAttributes( void ) const
  5778. {
  5779. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK ;
  5780. }
  5781. uint32 GetReadAttributes( void ) const
  5782. {
  5783. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK ;
  5784. }
  5785. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  5786. };
  5787. DEFINE_PARTICLE_OPERATOR( C_OP_MovementMaintainOffset , "Movement Maintain Offset", OPERATOR_GENERIC );
  5788. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_MovementMaintainOffset )
  5789. DMXELEMENT_UNPACK_FIELD( "Local Space CP", "-1", int, m_nCP )
  5790. DMXELEMENT_UNPACK_FIELD( "Desired Offset", "0 0 0", Vector, m_vecOffset )
  5791. DMXELEMENT_UNPACK_FIELD( "Scale by Radius", "0", bool, m_bRadiusScale )
  5792. END_PARTICLE_OPERATOR_UNPACK( C_OP_MovementMaintainOffset )
  5793. void C_OP_MovementMaintainOffset::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  5794. {
  5795. Vector vecLocalOffset = m_vecOffset;
  5796. if ( m_nCP > -1 )
  5797. {
  5798. matrix3x4_t mat;
  5799. pParticles->GetControlPointTransformAtCurrentTime( m_nCP, &mat );
  5800. VectorRotate( m_vecOffset, mat, vecLocalOffset );
  5801. }
  5802. Vector vecOffsetPos = ( vecLocalOffset * ( pParticles->m_nActiveParticles - 1 ) ) / 2 ;
  5803. Vector vecCurAvgPos = vec3_origin;
  5804. Vector vecCurAvgPrevPos = vec3_origin;
  5805. // FIXME: SSE-ize
  5806. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  5807. {
  5808. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, i );
  5809. float *xyz_prev = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  5810. Vector vecXYZ;
  5811. Vector vecPXYZ;
  5812. SetVectorFromAttribute( vecXYZ, xyz );
  5813. SetVectorFromAttribute( vecPXYZ, xyz_prev );
  5814. vecCurAvgPos += vecXYZ;
  5815. vecCurAvgPrevPos += vecPXYZ;
  5816. }
  5817. vecCurAvgPos = vecCurAvgPos / pParticles->m_nActiveParticles;
  5818. vecCurAvgPrevPos = vecCurAvgPrevPos / pParticles->m_nActiveParticles;
  5819. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  5820. {
  5821. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, i );
  5822. float *xyz_prev = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  5823. Vector vecXYZ;
  5824. Vector vecPXYZ;
  5825. SetVectorFromAttribute( vecXYZ, xyz );
  5826. SetVectorFromAttribute( vecPXYZ, xyz_prev );
  5827. float flRadius = 1;
  5828. if ( m_bRadiusScale )
  5829. {
  5830. const float *rad = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_RADIUS, i );
  5831. flRadius = *rad;
  5832. }
  5833. vecXYZ = vecCurAvgPos + vecOffsetPos * flRadius;
  5834. vecPXYZ = vecCurAvgPrevPos + vecOffsetPos * flRadius;
  5835. SetVectorAttribute( xyz, vecXYZ );
  5836. SetVectorAttribute( xyz_prev, vecPXYZ);
  5837. vecOffsetPos -= vecLocalOffset;
  5838. }
  5839. };
  5840. //-----------------------------------------------------------------------------
  5841. // Movement Place on Ground
  5842. //-----------------------------------------------------------------------------
  5843. class C_OP_MovementPlaceOnGround : public CParticleOperatorInstance
  5844. {
  5845. DECLARE_PARTICLE_OPERATOR( C_OP_MovementPlaceOnGround );
  5846. struct PlaceOnGroundContext_t
  5847. {
  5848. Vector m_vecPrevPos1;
  5849. Vector m_vecPrevPos2;
  5850. Vector m_vecPrevPosLerp;
  5851. float m_flLerpTime;
  5852. };
  5853. float m_flOffset;
  5854. float m_flMaxTraceLength;
  5855. float m_flTolerance;
  5856. float m_flTraceOffset;
  5857. float m_flLerpRate;
  5858. char m_CollisionGroupName[128];
  5859. int m_nCollisionGroupNumber;
  5860. int m_nRefCP1;
  5861. int m_nRefCP2;
  5862. int m_nLerpCP;
  5863. unsigned int m_CollisionMask;
  5864. bool m_bKill;
  5865. bool m_bIncludeWater;
  5866. bool m_bUsesCPs;
  5867. bool m_bUsesLerp;
  5868. //bool m_bSetNormal;
  5869. uint32 GetWrittenAttributes( void ) const
  5870. {
  5871. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK | PARTICLE_ATTRIBUTE_NORMAL_MASK | PARTICLE_ATTRIBUTE_HITBOX_RELATIVE_XYZ_MASK;
  5872. }
  5873. uint32 GetReadAttributes( void ) const
  5874. {
  5875. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_HITBOX_RELATIVE_XYZ_MASK;
  5876. }
  5877. virtual uint64 GetReadControlPointMask() const
  5878. {
  5879. uint64 nMask = 0;
  5880. if ( m_nRefCP1 != -1 )
  5881. {
  5882. nMask |= ( 1ULL << m_nRefCP1 );
  5883. }
  5884. if ( m_nRefCP2 != -1 )
  5885. {
  5886. nMask |= ( 1ULL << m_nRefCP2 );
  5887. }
  5888. if ( m_nLerpCP != -1 )
  5889. {
  5890. nMask |= ( 1ULL << m_nLerpCP );
  5891. }
  5892. return nMask;
  5893. }
  5894. void InitParams( CParticleSystemDefinition *pDef )
  5895. {
  5896. m_nCollisionGroupNumber = g_pParticleSystemMgr->Query()->GetCollisionGroupFromName( m_CollisionGroupName );
  5897. if ( m_bIncludeWater )
  5898. m_CollisionMask = MASK_SHOT_HULL|MASK_SPLITAREAPORTAL;
  5899. else
  5900. m_CollisionMask = MASK_SHOT_HULL;
  5901. if ( ( m_nRefCP1 > -1 || m_nRefCP2 > -1 || m_nLerpCP > -1 ) && ( m_flTolerance > 0 ) )
  5902. m_bUsesCPs = true;
  5903. else
  5904. m_bUsesCPs = false;
  5905. if ( m_nLerpCP > -1 || m_flLerpRate > 0 )
  5906. m_bUsesLerp = true;
  5907. else
  5908. m_bUsesLerp = false;
  5909. }
  5910. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  5911. {
  5912. PlaceOnGroundContext_t *pCtx = reinterpret_cast<PlaceOnGroundContext_t *>( pContext );
  5913. pCtx->m_vecPrevPos1 = vec3_invalid;
  5914. pCtx->m_vecPrevPos2 = vec3_invalid;
  5915. pCtx->m_vecPrevPosLerp = vec3_invalid;
  5916. pCtx->m_flLerpTime = pParticles->m_flCurTime;
  5917. }
  5918. size_t GetRequiredContextBytes( void ) const
  5919. {
  5920. return sizeof( PlaceOnGroundContext_t );
  5921. }
  5922. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  5923. };
  5924. DEFINE_PARTICLE_OPERATOR( C_OP_MovementPlaceOnGround, "Movement Place On Ground", OPERATOR_GENERIC );
  5925. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_MovementPlaceOnGround )
  5926. DMXELEMENT_UNPACK_FIELD( "offset", "0", float, m_flOffset )
  5927. DMXELEMENT_UNPACK_FIELD( "kill on no collision", "0", bool, m_bKill )
  5928. DMXELEMENT_UNPACK_FIELD( "include water", "0", bool, m_bIncludeWater )
  5929. //DMXELEMENT_UNPACK_FIELD( "set normal", "0", bool, m_bSetNormal )
  5930. DMXELEMENT_UNPACK_FIELD( "max trace length", "128", float, m_flMaxTraceLength )
  5931. DMXELEMENT_UNPACK_FIELD( "trace offset", "64", float, m_flTraceOffset )
  5932. DMXELEMENT_UNPACK_FIELD_STRING( "collision group", "NONE", m_CollisionGroupName )
  5933. DMXELEMENT_UNPACK_FIELD( "reference CP 1", "-1", int, m_nRefCP1 )
  5934. DMXELEMENT_UNPACK_FIELD( "reference CP 2", "-1", int, m_nRefCP2 )
  5935. DMXELEMENT_UNPACK_FIELD( "CP movement tolerance", "32", float, m_flTolerance )
  5936. DMXELEMENT_UNPACK_FIELD( "interpolation rate", "0", float, m_flLerpRate )
  5937. DMXELEMENT_UNPACK_FIELD( "interploation distance tolerance cp", "-1", int, m_nLerpCP )
  5938. END_PARTICLE_OPERATOR_UNPACK( C_OP_MovementPlaceOnGround )
  5939. void C_OP_MovementPlaceOnGround::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  5940. {
  5941. PlaceOnGroundContext_t *pCtx = reinterpret_cast<PlaceOnGroundContext_t *>( pContext );
  5942. // Only update if our reference CPs have moved more than the tolerance for performance
  5943. bool bDirty = false;
  5944. if ( m_bUsesCPs )
  5945. {
  5946. if ( m_nRefCP1 > -1 )
  5947. {
  5948. if ( ( pParticles->GetControlPointAtCurrentTime( m_nRefCP1 ) - pCtx->m_vecPrevPos1 ).Length() > m_flTolerance )
  5949. {
  5950. bDirty = true;
  5951. pCtx->m_vecPrevPos1 = pParticles->GetControlPointAtCurrentTime( m_nRefCP1 );
  5952. pCtx->m_flLerpTime = pParticles->m_flCurTime;
  5953. }
  5954. }
  5955. if ( m_nRefCP2 > -1 )
  5956. {
  5957. if ( ( pParticles->GetControlPointAtCurrentTime( m_nRefCP2 ) - pCtx->m_vecPrevPos2 ).Length() > m_flTolerance )
  5958. {
  5959. bDirty = true;
  5960. pCtx->m_vecPrevPos2 = pParticles->GetControlPointAtCurrentTime( m_nRefCP2 );
  5961. pCtx->m_flLerpTime = pParticles->m_flCurTime;
  5962. }
  5963. }
  5964. if ( m_nLerpCP > -1 )
  5965. {
  5966. if ( ( pParticles->GetControlPointAtCurrentTime( m_nLerpCP ) - pCtx->m_vecPrevPosLerp ).Length() > m_flTolerance )
  5967. {
  5968. pCtx->m_vecPrevPosLerp = pParticles->GetControlPointAtCurrentTime( m_nLerpCP );
  5969. }
  5970. }
  5971. }
  5972. else if ( !m_bUsesLerp )
  5973. {
  5974. // If we don't use CP or lerping tolerances, we always require an update so set dirty to true
  5975. bDirty = true;
  5976. }
  5977. // Set our lerp percentage based on rate for later use
  5978. float flPerc = 0;
  5979. if ( m_bUsesLerp )
  5980. {
  5981. // Either store the percentage based on time or by distance moved, but not both
  5982. if ( m_flLerpRate > 0 )
  5983. {
  5984. flPerc = RemapValClamped( pParticles->m_flCurTime, pCtx->m_flLerpTime, ( pCtx->m_flLerpTime + m_flLerpRate ), 0.0f, 1.0f );
  5985. if ( flPerc == 1.0f && !m_bUsesCPs)
  5986. {
  5987. bDirty = true;
  5988. pCtx->m_flLerpTime = pParticles->m_flCurTime;
  5989. }
  5990. }
  5991. else if ( m_nLerpCP > -1 )
  5992. flPerc = clamp( ( ( pParticles->GetControlPointAtCurrentTime( m_nLerpCP ) - pCtx->m_vecPrevPosLerp ).Length() ) / m_flTolerance, 0.0f, 1.0f );
  5993. // Debug for visualing the percentage amount
  5994. //g_pParticleSystemMgr->Query()->DebugDrawLine( pParticles->GetControlPointAtCurrentTime( m_nLerpCP ), ( pParticles->GetControlPointAtCurrentTime( m_nLerpCP ) + Vector ( 0, 0, flPerc * 128 ) ), 255, 0, ( flPerc * 255 ), true, 1.0f );
  5995. }
  5996. if ( bDirty || m_bUsesLerp )
  5997. {
  5998. // Trace down
  5999. Vector TraceDir=Vector(0, 0, -1);
  6000. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  6001. {
  6002. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, i );
  6003. float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  6004. float *plife = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_LIFE_DURATION, i );
  6005. //HACK - uses Hitbox Relative XYZ to store past/desired Z component for smooth lerping
  6006. float *pDesiredZ = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_HITBOX_RELATIVE_XYZ, i );
  6007. //float *pNormal = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_NORMAL, i );
  6008. Vector vecXYZPos, vecXYZPrevPos, vecTracePos, vecDesiredZ;
  6009. SetVectorFromAttribute( vecXYZPos, xyz );
  6010. SetVectorFromAttribute( vecXYZPrevPos, pxyz );
  6011. SetVectorFromAttribute( vecDesiredZ, pDesiredZ );
  6012. if ( m_bUsesLerp && vecDesiredZ.y != 1 )
  6013. {
  6014. vecDesiredZ = Vector( vecXYZPos.z, 1, vecXYZPos.z);
  6015. bDirty = true;
  6016. }
  6017. if ( bDirty )
  6018. {
  6019. vecTracePos = vecXYZPos;
  6020. vecTracePos.z += m_flTraceOffset;
  6021. CBaseTrace tr;
  6022. g_pParticleSystemMgr->Query()->TraceLine( vecTracePos, ( vecTracePos + ( TraceDir * m_flMaxTraceLength ) ), m_CollisionMask, NULL, m_nCollisionGroupNumber, &tr );
  6023. if ( tr.fraction == 1.0 && m_bKill )
  6024. {
  6025. *plife = -1.0f;
  6026. }
  6027. else
  6028. {
  6029. Vector vecEndPos = tr.endpos;
  6030. Vector vecOffset = Vector( 0, 0, m_flOffset );
  6031. //if ( m_bSetNormal )
  6032. //{
  6033. //SetVectorAttribute( pNormal, tr.plane.normal);
  6034. //vecOffset = tr.plane.normal * m_flOffset;
  6035. //}
  6036. vecEndPos += vecOffset;
  6037. if ( m_bUsesLerp )
  6038. {
  6039. vecDesiredZ.x = vecDesiredZ.z;
  6040. vecDesiredZ.z = vecEndPos.z;
  6041. SetVectorAttribute( pDesiredZ, vecDesiredZ );
  6042. }
  6043. else
  6044. {
  6045. vecXYZPos.z = vecEndPos.z;
  6046. vecXYZPrevPos.z = vecEndPos.z;
  6047. }
  6048. }
  6049. }
  6050. if ( m_bUsesLerp )
  6051. {
  6052. vecXYZPos.z = Lerp ( flPerc, vecDesiredZ.x, vecDesiredZ.z );
  6053. vecXYZPrevPos.z = vecXYZPos.z;
  6054. }
  6055. SetVectorAttribute( xyz, vecXYZPos );
  6056. SetVectorAttribute( pxyz, vecXYZPrevPos );
  6057. }
  6058. }
  6059. }
  6060. class C_OP_InheritFromParentParticles : public CParticleInitializerOperatorInstance
  6061. {
  6062. DECLARE_PARTICLE_OPERATOR( C_OP_InheritFromParentParticles );
  6063. struct ParentParticlesContext_t
  6064. {
  6065. int m_nCurrentParentParticle;
  6066. };
  6067. uint32 GetWrittenAttributes( void ) const
  6068. {
  6069. return 1 << m_nFieldOutput;
  6070. }
  6071. uint32 GetReadAttributes( void ) const
  6072. {
  6073. return 0;
  6074. }
  6075. uint32 GetFilter( void ) const
  6076. {
  6077. return FILTER_PARAMETER_REMAPPING_MASK;
  6078. }
  6079. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  6080. {
  6081. ParentParticlesContext_t *pCtx = reinterpret_cast<ParentParticlesContext_t *>( pContext );
  6082. pCtx->m_nCurrentParentParticle = 0;
  6083. }
  6084. size_t GetRequiredContextBytes( void ) const
  6085. {
  6086. return sizeof( ParentParticlesContext_t );
  6087. }
  6088. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  6089. float m_flScale;
  6090. int m_nFieldOutput;
  6091. int m_nIncrement;
  6092. bool m_bRandomDistribution;
  6093. };
  6094. DEFINE_PARTICLE_OPERATOR( C_OP_InheritFromParentParticles, "Inherit Attribute From Parent Particle", OPERATOR_GENERIC );
  6095. BEGIN_PARTICLE_INITIALIZER_OPERATOR_UNPACK( C_OP_InheritFromParentParticles )
  6096. DMXELEMENT_UNPACK_FIELD_USERDATA( "Inherited Field", "3", int, m_nFieldOutput, "intchoice particlefield" )
  6097. DMXELEMENT_UNPACK_FIELD( "Scale","1", float, m_flScale )
  6098. DMXELEMENT_UNPACK_FIELD( "Random Parent Particle Distribution","0", bool, m_bRandomDistribution )
  6099. DMXELEMENT_UNPACK_FIELD( "Particle Increment Amount","1", int, m_nIncrement )
  6100. END_PARTICLE_OPERATOR_UNPACK( C_OP_InheritFromParentParticles )
  6101. void C_OP_InheritFromParentParticles::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  6102. {
  6103. if ( !pParticles->m_pParent )
  6104. {
  6105. return;
  6106. }
  6107. ParentParticlesContext_t *pCtx = reinterpret_cast<ParentParticlesContext_t *>( pContext );
  6108. int nActiveParticles = pParticles->m_pParent->m_nActiveParticles;
  6109. if ( nActiveParticles == 0 )
  6110. {
  6111. return;
  6112. }
  6113. nActiveParticles = MAX( 0, nActiveParticles - 1 );
  6114. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  6115. {
  6116. if ( m_bRandomDistribution )
  6117. {
  6118. pCtx->m_nCurrentParentParticle = pParticles->RandomInt( 0, nActiveParticles );
  6119. }
  6120. else if ( pCtx->m_nCurrentParentParticle > nActiveParticles )
  6121. {
  6122. pCtx->m_nCurrentParentParticle = 0;
  6123. }
  6124. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, i );
  6125. const float *pParentValue = pParticles->m_pParent->GetFloatAttributePtr( m_nFieldOutput, pCtx->m_nCurrentParentParticle );
  6126. if ( ATTRIBUTES_WHICH_ARE_VEC3S_MASK & ( 1 << m_nFieldOutput ) )
  6127. {
  6128. Vector vecParentValue;
  6129. SetVectorFromAttribute( vecParentValue, pParentValue );
  6130. vecParentValue *= m_flScale;
  6131. // Clamp to 0-1 if color
  6132. if ( ATTRIBUTES_WHICH_ARE_COLOR_AND_OPACITY & ( 1 << m_nFieldOutput ) )
  6133. {
  6134. vecParentValue.Min( Vector( 1, 1, 1 ) );
  6135. vecParentValue.Max( Vector( 0, 0, 0 ) );
  6136. }
  6137. SetVectorAttribute( pOutput, vecParentValue );
  6138. }
  6139. else
  6140. {
  6141. float flOutput = *pParentValue * m_flScale;
  6142. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & ( 1 << m_nFieldOutput ) )
  6143. {
  6144. flOutput = clamp(flOutput, 0.0f, 1.0f );
  6145. }
  6146. *pOutput = flOutput;
  6147. }
  6148. pCtx->m_nCurrentParentParticle += m_nIncrement;
  6149. }
  6150. }
  6151. //-----------------------------------------------------------------------------
  6152. // Orient to heading
  6153. //-----------------------------------------------------------------------------
  6154. class C_OP_OrientTo2dDirection : public CParticleOperatorInstance
  6155. {
  6156. DECLARE_PARTICLE_OPERATOR( C_OP_OrientTo2dDirection );
  6157. float m_flRotOffset;
  6158. float m_flSpinStrength;
  6159. int m_nFieldOutput;
  6160. uint32 GetWrittenAttributes( void ) const
  6161. {
  6162. return 1 << m_nFieldOutput;
  6163. }
  6164. uint32 GetReadAttributes( void ) const
  6165. {
  6166. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK ;
  6167. }
  6168. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  6169. };
  6170. DEFINE_PARTICLE_OPERATOR( C_OP_OrientTo2dDirection , "Rotation Orient to 2D Direction", OPERATOR_GENERIC );
  6171. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_OrientTo2dDirection )
  6172. DMXELEMENT_UNPACK_FIELD( "Rotation Offset", "0", float, m_flRotOffset )
  6173. DMXELEMENT_UNPACK_FIELD( "Spin Strength", "1", float, m_flSpinStrength )
  6174. DMXELEMENT_UNPACK_FIELD_USERDATA( "rotation field", "4", int, m_nFieldOutput, "intchoice particlefield_rotation" )
  6175. END_PARTICLE_OPERATOR_UNPACK( C_OP_OrientTo2dDirection )
  6176. void C_OP_OrientTo2dDirection::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  6177. {
  6178. float flRotOffset = m_flRotOffset * ( M_PI / 180.0f );
  6179. // FIXME: SSE-ize
  6180. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  6181. {
  6182. const float *xyz = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_XYZ, i );
  6183. const float *xyz_prev = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  6184. float *roll = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, i );
  6185. Vector vecXYZ;
  6186. Vector vecPXYZ;
  6187. vecXYZ.x = xyz[0];
  6188. vecXYZ.y = xyz[4];
  6189. vecXYZ.z = xyz[8];
  6190. vecPXYZ.x = xyz_prev[0];
  6191. vecPXYZ.y = xyz_prev[4];
  6192. vecPXYZ.z = xyz_prev[8];
  6193. Vector vecVelocityCur = ( vecXYZ - vecPXYZ );
  6194. vecVelocityCur.z = 0.0f;
  6195. VectorNormalizeFast ( vecVelocityCur );
  6196. float flCurRot = *roll;
  6197. float flVelRot = atan2(vecVelocityCur.y, vecVelocityCur.x ) + M_PI;
  6198. flVelRot += flRotOffset;
  6199. float flRotation = Lerp ( m_flSpinStrength, flCurRot, flVelRot );
  6200. *roll = flRotation;
  6201. }
  6202. };
  6203. //-----------------------------------------------------------------------------
  6204. // Restart after Randomized Duration
  6205. //-----------------------------------------------------------------------------
  6206. class C_OP_RestartAfterDuration : public CParticleOperatorInstance
  6207. {
  6208. DECLARE_PARTICLE_OPERATOR( C_OP_RestartAfterDuration );
  6209. float m_flDurationMin;
  6210. float m_flDurationMax;
  6211. int m_nCP;
  6212. int m_nCPField;
  6213. int m_nChildGroupID;
  6214. bool m_bOnlyChildren;
  6215. struct RestartAfterDurationContext_t
  6216. {
  6217. float m_flLastRestart;
  6218. float m_flRestartDuration;
  6219. };
  6220. uint32 GetWrittenAttributes( void ) const
  6221. {
  6222. return 0;
  6223. }
  6224. uint32 GetReadAttributes( void ) const
  6225. {
  6226. return 0;
  6227. }
  6228. virtual uint64 GetReadControlPointMask() const
  6229. {
  6230. return ( 1ULL << m_nCP );
  6231. }
  6232. virtual void InitParams(CParticleSystemDefinition *pDef )
  6233. {
  6234. m_nCP = clamp( m_nCP, -1, MAX_PARTICLE_CONTROL_POINTS );
  6235. m_nCPField = clamp( m_nCPField, 0, 2 );
  6236. }
  6237. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  6238. {
  6239. RestartAfterDurationContext_t *pCtx = reinterpret_cast<RestartAfterDurationContext_t *>( pContext );
  6240. pCtx->m_flRestartDuration = pParticles->RandomFloat( m_flDurationMin, m_flDurationMax );
  6241. pCtx->m_flLastRestart = 0;
  6242. }
  6243. size_t GetRequiredContextBytes( void ) const
  6244. {
  6245. return sizeof( RestartAfterDurationContext_t );
  6246. }
  6247. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  6248. };
  6249. DEFINE_PARTICLE_OPERATOR( C_OP_RestartAfterDuration , "Restart Effect after Duration", OPERATOR_GENERIC );
  6250. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RestartAfterDuration )
  6251. DMXELEMENT_UNPACK_FIELD( "Minimum Restart Time", "0", float, m_flDurationMin )
  6252. DMXELEMENT_UNPACK_FIELD( "Maximum Restart Time", "1", float, m_flDurationMax )
  6253. DMXELEMENT_UNPACK_FIELD( "Control Point to Scale Duration", "-1", int, m_nCP )
  6254. DMXELEMENT_UNPACK_FIELD( "Control Point Field X/Y/Z", "0", int, m_nCPField )
  6255. DMXELEMENT_UNPACK_FIELD( "Only Restart Children", "0", bool, m_bOnlyChildren )
  6256. DMXELEMENT_UNPACK_FIELD( "Child Group ID", "0", int, m_nChildGroupID )
  6257. END_PARTICLE_OPERATOR_UNPACK( C_OP_RestartAfterDuration )
  6258. void C_OP_RestartAfterDuration::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  6259. {
  6260. if ( !pParticles->m_bEmissionStopped )
  6261. {
  6262. RestartAfterDurationContext_t *pCtx = reinterpret_cast<RestartAfterDurationContext_t *>( pContext );
  6263. float flDuration = pCtx->m_flRestartDuration;
  6264. if ( m_nCP > -1 )
  6265. {
  6266. flDuration *= pParticles->GetControlPointAtCurrentTime( m_nCP )[m_nCPField];
  6267. }
  6268. if ( pParticles->m_flCurTime > flDuration + pCtx->m_flLastRestart )
  6269. {
  6270. if ( m_bOnlyChildren )
  6271. {
  6272. for( CParticleCollection *pChild = pParticles->m_Children.m_pHead; pChild; pChild = pChild->m_pNext )
  6273. {
  6274. if ( pChild->GetGroupID() == m_nChildGroupID )
  6275. pChild->Restart();
  6276. }
  6277. }
  6278. else
  6279. {
  6280. pParticles->Restart();
  6281. }
  6282. pCtx->m_flLastRestart = pParticles->m_flCurTime;
  6283. pCtx->m_flRestartDuration = pParticles->RandomFloat( m_flDurationMin, m_flDurationMax );
  6284. }
  6285. }
  6286. };
  6287. //-----------------------------------------------------------------------------
  6288. // Stop after CP Specified Duration
  6289. //-----------------------------------------------------------------------------
  6290. class C_OP_StopAfterCPDuration : public CParticleOperatorInstance
  6291. {
  6292. DECLARE_PARTICLE_OPERATOR( C_OP_StopAfterCPDuration );
  6293. float m_flDuration;
  6294. int m_nCP;
  6295. int m_nCPField;
  6296. bool m_bDestroyImmediately;
  6297. bool m_bPlayEndCap;
  6298. uint32 GetWrittenAttributes( void ) const
  6299. {
  6300. return 0;
  6301. }
  6302. uint32 GetReadAttributes( void ) const
  6303. {
  6304. return 0;
  6305. }
  6306. virtual uint64 GetReadControlPointMask() const
  6307. {
  6308. return ( 1ULL << m_nCP );
  6309. }
  6310. virtual void InitParams(CParticleSystemDefinition *pDef )
  6311. {
  6312. m_nCP = clamp( m_nCP, -1, MAX_PARTICLE_CONTROL_POINTS );
  6313. m_nCPField = clamp( m_nCPField, 0, 2 );
  6314. }
  6315. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  6316. };
  6317. DEFINE_PARTICLE_OPERATOR( C_OP_StopAfterCPDuration , "Stop Effect after Duration", OPERATOR_GENERIC );
  6318. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_StopAfterCPDuration )
  6319. DMXELEMENT_UNPACK_FIELD( "Duration at which to Stop", "1", float, m_flDuration )
  6320. DMXELEMENT_UNPACK_FIELD( "Control Point to Scale Duration", "-1", int, m_nCP )
  6321. DMXELEMENT_UNPACK_FIELD( "Control Point Field X/Y/Z", "0", int, m_nCPField )
  6322. DMXELEMENT_UNPACK_FIELD( "Destroy All Particles Immediately", "0", bool, m_bDestroyImmediately )
  6323. DMXELEMENT_UNPACK_FIELD( "Play End Cap Effect", "1", bool, m_bPlayEndCap )
  6324. END_PARTICLE_OPERATOR_UNPACK( C_OP_StopAfterCPDuration )
  6325. void C_OP_StopAfterCPDuration::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  6326. {
  6327. if ( !pParticles->m_bEmissionStopped )
  6328. {
  6329. float flDuration = m_flDuration;
  6330. if ( m_nCP > -1 )
  6331. {
  6332. flDuration *= pParticles->GetControlPointAtCurrentTime( m_nCP )[m_nCPField];
  6333. }
  6334. if ( pParticles->m_flCurTime > flDuration )
  6335. {
  6336. pParticles->StopEmission( false, m_bDestroyImmediately, true, m_bPlayEndCap );
  6337. }
  6338. }
  6339. };
  6340. //-----------------------------------------------------------------------------
  6341. // Orient relative to CP
  6342. //-----------------------------------------------------------------------------
  6343. class C_OP_Orient2DRelToCP : public CParticleOperatorInstance
  6344. {
  6345. DECLARE_PARTICLE_OPERATOR( C_OP_Orient2DRelToCP );
  6346. float m_flRotOffset;
  6347. float m_flSpinStrength;
  6348. int m_nCP;
  6349. int m_nFieldOutput;
  6350. uint32 GetWrittenAttributes( void ) const
  6351. {
  6352. return 1 << m_nFieldOutput;
  6353. }
  6354. uint32 GetReadAttributes( void ) const
  6355. {
  6356. return PARTICLE_ATTRIBUTE_XYZ_MASK ;
  6357. }
  6358. virtual uint64 GetReadControlPointMask() const
  6359. {
  6360. return ( 1ULL << m_nCP );
  6361. }
  6362. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  6363. };
  6364. DEFINE_PARTICLE_OPERATOR( C_OP_Orient2DRelToCP , "Rotation Orient Relative to CP", OPERATOR_GENERIC );
  6365. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_Orient2DRelToCP )
  6366. DMXELEMENT_UNPACK_FIELD( "Rotation Offset", "0", float, m_flRotOffset )
  6367. DMXELEMENT_UNPACK_FIELD( "Spin Strength", "1", float, m_flSpinStrength )
  6368. DMXELEMENT_UNPACK_FIELD( "Control Point", "0", int, m_nCP )
  6369. DMXELEMENT_UNPACK_FIELD_USERDATA( "rotation field", "4", int, m_nFieldOutput, "intchoice particlefield_rotation" )
  6370. END_PARTICLE_OPERATOR_UNPACK( C_OP_Orient2DRelToCP )
  6371. void C_OP_Orient2DRelToCP::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  6372. {
  6373. float flRotOffset = m_flRotOffset * ( M_PI / 180.0f );
  6374. // FIXME: SSE-ize
  6375. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  6376. {
  6377. const float *xyz = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_XYZ, i );
  6378. float *roll = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, i );
  6379. Vector vecXYZ;
  6380. Vector vecCP;
  6381. vecCP = pParticles->GetControlPointAtCurrentTime( m_nCP );
  6382. vecXYZ.x = xyz[0];
  6383. vecXYZ.y = xyz[4];
  6384. vecXYZ.z = xyz[8];
  6385. Vector vecVelocityCur = ( vecXYZ - vecCP );
  6386. vecVelocityCur.z = 0.0f;
  6387. VectorNormalizeFast ( vecVelocityCur );
  6388. float flCurRot = *roll;
  6389. float flVelRot = atan2(vecVelocityCur.y, vecVelocityCur.x ) + M_PI;
  6390. flVelRot += flRotOffset;
  6391. float flRotation = Lerp ( m_flSpinStrength, flCurRot, flVelRot );
  6392. *roll = flRotation;
  6393. }
  6394. };
  6395. //-----------------------------------------------------------------------------
  6396. // Rotate CP
  6397. //-----------------------------------------------------------------------------
  6398. class C_OP_SetControlPointRotation : public CParticleOperatorInstance
  6399. {
  6400. DECLARE_PARTICLE_OPERATOR( C_OP_SetControlPointRotation );
  6401. Vector m_vecRotAxis;
  6402. float m_flRotRate;
  6403. int m_nCP;
  6404. int m_nLocalCP;
  6405. uint32 GetWrittenAttributes( void ) const
  6406. {
  6407. return 0;
  6408. }
  6409. uint32 GetReadAttributes( void ) const
  6410. {
  6411. return 0;
  6412. }
  6413. virtual uint64 GetReadControlPointMask() const
  6414. {
  6415. uint64 nMask = ( 1ULL << m_nCP );
  6416. if ( m_nLocalCP != -1 )
  6417. {
  6418. nMask |= ( 1ULL << m_nLocalCP );
  6419. }
  6420. return nMask;
  6421. }
  6422. bool ShouldRunBeforeEmitters( void ) const
  6423. {
  6424. return true;
  6425. }
  6426. void InitParams( CParticleSystemDefinition *pDef )
  6427. {
  6428. VectorNormalize( m_vecRotAxis );
  6429. }
  6430. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  6431. };
  6432. DEFINE_PARTICLE_OPERATOR( C_OP_SetControlPointRotation , "Set Control Point Rotation", OPERATOR_GENERIC );
  6433. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_SetControlPointRotation )
  6434. DMXELEMENT_UNPACK_FIELD( "Rotation Axis", "0 0 1", Vector, m_vecRotAxis )
  6435. DMXELEMENT_UNPACK_FIELD( "Rotation Rate", "180", float, m_flRotRate )
  6436. DMXELEMENT_UNPACK_FIELD( "Control Point", "0", int, m_nCP )
  6437. DMXELEMENT_UNPACK_FIELD( "Local Space Control Point", "-1", int, m_nLocalCP )
  6438. END_PARTICLE_OPERATOR_UNPACK( C_OP_SetControlPointRotation )
  6439. void C_OP_SetControlPointRotation::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  6440. {
  6441. float flRotRate = m_flRotRate * pParticles->m_flDt;
  6442. Vector vecForward, vecRight, vecUp;
  6443. matrix3x4_t matCP, matRot;
  6444. Vector vecRotAxis = m_vecRotAxis;
  6445. if ( m_nLocalCP > -1 )
  6446. {
  6447. matrix3x4_t matLocalCP;
  6448. pParticles->GetControlPointTransformAtCurrentTime( m_nLocalCP, &matLocalCP );
  6449. VectorRotate( m_vecRotAxis, matLocalCP, vecRotAxis );
  6450. }
  6451. pParticles->GetControlPointTransformAtCurrentTime( m_nCP, &matCP );
  6452. MatrixBuildRotationAboutAxis ( vecRotAxis, flRotRate, matRot );
  6453. MatrixMultiply( matCP, matRot, matCP );
  6454. Quaternion quatRot;
  6455. MatrixQuaternion( matCP, quatRot );
  6456. pParticles->SetControlPointOrientation( m_nCP, quatRot );
  6457. //perhaps it should be done this way rather than using a quaternion?
  6458. //MatrixVectors( matCP, &vecForward, &vecRight, &vecUp );
  6459. //VectorNormalize( vecRight );
  6460. //VectorNormalize( vecUp );
  6461. //vecForward = CrossProduct( vecRight, vecUp );
  6462. //pParticles->SetControlPointOrientation( m_nCP, vecForward, vecRight, vecUp );
  6463. };
  6464. //-----------------------------------------------------------------------------
  6465. // Rotate Particle around axis
  6466. //-----------------------------------------------------------------------------
  6467. class C_OP_MovementRotateParticleAroundAxis : public CParticleOperatorInstance
  6468. {
  6469. DECLARE_PARTICLE_OPERATOR( C_OP_MovementRotateParticleAroundAxis );
  6470. Vector m_vecRotAxis;
  6471. float m_flRotRate;
  6472. int m_nCP;
  6473. bool m_bLocalSpace;
  6474. uint32 GetWrittenAttributes( void ) const
  6475. {
  6476. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK ;
  6477. }
  6478. uint32 GetReadAttributes( void ) const
  6479. {
  6480. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK ;
  6481. }
  6482. virtual uint64 GetReadControlPointMask() const
  6483. {
  6484. return 1ULL << m_nCP;
  6485. }
  6486. void InitParams( CParticleSystemDefinition *pDef )
  6487. {
  6488. VectorNormalize( m_vecRotAxis );
  6489. }
  6490. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  6491. };
  6492. DEFINE_PARTICLE_OPERATOR( C_OP_MovementRotateParticleAroundAxis , "Movement Rotate Particle Around Axis", OPERATOR_GENERIC );
  6493. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_MovementRotateParticleAroundAxis )
  6494. DMXELEMENT_UNPACK_FIELD( "Rotation Axis", "0 0 1", Vector, m_vecRotAxis )
  6495. DMXELEMENT_UNPACK_FIELD( "Rotation Rate", "180", float, m_flRotRate )
  6496. DMXELEMENT_UNPACK_FIELD( "Control Point", "0", int, m_nCP )
  6497. DMXELEMENT_UNPACK_FIELD( "Use Local Space", "0", bool, m_bLocalSpace )
  6498. END_PARTICLE_OPERATOR_UNPACK( C_OP_MovementRotateParticleAroundAxis )
  6499. void C_OP_MovementRotateParticleAroundAxis::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  6500. {
  6501. float flRotRate = m_flRotRate * pParticles->m_flDt;
  6502. matrix3x4_t matRot;
  6503. Vector vecRotAxis = m_vecRotAxis;
  6504. if ( m_bLocalSpace )
  6505. {
  6506. matrix3x4_t matLocalCP;
  6507. pParticles->GetControlPointTransformAtCurrentTime( m_nCP, &matLocalCP );
  6508. VectorRotate( m_vecRotAxis, matLocalCP, vecRotAxis );
  6509. }
  6510. MatrixBuildRotationAboutAxis ( vecRotAxis, flRotRate, matRot );
  6511. Vector vecCPPos = pParticles->GetControlPointAtCurrentTime( m_nCP );
  6512. FourVectors fvCPPos;
  6513. fvCPPos.DuplicateVector( vecCPPos );
  6514. fltx4 fl4Strength = ReplicateX4( flStrength );
  6515. C4VAttributeWriteIterator pXYZ( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  6516. C4VAttributeWriteIterator pPrevXYZ( PARTICLE_ATTRIBUTE_PREV_XYZ, pParticles );
  6517. int nCtr = pParticles->m_nPaddedActiveParticles;
  6518. do
  6519. {
  6520. FourVectors fvCurPos = *pXYZ - fvCPPos;
  6521. FourVectors fvPrevPos = *pPrevXYZ - fvCPPos;
  6522. fvCurPos.RotateBy( matRot );
  6523. fvPrevPos.RotateBy( matRot );
  6524. fvCurPos += fvCPPos - *pXYZ;
  6525. fvCurPos *= fl4Strength;
  6526. *pXYZ += fvCurPos;
  6527. fvPrevPos += fvCPPos - *pPrevXYZ;
  6528. fvPrevPos *= fl4Strength;
  6529. *pPrevXYZ += fvPrevPos;
  6530. ++pXYZ;
  6531. ++pPrevXYZ;
  6532. } while ( --nCtr );
  6533. };
  6534. //-----------------------------------------------------------------------------
  6535. // Rotate Vector
  6536. //-----------------------------------------------------------------------------
  6537. class C_OP_RotateVector : public CParticleOperatorInstance
  6538. {
  6539. DECLARE_PARTICLE_OPERATOR( C_OP_RotateVector );
  6540. int m_nFieldOutput;
  6541. Vector m_vecRotAxisMin;
  6542. Vector m_vecRotAxisMax;
  6543. float m_flRotRateMin;
  6544. float m_flRotRateMax;
  6545. bool m_bNormalize;
  6546. uint32 GetWrittenAttributes( void ) const
  6547. {
  6548. return 1 << m_nFieldOutput;
  6549. }
  6550. uint32 GetReadAttributes( void ) const
  6551. {
  6552. return 1 << m_nFieldOutput | PARTICLE_ATTRIBUTE_PARTICLE_ID_MASK;
  6553. }
  6554. virtual uint64 GetReadControlPointMask() const
  6555. {
  6556. return 0;
  6557. }
  6558. void InitParams( CParticleSystemDefinition *pDef )
  6559. {
  6560. VectorNormalize( m_vecRotAxisMin );
  6561. VectorNormalize( m_vecRotAxisMax );
  6562. }
  6563. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  6564. };
  6565. DEFINE_PARTICLE_OPERATOR( C_OP_RotateVector , "Rotate Vector Random", OPERATOR_GENERIC );
  6566. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RotateVector )
  6567. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "21", int, m_nFieldOutput, "intchoice particlefield_vector" )
  6568. DMXELEMENT_UNPACK_FIELD( "Rotation Axis Min", "0 0 1", Vector, m_vecRotAxisMin )
  6569. DMXELEMENT_UNPACK_FIELD( "Rotation Axis Max", "0 0 1", Vector, m_vecRotAxisMax )
  6570. DMXELEMENT_UNPACK_FIELD( "Rotation Rate Min", "180", float, m_flRotRateMin )
  6571. DMXELEMENT_UNPACK_FIELD( "Rotation Rate Max", "180", float, m_flRotRateMax )
  6572. DMXELEMENT_UNPACK_FIELD( "Normalize Ouput", "0", float, m_bNormalize )
  6573. END_PARTICLE_OPERATOR_UNPACK( C_OP_RotateVector )
  6574. void C_OP_RotateVector::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  6575. {
  6576. Vector vecForward, vecRight, vecUp;
  6577. matrix3x4_t matCP, matRot;
  6578. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  6579. {
  6580. const int *pParticleID = pParticles->GetIntAttributePtr( PARTICLE_ATTRIBUTE_PARTICLE_ID, i );
  6581. float flRotRate = pParticles->RandomFloat( *pParticleID, m_flRotRateMin, m_flRotRateMax );
  6582. flRotRate *= pParticles->m_flDt;
  6583. Vector vecRotAxis;
  6584. float flAxis = pParticles->RandomFloat( *pParticleID, 0, 1 );
  6585. VectorLerp( m_vecRotAxisMin, m_vecRotAxisMax, flAxis, vecRotAxis );
  6586. VectorNormalize( vecRotAxis );
  6587. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, i );
  6588. Vector vecOutput;
  6589. SetVectorFromAttribute( vecOutput, pOutput );
  6590. Vector vecInput = vecOutput;
  6591. MatrixBuildRotationAboutAxis ( vecRotAxis, flRotRate, matRot );
  6592. VectorRotate( vecInput, matRot, vecOutput );
  6593. if ( m_bNormalize )
  6594. VectorNormalize( vecOutput );
  6595. vecOutput = VectorLerp ( vecInput, vecOutput, flStrength );
  6596. SetVectorAttribute( pOutput, vecOutput );
  6597. }
  6598. };
  6599. //-----------------------------------------------------------------------------
  6600. // Max Velocity - clamps the maximum velocity of a particle
  6601. //-----------------------------------------------------------------------------
  6602. class C_OP_MaxVelocity : public CParticleOperatorInstance
  6603. {
  6604. DECLARE_PARTICLE_OPERATOR( C_OP_MaxVelocity );
  6605. float m_flMaxVelocity;
  6606. int m_nOverrideCP;
  6607. int m_nOverrideCPField;
  6608. uint32 GetWrittenAttributes( void ) const
  6609. {
  6610. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK ;
  6611. }
  6612. uint32 GetReadAttributes( void ) const
  6613. {
  6614. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK ;
  6615. }
  6616. virtual uint64 GetReadControlPointMask() const
  6617. {
  6618. return ( 1ULL << m_nOverrideCP );
  6619. }
  6620. virtual void InitParams( CParticleSystemDefinition *pDef )
  6621. {
  6622. m_nOverrideCPField = int (clamp (m_nOverrideCPField, 0, 2));
  6623. }
  6624. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  6625. };
  6626. DEFINE_PARTICLE_OPERATOR( C_OP_MaxVelocity , "Movement Max Velocity", OPERATOR_GENERIC );
  6627. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_MaxVelocity )
  6628. DMXELEMENT_UNPACK_FIELD( "Maximum Velocity", "0", float, m_flMaxVelocity )
  6629. DMXELEMENT_UNPACK_FIELD( "Override Max Velocity from this CP", "-1", int, m_nOverrideCP )
  6630. DMXELEMENT_UNPACK_FIELD( "Override CP field", "0", int, m_nOverrideCPField )
  6631. END_PARTICLE_OPERATOR_UNPACK( C_OP_MaxVelocity )
  6632. void C_OP_MaxVelocity::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  6633. {
  6634. float flMaxVelocity = m_flMaxVelocity;
  6635. if ( m_nOverrideCP >= 0 )
  6636. {
  6637. Vector vecVelInput = pParticles->GetControlPointAtCurrentTime( m_nOverrideCP );
  6638. flMaxVelocity = vecVelInput[m_nOverrideCPField];
  6639. }
  6640. // FIXME: SSE-ize
  6641. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  6642. {
  6643. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, i );
  6644. float *xyz_prev = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  6645. Vector vecXYZ;
  6646. Vector vecPXYZ;
  6647. SetVectorFromAttribute( vecXYZ, xyz );
  6648. SetVectorFromAttribute( vecPXYZ, xyz_prev );
  6649. Vector vecVelocityCur = ( ( vecXYZ - vecPXYZ ) );
  6650. float flSpeed = vecVelocityCur.Length();
  6651. VectorNormalizeFast( vecVelocityCur );
  6652. float flMaxVelocityNormalized = flMaxVelocity * pParticles->m_flDt;
  6653. vecVelocityCur *= MIN( flSpeed, flMaxVelocityNormalized);
  6654. vecXYZ = vecPXYZ + vecVelocityCur;
  6655. SetVectorAttribute( xyz, vecXYZ );
  6656. }
  6657. };
  6658. //-----------------------------------------------------------------------------
  6659. // Movement Lag Compensation - Sets a speed and decelerates it based on an input lag amount (Sort of DotA specific)
  6660. //-----------------------------------------------------------------------------
  6661. class C_OP_LagCompensation : public CParticleOperatorInstance
  6662. {
  6663. DECLARE_PARTICLE_OPERATOR( C_OP_LagCompensation );
  6664. int m_nDesiredVelocityCP;
  6665. int m_nLatencyCP;
  6666. int m_nLatencyCPField;
  6667. int m_nDesiredVelocityCPField;
  6668. uint32 GetWrittenAttributes( void ) const
  6669. {
  6670. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK ;
  6671. }
  6672. uint32 GetReadAttributes( void ) const
  6673. {
  6674. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  6675. }
  6676. virtual uint64 GetReadControlPointMask() const
  6677. {
  6678. return ( 1ULL << m_nDesiredVelocityCP ) | ( 1ULL << m_nLatencyCP );
  6679. }
  6680. virtual void InitParams( CParticleSystemDefinition *pDef )
  6681. {
  6682. m_nLatencyCPField = int (clamp (m_nLatencyCPField, 0, 2));
  6683. m_nDesiredVelocityCPField = int (clamp (m_nDesiredVelocityCPField, -1, 2));
  6684. }
  6685. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  6686. };
  6687. DEFINE_PARTICLE_OPERATOR( C_OP_LagCompensation , "Movement Lag Compensation", OPERATOR_GENERIC );
  6688. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_LagCompensation )
  6689. DMXELEMENT_UNPACK_FIELD( "Desired Velocity CP", "-1", int, m_nDesiredVelocityCP )
  6690. DMXELEMENT_UNPACK_FIELD( "Desired Velocity CP Field Override(for speed only)", "-1", int, m_nDesiredVelocityCPField )
  6691. DMXELEMENT_UNPACK_FIELD( "Latency CP", "-1", int, m_nLatencyCP )
  6692. DMXELEMENT_UNPACK_FIELD( "Latency CP field", "0", int, m_nLatencyCPField )
  6693. END_PARTICLE_OPERATOR_UNPACK( C_OP_LagCompensation )
  6694. void C_OP_LagCompensation::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  6695. {
  6696. if ( m_nDesiredVelocityCP >= 0 && m_nLatencyCP >= 0 )
  6697. {
  6698. Vector vecDesiredVelocity = pParticles->GetControlPointAtCurrentTime( m_nDesiredVelocityCP );
  6699. Vector vecLatency = pParticles->GetControlPointAtCurrentTime( m_nLatencyCP );
  6700. float flLatency = vecLatency[m_nLatencyCPField] + FLT_EPSILON;
  6701. float flDesiredSpeed;
  6702. if ( m_nDesiredVelocityCPField > -1 )
  6703. flDesiredSpeed = vecDesiredVelocity[m_nDesiredVelocityCPField];
  6704. else
  6705. flDesiredSpeed = vecDesiredVelocity.Length();
  6706. float flStartSpeedScaled = flDesiredSpeed * 3;
  6707. float flCatchupTime = ( flLatency / 1000.0f );
  6708. // FIXME: SSE-ize
  6709. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  6710. {
  6711. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, i );
  6712. float *xyz_prev = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  6713. const float *ct = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, i );
  6714. float flAge = pParticles->m_flCurTime - *ct;
  6715. //float flCurrentSpeed = SimpleSplineRemapValClamped( flAge, 0.0f, flCatchupTime, flStartSpeedScaled, flDesiredSpeed );
  6716. float flCurrentSpeed = RemapValClamped( flAge, 0.0f, flCatchupTime, flStartSpeedScaled, flDesiredSpeed );
  6717. Vector vecXYZ;
  6718. Vector vecPXYZ;
  6719. SetVectorFromAttribute( vecXYZ, xyz );
  6720. SetVectorFromAttribute( vecPXYZ, xyz_prev );
  6721. Vector vecVelocityCur = ( ( vecXYZ - vecPXYZ ) );
  6722. VectorNormalizeFast( vecVelocityCur );
  6723. double flSpeed = flCurrentSpeed * pParticles->m_flDt;
  6724. vecVelocityCur *= flSpeed;
  6725. vecXYZ = vecPXYZ + vecVelocityCur;
  6726. SetVectorAttribute( xyz, vecXYZ );
  6727. }
  6728. }
  6729. };
  6730. //-----------------------------------------------------------------------------
  6731. // Maintain position along a path
  6732. //-----------------------------------------------------------------------------
  6733. struct SequentialPositionContext_t
  6734. {
  6735. int m_nParticleCount;
  6736. float m_flStep;
  6737. int m_nCountAmount;
  6738. bool m_bUseParticleCount;
  6739. Vector m_vecPrevPosStart;
  6740. Vector m_vecPrevPosEnd;
  6741. };
  6742. class C_OP_MaintainSequentialPath : public CParticleOperatorInstance
  6743. {
  6744. DECLARE_PARTICLE_OPERATOR( C_OP_MaintainSequentialPath );
  6745. float m_fMaxDistance;
  6746. float m_flNumToAssign;
  6747. float m_flCohesionStrength;
  6748. float m_flTolerance;
  6749. bool m_bLoop;
  6750. bool m_bUseParticleCount;
  6751. struct CPathParameters m_PathParams;
  6752. uint32 GetWrittenAttributes( void ) const
  6753. {
  6754. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  6755. }
  6756. uint32 GetReadAttributes( void ) const
  6757. {
  6758. return 0;
  6759. }
  6760. virtual uint64 GetReadControlPointMask() const
  6761. {
  6762. uint64 nStartMask = ( 1ULL << m_PathParams.m_nStartControlPointNumber ) - 1;
  6763. uint64 nEndMask = ( 1ULL << ( m_PathParams.m_nEndControlPointNumber + 1 ) ) - 1;
  6764. return nEndMask & (~nStartMask);
  6765. }
  6766. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  6767. {
  6768. SequentialPositionContext_t *pCtx = reinterpret_cast<SequentialPositionContext_t *>( pContext );
  6769. pCtx->m_nParticleCount = 0;
  6770. if ( m_flNumToAssign > 1.0f )
  6771. {
  6772. pCtx->m_flStep = 1.0f / ( m_flNumToAssign - 1 );
  6773. }
  6774. else
  6775. {
  6776. pCtx->m_flStep = 0.0f;
  6777. }
  6778. pCtx->m_nCountAmount = 1;
  6779. if ( m_flTolerance > 0 )
  6780. {
  6781. pCtx->m_vecPrevPosStart = vec3_invalid;
  6782. pCtx->m_vecPrevPosEnd = vec3_invalid;
  6783. }
  6784. }
  6785. void InitParams( CParticleSystemDefinition *pDef )
  6786. {
  6787. m_PathParams.ClampControlPointIndices();
  6788. }
  6789. size_t GetRequiredContextBytes( void ) const
  6790. {
  6791. return sizeof( SequentialPositionContext_t );
  6792. }
  6793. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  6794. };
  6795. DEFINE_PARTICLE_OPERATOR( C_OP_MaintainSequentialPath, "Movement Maintain Position Along Path", OPERATOR_GENERIC );
  6796. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_MaintainSequentialPath )
  6797. DMXELEMENT_UNPACK_FIELD( "maximum distance", "0", float, m_fMaxDistance )
  6798. DMXELEMENT_UNPACK_FIELD( "bulge", "0", float, m_PathParams.m_flBulge )
  6799. DMXELEMENT_UNPACK_FIELD( "start control point number", "0", int, m_PathParams.m_nStartControlPointNumber )
  6800. DMXELEMENT_UNPACK_FIELD( "end control point number", "0", int, m_PathParams.m_nEndControlPointNumber )
  6801. DMXELEMENT_UNPACK_FIELD( "bulge control 0=random 1=orientation of start pnt 2=orientation of end point", "0", int, m_PathParams.m_nBulgeControl )
  6802. DMXELEMENT_UNPACK_FIELD( "mid point position", "0.5", float, m_PathParams.m_flMidPoint )
  6803. DMXELEMENT_UNPACK_FIELD( "particles to map from start to end", "100", float, m_flNumToAssign )
  6804. DMXELEMENT_UNPACK_FIELD( "restart behavior (0 = bounce, 1 = loop )", "1", bool, m_bLoop )
  6805. DMXELEMENT_UNPACK_FIELD( "cohesion strength", "1", float, m_flCohesionStrength )
  6806. DMXELEMENT_UNPACK_FIELD( "use existing particle count", "0", bool, m_bUseParticleCount )
  6807. DMXELEMENT_UNPACK_FIELD( "control point movement tolerance", "0", float, m_flTolerance )
  6808. END_PARTICLE_OPERATOR_UNPACK( C_OP_MaintainSequentialPath )
  6809. void C_OP_MaintainSequentialPath::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  6810. {
  6811. SequentialPositionContext_t *pCtx = reinterpret_cast<SequentialPositionContext_t *>( pContext );
  6812. // Check to see if our CP movement is within tolerances - if so abort.
  6813. if ( m_flTolerance > 0 )
  6814. {
  6815. if ( ( pParticles->GetControlPointAtCurrentTime( m_PathParams.m_nStartControlPointNumber ) - pCtx->m_vecPrevPosStart ).Length() < m_flTolerance )
  6816. {
  6817. if ( ( pParticles->GetControlPointAtCurrentTime( m_PathParams.m_nEndControlPointNumber ) - pCtx->m_vecPrevPosEnd ).Length() < m_flTolerance )
  6818. return;
  6819. }
  6820. pCtx->m_vecPrevPosStart = pParticles->GetControlPointAtCurrentTime( m_PathParams.m_nStartControlPointNumber );
  6821. pCtx->m_vecPrevPosEnd = pParticles->GetControlPointAtCurrentTime( m_PathParams.m_nEndControlPointNumber );
  6822. }
  6823. float fl_Cohesion = ( 1 - m_flCohesionStrength );
  6824. float flNumToAssign = m_flNumToAssign;
  6825. if ( m_bUseParticleCount )
  6826. {
  6827. flNumToAssign = pParticles->m_nActiveParticles;
  6828. if ( flNumToAssign > 1.0f )
  6829. {
  6830. pCtx->m_flStep = 1.0f / ( flNumToAssign - 1 );
  6831. }
  6832. else
  6833. {
  6834. pCtx->m_flStep = 0.0f;
  6835. }
  6836. }
  6837. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  6838. {
  6839. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, i );
  6840. float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  6841. Vector StartPnt, MidP, EndPnt;
  6842. pParticles->CalculatePathValues( m_PathParams, pParticles->m_flCurTime, &StartPnt, &MidP, &EndPnt);
  6843. if ( pCtx->m_nParticleCount >= flNumToAssign || pCtx->m_nParticleCount < 0 )
  6844. {
  6845. if ( m_bLoop )
  6846. {
  6847. pCtx->m_nParticleCount = 0;
  6848. }
  6849. else
  6850. {
  6851. pCtx->m_nCountAmount *= -1;
  6852. pCtx->m_nParticleCount = MIN( pCtx->m_nParticleCount, ( flNumToAssign - 1) );
  6853. pCtx->m_nParticleCount = MAX( pCtx->m_nParticleCount, 1 );
  6854. }
  6855. }
  6856. float t= pCtx->m_nParticleCount * pCtx->m_flStep;
  6857. // form delta terms needed for quadratic bezier
  6858. Vector Delta0=MidP-StartPnt;
  6859. Vector Delta1 = EndPnt-MidP;
  6860. Vector L0 = StartPnt+t*Delta0;
  6861. Vector L1 = MidP+t*Delta1;
  6862. Vector Pnt = L0+(L1-L0)*t;
  6863. // Allow an offset distance and position lerp
  6864. Vector vecXYZ;
  6865. Vector vecPXYZ;
  6866. SetVectorFromAttribute( vecXYZ, xyz );
  6867. SetVectorFromAttribute( vecPXYZ, pxyz );
  6868. vecXYZ -= Pnt;
  6869. vecPXYZ -= Pnt;
  6870. float flXYZOffset = MIN(vecXYZ.Length(), m_fMaxDistance );
  6871. float flPXYZOffset = MIN(vecPXYZ.Length(), m_fMaxDistance );
  6872. VectorNormalizeFast( vecXYZ );
  6873. vecXYZ *= flXYZOffset * fl_Cohesion;
  6874. VectorNormalizeFast( vecPXYZ );
  6875. vecPXYZ *= flPXYZOffset * fl_Cohesion;
  6876. vecXYZ += Pnt;
  6877. vecPXYZ += Pnt;
  6878. xyz[0] = vecXYZ.x;
  6879. xyz[4] = vecXYZ.y;
  6880. xyz[8] = vecXYZ.z;
  6881. pxyz[0] = vecPXYZ.x;
  6882. pxyz[4] = vecPXYZ.y;
  6883. pxyz[8] = vecPXYZ.z;
  6884. pCtx->m_nParticleCount += pCtx->m_nCountAmount;
  6885. }
  6886. }
  6887. class C_OP_LockToSavedSequentialPath : public CParticleOperatorInstance
  6888. {
  6889. DECLARE_PARTICLE_OPERATOR( C_OP_LockToSavedSequentialPath );
  6890. int m_nPathCount;
  6891. float m_flFadeStart;
  6892. float m_flFadeEnd;
  6893. float m_flTolerance;
  6894. bool m_bCPPairs;
  6895. struct CPathParameters m_PathParams;
  6896. struct LockPathPositionContext_t
  6897. {
  6898. Vector m_vecPrevStartPnt[MAX_PARTICLE_CONTROL_POINTS];
  6899. Vector m_vecPrevMidP[MAX_PARTICLE_CONTROL_POINTS];
  6900. Vector m_vecPrevEndPnt[MAX_PARTICLE_CONTROL_POINTS];
  6901. };
  6902. uint32 GetWrittenAttributes( void ) const
  6903. {
  6904. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  6905. }
  6906. uint32 GetReadAttributes( void ) const
  6907. {
  6908. return PARTICLE_ATTRIBUTE_HITBOX_INDEX_MASK | PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_HITBOX_RELATIVE_XYZ_MASK;
  6909. }
  6910. virtual uint64 GetReadControlPointMask() const
  6911. {
  6912. uint64 nStartMask = ( 1ULL << m_PathParams.m_nStartControlPointNumber ) - 1;
  6913. uint64 nEndMask = m_bCPPairs ? 0xFFFFFFFFFFFFFFFFULL : ( 1ULL << ( m_PathParams.m_nEndControlPointNumber + 1 ) ) - 1;
  6914. return nEndMask & (~nStartMask);
  6915. }
  6916. void InitParams( CParticleSystemDefinition *pDef )
  6917. {
  6918. m_PathParams.ClampControlPointIndices();
  6919. m_nPathCount = MAX( 1, m_bCPPairs ? m_PathParams.m_nEndControlPointNumber - m_PathParams.m_nStartControlPointNumber : 1 );
  6920. }
  6921. size_t GetRequiredContextBytes( void ) const
  6922. {
  6923. return sizeof( LockPathPositionContext_t );
  6924. }
  6925. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  6926. {
  6927. LockPathPositionContext_t *pCtx = reinterpret_cast<LockPathPositionContext_t *>( pContext );
  6928. for ( int i = 0; i < m_nPathCount; ++i )
  6929. {
  6930. pCtx->m_vecPrevStartPnt[i] = vec3_invalid;
  6931. }
  6932. }
  6933. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  6934. };
  6935. DEFINE_PARTICLE_OPERATOR( C_OP_LockToSavedSequentialPath, "Movement Lock to Saved Position Along Path", OPERATOR_GENERIC );
  6936. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_LockToSavedSequentialPath )
  6937. DMXELEMENT_UNPACK_FIELD( "bulge", "0", float, m_PathParams.m_flBulge )
  6938. DMXELEMENT_UNPACK_FIELD( "start control point number", "0", int, m_PathParams.m_nStartControlPointNumber )
  6939. DMXELEMENT_UNPACK_FIELD( "end control point number", "1", int, m_PathParams.m_nEndControlPointNumber )
  6940. DMXELEMENT_UNPACK_FIELD( "bulge control 0=random 1=orientation of start pnt 2=orientation of end point", "0", int, m_PathParams.m_nBulgeControl )
  6941. DMXELEMENT_UNPACK_FIELD( "mid point position", "0.5", float, m_PathParams.m_flMidPoint )
  6942. DMXELEMENT_UNPACK_FIELD( "Use sequential CP pairs between start and end point", "0", bool, m_bCPPairs )
  6943. //DMXELEMENT_UNPACK_FIELD( "start fade time", "1", float, m_flFadeStart )
  6944. //DMXELEMENT_UNPACK_FIELD( "end fade time", "1", float, m_flFadeEnd )
  6945. END_PARTICLE_OPERATOR_UNPACK( C_OP_LockToSavedSequentialPath )
  6946. void C_OP_LockToSavedSequentialPath::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  6947. {
  6948. LockPathPositionContext_t *pCtx = reinterpret_cast<LockPathPositionContext_t *>( pContext );
  6949. Vector Delta0[MAX_PARTICLE_CONTROL_POINTS];
  6950. Vector Delta1[MAX_PARTICLE_CONTROL_POINTS];
  6951. Vector PrevDelta0[MAX_PARTICLE_CONTROL_POINTS];
  6952. Vector PrevDelta1[MAX_PARTICLE_CONTROL_POINTS];
  6953. Vector StartPnt[MAX_PARTICLE_CONTROL_POINTS];
  6954. Vector MidP[MAX_PARTICLE_CONTROL_POINTS];
  6955. Vector EndPnt[MAX_PARTICLE_CONTROL_POINTS];
  6956. for ( int i = 0; i < m_nPathCount; ++i )
  6957. {
  6958. struct CPathParameters CurrentPathParams = m_PathParams;
  6959. if ( m_bCPPairs )
  6960. {
  6961. CurrentPathParams.m_nStartControlPointNumber += i;
  6962. CurrentPathParams.m_nEndControlPointNumber = CurrentPathParams.m_nStartControlPointNumber + 1;
  6963. }
  6964. pParticles->CalculatePathValues( CurrentPathParams, pParticles->m_flCurTime, &StartPnt[i], &MidP[i], &EndPnt[i]);
  6965. // If it's first run, initialize our values
  6966. if ( pCtx->m_vecPrevStartPnt[i] == vec3_invalid )
  6967. {
  6968. pParticles->CalculatePathValues( CurrentPathParams, pParticles->m_flCurTime - pParticles->m_flDt, &pCtx->m_vecPrevStartPnt[i], &pCtx->m_vecPrevMidP[i], &pCtx->m_vecPrevEndPnt[i]);
  6969. }
  6970. // form delta terms needed for quadratic bezier
  6971. Delta0[i] = MidP[i] - StartPnt[i];
  6972. Delta1[i] = EndPnt[i] - MidP[i];
  6973. PrevDelta0[i] = pCtx->m_vecPrevMidP[i] - pCtx->m_vecPrevStartPnt[i];
  6974. PrevDelta1[i] = pCtx->m_vecPrevEndPnt[i] - pCtx->m_vecPrevMidP[i];
  6975. }
  6976. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  6977. {
  6978. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, i );
  6979. float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  6980. const float *pSavedPos = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_HITBOX_RELATIVE_XYZ, i );
  6981. const float *pCt = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, i );
  6982. Vector vecSavedPos;
  6983. SetVectorFromAttribute( vecSavedPos, pSavedPos );
  6984. float flParticleAge = pParticles->m_flCurTime - *pCt;
  6985. float flCreationFrameBias = MIN( flParticleAge, pParticles->m_flDt );
  6986. flCreationFrameBias *= ( 1 / pParticles->m_flDt );
  6987. float t= vecSavedPos.x;
  6988. int nStartCP = int ( MAX( 0, vecSavedPos.y - m_PathParams.m_nStartControlPointNumber ) );
  6989. Vector PrevL0 = pCtx->m_vecPrevStartPnt[nStartCP]+t*PrevDelta0[nStartCP];
  6990. Vector PrevL1 = pCtx->m_vecPrevMidP[nStartCP]+t*PrevDelta1[nStartCP];
  6991. Vector PrevPnt = PrevL0+(PrevL1-PrevL0)*t;
  6992. Vector L0 = StartPnt[nStartCP]+t*Delta0[nStartCP];
  6993. Vector L1 = MidP[nStartCP]+t*Delta1[nStartCP];
  6994. Vector Pnt = L0+(L1-L0)*t;
  6995. Pnt -= PrevPnt;
  6996. VectorLerp( vec3_origin, Pnt, vec_t ( flCreationFrameBias ), Pnt );
  6997. Vector vecXYZ;
  6998. Vector vecPXYZ;
  6999. SetVectorFromAttribute( vecXYZ, xyz );
  7000. SetVectorFromAttribute( vecPXYZ, pxyz );
  7001. vecXYZ += Pnt;
  7002. vecPXYZ += Pnt;
  7003. xyz[0] = vecXYZ.x;
  7004. xyz[4] = vecXYZ.y;
  7005. xyz[8] = vecXYZ.z;
  7006. pxyz[0] = vecPXYZ.x;
  7007. pxyz[4] = vecPXYZ.y;
  7008. pxyz[8] = vecPXYZ.z;
  7009. }
  7010. for ( int i = 0; i < m_nPathCount; ++i )
  7011. {
  7012. pCtx->m_vecPrevStartPnt[i] = StartPnt[i];
  7013. pCtx->m_vecPrevMidP[i] = MidP[i];
  7014. pCtx->m_vecPrevEndPnt[i] = EndPnt[i];
  7015. }
  7016. }
  7017. //-----------------------------------------------------------------------------
  7018. // Remap Dot Product to Scalar Operator
  7019. //-----------------------------------------------------------------------------
  7020. class C_OP_RemapDotProductToScalar : public CParticleOperatorInstance
  7021. {
  7022. DECLARE_PARTICLE_OPERATOR( C_OP_RemapDotProductToScalar );
  7023. uint32 GetWrittenAttributes( void ) const
  7024. {
  7025. return 1 << m_nFieldOutput;
  7026. }
  7027. uint32 GetReadAttributes( void ) const
  7028. {
  7029. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  7030. }
  7031. uint32 GetReadInitialAttributes( void ) const
  7032. {
  7033. if ( m_bScaleInitialRange )
  7034. return 1 << m_nFieldOutput;
  7035. else
  7036. return 0;
  7037. }
  7038. uint32 GetFilter( void ) const
  7039. {
  7040. return FILTER_PARAMETER_REMAPPING_MASK;
  7041. }
  7042. virtual uint64 GetReadControlPointMask() const
  7043. {
  7044. return ( 1ULL << m_nInputCP1 ) | ( 1ULL << m_nInputCP2 );
  7045. }
  7046. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  7047. int m_nInputCP1;
  7048. int m_nInputCP2;
  7049. int m_nFieldOutput;
  7050. float m_flInputMin;
  7051. float m_flInputMax;
  7052. float m_flOutputMin;
  7053. float m_flOutputMax;
  7054. bool m_bUseParticleVelocity;
  7055. bool m_bScaleInitialRange;
  7056. bool m_bScaleCurrent;
  7057. bool m_bActiveRange;
  7058. };
  7059. DEFINE_PARTICLE_OPERATOR( C_OP_RemapDotProductToScalar, "Remap Dot Product to Scalar", OPERATOR_GENERIC );
  7060. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RemapDotProductToScalar )
  7061. DMXELEMENT_UNPACK_FIELD( "use particle velocity for first input", "0", bool, m_bUseParticleVelocity )
  7062. DMXELEMENT_UNPACK_FIELD( "first input control point", "0", int, m_nInputCP1 )
  7063. DMXELEMENT_UNPACK_FIELD( "second input control point", "0", int, m_nInputCP2 )
  7064. DMXELEMENT_UNPACK_FIELD( "input minimum (-1 to 1)","0", float, m_flInputMin )
  7065. DMXELEMENT_UNPACK_FIELD( "input maximum (-1 to 1)","1", float, m_flInputMax )
  7066. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "3", int, m_nFieldOutput, "intchoice particlefield_scalar" )
  7067. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  7068. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  7069. DMXELEMENT_UNPACK_FIELD( "output is scalar of initial random range","0", bool, m_bScaleInitialRange )
  7070. DMXELEMENT_UNPACK_FIELD( "output is scalar of current value","0", bool, m_bScaleCurrent )
  7071. DMXELEMENT_UNPACK_FIELD( "only active within specified input range","0", bool, m_bActiveRange )
  7072. END_PARTICLE_OPERATOR_UNPACK( C_OP_RemapDotProductToScalar )
  7073. void C_OP_RemapDotProductToScalar::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  7074. {
  7075. // clamp the result to 0 and 1 if it's alpha
  7076. float flMin=m_flOutputMin;
  7077. float flMax=m_flOutputMax;
  7078. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & ( 1 << m_nFieldOutput ) )
  7079. {
  7080. flMin = clamp(m_flOutputMin, 0.0f, 1.0f );
  7081. flMax = clamp(m_flOutputMax, 0.0f, 1.0f );
  7082. }
  7083. Vector vecInput1;
  7084. Vector vecInput2;
  7085. CParticleSIMDTransformation pXForm1;
  7086. CParticleSIMDTransformation pXForm2;
  7087. pParticles->GetControlPointTransformAtTime( m_nInputCP1, pParticles->m_flCurTime, &pXForm1 );
  7088. pParticles->GetControlPointTransformAtTime( m_nInputCP2, pParticles->m_flCurTime, &pXForm2 );
  7089. vecInput1 = pXForm1.m_v4Fwd.Vec( 0 );
  7090. vecInput2 = pXForm2.m_v4Fwd.Vec( 0 );
  7091. float flInput = DotProduct( vecInput1, vecInput2 );
  7092. // only use within start/end time frame and, if set, active input range
  7093. if ( ( m_bActiveRange && !m_bUseParticleVelocity && ( flInput < m_flInputMin || flInput > m_flInputMax ) ) )
  7094. return;
  7095. // FIXME: SSE-ize
  7096. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  7097. {
  7098. if ( m_bUseParticleVelocity )
  7099. {
  7100. const float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, i );
  7101. const float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  7102. Vector vecXYZ;
  7103. Vector vecPXYZ;
  7104. vecXYZ.x = xyz[0];
  7105. vecXYZ.y = xyz[4];
  7106. vecXYZ.z = xyz[8];
  7107. vecPXYZ.x = pxyz[0];
  7108. vecPXYZ.y = pxyz[4];
  7109. vecPXYZ.z = pxyz[8];
  7110. vecInput1 = vecXYZ - vecPXYZ;
  7111. VectorNormalizeFast( vecInput1 );
  7112. float flInput = DotProduct( vecInput1, vecInput2 );
  7113. // only use within start/end time frame and, if set, active input range
  7114. if ( ( m_bActiveRange && ( flInput < m_flInputMin || flInput > m_flInputMax ) ) )
  7115. continue;
  7116. }
  7117. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, i );
  7118. float flOutput = RemapValClamped( flInput, m_flInputMin, m_flInputMax, flMin, flMax );
  7119. if ( m_bScaleInitialRange )
  7120. {
  7121. const float *pInput = pParticles->GetInitialFloatAttributePtr( m_nFieldOutput, i );
  7122. flOutput = *pInput * flOutput;
  7123. }
  7124. if ( m_bScaleCurrent )
  7125. {
  7126. flOutput *= *pOutput;
  7127. }
  7128. if ( ATTRIBUTES_WHICH_ARE_INTS & ( 1 << m_nFieldOutput ) )
  7129. {
  7130. *pOutput = int ( flOutput );
  7131. }
  7132. else
  7133. {
  7134. *pOutput = flOutput;
  7135. }
  7136. }
  7137. }
  7138. //-----------------------------------------------------------------------------
  7139. // Remap CP to Scalar Operator
  7140. //-----------------------------------------------------------------------------
  7141. class C_OP_RemapCPtoScalar : public CParticleOperatorInstance
  7142. {
  7143. DECLARE_PARTICLE_OPERATOR( C_OP_RemapCPtoScalar );
  7144. uint32 GetWrittenAttributes( void ) const
  7145. {
  7146. return 1 << m_nFieldOutput;
  7147. }
  7148. uint32 GetReadAttributes( void ) const
  7149. {
  7150. return 0;
  7151. }
  7152. uint32 GetReadInitialAttributes( void ) const
  7153. {
  7154. if ( m_bScaleInitialRange )
  7155. return 1 << m_nFieldOutput;
  7156. else
  7157. return 0;
  7158. }
  7159. uint32 GetFilter( void ) const
  7160. {
  7161. return FILTER_PARAMETER_REMAPPING_MASK;
  7162. }
  7163. virtual uint64 GetReadControlPointMask() const
  7164. {
  7165. return 1ULL << m_nCPInput;
  7166. }
  7167. virtual void InitParams( CParticleSystemDefinition *pDef )
  7168. {
  7169. m_nField = int (clamp (m_nField, 0, 2));
  7170. }
  7171. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  7172. int m_nCPInput;
  7173. int m_nFieldOutput;
  7174. int m_nField;
  7175. float m_flInputMin;
  7176. float m_flInputMax;
  7177. float m_flOutputMin;
  7178. float m_flOutputMax;
  7179. float m_flStartTime;
  7180. float m_flEndTime;
  7181. bool m_bScaleInitialRange;
  7182. bool m_bScaleCurrent;
  7183. };
  7184. DEFINE_PARTICLE_OPERATOR( C_OP_RemapCPtoScalar, "Remap Control Point to Scalar", OPERATOR_GENERIC );
  7185. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RemapCPtoScalar )
  7186. DMXELEMENT_UNPACK_FIELD( "emitter lifetime start time (seconds)", "-1", float, m_flStartTime )
  7187. DMXELEMENT_UNPACK_FIELD( "emitter lifetime end time (seconds)", "-1", float, m_flEndTime )
  7188. DMXELEMENT_UNPACK_FIELD( "input control point number", "0", int, m_nCPInput )
  7189. DMXELEMENT_UNPACK_FIELD( "input minimum","0", float, m_flInputMin )
  7190. DMXELEMENT_UNPACK_FIELD( "input maximum","1", float, m_flInputMax )
  7191. DMXELEMENT_UNPACK_FIELD( "input field 0-2 X/Y/Z","0", int, m_nField )
  7192. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "3", int, m_nFieldOutput, "intchoice particlefield_scalar" )
  7193. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  7194. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  7195. DMXELEMENT_UNPACK_FIELD( "output is scalar of initial random range","0", bool, m_bScaleInitialRange )
  7196. DMXELEMENT_UNPACK_FIELD( "output is scalar of current value","0", bool, m_bScaleCurrent )
  7197. END_PARTICLE_OPERATOR_UNPACK( C_OP_RemapCPtoScalar )
  7198. void C_OP_RemapCPtoScalar::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  7199. {
  7200. const float *pCreationTime;
  7201. // clamp the result to 0 and 1 if it's alpha
  7202. float flMin=m_flOutputMin;
  7203. float flMax=m_flOutputMax;
  7204. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & ( 1 << m_nFieldOutput ) )
  7205. {
  7206. flMin = clamp(m_flOutputMin, 0.0f, 1.0f );
  7207. flMax = clamp(m_flOutputMax, 0.0f, 1.0f );
  7208. }
  7209. Vector vecControlPoint = pParticles->GetControlPointAtCurrentTime( m_nCPInput );
  7210. float flInput = vecControlPoint[m_nField];
  7211. // FIXME: SSE-ize
  7212. for( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  7213. {
  7214. pCreationTime = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, i );
  7215. // using raw creation time to map to emitter lifespan
  7216. float flLifeTime = *pCreationTime;
  7217. // only use within start/end time frame
  7218. if ( ( ( flLifeTime < m_flStartTime ) || ( flLifeTime >= m_flEndTime ) ) && ( ( m_flStartTime != -1.0f) && ( m_flEndTime != -1.0f) ) )
  7219. continue;
  7220. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, i );
  7221. float flOutput = RemapValClamped( flInput, m_flInputMin, m_flInputMax, flMin, flMax );
  7222. if ( m_bScaleInitialRange )
  7223. {
  7224. const float *pInput = pParticles->GetInitialFloatAttributePtr( m_nFieldOutput, i );
  7225. flOutput = *pInput * flOutput;
  7226. }
  7227. if ( m_bScaleCurrent )
  7228. {
  7229. flOutput *= *pOutput;
  7230. }
  7231. if ( ATTRIBUTES_WHICH_ARE_INTS & ( 1 << m_nFieldOutput ) )
  7232. {
  7233. *pOutput = int ( flOutput );
  7234. }
  7235. else
  7236. {
  7237. *pOutput = flOutput;
  7238. }
  7239. }
  7240. }
  7241. //-----------------------------------------------------------------------------
  7242. // Normal Lock to Control Point
  7243. // Locks all particles to the specified control point
  7244. // Useful for making particles move with their emitter and so forth
  7245. //-----------------------------------------------------------------------------
  7246. class C_OP_NormalLock : public CParticleOperatorInstance
  7247. {
  7248. DECLARE_PARTICLE_OPERATOR( C_OP_NormalLock );
  7249. struct C_OP_NormalLockContext_t
  7250. {
  7251. matrix3x4_t m_matPrevTransform;
  7252. };
  7253. int m_nControlPointNumber;
  7254. uint32 GetWrittenAttributes( void ) const
  7255. {
  7256. return PARTICLE_ATTRIBUTE_NORMAL_MASK;
  7257. }
  7258. uint32 GetReadAttributes( void ) const
  7259. {
  7260. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK ;
  7261. }
  7262. virtual uint64 GetReadControlPointMask() const
  7263. {
  7264. return 1ULL << m_nControlPointNumber;
  7265. }
  7266. void InitParams( CParticleSystemDefinition *pDef )
  7267. {
  7268. m_nControlPointNumber = MAX( 0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nControlPointNumber ) );
  7269. }
  7270. size_t GetRequiredContextBytes( void ) const
  7271. {
  7272. return sizeof( C_OP_NormalLockContext_t );
  7273. }
  7274. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  7275. {
  7276. C_OP_NormalLockContext_t *pCtx=reinterpret_cast<C_OP_NormalLockContext_t *>( pContext );
  7277. pParticles->GetControlPointTransformAtTime( m_nControlPointNumber, pParticles->m_flCurTime, &pCtx->m_matPrevTransform );
  7278. }
  7279. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  7280. };
  7281. DEFINE_PARTICLE_OPERATOR( C_OP_NormalLock , "Normal Lock to Control Point", OPERATOR_GENERIC );
  7282. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_NormalLock )
  7283. DMXELEMENT_UNPACK_FIELD( "control_point_number", "0", int, m_nControlPointNumber )
  7284. END_PARTICLE_OPERATOR_UNPACK( C_OP_NormalLock )
  7285. void C_OP_NormalLock::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  7286. {
  7287. C_OP_NormalLockContext_t *pCtx=reinterpret_cast<C_OP_NormalLockContext_t *>( pContext );
  7288. matrix3x4_t matCurrentTransform;
  7289. matrix3x4_t matTransformLock;
  7290. pParticles->GetControlPointTransformAtTime( m_nControlPointNumber, pParticles->m_flCurTime, &matCurrentTransform );
  7291. matrix3x4_t matPrev;
  7292. MatrixInvert( pCtx->m_matPrevTransform, matPrev );
  7293. MatrixMultiply( matCurrentTransform, matPrev, matTransformLock);
  7294. // FIXME: SSE-ize
  7295. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  7296. {
  7297. const float *pCreationTime;
  7298. pCreationTime = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, i );
  7299. float flParticleAge = pParticles->m_flCurTime - *pCreationTime;
  7300. float flCreationFrameBias = MIN( flParticleAge, pParticles->m_flDt );
  7301. flCreationFrameBias *= ( 1 / pParticles->m_flDt );
  7302. float *normal = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_NORMAL, i );
  7303. Vector vecNormalOld, vecNormalNew;
  7304. SetVectorFromAttribute( vecNormalOld, normal );
  7305. VectorRotate( vecNormalOld, matTransformLock, vecNormalNew );
  7306. VectorLerp( vecNormalOld, vecNormalNew, vec_t ( flCreationFrameBias ), vecNormalNew );
  7307. SetVectorAttribute( normal, vecNormalNew );
  7308. }
  7309. // Store off the control point position for the next delta computation
  7310. pCtx->m_matPrevTransform = matCurrentTransform;
  7311. };
  7312. //-----------------------------------------------------------------------------
  7313. // Set Control Point to Impact Point
  7314. //-----------------------------------------------------------------------------
  7315. class C_OP_SetControlPointToImpactPoint : public CParticleOperatorInstance
  7316. {
  7317. DECLARE_PARTICLE_OPERATOR( C_OP_SetControlPointToImpactPoint );
  7318. int m_nCPOut;
  7319. int m_nCPIn;
  7320. int m_nCollisionGroupNumber;
  7321. float m_flUpdateRate;
  7322. float m_flTraceLength;
  7323. float m_flOffset;
  7324. Vector m_vecTraceDir;
  7325. char m_CollisionGroupName[128];
  7326. struct C_OP_SetCPToImpactPointContext_t
  7327. {
  7328. float m_flNextUpdateTime;
  7329. };
  7330. uint32 GetWrittenAttributes( void ) const
  7331. {
  7332. return 0;
  7333. }
  7334. uint32 GetReadAttributes( void ) const
  7335. {
  7336. return 0;
  7337. }
  7338. bool ShouldRunBeforeEmitters( void ) const
  7339. {
  7340. return true;
  7341. }
  7342. void InitParams( CParticleSystemDefinition *pDef )
  7343. {
  7344. m_nCollisionGroupNumber = g_pParticleSystemMgr->Query()->GetCollisionGroupFromName( m_CollisionGroupName );
  7345. m_nCPIn = MAX( 0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nCPIn ) );
  7346. m_nCPOut = MAX( 0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nCPOut ) );
  7347. }
  7348. size_t GetRequiredContextBytes( void ) const
  7349. {
  7350. return sizeof( C_OP_SetCPToImpactPointContext_t );
  7351. }
  7352. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  7353. {
  7354. C_OP_SetCPToImpactPointContext_t *pCtx=reinterpret_cast<C_OP_SetCPToImpactPointContext_t *>( pContext );
  7355. pCtx->m_flNextUpdateTime = 0.0 - m_flUpdateRate;
  7356. }
  7357. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  7358. };
  7359. DEFINE_PARTICLE_OPERATOR( C_OP_SetControlPointToImpactPoint, "Set Control Point to Impact Point", OPERATOR_GENERIC );
  7360. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_SetControlPointToImpactPoint )
  7361. DMXELEMENT_UNPACK_FIELD( "Control Point to Set", "1", int, m_nCPOut )
  7362. DMXELEMENT_UNPACK_FIELD( "Control Point to Trace From", "1", int, m_nCPIn )
  7363. DMXELEMENT_UNPACK_FIELD( "Trace Direction Override", "0 0 0", Vector, m_vecTraceDir )
  7364. DMXELEMENT_UNPACK_FIELD( "Trace Update Rate", "0.5", float, m_flUpdateRate )
  7365. DMXELEMENT_UNPACK_FIELD( "Max Trace Length", "1024", float, m_flTraceLength )
  7366. DMXELEMENT_UNPACK_FIELD( "Offset End Point Amount", "0", float, m_flOffset )
  7367. DMXELEMENT_UNPACK_FIELD_STRING( "trace collision group", "NONE", m_CollisionGroupName )
  7368. END_PARTICLE_OPERATOR_UNPACK( C_OP_SetControlPointToImpactPoint )
  7369. void C_OP_SetControlPointToImpactPoint::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  7370. {
  7371. C_OP_SetCPToImpactPointContext_t *pCtx=reinterpret_cast<C_OP_SetCPToImpactPointContext_t *>( pContext );
  7372. if ( pCtx->m_flNextUpdateTime <= pParticles->m_flCurTime )
  7373. {
  7374. Vector pForward = m_vecTraceDir;
  7375. Vector pUp;
  7376. Vector pRight;
  7377. if ( m_vecTraceDir == vec3_origin )
  7378. pParticles->GetControlPointOrientationAtTime(m_nCPIn, pParticles->m_flCurTime, &pForward, &pRight, &pUp );
  7379. Vector vecStartPnt = pParticles->GetControlPointAtCurrentTime( m_nCPIn );
  7380. Vector vecEndPnt = vecStartPnt + ( pForward * m_flTraceLength );
  7381. CBaseTrace tr;
  7382. g_pParticleSystemMgr->Query()->TraceLine( vecStartPnt, vecEndPnt, MASK_ALL, NULL , m_nCollisionGroupNumber, &tr );
  7383. Vector vecForward, vecRight, vecUp;
  7384. vecForward = tr.plane.normal;
  7385. VectorVectors( vecForward, vecRight, vecUp );
  7386. Vector vecPos = tr.endpos + ( pForward * -m_flOffset );
  7387. pParticles->SetControlPoint( m_nCPOut, vecPos );
  7388. pParticles->SetControlPointOrientation( m_nCPOut, vecForward, vecRight, vecUp );
  7389. pCtx->m_flNextUpdateTime = pParticles->m_flCurTime + m_flUpdateRate;
  7390. }
  7391. }
  7392. //-----------------------------------------------------------------------------
  7393. // Remap CP to Vector Operator
  7394. //-----------------------------------------------------------------------------
  7395. class C_OP_RemapCPtoVector : public CParticleOperatorInstance
  7396. {
  7397. DECLARE_PARTICLE_OPERATOR( C_OP_RemapCPtoVector );
  7398. uint32 GetWrittenAttributes( void ) const
  7399. {
  7400. return 1 << m_nFieldOutput | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  7401. }
  7402. uint32 GetReadAttributes( void ) const
  7403. {
  7404. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  7405. }
  7406. uint32 GetReadInitialAttributes( void ) const
  7407. {
  7408. if ( m_bScaleInitialRange )
  7409. return 1 << m_nFieldOutput;
  7410. else
  7411. return 0;
  7412. }
  7413. virtual uint64 GetReadControlPointMask() const
  7414. {
  7415. uint64 nMask = ( 1ULL << m_nCPInput );
  7416. if ( m_nLocalSpaceCP != -1 )
  7417. {
  7418. nMask |= ( 1ULL << m_nLocalSpaceCP );
  7419. }
  7420. return nMask;
  7421. }
  7422. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  7423. int m_nCPInput;
  7424. int m_nFieldOutput;
  7425. int m_nField;
  7426. int m_nLocalSpaceCP;
  7427. Vector m_vInputMin;
  7428. Vector m_vInputMax;
  7429. Vector m_vOutputMin;
  7430. Vector m_vOutputMax;
  7431. float m_flStartTime;
  7432. float m_flEndTime;
  7433. bool m_bScaleInitialRange;
  7434. bool m_bScaleCurrent;
  7435. bool m_bOffset;
  7436. bool m_bAccelerate;
  7437. };
  7438. DEFINE_PARTICLE_OPERATOR( C_OP_RemapCPtoVector, "Remap Control Point to Vector", OPERATOR_GENERIC );
  7439. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RemapCPtoVector )
  7440. DMXELEMENT_UNPACK_FIELD( "emitter lifetime start time (seconds)", "-1", float, m_flStartTime )
  7441. DMXELEMENT_UNPACK_FIELD( "emitter lifetime end time (seconds)", "-1", float, m_flEndTime )
  7442. DMXELEMENT_UNPACK_FIELD( "input control point number", "0", int, m_nCPInput )
  7443. DMXELEMENT_UNPACK_FIELD( "input minimum","0 0 0", Vector, m_vInputMin )
  7444. DMXELEMENT_UNPACK_FIELD( "input maximum","0 0 0", Vector, m_vInputMax )
  7445. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "0", int, m_nFieldOutput, "intchoice particlefield_vector" )
  7446. DMXELEMENT_UNPACK_FIELD( "output minimum","0 0 0", Vector, m_vOutputMin )
  7447. DMXELEMENT_UNPACK_FIELD( "output maximum","0 0 0", Vector, m_vOutputMax )
  7448. DMXELEMENT_UNPACK_FIELD( "output is scalar of initial random range","0", bool, m_bScaleInitialRange )
  7449. DMXELEMENT_UNPACK_FIELD( "output is scalar of current value","0", bool, m_bScaleCurrent )
  7450. DMXELEMENT_UNPACK_FIELD( "offset position","0", bool, m_bOffset )
  7451. DMXELEMENT_UNPACK_FIELD( "accelerate position","0", bool, m_bAccelerate )
  7452. DMXELEMENT_UNPACK_FIELD( "local space CP","-1", int, m_nLocalSpaceCP )
  7453. END_PARTICLE_OPERATOR_UNPACK( C_OP_RemapCPtoVector )
  7454. void C_OP_RemapCPtoVector::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  7455. {
  7456. Vector vecControlPoint;
  7457. pParticles->GetControlPointAtTime( m_nCPInput, pParticles->m_flCurTime, &vecControlPoint );
  7458. Vector vOutputMinLocal = m_vOutputMin;
  7459. Vector vOutputMaxLocal = m_vOutputMax;
  7460. if ( m_nLocalSpaceCP != -1 )
  7461. {
  7462. matrix3x4_t mat;
  7463. pParticles->GetControlPointTransformAtTime( m_nLocalSpaceCP, pParticles->m_flCurTime, &mat );
  7464. Vector vecTransformLocal = vec3_origin;
  7465. VectorRotate( vOutputMinLocal, mat, vecTransformLocal );
  7466. vOutputMinLocal = vecTransformLocal;
  7467. VectorRotate( vOutputMaxLocal, mat, vecTransformLocal );
  7468. vOutputMaxLocal = vecTransformLocal;
  7469. }
  7470. // FIXME: SSE-ize
  7471. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  7472. {
  7473. const float *pCreationTime = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, i );
  7474. // using raw creation time to map to emitter lifespan
  7475. float flLifeTime = *pCreationTime;
  7476. // only use within start/end time frame
  7477. if ( ( ( flLifeTime < m_flStartTime ) || ( flLifeTime >= m_flEndTime ) ) && ( ( m_flStartTime != -1.0f) && ( m_flEndTime != -1.0f) ) )
  7478. continue;
  7479. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, i );
  7480. Vector vOutput;
  7481. vOutput.x = RemapValClamped( vecControlPoint.x, m_vInputMin.x, m_vInputMax.x, vOutputMinLocal.x, vOutputMaxLocal.x );
  7482. vOutput.y = RemapValClamped( vecControlPoint.y, m_vInputMin.y, m_vInputMax.y, vOutputMinLocal.y, vOutputMaxLocal.y );
  7483. vOutput.z = RemapValClamped( vecControlPoint.z, m_vInputMin.z, m_vInputMax.z, vOutputMinLocal.z, vOutputMaxLocal.z );
  7484. if ( m_bScaleInitialRange )
  7485. {
  7486. Vector vOrgValue;
  7487. const float *pInput = pParticles->GetInitialFloatAttributePtr( m_nFieldOutput, i );
  7488. SetVectorFromAttribute ( vOrgValue, pInput );
  7489. vOutput *= vOrgValue;
  7490. }
  7491. if ( m_bScaleCurrent )
  7492. {
  7493. vOutput *= *pOutput;
  7494. }
  7495. if ( ATTRIBUTES_WHICH_ARE_COLOR_AND_OPACITY & ( 1 << m_nFieldOutput ) )
  7496. {
  7497. pOutput[0] = MAX( 0.0f, MIN( vOutput.x, 1.0f) );
  7498. pOutput[4] = MAX( 0.0f, MIN( vOutput.y, 1.0f) );
  7499. pOutput[8] = MAX( 0.0f, MIN( vOutput.z, 1.0f) );
  7500. }
  7501. else
  7502. {
  7503. float *pXYZ_Prev = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  7504. Vector vXYZPrev;
  7505. if ( m_bAccelerate )
  7506. {
  7507. if ( m_bOffset )
  7508. {
  7509. Vector vOrgValue;
  7510. SetVectorFromAttribute ( vOrgValue, pOutput );
  7511. SetVectorFromAttribute ( vXYZPrev, pXYZ_Prev );
  7512. vOutput += vOrgValue;
  7513. vXYZPrev += vOutput;
  7514. vOutput += vOutput * pParticles->m_flDt;
  7515. SetVectorAttribute ( pOutput, vOutput );
  7516. SetVectorAttribute ( pXYZ_Prev, vXYZPrev );
  7517. }
  7518. else
  7519. {
  7520. vOutput *= pParticles->m_flDt;
  7521. SetVectorAttribute ( pOutput, vOutput );
  7522. }
  7523. }
  7524. else
  7525. {
  7526. vXYZPrev = vOutput;
  7527. if ( m_bOffset )
  7528. {
  7529. Vector vOrgValue;
  7530. SetVectorFromAttribute ( vOrgValue, pOutput );
  7531. SetVectorFromAttribute ( vXYZPrev, pXYZ_Prev );
  7532. vOutput += vOrgValue;
  7533. vXYZPrev += vOutput;
  7534. }
  7535. SetVectorAttribute ( pOutput, vOutput );
  7536. SetVectorAttribute ( pXYZ_Prev, vXYZPrev );
  7537. }
  7538. }
  7539. }
  7540. }
  7541. class C_OP_RemapVelocityToVector : public CParticleOperatorInstance
  7542. {
  7543. DECLARE_PARTICLE_OPERATOR( C_OP_RemapVelocityToVector );
  7544. uint32 GetWrittenAttributes( void ) const
  7545. {
  7546. return 1 << m_nFieldOutput;
  7547. }
  7548. uint32 GetReadAttributes( void ) const
  7549. {
  7550. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ;
  7551. }
  7552. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  7553. int m_nFieldOutput;
  7554. float m_flScale;
  7555. bool m_bNormalize;
  7556. };
  7557. DEFINE_PARTICLE_OPERATOR( C_OP_RemapVelocityToVector, "Remap Velocity to Vector", OPERATOR_GENERIC );
  7558. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RemapVelocityToVector )
  7559. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "0", int, m_nFieldOutput, "intchoice particlefield_vector" )
  7560. DMXELEMENT_UNPACK_FIELD( "normalize","0", bool, m_bNormalize )
  7561. DMXELEMENT_UNPACK_FIELD( "scale factor" , "1", float, m_flScale )
  7562. END_PARTICLE_OPERATOR_UNPACK( C_OP_RemapVelocityToVector )
  7563. void C_OP_RemapVelocityToVector::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  7564. {
  7565. C4VAttributeIterator prev_xyz( PARTICLE_ATTRIBUTE_PREV_XYZ, pParticles );
  7566. C4VAttributeIterator xyz( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  7567. C4VAttributeWriteIterator pOutField( m_nFieldOutput, pParticles) ;
  7568. int nCtr = pParticles->m_nPaddedActiveParticles;
  7569. if ( m_bNormalize )
  7570. {
  7571. fltx4 fl4Scale = ReplicateX4( m_flScale );
  7572. do
  7573. {
  7574. FourVectors v4Vel = *xyz;
  7575. v4Vel -= *prev_xyz;
  7576. v4Vel.VectorNormalize();
  7577. v4Vel *= fl4Scale;
  7578. *pOutField = v4Vel;
  7579. ++pOutField;
  7580. ++xyz;
  7581. ++prev_xyz;
  7582. } while( --nCtr );
  7583. }
  7584. else
  7585. {
  7586. fltx4 fl4Scale = ReplicateX4( m_flScale * 1.0 / ( MAX( 1.0e-20, pParticles->m_flPreviousDt ) ) );
  7587. do
  7588. {
  7589. FourVectors v4Vel = *xyz;
  7590. v4Vel -= *prev_xyz;
  7591. v4Vel *= fl4Scale;
  7592. *pOutField = v4Vel;
  7593. ++pOutField;
  7594. ++xyz;
  7595. ++prev_xyz;
  7596. } while( --nCtr );
  7597. }
  7598. }
  7599. class C_OP_RemapCPVelocityToVector : public CParticleOperatorInstance
  7600. {
  7601. DECLARE_PARTICLE_OPERATOR( C_OP_RemapCPVelocityToVector );
  7602. uint32 GetWrittenAttributes( void ) const
  7603. {
  7604. return 1 << m_nFieldOutput;
  7605. }
  7606. uint32 GetReadAttributes( void ) const
  7607. {
  7608. return 0;
  7609. }
  7610. virtual uint64 GetReadControlPointMask() const
  7611. {
  7612. return 1ULL << m_nControlPoint;
  7613. }
  7614. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  7615. int m_nControlPoint;
  7616. int m_nFieldOutput;
  7617. float m_flScale;
  7618. bool m_bNormalize;
  7619. };
  7620. DEFINE_PARTICLE_OPERATOR( C_OP_RemapCPVelocityToVector, "Remap CP Velocity to Vector", OPERATOR_GENERIC );
  7621. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RemapCPVelocityToVector )
  7622. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "0", int, m_nFieldOutput, "intchoice particlefield_vector" )
  7623. DMXELEMENT_UNPACK_FIELD( "control point","0", int, m_nControlPoint )
  7624. DMXELEMENT_UNPACK_FIELD( "normalize","0", bool, m_bNormalize )
  7625. DMXELEMENT_UNPACK_FIELD( "scale factor" , "1", float, m_flScale )
  7626. END_PARTICLE_OPERATOR_UNPACK( C_OP_RemapCPVelocityToVector )
  7627. void C_OP_RemapCPVelocityToVector::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  7628. {
  7629. Vector vecCPPos = pParticles->GetControlPointAtCurrentTime( m_nControlPoint );
  7630. Vector vecCPPrevPos;
  7631. pParticles->GetControlPointAtPrevTime( m_nControlPoint, &vecCPPrevPos );
  7632. Vector vecDelta = vecCPPos - vecCPPrevPos;
  7633. if ( m_bNormalize )
  7634. {
  7635. vecDelta.NormalizeInPlace();
  7636. vecDelta *= m_flScale;
  7637. }
  7638. else
  7639. {
  7640. vecDelta *= m_flScale * 1.0 / ( MAX( 1.0e-20, pParticles->m_flPreviousDt ) );
  7641. }
  7642. FourVectors v4Vel;
  7643. v4Vel.DuplicateVector( vecDelta );
  7644. C4VAttributeWriteIterator pOutField( m_nFieldOutput, pParticles) ;
  7645. int nCtr = pParticles->m_nPaddedActiveParticles;
  7646. do
  7647. {
  7648. *pOutField = v4Vel;
  7649. ++pOutField;
  7650. } while( --nCtr );
  7651. }
  7652. class C_OP_SetCPOrientationToDirection : public CParticleOperatorInstance
  7653. {
  7654. DECLARE_PARTICLE_OPERATOR( C_OP_SetCPOrientationToDirection );
  7655. uint32 GetWrittenAttributes( void ) const
  7656. {
  7657. return 0;
  7658. }
  7659. uint32 GetReadAttributes( void ) const
  7660. {
  7661. return 0;
  7662. }
  7663. virtual uint64 GetReadControlPointMask() const
  7664. {
  7665. return ( 1ULL << m_nInputControlPoint ) | ( 1ULL << m_nOutputControlPoint );
  7666. }
  7667. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  7668. int m_nInputControlPoint;
  7669. int m_nOutputControlPoint;
  7670. };
  7671. DEFINE_PARTICLE_OPERATOR( C_OP_SetCPOrientationToDirection, "Set CP Orientation to CP Direction", OPERATOR_GENERIC );
  7672. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_SetCPOrientationToDirection )
  7673. DMXELEMENT_UNPACK_FIELD( "input control point","0", int, m_nInputControlPoint )
  7674. DMXELEMENT_UNPACK_FIELD( "output control point","0", int, m_nOutputControlPoint )
  7675. END_PARTICLE_OPERATOR_UNPACK( C_OP_SetCPOrientationToDirection )
  7676. void C_OP_SetCPOrientationToDirection::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  7677. {
  7678. Vector vecCPPos = pParticles->GetControlPointAtCurrentTime( m_nInputControlPoint );
  7679. Vector vecCPPrevPos;
  7680. pParticles->GetControlPointAtPrevTime( m_nInputControlPoint, &vecCPPrevPos );
  7681. Vector vecFwd = vecCPPos - vecCPPrevPos;
  7682. vecFwd.NormalizeInPlace();
  7683. Vector vecRight, vecUp;
  7684. VectorVectors( vecFwd, vecRight, vecUp );
  7685. pParticles->SetControlPointOrientation( m_nOutputControlPoint, vecFwd, vecRight, vecUp );
  7686. }
  7687. class C_OP_RemapDirectionToCPToVector : public CParticleOperatorInstance
  7688. {
  7689. DECLARE_PARTICLE_OPERATOR( C_OP_RemapDirectionToCPToVector );
  7690. uint32 GetWrittenAttributes( void ) const
  7691. {
  7692. return 1 << m_nFieldOutput;
  7693. }
  7694. uint32 GetReadAttributes( void ) const
  7695. {
  7696. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ;
  7697. }
  7698. virtual uint64 GetReadControlPointMask() const
  7699. {
  7700. return ( 1ULL << m_nCP );
  7701. }
  7702. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  7703. int m_nCP;
  7704. int m_nFieldOutput;
  7705. float m_flScale;
  7706. float m_flOffsetRot;
  7707. Vector m_vecOffsetAxis;
  7708. bool m_bNormalize;
  7709. };
  7710. DEFINE_PARTICLE_OPERATOR( C_OP_RemapDirectionToCPToVector, "Remap Direction to CP to Vector", OPERATOR_GENERIC );
  7711. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RemapDirectionToCPToVector )
  7712. DMXELEMENT_UNPACK_FIELD( "control point","0", int, m_nCP )
  7713. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "0", int, m_nFieldOutput, "intchoice particlefield_vector" )
  7714. DMXELEMENT_UNPACK_FIELD( "normalize","0", bool, m_bNormalize )
  7715. DMXELEMENT_UNPACK_FIELD( "offset axis","0 0 0", Vector, m_vecOffsetAxis )
  7716. DMXELEMENT_UNPACK_FIELD( "offset rotation","0", float, m_flOffsetRot )
  7717. DMXELEMENT_UNPACK_FIELD( "scale factor" , "1", float, m_flScale )
  7718. END_PARTICLE_OPERATOR_UNPACK( C_OP_RemapDirectionToCPToVector )
  7719. void C_OP_RemapDirectionToCPToVector::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  7720. {
  7721. C4VAttributeIterator xyz( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  7722. C4VAttributeWriteIterator pOutField( m_nFieldOutput, pParticles) ;
  7723. int nCtr = pParticles->m_nPaddedActiveParticles;
  7724. FourVectors v4CPPosition;
  7725. FourVectors v4Offset;
  7726. matrix3x4_t matRot;
  7727. MatrixBuildRotationAboutAxis ( m_vecOffsetAxis, m_flOffsetRot, matRot );
  7728. v4CPPosition.DuplicateVector( pParticles->GetControlPointAtCurrentTime( m_nCP ) );
  7729. if ( m_bNormalize )
  7730. {
  7731. fltx4 fl4Scale = ReplicateX4( m_flScale );
  7732. do
  7733. {
  7734. FourVectors v4Vel = *xyz;
  7735. v4Vel -= v4CPPosition;
  7736. v4Vel.RotateBy( matRot );
  7737. v4Vel.VectorNormalize();
  7738. v4Vel *= fl4Scale;
  7739. *pOutField = v4Vel;
  7740. ++pOutField;
  7741. ++xyz;
  7742. } while( --nCtr );
  7743. }
  7744. else
  7745. {
  7746. fltx4 fl4Scale = ReplicateX4( m_flScale * 1.0 / ( MAX( 1.0e-20, pParticles->m_flPreviousDt ) ) );
  7747. do
  7748. {
  7749. FourVectors v4Vel = *xyz;
  7750. v4Vel -= v4CPPosition;
  7751. v4Vel += v4Offset;
  7752. v4Vel.RotateBy( matRot );
  7753. v4Vel *= fl4Scale;
  7754. *pOutField = v4Vel;
  7755. ++pOutField;
  7756. ++xyz;
  7757. } while( --nCtr );
  7758. }
  7759. }
  7760. class C_OP_NormalizeVector : public CParticleOperatorInstance
  7761. {
  7762. DECLARE_PARTICLE_OPERATOR( C_OP_NormalizeVector );
  7763. uint32 GetWrittenAttributes( void ) const
  7764. {
  7765. return 1 << m_nFieldOutput;
  7766. }
  7767. uint32 GetReadAttributes( void ) const
  7768. {
  7769. return 1 << m_nFieldOutput;
  7770. }
  7771. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  7772. int m_nFieldOutput;
  7773. float m_flScale;
  7774. };
  7775. DEFINE_PARTICLE_OPERATOR( C_OP_NormalizeVector, "Normalize Vector", OPERATOR_GENERIC );
  7776. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_NormalizeVector )
  7777. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "0", int, m_nFieldOutput, "intchoice particlefield_vector" )
  7778. DMXELEMENT_UNPACK_FIELD( "scale factor" , "1", float, m_flScale )
  7779. END_PARTICLE_OPERATOR_UNPACK( C_OP_NormalizeVector )
  7780. void C_OP_NormalizeVector::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  7781. {
  7782. C4VAttributeWriteIterator pOutField( m_nFieldOutput, pParticles) ;
  7783. int nCtr = pParticles->m_nPaddedActiveParticles;
  7784. fltx4 fl4Scale = ReplicateX4( m_flScale );
  7785. do
  7786. {
  7787. FourVectors v4Val = *pOutField;
  7788. v4Val.VectorNormalize();
  7789. v4Val *= fl4Scale;
  7790. *pOutField = v4Val;
  7791. ++pOutField;
  7792. } while( --nCtr );
  7793. }
  7794. class C_OP_RemapControlPointDirectionToVector : public CParticleOperatorInstance
  7795. {
  7796. DECLARE_PARTICLE_OPERATOR( C_OP_RemapControlPointDirectionToVector );
  7797. uint32 GetWrittenAttributes( void ) const
  7798. {
  7799. return 1 << m_nFieldOutput;
  7800. }
  7801. uint32 GetReadAttributes( void ) const
  7802. {
  7803. return 0;
  7804. }
  7805. virtual uint64 GetReadControlPointMask() const
  7806. {
  7807. return 1ULL << m_nControlPointNumber;
  7808. }
  7809. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  7810. int m_nFieldOutput;
  7811. float m_flScale;
  7812. int m_nControlPointNumber;
  7813. };
  7814. DEFINE_PARTICLE_OPERATOR( C_OP_RemapControlPointDirectionToVector, "Remap Control Point Direction to Vector", OPERATOR_GENERIC );
  7815. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RemapControlPointDirectionToVector )
  7816. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "0", int, m_nFieldOutput, "intchoice particlefield_vector" )
  7817. DMXELEMENT_UNPACK_FIELD( "control point number", "0", int, m_nControlPointNumber )
  7818. DMXELEMENT_UNPACK_FIELD( "scale factor" , "1", float, m_flScale )
  7819. END_PARTICLE_OPERATOR_UNPACK( C_OP_RemapControlPointDirectionToVector )
  7820. void C_OP_RemapControlPointDirectionToVector::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  7821. {
  7822. C4VAttributeWriteIterator pOutField( m_nFieldOutput, pParticles) ;
  7823. int nCtr = pParticles->m_nPaddedActiveParticles;
  7824. Vector vecFwd, vecRight, vecUp;
  7825. pParticles->GetControlPointOrientationAtCurrentTime( m_nControlPointNumber, &vecFwd, &vecRight, &vecUp );
  7826. vecFwd *= m_flScale;
  7827. FourVectors v4Out;
  7828. v4Out.DuplicateVector( vecFwd );
  7829. do
  7830. {
  7831. *pOutField = v4Out;
  7832. ++pOutField;
  7833. } while( --nCtr );
  7834. }
  7835. void AddBuiltInParticleOperators( void )
  7836. {
  7837. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_BasicMovement );
  7838. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_Decay );
  7839. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_DecayMaintainCount );
  7840. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_VelocityDecay );
  7841. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_AlphaDecay );
  7842. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_FadeAndKill );
  7843. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_FadeAndKillForTracers );
  7844. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_FadeIn );
  7845. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_FadeInSimple );
  7846. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_FadeOut );
  7847. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_FadeOutSimple );
  7848. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_Spin );
  7849. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_SpinUpdate );
  7850. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_SpinYaw );
  7851. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_OrientTo2dDirection );
  7852. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_Orient2DRelToCP );
  7853. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_InterpolateRadius );
  7854. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_ColorInterpolate );
  7855. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_OscillateScalar );
  7856. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_OscillateScalarSimple );
  7857. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_OscillateVector );
  7858. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_OscillateVectorSimple );
  7859. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_DampenToCP );
  7860. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_PositionLock );
  7861. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_LockToBone );
  7862. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_DistanceBetweenCPs );
  7863. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_DistanceBetweenCPsToCP );
  7864. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_PercentageBetweenCPs );
  7865. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_PercentageBetweenCPsVector );
  7866. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_DistanceToCP );
  7867. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_SetControlPointToPlayer );
  7868. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_SetControlPointToCenter );
  7869. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_SetChildControlPoints );
  7870. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_SetControlPointsToParticle );
  7871. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_SetControlPointPositions );
  7872. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_SetControlPointToImpactPoint );
  7873. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_CPOffsetToPercentageBetweenCPs );
  7874. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_PlaneCull );
  7875. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_ModelCull );
  7876. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_Cull );
  7877. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_DistanceCull );
  7878. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_ControlpointLight );
  7879. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_RemapScalar );
  7880. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_RemapSpeed );
  7881. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_RemapSpeedtoCP );
  7882. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_Noise );
  7883. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_VectorNoise );
  7884. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_VelocityMatchingForce );
  7885. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_MaxVelocity );
  7886. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_MaintainSequentialPath );
  7887. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_MovementMaintainOffset );
  7888. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_MovementPlaceOnGround );
  7889. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_RemapDotProductToScalar );
  7890. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_RemapCPtoScalar );
  7891. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_RemapCPtoVector );
  7892. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_RemapDirectionToCPToVector );
  7893. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_RemapModelVolumetoCP );
  7894. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_RemapBoundingVolumetoCP );
  7895. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_RemapVelocityToVector );
  7896. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_RemapCPVelocityToVector );
  7897. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_RemapControlPointDirectionToVector );
  7898. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_RemapAverageScalarValuetoCP );
  7899. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_DifferencePreviousParticle );
  7900. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_RampScalarLinear );
  7901. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_RampScalarSpline );
  7902. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_RampScalarSplineSimple );
  7903. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_RampScalarLinearSimple );
  7904. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_NormalLock );
  7905. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_NormalizeVector );
  7906. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_RotateVector );
  7907. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_SetControlPointRotation );
  7908. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_SetCPOrientationToDirection );
  7909. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_StopAfterCPDuration );
  7910. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_RestartAfterDuration );
  7911. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_MoveToHitbox );
  7912. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_ClampScalar );
  7913. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_ClampVector );
  7914. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_RadiusDecay );
  7915. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_LockToSavedSequentialPath );
  7916. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_SetPerChildControlPoint );
  7917. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_LerpVector );
  7918. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_LerpScalar );
  7919. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_LerpEndCapScalar );
  7920. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_LerpEndCapVector );
  7921. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_InheritFromParentParticles );
  7922. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_LagCompensation );
  7923. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_MovementRotateParticleAroundAxis );
  7924. }