Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4584 lines
158 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: particle system code
  4. //
  5. //===========================================================================//
  6. #include "tier0/platform.h"
  7. #include "particles/particles.h"
  8. #include "filesystem.h"
  9. #include "tier2/tier2.h"
  10. #include "tier2/fileutils.h"
  11. #include "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-max(0.f,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 flStrengthOp;
  123. CParticleOperatorInstance *pOp = pParticles->m_pDef->m_ForceGenerators[i];
  124. if ( pParticles->CheckIfOperatorShouldRun( pOp, &flStrengthOp ))
  125. {
  126. START_OP;
  127. pParticles->m_pDef->m_ForceGenerators[i]->AddForces(
  128. PerParticleForceAccumulator,
  129. pParticles,
  130. nblocks,
  131. flStrengthOp,
  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. accFactorX = MulSIMD( pAccIn->x, DtSquared );
  152. accFactorY = MulSIMD( pAccIn->y, DtSquared );
  153. 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]->IsFinalConstraint();
  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. if ( ( !bFinalConstraint[i] ) && ( pParticles->CheckIfOperatorShouldRun( pOp ) ) )
  194. {
  195. START_OP;
  196. bool bDidSomething = pOp->EnforceConstraint(
  197. 0, pParticles->m_nPaddedActiveParticles, pParticles,
  198. pParticles->m_pOperatorContextData +
  199. pParticles->m_pDef->m_nConstraintsCtxOffsets[i],
  200. pParticles->m_nActiveParticles );
  201. END_OP;
  202. CHECKSYSTEM( pParticles );
  203. if ( bDidSomething )
  204. {
  205. // other constraints now not satisfied, maybe
  206. for( int j=0; j<nConstraints; j++)
  207. {
  208. if ( i != j )
  209. {
  210. bConstraintSatisfied[ j ] = false;
  211. }
  212. }
  213. }
  214. }
  215. }
  216. }
  217. // pParticles->m_nOperatorRandomSampleOffset = nSaveOffset;
  218. }
  219. // now, run final constraints
  220. for(int i=0;i<nConstraints; i++)
  221. {
  222. CParticleOperatorInstance *pOp = pParticles->m_pDef->m_Constraints[i];
  223. if ( ( bFinalConstraint[i] ) &&
  224. ( pParticles->CheckIfOperatorShouldRun(
  225. pOp ) ) )
  226. {
  227. START_OP;
  228. pOp->EnforceConstraint(
  229. 0, pParticles->m_nPaddedActiveParticles, pParticles,
  230. pParticles->m_pOperatorContextData +
  231. pParticles->m_pDef->m_nConstraintsCtxOffsets[i],
  232. pParticles->m_nActiveParticles );
  233. END_OP;
  234. CHECKSYSTEM( pParticles );
  235. }
  236. }
  237. }
  238. CHECKSYSTEM( pParticles );
  239. }
  240. //-----------------------------------------------------------------------------
  241. // Fade and kill operator
  242. //-----------------------------------------------------------------------------
  243. class C_OP_FadeAndKill : public CParticleOperatorInstance
  244. {
  245. DECLARE_PARTICLE_OPERATOR( C_OP_FadeAndKill );
  246. uint32 GetWrittenAttributes( void ) const
  247. {
  248. return PARTICLE_ATTRIBUTE_ALPHA_MASK;
  249. }
  250. uint32 GetReadAttributes( void ) const
  251. {
  252. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK;
  253. }
  254. uint32 GetReadInitialAttributes( void ) const
  255. {
  256. return PARTICLE_ATTRIBUTE_ALPHA_MASK;
  257. }
  258. virtual void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement );
  259. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  260. float m_flStartFadeInTime;
  261. float m_flEndFadeInTime;
  262. float m_flStartFadeOutTime;
  263. float m_flEndFadeOutTime;
  264. float m_flStartAlpha;
  265. float m_flEndAlpha;
  266. };
  267. DEFINE_PARTICLE_OPERATOR( C_OP_FadeAndKill, "Alpha Fade and Decay", OPERATOR_GENERIC );
  268. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_FadeAndKill )
  269. DMXELEMENT_UNPACK_FIELD( "start_alpha","1", float, m_flStartAlpha )
  270. DMXELEMENT_UNPACK_FIELD( "end_alpha","0", float, m_flEndAlpha )
  271. DMXELEMENT_UNPACK_FIELD( "start_fade_in_time","0", float, m_flStartFadeInTime )
  272. DMXELEMENT_UNPACK_FIELD( "end_fade_in_time","0.5", float, m_flEndFadeInTime )
  273. DMXELEMENT_UNPACK_FIELD( "start_fade_out_time","0.5", float, m_flStartFadeOutTime )
  274. DMXELEMENT_UNPACK_FIELD( "end_fade_out_time","1", float, m_flEndFadeOutTime )
  275. END_PARTICLE_OPERATOR_UNPACK( C_OP_FadeAndKill )
  276. void C_OP_FadeAndKill::InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  277. {
  278. // Cache off and validate values
  279. if ( m_flEndFadeInTime < m_flStartFadeInTime )
  280. {
  281. m_flEndFadeInTime = m_flStartFadeInTime;
  282. }
  283. if ( m_flEndFadeOutTime < m_flStartFadeOutTime )
  284. {
  285. m_flEndFadeOutTime = m_flStartFadeOutTime;
  286. }
  287. if ( m_flStartFadeOutTime < m_flStartFadeInTime )
  288. {
  289. V_swap( m_flStartFadeInTime, m_flStartFadeOutTime );
  290. }
  291. if ( m_flEndFadeOutTime < m_flEndFadeInTime )
  292. {
  293. V_swap( m_flEndFadeInTime, m_flEndFadeOutTime );
  294. }
  295. }
  296. void C_OP_FadeAndKill::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  297. {
  298. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  299. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  300. CM128InitialAttributeIterator pInitialAlpha( PARTICLE_ATTRIBUTE_ALPHA, pParticles );
  301. CM128AttributeWriteIterator pAlpha( PARTICLE_ATTRIBUTE_ALPHA, pParticles );
  302. fltx4 fl4StartFadeInTime = ReplicateX4( m_flStartFadeInTime );
  303. fltx4 fl4StartFadeOutTime = ReplicateX4( m_flStartFadeOutTime );
  304. fltx4 fl4EndFadeInTime = ReplicateX4( m_flEndFadeInTime );
  305. fltx4 fl4EndFadeOutTime = ReplicateX4( m_flEndFadeOutTime );
  306. fltx4 fl4EndAlpha = ReplicateX4( m_flEndAlpha );
  307. fltx4 fl4StartAlpha = ReplicateX4( m_flStartAlpha );
  308. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  309. int nLimit = pParticles->m_nPaddedActiveParticles << 2;
  310. fltx4 fl4FadeInDuration = ReplicateX4( m_flEndFadeInTime - m_flStartFadeInTime );
  311. fltx4 fl4OOFadeInDuration = ReciprocalEstSIMD( fl4FadeInDuration );
  312. fltx4 fl4FadeOutDuration = ReplicateX4( m_flEndFadeOutTime - m_flStartFadeOutTime );
  313. fltx4 fl4OOFadeOutDuration = ReciprocalEstSIMD( fl4FadeOutDuration );
  314. for ( int i = 0; i < nLimit; i+= 4 )
  315. {
  316. fltx4 fl4Age = SubSIMD( fl4CurTime, *pCreationTime );
  317. fltx4 fl4ParticleLifeTime = *pLifeDuration;
  318. fltx4 fl4KillMask = CmpGeSIMD( fl4Age, *pLifeDuration ); // takes care of lifeduration = 0 div 0
  319. fl4Age = MulSIMD( fl4Age, ReciprocalEstSIMD( fl4ParticleLifeTime ) ); // age 0..1
  320. fltx4 fl4FadingInMask = AndNotSIMD( fl4KillMask,
  321. AndSIMD(
  322. CmpLeSIMD( fl4StartFadeInTime, fl4Age ), CmpGtSIMD(fl4EndFadeInTime, fl4Age ) ) );
  323. fltx4 fl4FadingOutMask = AndNotSIMD( fl4KillMask,
  324. AndSIMD(
  325. CmpLeSIMD( fl4StartFadeOutTime, fl4Age ), CmpGtSIMD(fl4EndFadeOutTime, fl4Age ) ) );
  326. if ( IsAnyNegative( fl4FadingInMask ) )
  327. {
  328. fltx4 fl4Goal = MulSIMD( *pInitialAlpha, fl4StartAlpha );
  329. fltx4 fl4NewAlpha = SimpleSplineRemapValWithDeltasClamped( fl4Age, fl4StartFadeInTime, fl4FadeInDuration, fl4OOFadeInDuration,
  330. fl4Goal, SubSIMD( *pInitialAlpha, fl4Goal ) );
  331. *pAlpha = MaskedAssign( fl4FadingInMask, fl4NewAlpha, *pAlpha );
  332. }
  333. if ( IsAnyNegative( fl4FadingOutMask ) )
  334. {
  335. fltx4 fl4Goal = MulSIMD( *pInitialAlpha, fl4EndAlpha );
  336. fltx4 fl4NewAlpha = SimpleSplineRemapValWithDeltasClamped( fl4Age, fl4StartFadeOutTime, fl4FadeOutDuration, fl4OOFadeOutDuration,
  337. *pInitialAlpha, SubSIMD( fl4Goal, *pInitialAlpha ) );
  338. *pAlpha = MaskedAssign( fl4FadingOutMask, fl4NewAlpha, *pAlpha );
  339. }
  340. if ( IsAnyNegative( fl4KillMask ) )
  341. {
  342. int nMask = TestSignSIMD( fl4KillMask );
  343. if ( nMask & 1 )
  344. pParticles->KillParticle( i );
  345. if ( nMask & 2 )
  346. pParticles->KillParticle( i + 1 );
  347. if ( nMask & 4 )
  348. pParticles->KillParticle( i + 2 );
  349. if ( nMask & 8 )
  350. pParticles->KillParticle( i + 3 );
  351. }
  352. ++pCreationTime;
  353. ++pLifeDuration;
  354. ++pInitialAlpha;
  355. ++pAlpha;
  356. }
  357. }
  358. //-----------------------------------------------------------------------------
  359. // Fade In Operator
  360. //-----------------------------------------------------------------------------
  361. class C_OP_FadeIn : public CParticleOperatorInstance
  362. {
  363. DECLARE_PARTICLE_OPERATOR( C_OP_FadeIn );
  364. uint32 GetWrittenAttributes( void ) const
  365. {
  366. return PARTICLE_ATTRIBUTE_ALPHA_MASK;
  367. }
  368. uint32 GetReadAttributes( void ) const
  369. {
  370. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK | PARTICLE_ATTRIBUTE_PARTICLE_ID_MASK;
  371. }
  372. uint32 GetReadInitialAttributes( void ) const
  373. {
  374. return PARTICLE_ATTRIBUTE_ALPHA_MASK;
  375. }
  376. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  377. float m_flFadeInTimeMin;
  378. float m_flFadeInTimeMax;
  379. float m_flFadeInTimeExp;
  380. bool m_bProportional;
  381. };
  382. DEFINE_PARTICLE_OPERATOR( C_OP_FadeIn, "Alpha Fade In Random", OPERATOR_GENERIC );
  383. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_FadeIn )
  384. DMXELEMENT_UNPACK_FIELD( "fade in time min",".25", float, m_flFadeInTimeMin )
  385. DMXELEMENT_UNPACK_FIELD( "fade in time max",".25", float, m_flFadeInTimeMax )
  386. DMXELEMENT_UNPACK_FIELD( "fade in time exponent","1", float, m_flFadeInTimeExp )
  387. DMXELEMENT_UNPACK_FIELD( "proportional 0/1","1", bool, m_bProportional )
  388. END_PARTICLE_OPERATOR_UNPACK( C_OP_FadeIn )
  389. void C_OP_FadeIn::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  390. {
  391. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  392. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  393. CM128InitialAttributeIterator pInitialAlpha( PARTICLE_ATTRIBUTE_ALPHA, pParticles );
  394. CM128AttributeWriteIterator pAlpha( PARTICLE_ATTRIBUTE_ALPHA, pParticles );
  395. C4IAttributeIterator pParticleID( PARTICLE_ATTRIBUTE_PARTICLE_ID, pParticles );
  396. int nRandomOffset = pParticles->OperatorRandomSampleOffset();
  397. fltx4 CurTime = pParticles->m_fl4CurTime;
  398. int nCtr = pParticles->m_nPaddedActiveParticles;
  399. int nSSEFixedExponent = m_flFadeInTimeExp*4.0;
  400. fltx4 FadeTimeMin = ReplicateX4( m_flFadeInTimeMin );
  401. fltx4 FadeTimeWidth = ReplicateX4( m_flFadeInTimeMax - m_flFadeInTimeMin );
  402. do
  403. {
  404. fltx4 FadeInTime= Pow_FixedPoint_Exponent_SIMD(
  405. pParticles->RandomFloat( *pParticleID, nRandomOffset ),
  406. nSSEFixedExponent);
  407. FadeInTime = AddSIMD( FadeTimeMin, MulSIMD( FadeTimeWidth, FadeInTime ) );
  408. // Find our life percentage
  409. fltx4 flLifeTime = SubSIMD( CurTime, *pCreationTime );
  410. if ( m_bProportional )
  411. {
  412. flLifeTime =
  413. MaxSIMD( Four_Zeros,
  414. MinSIMD( Four_Ones,
  415. MulSIMD( flLifeTime, ReciprocalEstSIMD( *pLifeDuration ) ) ) );
  416. }
  417. fltx4 ApplyMask = CmpGtSIMD( FadeInTime, flLifeTime );
  418. if ( IsAnyNegative( ApplyMask ) )
  419. {
  420. // Fading in
  421. fltx4 NewAlpha =
  422. SimpleSplineRemapValWithDeltasClamped(
  423. flLifeTime, Four_Zeros,
  424. FadeInTime, ReciprocalEstSIMD( FadeInTime ),
  425. Four_Zeros, *pInitialAlpha );
  426. *( pAlpha ) = MaskedAssign( ApplyMask, NewAlpha, *( pAlpha ) );
  427. }
  428. ++pCreationTime;
  429. ++pLifeDuration;
  430. ++pInitialAlpha;
  431. ++pAlpha;
  432. ++pParticleID;
  433. } while( --nCtr );
  434. }
  435. //-----------------------------------------------------------------------------
  436. // Fade Out Operator
  437. //-----------------------------------------------------------------------------
  438. class C_OP_FadeOut : public CParticleOperatorInstance
  439. {
  440. DECLARE_PARTICLE_OPERATOR( C_OP_FadeOut );
  441. uint32 GetWrittenAttributes( void ) const
  442. {
  443. return PARTICLE_ATTRIBUTE_ALPHA_MASK;
  444. }
  445. uint32 GetReadAttributes( void ) const
  446. {
  447. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK | PARTICLE_ATTRIBUTE_PARTICLE_ID_MASK;
  448. }
  449. uint32 GetReadInitialAttributes( void ) const
  450. {
  451. return PARTICLE_ATTRIBUTE_ALPHA_MASK;
  452. }
  453. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  454. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  455. {
  456. float flBias = ( m_flFadeBias != 0.0f ) ? m_flFadeBias : 0.5f;
  457. m_fl4BiasParam = PreCalcBiasParameter( ReplicateX4( flBias ) );
  458. if ( m_flFadeOutTimeMin == 0.0f && m_flFadeOutTimeMax == 0.0f )
  459. {
  460. m_flFadeOutTimeMin = m_flFadeOutTimeMax = FLT_EPSILON;
  461. }
  462. }
  463. float m_flFadeOutTimeMin;
  464. float m_flFadeOutTimeMax;
  465. float m_flFadeOutTimeExp;
  466. float m_flFadeBias;
  467. fltx4 m_fl4BiasParam;
  468. bool m_bProportional;
  469. bool m_bEaseInAndOut;
  470. };
  471. DEFINE_PARTICLE_OPERATOR( C_OP_FadeOut, "Alpha Fade Out Random", OPERATOR_GENERIC );
  472. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_FadeOut )
  473. DMXELEMENT_UNPACK_FIELD( "fade out time min",".25", float, m_flFadeOutTimeMin )
  474. DMXELEMENT_UNPACK_FIELD( "fade out time max",".25", float, m_flFadeOutTimeMax )
  475. DMXELEMENT_UNPACK_FIELD( "fade out time exponent","1", float, m_flFadeOutTimeExp )
  476. DMXELEMENT_UNPACK_FIELD( "proportional 0/1","1", bool, m_bProportional )
  477. DMXELEMENT_UNPACK_FIELD( "ease in and out","1", bool, m_bEaseInAndOut )
  478. DMXELEMENT_UNPACK_FIELD( "fade bias", "0.5", float, m_flFadeBias )
  479. END_PARTICLE_OPERATOR_UNPACK( C_OP_FadeOut )
  480. void C_OP_FadeOut::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  481. {
  482. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  483. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  484. CM128InitialAttributeIterator pInitialAlpha( PARTICLE_ATTRIBUTE_ALPHA, pParticles );
  485. CM128AttributeWriteIterator pAlpha( PARTICLE_ATTRIBUTE_ALPHA, pParticles );
  486. C4IAttributeIterator pParticleID( PARTICLE_ATTRIBUTE_PARTICLE_ID, pParticles );
  487. int nRandomOffset = pParticles->OperatorRandomSampleOffset();
  488. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  489. int nCtr = pParticles->m_nPaddedActiveParticles;
  490. int nSSEFixedExponent = m_flFadeOutTimeExp*4.0;
  491. fltx4 FadeTimeMin = ReplicateX4( m_flFadeOutTimeMin );
  492. fltx4 FadeTimeWidth = ReplicateX4( m_flFadeOutTimeMax - m_flFadeOutTimeMin );
  493. do
  494. {
  495. fltx4 fl4FadeOutTime = Pow_FixedPoint_Exponent_SIMD(
  496. pParticles->RandomFloat( *pParticleID, nRandomOffset ),
  497. nSSEFixedExponent );
  498. fl4FadeOutTime = AddSIMD( FadeTimeMin, MulSIMD( FadeTimeWidth, fl4FadeOutTime ) );
  499. fltx4 fl4Lifespan;
  500. // Find our life percentage
  501. fltx4 fl4LifeTime = SubSIMD( fl4CurTime, *pCreationTime );
  502. fltx4 fl4LifeDuration = *pLifeDuration;
  503. if ( m_bProportional )
  504. {
  505. fl4LifeTime = MulSIMD( fl4LifeTime, ReciprocalEstSIMD( fl4LifeDuration ) );
  506. fl4FadeOutTime = SubSIMD( Four_Ones, fl4FadeOutTime );
  507. fl4Lifespan = SubSIMD ( Four_Ones, fl4FadeOutTime );
  508. }
  509. else
  510. {
  511. fl4FadeOutTime = SubSIMD( *pLifeDuration, fl4FadeOutTime );
  512. fl4Lifespan = SubSIMD( *pLifeDuration, fl4FadeOutTime ) ;
  513. }
  514. fltx4 ApplyMask = CmpLtSIMD( fl4FadeOutTime, fl4LifeTime );
  515. if ( IsAnyNegative( ApplyMask ) )
  516. {
  517. // Fading out
  518. fltx4 NewAlpha;
  519. if ( m_bEaseInAndOut )
  520. {
  521. NewAlpha = SimpleSplineRemapValWithDeltasClamped(
  522. fl4LifeTime, fl4FadeOutTime,
  523. fl4Lifespan, ReciprocalEstSIMD( fl4Lifespan ),
  524. *pInitialAlpha, SubSIMD ( Four_Zeros, *pInitialAlpha ) );
  525. NewAlpha = MaxSIMD( Four_Zeros, NewAlpha );
  526. }
  527. else
  528. {
  529. fltx4 fl4Frac = MulSIMD( SubSIMD( fl4LifeTime, fl4FadeOutTime ), ReciprocalEstSIMD( fl4Lifespan ) );
  530. fl4Frac = MinSIMD( Four_Ones, MaxSIMD( Four_Zeros, fl4Frac ) );
  531. fl4Frac = BiasSIMD( fl4Frac, m_fl4BiasParam );
  532. fl4Frac = SubSIMD( Four_Ones, fl4Frac );
  533. NewAlpha = MulSIMD( *pInitialAlpha, fl4Frac );
  534. }
  535. *( pAlpha ) = MaskedAssign( ApplyMask, NewAlpha, *( pAlpha ) );
  536. }
  537. ++pCreationTime;
  538. ++pLifeDuration;
  539. ++pInitialAlpha;
  540. ++pAlpha;
  541. ++pParticleID;
  542. } while( --nCtr );
  543. }
  544. //-----------------------------------------------------------------------------
  545. // Oscillating Scalar operator
  546. // performs an oscillation operation on any scalar (fade, radius, etc.)
  547. //-----------------------------------------------------------------------------
  548. class C_OP_OscillateScalar : public CParticleOperatorInstance
  549. {
  550. DECLARE_PARTICLE_OPERATOR( C_OP_OscillateScalar );
  551. uint32 GetWrittenAttributes( void ) const
  552. {
  553. return 1 << m_nField;
  554. }
  555. uint32 GetReadAttributes( void ) const
  556. {
  557. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK |
  558. PARTICLE_ATTRIBUTE_PARTICLE_ID_MASK;
  559. }
  560. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  561. float m_RateMin;
  562. float m_RateMax;
  563. float m_FrequencyMin;
  564. float m_FrequencyMax;
  565. int m_nField;
  566. bool m_bProportional, m_bProportionalOp;
  567. float m_flStartTime_min;
  568. float m_flStartTime_max;
  569. float m_flEndTime_min;
  570. float m_flEndTime_max;
  571. float m_flOscMult;
  572. float m_flOscAdd;
  573. };
  574. DEFINE_PARTICLE_OPERATOR( C_OP_OscillateScalar, "Oscillate Scalar", OPERATOR_GENERIC );
  575. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_OscillateScalar )
  576. DMXELEMENT_UNPACK_FIELD_USERDATA( "oscillation field", "7", int, m_nField, "intchoice particlefield_scalar" )
  577. DMXELEMENT_UNPACK_FIELD( "oscillation rate min", "0", float, m_RateMin )
  578. DMXELEMENT_UNPACK_FIELD( "oscillation rate max", "0", float, m_RateMax )
  579. DMXELEMENT_UNPACK_FIELD( "oscillation frequency min", "1", float, m_FrequencyMin )
  580. DMXELEMENT_UNPACK_FIELD( "oscillation frequency max", "1", float, m_FrequencyMax )
  581. DMXELEMENT_UNPACK_FIELD( "proportional 0/1", "1", bool, m_bProportional )
  582. DMXELEMENT_UNPACK_FIELD( "start time min", "0", float, m_flStartTime_min )
  583. DMXELEMENT_UNPACK_FIELD( "start time max", "0", float, m_flStartTime_max )
  584. DMXELEMENT_UNPACK_FIELD( "end time min", "1", float, m_flEndTime_min )
  585. DMXELEMENT_UNPACK_FIELD( "end time max", "1", float, m_flEndTime_max )
  586. DMXELEMENT_UNPACK_FIELD( "start/end proportional", "1", bool, m_bProportionalOp )
  587. DMXELEMENT_UNPACK_FIELD( "oscillation multiplier", "2", float, m_flOscMult )
  588. DMXELEMENT_UNPACK_FIELD( "oscillation start phase", ".5", float, m_flOscAdd )
  589. END_PARTICLE_OPERATOR_UNPACK( C_OP_OscillateScalar )
  590. void C_OP_OscillateScalar::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  591. {
  592. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  593. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  594. C4IAttributeIterator pParticleId ( PARTICLE_ATTRIBUTE_PARTICLE_ID, pParticles );
  595. CM128AttributeWriteIterator pOscField ( m_nField, pParticles) ;
  596. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  597. int nRandomOffset = pParticles->OperatorRandomSampleOffset();
  598. fltx4 fl4OscVal;
  599. fltx4 fl4ScaleFactor = ReplicateX4( flStrength * pParticles->m_flDt );
  600. fltx4 fl4CosFactorMultiplier = ReplicateX4( m_flOscMult );
  601. fltx4 fl4CosFactorAdd = ReplicateX4( m_flOscAdd );
  602. fltx4 fl4CosFactor = AddSIMD( MulSIMD( fl4CosFactorMultiplier, fl4CurTime ), fl4CosFactorAdd );
  603. fltx4 fl4CosFactorProp = fl4CosFactorMultiplier;
  604. fltx4 fl4StartTimeMin = ReplicateX4( m_flStartTime_min );
  605. fltx4 fl4StartTimeWidth = ReplicateX4( m_flStartTime_max - m_flStartTime_min );
  606. fltx4 fl4EndTimeMin = ReplicateX4( m_flEndTime_min );
  607. fltx4 fl4EndTimeWidth = ReplicateX4( m_flEndTime_max - m_flEndTime_min );
  608. fltx4 fl4FrequencyMin = ReplicateX4( m_FrequencyMin );
  609. fltx4 fl4FrequencyWidth = ReplicateX4( m_FrequencyMax - m_FrequencyMin );
  610. fltx4 fl4RateMin = ReplicateX4( m_RateMin );
  611. fltx4 fl4RateWidth = ReplicateX4( m_RateMax - m_RateMin );
  612. int nCtr = pParticles->m_nPaddedActiveParticles;
  613. do
  614. {
  615. fltx4 fl4LifeDuration = *pLifeDuration;
  616. fltx4 fl4GoodMask = CmpGtSIMD( fl4LifeDuration, Four_Zeros );
  617. fltx4 fl4LifeTime;
  618. if ( m_bProportionalOp )
  619. {
  620. fl4LifeTime = MulSIMD( SubSIMD( fl4CurTime, *pCreationTime ), ReciprocalEstSIMD( fl4LifeDuration ) ); // maybe need accurate div here?
  621. }
  622. else
  623. {
  624. fl4LifeTime = SubSIMD( fl4CurTime, *pCreationTime );
  625. }
  626. fltx4 fl4StartTime= pParticles->RandomFloat( *pParticleId, nRandomOffset + 11);
  627. fl4StartTime = AddSIMD( fl4StartTimeMin, MulSIMD( fl4StartTimeWidth, fl4StartTime ) );
  628. fltx4 fl4EndTime= pParticles->RandomFloat( *pParticleId, nRandomOffset + 12);
  629. fl4EndTime = AddSIMD( fl4EndTimeMin, MulSIMD( fl4EndTimeWidth, fl4EndTime ) );
  630. fl4GoodMask = AndSIMD( fl4GoodMask, CmpGeSIMD( fl4LifeTime, fl4StartTime ) );
  631. fl4GoodMask = AndSIMD( fl4GoodMask, CmpLtSIMD( fl4LifeTime, fl4EndTime ) );
  632. if ( IsAnyNegative( fl4GoodMask ) )
  633. {
  634. fltx4 fl4Frequency = pParticles->RandomFloat( *pParticleId, nRandomOffset );
  635. fl4Frequency = AddSIMD( fl4FrequencyMin, MulSIMD( fl4FrequencyWidth, fl4Frequency ) );
  636. fltx4 fl4Rate= pParticles->RandomFloat( *pParticleId, nRandomOffset + 1);
  637. fl4Rate = AddSIMD( fl4RateMin, MulSIMD( fl4RateWidth, fl4Rate ) );
  638. fltx4 fl4Cos;
  639. if ( m_bProportional )
  640. {
  641. fl4LifeTime = MulSIMD( SubSIMD( fl4CurTime, *pCreationTime ), ReciprocalEstSIMD( fl4LifeDuration ) );
  642. fl4Cos = AddSIMD( MulSIMD( fl4CosFactorProp, MulSIMD( fl4LifeTime, fl4Frequency )), fl4CosFactorAdd );
  643. }
  644. else
  645. {
  646. fl4Cos = MulSIMD( fl4CosFactor, fl4Frequency );
  647. }
  648. fltx4 fl4OscMultiplier = MulSIMD( fl4Rate, fl4ScaleFactor);
  649. fl4OscVal = AddSIMD ( *pOscField, MulSIMD ( fl4OscMultiplier, SinEst01SIMD( fl4Cos ) ) );
  650. if ( m_nField == 7)
  651. {
  652. *pOscField = MaskedAssign( fl4GoodMask,
  653. MaxSIMD( MinSIMD( fl4OscVal, Four_Ones), Four_Zeros ), *pOscField );
  654. }
  655. else
  656. {
  657. *pOscField = MaskedAssign( fl4GoodMask, fl4OscVal, *pOscField );
  658. }
  659. }
  660. ++pCreationTime;
  661. ++pLifeDuration;
  662. ++pOscField;
  663. ++pParticleId;
  664. } while (--nCtr );
  665. };
  666. //-----------------------------------------------------------------------------
  667. // Oscillating Vector operator
  668. // performs an oscillation operation on any vector (location, tint)
  669. //-----------------------------------------------------------------------------
  670. class C_OP_OscillateVector : public CParticleOperatorInstance
  671. {
  672. DECLARE_PARTICLE_OPERATOR( C_OP_OscillateVector );
  673. uint32 GetWrittenAttributes( void ) const
  674. {
  675. return 1 << m_nField;
  676. }
  677. uint32 GetReadAttributes( void ) const
  678. {
  679. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK |
  680. PARTICLE_ATTRIBUTE_PARTICLE_ID_MASK;
  681. }
  682. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  683. Vector m_RateMin;
  684. Vector m_RateMax;
  685. Vector m_FrequencyMin;
  686. Vector m_FrequencyMax;
  687. int m_nField;
  688. bool m_bProportional, m_bProportionalOp;
  689. bool m_bAccelerator;
  690. float m_flStartTime_min;
  691. float m_flStartTime_max;
  692. float m_flEndTime_min;
  693. float m_flEndTime_max;
  694. float m_flOscMult;
  695. float m_flOscAdd;
  696. };
  697. DEFINE_PARTICLE_OPERATOR( C_OP_OscillateVector, "Oscillate Vector", OPERATOR_GENERIC );
  698. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_OscillateVector )
  699. DMXELEMENT_UNPACK_FIELD_USERDATA( "oscillation field", "0", int, m_nField, "intchoice particlefield_vector" )
  700. DMXELEMENT_UNPACK_FIELD( "oscillation rate min", "0 0 0", Vector, m_RateMin )
  701. DMXELEMENT_UNPACK_FIELD( "oscillation rate max", "0 0 0", Vector, m_RateMax )
  702. DMXELEMENT_UNPACK_FIELD( "oscillation frequency min", "1 1 1", Vector, m_FrequencyMin )
  703. DMXELEMENT_UNPACK_FIELD( "oscillation frequency max", "1 1 1", Vector, m_FrequencyMax )
  704. DMXELEMENT_UNPACK_FIELD( "proportional 0/1", "1", bool, m_bProportional )
  705. DMXELEMENT_UNPACK_FIELD( "start time min", "0", float, m_flStartTime_min )
  706. DMXELEMENT_UNPACK_FIELD( "start time max", "0", float, m_flStartTime_max )
  707. DMXELEMENT_UNPACK_FIELD( "end time min", "1", float, m_flEndTime_min )
  708. DMXELEMENT_UNPACK_FIELD( "end time max", "1", float, m_flEndTime_max )
  709. DMXELEMENT_UNPACK_FIELD( "start/end proportional", "1", bool, m_bProportionalOp )
  710. DMXELEMENT_UNPACK_FIELD( "oscillation multiplier", "2", float, m_flOscMult )
  711. DMXELEMENT_UNPACK_FIELD( "oscillation start phase", ".5", float, m_flOscAdd )
  712. END_PARTICLE_OPERATOR_UNPACK( C_OP_OscillateVector )
  713. void C_OP_OscillateVector::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  714. {
  715. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  716. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  717. C4IAttributeIterator pParticleId ( PARTICLE_ATTRIBUTE_PARTICLE_ID, pParticles );
  718. C4VAttributeWriteIterator pOscField ( m_nField, pParticles) ;
  719. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  720. int nRandomOffset = pParticles->OperatorRandomSampleOffset();
  721. FourVectors fvOscVal;
  722. fltx4 fl4ScaleFactor = ReplicateX4( flStrength * pParticles->m_flDt );
  723. fltx4 fl4CosFactorMultiplier = ReplicateX4( m_flOscMult );
  724. fltx4 fl4CosFactorAdd = ReplicateX4( m_flOscAdd );
  725. fltx4 fl4CosFactor = AddSIMD( MulSIMD( fl4CosFactorMultiplier, fl4CurTime ), fl4CosFactorAdd );
  726. fltx4 fl4CosFactorProp = fl4CosFactorMultiplier;
  727. fltx4 fl4StartTimeMin = ReplicateX4( m_flStartTime_min );
  728. fltx4 fl4StartTimeWidth = ReplicateX4( m_flStartTime_max - m_flStartTime_min );
  729. fltx4 fl4EndTimeMin = ReplicateX4( m_flEndTime_min );
  730. fltx4 fl4EndTimeWidth = ReplicateX4( m_flEndTime_max - m_flEndTime_min );
  731. FourVectors fvFrequencyMin;
  732. fvFrequencyMin.DuplicateVector( m_FrequencyMin );
  733. FourVectors fvFrequencyWidth;
  734. fvFrequencyWidth.DuplicateVector( m_FrequencyMax - m_FrequencyMin );
  735. FourVectors fvRateMin;
  736. fvRateMin.DuplicateVector( m_RateMin );
  737. FourVectors fvRateWidth;
  738. fvRateWidth.DuplicateVector( m_RateMax - m_RateMin );
  739. int nCtr = pParticles->m_nPaddedActiveParticles;
  740. do
  741. {
  742. fltx4 fl4LifeDuration = *pLifeDuration;
  743. fltx4 fl4GoodMask = CmpGtSIMD( fl4LifeDuration, Four_Zeros );
  744. fltx4 fl4LifeTime;
  745. if ( m_bProportionalOp )
  746. {
  747. fl4LifeTime = MulSIMD( SubSIMD( fl4CurTime, *pCreationTime ), ReciprocalEstSIMD( fl4LifeDuration ) ); // maybe need accurate div here?
  748. }
  749. else
  750. {
  751. fl4LifeTime = SubSIMD( fl4CurTime, *pCreationTime );
  752. }
  753. fltx4 fl4StartTime= pParticles->RandomFloat( *pParticleId, nRandomOffset + 11);
  754. fl4StartTime = AddSIMD( fl4StartTimeMin, MulSIMD( fl4StartTimeWidth, fl4StartTime ) );
  755. fltx4 fl4EndTime= pParticles->RandomFloat( *pParticleId, nRandomOffset + 12);
  756. fl4EndTime = AddSIMD( fl4EndTimeMin, MulSIMD( fl4EndTimeWidth, fl4EndTime ) );
  757. fl4GoodMask = AndSIMD( fl4GoodMask, CmpGeSIMD( fl4LifeTime, fl4StartTime ) );
  758. fl4GoodMask = AndSIMD( fl4GoodMask, CmpLtSIMD( fl4LifeTime, fl4EndTime ) );
  759. if ( IsAnyNegative( fl4GoodMask ) )
  760. {
  761. FourVectors fvFrequency;
  762. fvFrequency.x = pParticles->RandomFloat( *pParticleId, nRandomOffset + 8 );
  763. fvFrequency.y = pParticles->RandomFloat( *pParticleId, nRandomOffset + 12 );
  764. fvFrequency.z = pParticles->RandomFloat( *pParticleId, nRandomOffset + 15 );
  765. fvFrequency.VProduct( fvFrequencyWidth );
  766. fvFrequency += fvFrequencyMin;
  767. FourVectors fvRate;
  768. fvRate.x = pParticles->RandomFloat( *pParticleId, nRandomOffset + 3);
  769. fvRate.y = pParticles->RandomFloat( *pParticleId, nRandomOffset + 7);
  770. fvRate.z = pParticles->RandomFloat( *pParticleId, nRandomOffset + 9);
  771. //fvRate = AddSIMD( fvRateMin, MulSIMD( fvRateWidth, fvRate ) );
  772. fvRate.VProduct( fvRateWidth );
  773. fvRate += fvRateMin;
  774. FourVectors fvCos;
  775. if ( m_bProportional )
  776. {
  777. fl4LifeTime = MulSIMD( SubSIMD( fl4CurTime, *pCreationTime ), ReciprocalEstSIMD( fl4LifeDuration ) );
  778. fvCos.x = AddSIMD( MulSIMD( fl4CosFactorProp, MulSIMD( fvFrequency.x, fl4LifeTime )), fl4CosFactorAdd );
  779. fvCos.y = AddSIMD( MulSIMD( fl4CosFactorProp, MulSIMD( fvFrequency.y, fl4LifeTime )), fl4CosFactorAdd );
  780. fvCos.z = AddSIMD( MulSIMD( fl4CosFactorProp, MulSIMD( fvFrequency.z, fl4LifeTime )), fl4CosFactorAdd );
  781. }
  782. else
  783. {
  784. //fvCos = MulSIMD( fl4CosFactor, fvFrequency );
  785. fvCos.x = MulSIMD( fvFrequency.x, fl4CosFactor );
  786. fvCos.y = MulSIMD( fvFrequency.y, fl4CosFactor );
  787. fvCos.z = MulSIMD( fvFrequency.z, fl4CosFactor );
  788. }
  789. FourVectors fvOscMultiplier;
  790. fvOscMultiplier.x = MulSIMD( fvRate.x, fl4ScaleFactor);
  791. fvOscMultiplier.y = MulSIMD( fvRate.y, fl4ScaleFactor);
  792. fvOscMultiplier.z = MulSIMD( fvRate.z, fl4ScaleFactor);
  793. FourVectors fvOutput = *pOscField;
  794. fvOscVal.x = AddSIMD ( fvOutput.x, MulSIMD ( fvOscMultiplier.x, SinEst01SIMD( fvCos.x ) ) );
  795. fvOscVal.y = AddSIMD ( fvOutput.y, MulSIMD ( fvOscMultiplier.y, SinEst01SIMD( fvCos.y ) ) );
  796. fvOscVal.z = AddSIMD ( fvOutput.z, MulSIMD ( fvOscMultiplier.z, SinEst01SIMD( fvCos.z ) ) );
  797. if ( m_nField == 6)
  798. {
  799. pOscField->x = MaskedAssign( fl4GoodMask,
  800. MaxSIMD( MinSIMD( fvOscVal.x, Four_Ones), Four_Zeros ), fvOutput.x );
  801. pOscField->y = MaskedAssign( fl4GoodMask,
  802. MaxSIMD( MinSIMD( fvOscVal.y, Four_Ones), Four_Zeros ), fvOutput.y );
  803. pOscField->z = MaskedAssign( fl4GoodMask,
  804. MaxSIMD( MinSIMD( fvOscVal.z, Four_Ones), Four_Zeros ), fvOutput.z );
  805. }
  806. else
  807. {
  808. pOscField->x = MaskedAssign( fl4GoodMask, fvOscVal.x, fvOutput.x );
  809. pOscField->y = MaskedAssign( fl4GoodMask, fvOscVal.y, fvOutput.y );
  810. pOscField->z = MaskedAssign( fl4GoodMask, fvOscVal.z, fvOutput.z );
  811. }
  812. }
  813. ++pCreationTime;
  814. ++pLifeDuration;
  815. ++pOscField;
  816. ++pParticleId;
  817. } while (--nCtr );
  818. };
  819. //-----------------------------------------------------------------------------
  820. // Remap Scalar Operator
  821. //-----------------------------------------------------------------------------
  822. class C_OP_RemapScalar : public CParticleOperatorInstance
  823. {
  824. DECLARE_PARTICLE_OPERATOR( C_OP_RemapScalar );
  825. uint32 GetWrittenAttributes( void ) const
  826. {
  827. return 1 << m_nFieldOutput;
  828. }
  829. uint32 GetReadAttributes( void ) const
  830. {
  831. return 1 << m_nFieldInput;
  832. }
  833. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  834. int m_nFieldInput;
  835. int m_nFieldOutput;
  836. float m_flInputMin;
  837. float m_flInputMax;
  838. float m_flOutputMin;
  839. float m_flOutputMax;
  840. };
  841. DEFINE_PARTICLE_OPERATOR( C_OP_RemapScalar, "Remap Scalar", OPERATOR_GENERIC );
  842. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RemapScalar )
  843. DMXELEMENT_UNPACK_FIELD_USERDATA( "input field", "7", int, m_nFieldInput, "intchoice particlefield_scalar" )
  844. DMXELEMENT_UNPACK_FIELD( "input minimum","0", float, m_flInputMin )
  845. DMXELEMENT_UNPACK_FIELD( "input maximum","1", float, m_flInputMax )
  846. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "3", int, m_nFieldOutput, "intchoice particlefield_scalar" )
  847. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  848. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  849. END_PARTICLE_OPERATOR_UNPACK( C_OP_RemapScalar )
  850. void C_OP_RemapScalar::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  851. {
  852. // clamp the result to 0 and 1 if it's alpha
  853. float flMin=m_flOutputMin;
  854. float flMax=m_flOutputMax;
  855. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & ( 1 << m_nFieldOutput ) )
  856. {
  857. flMin = clamp(m_flOutputMin, 0.0f, 1.0f );
  858. flMax = clamp(m_flOutputMax, 0.0f, 1.0f );
  859. }
  860. // FIXME: SSE-ize
  861. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  862. {
  863. const float *pInput = pParticles->GetFloatAttributePtr( m_nFieldInput, i );
  864. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, i );
  865. float flOutput = RemapValClamped( *pInput, m_flInputMin, m_flInputMax, flMin, flMax );
  866. *pOutput = Lerp (flStrength, *pOutput, flOutput);
  867. }
  868. }
  869. //-----------------------------------------------------------------------------
  870. // noise Operator
  871. //-----------------------------------------------------------------------------
  872. class C_OP_Noise : public CParticleOperatorInstance
  873. {
  874. DECLARE_PARTICLE_OPERATOR( C_OP_Noise );
  875. uint32 GetWrittenAttributes( void ) const
  876. {
  877. return 1 << m_nFieldOutput;
  878. }
  879. uint32 GetReadAttributes( void ) const
  880. {
  881. return PARTICLE_ATTRIBUTE_XYZ_MASK;
  882. }
  883. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  884. int m_nFieldOutput;
  885. float m_flOutputMin;
  886. float m_flOutputMax;
  887. fltx4 m_fl4NoiseScale;
  888. };
  889. DEFINE_PARTICLE_OPERATOR( C_OP_Noise, "Noise Scalar", OPERATOR_GENERIC );
  890. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_Noise )
  891. DMXELEMENT_UNPACK_FLTX4( "noise coordinate scale", "0.1", m_fl4NoiseScale)
  892. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "3", int, m_nFieldOutput, "intchoice particlefield_scalar" )
  893. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  894. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  895. END_PARTICLE_OPERATOR_UNPACK( C_OP_Noise );
  896. void C_OP_Noise::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  897. {
  898. CM128AttributeWriteIterator pAttr( m_nFieldOutput, pParticles );
  899. C4VAttributeIterator pXYZ( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  900. fltx4 CoordScale=m_fl4NoiseScale;
  901. float fMin = m_flOutputMin;
  902. float fMax = m_flOutputMax;
  903. if ( ATTRIBUTES_WHICH_ARE_ANGLES & (1 << m_nFieldOutput ) )
  904. {
  905. fMin *= ( M_PI / 180.0f );
  906. fMax *= ( M_PI / 180.0f );
  907. }
  908. // calculate coefficients. noise retuns -1..1
  909. fltx4 ValueScale=ReplicateX4( 0.5*(fMax-fMin ) );
  910. fltx4 ValueBase=ReplicateX4( fMin + 0.5*( fMax - fMin ) );
  911. int nActive = pParticles->m_nPaddedActiveParticles;
  912. do
  913. {
  914. FourVectors Coord = *pXYZ;
  915. Coord *= CoordScale;
  916. *( pAttr )=AddSIMD( ValueBase, MulSIMD( ValueScale, NoiseSIMD( Coord ) ) );
  917. ++pAttr;
  918. ++pXYZ;
  919. } while( --nActive );
  920. }
  921. //-----------------------------------------------------------------------------
  922. // vector noise Operator
  923. //-----------------------------------------------------------------------------
  924. class C_OP_VectorNoise : public CParticleOperatorInstance
  925. {
  926. DECLARE_PARTICLE_OPERATOR( C_OP_VectorNoise );
  927. uint32 GetWrittenAttributes( void ) const
  928. {
  929. return 1 << m_nFieldOutput;
  930. }
  931. uint32 GetReadAttributes( void ) const
  932. {
  933. return PARTICLE_ATTRIBUTE_XYZ_MASK;
  934. }
  935. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  936. int m_nFieldOutput;
  937. Vector m_vecOutputMin;
  938. Vector m_vecOutputMax;
  939. fltx4 m_fl4NoiseScale;
  940. };
  941. DEFINE_PARTICLE_OPERATOR( C_OP_VectorNoise, "Noise Vector", OPERATOR_GENERIC );
  942. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_VectorNoise )
  943. DMXELEMENT_UNPACK_FLTX4( "noise coordinate scale", "0.1", m_fl4NoiseScale)
  944. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "6", int, m_nFieldOutput, "intchoice particlefield_vector" )
  945. DMXELEMENT_UNPACK_FIELD( "output minimum","0 0 0", Vector, m_vecOutputMin )
  946. DMXELEMENT_UNPACK_FIELD( "output maximum","1 1 1", Vector, m_vecOutputMax )
  947. END_PARTICLE_OPERATOR_UNPACK( C_OP_VectorNoise );
  948. void C_OP_VectorNoise::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  949. {
  950. C4VAttributeWriteIterator pAttr( m_nFieldOutput, pParticles );
  951. C4VAttributeIterator pXYZ( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  952. fltx4 CoordScale = m_fl4NoiseScale;
  953. // calculate coefficients. noise retuns -1..1
  954. fltx4 ValueScaleX = ReplicateX4( 0.5*(m_vecOutputMax.x-m_vecOutputMin.x ) );
  955. fltx4 ValueBaseX = ReplicateX4(m_vecOutputMin.x+0.5*( m_vecOutputMax.x-m_vecOutputMin.x ) );
  956. fltx4 ValueScaleY = ReplicateX4( 0.5*(m_vecOutputMax.y-m_vecOutputMin.y ) );
  957. fltx4 ValueBaseY = ReplicateX4(m_vecOutputMin.y+0.5*( m_vecOutputMax.y-m_vecOutputMin.y ) );
  958. fltx4 ValueScaleZ = ReplicateX4( 0.5*(m_vecOutputMax.z-m_vecOutputMin.z ) );
  959. fltx4 ValueBaseZ = ReplicateX4(m_vecOutputMin.z+0.5*( m_vecOutputMax.z-m_vecOutputMin.z ) );
  960. FourVectors ofs_y;
  961. ofs_y.DuplicateVector( Vector( 100000.5, 300000.25, 9000000.75 ) );
  962. FourVectors ofs_z;
  963. ofs_z.DuplicateVector( Vector( 110000.25, 310000.75, 9100000.5 ) );
  964. int nActive = pParticles->m_nActiveParticles;
  965. for( int i=0; i < nActive; i+=4 )
  966. {
  967. FourVectors Coord = *pXYZ;
  968. Coord *= CoordScale;
  969. pAttr->x=AddSIMD( ValueBaseX, MulSIMD( ValueScaleX, NoiseSIMD( Coord ) ) );
  970. Coord += ofs_y;
  971. pAttr->y=AddSIMD( ValueBaseY, MulSIMD( ValueScaleY, NoiseSIMD( Coord ) ) );
  972. Coord += ofs_z;
  973. pAttr->z=AddSIMD( ValueBaseZ, MulSIMD( ValueScaleZ, NoiseSIMD( Coord ) ) );
  974. ++pAttr;
  975. ++pXYZ;
  976. }
  977. }
  978. //-----------------------------------------------------------------------------
  979. // Decay Operator (Lifespan limiter - kills dead particles)
  980. //-----------------------------------------------------------------------------
  981. class C_OP_Decay : public CParticleOperatorInstance
  982. {
  983. DECLARE_PARTICLE_OPERATOR( C_OP_Decay );
  984. uint32 GetWrittenAttributes( void ) const
  985. {
  986. return 0;
  987. }
  988. uint32 GetReadAttributes( void ) const
  989. {
  990. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK;
  991. }
  992. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  993. };
  994. DEFINE_PARTICLE_OPERATOR( C_OP_Decay, "Lifespan Decay", OPERATOR_GENERIC );
  995. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_Decay )
  996. END_PARTICLE_OPERATOR_UNPACK( C_OP_Decay )
  997. void C_OP_Decay::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  998. {
  999. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  1000. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  1001. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  1002. int nLimit = pParticles->m_nPaddedActiveParticles << 2;
  1003. for ( int i = 0; i < nLimit; i+= 4 )
  1004. {
  1005. fltx4 fl4LifeDuration = *pLifeDuration;
  1006. fltx4 fl4KillMask = CmpLeSIMD( fl4LifeDuration, Four_Zeros );
  1007. fltx4 fl4Age = SubSIMD( fl4CurTime, *pCreationTime );
  1008. fl4KillMask = OrSIMD( fl4KillMask, CmpGeSIMD( fl4Age, fl4LifeDuration ) );
  1009. if ( IsAnyNegative( fl4KillMask ) )
  1010. {
  1011. // not especially pretty - we need to kill some particles.
  1012. int nMask = TestSignSIMD( fl4KillMask );
  1013. if ( nMask & 1 )
  1014. pParticles->KillParticle( i );
  1015. if ( nMask & 2 )
  1016. pParticles->KillParticle( i + 1 );
  1017. if ( nMask & 4 )
  1018. pParticles->KillParticle( i + 2 );
  1019. if ( nMask & 8 )
  1020. pParticles->KillParticle( i + 3 );
  1021. }
  1022. ++pCreationTime;
  1023. ++pLifeDuration;
  1024. }
  1025. }
  1026. //-----------------------------------------------------------------------------
  1027. // Lifespan Minimum Velocity Decay Operator (kills particles if they cease moving)
  1028. //-----------------------------------------------------------------------------
  1029. class C_OP_VelocityDecay : public CParticleOperatorInstance
  1030. {
  1031. DECLARE_PARTICLE_OPERATOR( C_OP_VelocityDecay );
  1032. uint32 GetWrittenAttributes( void ) const
  1033. {
  1034. return 0;
  1035. }
  1036. uint32 GetReadAttributes( void ) const
  1037. {
  1038. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  1039. }
  1040. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  1041. float m_flMinVelocity;
  1042. };
  1043. DEFINE_PARTICLE_OPERATOR( C_OP_VelocityDecay, "Lifespan Minimum Velocity Decay", OPERATOR_GENERIC );
  1044. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_VelocityDecay )
  1045. DMXELEMENT_UNPACK_FIELD( "minimum velocity","1", float, m_flMinVelocity )
  1046. END_PARTICLE_OPERATOR_UNPACK( C_OP_VelocityDecay )
  1047. void C_OP_VelocityDecay::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  1048. {
  1049. fltx4 fl4MinVelocity = ReplicateX4( m_flMinVelocity );
  1050. fltx4 fl4Dt = ReplicateX4( pParticles->m_flDt );
  1051. CM128AttributeIterator pXYZ( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  1052. CM128AttributeIterator pPrevXYZ( PARTICLE_ATTRIBUTE_PREV_XYZ, pParticles );
  1053. int nLimit = pParticles->m_nPaddedActiveParticles << 2;
  1054. for ( int i = 0; i < nLimit; i+= 4 )
  1055. {
  1056. fltx4 fl4KillMask = CmpLeSIMD( DivSIMD ( SubSIMD( *pXYZ, *pPrevXYZ ), fl4Dt ), fl4MinVelocity );
  1057. if ( IsAnyNegative( fl4KillMask ) )
  1058. {
  1059. // not especially pretty - we need to kill some particles.
  1060. int nMask = TestSignSIMD( fl4KillMask );
  1061. if ( nMask & 1 )
  1062. pParticles->KillParticle( i );
  1063. if ( nMask & 2 )
  1064. pParticles->KillParticle( i + 1 );
  1065. if ( nMask & 4 )
  1066. pParticles->KillParticle( i + 2 );
  1067. if ( nMask & 8 )
  1068. pParticles->KillParticle( i + 3 );
  1069. }
  1070. ++pXYZ;
  1071. ++pPrevXYZ;
  1072. }
  1073. }
  1074. //-----------------------------------------------------------------------------
  1075. // Random Cull Operator - Randomly culls particles before their lifespan
  1076. //-----------------------------------------------------------------------------
  1077. class C_OP_Cull : public CParticleOperatorInstance
  1078. {
  1079. float m_flCullPerc;
  1080. float m_flCullStart;
  1081. float m_flCullEnd;
  1082. float m_flCullExp;
  1083. DECLARE_PARTICLE_OPERATOR( C_OP_Cull );
  1084. uint32 GetWrittenAttributes( void ) const
  1085. {
  1086. return 0;
  1087. }
  1088. uint32 GetReadAttributes( void ) const
  1089. {
  1090. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK | PARTICLE_ATTRIBUTE_PARTICLE_ID_MASK;
  1091. }
  1092. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  1093. };
  1094. DEFINE_PARTICLE_OPERATOR( C_OP_Cull, "Cull Random", OPERATOR_GENERIC );
  1095. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_Cull )
  1096. DMXELEMENT_UNPACK_FIELD( "Cull Start Time", "0", float, m_flCullStart )
  1097. DMXELEMENT_UNPACK_FIELD( "Cull End Time", "1", float, m_flCullEnd )
  1098. DMXELEMENT_UNPACK_FIELD( "Cull Time Exponent", "1", float, m_flCullExp )
  1099. DMXELEMENT_UNPACK_FIELD( "Cull Percentage", "0.5", float, m_flCullPerc )
  1100. END_PARTICLE_OPERATOR_UNPACK( C_OP_Cull )
  1101. void C_OP_Cull::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  1102. {
  1103. const float *pCreationTime;
  1104. const float *pLifeDuration;
  1105. float flLifeTime;
  1106. int nRandomOffset = pParticles->OperatorRandomSampleOffset();
  1107. // FIXME: SSE-ize
  1108. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  1109. {
  1110. pCreationTime = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, i );
  1111. pLifeDuration = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_LIFE_DURATION, i );
  1112. int nParticleId = *pParticles->GetIntAttributePtr( PARTICLE_ATTRIBUTE_PARTICLE_ID, i );
  1113. float flCullRank = pParticles->RandomFloat( nParticleId + nRandomOffset + 15, 0.0f, 1.0f);
  1114. float flCullTime = pParticles->RandomFloatExp( nParticleId + nRandomOffset + 12, m_flCullStart, m_flCullEnd, m_flCullExp );
  1115. if ( flCullRank > ( m_flCullPerc * flStrength ) )
  1116. {
  1117. continue;
  1118. }
  1119. // Find our life percentage
  1120. flLifeTime = clamp( ( pParticles->m_flCurTime - *pCreationTime ) / ( *pLifeDuration ), 0.0f, 1.0f );
  1121. if ( flLifeTime >= m_flCullStart && flLifeTime <= m_flCullEnd && flLifeTime >= flCullTime )
  1122. {
  1123. pParticles->KillParticle( i );
  1124. }
  1125. }
  1126. }
  1127. //-----------------------------------------------------------------------------
  1128. // generic spin operator
  1129. //-----------------------------------------------------------------------------
  1130. class CGeneralSpin : public CParticleOperatorInstance
  1131. {
  1132. protected:
  1133. virtual int GetAttributeToSpin( void ) const =0;
  1134. uint32 GetWrittenAttributes( void ) const
  1135. {
  1136. if ( m_nSpinRateDegrees != 0.0 )
  1137. return (1 << GetAttributeToSpin() );
  1138. return 0;
  1139. }
  1140. uint32 GetReadAttributes( void ) const
  1141. {
  1142. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK;
  1143. }
  1144. virtual void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  1145. {
  1146. m_fSpinRateRadians = (float) m_nSpinRateDegrees * ( M_PI / 180.0f );
  1147. m_fSpinRateMinRadians = (float) m_nSpinRateMinDegrees * ( M_PI / 180.0f );
  1148. }
  1149. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  1150. int m_nSpinRateDegrees;
  1151. int m_nSpinRateMinDegrees;
  1152. float m_fSpinRateRadians;
  1153. float m_fSpinRateStopTime;
  1154. float m_fSpinRateMinRadians;
  1155. };
  1156. void CGeneralSpin::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  1157. {
  1158. float fCurSpinRate = m_fSpinRateRadians * flStrength;
  1159. if ( fCurSpinRate == 0.0 )
  1160. return;
  1161. float dt = pParticles->m_flDt;
  1162. float drot = dt * fabs( fCurSpinRate * 2.0f * M_PI );
  1163. if ( m_fSpinRateStopTime == 0.0f )
  1164. {
  1165. drot = fmod( drot, (float)(2.0f * M_PI) );
  1166. }
  1167. if ( fCurSpinRate < 0.0f )
  1168. {
  1169. drot = -drot;
  1170. }
  1171. fltx4 Rot_Add = ReplicateX4( drot );
  1172. fltx4 Pi_2 = ReplicateX4( 2.0*M_PI );
  1173. fltx4 nPi_2 = ReplicateX4( -2.0*M_PI );
  1174. // FIXME: This is wrong
  1175. fltx4 minSpeedRadians = ReplicateX4( dt * fabs( m_fSpinRateMinRadians * 2.0f * M_PI ) );
  1176. fltx4 now = pParticles->m_fl4CurTime;
  1177. fltx4 SpinRateStopTime = ReplicateX4( m_fSpinRateStopTime );
  1178. CM128AttributeIterator pCreationTimeStamp( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  1179. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  1180. CM128AttributeWriteIterator pRot( GetAttributeToSpin(), pParticles );
  1181. int nActive = pParticles->m_nActiveParticles;
  1182. for( int i=0; i < nActive; i+=4 )
  1183. {
  1184. // HACK: Rather than redo this, I'm simply remapping the stop time into the percentage of lifetime, rather than seconds
  1185. fltx4 LifeSpan = *pLifeDuration;
  1186. fltx4 SpinFadePerc = Four_Zeros;
  1187. fltx4 OOSpinFadeRate = Four_Zeros;
  1188. if ( m_fSpinRateStopTime )
  1189. {
  1190. SpinFadePerc = MulSIMD( LifeSpan, SpinRateStopTime );
  1191. OOSpinFadeRate = DivSIMD( Four_Ones, SpinFadePerc );
  1192. }
  1193. fltx4 Age = SubSIMD( now, *pCreationTimeStamp );
  1194. fltx4 RScale = MaxSIMD( Four_Zeros,
  1195. SubSIMD( Four_Ones, MulSIMD( Age, OOSpinFadeRate ) ) );
  1196. // Cap the rotation at a minimum speed
  1197. fltx4 deltaRot = MulSIMD( Rot_Add, RScale );
  1198. fltx4 Tooslow = CmpLeSIMD( deltaRot, minSpeedRadians );
  1199. deltaRot = OrSIMD( AndSIMD( Tooslow, minSpeedRadians ), AndNotSIMD( Tooslow, deltaRot ) );
  1200. fltx4 NewRot = AddSIMD( *pRot, deltaRot );
  1201. // now, cap at +/- 2*pi
  1202. fltx4 Toobig =CmpGeSIMD( NewRot, Pi_2 );
  1203. fltx4 Toosmall = CmpLeSIMD( NewRot, nPi_2 );
  1204. NewRot = OrSIMD( AndSIMD( Toobig, SubSIMD( NewRot, Pi_2 ) ),
  1205. AndNotSIMD( Toobig, NewRot ) );
  1206. NewRot = OrSIMD( AndSIMD( Toosmall, AddSIMD( NewRot, Pi_2 ) ),
  1207. AndNotSIMD( Toosmall, NewRot ) );
  1208. *( pRot )= NewRot;
  1209. ++pRot;
  1210. ++pCreationTimeStamp;
  1211. ++pLifeDuration;
  1212. }
  1213. }
  1214. //-----------------------------------------------------------------------------
  1215. // generic spin operator, version 2. Uses rotation_speed
  1216. //-----------------------------------------------------------------------------
  1217. class CSpinUpdateBase : public CParticleOperatorInstance
  1218. {
  1219. protected:
  1220. virtual int GetAttributeToSpin( void ) const =0;
  1221. virtual int GetSpinSpeedAttribute( void ) const =0;
  1222. uint32 GetWrittenAttributes( void ) const
  1223. {
  1224. return (1 << GetAttributeToSpin() );
  1225. }
  1226. uint32 GetReadAttributes( void ) const
  1227. {
  1228. return ( 1 << GetAttributeToSpin() ) | ( 1 << GetSpinSpeedAttribute() ) |
  1229. PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  1230. }
  1231. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  1232. };
  1233. void CSpinUpdateBase::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  1234. {
  1235. CM128AttributeIterator pCreationTimeStamp( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  1236. CM128AttributeIterator pRotationSpeed( GetSpinSpeedAttribute(), pParticles );
  1237. CM128AttributeWriteIterator pRot( GetAttributeToSpin(), pParticles );
  1238. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  1239. fltx4 fl4Dt = ReplicateX4( pParticles->m_flDt );
  1240. fltx4 fl4ScaleFactor = ReplicateX4( flStrength );
  1241. int nActive = pParticles->m_nActiveParticles;
  1242. for( int i=0; i < nActive; i += 4 )
  1243. {
  1244. fltx4 fl4SimTime = MinSIMD( fl4Dt, SubSIMD( fl4CurTime, *pCreationTimeStamp ) );
  1245. fl4SimTime = MulSIMD( fl4SimTime, fl4ScaleFactor );
  1246. *pRot = MaddSIMD( fl4SimTime, *pRotationSpeed, *pRot );
  1247. ++pRot;
  1248. ++pRotationSpeed;
  1249. ++pCreationTimeStamp;
  1250. }
  1251. }
  1252. class C_OP_Spin : public CGeneralSpin
  1253. {
  1254. DECLARE_PARTICLE_OPERATOR( C_OP_Spin );
  1255. int GetAttributeToSpin( void ) const
  1256. {
  1257. return PARTICLE_ATTRIBUTE_ROTATION;
  1258. }
  1259. };
  1260. DEFINE_PARTICLE_OPERATOR( C_OP_Spin, "Rotation Spin Roll", OPERATOR_GENERIC );
  1261. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_Spin )
  1262. DMXELEMENT_UNPACK_FIELD( "spin_rate_degrees", "0", int, m_nSpinRateDegrees )
  1263. DMXELEMENT_UNPACK_FIELD( "spin_stop_time", "0", float, m_fSpinRateStopTime )
  1264. DMXELEMENT_UNPACK_FIELD( "spin_rate_min", "0", int, m_nSpinRateMinDegrees )
  1265. END_PARTICLE_OPERATOR_UNPACK( C_OP_Spin )
  1266. class C_OP_SpinUpdate : public CSpinUpdateBase
  1267. {
  1268. DECLARE_PARTICLE_OPERATOR( C_OP_SpinUpdate );
  1269. virtual int GetAttributeToSpin( void ) const
  1270. {
  1271. return PARTICLE_ATTRIBUTE_ROTATION;
  1272. }
  1273. virtual int GetSpinSpeedAttribute( void ) const
  1274. {
  1275. return PARTICLE_ATTRIBUTE_ROTATION_SPEED;
  1276. }
  1277. };
  1278. DEFINE_PARTICLE_OPERATOR( C_OP_SpinUpdate, "Rotation Basic", OPERATOR_GENERIC );
  1279. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_SpinUpdate )
  1280. END_PARTICLE_OPERATOR_UNPACK( C_OP_SpinUpdate )
  1281. class C_OP_SpinYaw : public CGeneralSpin
  1282. {
  1283. DECLARE_PARTICLE_OPERATOR( C_OP_SpinYaw );
  1284. int GetAttributeToSpin( void ) const
  1285. {
  1286. return PARTICLE_ATTRIBUTE_YAW;
  1287. }
  1288. };
  1289. DEFINE_PARTICLE_OPERATOR( C_OP_SpinYaw, "Rotation Spin Yaw", OPERATOR_GENERIC );
  1290. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_SpinYaw )
  1291. DMXELEMENT_UNPACK_FIELD( "yaw_rate_degrees", "0", int, m_nSpinRateDegrees )
  1292. DMXELEMENT_UNPACK_FIELD( "yaw_stop_time", "0", float, m_fSpinRateStopTime )
  1293. DMXELEMENT_UNPACK_FIELD( "yaw_rate_min", "0", int, m_nSpinRateMinDegrees )
  1294. END_PARTICLE_OPERATOR_UNPACK( C_OP_SpinYaw )
  1295. //-----------------------------------------------------------------------------
  1296. // Size changing operator
  1297. //-----------------------------------------------------------------------------
  1298. class C_OP_InterpolateRadius : public CParticleOperatorInstance
  1299. {
  1300. DECLARE_PARTICLE_OPERATOR( C_OP_InterpolateRadius );
  1301. uint32 GetReadInitialAttributes( void ) const
  1302. {
  1303. return PARTICLE_ATTRIBUTE_RADIUS_MASK;
  1304. }
  1305. uint32 GetWrittenAttributes( void ) const
  1306. {
  1307. return PARTICLE_ATTRIBUTE_RADIUS_MASK;
  1308. }
  1309. uint32 GetReadAttributes( void ) const
  1310. {
  1311. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK;
  1312. }
  1313. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  1314. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  1315. {
  1316. m_flBias = ( m_flBias != 0.0f ) ? m_flBias : 0.5f;
  1317. m_fl4BiasParam = PreCalcBiasParameter( ReplicateX4( m_flBias ) );
  1318. }
  1319. float m_flStartTime;
  1320. float m_flEndTime;
  1321. float m_flStartScale;
  1322. float m_flEndScale;
  1323. bool m_bEaseInAndOut;
  1324. float m_flBias;
  1325. fltx4 m_fl4BiasParam;
  1326. };
  1327. DEFINE_PARTICLE_OPERATOR( C_OP_InterpolateRadius, "Radius Scale", OPERATOR_GENERIC );
  1328. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_InterpolateRadius )
  1329. DMXELEMENT_UNPACK_FIELD( "start_time", "0", float, m_flStartTime )
  1330. DMXELEMENT_UNPACK_FIELD( "end_time", "1", float, m_flEndTime )
  1331. DMXELEMENT_UNPACK_FIELD( "radius_start_scale", "1", float, m_flStartScale )
  1332. DMXELEMENT_UNPACK_FIELD( "radius_end_scale", "1", float, m_flEndScale )
  1333. DMXELEMENT_UNPACK_FIELD( "ease_in_and_out", "0", bool, m_bEaseInAndOut )
  1334. DMXELEMENT_UNPACK_FIELD( "scale_bias", "0.5", float, m_flBias )
  1335. END_PARTICLE_OPERATOR_UNPACK( C_OP_InterpolateRadius )
  1336. void C_OP_InterpolateRadius::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  1337. {
  1338. if ( m_flEndTime <= m_flStartTime )
  1339. return;
  1340. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  1341. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  1342. CM128AttributeWriteIterator pRadius( PARTICLE_ATTRIBUTE_RADIUS, pParticles );
  1343. CM128InitialAttributeIterator pInitialRadius( PARTICLE_ATTRIBUTE_RADIUS, pParticles );
  1344. fltx4 fl4StartTime = ReplicateX4( m_flStartTime );
  1345. fltx4 fl4EndTime = ReplicateX4( m_flEndTime );
  1346. fltx4 fl4OOTimeWidth = ReciprocalSIMD( SubSIMD( fl4EndTime, fl4StartTime ) );
  1347. fltx4 fl4ScaleWidth = ReplicateX4( m_flEndScale - m_flStartScale );
  1348. fltx4 fl4StartScale = ReplicateX4( m_flStartScale );
  1349. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  1350. int nCtr = pParticles->m_nPaddedActiveParticles;
  1351. if ( m_bEaseInAndOut )
  1352. {
  1353. do
  1354. {
  1355. fltx4 fl4LifeDuration = *pLifeDuration;
  1356. fltx4 fl4GoodMask = CmpGtSIMD( fl4LifeDuration, Four_Zeros );
  1357. fltx4 fl4LifeTime = MulSIMD( SubSIMD( fl4CurTime, *pCreationTime ), ReciprocalEstSIMD( fl4LifeDuration ) ); // maybe need accurate div here?
  1358. fl4GoodMask = AndSIMD( fl4GoodMask, CmpGeSIMD( fl4LifeTime, fl4StartTime ) );
  1359. fl4GoodMask = AndSIMD( fl4GoodMask, CmpLtSIMD( fl4LifeTime, fl4EndTime ) );
  1360. if ( IsAnyNegative( fl4GoodMask ) )
  1361. {
  1362. fltx4 fl4FadeWindow = MulSIMD( SubSIMD( fl4LifeTime, fl4StartTime ), fl4OOTimeWidth );
  1363. fl4FadeWindow = AddSIMD( fl4StartScale, MulSIMD( SimpleSpline( fl4FadeWindow ), fl4ScaleWidth ) );
  1364. // !!speed!! - can anyone really tell the diff between spline and lerp here?
  1365. *pRadius = MaskedAssign(
  1366. fl4GoodMask, MulSIMD( *pInitialRadius, fl4FadeWindow ), *pRadius );
  1367. }
  1368. ++pCreationTime;
  1369. ++pLifeDuration;
  1370. ++pRadius;
  1371. ++pInitialRadius;
  1372. } while (--nCtr );
  1373. }
  1374. else
  1375. {
  1376. if ( m_flBias == 0.5f ) // no bias case
  1377. {
  1378. do
  1379. {
  1380. fltx4 fl4LifeDuration = *pLifeDuration;
  1381. fltx4 fl4GoodMask = CmpGtSIMD( fl4LifeDuration, Four_Zeros );
  1382. fltx4 fl4LifeTime = MulSIMD( SubSIMD( fl4CurTime, *pCreationTime ), ReciprocalEstSIMD( fl4LifeDuration ) ); // maybe need accurate div here?
  1383. fl4GoodMask = AndSIMD( fl4GoodMask, CmpGeSIMD( fl4LifeTime, fl4StartTime ) );
  1384. fl4GoodMask = AndSIMD( fl4GoodMask, CmpLtSIMD( fl4LifeTime, fl4EndTime ) );
  1385. if ( IsAnyNegative( fl4GoodMask ) )
  1386. {
  1387. fltx4 fl4FadeWindow = MulSIMD( SubSIMD( fl4LifeTime, fl4StartTime ), fl4OOTimeWidth );
  1388. fl4FadeWindow = AddSIMD( fl4StartScale, MulSIMD( fl4FadeWindow, fl4ScaleWidth ) );
  1389. *pRadius = MaskedAssign( fl4GoodMask, MulSIMD( *pInitialRadius, fl4FadeWindow ), *pRadius );
  1390. }
  1391. ++pCreationTime;
  1392. ++pLifeDuration;
  1393. ++pRadius;
  1394. ++pInitialRadius;
  1395. } while (--nCtr );
  1396. }
  1397. else
  1398. {
  1399. // use rational approximation to bias
  1400. do
  1401. {
  1402. fltx4 fl4LifeDuration = *pLifeDuration;
  1403. fltx4 fl4GoodMask = CmpGtSIMD( fl4LifeDuration, Four_Zeros );
  1404. fltx4 fl4LifeTime = MulSIMD( SubSIMD( fl4CurTime, *pCreationTime ), ReciprocalEstSIMD( fl4LifeDuration ) ); // maybe need accurate div here?
  1405. fl4GoodMask = AndSIMD( fl4GoodMask, CmpGeSIMD( fl4LifeTime, fl4StartTime ) );
  1406. fl4GoodMask = AndSIMD( fl4GoodMask, CmpLtSIMD( fl4LifeTime, fl4EndTime ) );
  1407. if ( IsAnyNegative( fl4GoodMask ) )
  1408. {
  1409. fltx4 fl4FadeWindow = MulSIMD( SubSIMD( fl4LifeTime, fl4StartTime ), fl4OOTimeWidth );
  1410. #ifdef FP_EXCEPTIONS_ENABLED
  1411. // Wherever fl4GoodMask is zero we need to ensure that fl4FadeWindow is not zero
  1412. // to avoid 0/0 divides in BiasSIMD. Setting those elements to fl4EndTime
  1413. // should do the trick...
  1414. fl4FadeWindow = OrSIMD( AndSIMD( fl4GoodMask, fl4EndTime ), AndNotSIMD( fl4GoodMask, fl4EndTime ) );
  1415. #endif
  1416. fl4FadeWindow = AddSIMD( fl4StartScale, MulSIMD( BiasSIMD( fl4FadeWindow, m_fl4BiasParam ), fl4ScaleWidth ) );
  1417. *pRadius = MaskedAssign(
  1418. fl4GoodMask,
  1419. MulSIMD( *pInitialRadius, fl4FadeWindow ), *pRadius );
  1420. }
  1421. ++pCreationTime;
  1422. ++pLifeDuration;
  1423. ++pRadius;
  1424. ++pInitialRadius;
  1425. } while (--nCtr );
  1426. }
  1427. }
  1428. }
  1429. //-----------------------------------------------------------------------------
  1430. // Color Fade
  1431. //-----------------------------------------------------------------------------
  1432. class C_OP_ColorInterpolate : public CParticleOperatorInstance
  1433. {
  1434. DECLARE_PARTICLE_OPERATOR( C_OP_ColorInterpolate );
  1435. uint32 GetReadInitialAttributes( void ) const
  1436. {
  1437. return PARTICLE_ATTRIBUTE_TINT_RGB_MASK;
  1438. }
  1439. uint32 GetWrittenAttributes( void ) const
  1440. {
  1441. return PARTICLE_ATTRIBUTE_TINT_RGB_MASK;
  1442. }
  1443. uint32 GetReadAttributes( void ) const
  1444. {
  1445. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK;
  1446. }
  1447. virtual void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  1448. {
  1449. m_flColorFade[0] = m_ColorFade[0] / 255.0f;
  1450. m_flColorFade[1] = m_ColorFade[1] / 255.0f;
  1451. m_flColorFade[2] = m_ColorFade[2] / 255.0f;
  1452. }
  1453. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  1454. Color m_ColorFade;
  1455. float m_flColorFade[3];
  1456. float m_flFadeStartTime;
  1457. float m_flFadeEndTime;
  1458. bool m_bEaseInOut;
  1459. };
  1460. void C_OP_ColorInterpolate::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  1461. {
  1462. C4VAttributeWriteIterator pColor( PARTICLE_ATTRIBUTE_TINT_RGB, pParticles );
  1463. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  1464. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  1465. C4VInitialAttributeIterator pInitialColor( PARTICLE_ATTRIBUTE_TINT_RGB, pParticles );
  1466. if ( m_flFadeEndTime == m_flFadeStartTime )
  1467. return;
  1468. fltx4 ooInRange = ReplicateX4( 1.0 / ( m_flFadeEndTime - m_flFadeStartTime ) );
  1469. fltx4 curTime = pParticles->m_fl4CurTime;
  1470. fltx4 lowRange = ReplicateX4( m_flFadeStartTime );
  1471. fltx4 targetR = ReplicateX4( m_flColorFade[0] );
  1472. fltx4 targetG = ReplicateX4( m_flColorFade[1] );
  1473. fltx4 targetB = ReplicateX4( m_flColorFade[2] );
  1474. int nCtr = pParticles->m_nPaddedActiveParticles;
  1475. if ( m_bEaseInOut )
  1476. {
  1477. do
  1478. {
  1479. fltx4 goodMask = CmpGtSIMD( *pLifeDuration, Four_Zeros );
  1480. if ( IsAnyNegative( goodMask ) )
  1481. {
  1482. fltx4 flLifeTime = DivSIMD( SubSIMD( curTime, *pCreationTime ), *pLifeDuration );
  1483. fltx4 T = MulSIMD( SubSIMD( flLifeTime, lowRange ), ooInRange );
  1484. T = MinSIMD( Four_Ones, MaxSIMD( Four_Zeros, T ) );
  1485. T = SimpleSpline( T );
  1486. pColor->x = MaskedAssign( goodMask, AddSIMD( pInitialColor->x, MulSIMD( T, SubSIMD( targetR, pInitialColor->x ) ) ), pColor->x );
  1487. pColor->y = MaskedAssign( goodMask, AddSIMD( pInitialColor->y, MulSIMD( T, SubSIMD( targetG, pInitialColor->y ) ) ), pColor->y );
  1488. pColor->z = MaskedAssign( goodMask, AddSIMD( pInitialColor->z, MulSIMD( T, SubSIMD( targetB, pInitialColor->z ) ) ), pColor->z );
  1489. }
  1490. ++pColor;
  1491. ++pCreationTime;
  1492. ++pLifeDuration;
  1493. ++pInitialColor;
  1494. } while( --nCtr );
  1495. }
  1496. else
  1497. {
  1498. do
  1499. {
  1500. fltx4 goodMask = CmpGtSIMD( *pLifeDuration, Four_Zeros );
  1501. if ( IsAnyNegative( goodMask ) )
  1502. {
  1503. fltx4 flLifeTime = DivSIMD( SubSIMD( curTime, *pCreationTime ), *pLifeDuration );
  1504. fltx4 T = MulSIMD( SubSIMD( flLifeTime, lowRange ), ooInRange );
  1505. T = MinSIMD( Four_Ones, MaxSIMD( Four_Zeros, T ) );
  1506. pColor->x = MaskedAssign( goodMask, AddSIMD( pInitialColor->x, MulSIMD( T, SubSIMD( targetR, pInitialColor->x ) ) ), pColor->x );
  1507. pColor->y = MaskedAssign( goodMask, AddSIMD( pInitialColor->y, MulSIMD( T, SubSIMD( targetG, pInitialColor->y ) ) ), pColor->y );
  1508. pColor->z = MaskedAssign( goodMask, AddSIMD( pInitialColor->z, MulSIMD( T, SubSIMD( targetB, pInitialColor->z ) ) ), pColor->z );
  1509. }
  1510. ++pColor;
  1511. ++pCreationTime;
  1512. ++pLifeDuration;
  1513. ++pInitialColor;
  1514. } while( --nCtr );
  1515. }
  1516. }
  1517. DEFINE_PARTICLE_OPERATOR( C_OP_ColorInterpolate, "Color Fade", OPERATOR_GENERIC );
  1518. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_ColorInterpolate )
  1519. DMXELEMENT_UNPACK_FIELD( "color_fade", "255 255 255 255", Color, m_ColorFade )
  1520. DMXELEMENT_UNPACK_FIELD( "fade_start_time", "0", float, m_flFadeStartTime )
  1521. DMXELEMENT_UNPACK_FIELD( "fade_end_time", "1", float, m_flFadeEndTime )
  1522. DMXELEMENT_UNPACK_FIELD( "ease_in_and_out", "1", bool, m_bEaseInOut )
  1523. END_PARTICLE_OPERATOR_UNPACK( C_OP_ColorInterpolate )
  1524. //-----------------------------------------------------------------------------
  1525. // Position Lock to Control Point
  1526. // Locks all particles to the specified control point
  1527. // Useful for making particles move with their emitter and so forth
  1528. //-----------------------------------------------------------------------------
  1529. class C_OP_PositionLock : public CParticleOperatorInstance
  1530. {
  1531. DECLARE_PARTICLE_OPERATOR( C_OP_PositionLock );
  1532. struct C_OP_PositionLockContext_t
  1533. {
  1534. Vector m_vPrevPosition;
  1535. matrix3x4_t m_matPrevTransform;
  1536. };
  1537. int m_nControlPointNumber;
  1538. Vector m_vPrevPosition;
  1539. float m_flStartTime_min;
  1540. float m_flStartTime_max;
  1541. float m_flStartTime_exp;
  1542. float m_flEndTime_min;
  1543. float m_flEndTime_max;
  1544. float m_flEndTime_exp;
  1545. float m_flRange;
  1546. bool m_bLockRot;
  1547. uint32 GetWrittenAttributes( void ) const
  1548. {
  1549. return PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_XYZ_MASK;
  1550. }
  1551. uint32 GetReadAttributes( void ) const
  1552. {
  1553. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK |
  1554. PARTICLE_ATTRIBUTE_PARTICLE_ID_MASK;
  1555. }
  1556. virtual uint64 GetReadControlPointMask() const
  1557. {
  1558. return 1ULL << m_nControlPointNumber;
  1559. }
  1560. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  1561. {
  1562. m_nControlPointNumber = max( 0, min( MAX_PARTICLE_CONTROL_POINTS-1, m_nControlPointNumber ) );
  1563. }
  1564. size_t GetRequiredContextBytes( void ) const
  1565. {
  1566. return sizeof( C_OP_PositionLockContext_t );
  1567. }
  1568. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  1569. {
  1570. C_OP_PositionLockContext_t *pCtx=reinterpret_cast<C_OP_PositionLockContext_t *>( pContext );
  1571. pCtx->m_vPrevPosition = vec3_origin;
  1572. pParticles->GetControlPointTransformAtTime( m_nControlPointNumber, pParticles->m_flCurTime, &pCtx->m_matPrevTransform );
  1573. }
  1574. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  1575. };
  1576. DEFINE_PARTICLE_OPERATOR( C_OP_PositionLock , "Movement Lock to Control Point", OPERATOR_GENERIC );
  1577. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_PositionLock )
  1578. DMXELEMENT_UNPACK_FIELD( "control_point_number", "0", int, m_nControlPointNumber )
  1579. DMXELEMENT_UNPACK_FIELD( "start_fadeout_min", "1", float, m_flStartTime_min )
  1580. DMXELEMENT_UNPACK_FIELD( "start_fadeout_max", "1", float, m_flStartTime_max )
  1581. DMXELEMENT_UNPACK_FIELD( "start_fadeout_exponent", "1", float, m_flStartTime_exp )
  1582. DMXELEMENT_UNPACK_FIELD( "end_fadeout_min", "1", float, m_flEndTime_min )
  1583. DMXELEMENT_UNPACK_FIELD( "end_fadeout_max", "1", float, m_flEndTime_max )
  1584. DMXELEMENT_UNPACK_FIELD( "end_fadeout_exponent", "1", float, m_flEndTime_exp )
  1585. DMXELEMENT_UNPACK_FIELD( "distance fade range", "0", float, m_flRange )
  1586. DMXELEMENT_UNPACK_FIELD( "lock rotation", "0", bool, m_bLockRot )
  1587. END_PARTICLE_OPERATOR_UNPACK( C_OP_PositionLock )
  1588. #ifdef OLD_NON_SSE_POSLOCK_FOR_TESTING
  1589. void C_OP_PositionLock::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  1590. {
  1591. Vector vecControlPoint = pParticles->GetControlPointAtCurrentTime( m_nControlPointNumber );
  1592. // At initialization, set prevposition to the control point to prevent random placements/velocities
  1593. C_OP_PositionLockContext_t *pCtx=reinterpret_cast<C_OP_PositionLockContext_t *>( pContext );
  1594. if ( pCtx->m_vPrevPosition == Vector (0, 0, 0) )
  1595. {
  1596. pCtx->m_vPrevPosition = vecControlPoint;
  1597. }
  1598. // Control point movement delta
  1599. int nRandomOffset = pParticles->OperatorRandomSampleOffset();
  1600. // FIXME: SSE-ize
  1601. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  1602. {
  1603. Vector vecPrevCPPos = pCtx->m_vPrevPosition;
  1604. const float *pCreationTime;
  1605. const float *pLifeDuration;
  1606. pCreationTime = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, i );
  1607. pLifeDuration = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_LIFE_DURATION, i );
  1608. float flLifeTime = *pLifeDuration != 0.0f ? clamp( ( pParticles->m_flCurTime - *pCreationTime ) / ( *pLifeDuration ), 0.0f, 1.0f ) : 0.0f;
  1609. if ( *pCreationTime >= ( pParticles->m_flCurTime - pParticles->m_flDt ) )
  1610. {
  1611. pParticles->GetControlPointAtTime( m_nControlPointNumber, *pCreationTime, &vecPrevCPPos );
  1612. }
  1613. Vector vDelta = vecControlPoint - vecPrevCPPos;
  1614. vDelta *= flStrength;
  1615. // clamp activity to start/end time
  1616. int nParticleId = *pParticles->GetIntAttributePtr( PARTICLE_ATTRIBUTE_PARTICLE_ID, i );
  1617. float flStartTime = pParticles->RandomFloatExp( nParticleId + nRandomOffset + 9, m_flStartTime_min, m_flStartTime_max, m_flStartTime_exp );
  1618. float flEndTime = pParticles->RandomFloatExp( nParticleId + nRandomOffset + 10, m_flEndTime_min, m_flEndTime_max, m_flEndTime_exp );
  1619. // bias attachedness by fadeout
  1620. float flLockScale = SimpleSplineRemapValClamped( flLifeTime, flStartTime, flEndTime, 1.0f, 0.0f );
  1621. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, i );
  1622. float *xyz_prev = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  1623. Vector vecParticlePosition, vecParticlePosition_prev ;
  1624. SetVectorFromAttribute( vecParticlePosition, xyz );
  1625. SetVectorFromAttribute( vecParticlePosition_prev, xyz_prev );
  1626. float flDampenAmount = 1;
  1627. if ( m_flRange != 0 )
  1628. {
  1629. Vector ofs;
  1630. ofs = (vecParticlePosition + ( vDelta * flLockScale ) ) - vecControlPoint;
  1631. float flDistance = ofs.Length();
  1632. flDampenAmount = SimpleSplineRemapValClamped( flDistance, 0, m_flRange, 1.0f, 0.0f );
  1633. flDampenAmount = Bias( flDampenAmount, .2 );
  1634. }
  1635. Vector vParticleDelta = vDelta * flLockScale * flDampenAmount;
  1636. vecParticlePosition += vParticleDelta;
  1637. vecParticlePosition_prev += vParticleDelta;
  1638. SetVectorAttribute( xyz, vecParticlePosition );
  1639. SetVectorAttribute( xyz_prev, vecParticlePosition_prev );
  1640. }
  1641. // Store off the control point position for the next delta computation
  1642. pCtx->m_vPrevPosition = vecControlPoint;
  1643. };
  1644. #else
  1645. void C_OP_PositionLock::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  1646. {
  1647. Vector vecControlPoint = pParticles->GetControlPointAtCurrentTime( m_nControlPointNumber );
  1648. // At initialization, set prevposition to the control point to prevent random placements/velocities
  1649. C_OP_PositionLockContext_t *pCtx=reinterpret_cast<C_OP_PositionLockContext_t *>( pContext );
  1650. if ( pCtx->m_vPrevPosition == Vector (0, 0, 0) )
  1651. {
  1652. pCtx->m_vPrevPosition = vecControlPoint;
  1653. pParticles->GetControlPointTransformAtTime( m_nControlPointNumber, pParticles->m_flCurTime, &pCtx->m_matPrevTransform );
  1654. }
  1655. Vector vDelta;
  1656. matrix3x4_t matCurrentTransform;
  1657. matrix3x4_t matTransformLock;
  1658. if ( m_bLockRot )
  1659. {
  1660. pParticles->GetControlPointTransformAtTime( m_nControlPointNumber, pParticles->m_flCurTime, &matCurrentTransform );
  1661. matrix3x4_t matPrev;
  1662. //if ( MatricesAreEqual ( matCurrentTransform, pCtx->m_matPrevTransform ) )
  1663. // return;
  1664. MatrixInvert( pCtx->m_matPrevTransform, matPrev );
  1665. MatrixMultiply( matCurrentTransform, matPrev, matTransformLock);
  1666. }
  1667. int nContext = GetSIMDRandContext();
  1668. // Control point movement delta - not full transform
  1669. vDelta = vecControlPoint - pCtx->m_vPrevPosition;
  1670. //if ( vDelta == vec3_origin && !m_bLockRot )
  1671. // return;
  1672. vDelta *= flStrength;
  1673. FourVectors v4Delta;
  1674. v4Delta.DuplicateVector( vDelta );
  1675. FourVectors v4ControlPoint;
  1676. v4ControlPoint.DuplicateVector( vecControlPoint );
  1677. C4VAttributeWriteIterator pXYZ( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  1678. C4VAttributeWriteIterator pPrevXYZ( PARTICLE_ATTRIBUTE_PREV_XYZ, pParticles );
  1679. fltx4 fl4_Dt = ReplicateX4( pParticles->m_flDt );
  1680. int nCtr = pParticles->m_nPaddedActiveParticles;
  1681. bool bUseRange = ( m_flRange != 0.0 );
  1682. fltx4 fl4OORange;
  1683. if ( bUseRange )
  1684. fl4OORange = ReplicateX4( 1.0 / m_flRange );
  1685. fltx4 fl4BiasParm = PreCalcBiasParameter( ReplicateX4( 0.2 ) );
  1686. if ( m_flStartTime_min >= 1.0 ) // always locked on
  1687. {
  1688. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  1689. do
  1690. {
  1691. fltx4 fl4ParticleAge = SubSIMD( pParticles->m_fl4CurTime, *pCreationTime);
  1692. fltx4 fl4CreationFrameBias = MinSIMD( fl4ParticleAge, fl4_Dt );
  1693. fl4CreationFrameBias = MulSIMD( DivSIMD( Four_Ones, fl4_Dt ), fl4CreationFrameBias );
  1694. FourVectors v4ScaledDelta = v4Delta;
  1695. v4ScaledDelta *= fl4CreationFrameBias;
  1696. fltx4 fl4LockStrength = ReplicateX4( flStrength );
  1697. // ok, some of these particles should be moved
  1698. if ( bUseRange )
  1699. {
  1700. FourVectors ofs = *pXYZ;
  1701. ofs += v4ScaledDelta;
  1702. ofs -= v4ControlPoint;
  1703. fltx4 fl4Dist = ofs.length();
  1704. fl4Dist = BiasSIMD( MinSIMD( Four_Ones, MulSIMD( fl4Dist, fl4OORange ) ), fl4BiasParm );
  1705. v4ScaledDelta *= SubSIMD( Four_Ones, fl4Dist );
  1706. fl4LockStrength = SubSIMD( Four_Ones, MulSIMD ( fl4Dist, fl4LockStrength ) );
  1707. }
  1708. if ( m_bLockRot )
  1709. {
  1710. fl4LockStrength = MulSIMD( fl4LockStrength, fl4CreationFrameBias );
  1711. FourVectors fvCurPos = *pXYZ;
  1712. FourVectors fvPrevPos = *pPrevXYZ;
  1713. fvCurPos.TransformBy( matTransformLock );
  1714. fvPrevPos.TransformBy( matTransformLock );
  1715. fvCurPos -= *pXYZ;
  1716. fvCurPos *= fl4LockStrength;
  1717. fvPrevPos -= *pPrevXYZ;
  1718. fvPrevPos *= fl4LockStrength;
  1719. *(pXYZ) += fvCurPos;
  1720. *(pPrevXYZ) += fvPrevPos;
  1721. }
  1722. else
  1723. {
  1724. *(pXYZ) += v4ScaledDelta;
  1725. *(pPrevXYZ) += v4ScaledDelta;
  1726. }
  1727. ++pCreationTime;
  1728. ++pXYZ;
  1729. ++pPrevXYZ;
  1730. } while ( --nCtr );
  1731. }
  1732. else
  1733. {
  1734. CM128AttributeIterator pCreationTime( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  1735. CM128AttributeIterator pLifeDuration( PARTICLE_ATTRIBUTE_LIFE_DURATION, pParticles );
  1736. fltx4 fl4CurTime = pParticles->m_fl4CurTime;
  1737. fltx4 fl4StartRange = ReplicateX4( m_flStartTime_max - m_flStartTime_min );
  1738. fltx4 fl4StartBias = ReplicateX4( m_flStartTime_min );
  1739. fltx4 fl4EndRange = ReplicateX4( m_flEndTime_max - m_flEndTime_min );
  1740. fltx4 fl4EndBias = ReplicateX4( m_flEndTime_min );
  1741. int nSSEStartExponent = m_flStartTime_exp * 4.0;
  1742. int nSSEEndExponent = m_flEndTime_exp * 4.0;
  1743. do
  1744. {
  1745. fltx4 fl4LifeTime = SubSIMD( fl4CurTime, *pCreationTime );
  1746. fltx4 fl4CreationFrameBias = MinSIMD( fl4LifeTime, fl4_Dt );
  1747. fl4CreationFrameBias = MulSIMD( DivSIMD( Four_Ones, fl4_Dt ), fl4CreationFrameBias );
  1748. FourVectors v4ScaledDelta = v4Delta;
  1749. v4ScaledDelta *= fl4CreationFrameBias;
  1750. fl4LifeTime = MaxSIMD( Four_Zeros, MinSIMD( Four_Ones,
  1751. MulSIMD( fl4LifeTime, ReciprocalEstSIMD( *pLifeDuration ) ) ) );
  1752. fltx4 fl4StartTime = Pow_FixedPoint_Exponent_SIMD( RandSIMD( nContext ), nSSEStartExponent );
  1753. fl4StartTime = AddSIMD( fl4StartBias, MulSIMD( fl4StartTime, fl4StartRange ) );
  1754. fltx4 fl4EndTime = Pow_FixedPoint_Exponent_SIMD( RandSIMD( nContext ), nSSEEndExponent );
  1755. fl4EndTime = AddSIMD( fl4EndBias, MulSIMD( fl4EndTime, fl4EndRange ) );
  1756. // now, determine "lockedness"
  1757. fltx4 fl4LockScale = DivSIMD( SubSIMD( fl4LifeTime, fl4StartTime ), SubSIMD( fl4EndTime, fl4StartTime ) );
  1758. fl4LockScale = SubSIMD( Four_Ones, MaxSIMD( Four_Zeros, MinSIMD( Four_Ones, fl4LockScale ) ) );
  1759. if ( IsAnyNegative( CmpGtSIMD( fl4LockScale, Four_Zeros ) ) )
  1760. {
  1761. //fl4LockScale = MulSIMD( fl4LockScale, fl4CreationFrameBias );
  1762. v4ScaledDelta *= fl4LockScale;
  1763. fltx4 fl4LockStrength = fl4LockScale ;
  1764. // ok, some of these particles should be moved
  1765. if ( bUseRange )
  1766. {
  1767. FourVectors ofs = *pXYZ;
  1768. ofs += v4ScaledDelta;
  1769. ofs -= v4ControlPoint;
  1770. fltx4 fl4Dist = ofs.length();
  1771. fl4Dist = BiasSIMD( MinSIMD( Four_Ones, MulSIMD( fl4Dist, fl4OORange ) ), fl4BiasParm );
  1772. v4ScaledDelta *= SubSIMD( Four_Ones, fl4Dist );
  1773. fl4LockStrength = SubSIMD( Four_Ones, MulSIMD ( fl4Dist, fl4LockStrength ) );
  1774. }
  1775. if ( m_bLockRot )
  1776. {
  1777. fl4LockStrength = MulSIMD( fl4LockStrength, fl4CreationFrameBias );
  1778. FourVectors fvCurPos = *pXYZ;
  1779. FourVectors fvPrevPos = *pPrevXYZ;
  1780. fvCurPos.TransformBy( matTransformLock );
  1781. fvPrevPos.TransformBy( matTransformLock );
  1782. fvCurPos -= *pXYZ;
  1783. fvCurPos *= fl4LockStrength;
  1784. fvPrevPos -= *pPrevXYZ;
  1785. fvPrevPos *= fl4LockStrength;
  1786. *(pXYZ) += fvCurPos;
  1787. *(pPrevXYZ) += fvPrevPos;
  1788. }
  1789. else
  1790. {
  1791. *(pXYZ) += v4ScaledDelta;
  1792. *(pPrevXYZ) += v4ScaledDelta;
  1793. }
  1794. }
  1795. ++pCreationTime;
  1796. ++pLifeDuration;
  1797. ++pXYZ;
  1798. ++pPrevXYZ;
  1799. } while ( --nCtr );
  1800. }
  1801. // Store off the control point position for the next delta computation
  1802. pCtx->m_vPrevPosition = vecControlPoint;
  1803. pCtx->m_matPrevTransform = matCurrentTransform;
  1804. ReleaseSIMDRandContext( nContext );
  1805. };
  1806. #endif
  1807. //-----------------------------------------------------------------------------
  1808. // Controlpoint Light
  1809. // Determines particle color/fakes lighting using the influence of control
  1810. // points
  1811. //-----------------------------------------------------------------------------
  1812. class C_OP_ControlpointLight : public CParticleOperatorInstance
  1813. {
  1814. float m_flScale;
  1815. LightDesc_t m_LightNode1, m_LightNode2, m_LightNode3, m_LightNode4;
  1816. int m_nControlPoint1, m_nControlPoint2, m_nControlPoint3, m_nControlPoint4;
  1817. Vector m_vecCPOffset1, m_vecCPOffset2, m_vecCPOffset3, m_vecCPOffset4;
  1818. float m_LightFiftyDist1, m_LightZeroDist1, m_LightFiftyDist2, m_LightZeroDist2,
  1819. m_LightFiftyDist3, m_LightZeroDist3, m_LightFiftyDist4, m_LightZeroDist4;
  1820. Color m_LightColor1, m_LightColor2, m_LightColor3, m_LightColor4;
  1821. bool m_bLightType1, m_bLightType2, m_bLightType3, m_bLightType4, m_bLightDynamic1,
  1822. m_bLightDynamic2, m_bLightDynamic3, m_bLightDynamic4, m_bUseNormal, m_bUseHLambert,
  1823. m_bLightActive1, m_bLightActive2, m_bLightActive3, m_bLightActive4,
  1824. m_bClampLowerRange, m_bClampUpperRange;
  1825. DECLARE_PARTICLE_OPERATOR( C_OP_ControlpointLight );
  1826. uint32 GetReadInitialAttributes( void ) const
  1827. {
  1828. return PARTICLE_ATTRIBUTE_TINT_RGB_MASK;
  1829. }
  1830. uint32 GetWrittenAttributes( void ) const
  1831. {
  1832. return PARTICLE_ATTRIBUTE_TINT_RGB_MASK;
  1833. }
  1834. uint32 GetReadAttributes( void ) const
  1835. {
  1836. return PARTICLE_ATTRIBUTE_XYZ_MASK;
  1837. }
  1838. virtual uint64 GetReadControlPointMask() const
  1839. {
  1840. return ( 1ULL << m_nControlPoint1 ) | ( 1ULL << m_nControlPoint2 ) |
  1841. ( 1ULL << m_nControlPoint3 ) | ( 1ULL << m_nControlPoint4 );
  1842. }
  1843. virtual void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  1844. {
  1845. m_LightNode1.m_Color[0] = m_LightColor1[0] / 255.0f;
  1846. m_LightNode1.m_Color[1] = m_LightColor1[1] / 255.0f;
  1847. m_LightNode1.m_Color[2] = m_LightColor1[2] / 255.0f;
  1848. m_LightNode2.m_Color[0] = m_LightColor2[0] / 255.0f;
  1849. m_LightNode2.m_Color[1] = m_LightColor2[1] / 255.0f;
  1850. m_LightNode2.m_Color[2] = m_LightColor2[2] / 255.0f;
  1851. m_LightNode3.m_Color[0] = m_LightColor3[0] / 255.0f;
  1852. m_LightNode3.m_Color[1] = m_LightColor3[1] / 255.0f;
  1853. m_LightNode3.m_Color[2] = m_LightColor3[2] / 255.0f;
  1854. m_LightNode4.m_Color[0] = m_LightColor4[0] / 255.0f;
  1855. m_LightNode4.m_Color[1] = m_LightColor4[1] / 255.0f;
  1856. m_LightNode4.m_Color[2] = m_LightColor4[2] / 255.0f;
  1857. m_LightNode1.m_Range = 0;
  1858. m_LightNode2.m_Range = 0;
  1859. m_LightNode3.m_Range = 0;
  1860. m_LightNode4.m_Range = 0;
  1861. m_LightNode1.m_Falloff=5.0;
  1862. m_LightNode2.m_Falloff=5.0;
  1863. m_LightNode3.m_Falloff=5.0;
  1864. m_LightNode4.m_Falloff=5.0;
  1865. m_LightNode1.m_Attenuation0 = 0;
  1866. m_LightNode1.m_Attenuation1 = 0;
  1867. m_LightNode1.m_Attenuation2 = 1;
  1868. m_LightNode2.m_Attenuation0 = 0;
  1869. m_LightNode2.m_Attenuation1 = 0;
  1870. m_LightNode2.m_Attenuation2 = 1;
  1871. m_LightNode3.m_Attenuation0 = 0;
  1872. m_LightNode3.m_Attenuation1 = 0;
  1873. m_LightNode3.m_Attenuation2 = 1;
  1874. m_LightNode4.m_Attenuation0 = 0;
  1875. m_LightNode4.m_Attenuation1 = 0;
  1876. m_LightNode4.m_Attenuation2 = 1;
  1877. if ( !m_bLightType1 )
  1878. {
  1879. m_LightNode1.m_Type = MATERIAL_LIGHT_POINT;
  1880. }
  1881. else
  1882. {
  1883. m_LightNode1.m_Type = MATERIAL_LIGHT_SPOT;
  1884. }
  1885. if ( !m_bLightType2 )
  1886. {
  1887. m_LightNode2.m_Type = MATERIAL_LIGHT_POINT;
  1888. }
  1889. else
  1890. {
  1891. m_LightNode2.m_Type = MATERIAL_LIGHT_SPOT;
  1892. }
  1893. if ( !m_bLightType3 )
  1894. {
  1895. m_LightNode3.m_Type = MATERIAL_LIGHT_POINT;
  1896. }
  1897. else
  1898. {
  1899. m_LightNode3.m_Type = MATERIAL_LIGHT_SPOT;
  1900. }
  1901. if ( !m_bLightType4 )
  1902. {
  1903. m_LightNode4.m_Type = MATERIAL_LIGHT_POINT;
  1904. }
  1905. else
  1906. {
  1907. m_LightNode4.m_Type = MATERIAL_LIGHT_SPOT;
  1908. }
  1909. if ( !m_bLightDynamic1 && ( m_LightColor1 != Color( 0, 0, 0, 255 ) ) )
  1910. {
  1911. m_bLightActive1 = true;
  1912. }
  1913. else
  1914. {
  1915. m_bLightActive1 = false;
  1916. }
  1917. if ( !m_bLightDynamic2 && ( m_LightColor2 != Color( 0, 0, 0, 255 ) ) )
  1918. {
  1919. m_bLightActive2 = true;
  1920. }
  1921. else
  1922. {
  1923. m_bLightActive2 = false;
  1924. }
  1925. if ( !m_bLightDynamic3 && ( m_LightColor3 != Color( 0, 0, 0, 255 ) ) )
  1926. {
  1927. m_bLightActive3 = true;
  1928. }
  1929. else
  1930. {
  1931. m_bLightActive3 = false;
  1932. }
  1933. if ( !m_bLightDynamic4 && ( m_LightColor4 != Color( 0, 0, 0, 255 ) ) )
  1934. {
  1935. m_bLightActive4 = true;
  1936. }
  1937. else
  1938. {
  1939. m_bLightActive4 = false;
  1940. }
  1941. m_LightNode1.SetupNewStyleAttenuation ( m_LightFiftyDist1, m_LightZeroDist1 );
  1942. m_LightNode2.SetupNewStyleAttenuation ( m_LightFiftyDist2, m_LightZeroDist2 );
  1943. m_LightNode3.SetupNewStyleAttenuation ( m_LightFiftyDist3, m_LightZeroDist3 );
  1944. m_LightNode4.SetupNewStyleAttenuation ( m_LightFiftyDist4, m_LightZeroDist4 );
  1945. }
  1946. void Render( CParticleCollection *pParticles ) const;
  1947. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  1948. };
  1949. DEFINE_PARTICLE_OPERATOR( C_OP_ControlpointLight, "Color Light from Control Point", OPERATOR_GENERIC );
  1950. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_ControlpointLight )
  1951. DMXELEMENT_UNPACK_FIELD( "Light 1 Control Point", "0", int, m_nControlPoint1 )
  1952. DMXELEMENT_UNPACK_FIELD( "Light 1 Control Point Offset", "0 0 0", Vector, m_vecCPOffset1 )
  1953. DMXELEMENT_UNPACK_FIELD( "Light 1 Type 0=Point 1=Spot", "0", bool, m_bLightType1 )
  1954. DMXELEMENT_UNPACK_FIELD( "Light 1 Color", "0 0 0 255", Color, m_LightColor1 )
  1955. DMXELEMENT_UNPACK_FIELD( "Light 1 Dynamic Light", "0", bool, m_bLightDynamic1 )
  1956. DMXELEMENT_UNPACK_FIELD( "Light 1 Direction", "0 0 0", Vector, m_LightNode1.m_Direction )
  1957. DMXELEMENT_UNPACK_FIELD( "Light 1 50% Distance", "100", float, m_LightFiftyDist1 )
  1958. DMXELEMENT_UNPACK_FIELD( "Light 1 0% Distance", "200", float, m_LightZeroDist1 )
  1959. DMXELEMENT_UNPACK_FIELD( "Light 1 Spot Inner Cone", "30.0", float, m_LightNode1.m_Theta )
  1960. DMXELEMENT_UNPACK_FIELD( "Light 1 Spot Outer Cone", "45.0", float, m_LightNode1.m_Phi )
  1961. DMXELEMENT_UNPACK_FIELD( "Light 2 Control Point", "0", int, m_nControlPoint2 )
  1962. DMXELEMENT_UNPACK_FIELD( "Light 2 Control Point Offset", "0 0 0", Vector, m_vecCPOffset2 )
  1963. DMXELEMENT_UNPACK_FIELD( "Light 2 Type 0=Point 1=Spot", "0", bool, m_bLightType2 )
  1964. DMXELEMENT_UNPACK_FIELD( "Light 2 Color", "0 0 0 255", Color, m_LightColor2 )
  1965. DMXELEMENT_UNPACK_FIELD( "Light 2 Dynamic Light", "0", bool, m_bLightDynamic2 )
  1966. DMXELEMENT_UNPACK_FIELD( "Light 2 Direction", "0 0 0", Vector, m_LightNode2.m_Direction )
  1967. DMXELEMENT_UNPACK_FIELD( "Light 2 50% Distance", "100", float, m_LightFiftyDist2 )
  1968. DMXELEMENT_UNPACK_FIELD( "Light 2 0% Distance", "200", float, m_LightZeroDist2 )
  1969. DMXELEMENT_UNPACK_FIELD( "Light 2 Spot Inner Cone", "30.0", float, m_LightNode2.m_Theta )
  1970. DMXELEMENT_UNPACK_FIELD( "Light 2 Spot Outer Cone", "45.0", float, m_LightNode2.m_Phi )
  1971. DMXELEMENT_UNPACK_FIELD( "Light 3 Control Point", "0", int, m_nControlPoint3 )
  1972. DMXELEMENT_UNPACK_FIELD( "Light 3 Control Point Offset", "0 0 0", Vector, m_vecCPOffset3 )
  1973. DMXELEMENT_UNPACK_FIELD( "Light 3 Type 0=Point 1=Spot", "0", bool, m_bLightType3 )
  1974. DMXELEMENT_UNPACK_FIELD( "Light 3 Color", "0 0 0 255", Color, m_LightColor3 )
  1975. DMXELEMENT_UNPACK_FIELD( "Light 3 Dynamic Light", "0", bool, m_bLightDynamic3 )
  1976. DMXELEMENT_UNPACK_FIELD( "Light 3 Direction", "0 0 0", Vector, m_LightNode3.m_Direction )
  1977. DMXELEMENT_UNPACK_FIELD( "Light 3 50% Distance", "100", float, m_LightFiftyDist3 )
  1978. DMXELEMENT_UNPACK_FIELD( "Light 3 0% Distance", "200", float, m_LightZeroDist3 )
  1979. DMXELEMENT_UNPACK_FIELD( "Light 3 Spot Inner Cone", "30.0", float, m_LightNode3.m_Theta )
  1980. DMXELEMENT_UNPACK_FIELD( "Light 3 Spot Outer Cone", "45.0", float, m_LightNode3.m_Phi )
  1981. DMXELEMENT_UNPACK_FIELD( "Light 4 Control Point", "0", int, m_nControlPoint4 )
  1982. DMXELEMENT_UNPACK_FIELD( "Light 4 Control Point Offset", "0 0 0", Vector, m_vecCPOffset4 )
  1983. DMXELEMENT_UNPACK_FIELD( "Light 4 Type 0=Point 1=Spot", "0", bool, m_bLightType4 )
  1984. DMXELEMENT_UNPACK_FIELD( "Light 4 Color", "0 0 0 255", Color, m_LightColor4 )
  1985. DMXELEMENT_UNPACK_FIELD( "Light 4 Dynamic Light", "0", bool, m_bLightDynamic4 )
  1986. DMXELEMENT_UNPACK_FIELD( "Light 4 Direction", "0 0 0", Vector, m_LightNode4.m_Direction )
  1987. DMXELEMENT_UNPACK_FIELD( "Light 4 50% Distance", "100", float, m_LightFiftyDist4 )
  1988. DMXELEMENT_UNPACK_FIELD( "Light 4 0% Distance", "200", float, m_LightZeroDist4 )
  1989. DMXELEMENT_UNPACK_FIELD( "Light 4 Spot Inner Cone", "30.0", float, m_LightNode4.m_Theta )
  1990. DMXELEMENT_UNPACK_FIELD( "Light 4 Spot Outer Cone", "45.0", float, m_LightNode4.m_Phi )
  1991. DMXELEMENT_UNPACK_FIELD( "Initial Color Bias", "0.0", float, m_flScale )
  1992. DMXELEMENT_UNPACK_FIELD( "Clamp Minimum Light Value to Initial Color", "0", bool, m_bClampLowerRange )
  1993. DMXELEMENT_UNPACK_FIELD( "Clamp Maximum Light Value to Initial Color", "0", bool, m_bClampUpperRange )
  1994. DMXELEMENT_UNPACK_FIELD( "Compute Normals From Control Points", "0", bool, m_bUseNormal )
  1995. DMXELEMENT_UNPACK_FIELD( "Half-Lambert Normals", "1", bool, m_bUseHLambert )
  1996. END_PARTICLE_OPERATOR_UNPACK( C_OP_ControlpointLight )
  1997. void C_OP_ControlpointLight::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  1998. {
  1999. //Set up location of each light - this needs to be done every time as the CP's can move
  2000. Vector vecLocation1, vecLocation2, vecLocation3, vecLocation4;
  2001. vecLocation1 = pParticles->GetControlPointAtCurrentTime( m_nControlPoint1 );
  2002. vecLocation2 = pParticles->GetControlPointAtCurrentTime( m_nControlPoint2 );
  2003. vecLocation3 = pParticles->GetControlPointAtCurrentTime( m_nControlPoint3 );
  2004. vecLocation4 = pParticles->GetControlPointAtCurrentTime( m_nControlPoint4 );
  2005. LightDesc_t LightNode1 = m_LightNode1;
  2006. LightDesc_t LightNode2 = m_LightNode2;
  2007. LightDesc_t LightNode3 = m_LightNode3;
  2008. LightDesc_t LightNode4 = m_LightNode3;
  2009. // Apply any offsets
  2010. LightNode1.m_Position = vecLocation1 + m_vecCPOffset1;
  2011. LightNode2.m_Position = vecLocation2 + m_vecCPOffset2;
  2012. LightNode3.m_Position = vecLocation3 + m_vecCPOffset3;
  2013. LightNode4.m_Position = vecLocation4 + m_vecCPOffset4;
  2014. C4VAttributeIterator pInitialColor( PARTICLE_ATTRIBUTE_TINT_RGB, pParticles );
  2015. C4VAttributeWriteIterator pColor( PARTICLE_ATTRIBUTE_TINT_RGB, pParticles );
  2016. C4VAttributeIterator pXYZ( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  2017. // Set up lighting conditions and attenuation
  2018. if ( m_bLightDynamic1 )
  2019. {
  2020. // Get the color and luminosity at this position
  2021. Color lc;
  2022. g_pParticleSystemMgr->Query()->GetLightingAtPoint( LightNode1.m_Position, lc );
  2023. LightNode1.m_Color[0] = lc[0] / 255.0f;
  2024. LightNode1.m_Color[1] = lc[1] / 255.0f;
  2025. LightNode1.m_Color[2] = lc[2] / 255.0f;
  2026. }
  2027. if ( m_bLightDynamic2 )
  2028. {
  2029. // Get the color and luminosity at this position
  2030. Color lc;
  2031. g_pParticleSystemMgr->Query()->GetLightingAtPoint( LightNode2.m_Position, lc );
  2032. LightNode2.m_Color[0] = lc[0] / 255.0f;
  2033. LightNode2.m_Color[1] = lc[1] / 255.0f;
  2034. LightNode2.m_Color[2] = lc[2] / 255.0f;
  2035. }
  2036. if ( m_bLightDynamic3 )
  2037. {
  2038. // Get the color and luminosity at this position
  2039. Color lc;
  2040. g_pParticleSystemMgr->Query()->GetLightingAtPoint( LightNode3.m_Position, lc );
  2041. LightNode3.m_Color[0] = lc[0] / 255.0f;
  2042. LightNode3.m_Color[1] = lc[1] / 255.0f;
  2043. LightNode3.m_Color[2] = lc[2] / 255.0f;
  2044. }
  2045. if ( m_bLightDynamic4 )
  2046. {
  2047. // Get the color and luminosity at this position
  2048. Color lc;
  2049. g_pParticleSystemMgr->Query()->GetLightingAtPoint( LightNode4.m_Position, lc );
  2050. LightNode4.m_Color[0] = lc[0] / 255.0f;
  2051. LightNode4.m_Color[1] = lc[1] / 255.0f;
  2052. LightNode4.m_Color[2] = lc[2] / 255.0f;
  2053. }
  2054. LightNode1.RecalculateDerivedValues();
  2055. LightNode2.RecalculateDerivedValues();
  2056. LightNode3.RecalculateDerivedValues();
  2057. LightNode4.RecalculateDerivedValues();
  2058. FourVectors vScale;
  2059. vScale.DuplicateVector( Vector(m_flScale, m_flScale, m_flScale) );
  2060. if ( m_bUseNormal )
  2061. {
  2062. FourVectors vCPPosition1, vCPPosition2, vCPPosition3, vCPPosition4;
  2063. //vCPPosition1.DuplicateVector( LightNode1.m_Position );
  2064. vCPPosition1.DuplicateVector( vecLocation1 );
  2065. vCPPosition2.DuplicateVector( vecLocation2 );
  2066. vCPPosition3.DuplicateVector( vecLocation3 );
  2067. vCPPosition4.DuplicateVector( vecLocation4 );
  2068. int nCtr = pParticles->m_nPaddedActiveParticles;
  2069. do
  2070. {
  2071. FourVectors vLighting = vScale;
  2072. vLighting *= *pInitialColor;
  2073. FourVectors vNormal = *pXYZ;
  2074. vNormal -= vCPPosition1;
  2075. vNormal.VectorNormalizeFast();
  2076. LightNode1.ComputeLightAtPoints( *pXYZ, vNormal, vLighting, m_bUseHLambert );
  2077. vNormal = *pXYZ;
  2078. vNormal -= vCPPosition2;
  2079. vNormal.VectorNormalizeFast();
  2080. LightNode2.ComputeLightAtPoints( *pXYZ, vNormal, vLighting, m_bUseHLambert );
  2081. vNormal = *pXYZ;
  2082. vNormal -= vCPPosition3;
  2083. vNormal.VectorNormalizeFast();
  2084. LightNode3.ComputeLightAtPoints( *pXYZ, vNormal, vLighting, m_bUseHLambert );
  2085. vNormal = *pXYZ;
  2086. vNormal -= vCPPosition4;
  2087. vNormal.VectorNormalizeFast();
  2088. LightNode4.ComputeLightAtPoints( *pXYZ, vNormal, vLighting, m_bUseHLambert );
  2089. if ( m_bClampLowerRange )
  2090. {
  2091. FourVectors vInitialClamp = *pInitialColor;
  2092. vLighting.x = MaxSIMD( vLighting.x, vInitialClamp.x );
  2093. vLighting.y = MaxSIMD( vLighting.y, vInitialClamp.y );
  2094. vLighting.z = MaxSIMD( vLighting.z, vInitialClamp.z );
  2095. }
  2096. else
  2097. {
  2098. vLighting.x = MaxSIMD( vLighting.x, Four_Zeros );
  2099. vLighting.y = MaxSIMD( vLighting.y, Four_Zeros );
  2100. vLighting.z = MaxSIMD( vLighting.z, Four_Zeros );
  2101. }
  2102. if ( m_bClampUpperRange )
  2103. {
  2104. FourVectors vInitialClamp = *pInitialColor;
  2105. vLighting.x = MinSIMD( vLighting.x, vInitialClamp.x );
  2106. vLighting.y = MinSIMD( vLighting.y, vInitialClamp.y );
  2107. vLighting.z = MinSIMD( vLighting.z, vInitialClamp.z );
  2108. }
  2109. else
  2110. {
  2111. vLighting.x = MinSIMD( vLighting.x, Four_Ones );
  2112. vLighting.y = MinSIMD( vLighting.y, Four_Ones );
  2113. vLighting.z = MinSIMD( vLighting.z, Four_Ones );
  2114. }
  2115. *pColor = vLighting;
  2116. ++pColor;
  2117. ++pXYZ;
  2118. ++pInitialColor;
  2119. } while (--nCtr);
  2120. }
  2121. else
  2122. {
  2123. int nCtr = pParticles->m_nPaddedActiveParticles;
  2124. do
  2125. {
  2126. FourVectors vLighting = vScale;
  2127. vLighting *= *pInitialColor;
  2128. LightNode1.ComputeNonincidenceLightAtPoints( *pXYZ, vLighting );
  2129. LightNode2.ComputeNonincidenceLightAtPoints( *pXYZ, vLighting );
  2130. LightNode3.ComputeNonincidenceLightAtPoints( *pXYZ, vLighting );
  2131. LightNode4.ComputeNonincidenceLightAtPoints( *pXYZ, vLighting );
  2132. if ( m_bClampLowerRange )
  2133. {
  2134. FourVectors vInitialClamp = *pInitialColor;
  2135. vLighting.x = MaxSIMD( vLighting.x, vInitialClamp.x );
  2136. vLighting.y = MaxSIMD( vLighting.y, vInitialClamp.y );
  2137. vLighting.z = MaxSIMD( vLighting.z, vInitialClamp.z );
  2138. }
  2139. else
  2140. {
  2141. vLighting.x = MaxSIMD( vLighting.x, Four_Zeros );
  2142. vLighting.y = MaxSIMD( vLighting.y, Four_Zeros );
  2143. vLighting.z = MaxSIMD( vLighting.z, Four_Zeros );
  2144. }
  2145. if ( m_bClampUpperRange )
  2146. {
  2147. FourVectors vInitialClamp = *pInitialColor;
  2148. vLighting.x = MinSIMD( vLighting.x, vInitialClamp.x );
  2149. vLighting.y = MinSIMD( vLighting.y, vInitialClamp.y );
  2150. vLighting.z = MinSIMD( vLighting.z, vInitialClamp.z );
  2151. }
  2152. else
  2153. {
  2154. vLighting.x = MinSIMD( vLighting.x, Four_Ones );
  2155. vLighting.y = MinSIMD( vLighting.y, Four_Ones );
  2156. vLighting.z = MinSIMD( vLighting.z, Four_Ones );
  2157. }
  2158. *pColor = vLighting;
  2159. ++pColor;
  2160. ++pXYZ;
  2161. ++pInitialColor;
  2162. } while (--nCtr);
  2163. }
  2164. };
  2165. //-----------------------------------------------------------------------------
  2166. // Render visualization
  2167. //-----------------------------------------------------------------------------
  2168. void C_OP_ControlpointLight::Render( CParticleCollection *pParticles ) const
  2169. {
  2170. Vector vecOrigin1 = pParticles->GetControlPointAtCurrentTime( m_nControlPoint1 );
  2171. vecOrigin1 += m_vecCPOffset1;
  2172. Vector vecOrigin2 = pParticles->GetControlPointAtCurrentTime( m_nControlPoint2 );
  2173. vecOrigin2 += m_vecCPOffset2;
  2174. Vector vecOrigin3 = pParticles->GetControlPointAtCurrentTime( m_nControlPoint3 );
  2175. vecOrigin3 += m_vecCPOffset3;
  2176. Vector vecOrigin4 = pParticles->GetControlPointAtCurrentTime( m_nControlPoint4 );
  2177. vecOrigin4 += m_vecCPOffset4;
  2178. Color LightColor1Outer;
  2179. LightColor1Outer[0] = m_LightColor1[0] / 2.0f;
  2180. LightColor1Outer[1] = m_LightColor1[1] / 2.0f;
  2181. LightColor1Outer[2] = m_LightColor1[2] / 2.0f;
  2182. LightColor1Outer[3] = 255;
  2183. Color LightColor2Outer;
  2184. LightColor2Outer[0] = m_LightColor2[0] / 2.0f;
  2185. LightColor2Outer[1] = m_LightColor2[1] / 2.0f;
  2186. LightColor2Outer[2] = m_LightColor2[2] / 2.0f;
  2187. LightColor2Outer[3] = 255;
  2188. Color LightColor3Outer;
  2189. LightColor3Outer[0] = m_LightColor3[0] / 2.0f;
  2190. LightColor3Outer[1] = m_LightColor3[1] / 2.0f;
  2191. LightColor3Outer[2] = m_LightColor3[2] / 2.0f;
  2192. LightColor3Outer[3] = 255;
  2193. Color LightColor4Outer;
  2194. LightColor4Outer[0] = m_LightColor4[0] / 2.0f;
  2195. LightColor4Outer[1] = m_LightColor4[1] / 2.0f;
  2196. LightColor4Outer[2] = m_LightColor4[2] / 2.0f;
  2197. LightColor4Outer[3] = 255;
  2198. if ( m_bLightActive1 )
  2199. {
  2200. RenderWireframeSphere( vecOrigin1, m_LightFiftyDist1, 16, 8, m_LightColor1, false );
  2201. RenderWireframeSphere( vecOrigin1, m_LightZeroDist1, 16, 8, LightColor1Outer, false );
  2202. }
  2203. if ( m_bLightActive2 )
  2204. {
  2205. RenderWireframeSphere( vecOrigin2, m_LightFiftyDist2, 16, 8, m_LightColor2, false );
  2206. RenderWireframeSphere( vecOrigin2, m_LightZeroDist2, 16, 8, LightColor2Outer, false );
  2207. }
  2208. if ( m_bLightActive3 )
  2209. {
  2210. RenderWireframeSphere( vecOrigin3, m_LightFiftyDist3, 16, 8, m_LightColor3, false );
  2211. RenderWireframeSphere( vecOrigin3, m_LightZeroDist3, 16, 8, LightColor3Outer, false );
  2212. }
  2213. if ( m_bLightActive4 )
  2214. {
  2215. RenderWireframeSphere( vecOrigin4, m_LightFiftyDist4, 16, 8, m_LightColor4, false );
  2216. RenderWireframeSphere( vecOrigin4, m_LightZeroDist4, 16, 8, LightColor4Outer, false );
  2217. }
  2218. }
  2219. // set child controlpoints - copy the positions of our particles to the control points of a child
  2220. class C_OP_SetChildControlPoints : public CParticleOperatorInstance
  2221. {
  2222. DECLARE_PARTICLE_OPERATOR( C_OP_SetChildControlPoints );
  2223. int m_nChildGroupID;
  2224. int m_nFirstControlPoint;
  2225. int m_nNumControlPoints;
  2226. int m_nFirstSourcePoint;
  2227. uint32 GetWrittenAttributes( void ) const
  2228. {
  2229. return 0;
  2230. }
  2231. uint32 GetReadAttributes( void ) const
  2232. {
  2233. return PARTICLE_ATTRIBUTE_XYZ;
  2234. }
  2235. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  2236. };
  2237. DEFINE_PARTICLE_OPERATOR( C_OP_SetChildControlPoints, "Set child control points from particle positions", OPERATOR_GENERIC );
  2238. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_SetChildControlPoints )
  2239. DMXELEMENT_UNPACK_FIELD( "Group ID to affect", "0", int, m_nChildGroupID )
  2240. DMXELEMENT_UNPACK_FIELD( "First control point to set", "0", int, m_nFirstControlPoint )
  2241. DMXELEMENT_UNPACK_FIELD( "# of control points to set", "1", int, m_nNumControlPoints )
  2242. DMXELEMENT_UNPACK_FIELD( "first particle to copy", "0", int, m_nFirstSourcePoint )
  2243. END_PARTICLE_OPERATOR_UNPACK( C_OP_SetChildControlPoints )
  2244. void C_OP_SetChildControlPoints::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  2245. {
  2246. int nFirst=max(0, min( MAX_PARTICLE_CONTROL_POINTS-1, m_nFirstControlPoint ) );
  2247. int nToSet=min( pParticles->m_nActiveParticles-m_nFirstSourcePoint, m_nNumControlPoints );
  2248. nToSet=min( nToSet, MAX_PARTICLE_CONTROL_POINTS-nFirst );
  2249. if ( nToSet )
  2250. {
  2251. for( CParticleCollection *pChild = pParticles->m_Children.m_pHead; pChild; pChild = pChild->m_pNext )
  2252. {
  2253. if ( pChild->GetGroupID() == m_nChildGroupID )
  2254. {
  2255. for( int p=0; p < nToSet; p++ )
  2256. {
  2257. const float *pXYZ = pParticles->GetFloatAttributePtr(
  2258. PARTICLE_ATTRIBUTE_XYZ, p + m_nFirstSourcePoint );
  2259. Vector cPnt( pXYZ[0], pXYZ[4], pXYZ[8] );
  2260. pChild->SetControlPoint( p+nFirst, cPnt );
  2261. }
  2262. }
  2263. }
  2264. }
  2265. }
  2266. //-----------------------------------------------------------------------------
  2267. // Set Control Point Positions
  2268. //-----------------------------------------------------------------------------
  2269. class C_OP_SetControlPointPositions : public CParticleOperatorInstance
  2270. {
  2271. DECLARE_PARTICLE_OPERATOR( C_OP_SetControlPointPositions );
  2272. bool m_bUseWorldLocation;
  2273. int m_nCP1, m_nCP1Parent;
  2274. int m_nCP2, m_nCP2Parent;
  2275. int m_nCP3, m_nCP3Parent;
  2276. int m_nCP4, m_nCP4Parent;
  2277. Vector m_vecCP1Pos, m_vecCP2Pos, m_vecCP3Pos, m_vecCP4Pos;
  2278. int m_nHeadLocation;
  2279. uint32 GetWrittenAttributes( void ) const
  2280. {
  2281. return 0;
  2282. }
  2283. uint32 GetReadAttributes( void ) const
  2284. {
  2285. return 0;
  2286. }
  2287. bool ShouldRunBeforeEmitters( void ) const
  2288. {
  2289. return true;
  2290. }
  2291. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  2292. };
  2293. DEFINE_PARTICLE_OPERATOR( C_OP_SetControlPointPositions, "Set Control Point Positions", OPERATOR_GENERIC );
  2294. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_SetControlPointPositions )
  2295. DMXELEMENT_UNPACK_FIELD( "First Control Point Number", "1", int, m_nCP1 )
  2296. DMXELEMENT_UNPACK_FIELD( "First Control Point Parent", "0", int, m_nCP1Parent )
  2297. DMXELEMENT_UNPACK_FIELD( "First Control Point Location", "128 0 0", Vector, m_vecCP1Pos )
  2298. DMXELEMENT_UNPACK_FIELD( "Second Control Point Number", "2", int, m_nCP2 )
  2299. DMXELEMENT_UNPACK_FIELD( "Second Control Point Parent", "0", int, m_nCP2Parent )
  2300. DMXELEMENT_UNPACK_FIELD( "Second Control Point Location", "0 128 0", Vector, m_vecCP2Pos )
  2301. DMXELEMENT_UNPACK_FIELD( "Third Control Point Number", "3", int, m_nCP3 )
  2302. DMXELEMENT_UNPACK_FIELD( "Third Control Point Parent", "0", int, m_nCP3Parent )
  2303. DMXELEMENT_UNPACK_FIELD( "Third Control Point Location", "-128 0 0", Vector, m_vecCP3Pos )
  2304. DMXELEMENT_UNPACK_FIELD( "Fourth Control Point Number", "4", int, m_nCP4 )
  2305. DMXELEMENT_UNPACK_FIELD( "Fourth Control Point Parent", "0", int, m_nCP4Parent )
  2306. DMXELEMENT_UNPACK_FIELD( "Fourth Control Point Location", "0 -128 0", Vector, m_vecCP4Pos )
  2307. DMXELEMENT_UNPACK_FIELD( "Set positions in world space", "0", bool, m_bUseWorldLocation )
  2308. DMXELEMENT_UNPACK_FIELD( "Control Point to offset positions from", "0", int, m_nHeadLocation )
  2309. END_PARTICLE_OPERATOR_UNPACK( C_OP_SetControlPointPositions )
  2310. void C_OP_SetControlPointPositions::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  2311. {
  2312. if ( !m_bUseWorldLocation )
  2313. {
  2314. Vector vecControlPoint = pParticles->GetControlPointAtCurrentTime( m_nHeadLocation );
  2315. matrix3x4_t mat;
  2316. pParticles->GetControlPointTransformAtTime( m_nHeadLocation, pParticles->m_flCurTime, &mat );
  2317. Vector vecTransformLocal = vec3_origin;
  2318. VectorTransform( m_vecCP1Pos, mat, vecTransformLocal );
  2319. pParticles->SetControlPoint( m_nCP1, vecTransformLocal );
  2320. pParticles->SetControlPointParent( m_nCP1, m_nCP1Parent );
  2321. VectorTransform( m_vecCP2Pos, mat, vecTransformLocal );
  2322. pParticles->SetControlPoint( m_nCP2, vecTransformLocal );
  2323. pParticles->SetControlPointParent( m_nCP2, m_nCP2Parent );
  2324. VectorTransform( m_vecCP3Pos, mat, vecTransformLocal );
  2325. pParticles->SetControlPoint( m_nCP3, vecTransformLocal );
  2326. pParticles->SetControlPointParent( m_nCP3, m_nCP3Parent );
  2327. VectorTransform( m_vecCP4Pos, mat, vecTransformLocal );
  2328. pParticles->SetControlPoint( m_nCP4, vecTransformLocal );
  2329. pParticles->SetControlPointParent( m_nCP4, m_nCP4Parent );
  2330. }
  2331. else
  2332. {
  2333. pParticles->SetControlPoint( m_nCP1, m_vecCP1Pos );
  2334. pParticles->SetControlPointParent( m_nCP1, m_nCP1Parent );
  2335. pParticles->SetControlPoint( m_nCP2, m_vecCP2Pos );
  2336. pParticles->SetControlPointParent( m_nCP2, m_nCP2Parent );
  2337. pParticles->SetControlPoint( m_nCP3, m_vecCP3Pos );
  2338. pParticles->SetControlPointParent( m_nCP3, m_nCP3Parent );
  2339. pParticles->SetControlPoint( m_nCP4, m_vecCP4Pos );
  2340. pParticles->SetControlPointParent( m_nCP4, m_nCP4Parent );
  2341. }
  2342. }
  2343. //-----------------------------------------------------------------------------
  2344. // Dampen Movement Relative to Control Point
  2345. // The closer a particle is the the assigned control point, the less
  2346. // it can move
  2347. //-----------------------------------------------------------------------------
  2348. class C_OP_DampenToCP : public CParticleOperatorInstance
  2349. {
  2350. DECLARE_PARTICLE_OPERATOR( C_OP_DampenToCP );
  2351. int m_nControlPointNumber;
  2352. float m_flRange, m_flScale;
  2353. uint32 GetWrittenAttributes( void ) const
  2354. {
  2355. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  2356. }
  2357. uint32 GetReadAttributes( void ) const
  2358. {
  2359. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK |
  2360. PARTICLE_ATTRIBUTE_PARTICLE_ID_MASK;
  2361. }
  2362. virtual uint64 GetReadControlPointMask() const
  2363. {
  2364. return ( 1ULL << m_nControlPointNumber );
  2365. }
  2366. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  2367. {
  2368. m_nControlPointNumber = max( 0, min( MAX_PARTICLE_CONTROL_POINTS-1, m_nControlPointNumber ) );
  2369. }
  2370. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  2371. };
  2372. DEFINE_PARTICLE_OPERATOR( C_OP_DampenToCP , "Movement Dampen Relative to Control Point", OPERATOR_GENERIC );
  2373. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_DampenToCP )
  2374. DMXELEMENT_UNPACK_FIELD( "control_point_number", "0", int, m_nControlPointNumber )
  2375. DMXELEMENT_UNPACK_FIELD( "falloff range", "100", float, m_flRange )
  2376. DMXELEMENT_UNPACK_FIELD( "dampen scale", "1", float, m_flScale )
  2377. END_PARTICLE_OPERATOR_UNPACK( C_OP_DampenToCP )
  2378. void C_OP_DampenToCP::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  2379. {
  2380. if ( m_flRange <= 0.0f )
  2381. return;
  2382. Vector vecControlPoint = pParticles->GetControlPointAtCurrentTime( m_nControlPointNumber );
  2383. // FIXME: SSE-ize
  2384. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  2385. {
  2386. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, i );
  2387. float *xyz_prev = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  2388. Vector vecParticlePosition, vecParticlePosition_prev, vParticleDelta ;
  2389. SetVectorFromAttribute( vecParticlePosition, xyz );
  2390. SetVectorFromAttribute( vecParticlePosition_prev, xyz_prev );
  2391. Vector ofs;
  2392. ofs = vecParticlePosition - vecControlPoint;
  2393. float flDistance = ofs.Length();
  2394. float flDampenAmount;
  2395. if ( flDistance > m_flRange )
  2396. {
  2397. continue;
  2398. }
  2399. else
  2400. {
  2401. flDampenAmount = flDistance / m_flRange;
  2402. flDampenAmount = pow( flDampenAmount, m_flScale);
  2403. }
  2404. vParticleDelta = vecParticlePosition - vecParticlePosition_prev;
  2405. Vector vParticleDampened = vParticleDelta * flDampenAmount;
  2406. vecParticlePosition = vecParticlePosition_prev + vParticleDampened;
  2407. Vector vecParticlePositionOrg;
  2408. SetVectorFromAttribute( vecParticlePositionOrg, xyz );
  2409. VectorLerp (vecParticlePositionOrg, vecParticlePosition, flStrength, vecParticlePosition );
  2410. SetVectorAttribute( xyz, vecParticlePosition );
  2411. }
  2412. };
  2413. //-----------------------------------------------------------------------------
  2414. // Distance Between CP Operator
  2415. //-----------------------------------------------------------------------------
  2416. class C_OP_DistanceBetweenCPs : public CParticleOperatorInstance
  2417. {
  2418. DECLARE_PARTICLE_OPERATOR( C_OP_DistanceBetweenCPs );
  2419. uint32 GetWrittenAttributes( void ) const
  2420. {
  2421. return 1 << m_nFieldOutput;
  2422. }
  2423. uint32 GetReadAttributes( void ) const
  2424. {
  2425. return 0;
  2426. }
  2427. uint32 GetReadInitialAttributes( void ) const
  2428. {
  2429. return 1 << m_nFieldOutput;
  2430. }
  2431. virtual uint64 GetReadControlPointMask() const
  2432. {
  2433. return ( 1ULL << m_nStartCP ) | ( 1ULL << m_nEndCP );
  2434. }
  2435. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  2436. {
  2437. m_nCollisionGroupNumber = g_pParticleSystemMgr->Query()->GetCollisionGroupFromName( m_CollisionGroupName );
  2438. m_nStartCP = max( 0, min( MAX_PARTICLE_CONTROL_POINTS-1, m_nStartCP ) );
  2439. m_nEndCP = max( 0, min( MAX_PARTICLE_CONTROL_POINTS-1, m_nEndCP ) );
  2440. }
  2441. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  2442. int m_nFieldOutput;
  2443. float m_flInputMin;
  2444. float m_flInputMax;
  2445. float m_flOutputMin;
  2446. float m_flOutputMax;
  2447. int m_nStartCP;
  2448. int m_nEndCP;
  2449. bool m_bLOS;
  2450. char m_CollisionGroupName[128];
  2451. int m_nCollisionGroupNumber;
  2452. float m_flMaxTraceLength;
  2453. float m_flLOSScale;
  2454. bool m_bScaleInitialRange;
  2455. };
  2456. DEFINE_PARTICLE_OPERATOR( C_OP_DistanceBetweenCPs, "Remap Distance Between Two Control Points to Scalar", OPERATOR_GENERIC );
  2457. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_DistanceBetweenCPs )
  2458. DMXELEMENT_UNPACK_FIELD( "distance minimum","0", float, m_flInputMin )
  2459. DMXELEMENT_UNPACK_FIELD( "distance maximum","128", float, m_flInputMax )
  2460. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "3", int, m_nFieldOutput, "intchoice particlefield_scalar" )
  2461. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  2462. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  2463. DMXELEMENT_UNPACK_FIELD( "starting control point","0", int, m_nStartCP )
  2464. DMXELEMENT_UNPACK_FIELD( "ending control point","1", int, m_nEndCP )
  2465. DMXELEMENT_UNPACK_FIELD( "ensure line of sight","0", bool, m_bLOS )
  2466. DMXELEMENT_UNPACK_FIELD_STRING( "LOS collision group", "NONE", m_CollisionGroupName )
  2467. DMXELEMENT_UNPACK_FIELD( "Maximum Trace Length", "-1", float, m_flMaxTraceLength )
  2468. DMXELEMENT_UNPACK_FIELD( "LOS Failure Scalar", "0", float, m_flLOSScale )
  2469. DMXELEMENT_UNPACK_FIELD( "output is scalar of initial random range","0", bool, m_bScaleInitialRange )
  2470. END_PARTICLE_OPERATOR_UNPACK( C_OP_DistanceBetweenCPs )
  2471. void C_OP_DistanceBetweenCPs::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  2472. {
  2473. // clamp the result to 0 and 1 if it's alpha
  2474. float flMin=m_flOutputMin;
  2475. float flMax=m_flOutputMax;
  2476. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & ( 1 << m_nFieldOutput ) )
  2477. {
  2478. flMin = clamp(m_flOutputMin, 0.0f, 1.0f );
  2479. flMax = clamp(m_flOutputMax, 0.0f, 1.0f );
  2480. }
  2481. Vector vecControlPoint1 = pParticles->GetControlPointAtCurrentTime( m_nStartCP );
  2482. Vector vecControlPoint2 = pParticles->GetControlPointAtCurrentTime( m_nEndCP );
  2483. Vector vecDelta = vecControlPoint1 - vecControlPoint2;
  2484. float flDistance = vecDelta.Length();
  2485. if ( m_bLOS )
  2486. {
  2487. Vector vecEndPoint = vecControlPoint2;
  2488. if ( m_flMaxTraceLength != -1.0f && m_flMaxTraceLength < flDistance )
  2489. {
  2490. VectorNormalize(vecEndPoint);
  2491. vecEndPoint *= m_flMaxTraceLength;
  2492. vecEndPoint += vecControlPoint1;
  2493. }
  2494. CBaseTrace tr;
  2495. g_pParticleSystemMgr->Query()->TraceLine( vecControlPoint1, vecEndPoint, MASK_OPAQUE_AND_NPCS, NULL, m_nCollisionGroupNumber, &tr );
  2496. if (tr.fraction != 1.0f)
  2497. {
  2498. flDistance *= tr.fraction * m_flLOSScale;
  2499. }
  2500. }
  2501. // FIXME: SSE-ize
  2502. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  2503. {
  2504. float flOutput = RemapValClamped( flDistance, m_flInputMin, m_flInputMax, flMin, flMax );
  2505. if ( m_bScaleInitialRange )
  2506. {
  2507. const float *pInitialOutput = pParticles->GetInitialFloatAttributePtr( m_nFieldOutput, i );
  2508. flOutput = *pInitialOutput * flOutput;
  2509. }
  2510. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, i );
  2511. *pOutput = Lerp (flStrength, *pOutput, flOutput);
  2512. }
  2513. }
  2514. //-----------------------------------------------------------------------------
  2515. // Distance to CP Operator
  2516. //-----------------------------------------------------------------------------
  2517. class C_OP_DistanceToCP : public CParticleOperatorInstance
  2518. {
  2519. DECLARE_PARTICLE_OPERATOR( C_OP_DistanceToCP );
  2520. uint32 GetWrittenAttributes( void ) const
  2521. {
  2522. return 1 << m_nFieldOutput;
  2523. }
  2524. uint32 GetReadAttributes( void ) const
  2525. {
  2526. return PARTICLE_ATTRIBUTE_XYZ_MASK;
  2527. }
  2528. uint32 GetReadInitialAttributes( void ) const
  2529. {
  2530. return 1 << m_nFieldOutput;
  2531. }
  2532. virtual uint64 GetReadControlPointMask() const
  2533. {
  2534. return ( 1ULL << m_nStartCP ) | ( 1ULL << m_nEndCP );
  2535. }
  2536. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  2537. {
  2538. m_nCollisionGroupNumber = g_pParticleSystemMgr->Query()->GetCollisionGroupFromName( m_CollisionGroupName );
  2539. m_nStartCP = max( 0, min( MAX_PARTICLE_CONTROL_POINTS-1, m_nStartCP ) );
  2540. m_nEndCP = max( 0, min( MAX_PARTICLE_CONTROL_POINTS-1, m_nEndCP ) );
  2541. }
  2542. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  2543. int m_nFieldOutput;
  2544. float m_flInputMin;
  2545. float m_flInputMax;
  2546. float m_flOutputMin;
  2547. float m_flOutputMax;
  2548. int m_nStartCP;
  2549. int m_nEndCP;
  2550. bool m_bLOS;
  2551. char m_CollisionGroupName[128];
  2552. int m_nCollisionGroupNumber;
  2553. float m_flMaxTraceLength;
  2554. float m_flLOSScale;
  2555. bool m_bScaleInitialRange;
  2556. bool m_bActiveRange;
  2557. };
  2558. DEFINE_PARTICLE_OPERATOR( C_OP_DistanceToCP, "Remap Distance to Control Point to Scalar", OPERATOR_GENERIC );
  2559. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_DistanceToCP )
  2560. DMXELEMENT_UNPACK_FIELD( "distance minimum","0", float, m_flInputMin )
  2561. DMXELEMENT_UNPACK_FIELD( "distance maximum","128", float, m_flInputMax )
  2562. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "3", int, m_nFieldOutput, "intchoice particlefield_scalar" )
  2563. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  2564. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  2565. DMXELEMENT_UNPACK_FIELD( "control point","0", int, m_nStartCP )
  2566. DMXELEMENT_UNPACK_FIELD( "ensure line of sight","0", bool, m_bLOS )
  2567. DMXELEMENT_UNPACK_FIELD_STRING( "LOS collision group", "NONE", m_CollisionGroupName )
  2568. DMXELEMENT_UNPACK_FIELD( "Maximum Trace Length", "-1", float, m_flMaxTraceLength )
  2569. DMXELEMENT_UNPACK_FIELD( "LOS Failure Scalar", "0", float, m_flLOSScale )
  2570. DMXELEMENT_UNPACK_FIELD( "output is scalar of initial random range","0", bool, m_bScaleInitialRange )
  2571. DMXELEMENT_UNPACK_FIELD( "only active within specified distance","0", bool, m_bActiveRange )
  2572. END_PARTICLE_OPERATOR_UNPACK( C_OP_DistanceToCP )
  2573. void C_OP_DistanceToCP::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  2574. {
  2575. // clamp the result to 0 and 1 if it's alpha
  2576. float flMin=m_flOutputMin;
  2577. float flMax=m_flOutputMax;
  2578. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & ( 1 << m_nFieldOutput ) )
  2579. {
  2580. flMin = clamp(m_flOutputMin, 0.0f, 1.0f );
  2581. flMax = clamp(m_flOutputMax, 0.0f, 1.0f );
  2582. }
  2583. Vector vecControlPoint1 = pParticles->GetControlPointAtCurrentTime( m_nStartCP );
  2584. // FIXME: SSE-ize
  2585. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  2586. {
  2587. Vector vecPosition2;
  2588. const float *pXYZ = pParticles->GetFloatAttributePtr(PARTICLE_ATTRIBUTE_XYZ, i );
  2589. vecPosition2 = Vector(pXYZ[0], pXYZ[4], pXYZ[8]);
  2590. Vector vecDelta = vecControlPoint1 - vecPosition2;
  2591. float flDistance = vecDelta.Length();
  2592. if ( m_bActiveRange && ( flDistance < m_flInputMin || flDistance > m_flInputMax ) )
  2593. {
  2594. continue;
  2595. }
  2596. if ( m_bLOS )
  2597. {
  2598. Vector vecEndPoint = vecPosition2;
  2599. if ( m_flMaxTraceLength != -1.0f && m_flMaxTraceLength < flDistance )
  2600. {
  2601. VectorNormalize(vecEndPoint);
  2602. vecEndPoint *= m_flMaxTraceLength;
  2603. vecEndPoint += vecControlPoint1;
  2604. }
  2605. CBaseTrace tr;
  2606. g_pParticleSystemMgr->Query()->TraceLine( vecControlPoint1, vecEndPoint, MASK_OPAQUE_AND_NPCS, NULL , m_nCollisionGroupNumber, &tr );
  2607. if (tr.fraction != 1.0f)
  2608. {
  2609. flDistance *= tr.fraction * m_flLOSScale;
  2610. }
  2611. }
  2612. float flOutput = RemapValClamped( flDistance, m_flInputMin, m_flInputMax, flMin, flMax );
  2613. if ( m_bScaleInitialRange )
  2614. {
  2615. const float *pInitialOutput = pParticles->GetInitialFloatAttributePtr( m_nFieldOutput, i );
  2616. flOutput = *pInitialOutput * flOutput;
  2617. }
  2618. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, i );
  2619. *pOutput = Lerp (flStrength, *pOutput, flOutput);
  2620. //float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, i );
  2621. //float flOutput = RemapValClamped( flDistance, m_flInputMin, m_flInputMax, flMin, flMax );
  2622. //*pOutput = Lerp (flStrength, *pOutput, flOutput);
  2623. }
  2624. }
  2625. //-----------------------------------------------------------------------------
  2626. // Assign CP to Player
  2627. //-----------------------------------------------------------------------------
  2628. class C_OP_SetControlPointToPlayer : public CParticleOperatorInstance
  2629. {
  2630. DECLARE_PARTICLE_OPERATOR( C_OP_SetControlPointToPlayer );
  2631. int m_nCP1;
  2632. Vector m_vecCP1Pos;
  2633. uint32 GetWrittenAttributes( void ) const
  2634. {
  2635. return 0;
  2636. }
  2637. uint32 GetReadAttributes( void ) const
  2638. {
  2639. return 0;
  2640. }
  2641. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  2642. {
  2643. m_nCP1 = max( 0, min( MAX_PARTICLE_CONTROL_POINTS-1, m_nCP1 ) );
  2644. }
  2645. bool ShouldRunBeforeEmitters( void ) const
  2646. {
  2647. return true;
  2648. }
  2649. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  2650. };
  2651. DEFINE_PARTICLE_OPERATOR( C_OP_SetControlPointToPlayer, "Set Control Point To Player", OPERATOR_GENERIC );
  2652. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_SetControlPointToPlayer )
  2653. DMXELEMENT_UNPACK_FIELD( "Control Point Number", "1", int, m_nCP1 )
  2654. DMXELEMENT_UNPACK_FIELD( "Control Point Offset", "0 0 0", Vector, m_vecCP1Pos )
  2655. END_PARTICLE_OPERATOR_UNPACK( C_OP_SetControlPointToPlayer )
  2656. void C_OP_SetControlPointToPlayer::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  2657. {
  2658. Vector vecClientPos =g_pParticleSystemMgr->Query()->GetLocalPlayerPos();
  2659. pParticles->SetControlPoint( m_nCP1, m_vecCP1Pos + vecClientPos );
  2660. Vector vecForward;
  2661. Vector vecRight;
  2662. Vector vecUp;
  2663. g_pParticleSystemMgr->Query()->GetLocalPlayerEyeVectors( &vecForward, &vecRight, &vecUp);
  2664. pParticles->SetControlPointOrientation( m_nCP1, vecForward, vecRight, vecUp );
  2665. }
  2666. //-------------------------
  2667. // Emits particles from particles
  2668. //NOT FINISHED
  2669. //-------------------------
  2670. class C_OP_PerParticleEmitter : public CParticleOperatorInstance
  2671. {
  2672. DECLARE_PARTICLE_OPERATOR( C_OP_PerParticleEmitter );
  2673. struct C_OP_PerParticleEmitterContext_t
  2674. {
  2675. float m_flTotalActualParticlesSoFar;
  2676. int m_nTotalEmittedSoFar;
  2677. bool m_bStoppedEmission;
  2678. };
  2679. int m_nChildGroupID;
  2680. bool m_bInheritVelocity;
  2681. float m_flEmitRate;
  2682. float m_flVelocityScale;
  2683. float m_flStartTime;
  2684. float m_flEmissionDuration;
  2685. uint32 GetWrittenAttributes( void ) const
  2686. {
  2687. return PARTICLE_ATTRIBUTE_CREATION_TIME;
  2688. }
  2689. uint32 GetReadAttributes( void ) const
  2690. {
  2691. return PARTICLE_ATTRIBUTE_XYZ | PARTICLE_ATTRIBUTE_PREV_XYZ;
  2692. }
  2693. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  2694. {
  2695. if ( m_flEmitRate < 0.0f )
  2696. {
  2697. m_flEmitRate = 0.0f;
  2698. }
  2699. if ( m_flEmissionDuration < 0.0f )
  2700. {
  2701. m_flEmissionDuration = 0.0f;
  2702. }
  2703. }
  2704. inline bool IsInfinitelyEmitting() const
  2705. {
  2706. return ( m_flEmissionDuration == 0.0f );
  2707. }
  2708. virtual bool MayCreateMoreParticles( CParticleCollection *pParticles, void *pContext ) const
  2709. {
  2710. C_OP_PerParticleEmitterContext_t *pCtx = reinterpret_cast<C_OP_PerParticleEmitterContext_t *>( pContext );
  2711. if ( pCtx->m_bStoppedEmission )
  2712. return false;
  2713. if ( m_flEmitRate <= 0.0f )
  2714. return false;
  2715. if ( m_flEmissionDuration != 0.0f && ( pParticles->m_flCurTime - pParticles->m_flDt ) > ( m_flStartTime + m_flEmissionDuration ) )
  2716. return false;
  2717. return true;
  2718. }
  2719. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  2720. {
  2721. C_OP_PerParticleEmitterContext_t *pCtx=reinterpret_cast<C_OP_PerParticleEmitterContext_t *>( pContext );
  2722. pCtx->m_flTotalActualParticlesSoFar = 0.0f;
  2723. pCtx->m_nTotalEmittedSoFar = 0;
  2724. pCtx->m_bStoppedEmission = false;
  2725. }
  2726. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  2727. };
  2728. DEFINE_PARTICLE_OPERATOR( C_OP_PerParticleEmitter, "Per Particle Emitter", OPERATOR_GENERIC );
  2729. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_PerParticleEmitter )
  2730. DMXELEMENT_UNPACK_FIELD( "Group ID to affect", "1", int, m_nChildGroupID )
  2731. DMXELEMENT_UNPACK_FIELD( "Inherit Velocity", "0", int, m_bInheritVelocity )
  2732. DMXELEMENT_UNPACK_FIELD( "Emission Rate", "100", float, m_flEmitRate )
  2733. DMXELEMENT_UNPACK_FIELD( "Velocity Scale", "0", int, m_flVelocityScale )
  2734. DMXELEMENT_UNPACK_FIELD( "Emission Start Time", "0", float, m_flStartTime )
  2735. DMXELEMENT_UNPACK_FIELD( "Emission Duration", "0", float, m_flEmissionDuration )
  2736. END_PARTICLE_OPERATOR_UNPACK( C_OP_PerParticleEmitter )
  2737. void C_OP_PerParticleEmitter::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  2738. {
  2739. for( CParticleCollection *pChild = pParticles->m_Children.m_pHead; pChild; pChild = pChild->m_pNext )
  2740. {
  2741. if ( pChild->GetGroupID() == m_nChildGroupID )
  2742. {
  2743. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  2744. {
  2745. C_OP_PerParticleEmitterContext_t *pCtx=reinterpret_cast<C_OP_PerParticleEmitterContext_t *>( pContext );
  2746. const float *pXYZ = pParticles->GetFloatAttributePtr(
  2747. PARTICLE_ATTRIBUTE_XYZ, i );
  2748. const float *pXYZ_Prev = pParticles->GetFloatAttributePtr(
  2749. PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  2750. Vector vecParticlePosition, vecParticlePosition_prev, vParticleDelta ;
  2751. vecParticlePosition = Vector ( pXYZ[0], pXYZ[4], pXYZ[8] );
  2752. vecParticlePosition_prev = Vector ( pXYZ_Prev[0], pXYZ_Prev[4], pXYZ_Prev[8] );
  2753. vParticleDelta = vecParticlePosition - vecParticlePosition_prev;
  2754. float flEmissionRate = m_flEmitRate * flStrength;
  2755. if ( m_flVelocityScale != 0.0f )
  2756. {
  2757. float flVelocity = vParticleDelta.Length();
  2758. flEmissionRate *= flVelocity * m_flVelocityScale * pParticles->m_flDt;
  2759. }
  2760. if ( flEmissionRate == 0.0f )
  2761. continue;
  2762. if ( !C_OP_PerParticleEmitter::MayCreateMoreParticles( pChild, pContext ) )
  2763. continue;
  2764. Assert( flEmissionRate != 0.0f );
  2765. // determine our previous and current draw times and clamp them to start time and emission duration
  2766. float flPrevDrawTime = pParticles->m_flCurTime - pParticles->m_flDt;
  2767. float flCurrDrawTime = pParticles->m_flCurTime;
  2768. if ( !IsInfinitelyEmitting() )
  2769. {
  2770. if ( flPrevDrawTime < m_flStartTime )
  2771. {
  2772. flPrevDrawTime = m_flStartTime;
  2773. }
  2774. if ( flCurrDrawTime > m_flStartTime + m_flEmissionDuration )
  2775. {
  2776. flCurrDrawTime = m_flStartTime + m_flEmissionDuration;
  2777. }
  2778. }
  2779. float flDeltaTime = flCurrDrawTime - flPrevDrawTime;
  2780. //Calculate emission rate by delta time from last frame to determine number of particles to emit this frame as a fractional float
  2781. float flActualParticlesToEmit = flEmissionRate * flDeltaTime;
  2782. int nParticlesEmitted = pCtx->m_nTotalEmittedSoFar;
  2783. //Add emitted particle to float counter to allow for fractional emission
  2784. pCtx->m_flTotalActualParticlesSoFar += flActualParticlesToEmit;
  2785. //Floor float accumulated value and subtract whole int emitted so far from the result to determine total whole particles to emit this frame
  2786. int nParticlesToEmit = floor ( pCtx->m_flTotalActualParticlesSoFar ) - pCtx->m_nTotalEmittedSoFar;
  2787. //Add emitted particles to running int total.
  2788. pCtx->m_nTotalEmittedSoFar += nParticlesToEmit;
  2789. if ( nParticlesToEmit == 0 )
  2790. continue;
  2791. // We're only allowed to emit so many particles, though..
  2792. // If we run out of room, only emit the last N particles
  2793. int nActualParticlesToEmit = nParticlesToEmit;
  2794. int nAllowedParticlesToEmit = pChild->m_nMaxAllowedParticles - pParticles->m_nActiveParticles;
  2795. if ( nAllowedParticlesToEmit < nParticlesToEmit )
  2796. {
  2797. nActualParticlesToEmit = nAllowedParticlesToEmit;
  2798. }
  2799. if ( nActualParticlesToEmit == 0 )
  2800. continue;
  2801. int nStartParticle = pChild->m_nActiveParticles;
  2802. pChild->SetNActiveParticles( nActualParticlesToEmit + pChild->m_nActiveParticles );
  2803. float flTimeStampStep = ( flDeltaTime ) / ( nActualParticlesToEmit );
  2804. float flTimeStep = flPrevDrawTime + flTimeStampStep;
  2805. Vector vecMoveStampStep = vParticleDelta / nActualParticlesToEmit ;
  2806. Vector vecMoveStep = vecParticlePosition_prev + vecMoveStampStep ;
  2807. if ( nParticlesEmitted != pChild->m_nActiveParticles )
  2808. {
  2809. uint32 nInittedMask = ( PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_CREATION_TIME_MASK );
  2810. // init newly emitted particles
  2811. pChild->InitializeNewParticles( nParticlesEmitted, pChild->m_nActiveParticles - nParticlesEmitted, nInittedMask );
  2812. //CHECKSYSTEM( this );
  2813. }
  2814. // Set the particle creation time to the exact sub-frame particle emission time
  2815. // !! speed!! do sse init here
  2816. for( int j = nStartParticle; j < nStartParticle + nActualParticlesToEmit; j++ )
  2817. {
  2818. float *pTimeStamp = pChild->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_CREATION_TIME, j );
  2819. flTimeStep = min( flTimeStep, flCurrDrawTime );
  2820. *pTimeStamp = flTimeStep;
  2821. flTimeStep += flTimeStampStep;
  2822. float *pXYZ_Child = pChild->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, j );
  2823. float *pXYZ_Prev_Child = pChild->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, j );
  2824. Vector vecChildXYZ;
  2825. SetVectorFromAttribute ( vecChildXYZ, pXYZ_Child);
  2826. vecChildXYZ = vecMoveStep;
  2827. SetVectorAttribute ( pXYZ_Child, vecChildXYZ);
  2828. vecMoveStep += vecMoveStampStep;
  2829. if ( m_bInheritVelocity )
  2830. {
  2831. *pXYZ_Prev_Child = *pXYZ_Prev;
  2832. }
  2833. else
  2834. {
  2835. *pXYZ_Prev_Child = *pXYZ_Child;
  2836. }
  2837. }
  2838. }
  2839. }
  2840. }
  2841. }
  2842. class C_OP_LockToBone : public CParticleOperatorInstance
  2843. {
  2844. DECLARE_PARTICLE_OPERATOR( C_OP_LockToBone );
  2845. int m_nControlPointNumber;
  2846. float m_flLifeTimeFadeStart;
  2847. float m_flLifeTimeFadeEnd;
  2848. uint32 GetWrittenAttributes( void ) const
  2849. {
  2850. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  2851. }
  2852. uint32 GetReadAttributes( void ) const
  2853. {
  2854. int ret= PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK |
  2855. PARTICLE_ATTRIBUTE_HITBOX_RELATIVE_XYZ_MASK | PARTICLE_ATTRIBUTE_HITBOX_INDEX_MASK;
  2856. ret |= PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  2857. return ret;
  2858. }
  2859. virtual uint64 GetReadControlPointMask() const
  2860. {
  2861. return ( 1ULL << m_nControlPointNumber );
  2862. }
  2863. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  2864. {
  2865. m_nControlPointNumber = max( 0, min( MAX_PARTICLE_CONTROL_POINTS-1, m_nControlPointNumber ) );
  2866. }
  2867. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  2868. };
  2869. DEFINE_PARTICLE_OPERATOR( C_OP_LockToBone , "Movement Lock to Bone", OPERATOR_GENERIC );
  2870. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_LockToBone )
  2871. DMXELEMENT_UNPACK_FIELD( "control_point_number", "0", int, m_nControlPointNumber )
  2872. DMXELEMENT_UNPACK_FIELD( "lifetime fade start", "0", float, m_flLifeTimeFadeStart )
  2873. DMXELEMENT_UNPACK_FIELD( "lifetime fade end", "0", float, m_flLifeTimeFadeEnd )
  2874. END_PARTICLE_OPERATOR_UNPACK( C_OP_LockToBone )
  2875. void C_OP_LockToBone::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  2876. {
  2877. pParticles->UpdateHitBoxInfo( m_nControlPointNumber );
  2878. if ( pParticles->m_ControlPointHitBoxes[m_nControlPointNumber].CurAndPrevValid() )
  2879. {
  2880. float flAgeThreshold = m_flLifeTimeFadeEnd;
  2881. if ( flAgeThreshold <= 0.0 )
  2882. flAgeThreshold = 1.0e20;
  2883. float flIScale = 0.0;
  2884. if ( m_flLifeTimeFadeEnd > m_flLifeTimeFadeStart )
  2885. flIScale = 1.0/( m_flLifeTimeFadeEnd - m_flLifeTimeFadeStart );
  2886. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  2887. {
  2888. float *pXYZ = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, i );
  2889. float *pPrevXYZ = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  2890. const float *pUVW = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_HITBOX_RELATIVE_XYZ, i );
  2891. const int nBoxIndex = *pParticles->GetIntAttributePtr( PARTICLE_ATTRIBUTE_HITBOX_INDEX, i );
  2892. float const *pCreationTime = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, i );
  2893. float flAge = pParticles->m_flCurTime -*pCreationTime;
  2894. if ( flAge < flAgeThreshold )
  2895. {
  2896. if (
  2897. ( nBoxIndex < pParticles->m_ControlPointHitBoxes[m_nControlPointNumber].m_nNumHitBoxes ) &&
  2898. ( nBoxIndex < pParticles->m_ControlPointHitBoxes[m_nControlPointNumber].m_nNumPrevHitBoxes ) &&
  2899. ( nBoxIndex >= 0 )
  2900. )
  2901. {
  2902. Vector vecParticlePosition;
  2903. ModelHitBoxInfo_t const &hb = pParticles->m_ControlPointHitBoxes[m_nControlPointNumber].m_pHitBoxes[ nBoxIndex ];
  2904. vecParticlePosition.x = Lerp( pUVW[0], hb.m_vecBoxMins.x, hb.m_vecBoxMaxes.x );
  2905. vecParticlePosition.y = Lerp( pUVW[4], hb.m_vecBoxMins.y, hb.m_vecBoxMaxes.y );
  2906. vecParticlePosition.z = Lerp( pUVW[8], hb.m_vecBoxMins.z, hb.m_vecBoxMaxes.z );
  2907. Vector vecWorldPosition;
  2908. VectorTransform( vecParticlePosition, hb.m_Transform, vecWorldPosition );
  2909. Vector vecPrevParticlePosition;
  2910. ModelHitBoxInfo_t phb = pParticles->m_ControlPointHitBoxes[m_nControlPointNumber].m_pPrevBoxes[ nBoxIndex ];
  2911. vecPrevParticlePosition.x = Lerp( pUVW[0], phb.m_vecBoxMins.x, phb.m_vecBoxMaxes.x );
  2912. vecPrevParticlePosition.y = Lerp( pUVW[4], phb.m_vecBoxMins.y, phb.m_vecBoxMaxes.y );
  2913. vecPrevParticlePosition.z = Lerp( pUVW[8], phb.m_vecBoxMins.z, phb.m_vecBoxMaxes.z );
  2914. Vector vecPrevWorldPosition;
  2915. VectorTransform( vecPrevParticlePosition, phb.m_Transform, vecPrevWorldPosition );
  2916. Vector Delta = vecWorldPosition-vecPrevWorldPosition;
  2917. if ( flAge > m_flLifeTimeFadeStart )
  2918. Delta *= flStrength * ( 1.0- ( ( flAge - m_flLifeTimeFadeStart ) * flIScale ) );
  2919. Vector xyz;
  2920. SetVectorFromAttribute( xyz, pXYZ );
  2921. xyz += Delta;
  2922. SetVectorAttribute( pXYZ, xyz );
  2923. Vector prevxyz;
  2924. SetVectorFromAttribute( prevxyz, pPrevXYZ );
  2925. prevxyz += Delta;
  2926. SetVectorAttribute( pPrevXYZ, prevxyz );
  2927. }
  2928. }
  2929. }
  2930. }
  2931. };
  2932. //-----------------------------------------------------------------------------
  2933. // Plane Cull Operator - cull particles on the "wrong" side of a plane
  2934. //-----------------------------------------------------------------------------
  2935. class C_OP_PlaneCull : public CParticleOperatorInstance
  2936. {
  2937. int m_nPlaneControlPoint;
  2938. Vector m_vecPlaneDirection;
  2939. float m_flPlaneOffset;
  2940. DECLARE_PARTICLE_OPERATOR( C_OP_PlaneCull );
  2941. uint32 GetWrittenAttributes( void ) const
  2942. {
  2943. return 0;
  2944. }
  2945. uint32 GetReadAttributes( void ) const
  2946. {
  2947. return PARTICLE_ATTRIBUTE_XYZ_MASK;
  2948. }
  2949. virtual uint64 GetReadControlPointMask() const
  2950. {
  2951. return ( 1ULL << m_nPlaneControlPoint );
  2952. }
  2953. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  2954. };
  2955. DEFINE_PARTICLE_OPERATOR( C_OP_PlaneCull, "Cull when crossing plane", OPERATOR_GENERIC );
  2956. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_PlaneCull )
  2957. DMXELEMENT_UNPACK_FIELD( "Control Point for point on plane", "0", int, m_nPlaneControlPoint )
  2958. DMXELEMENT_UNPACK_FIELD( "Cull plane offset", "0", float, m_flPlaneOffset )
  2959. DMXELEMENT_UNPACK_FIELD( "Plane Normal", "0 0 1", Vector, m_vecPlaneDirection )
  2960. END_PARTICLE_OPERATOR_UNPACK( C_OP_PlaneCull )
  2961. void C_OP_PlaneCull::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  2962. {
  2963. C4VAttributeIterator pXYZ( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  2964. int nLimit = pParticles->m_nPaddedActiveParticles << 2;
  2965. // setup vars
  2966. FourVectors v4N ;
  2967. v4N.DuplicateVector( m_vecPlaneDirection );
  2968. v4N.VectorNormalize();
  2969. FourVectors v4Pnt;
  2970. v4Pnt.DuplicateVector( pParticles->GetControlPointAtCurrentTime( m_nPlaneControlPoint ) );
  2971. FourVectors ofs = v4N;
  2972. ofs *= ReplicateX4( m_flPlaneOffset );
  2973. v4Pnt -= ofs;
  2974. for ( int i = 0; i < nLimit; i+= 4 )
  2975. {
  2976. FourVectors f4PlaneRel = (*pXYZ );
  2977. f4PlaneRel -= v4Pnt;
  2978. fltx4 fl4PlaneEq = ( f4PlaneRel * v4N );
  2979. if ( IsAnyNegative( fl4PlaneEq ) )
  2980. {
  2981. // not especially pretty - we need to kill some particles.
  2982. int nMask = TestSignSIMD( fl4PlaneEq );
  2983. if ( nMask & 1 )
  2984. pParticles->KillParticle( i );
  2985. if ( nMask & 2 )
  2986. pParticles->KillParticle( i + 1 );
  2987. if ( nMask & 4 )
  2988. pParticles->KillParticle( i + 2 );
  2989. if ( nMask & 8 )
  2990. pParticles->KillParticle( i + 3 );
  2991. }
  2992. ++pXYZ;
  2993. }
  2994. }
  2995. //-----------------------------------------------------------------------------
  2996. // Model Cull Operator - cull particles inside or outside of a brush/animated model
  2997. //-----------------------------------------------------------------------------
  2998. class C_OP_ModelCull : public CParticleOperatorInstance
  2999. {
  3000. DECLARE_PARTICLE_OPERATOR( C_OP_ModelCull );
  3001. int m_nControlPointNumber;
  3002. bool m_bBoundBox;
  3003. bool m_bCullOutside;
  3004. uint32 GetWrittenAttributes( void ) const
  3005. {
  3006. return 0;
  3007. }
  3008. uint32 GetReadAttributes( void ) const
  3009. {
  3010. return PARTICLE_ATTRIBUTE_XYZ_MASK;
  3011. }
  3012. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  3013. {
  3014. m_nControlPointNumber = max( 0, min( MAX_PARTICLE_CONTROL_POINTS-1, m_nControlPointNumber ) );
  3015. }
  3016. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  3017. };
  3018. DEFINE_PARTICLE_OPERATOR( C_OP_ModelCull , "Cull relative to model", OPERATOR_GENERIC );
  3019. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_ModelCull )
  3020. DMXELEMENT_UNPACK_FIELD( "control_point_number", "0", int, m_nControlPointNumber )
  3021. DMXELEMENT_UNPACK_FIELD( "use only bounding box", "0", bool, m_bBoundBox )
  3022. DMXELEMENT_UNPACK_FIELD( "cull outside instead of inside", "0", bool, m_bCullOutside )
  3023. END_PARTICLE_OPERATOR_UNPACK( C_OP_ModelCull )
  3024. void C_OP_ModelCull::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  3025. {
  3026. pParticles->UpdateHitBoxInfo( m_nControlPointNumber );
  3027. if ( pParticles->m_ControlPointHitBoxes[m_nControlPointNumber].CurAndPrevValid() )
  3028. {
  3029. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  3030. {
  3031. float *pXYZ = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, i );
  3032. Vector vecParticlePosition;
  3033. SetVectorFromAttribute( vecParticlePosition, pXYZ );
  3034. bool bInside = g_pParticleSystemMgr->Query()->IsPointInControllingObjectHitBox( pParticles, m_nControlPointNumber, vecParticlePosition, m_bBoundBox );
  3035. if ( ( bInside && m_bCullOutside ) || ( !bInside && !m_bCullOutside ))
  3036. continue;
  3037. pParticles->KillParticle(i);
  3038. }
  3039. }
  3040. };
  3041. //-----------------------------------------------------------------------------
  3042. // Assign CP to Center
  3043. //-----------------------------------------------------------------------------
  3044. class C_OP_SetControlPointToCenter : public CParticleOperatorInstance
  3045. {
  3046. DECLARE_PARTICLE_OPERATOR( C_OP_SetControlPointToCenter );
  3047. int m_nCP1;
  3048. Vector m_vecCP1Pos;
  3049. uint32 GetWrittenAttributes( void ) const
  3050. {
  3051. return 0;
  3052. }
  3053. uint32 GetReadAttributes( void ) const
  3054. {
  3055. return 0;
  3056. }
  3057. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  3058. {
  3059. m_nCP1 = max( 0, min( MAX_PARTICLE_CONTROL_POINTS-1, m_nCP1 ) );
  3060. }
  3061. bool ShouldRunBeforeEmitters( void ) const
  3062. {
  3063. return true;
  3064. }
  3065. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  3066. };
  3067. DEFINE_PARTICLE_OPERATOR( C_OP_SetControlPointToCenter, "Set Control Point To Particles' Center", OPERATOR_GENERIC );
  3068. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_SetControlPointToCenter )
  3069. DMXELEMENT_UNPACK_FIELD( "Control Point Number to Set", "1", int, m_nCP1 )
  3070. DMXELEMENT_UNPACK_FIELD( "Center Offset", "0 0 0", Vector, m_vecCP1Pos )
  3071. END_PARTICLE_OPERATOR_UNPACK( C_OP_SetControlPointToCenter )
  3072. void C_OP_SetControlPointToCenter::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  3073. {
  3074. Vector vecMinBounds;
  3075. Vector vecMaxBounds;
  3076. pParticles->GetBounds( &vecMinBounds, &vecMaxBounds );
  3077. Vector vecCenter = ( ( vecMinBounds + vecMaxBounds ) / 2 );
  3078. pParticles->SetControlPoint( m_nCP1, m_vecCP1Pos + vecCenter );
  3079. }
  3080. //-----------------------------------------------------------------------------
  3081. // Velocity Match a group of particles
  3082. //-----------------------------------------------------------------------------
  3083. class C_OP_VelocityMatchingForce : public CParticleOperatorInstance
  3084. {
  3085. DECLARE_PARTICLE_OPERATOR( C_OP_VelocityMatchingForce );
  3086. float m_flDirScale;
  3087. float m_flSpdScale;
  3088. int m_nCPBroadcast;
  3089. struct VelocityMatchingForceContext_t
  3090. {
  3091. Vector m_vecAvgVelocity;
  3092. float m_flAvgSpeed;
  3093. };
  3094. uint32 GetWrittenAttributes( void ) const
  3095. {
  3096. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK ;
  3097. }
  3098. uint32 GetReadAttributes( void ) const
  3099. {
  3100. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK ;
  3101. }
  3102. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  3103. {
  3104. VelocityMatchingForceContext_t *pCtx = reinterpret_cast<VelocityMatchingForceContext_t *>( pContext );
  3105. pCtx->m_vecAvgVelocity = vec3_origin;
  3106. pCtx->m_flAvgSpeed = 0;
  3107. }
  3108. size_t GetRequiredContextBytes( void ) const
  3109. {
  3110. return sizeof( VelocityMatchingForceContext_t );
  3111. }
  3112. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  3113. };
  3114. DEFINE_PARTICLE_OPERATOR( C_OP_VelocityMatchingForce , "Movement Match Particle Velocities", OPERATOR_GENERIC );
  3115. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_VelocityMatchingForce )
  3116. DMXELEMENT_UNPACK_FIELD( "Direction Matching Strength", "0.25", float, m_flDirScale )
  3117. DMXELEMENT_UNPACK_FIELD( "Speed Matching Strength", "0.25", float, m_flSpdScale )
  3118. DMXELEMENT_UNPACK_FIELD( "Control Point to Broadcast Speed and Direction To", "-1", int, m_nCPBroadcast )
  3119. END_PARTICLE_OPERATOR_UNPACK( C_OP_VelocityMatchingForce )
  3120. void C_OP_VelocityMatchingForce::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  3121. {
  3122. VelocityMatchingForceContext_t *pCtx = reinterpret_cast<VelocityMatchingForceContext_t *>( pContext );
  3123. Vector vecVelocityAvg = vec3_origin;
  3124. float flAvgSpeed = 0;
  3125. // FIXME: SSE-ize
  3126. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  3127. {
  3128. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, i );
  3129. float *xyz_prev = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  3130. Vector vecXYZ;
  3131. Vector vecPXYZ;
  3132. SetVectorFromAttribute( vecXYZ, xyz );
  3133. SetVectorFromAttribute( vecPXYZ, xyz_prev );
  3134. Vector vecVelocityCur = ( ( vecXYZ - vecPXYZ ) / pParticles->m_flDt );
  3135. vecVelocityAvg += vecVelocityCur;
  3136. float flSpeed = vecVelocityCur.Length();
  3137. flAvgSpeed += flSpeed;
  3138. if ( pCtx->m_vecAvgVelocity != vec3_origin )
  3139. {
  3140. Vector vecScaledXYZ;
  3141. VectorNormalizeFast(vecVelocityCur);
  3142. VectorLerp( vecVelocityCur, pCtx->m_vecAvgVelocity, m_flDirScale, vecScaledXYZ );
  3143. VectorNormalizeFast(vecScaledXYZ);
  3144. flSpeed = Lerp ( m_flSpdScale, flSpeed, pCtx->m_flAvgSpeed );
  3145. vecScaledXYZ *= flSpeed;
  3146. vecScaledXYZ = ( ( vecScaledXYZ * pParticles->m_flDt ) + vecPXYZ );
  3147. SetVectorAttribute( xyz, vecScaledXYZ );
  3148. }
  3149. }
  3150. VectorNormalizeFast( vecVelocityAvg );
  3151. pCtx->m_vecAvgVelocity = vecVelocityAvg;
  3152. pCtx->m_flAvgSpeed = ( flAvgSpeed / pParticles->m_nActiveParticles );
  3153. if ( m_nCPBroadcast != -1 )
  3154. {
  3155. pParticles->SetControlPoint( m_nCPBroadcast, Vector ( pCtx->m_flAvgSpeed, pCtx->m_flAvgSpeed, pCtx->m_flAvgSpeed ) );
  3156. pParticles->SetControlPointForwardVector( m_nCPBroadcast, pCtx->m_vecAvgVelocity );
  3157. }
  3158. };
  3159. //-----------------------------------------------------------------------------
  3160. // Orient to heading
  3161. //-----------------------------------------------------------------------------
  3162. class C_OP_OrientTo2dDirection : public CParticleOperatorInstance
  3163. {
  3164. DECLARE_PARTICLE_OPERATOR( C_OP_OrientTo2dDirection );
  3165. float m_flRotOffset;
  3166. float m_flSpinStrength;
  3167. uint32 GetWrittenAttributes( void ) const
  3168. {
  3169. return PARTICLE_ATTRIBUTE_ROTATION_MASK;
  3170. }
  3171. uint32 GetReadAttributes( void ) const
  3172. {
  3173. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK ;
  3174. }
  3175. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  3176. };
  3177. DEFINE_PARTICLE_OPERATOR( C_OP_OrientTo2dDirection , "Rotation Orient to 2D Direction", OPERATOR_GENERIC );
  3178. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_OrientTo2dDirection )
  3179. DMXELEMENT_UNPACK_FIELD( "Rotation Offset", "0", float, m_flRotOffset )
  3180. DMXELEMENT_UNPACK_FIELD( "Spin Strength", "1", float, m_flSpinStrength )
  3181. END_PARTICLE_OPERATOR_UNPACK( C_OP_OrientTo2dDirection )
  3182. void C_OP_OrientTo2dDirection::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  3183. {
  3184. float flRotOffset = m_flRotOffset * ( M_PI / 180.0f );
  3185. // FIXME: SSE-ize
  3186. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  3187. {
  3188. const float *xyz = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_XYZ, i );
  3189. const float *xyz_prev = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  3190. float *roll = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_ROTATION, i );
  3191. Vector vecXYZ;
  3192. Vector vecPXYZ;
  3193. vecXYZ.x = xyz[0];
  3194. vecXYZ.y = xyz[4];
  3195. vecXYZ.z = xyz[8];
  3196. vecPXYZ.x = xyz_prev[0];
  3197. vecPXYZ.y = xyz_prev[4];
  3198. vecPXYZ.z = xyz_prev[8];
  3199. Vector vecVelocityCur = ( vecXYZ - vecPXYZ );
  3200. vecVelocityCur.z = 0.0f;
  3201. VectorNormalizeFast ( vecVelocityCur );
  3202. float flCurRot = *roll;
  3203. float flVelRot = atan2(vecVelocityCur.y, vecVelocityCur.x ) + M_PI;
  3204. flVelRot += flRotOffset;
  3205. float flRotation = Lerp ( m_flSpinStrength, flCurRot, flVelRot );
  3206. *roll = flRotation;
  3207. }
  3208. };
  3209. //-----------------------------------------------------------------------------
  3210. // Orient relative to CP
  3211. //-----------------------------------------------------------------------------
  3212. class C_OP_Orient2DRelToCP : public CParticleOperatorInstance
  3213. {
  3214. DECLARE_PARTICLE_OPERATOR( C_OP_Orient2DRelToCP );
  3215. float m_flRotOffset;
  3216. float m_flSpinStrength;
  3217. int m_nCP;
  3218. uint32 GetWrittenAttributes( void ) const
  3219. {
  3220. return PARTICLE_ATTRIBUTE_ROTATION_MASK;
  3221. }
  3222. uint32 GetReadAttributes( void ) const
  3223. {
  3224. return PARTICLE_ATTRIBUTE_XYZ_MASK ;
  3225. }
  3226. virtual uint64 GetReadControlPointMask() const
  3227. {
  3228. return ( 1ULL << m_nCP );
  3229. }
  3230. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  3231. };
  3232. DEFINE_PARTICLE_OPERATOR( C_OP_Orient2DRelToCP , "Rotation Orient Relative to CP", OPERATOR_GENERIC );
  3233. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_Orient2DRelToCP )
  3234. DMXELEMENT_UNPACK_FIELD( "Rotation Offset", "0", float, m_flRotOffset )
  3235. DMXELEMENT_UNPACK_FIELD( "Spin Strength", "1", float, m_flSpinStrength )
  3236. DMXELEMENT_UNPACK_FIELD( "Control Point", "0", int, m_nCP )
  3237. END_PARTICLE_OPERATOR_UNPACK( C_OP_Orient2DRelToCP )
  3238. void C_OP_Orient2DRelToCP::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  3239. {
  3240. float flRotOffset = m_flRotOffset * ( M_PI / 180.0f );
  3241. // FIXME: SSE-ize
  3242. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  3243. {
  3244. const float *xyz = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_XYZ, i );
  3245. float *roll = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_ROTATION, i );
  3246. Vector vecXYZ;
  3247. Vector vecCP;
  3248. vecCP = pParticles->GetControlPointAtCurrentTime( m_nCP );
  3249. vecXYZ.x = xyz[0];
  3250. vecXYZ.y = xyz[4];
  3251. vecXYZ.z = xyz[8];
  3252. Vector vecVelocityCur = ( vecXYZ - vecCP );
  3253. vecVelocityCur.z = 0.0f;
  3254. VectorNormalizeFast ( vecVelocityCur );
  3255. float flCurRot = *roll;
  3256. float flVelRot = atan2(vecVelocityCur.y, vecVelocityCur.x ) + M_PI;
  3257. flVelRot += flRotOffset;
  3258. float flRotation = Lerp ( m_flSpinStrength, flCurRot, flVelRot );
  3259. *roll = flRotation;
  3260. }
  3261. };
  3262. //-----------------------------------------------------------------------------
  3263. // Max Velocity - clamps the maximum velocity of a particle
  3264. //-----------------------------------------------------------------------------
  3265. class C_OP_MaxVelocity : public CParticleOperatorInstance
  3266. {
  3267. DECLARE_PARTICLE_OPERATOR( C_OP_MaxVelocity );
  3268. float m_flMaxVelocity;
  3269. uint32 GetWrittenAttributes( void ) const
  3270. {
  3271. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK ;
  3272. }
  3273. uint32 GetReadAttributes( void ) const
  3274. {
  3275. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK ;
  3276. }
  3277. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  3278. };
  3279. DEFINE_PARTICLE_OPERATOR( C_OP_MaxVelocity , "Movement Max Velocity", OPERATOR_GENERIC );
  3280. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_MaxVelocity )
  3281. DMXELEMENT_UNPACK_FIELD( "Maximum Velocity", "0", float, m_flMaxVelocity )
  3282. END_PARTICLE_OPERATOR_UNPACK( C_OP_MaxVelocity )
  3283. void C_OP_MaxVelocity::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  3284. {
  3285. // FIXME: SSE-ize
  3286. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  3287. {
  3288. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, i );
  3289. float *xyz_prev = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  3290. Vector vecXYZ;
  3291. Vector vecPXYZ;
  3292. SetVectorFromAttribute( vecXYZ, xyz );
  3293. SetVectorFromAttribute( vecPXYZ, xyz_prev );
  3294. Vector vecVelocityCur = ( ( vecXYZ - vecPXYZ ) );
  3295. float flSpeed = vecVelocityCur.Length();
  3296. VectorNormalizeFast( vecVelocityCur );
  3297. float flMaxVelocityNormalized = m_flMaxVelocity * pParticles->m_flDt;
  3298. vecVelocityCur *= min( flSpeed, flMaxVelocityNormalized);
  3299. vecXYZ = vecPXYZ + vecVelocityCur;
  3300. SetVectorAttribute( xyz, vecXYZ );
  3301. }
  3302. };
  3303. //-----------------------------------------------------------------------------
  3304. // Maintain position along a path
  3305. //-----------------------------------------------------------------------------
  3306. struct SequentialPositionContext_t
  3307. {
  3308. int m_nParticleCount;
  3309. float m_flStep;
  3310. int m_nCountAmount;
  3311. };
  3312. class C_OP_MaintainSequentialPath : public CParticleOperatorInstance
  3313. {
  3314. DECLARE_PARTICLE_OPERATOR( C_OP_MaintainSequentialPath );
  3315. float m_fMaxDistance;
  3316. float m_flNumToAssign;
  3317. bool m_bLoop;
  3318. float m_flCohesionStrength;
  3319. struct CPathParameters m_PathParams;
  3320. uint32 GetWrittenAttributes( void ) const
  3321. {
  3322. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  3323. }
  3324. uint32 GetReadAttributes( void ) const
  3325. {
  3326. return 0;
  3327. }
  3328. virtual uint64 GetReadControlPointMask() const
  3329. {
  3330. uint64 nStartMask = ( 1ULL << m_PathParams.m_nStartControlPointNumber ) - 1;
  3331. uint64 nEndMask = ( 1ULL << ( m_PathParams.m_nEndControlPointNumber + 1 ) ) - 1;
  3332. return nEndMask & (~nStartMask);
  3333. }
  3334. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  3335. {
  3336. SequentialPositionContext_t *pCtx = reinterpret_cast<SequentialPositionContext_t *>( pContext );
  3337. pCtx->m_nParticleCount = 0;
  3338. if ( m_flNumToAssign > 1.0f )
  3339. {
  3340. pCtx->m_flStep = 1.0f / ( m_flNumToAssign - 1 );
  3341. }
  3342. else
  3343. {
  3344. pCtx->m_flStep = 0.0f;
  3345. }
  3346. pCtx->m_nCountAmount = 1;
  3347. }
  3348. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  3349. {
  3350. m_PathParams.ClampControlPointIndices();
  3351. }
  3352. size_t GetRequiredContextBytes( void ) const
  3353. {
  3354. return sizeof( SequentialPositionContext_t );
  3355. }
  3356. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  3357. };
  3358. DEFINE_PARTICLE_OPERATOR( C_OP_MaintainSequentialPath, "Movement Maintain Position Along Path", OPERATOR_GENERIC );
  3359. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_MaintainSequentialPath )
  3360. DMXELEMENT_UNPACK_FIELD( "maximum distance", "0", float, m_fMaxDistance )
  3361. DMXELEMENT_UNPACK_FIELD( "bulge", "0", float, m_PathParams.m_flBulge )
  3362. DMXELEMENT_UNPACK_FIELD( "start control point number", "0", int, m_PathParams.m_nStartControlPointNumber )
  3363. DMXELEMENT_UNPACK_FIELD( "end control point number", "0", int, m_PathParams.m_nEndControlPointNumber )
  3364. DMXELEMENT_UNPACK_FIELD( "bulge control 0=random 1=orientation of start pnt 2=orientation of end point", "0", int, m_PathParams.m_nBulgeControl )
  3365. DMXELEMENT_UNPACK_FIELD( "mid point position", "0.5", float, m_PathParams.m_flMidPoint )
  3366. DMXELEMENT_UNPACK_FIELD( "particles to map from start to end", "100", float, m_flNumToAssign )
  3367. DMXELEMENT_UNPACK_FIELD( "restart behavior (0 = bounce, 1 = loop )", "1", bool, m_bLoop )
  3368. DMXELEMENT_UNPACK_FIELD( "cohesion strength", "1", float, m_flCohesionStrength )
  3369. END_PARTICLE_OPERATOR_UNPACK( C_OP_MaintainSequentialPath )
  3370. void C_OP_MaintainSequentialPath::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  3371. {
  3372. // NOTE: Using C_OP_ContinuousEmitter:: avoids a virtual function call
  3373. SequentialPositionContext_t *pCtx = reinterpret_cast<SequentialPositionContext_t *>( pContext );
  3374. float fl_Cohesion = ( 1 - m_flCohesionStrength );
  3375. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  3376. {
  3377. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, i );
  3378. float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  3379. Vector StartPnt, MidP, EndPnt;
  3380. pParticles->CalculatePathValues( m_PathParams, pParticles->m_flCurTime, &StartPnt, &MidP, &EndPnt);
  3381. if ( pCtx->m_nParticleCount >= m_flNumToAssign || pCtx->m_nParticleCount < 0 )
  3382. {
  3383. if ( m_bLoop )
  3384. {
  3385. pCtx->m_nParticleCount = 0;
  3386. }
  3387. else
  3388. {
  3389. pCtx->m_nCountAmount *= -1;
  3390. pCtx->m_nParticleCount = min ( pCtx->m_nParticleCount, (int)( m_flNumToAssign - 1) );
  3391. pCtx->m_nParticleCount = max ( pCtx->m_nParticleCount, 1 );
  3392. }
  3393. }
  3394. float t= pCtx->m_nParticleCount * pCtx->m_flStep;
  3395. // form delta terms needed for quadratic bezier
  3396. Vector Delta0=MidP-StartPnt;
  3397. Vector Delta1 = EndPnt-MidP;
  3398. Vector L0 = StartPnt+t*Delta0;
  3399. Vector L1 = MidP+t*Delta1;
  3400. Vector Pnt = L0+(L1-L0)*t;
  3401. // Allow an offset distance and position lerp
  3402. Vector vecXYZ;
  3403. Vector vecPXYZ;
  3404. SetVectorFromAttribute( vecXYZ, xyz );
  3405. SetVectorFromAttribute( vecPXYZ, pxyz );
  3406. vecXYZ -= Pnt;
  3407. vecPXYZ -= Pnt;
  3408. float flXYZOffset = min (vecXYZ.Length(), m_fMaxDistance );
  3409. float flPXYZOffset = min (vecPXYZ.Length(), m_fMaxDistance );
  3410. VectorNormalizeFast( vecXYZ );
  3411. vecXYZ *= flXYZOffset * fl_Cohesion;
  3412. VectorNormalizeFast( vecPXYZ );
  3413. vecPXYZ *= flPXYZOffset * fl_Cohesion;
  3414. vecXYZ += Pnt;
  3415. vecPXYZ += Pnt;
  3416. xyz[0] = vecXYZ.x;
  3417. xyz[4] = vecXYZ.y;
  3418. xyz[8] = vecXYZ.z;
  3419. pxyz[0] = vecPXYZ.x;
  3420. pxyz[4] = vecPXYZ.y;
  3421. pxyz[8] = vecPXYZ.z;
  3422. pCtx->m_nParticleCount += pCtx->m_nCountAmount;
  3423. }
  3424. }
  3425. //-----------------------------------------------------------------------------
  3426. // Remap Dot Product to Scalar Operator
  3427. //-----------------------------------------------------------------------------
  3428. class C_OP_RemapDotProductToScalar : public CParticleOperatorInstance
  3429. {
  3430. DECLARE_PARTICLE_OPERATOR( C_OP_RemapDotProductToScalar );
  3431. uint32 GetWrittenAttributes( void ) const
  3432. {
  3433. return 1 << m_nFieldOutput;
  3434. }
  3435. uint32 GetReadAttributes( void ) const
  3436. {
  3437. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  3438. }
  3439. virtual uint64 GetReadControlPointMask() const
  3440. {
  3441. return ( 1ULL << m_nInputCP1 ) | ( 1ULL << m_nInputCP2 );
  3442. }
  3443. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  3444. int m_nInputCP1;
  3445. int m_nInputCP2;
  3446. int m_nFieldOutput;
  3447. float m_flInputMin;
  3448. float m_flInputMax;
  3449. float m_flOutputMin;
  3450. float m_flOutputMax;
  3451. bool m_bUseParticleVelocity;
  3452. bool m_bScaleInitialRange;
  3453. bool m_bActiveRange;
  3454. };
  3455. DEFINE_PARTICLE_OPERATOR( C_OP_RemapDotProductToScalar, "Remap Dot Product to Scalar", OPERATOR_GENERIC );
  3456. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RemapDotProductToScalar )
  3457. DMXELEMENT_UNPACK_FIELD( "use particle velocity for first input", "0", bool, m_bUseParticleVelocity )
  3458. DMXELEMENT_UNPACK_FIELD( "first input control point", "0", int, m_nInputCP1 )
  3459. DMXELEMENT_UNPACK_FIELD( "second input control point", "0", int, m_nInputCP2 )
  3460. DMXELEMENT_UNPACK_FIELD( "input minimum (-1 to 1)","0", float, m_flInputMin )
  3461. DMXELEMENT_UNPACK_FIELD( "input maximum (-1 to 1)","1", float, m_flInputMax )
  3462. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "3", int, m_nFieldOutput, "intchoice particlefield_scalar" )
  3463. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  3464. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  3465. DMXELEMENT_UNPACK_FIELD( "output is scalar of initial random range","0", bool, m_bScaleInitialRange )
  3466. DMXELEMENT_UNPACK_FIELD( "only active within specified input range","0", bool, m_bActiveRange )
  3467. END_PARTICLE_OPERATOR_UNPACK( C_OP_RemapDotProductToScalar )
  3468. void C_OP_RemapDotProductToScalar::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  3469. {
  3470. // clamp the result to 0 and 1 if it's alpha
  3471. float flMin=m_flOutputMin;
  3472. float flMax=m_flOutputMax;
  3473. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & ( 1 << m_nFieldOutput ) )
  3474. {
  3475. flMin = clamp(m_flOutputMin, 0.0f, 1.0f );
  3476. flMax = clamp(m_flOutputMax, 0.0f, 1.0f );
  3477. }
  3478. Vector vecInput1;
  3479. Vector vecInput2;
  3480. CParticleSIMDTransformation pXForm1;
  3481. CParticleSIMDTransformation pXForm2;
  3482. pParticles->GetControlPointTransformAtTime( m_nInputCP1, pParticles->m_flCurTime, &pXForm1 );
  3483. pParticles->GetControlPointTransformAtTime( m_nInputCP2, pParticles->m_flCurTime, &pXForm2 );
  3484. vecInput1 = pXForm1.m_v4Fwd.Vec( 0 );
  3485. vecInput2 = pXForm2.m_v4Fwd.Vec( 0 );
  3486. float flInput = DotProduct( vecInput1, vecInput2 );
  3487. // only use within start/end time frame and, if set, active input range
  3488. if ( ( m_bActiveRange && !m_bUseParticleVelocity && ( flInput < m_flInputMin || flInput > m_flInputMax ) ) )
  3489. return;
  3490. // FIXME: SSE-ize
  3491. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  3492. {
  3493. if ( m_bUseParticleVelocity )
  3494. {
  3495. const float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, i );
  3496. const float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, i );
  3497. Vector vecXYZ;
  3498. Vector vecPXYZ;
  3499. vecXYZ.x = xyz[0];
  3500. vecXYZ.y = xyz[4];
  3501. vecXYZ.z = xyz[8];
  3502. vecPXYZ.x = pxyz[0];
  3503. vecPXYZ.y = pxyz[4];
  3504. vecPXYZ.z = pxyz[8];
  3505. vecInput1 = vecXYZ - vecPXYZ;
  3506. VectorNormalizeFast( vecInput1 );
  3507. float flInputDot = DotProduct( vecInput1, vecInput2 );
  3508. // only use within start/end time frame and, if set, active input range
  3509. if ( ( m_bActiveRange && (flInputDot < m_flInputMin || flInputDot > m_flInputMax ) ) )
  3510. continue;
  3511. }
  3512. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, i );
  3513. float flOutput = RemapValClamped( flInput, m_flInputMin, m_flInputMax, flMin, flMax );
  3514. if ( m_bScaleInitialRange )
  3515. {
  3516. flOutput *= *pOutput;
  3517. }
  3518. if ( ATTRIBUTES_WHICH_ARE_INTS & ( 1 << m_nFieldOutput ) )
  3519. {
  3520. *pOutput = int ( flOutput );
  3521. }
  3522. else
  3523. {
  3524. *pOutput = flOutput;
  3525. }
  3526. }
  3527. }
  3528. //-----------------------------------------------------------------------------
  3529. // Remap CP to Scalar Operator
  3530. //-----------------------------------------------------------------------------
  3531. class C_OP_RemapCPtoScalar : public CParticleOperatorInstance
  3532. {
  3533. DECLARE_PARTICLE_OPERATOR( C_OP_RemapCPtoScalar );
  3534. uint32 GetWrittenAttributes( void ) const
  3535. {
  3536. return 1 << m_nFieldOutput;
  3537. }
  3538. uint32 GetReadAttributes( void ) const
  3539. {
  3540. return 0;
  3541. }
  3542. virtual uint64 GetReadControlPointMask() const
  3543. {
  3544. return 1ULL << m_nCPInput;
  3545. }
  3546. virtual void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  3547. {
  3548. m_nField = int (clamp (m_nField, 0, 2));
  3549. }
  3550. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  3551. int m_nCPInput;
  3552. int m_nFieldOutput;
  3553. int m_nField;
  3554. float m_flInputMin;
  3555. float m_flInputMax;
  3556. float m_flOutputMin;
  3557. float m_flOutputMax;
  3558. float m_flStartTime;
  3559. float m_flEndTime;
  3560. bool m_bScaleInitialRange;
  3561. };
  3562. DEFINE_PARTICLE_OPERATOR( C_OP_RemapCPtoScalar, "Remap Control Point to Scalar", OPERATOR_GENERIC );
  3563. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RemapCPtoScalar )
  3564. DMXELEMENT_UNPACK_FIELD( "emitter lifetime start time (seconds)", "-1", float, m_flStartTime )
  3565. DMXELEMENT_UNPACK_FIELD( "emitter lifetime end time (seconds)", "-1", float, m_flEndTime )
  3566. DMXELEMENT_UNPACK_FIELD( "input control point number", "0", int, m_nCPInput )
  3567. DMXELEMENT_UNPACK_FIELD( "input minimum","0", float, m_flInputMin )
  3568. DMXELEMENT_UNPACK_FIELD( "input maximum","1", float, m_flInputMax )
  3569. DMXELEMENT_UNPACK_FIELD( "input field 0-2 X/Y/Z","0", int, m_nField )
  3570. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "3", int, m_nFieldOutput, "intchoice particlefield_scalar" )
  3571. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  3572. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  3573. DMXELEMENT_UNPACK_FIELD( "output is scalar of initial random range","0", bool, m_bScaleInitialRange )
  3574. END_PARTICLE_OPERATOR_UNPACK( C_OP_RemapCPtoScalar )
  3575. void C_OP_RemapCPtoScalar::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  3576. {
  3577. const float *pCreationTime;
  3578. // clamp the result to 0 and 1 if it's alpha
  3579. float flMin=m_flOutputMin;
  3580. float flMax=m_flOutputMax;
  3581. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & ( 1 << m_nFieldOutput ) )
  3582. {
  3583. flMin = clamp(m_flOutputMin, 0.0f, 1.0f );
  3584. flMax = clamp(m_flOutputMax, 0.0f, 1.0f );
  3585. }
  3586. Vector vecControlPoint = pParticles->GetControlPointAtCurrentTime( m_nCPInput );
  3587. float flInput = vecControlPoint[m_nField];
  3588. // FIXME: SSE-ize
  3589. for( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  3590. {
  3591. pCreationTime = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, i );
  3592. // using raw creation time to map to emitter lifespan
  3593. float flLifeTime = *pCreationTime;
  3594. // only use within start/end time frame
  3595. if ( ( ( flLifeTime < m_flStartTime ) || ( flLifeTime >= m_flEndTime ) ) && ( ( m_flStartTime != -1.0f) && ( m_flEndTime != -1.0f) ) )
  3596. continue;
  3597. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, i );
  3598. float flOutput = RemapValClamped( flInput, m_flInputMin, m_flInputMax, flMin, flMax );
  3599. if ( m_bScaleInitialRange )
  3600. {
  3601. flOutput = *pOutput * flOutput;
  3602. }
  3603. if ( ATTRIBUTES_WHICH_ARE_INTS & ( 1 << m_nFieldOutput ) )
  3604. {
  3605. *pOutput = int ( flOutput );
  3606. }
  3607. else
  3608. {
  3609. *pOutput = flOutput;
  3610. }
  3611. }
  3612. }
  3613. //-----------------------------------------------------------------------------
  3614. // Rotate Particle around axis
  3615. //-----------------------------------------------------------------------------
  3616. class C_OP_MovementRotateParticleAroundAxis : public CParticleOperatorInstance
  3617. {
  3618. DECLARE_PARTICLE_OPERATOR( C_OP_MovementRotateParticleAroundAxis );
  3619. Vector m_vecRotAxis;
  3620. float m_flRotRate;
  3621. int m_nCP;
  3622. bool m_bLocalSpace;
  3623. uint32 GetWrittenAttributes( void ) const
  3624. {
  3625. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK ;
  3626. }
  3627. uint32 GetReadAttributes( void ) const
  3628. {
  3629. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK ;
  3630. }
  3631. virtual uint64 GetReadControlPointMask() const
  3632. {
  3633. return 1ULL << m_nCP;
  3634. }
  3635. void InitParams( CParticleSystemDefinition *pDef )
  3636. {
  3637. VectorNormalize( m_vecRotAxis );
  3638. }
  3639. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  3640. };
  3641. DEFINE_PARTICLE_OPERATOR( C_OP_MovementRotateParticleAroundAxis , "Movement Rotate Particle Around Axis", OPERATOR_GENERIC );
  3642. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_MovementRotateParticleAroundAxis )
  3643. DMXELEMENT_UNPACK_FIELD( "Rotation Axis", "0 0 1", Vector, m_vecRotAxis )
  3644. DMXELEMENT_UNPACK_FIELD( "Rotation Rate", "180", float, m_flRotRate )
  3645. DMXELEMENT_UNPACK_FIELD( "Control Point", "0", int, m_nCP )
  3646. DMXELEMENT_UNPACK_FIELD( "Use Local Space", "0", bool, m_bLocalSpace )
  3647. END_PARTICLE_OPERATOR_UNPACK( C_OP_MovementRotateParticleAroundAxis )
  3648. void C_OP_MovementRotateParticleAroundAxis::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  3649. {
  3650. float flRotRate = m_flRotRate * pParticles->m_flDt;
  3651. matrix3x4_t matRot;
  3652. Vector vecRotAxis = m_vecRotAxis;
  3653. if ( m_bLocalSpace )
  3654. {
  3655. matrix3x4_t matLocalCP;
  3656. pParticles->GetControlPointTransformAtCurrentTime( m_nCP, &matLocalCP );
  3657. VectorRotate( m_vecRotAxis, matLocalCP, vecRotAxis );
  3658. }
  3659. MatrixBuildRotationAboutAxis ( vecRotAxis, flRotRate, matRot );
  3660. Vector vecCPPos = pParticles->GetControlPointAtCurrentTime( m_nCP );
  3661. FourVectors fvCPPos;
  3662. fvCPPos.DuplicateVector( vecCPPos );
  3663. fltx4 fl4Strength = ReplicateX4( flStrength );
  3664. C4VAttributeWriteIterator pXYZ( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  3665. C4VAttributeWriteIterator pPrevXYZ( PARTICLE_ATTRIBUTE_PREV_XYZ, pParticles );
  3666. int nCtr = pParticles->m_nPaddedActiveParticles;
  3667. do
  3668. {
  3669. FourVectors fvCurPos = *pXYZ;
  3670. fvCurPos -= fvCPPos;
  3671. FourVectors fvPrevPos = *pPrevXYZ;
  3672. fvPrevPos -= fvCPPos;
  3673. fvCurPos.RotateBy( matRot );
  3674. fvPrevPos.RotateBy( matRot );
  3675. fvCurPos += fvCPPos;
  3676. fvCurPos -= *pXYZ;
  3677. fvCurPos *= fl4Strength;
  3678. *pXYZ += fvCurPos;
  3679. fvPrevPos += fvCPPos;
  3680. fvPrevPos -= *pPrevXYZ;
  3681. fvPrevPos *= fl4Strength;
  3682. *pPrevXYZ += fvPrevPos;
  3683. ++pXYZ;
  3684. ++pPrevXYZ;
  3685. } while ( --nCtr );
  3686. };
  3687. //-----------------------------------------------------------------------------
  3688. // Remap Speed to CP Operator
  3689. //-----------------------------------------------------------------------------
  3690. class C_OP_RemapSpeedtoCP : public CParticleOperatorInstance
  3691. {
  3692. DECLARE_PARTICLE_OPERATOR( C_OP_RemapSpeedtoCP );
  3693. uint32 GetWrittenAttributes( void ) const
  3694. {
  3695. return 0;
  3696. }
  3697. uint32 GetReadAttributes( void ) const
  3698. {
  3699. return 0;
  3700. }
  3701. virtual uint64 GetReadControlPointMask() const
  3702. {
  3703. return ( 1ULL << m_nInControlPointNumber ) | ( 1ULL << m_nOutControlPointNumber );
  3704. }
  3705. bool ShouldRunBeforeEmitters( void ) const
  3706. {
  3707. return true;
  3708. }
  3709. virtual void InitParams(CParticleSystemDefinition *pDef )
  3710. {
  3711. // Safety for bogus input->output feedback loop
  3712. if ( m_nInControlPointNumber == m_nOutControlPointNumber )
  3713. m_nOutControlPointNumber = -1;
  3714. }
  3715. virtual void Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const;
  3716. int m_nInControlPointNumber;
  3717. int m_nOutControlPointNumber;
  3718. int m_nField;
  3719. float m_flInputMin;
  3720. float m_flInputMax;
  3721. float m_flOutputMin;
  3722. float m_flOutputMax;
  3723. };
  3724. DEFINE_PARTICLE_OPERATOR( C_OP_RemapSpeedtoCP, "Remap CP Speed to CP", OPERATOR_GENERIC );
  3725. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RemapSpeedtoCP )
  3726. DMXELEMENT_UNPACK_FIELD( "input control point", "0", int, m_nInControlPointNumber )
  3727. DMXELEMENT_UNPACK_FIELD( "input minimum","0", float, m_flInputMin )
  3728. DMXELEMENT_UNPACK_FIELD( "input maximum","1", float, m_flInputMax )
  3729. DMXELEMENT_UNPACK_FIELD( "output control point", "-1", int, m_nOutControlPointNumber )
  3730. DMXELEMENT_UNPACK_FIELD( "Output field 0-2 X/Y/Z","0", int, m_nField )
  3731. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  3732. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  3733. END_PARTICLE_OPERATOR_UNPACK( C_OP_RemapSpeedtoCP );
  3734. void C_OP_RemapSpeedtoCP::Operate( CParticleCollection *pParticles, float flStrength, void *pContext ) const
  3735. {
  3736. if ( m_nOutControlPointNumber >= 0 )
  3737. {
  3738. Vector vecPrevPos;
  3739. pParticles->GetControlPointAtPrevTime( m_nInControlPointNumber, &vecPrevPos );
  3740. Vector vecDelta;
  3741. vecDelta = pParticles->GetControlPointAtCurrentTime( m_nInControlPointNumber ) - vecPrevPos;
  3742. float flSpeed = vecDelta.Length() / pParticles->m_flPreviousDt;
  3743. float flOutput = RemapValClamped( flSpeed, m_flInputMin, m_flInputMax, m_flOutputMin, m_flOutputMax );
  3744. Vector vecControlPoint = pParticles->GetControlPointAtCurrentTime( m_nOutControlPointNumber );
  3745. vecControlPoint[m_nField] = flOutput;
  3746. pParticles->SetControlPoint( m_nOutControlPointNumber, vecControlPoint );
  3747. }
  3748. }
  3749. void AddBuiltInParticleOperators( void )
  3750. {
  3751. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_BasicMovement );
  3752. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_Decay );
  3753. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_VelocityDecay );
  3754. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_FadeAndKill );
  3755. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_FadeIn );
  3756. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_FadeOut );
  3757. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_Spin );
  3758. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_SpinUpdate );
  3759. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_SpinYaw );
  3760. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_OrientTo2dDirection );
  3761. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_Orient2DRelToCP );
  3762. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_InterpolateRadius );
  3763. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_ColorInterpolate );
  3764. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_OscillateScalar );
  3765. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_OscillateVector );
  3766. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_DampenToCP );
  3767. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_PositionLock );
  3768. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_LockToBone );
  3769. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_DistanceBetweenCPs );
  3770. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_DistanceToCP );
  3771. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_SetControlPointToPlayer );
  3772. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_SetControlPointToCenter );
  3773. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_SetChildControlPoints );
  3774. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_SetControlPointPositions );
  3775. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_PlaneCull );
  3776. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_ModelCull );
  3777. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_Cull );
  3778. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_ControlpointLight );
  3779. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_RemapScalar );
  3780. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_Noise );
  3781. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_VectorNoise );
  3782. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_VelocityMatchingForce );
  3783. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_MaxVelocity );
  3784. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_MaintainSequentialPath );
  3785. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_RemapDotProductToScalar );
  3786. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_RemapCPtoScalar );
  3787. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_MovementRotateParticleAroundAxis );
  3788. REGISTER_PARTICLE_OPERATOR( FUNCTION_OPERATOR, C_OP_RemapSpeedtoCP );
  3789. }