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.

4741 lines
157 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 "dmxloader/dmxelement.h"
  15. #include "psheet.h"
  16. #include "bspflags.h"
  17. #include "const.h"
  18. #include "particles_internal.h"
  19. // memdbgon must be the last include file in a .cpp file!!!
  20. #include "tier0/memdbgon.h"
  21. void CParticleOperatorInstance::InitScalarAttributeRandomRangeBlock(
  22. int attr_num, float fMin, float fMax,
  23. CParticleCollection *pParticles, int start_block, int n_blocks ) const
  24. {
  25. size_t attr_stride;
  26. fltx4 *pAttr = pParticles->GetM128AttributePtrForWrite( attr_num, &attr_stride );
  27. pAttr += attr_stride * start_block;
  28. fltx4 val0 = ReplicateX4( fMin );
  29. fltx4 val_d = ReplicateX4( fMax - fMin );
  30. int nRandContext = GetSIMDRandContext();
  31. while( n_blocks-- )
  32. {
  33. *( pAttr ) = AddSIMD( val0, MulSIMD( RandSIMD( nRandContext ), val_d ) );
  34. pAttr += attr_stride;
  35. }
  36. ReleaseSIMDRandContext( nRandContext );
  37. }
  38. void CParticleOperatorInstance::InitScalarAttributeRandomRangeExpBlock(
  39. int attr_num, float fMin, float fMax, float fExp,
  40. CParticleCollection *pParticles, int start_block, int n_blocks ) const
  41. {
  42. size_t attr_stride;
  43. fltx4 *pAttr = pParticles->GetM128AttributePtrForWrite( attr_num, &attr_stride );
  44. pAttr += attr_stride * start_block;
  45. fltx4 val0 = ReplicateX4( fMin );
  46. fltx4 val_d = ReplicateX4( fMax - fMin );
  47. //fltx4 val_e = ReplicateX4( fExp );
  48. int nExp = (int)(4.0f * fExp);
  49. int nRandContext = GetSIMDRandContext();
  50. while( n_blocks-- )
  51. {
  52. *( pAttr ) = AddSIMD( val0, MulSIMD( Pow_FixedPoint_Exponent_SIMD( RandSIMD( nRandContext ), nExp ), val_d ) );
  53. pAttr += attr_stride;
  54. }
  55. ReleaseSIMDRandContext( nRandContext );
  56. }
  57. void CParticleOperatorInstance::AddScalarAttributeRandomRangeBlock(
  58. int nAttributeId, float fMin, float fMax, float fExp,
  59. CParticleCollection *pParticles, int nStartBlock, int nBlockCount, bool bRandomlyInvert ) const
  60. {
  61. size_t nAttrStride;
  62. fltx4 *pAttr = pParticles->GetM128AttributePtrForWrite( nAttributeId, &nAttrStride );
  63. pAttr += nAttrStride * nStartBlock;
  64. fltx4 val0 = ReplicateX4( fMin );
  65. fltx4 val_d = ReplicateX4( fMax - fMin );
  66. int nRandContext = GetSIMDRandContext();
  67. if ( !bRandomlyInvert )
  68. {
  69. if ( fExp != 1.0f )
  70. {
  71. int nExp = (int)(4.0f * fExp);
  72. while( nBlockCount-- )
  73. {
  74. *( pAttr ) = AddSIMD( *pAttr, AddSIMD( val0, MulSIMD( Pow_FixedPoint_Exponent_SIMD( RandSIMD( nRandContext ), nExp ), val_d ) ) );
  75. pAttr += nAttrStride;
  76. }
  77. }
  78. else
  79. {
  80. while( nBlockCount-- )
  81. {
  82. *pAttr = AddSIMD( *pAttr, AddSIMD( val0, MulSIMD( RandSIMD( nRandContext ), val_d ) ) );
  83. pAttr += nAttrStride;
  84. }
  85. }
  86. }
  87. else
  88. {
  89. fltx4 fl4NegOne = ReplicateX4( -1.0f );
  90. if ( fExp != 1.0f )
  91. {
  92. int nExp = (int)(4.0f * fExp);
  93. while( nBlockCount-- )
  94. {
  95. fltx4 fl4RandVal = AddSIMD( val0, MulSIMD( Pow_FixedPoint_Exponent_SIMD( RandSIMD( nRandContext ), nExp ), val_d ) );
  96. fltx4 fl4Sign = MaskedAssign( CmpGeSIMD( RandSIMD( nRandContext ), Four_PointFives ), Four_Ones, fl4NegOne );
  97. *pAttr = AddSIMD( *pAttr, MulSIMD( fl4RandVal, fl4Sign ) );
  98. pAttr += nAttrStride;
  99. }
  100. }
  101. else
  102. {
  103. while( nBlockCount-- )
  104. {
  105. fltx4 fl4RandVal = AddSIMD( val0, MulSIMD( RandSIMD( nRandContext ), val_d ) );
  106. fltx4 fl4Sign = MaskedAssign( CmpGeSIMD( RandSIMD( nRandContext ), Four_PointFives ), Four_Ones, fl4NegOne );
  107. *pAttr = AddSIMD( *pAttr, MulSIMD( fl4RandVal, fl4Sign ) );
  108. pAttr += nAttrStride;
  109. }
  110. }
  111. }
  112. ReleaseSIMDRandContext( nRandContext );
  113. }
  114. class C_INIT_CreateOnModel : public CParticleOperatorInstance
  115. {
  116. DECLARE_PARTICLE_OPERATOR( C_INIT_CreateOnModel );
  117. int m_nControlPointNumber;
  118. int m_nForceInModel;
  119. float m_flHitBoxScale;
  120. Vector m_vecDirectionBias;
  121. uint32 GetWrittenAttributes( void ) const
  122. {
  123. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK |
  124. PARTICLE_ATTRIBUTE_HITBOX_RELATIVE_XYZ_MASK | PARTICLE_ATTRIBUTE_HITBOX_INDEX_MASK;
  125. }
  126. uint32 GetReadAttributes( void ) const
  127. {
  128. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  129. }
  130. virtual uint64 GetReadControlPointMask() const
  131. {
  132. return 1ULL << m_nControlPointNumber;
  133. }
  134. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  135. int nParticleCount, int nAttributeWriteMask,
  136. void *pContext) const;
  137. };
  138. DEFINE_PARTICLE_OPERATOR( C_INIT_CreateOnModel, "Position on Model Random", OPERATOR_PI_POSITION );
  139. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_CreateOnModel )
  140. DMXELEMENT_UNPACK_FIELD( "control_point_number", "0", int, m_nControlPointNumber )
  141. DMXELEMENT_UNPACK_FIELD( "force to be inside model", "0", int, m_nForceInModel )
  142. DMXELEMENT_UNPACK_FIELD( "hitbox scale", "1.0", int, m_flHitBoxScale )
  143. DMXELEMENT_UNPACK_FIELD( "direction bias", "0 0 0", Vector, m_vecDirectionBias )
  144. END_PARTICLE_OPERATOR_UNPACK( C_INIT_CreateOnModel )
  145. void C_INIT_CreateOnModel::InitNewParticlesScalar(
  146. CParticleCollection *pParticles, int start_p,
  147. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  148. {
  149. pParticles->UpdateHitBoxInfo( m_nControlPointNumber );
  150. while( nParticleCount )
  151. {
  152. Vector vecPnts[100]; // minimize stack usage
  153. Vector vecUVW[100];
  154. int nHitBoxIndex[100];
  155. int nToDo = min( (int)ARRAYSIZE( vecPnts ), nParticleCount );
  156. Assert( m_nControlPointNumber <= pParticles->GetHighestControlPoint() );
  157. g_pParticleSystemMgr->Query()->GetRandomPointsOnControllingObjectHitBox(
  158. pParticles, m_nControlPointNumber,
  159. nToDo, m_flHitBoxScale, m_nForceInModel, vecPnts, m_vecDirectionBias, vecUVW,
  160. nHitBoxIndex );
  161. for( int i=0; i<nToDo; i++)
  162. {
  163. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, start_p );
  164. float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, start_p );
  165. float *pHitboxRelXYZ = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_HITBOX_RELATIVE_XYZ, start_p );
  166. int *pHitboxIndex = pParticles->GetIntAttributePtrForWrite( PARTICLE_ATTRIBUTE_HITBOX_INDEX, start_p );
  167. start_p++;
  168. Vector randpos = vecPnts[i];
  169. xyz[0] = randpos.x;
  170. xyz[4] = randpos.y;
  171. xyz[8] = randpos.z;
  172. if ( pxyz && ( nAttributeWriteMask & PARTICLE_ATTRIBUTE_PREV_XYZ_MASK ) )
  173. {
  174. pxyz[0] = randpos.x;
  175. pxyz[4] = randpos.y;
  176. pxyz[8] = randpos.z;
  177. }
  178. if ( pHitboxRelXYZ && ( nAttributeWriteMask & PARTICLE_ATTRIBUTE_HITBOX_RELATIVE_XYZ_MASK ) )
  179. {
  180. pHitboxRelXYZ[0] = vecUVW[i].x;
  181. pHitboxRelXYZ[4] = vecUVW[i].y;
  182. pHitboxRelXYZ[8] = vecUVW[i].z;
  183. }
  184. if ( pHitboxIndex && ( nAttributeWriteMask & PARTICLE_ATTRIBUTE_HITBOX_INDEX_MASK ) )
  185. {
  186. *pHitboxIndex = nHitBoxIndex[i];
  187. }
  188. }
  189. nParticleCount -= nToDo;
  190. }
  191. }
  192. static inline void RandomPointOnUnitSphere( int nRandContext, FourVectors &out )
  193. {
  194. // generate 4 random points on the unit sphere. uses Marsaglia (1972) method from
  195. // http://mathworld.wolfram.com/SpherePointPicking.html
  196. fltx4 f4x1 = SubSIMD( MulSIMD( Four_Twos, RandSIMD( nRandContext ) ), Four_Ones ); // -1..1
  197. fltx4 f4x2 = SubSIMD( MulSIMD( Four_Twos, RandSIMD( nRandContext ) ), Four_Ones ); // -1..1
  198. fltx4 f4x1SQ = MulSIMD( f4x1, f4x1 );
  199. fltx4 f4x2SQ = MulSIMD( f4x2, f4x2 );
  200. fltx4 badMask = CmpGeSIMD( AddSIMD( f4x1SQ, f4x2SQ ), Four_Ones );
  201. while( IsAnyNegative( badMask ) )
  202. {
  203. f4x1 = MaskedAssign( badMask, SubSIMD( MulSIMD( Four_Twos, RandSIMD( nRandContext ) ), Four_Ones ), f4x1 );
  204. f4x2 = MaskedAssign( badMask, SubSIMD( MulSIMD( Four_Twos, RandSIMD( nRandContext ) ), Four_Ones ), f4x2 );
  205. f4x1SQ = MulSIMD( f4x1, f4x1 );
  206. f4x2SQ = MulSIMD( f4x2, f4x2 );
  207. badMask = CmpGeSIMD( AddSIMD( f4x1SQ, f4x2SQ ), Four_Ones );
  208. }
  209. // now, we have 2 points on the unit circle
  210. fltx4 f4OuterArea = SqrtEstSIMD( SubSIMD( Four_Ones, SubSIMD( f4x1SQ, f4x2SQ ) ) );
  211. out.x = MulSIMD( AddSIMD( f4x1, f4x1 ), f4OuterArea );
  212. out.y = MulSIMD( AddSIMD( f4x2, f4x2 ), f4OuterArea );
  213. out.z = SubSIMD( Four_Ones, MulSIMD( Four_Twos, AddSIMD( f4x1, f4x2 ) ) );
  214. }
  215. static inline void RandomPointInUnitSphere( int nRandContext, FourVectors &out )
  216. {
  217. // generate 4 random points inside the unit sphere. uses rejection method.
  218. out.x = SubSIMD( MulSIMD( Four_Twos, RandSIMD( nRandContext ) ), Four_Ones ); // -1..1
  219. out.y = SubSIMD( MulSIMD( Four_Twos, RandSIMD( nRandContext ) ), Four_Ones ); // -1..1
  220. out.z = SubSIMD( MulSIMD( Four_Twos, RandSIMD( nRandContext ) ), Four_Ones ); // -1..1
  221. fltx4 f4xSQ = MulSIMD( out.x, out.x );
  222. fltx4 f4ySQ = MulSIMD( out.y, out.y );
  223. fltx4 f4zSQ = MulSIMD( out.z, out.z );
  224. fltx4 badMask = CmpGtSIMD( AddSIMD( AddSIMD( f4xSQ, f4ySQ ), f4zSQ ), Four_Ones );
  225. while( IsAnyNegative( badMask ) )
  226. {
  227. out.x = MaskedAssign( badMask, SubSIMD( MulSIMD( Four_Twos, RandSIMD( nRandContext ) ), Four_Ones ), out.x );
  228. out.y = MaskedAssign( badMask, SubSIMD( MulSIMD( Four_Twos, RandSIMD( nRandContext ) ), Four_Ones ), out.y );
  229. out.z = MaskedAssign( badMask, SubSIMD( MulSIMD( Four_Twos, RandSIMD( nRandContext ) ), Four_Ones ), out.z );
  230. f4xSQ = MulSIMD( out.x, out.x );
  231. f4ySQ = MulSIMD( out.y, out.y );
  232. f4zSQ = MulSIMD( out.z, out.z );
  233. badMask = CmpGeSIMD( AddSIMD( AddSIMD( f4xSQ, f4ySQ ), f4zSQ ), Four_Ones );
  234. }
  235. }
  236. class C_INIT_CreateWithinSphere : public CParticleOperatorInstance
  237. {
  238. DECLARE_PARTICLE_OPERATOR( C_INIT_CreateWithinSphere );
  239. float m_fRadiusMin;
  240. float m_fRadiusMax;
  241. Vector m_vecDistanceBias, m_vecDistanceBiasAbs;
  242. int m_nControlPointNumber;
  243. float m_fSpeedMin;
  244. float m_fSpeedMax;
  245. float m_fSpeedRandExp;
  246. bool m_bLocalCoords;
  247. bool m_bDistanceBiasAbs;
  248. bool m_bUseHighestEndCP;
  249. bool m_bDistanceBias;
  250. float m_flEndCPGrowthTime;
  251. Vector m_LocalCoordinateSystemSpeedMin;
  252. Vector m_LocalCoordinateSystemSpeedMax;
  253. int m_nCreateInModel;
  254. uint32 GetWrittenAttributes( void ) const
  255. {
  256. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  257. }
  258. uint32 GetReadAttributes( void ) const
  259. {
  260. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  261. }
  262. virtual uint64 GetReadControlPointMask() const
  263. {
  264. if ( !m_bUseHighestEndCP )
  265. return 1ULL << m_nControlPointNumber;
  266. return ~( ( 1ULL << m_nControlPointNumber ) - 1 );
  267. }
  268. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  269. int nParticleCount, int nAttributeWriteMask,
  270. void *pContext) const;
  271. virtual void InitNewParticlesBlock( CParticleCollection *pParticles,
  272. int start_block, int n_blocks, int nAttributeWriteMask,
  273. void *pContext ) const;
  274. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  275. {
  276. m_nControlPointNumber = max( 0, min( MAX_PARTICLE_CONTROL_POINTS-1, m_nControlPointNumber ) );
  277. m_bDistanceBias = ( m_vecDistanceBias.x != 1.0f ) || ( m_vecDistanceBias.y != 1.0f ) || ( m_vecDistanceBias.z != 1.0f );
  278. m_bDistanceBiasAbs = ( m_vecDistanceBiasAbs.x != 0.0f ) || ( m_vecDistanceBiasAbs.y != 0.0f ) || ( m_vecDistanceBiasAbs.z != 0.0f );
  279. }
  280. void Render( CParticleCollection *pParticles ) const;
  281. };
  282. DEFINE_PARTICLE_OPERATOR( C_INIT_CreateWithinSphere, "Position Within Sphere Random", OPERATOR_PI_POSITION );
  283. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_CreateWithinSphere )
  284. DMXELEMENT_UNPACK_FIELD( "distance_min", "0", float, m_fRadiusMin )
  285. DMXELEMENT_UNPACK_FIELD( "distance_max", "0", float, m_fRadiusMax )
  286. DMXELEMENT_UNPACK_FIELD( "distance_bias", "1 1 1", Vector, m_vecDistanceBias )
  287. DMXELEMENT_UNPACK_FIELD( "distance_bias_absolute_value", "0 0 0", Vector, m_vecDistanceBiasAbs )
  288. DMXELEMENT_UNPACK_FIELD( "bias in local system", "0", bool, m_bLocalCoords )
  289. DMXELEMENT_UNPACK_FIELD( "control_point_number", "0", int, m_nControlPointNumber )
  290. DMXELEMENT_UNPACK_FIELD( "speed_min", "0", float, m_fSpeedMin )
  291. DMXELEMENT_UNPACK_FIELD( "speed_max", "0", float, m_fSpeedMax )
  292. DMXELEMENT_UNPACK_FIELD( "speed_random_exponent", "1", float, m_fSpeedRandExp )
  293. DMXELEMENT_UNPACK_FIELD( "speed_in_local_coordinate_system_min", "0 0 0", Vector, m_LocalCoordinateSystemSpeedMin )
  294. DMXELEMENT_UNPACK_FIELD( "speed_in_local_coordinate_system_max", "0 0 0", Vector, m_LocalCoordinateSystemSpeedMax )
  295. DMXELEMENT_UNPACK_FIELD( "create in model", "0", int, m_nCreateInModel )
  296. DMXELEMENT_UNPACK_FIELD( "randomly distribute to highest supplied Control Point", "0", bool, m_bUseHighestEndCP )
  297. DMXELEMENT_UNPACK_FIELD( "randomly distribution growth time", "0", float, m_flEndCPGrowthTime )
  298. END_PARTICLE_OPERATOR_UNPACK( C_INIT_CreateWithinSphere )
  299. ConVar r_sse_s( "r_sse_s", "1", 0, "sse ins for particle sphere create" );
  300. void C_INIT_CreateWithinSphere::InitNewParticlesScalar(
  301. CParticleCollection *pParticles, int start_p,
  302. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  303. {
  304. for( ; nParticleCount--; start_p++ )
  305. {
  306. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, start_p );
  307. const float *ct = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, start_p );
  308. float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, start_p );
  309. int nCurrentControlPoint = m_nControlPointNumber;
  310. if ( m_bUseHighestEndCP )
  311. {
  312. //hack for growth time instead of using strength as currenly initializers don't support it.
  313. float flStrength = 1.0;
  314. if ( m_flEndCPGrowthTime != 0.0f )
  315. {
  316. flStrength = min ( pParticles->m_flCurTime, m_flEndCPGrowthTime ) / m_flEndCPGrowthTime ;
  317. }
  318. int nHighestControlPoint = floor ( pParticles->GetHighestControlPoint() * flStrength );
  319. nCurrentControlPoint = pParticles->RandomInt( m_nControlPointNumber, nHighestControlPoint );
  320. }
  321. Vector randpos, randDir;
  322. for( int nTryCtr = 0 ; nTryCtr < 10; nTryCtr++ )
  323. {
  324. float flLength = pParticles->RandomVectorInUnitSphere( &randpos );
  325. // Absolute value and biasing for creating hemispheres and ovoids.
  326. if ( m_bDistanceBiasAbs )
  327. {
  328. if ( m_vecDistanceBiasAbs.x != 0.0f )
  329. {
  330. randpos.x = fabs(randpos.x);
  331. }
  332. if ( m_vecDistanceBiasAbs.y != 0.0f )
  333. {
  334. randpos.y = fabs(randpos.y);
  335. }
  336. if ( m_vecDistanceBiasAbs.z != 0.0f )
  337. {
  338. randpos.z = fabs(randpos.z);
  339. }
  340. }
  341. randpos *= m_vecDistanceBias;
  342. randpos.NormalizeInPlace();
  343. randDir = randpos;
  344. randpos *= Lerp( flLength, m_fRadiusMin, m_fRadiusMax );
  345. if ( !m_bDistanceBias || !m_bLocalCoords )
  346. {
  347. Vector vecControlPoint;
  348. pParticles->GetControlPointAtTime( nCurrentControlPoint, *ct, &vecControlPoint );
  349. randpos += vecControlPoint;
  350. }
  351. else
  352. {
  353. matrix3x4_t mat;
  354. pParticles->GetControlPointTransformAtTime( nCurrentControlPoint, *ct, &mat );
  355. Vector vecTransformLocal = vec3_origin;
  356. VectorTransform( randpos, mat, vecTransformLocal );
  357. randpos = vecTransformLocal;
  358. }
  359. // now, force to be in model if we can
  360. if (
  361. ( m_nCreateInModel == 0 ) ||
  362. (g_pParticleSystemMgr->Query()->MovePointInsideControllingObject(
  363. pParticles, pParticles->m_ControlPoints[nCurrentControlPoint].m_pObject, &randpos ) ) )
  364. break;
  365. }
  366. xyz[0] = randpos.x;
  367. xyz[4] = randpos.y;
  368. xyz[8] = randpos.z;
  369. // FIXME: Remove this into a speed setting initializer
  370. if ( pxyz && ( nAttributeWriteMask & PARTICLE_ATTRIBUTE_PREV_XYZ_MASK ) )
  371. {
  372. Vector poffset(0,0,0);
  373. if ( m_fSpeedMax > 0.0 )
  374. {
  375. float rand_speed = pParticles->RandomFloatExp( m_fSpeedMin, m_fSpeedMax, m_fSpeedRandExp );
  376. poffset.x -= rand_speed * randDir.x;
  377. poffset.y -= rand_speed * randDir.y;
  378. poffset.z -= rand_speed * randDir.z;
  379. }
  380. poffset -=
  381. pParticles->RandomFloat( m_LocalCoordinateSystemSpeedMin.x, m_LocalCoordinateSystemSpeedMax.x )*
  382. pParticles->m_ControlPoints[ nCurrentControlPoint ].m_ForwardVector;
  383. poffset -=
  384. pParticles->RandomFloat( m_LocalCoordinateSystemSpeedMin.y, m_LocalCoordinateSystemSpeedMax.y )*
  385. pParticles->m_ControlPoints[ nCurrentControlPoint ].m_RightVector;
  386. poffset -=
  387. pParticles->RandomFloat( m_LocalCoordinateSystemSpeedMin.z, m_LocalCoordinateSystemSpeedMax.z )*
  388. pParticles->m_ControlPoints[ nCurrentControlPoint ].m_UpVector;
  389. poffset *= pParticles->m_flPreviousDt;
  390. randpos += poffset;
  391. pxyz[0] = randpos.x;
  392. pxyz[4] = randpos.y;
  393. pxyz[8] = randpos.z;
  394. }
  395. }
  396. }
  397. void C_INIT_CreateWithinSphere::InitNewParticlesBlock( CParticleCollection *pParticles,
  398. int start_block, int n_blocks, int nAttributeWriteMask,
  399. void *pContext ) const
  400. {
  401. // sse-favorable settings
  402. bool bMustUseScalar = m_bUseHighestEndCP || m_nCreateInModel;
  403. if ( m_bDistanceBias && m_bLocalCoords )
  404. bMustUseScalar = true;
  405. if ( ( !bMustUseScalar ) &&
  406. // (( nAttributeWriteMask & PARTICLE_ATTRIBUTE_PREV_XYZ_MASK ) == 0 ) &&
  407. r_sse_s.GetInt() )
  408. {
  409. C4VAttributeWriteIterator pXYZ( PARTICLE_ATTRIBUTE_XYZ, pParticles );
  410. pXYZ += start_block;
  411. C4VAttributeWriteIterator pPrevXYZ( PARTICLE_ATTRIBUTE_PREV_XYZ, pParticles );
  412. pPrevXYZ += start_block;
  413. CM128AttributeIterator pCT( PARTICLE_ATTRIBUTE_CREATION_TIME, pParticles );
  414. pCT += start_block;
  415. // now, calculate the terms we need for interpolating control points
  416. FourVectors v4PrevControlPointPosition;
  417. v4PrevControlPointPosition.DuplicateVector( pParticles->m_ControlPoints[m_nControlPointNumber].m_PrevPosition );
  418. FourVectors v4ControlPointDelta;
  419. v4ControlPointDelta.DuplicateVector( pParticles->m_ControlPoints[m_nControlPointNumber].m_Position );
  420. v4ControlPointDelta -= v4PrevControlPointPosition;
  421. float flOODT = ( pParticles->m_flDt > 0.0 ) ? ( 1.0 / pParticles->m_flDt ) : 0.0;
  422. fltx4 fl4OODt = ReplicateX4( flOODT );
  423. fltx4 fl4PrevTime = ReplicateX4( pParticles->m_flCurTime - pParticles->m_flDt );
  424. int nContext = GetSIMDRandContext();
  425. FourVectors v4DistanceBias;
  426. v4DistanceBias.DuplicateVector( m_vecDistanceBias );
  427. FourVectors v4ConditionalAbsMask;
  428. for( int nComp = 0 ; nComp < 3; nComp++ )
  429. {
  430. v4ConditionalAbsMask[nComp] = ( m_vecDistanceBiasAbs[nComp] > 0 ) ?
  431. LoadAlignedSIMD( ( const float *) g_SIMD_clear_signmask ) :
  432. LoadAlignedSIMD( ( const float *) g_SIMD_AllOnesMask );
  433. }
  434. fltx4 fl4RadiusMin = ReplicateX4( m_fRadiusMin );
  435. fltx4 fl4RadiusSpread = ReplicateX4( m_fRadiusMax - m_fRadiusMin );
  436. int nPowSSEMask = 4.0 * m_fSpeedRandExp;
  437. bool bDoRandSpeed =
  438. ( m_fSpeedMax > 0. ) ||
  439. ( m_LocalCoordinateSystemSpeedMax.x != 0 ) ||
  440. ( m_LocalCoordinateSystemSpeedMax.y != 0 ) ||
  441. ( m_LocalCoordinateSystemSpeedMax.z != 0 ) ||
  442. ( m_LocalCoordinateSystemSpeedMin.x != 0 ) ||
  443. ( m_LocalCoordinateSystemSpeedMin.y != 0 ) ||
  444. ( m_LocalCoordinateSystemSpeedMin.z != 0 );
  445. fltx4 fl4SpeedMin = ReplicateX4( m_fSpeedMin );
  446. fltx4 fl4SpeedRange = ReplicateX4( m_fSpeedMax - m_fSpeedMin );
  447. fltx4 fl4LocalSpeedMinX = ReplicateX4( m_LocalCoordinateSystemSpeedMin.x );
  448. fltx4 fl4LocalSpeedXSpread = ReplicateX4( m_LocalCoordinateSystemSpeedMax.x -
  449. m_LocalCoordinateSystemSpeedMin.x );
  450. fltx4 fl4LocalSpeedMinY = ReplicateX4( m_LocalCoordinateSystemSpeedMin.y );
  451. fltx4 fl4LocalSpeedYSpread = ReplicateX4( m_LocalCoordinateSystemSpeedMax.y -
  452. m_LocalCoordinateSystemSpeedMin.y );
  453. fltx4 fl4LocalSpeedMinZ = ReplicateX4( m_LocalCoordinateSystemSpeedMin.z );
  454. fltx4 fl4LocalSpeedZSpread = ReplicateX4( m_LocalCoordinateSystemSpeedMax.z -
  455. m_LocalCoordinateSystemSpeedMin.z );
  456. FourVectors v4CPForward;
  457. v4CPForward.DuplicateVector( pParticles->m_ControlPoints[m_nControlPointNumber].m_ForwardVector );
  458. FourVectors v4CPUp;
  459. v4CPUp.DuplicateVector( pParticles->m_ControlPoints[m_nControlPointNumber].m_UpVector );
  460. FourVectors v4CPRight;
  461. v4CPRight.DuplicateVector( pParticles->m_ControlPoints[m_nControlPointNumber].m_RightVector );
  462. fltx4 fl4PreviousDt = ReplicateX4( pParticles->m_flPreviousDt );
  463. while( n_blocks-- )
  464. {
  465. FourVectors v4RandPos;
  466. RandomPointInUnitSphere( nContext, v4RandPos );
  467. fltx4 fl4Length = v4RandPos.length();
  468. // conditional absolute value
  469. v4RandPos.x = AndSIMD( v4RandPos.x, v4ConditionalAbsMask.x );
  470. v4RandPos.y = AndSIMD( v4RandPos.y, v4ConditionalAbsMask.y );
  471. v4RandPos.z = AndSIMD( v4RandPos.z, v4ConditionalAbsMask.z );
  472. v4RandPos *= v4DistanceBias;
  473. v4RandPos.VectorNormalizeFast();
  474. FourVectors v4randDir = v4RandPos;
  475. // lerp radius
  476. v4RandPos *= AddSIMD( fl4RadiusMin, MulSIMD( fl4Length, fl4RadiusSpread ) );
  477. v4RandPos += v4PrevControlPointPosition;
  478. FourVectors cpnt = v4ControlPointDelta;
  479. cpnt *= MulSIMD( SubSIMD( *pCT, fl4PrevTime ), fl4OODt );
  480. v4RandPos += cpnt;
  481. *(pXYZ) = v4RandPos;
  482. if ( nAttributeWriteMask & PARTICLE_ATTRIBUTE_PREV_XYZ_MASK )
  483. {
  484. if ( bDoRandSpeed )
  485. {
  486. fltx4 fl4Rand_speed = Pow_FixedPoint_Exponent_SIMD( RandSIMD( nContext ), nPowSSEMask );
  487. fl4Rand_speed = AddSIMD( fl4SpeedMin, MulSIMD( fl4SpeedRange, fl4Rand_speed ) );
  488. v4randDir *= fl4Rand_speed;
  489. // local speed
  490. FourVectors v4LocalOffset = v4CPForward;
  491. v4LocalOffset *= AddSIMD( fl4LocalSpeedMinX,
  492. MulSIMD( fl4LocalSpeedXSpread, RandSIMD( nContext ) ) );
  493. v4randDir += v4LocalOffset;
  494. v4LocalOffset = v4CPRight;
  495. v4LocalOffset *= AddSIMD( fl4LocalSpeedMinY,
  496. MulSIMD( fl4LocalSpeedYSpread, RandSIMD( nContext ) ) );
  497. v4randDir += v4LocalOffset;
  498. v4LocalOffset = v4CPUp;
  499. v4LocalOffset *= AddSIMD( fl4LocalSpeedMinZ,
  500. MulSIMD( fl4LocalSpeedZSpread, RandSIMD( nContext ) ) );
  501. v4randDir += v4LocalOffset;
  502. v4randDir *= fl4PreviousDt;
  503. v4RandPos -= v4randDir;
  504. }
  505. *(pPrevXYZ) = v4RandPos;
  506. }
  507. ++pXYZ;
  508. ++pPrevXYZ;
  509. ++pCT;
  510. }
  511. ReleaseSIMDRandContext( nContext );
  512. }
  513. else
  514. CParticleOperatorInstance::InitNewParticlesBlock( pParticles, start_block, n_blocks, nAttributeWriteMask, pContext );
  515. }
  516. //-----------------------------------------------------------------------------
  517. // Render visualization
  518. //-----------------------------------------------------------------------------
  519. void C_INIT_CreateWithinSphere::Render( CParticleCollection *pParticles ) const
  520. {
  521. Vector vecOrigin;
  522. pParticles->GetControlPointAtTime( m_nControlPointNumber, pParticles->m_flCurTime, &vecOrigin );
  523. RenderWireframeSphere( vecOrigin, m_fRadiusMin, 16, 8, Color( 192, 192, 0, 255 ), false );
  524. RenderWireframeSphere( vecOrigin, m_fRadiusMax, 16, 8, Color( 128, 128, 0, 255 ), false );
  525. }
  526. class C_INIT_CreateWithinBox : public CParticleOperatorInstance
  527. {
  528. DECLARE_PARTICLE_OPERATOR( C_INIT_CreateWithinBox );
  529. Vector m_vecMin;
  530. Vector m_vecMax;
  531. int m_nControlPointNumber;
  532. uint32 GetWrittenAttributes( void ) const
  533. {
  534. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  535. }
  536. uint32 GetReadAttributes( void ) const
  537. {
  538. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  539. }
  540. virtual uint64 GetReadControlPointMask() const
  541. {
  542. return 1ULL << m_nControlPointNumber;
  543. }
  544. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  545. int nParticleCount, int nAttributeWriteMask,
  546. void *pContext) const;
  547. void Render( CParticleCollection *pParticles ) const;
  548. };
  549. DEFINE_PARTICLE_OPERATOR( C_INIT_CreateWithinBox, "Position Within Box Random", OPERATOR_PI_POSITION );
  550. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_CreateWithinBox )
  551. DMXELEMENT_UNPACK_FIELD( "min", "0 0 0", Vector, m_vecMin )
  552. DMXELEMENT_UNPACK_FIELD( "max", "0 0 0", Vector, m_vecMax )
  553. DMXELEMENT_UNPACK_FIELD( "control point number", "0", int, m_nControlPointNumber )
  554. END_PARTICLE_OPERATOR_UNPACK( C_INIT_CreateWithinBox )
  555. void C_INIT_CreateWithinBox::InitNewParticlesScalar(
  556. CParticleCollection *pParticles, int start_p,
  557. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  558. {
  559. int nControlPointNumber = max( 0, min( MAX_PARTICLE_CONTROL_POINTS-1, m_nControlPointNumber ) );
  560. for( ; nParticleCount--; start_p++ )
  561. {
  562. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, start_p );
  563. const float *ct = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, start_p );
  564. float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, start_p );
  565. Vector randpos;
  566. pParticles->RandomVector( m_vecMin, m_vecMax, &randpos );
  567. Vector vecControlPoint;
  568. pParticles->GetControlPointAtTime( nControlPointNumber, *ct, &vecControlPoint );
  569. randpos += vecControlPoint;
  570. xyz[0] = randpos.x;
  571. xyz[4] = randpos.y;
  572. xyz[8] = randpos.z;
  573. if ( pxyz && ( nAttributeWriteMask & PARTICLE_ATTRIBUTE_PREV_XYZ_MASK ) )
  574. {
  575. pxyz[0] = randpos.x;
  576. pxyz[4] = randpos.y;
  577. pxyz[8] = randpos.z;
  578. }
  579. }
  580. }
  581. //-----------------------------------------------------------------------------
  582. // Render visualization
  583. //-----------------------------------------------------------------------------
  584. void C_INIT_CreateWithinBox::Render( CParticleCollection *pParticles ) const
  585. {
  586. Vector vecOrigin;
  587. pParticles->GetControlPointAtTime( m_nControlPointNumber, pParticles->m_flCurTime, &vecOrigin );
  588. RenderWireframeBox( vecOrigin, vec3_angle, m_vecMin, m_vecMax, Color( 192, 192, 0, 255 ), false );
  589. }
  590. //-----------------------------------------------------------------------------
  591. // Position Offset Initializer
  592. // offsets initial position of particles within a random vector range,
  593. // while still respecting spherical/conical spacial and velocity initialization
  594. //-----------------------------------------------------------------------------
  595. class C_INIT_PositionOffset : public CParticleOperatorInstance
  596. {
  597. DECLARE_PARTICLE_OPERATOR( C_INIT_PositionOffset );
  598. Vector m_OffsetMin;
  599. Vector m_OffsetMax;
  600. int m_nControlPointNumber;
  601. bool m_bLocalCoords;
  602. bool m_bProportional;
  603. uint32 GetWrittenAttributes( void ) const
  604. {
  605. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  606. }
  607. uint32 GetReadAttributes( void ) const
  608. {
  609. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_RADIUS_MASK;
  610. }
  611. virtual uint64 GetReadControlPointMask() const
  612. {
  613. return 1ULL << m_nControlPointNumber;
  614. }
  615. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  616. int nParticleCount, int nAttributeWriteMask,
  617. void *pContext) const;
  618. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  619. {
  620. m_nControlPointNumber = max( 0, min( MAX_PARTICLE_CONTROL_POINTS-1, m_nControlPointNumber ) );
  621. }
  622. bool InitMultipleOverride ( void ) { return true; }
  623. void Render( CParticleCollection *pParticles ) const;
  624. };
  625. DEFINE_PARTICLE_OPERATOR( C_INIT_PositionOffset, "Position Modify Offset Random", OPERATOR_GENERIC );
  626. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_PositionOffset )
  627. DMXELEMENT_UNPACK_FIELD( "control_point_number", "0", int, m_nControlPointNumber )
  628. DMXELEMENT_UNPACK_FIELD( "offset min", "0 0 0", Vector, m_OffsetMin )
  629. DMXELEMENT_UNPACK_FIELD( "offset max", "0 0 0", Vector, m_OffsetMax )
  630. DMXELEMENT_UNPACK_FIELD( "offset in local space 0/1", "0", bool, m_bLocalCoords )
  631. DMXELEMENT_UNPACK_FIELD( "offset proportional to radius 0/1", "0", bool, m_bProportional )
  632. END_PARTICLE_OPERATOR_UNPACK( C_INIT_PositionOffset )
  633. void C_INIT_PositionOffset::InitNewParticlesScalar(
  634. CParticleCollection *pParticles, int start_p,
  635. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  636. {
  637. for( ; nParticleCount--; start_p++ )
  638. {
  639. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, start_p );
  640. float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, start_p );
  641. const float *ct = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, start_p );
  642. const float *radius = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_RADIUS, start_p );
  643. Vector randpos;
  644. if ( m_bProportional )
  645. {
  646. pParticles->RandomVector( (m_OffsetMin * *radius), (m_OffsetMax * *radius), &randpos );
  647. }
  648. else
  649. {
  650. pParticles->RandomVector( m_OffsetMin, m_OffsetMax, &randpos );
  651. }
  652. if ( m_bLocalCoords )
  653. {
  654. matrix3x4_t mat;
  655. pParticles->GetControlPointTransformAtTime( m_nControlPointNumber, *ct, &mat );
  656. Vector vecTransformLocal = vec3_origin;
  657. VectorRotate( randpos, mat, vecTransformLocal );
  658. randpos = vecTransformLocal;
  659. }
  660. xyz[0] += randpos.x;
  661. xyz[4] += randpos.y;
  662. xyz[8] += randpos.z;
  663. pxyz[0] += randpos.x;
  664. pxyz[4] += randpos.y;
  665. pxyz[8] += randpos.z;
  666. }
  667. }
  668. //-----------------------------------------------------------------------------
  669. // Render visualization
  670. //-----------------------------------------------------------------------------
  671. void C_INIT_PositionOffset::Render( CParticleCollection *pParticles ) const
  672. {
  673. Vector vecOrigin (0,0,0);
  674. Vector vecMinExtent = m_OffsetMin;
  675. Vector vecMaxExtent = m_OffsetMax;
  676. if ( m_bLocalCoords )
  677. {
  678. matrix3x4_t mat;
  679. pParticles->GetControlPointTransformAtTime( m_nControlPointNumber, pParticles->m_flCurTime, &mat );
  680. VectorRotate( m_OffsetMin, mat, vecMinExtent );
  681. VectorRotate( m_OffsetMax, mat, vecMaxExtent );
  682. }
  683. else
  684. {
  685. pParticles->GetControlPointAtTime( m_nControlPointNumber, pParticles->m_flCurTime, &vecOrigin );
  686. }
  687. RenderWireframeBox( vecOrigin, vec3_angle, vecMinExtent , vecMaxExtent , Color( 192, 192, 0, 255 ), false );
  688. }
  689. //-----------------------------------------------------------------------------
  690. //
  691. // Velocity-based Operators
  692. //
  693. //-----------------------------------------------------------------------------
  694. //-----------------------------------------------------------------------------
  695. // Random velocity initializer
  696. //-----------------------------------------------------------------------------
  697. class C_INIT_VelocityRandom : public CParticleOperatorInstance
  698. {
  699. DECLARE_PARTICLE_OPERATOR( C_INIT_VelocityRandom );
  700. uint32 GetWrittenAttributes( void ) const
  701. {
  702. return PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  703. }
  704. uint32 GetReadAttributes( void ) const
  705. {
  706. return PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  707. }
  708. virtual uint64 GetReadControlPointMask() const
  709. {
  710. if ( m_bHasLocalSpeed )
  711. return 1ULL << m_nControlPointNumber;
  712. return 0;
  713. }
  714. virtual bool InitMultipleOverride() { return true; }
  715. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  716. int nParticleCount, int nAttributeWriteMask,
  717. void *pContext) const;
  718. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  719. {
  720. m_nControlPointNumber = max( 0, min( MAX_PARTICLE_CONTROL_POINTS-1, m_nControlPointNumber ) );
  721. m_bHasLocalSpeed = ( m_LocalCoordinateSystemSpeedMin != vec3_origin ) || ( m_LocalCoordinateSystemSpeedMax != vec3_origin );
  722. if ( m_fSpeedMax < m_fSpeedMin )
  723. {
  724. V_swap( m_fSpeedMin, m_fSpeedMax );
  725. }
  726. }
  727. private:
  728. int m_nControlPointNumber;
  729. float m_fSpeedMin;
  730. float m_fSpeedMax;
  731. Vector m_LocalCoordinateSystemSpeedMin;
  732. Vector m_LocalCoordinateSystemSpeedMax;
  733. bool m_bHasLocalSpeed;
  734. };
  735. DEFINE_PARTICLE_OPERATOR( C_INIT_VelocityRandom, "Velocity Random", OPERATOR_GENERIC );
  736. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_VelocityRandom )
  737. DMXELEMENT_UNPACK_FIELD( "control_point_number", "0", int, m_nControlPointNumber )
  738. DMXELEMENT_UNPACK_FIELD( "random_speed_min", "0", float, m_fSpeedMin )
  739. DMXELEMENT_UNPACK_FIELD( "random_speed_max", "0", float, m_fSpeedMax )
  740. DMXELEMENT_UNPACK_FIELD( "speed_in_local_coordinate_system_min", "0 0 0", Vector, m_LocalCoordinateSystemSpeedMin )
  741. DMXELEMENT_UNPACK_FIELD( "speed_in_local_coordinate_system_max", "0 0 0", Vector, m_LocalCoordinateSystemSpeedMax )
  742. END_PARTICLE_OPERATOR_UNPACK( C_INIT_VelocityRandom )
  743. void C_INIT_VelocityRandom::InitNewParticlesScalar(
  744. CParticleCollection *pParticles, int start_p,
  745. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  746. {
  747. for( ; nParticleCount--; start_p++ )
  748. {
  749. const float *ct = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, start_p );
  750. float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, start_p );
  751. Vector vecVelocity( 0.0f, 0.0f, 0.0f );
  752. if ( m_bHasLocalSpeed )
  753. {
  754. Vector vecRandomSpeed, vecForward, vecUp, vecRight;
  755. pParticles->RandomVector( m_LocalCoordinateSystemSpeedMin, m_LocalCoordinateSystemSpeedMax, &vecRandomSpeed );
  756. pParticles->GetControlPointOrientationAtTime( m_nControlPointNumber, *ct, &vecForward, &vecRight, &vecUp );
  757. VectorMA( vecVelocity, vecRandomSpeed.x, vecForward, vecVelocity );
  758. VectorMA( vecVelocity, -vecRandomSpeed.y, vecRight, vecVelocity );
  759. VectorMA( vecVelocity, vecRandomSpeed.z, vecUp, vecVelocity );
  760. }
  761. if ( m_fSpeedMax > 0.0f )
  762. {
  763. Vector vecRandomSpeed;
  764. pParticles->RandomVector( m_fSpeedMin, m_fSpeedMax, &vecRandomSpeed );
  765. vecVelocity += vecRandomSpeed;
  766. }
  767. vecVelocity *= pParticles->m_flPreviousDt;
  768. pxyz[0] -= vecVelocity.x;
  769. pxyz[4] -= vecVelocity.y;
  770. pxyz[8] -= vecVelocity.z;
  771. }
  772. }
  773. //-----------------------------------------------------------------------------
  774. // Initial Velocity Noise Operator
  775. //-----------------------------------------------------------------------------
  776. class C_INIT_InitialVelocityNoise : public CParticleOperatorInstance
  777. {
  778. DECLARE_PARTICLE_OPERATOR( C_INIT_InitialVelocityNoise );
  779. uint32 GetWrittenAttributes( void ) const
  780. {
  781. return PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  782. }
  783. uint32 GetReadAttributes( void ) const
  784. {
  785. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_XYZ_MASK;
  786. }
  787. virtual uint64 GetReadControlPointMask() const
  788. {
  789. return 1ULL << m_nControlPointNumber;
  790. }
  791. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  792. int nParticleCount, int nAttributeWriteMask,
  793. void *pContext) const;
  794. void InitNewParticlesBlock( CParticleCollection *pParticles,
  795. int start_block, int n_blocks, int nAttributeWriteMask,
  796. void *pContext ) const;
  797. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  798. {
  799. m_nControlPointNumber = max( 0, min( MAX_PARTICLE_CONTROL_POINTS-1, m_nControlPointNumber ) );
  800. }
  801. virtual bool InitMultipleOverride() { return true; }
  802. Vector m_vecAbsVal, m_vecAbsValInv, m_vecOffsetLoc;
  803. float m_flOffset;
  804. Vector m_vecOutputMin;
  805. Vector m_vecOutputMax;
  806. float m_flNoiseScale, m_flNoiseScaleLoc;
  807. int nRemainingBlocks, m_nControlPointNumber;
  808. bool m_bLocalSpace;
  809. };
  810. DEFINE_PARTICLE_OPERATOR( C_INIT_InitialVelocityNoise, "Velocity Noise", OPERATOR_GENERIC );
  811. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_InitialVelocityNoise )
  812. DMXELEMENT_UNPACK_FIELD( "Control Point Number","0",int,m_nControlPointNumber)
  813. DMXELEMENT_UNPACK_FIELD( "Time Noise Coordinate Scale","1",float,m_flNoiseScale)
  814. DMXELEMENT_UNPACK_FIELD( "Spatial Noise Coordinate Scale","0.01",float,m_flNoiseScaleLoc)
  815. DMXELEMENT_UNPACK_FIELD( "Time Coordinate Offset","0", float, m_flOffset )
  816. DMXELEMENT_UNPACK_FIELD( "Spatial Coordinate Offset","0 0 0", Vector, m_vecOffsetLoc )
  817. DMXELEMENT_UNPACK_FIELD( "Absolute Value","0 0 0", Vector, m_vecAbsVal )
  818. DMXELEMENT_UNPACK_FIELD( "Invert Abs Value","0 0 0", Vector, m_vecAbsValInv )
  819. DMXELEMENT_UNPACK_FIELD( "output minimum","0 0 0", Vector, m_vecOutputMin )
  820. DMXELEMENT_UNPACK_FIELD( "output maximum","1 1 1", Vector, m_vecOutputMax )
  821. DMXELEMENT_UNPACK_FIELD( "Apply Velocity in Local Space (0/1)","0", bool, m_bLocalSpace )
  822. END_PARTICLE_OPERATOR_UNPACK( C_INIT_InitialVelocityNoise );
  823. void C_INIT_InitialVelocityNoise::InitNewParticlesBlock( CParticleCollection *pParticles,
  824. int start_block, int n_blocks, int nAttributeWriteMask,
  825. void *pContext ) const
  826. {
  827. float flAbsScaleX, flAbsScaleY, flAbsScaleZ;
  828. fltx4 fl4AbsValX, fl4AbsValY, fl4AbsValZ;
  829. fl4AbsValX = CmpEqSIMD( Four_Zeros, Four_Zeros );
  830. fl4AbsValY = fl4AbsValX;
  831. fl4AbsValZ = fl4AbsValX;
  832. flAbsScaleX = 0.5;
  833. flAbsScaleY = 0.5;
  834. flAbsScaleZ = 0.5;
  835. // Set up single if check for absolute value inversion inside the loop
  836. bool m_bNoiseAbs = ( m_vecAbsValInv.x != 0.0f ) || ( m_vecAbsValInv.y != 0.0f ) || ( m_vecAbsValInv.z != 0.0f );
  837. // Set up values for more optimal absolute value calculations inside the loop
  838. if ( m_vecAbsVal.x != 0.0f )
  839. {
  840. fl4AbsValX = LoadAlignedSIMD( (float *) g_SIMD_clear_signmask );
  841. flAbsScaleX = 1.0;
  842. }
  843. if ( m_vecAbsVal.y != 0.0f )
  844. {
  845. fl4AbsValY = LoadAlignedSIMD( (float *) g_SIMD_clear_signmask );
  846. flAbsScaleY = 1.0;
  847. }
  848. if ( m_vecAbsVal.z != 0.0f )
  849. {
  850. fl4AbsValZ = LoadAlignedSIMD( (float *) g_SIMD_clear_signmask );
  851. flAbsScaleZ = 1.0;
  852. }
  853. float ValueScaleX, ValueScaleY, ValueScaleZ, ValueBaseX, ValueBaseY, ValueBaseZ;
  854. ValueScaleX = ( flAbsScaleX *(m_vecOutputMax.x-m_vecOutputMin.x ) );
  855. ValueBaseX = (m_vecOutputMin.x+ ( ( 1.0 - flAbsScaleX ) *( m_vecOutputMax.x-m_vecOutputMin.x ) ) );
  856. ValueScaleY = ( flAbsScaleY *(m_vecOutputMax.y-m_vecOutputMin.y ) );
  857. ValueBaseY = (m_vecOutputMin.y+ ( ( 1.0 - flAbsScaleY ) *( m_vecOutputMax.y-m_vecOutputMin.y ) ) );
  858. ValueScaleZ = ( flAbsScaleZ *(m_vecOutputMax.z-m_vecOutputMin.z ) );
  859. ValueBaseZ = (m_vecOutputMin.z+ ( ( 1.0 - flAbsScaleZ ) *( m_vecOutputMax.z-m_vecOutputMin.z ) ) );
  860. fltx4 fl4ValueBaseX = ReplicateX4( ValueBaseX );
  861. fltx4 fl4ValueBaseY = ReplicateX4( ValueBaseY );
  862. fltx4 fl4ValueBaseZ = ReplicateX4( ValueBaseZ );
  863. fltx4 fl4ValueScaleX = ReplicateX4( ValueScaleX );
  864. fltx4 fl4ValueScaleY = ReplicateX4( ValueScaleY );
  865. fltx4 fl4ValueScaleZ = ReplicateX4( ValueScaleZ );
  866. float CoordScale = m_flNoiseScale;
  867. float CoordScaleLoc = m_flNoiseScaleLoc;
  868. Vector ofs_y = Vector( 100000.5, 300000.25, 9000000.75 );
  869. Vector ofs_z = Vector( 110000.25, 310000.75, 9100000.5 );
  870. size_t attr_stride;
  871. const FourVectors *xyz = pParticles->Get4VAttributePtr( PARTICLE_ATTRIBUTE_XYZ, &attr_stride );
  872. xyz += attr_stride * start_block;
  873. FourVectors *pxyz = pParticles->Get4VAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, &attr_stride );
  874. pxyz += attr_stride * start_block;
  875. const fltx4 *pCreationTime = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, &attr_stride );
  876. pCreationTime += attr_stride * start_block;
  877. // setup
  878. fltx4 fl4Offset = ReplicateX4( m_flOffset );
  879. FourVectors fvOffsetLoc;
  880. fvOffsetLoc.DuplicateVector( m_vecOffsetLoc );
  881. CParticleSIMDTransformation CPTransform;
  882. float flCreationTime = SubFloat( *pCreationTime, 0 );
  883. pParticles->GetControlPointTransformAtTime( m_nControlPointNumber, flCreationTime, &CPTransform );
  884. while( n_blocks-- )
  885. {
  886. FourVectors fvCoordLoc = *xyz;
  887. fvCoordLoc += fvOffsetLoc;
  888. FourVectors fvCoord;
  889. fvCoord.x = AddSIMD(*pCreationTime, fl4Offset);
  890. fvCoord.y = AddSIMD(*pCreationTime, fl4Offset);
  891. fvCoord.z = AddSIMD(*pCreationTime, fl4Offset);
  892. fvCoordLoc *= CoordScaleLoc;
  893. fvCoord *= CoordScale;
  894. fvCoord += fvCoordLoc;
  895. FourVectors fvCoord2 = fvCoord;
  896. FourVectors fvOffsetTemp;
  897. fvOffsetTemp.DuplicateVector( ofs_y );
  898. fvCoord2 += fvOffsetTemp;
  899. FourVectors fvCoord3 = fvCoord;
  900. fvOffsetTemp.DuplicateVector( ofs_z );
  901. fvCoord3 += fvOffsetTemp;
  902. fltx4 fl4NoiseX;
  903. fltx4 fl4NoiseY;
  904. fltx4 fl4NoiseZ;
  905. fl4NoiseX = NoiseSIMD( fvCoord );
  906. fl4NoiseY = NoiseSIMD( fvCoord2 );
  907. fl4NoiseZ = NoiseSIMD( fvCoord3 );
  908. fl4NoiseX = AndSIMD ( fl4NoiseX, fl4AbsValX );
  909. fl4NoiseY = AndSIMD ( fl4NoiseY, fl4AbsValY );
  910. fl4NoiseZ = AndSIMD ( fl4NoiseZ, fl4AbsValZ );
  911. if ( m_bNoiseAbs )
  912. {
  913. if ( m_vecAbsValInv.x != 0.0f )
  914. {
  915. fl4NoiseX = SubSIMD( Four_Ones, fl4NoiseX );
  916. }
  917. if ( m_vecAbsValInv.y != 0.0f )
  918. {
  919. fl4NoiseY = SubSIMD( Four_Ones, fl4NoiseY );
  920. }
  921. if ( m_vecAbsValInv.z != 0.0f )
  922. {
  923. fl4NoiseZ = SubSIMD( Four_Ones, fl4NoiseZ );
  924. }
  925. }
  926. FourVectors fvOffset;
  927. fvOffset.x = AddSIMD( fl4ValueBaseX, ( MulSIMD( fl4ValueScaleX , fl4NoiseX ) ) );
  928. fvOffset.y = AddSIMD( fl4ValueBaseY, ( MulSIMD( fl4ValueScaleY , fl4NoiseY ) ) );
  929. fvOffset.z = AddSIMD( fl4ValueBaseZ, ( MulSIMD( fl4ValueScaleZ , fl4NoiseZ ) ) );
  930. fvOffset *= pParticles->m_flPreviousDt;
  931. if ( m_bLocalSpace )
  932. {
  933. CPTransform.VectorRotate( fvOffset );
  934. }
  935. *pxyz -= fvOffset;
  936. xyz += attr_stride;
  937. pxyz += attr_stride;
  938. pCreationTime += attr_stride;
  939. }
  940. }
  941. void C_INIT_InitialVelocityNoise::InitNewParticlesScalar(
  942. CParticleCollection *pParticles, int start_p,
  943. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  944. {
  945. float flAbsScaleX, flAbsScaleY, flAbsScaleZ;
  946. int nAbsValX, nAbsValY, nAbsValZ;
  947. nAbsValX = 0xffffffff;
  948. nAbsValY = 0xffffffff;
  949. nAbsValZ = 0xffffffff;
  950. flAbsScaleX = 0.5;
  951. flAbsScaleY = 0.5;
  952. flAbsScaleZ = 0.5;
  953. // Set up single if check for absolute value inversion inside the loop
  954. bool m_bNoiseAbs = ( m_vecAbsValInv.x != 0.0f ) || ( m_vecAbsValInv.y != 0.0f ) || ( m_vecAbsValInv.z != 0.0f );
  955. // Set up values for more optimal absolute value calculations inside the loop
  956. if ( m_vecAbsVal.x != 0.0f )
  957. {
  958. nAbsValX = 0x7fffffff;
  959. flAbsScaleX = 1.0;
  960. }
  961. if ( m_vecAbsVal.y != 0.0f )
  962. {
  963. nAbsValY = 0x7fffffff;
  964. flAbsScaleY = 1.0;
  965. }
  966. if ( m_vecAbsVal.z != 0.0f )
  967. {
  968. nAbsValZ = 0x7fffffff;
  969. flAbsScaleZ = 1.0;
  970. }
  971. float ValueScaleX, ValueScaleY, ValueScaleZ, ValueBaseX, ValueBaseY, ValueBaseZ;
  972. ValueScaleX = ( flAbsScaleX *(m_vecOutputMax.x-m_vecOutputMin.x ) );
  973. ValueBaseX = (m_vecOutputMin.x+ ( ( 1.0 - flAbsScaleX ) *( m_vecOutputMax.x-m_vecOutputMin.x ) ) );
  974. ValueScaleY = ( flAbsScaleY *(m_vecOutputMax.y-m_vecOutputMin.y ) );
  975. ValueBaseY = (m_vecOutputMin.y+ ( ( 1.0 - flAbsScaleY ) *( m_vecOutputMax.y-m_vecOutputMin.y ) ) );
  976. ValueScaleZ = ( flAbsScaleZ *(m_vecOutputMax.z-m_vecOutputMin.z ) );
  977. ValueBaseZ = (m_vecOutputMin.z+ ( ( 1.0 - flAbsScaleZ ) *( m_vecOutputMax.z-m_vecOutputMin.z ) ) );
  978. float CoordScale = m_flNoiseScale;
  979. float CoordScaleLoc = m_flNoiseScaleLoc;
  980. Vector ofs_y = Vector( 100000.5, 300000.25, 9000000.75 );
  981. Vector ofs_z = Vector( 110000.25, 310000.75, 9100000.5 );
  982. for( ; nParticleCount--; start_p++ )
  983. {
  984. const float *xyz = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_XYZ, start_p );
  985. float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, start_p );
  986. const float *pCreationTime = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, start_p );
  987. Vector Coord, Coord2, Coord3, CoordLoc;
  988. SetVectorFromAttribute( CoordLoc, xyz );
  989. CoordLoc += m_vecOffsetLoc;
  990. float Offset = m_flOffset;
  991. Coord = Vector ( (*pCreationTime + Offset), (*pCreationTime + Offset), (*pCreationTime + Offset) );
  992. Coord *= CoordScale;
  993. CoordLoc *= CoordScaleLoc;
  994. Coord += CoordLoc;
  995. Coord2 = ( Coord );
  996. Coord3 = ( Coord );
  997. fltx4 flNoise128;
  998. FourVectors fvNoise;
  999. fvNoise.DuplicateVector( Coord );
  1000. flNoise128 = NoiseSIMD( fvNoise );
  1001. float flNoiseX = SubFloat( flNoise128, 0 );
  1002. fvNoise.DuplicateVector( Coord2 + ofs_y );
  1003. flNoise128 = NoiseSIMD( fvNoise );
  1004. float flNoiseY = SubFloat( flNoise128, 0 );
  1005. fvNoise.DuplicateVector( Coord3 + ofs_z );
  1006. flNoise128 = NoiseSIMD( fvNoise );
  1007. float flNoiseZ = SubFloat( flNoise128, 0 );
  1008. *( (int *) &flNoiseX) &= nAbsValX;
  1009. *( (int *) &flNoiseY) &= nAbsValY;
  1010. *( (int *) &flNoiseZ) &= nAbsValZ;
  1011. if ( m_bNoiseAbs )
  1012. {
  1013. if ( m_vecAbsValInv.x != 0.0f )
  1014. {
  1015. flNoiseX = 1.0 - flNoiseX;
  1016. }
  1017. if ( m_vecAbsValInv.y != 0.0f )
  1018. {
  1019. flNoiseY = 1.0 - flNoiseY;
  1020. }
  1021. if ( m_vecAbsValInv.z != 0.0f )
  1022. {
  1023. flNoiseZ = 1.0 - flNoiseZ;
  1024. }
  1025. }
  1026. Vector poffset;
  1027. poffset.x = ( ValueBaseX + ( ValueScaleX * flNoiseX ) );
  1028. poffset.y = ( ValueBaseY + ( ValueScaleY * flNoiseY ) );
  1029. poffset.z = ( ValueBaseZ + ( ValueScaleZ * flNoiseZ ) );
  1030. poffset *= pParticles->m_flPreviousDt;
  1031. if ( m_bLocalSpace )
  1032. {
  1033. matrix3x4_t mat;
  1034. pParticles->GetControlPointTransformAtTime( m_nControlPointNumber, *pCreationTime, &mat );
  1035. Vector vecTransformLocal = vec3_origin;
  1036. VectorRotate( poffset, mat, vecTransformLocal );
  1037. poffset = vecTransformLocal;
  1038. }
  1039. pxyz[0] -= poffset.x;
  1040. pxyz[4] -= poffset.y;
  1041. pxyz[8] -= poffset.z;
  1042. }
  1043. }
  1044. class C_INIT_RandomLifeTime : public CParticleOperatorInstance
  1045. {
  1046. DECLARE_PARTICLE_OPERATOR( C_INIT_RandomLifeTime );
  1047. float m_fLifetimeMin;
  1048. float m_fLifetimeMax;
  1049. float m_fLifetimeRandExponent;
  1050. uint32 GetWrittenAttributes( void ) const
  1051. {
  1052. return PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK;
  1053. }
  1054. uint32 GetReadAttributes( void ) const
  1055. {
  1056. return 0;
  1057. }
  1058. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  1059. int nParticleCount, int nAttributeWriteMask, void *pContext ) const;
  1060. void InitNewParticlesBlock( CParticleCollection *pParticles,
  1061. int start_block, int n_blocks, int nAttributeWriteMask,
  1062. void *pContext ) const
  1063. {
  1064. if ( m_fLifetimeRandExponent != 1.0f )
  1065. {
  1066. InitScalarAttributeRandomRangeExpBlock( PARTICLE_ATTRIBUTE_LIFE_DURATION,
  1067. m_fLifetimeMin, m_fLifetimeMax, m_fLifetimeRandExponent,
  1068. pParticles, start_block, n_blocks );
  1069. }
  1070. else
  1071. {
  1072. InitScalarAttributeRandomRangeBlock( PARTICLE_ATTRIBUTE_LIFE_DURATION,
  1073. m_fLifetimeMin, m_fLifetimeMax, pParticles, start_block, n_blocks );
  1074. }
  1075. }
  1076. };
  1077. DEFINE_PARTICLE_OPERATOR( C_INIT_RandomLifeTime, "Lifetime Random", OPERATOR_GENERIC );
  1078. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_RandomLifeTime )
  1079. DMXELEMENT_UNPACK_FIELD( "lifetime_min", "0", float, m_fLifetimeMin )
  1080. DMXELEMENT_UNPACK_FIELD( "lifetime_max", "0", float, m_fLifetimeMax )
  1081. DMXELEMENT_UNPACK_FIELD( "lifetime_random_exponent", "1", float, m_fLifetimeRandExponent )
  1082. END_PARTICLE_OPERATOR_UNPACK( C_INIT_RandomLifeTime )
  1083. void C_INIT_RandomLifeTime::InitNewParticlesScalar(
  1084. CParticleCollection *pParticles, int start_p,
  1085. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  1086. {
  1087. for( ; nParticleCount--; start_p++ )
  1088. {
  1089. float *dtime = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_LIFE_DURATION, start_p );
  1090. *dtime = pParticles->RandomFloatExp( m_fLifetimeMin, m_fLifetimeMax, m_fLifetimeRandExponent );
  1091. }
  1092. }
  1093. //-----------------------------------------------------------------------------
  1094. // Random radius
  1095. //-----------------------------------------------------------------------------
  1096. class C_INIT_RandomRadius : public CParticleOperatorInstance
  1097. {
  1098. DECLARE_PARTICLE_OPERATOR( C_INIT_RandomRadius );
  1099. uint32 GetWrittenAttributes( void ) const
  1100. {
  1101. return PARTICLE_ATTRIBUTE_RADIUS_MASK;
  1102. }
  1103. uint32 GetReadAttributes( void ) const
  1104. {
  1105. return 0;
  1106. }
  1107. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  1108. int nParticleCount, int nAttributeWriteMask, void *pContext ) const;
  1109. virtual void InitNewParticlesBlock( CParticleCollection *pParticles,
  1110. int start_block, int n_blocks, int nAttributeWriteMask,
  1111. void *pContext ) const
  1112. {
  1113. if ( m_flRadiusRandExponent != 1.0f )
  1114. {
  1115. InitScalarAttributeRandomRangeExpBlock( PARTICLE_ATTRIBUTE_RADIUS,
  1116. m_flRadiusMin, m_flRadiusMax, m_flRadiusRandExponent,
  1117. pParticles, start_block, n_blocks );
  1118. }
  1119. else
  1120. {
  1121. InitScalarAttributeRandomRangeBlock( PARTICLE_ATTRIBUTE_RADIUS,
  1122. m_flRadiusMin, m_flRadiusMax,
  1123. pParticles, start_block, n_blocks );
  1124. }
  1125. }
  1126. float m_flRadiusMin;
  1127. float m_flRadiusMax;
  1128. float m_flRadiusRandExponent;
  1129. };
  1130. DEFINE_PARTICLE_OPERATOR( C_INIT_RandomRadius, "Radius Random", OPERATOR_PI_RADIUS );
  1131. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_RandomRadius )
  1132. DMXELEMENT_UNPACK_FIELD( "radius_min", "1", float, m_flRadiusMin )
  1133. DMXELEMENT_UNPACK_FIELD( "radius_max", "1", float, m_flRadiusMax )
  1134. DMXELEMENT_UNPACK_FIELD( "radius_random_exponent", "1", float, m_flRadiusRandExponent )
  1135. END_PARTICLE_OPERATOR_UNPACK( C_INIT_RandomRadius )
  1136. void C_INIT_RandomRadius::InitNewParticlesScalar(
  1137. CParticleCollection *pParticles, int start_p,
  1138. int nParticleCount, int nAttributeWriteMask,
  1139. void *pContext) const
  1140. {
  1141. for( ; nParticleCount--; start_p++ )
  1142. {
  1143. float *r = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_RADIUS, start_p );
  1144. *r = pParticles->RandomFloatExp( m_flRadiusMin, m_flRadiusMax, m_flRadiusRandExponent );
  1145. }
  1146. }
  1147. //-----------------------------------------------------------------------------
  1148. // Random alpha
  1149. //-----------------------------------------------------------------------------
  1150. class C_INIT_RandomAlpha : public CParticleOperatorInstance
  1151. {
  1152. DECLARE_PARTICLE_OPERATOR( C_INIT_RandomAlpha );
  1153. uint32 GetWrittenAttributes( void ) const
  1154. {
  1155. return PARTICLE_ATTRIBUTE_ALPHA_MASK;
  1156. }
  1157. uint32 GetReadAttributes( void ) const
  1158. {
  1159. return 0;
  1160. }
  1161. virtual void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  1162. {
  1163. m_flAlphaMin = m_nAlphaMin / 255.0f;
  1164. m_flAlphaMax = m_nAlphaMax / 255.0f;
  1165. }
  1166. virtual void InitNewParticlesBlock( CParticleCollection *pParticles,
  1167. int start_block, int n_blocks, int nAttributeWriteMask,
  1168. void *pContext ) const
  1169. {
  1170. if ( m_flAlphaRandExponent != 1.0f )
  1171. {
  1172. InitScalarAttributeRandomRangeExpBlock( PARTICLE_ATTRIBUTE_ALPHA,
  1173. m_flAlphaMin, m_flAlphaMax, m_flAlphaRandExponent,
  1174. pParticles, start_block, n_blocks );
  1175. }
  1176. else
  1177. {
  1178. InitScalarAttributeRandomRangeBlock( PARTICLE_ATTRIBUTE_ALPHA,
  1179. m_flAlphaMin, m_flAlphaMax,
  1180. pParticles, start_block, n_blocks );
  1181. }
  1182. }
  1183. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p, int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  1184. {
  1185. for( ; nParticleCount--; start_p++ )
  1186. {
  1187. float *pAlpha = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_ALPHA, start_p );
  1188. *pAlpha = pParticles->RandomFloatExp( m_flAlphaMin, m_flAlphaMax, m_flAlphaRandExponent );
  1189. }
  1190. }
  1191. int m_nAlphaMin;
  1192. int m_nAlphaMax;
  1193. float m_flAlphaMin;
  1194. float m_flAlphaMax;
  1195. float m_flAlphaRandExponent;
  1196. };
  1197. DEFINE_PARTICLE_OPERATOR( C_INIT_RandomAlpha, "Alpha Random", OPERATOR_PI_ALPHA );
  1198. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_RandomAlpha )
  1199. DMXELEMENT_UNPACK_FIELD( "alpha_min", "255", int, m_nAlphaMin )
  1200. DMXELEMENT_UNPACK_FIELD( "alpha_max", "255", int, m_nAlphaMax )
  1201. DMXELEMENT_UNPACK_FIELD( "alpha_random_exponent", "1", float, m_flAlphaRandExponent )
  1202. END_PARTICLE_OPERATOR_UNPACK( C_INIT_RandomAlpha )
  1203. //-----------------------------------------------------------------------------
  1204. // Random rotation
  1205. //-----------------------------------------------------------------------------
  1206. class CGeneralRandomRotation : public CParticleOperatorInstance
  1207. {
  1208. protected:
  1209. virtual int GetAttributeToInit( void ) const = 0;
  1210. uint32 GetWrittenAttributes( void ) const
  1211. {
  1212. return (1 << GetAttributeToInit() );
  1213. }
  1214. uint32 GetReadAttributes( void ) const
  1215. {
  1216. return 0;
  1217. }
  1218. virtual void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  1219. {
  1220. m_flRadians = m_flDegrees * ( M_PI / 180.0f );
  1221. m_flRadiansMin = m_flDegreesMin * ( M_PI / 180.0f );
  1222. m_flRadiansMax = m_flDegreesMax * ( M_PI / 180.0f );
  1223. }
  1224. virtual void InitNewParticlesBlock( CParticleCollection *pParticles,
  1225. int start_block, int n_blocks, int nAttributeWriteMask,
  1226. void *pContext ) const
  1227. {
  1228. if ( m_flRotationRandExponent != 1.0f )
  1229. {
  1230. InitScalarAttributeRandomRangeExpBlock( GetAttributeToInit(),
  1231. m_flRadiansMin, m_flRadiansMax, m_flRotationRandExponent,
  1232. pParticles, start_block, n_blocks );
  1233. }
  1234. else
  1235. {
  1236. InitScalarAttributeRandomRangeBlock( GetAttributeToInit(),
  1237. m_flRadiansMin, m_flRadiansMax,
  1238. pParticles, start_block, n_blocks );
  1239. }
  1240. }
  1241. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p, int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  1242. {
  1243. for( ; nParticleCount--; start_p++ )
  1244. {
  1245. float *drot = pParticles->GetFloatAttributePtrForWrite( GetAttributeToInit(), start_p );
  1246. *drot = m_flRadians + pParticles->RandomFloatExp( m_flRadiansMin, m_flRadiansMax, m_flRotationRandExponent );
  1247. }
  1248. }
  1249. // User-specified range
  1250. float m_flDegreesMin;
  1251. float m_flDegreesMax;
  1252. float m_flDegrees;
  1253. // Converted range
  1254. float m_flRadiansMin;
  1255. float m_flRadiansMax;
  1256. float m_flRadians;
  1257. float m_flRotationRandExponent;
  1258. };
  1259. class CAddGeneralRandomRotation : public CParticleOperatorInstance
  1260. {
  1261. protected:
  1262. virtual int GetAttributeToInit( void ) const = 0;
  1263. uint32 GetWrittenAttributes( void ) const
  1264. {
  1265. return (1 << GetAttributeToInit() );
  1266. }
  1267. uint32 GetReadAttributes( void ) const
  1268. {
  1269. return (1 << GetAttributeToInit() );
  1270. }
  1271. virtual bool InitMultipleOverride() { return true; }
  1272. virtual void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  1273. {
  1274. m_flRadians = m_flDegrees * ( M_PI / 180.0f );
  1275. m_flRadiansMin = m_flDegreesMin * ( M_PI / 180.0f );
  1276. m_flRadiansMax = m_flDegreesMax * ( M_PI / 180.0f );
  1277. }
  1278. virtual void InitNewParticlesBlock( CParticleCollection *pParticles,
  1279. int start_block, int n_blocks, int nAttributeWriteMask,
  1280. void *pContext ) const
  1281. {
  1282. AddScalarAttributeRandomRangeBlock( GetAttributeToInit(),
  1283. m_flRadiansMin, m_flRadiansMax, m_flRotationRandExponent,
  1284. pParticles, start_block, n_blocks, m_bRandomlyFlipDirection );
  1285. }
  1286. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p, int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  1287. {
  1288. if ( !m_bRandomlyFlipDirection )
  1289. {
  1290. for( ; nParticleCount--; start_p++ )
  1291. {
  1292. float *pAttr = pParticles->GetFloatAttributePtrForWrite( GetAttributeToInit(), start_p );
  1293. *pAttr += m_flRadians + pParticles->RandomFloatExp( m_flRadiansMin, m_flRadiansMax, m_flRotationRandExponent );
  1294. }
  1295. }
  1296. else
  1297. {
  1298. for( ; nParticleCount--; start_p++ )
  1299. {
  1300. float *pAttr = pParticles->GetFloatAttributePtrForWrite( GetAttributeToInit(), start_p );
  1301. float flSpeed = m_flRadians + pParticles->RandomFloatExp( m_flRadiansMin, m_flRadiansMax, m_flRotationRandExponent );
  1302. bool bFlip = ( pParticles->RandomFloat( -1.0f, 1.0f ) >= 0.0f );
  1303. *pAttr += bFlip ? -flSpeed : flSpeed;
  1304. }
  1305. }
  1306. }
  1307. // User-specified range
  1308. float m_flDegreesMin;
  1309. float m_flDegreesMax;
  1310. float m_flDegrees;
  1311. // Converted range
  1312. float m_flRadiansMin;
  1313. float m_flRadiansMax;
  1314. float m_flRadians;
  1315. float m_flRotationRandExponent;
  1316. bool m_bRandomlyFlipDirection;
  1317. };
  1318. //-----------------------------------------------------------------------------
  1319. // Random rotation
  1320. //-----------------------------------------------------------------------------
  1321. class C_INIT_RandomRotation : public CGeneralRandomRotation
  1322. {
  1323. DECLARE_PARTICLE_OPERATOR( C_INIT_RandomRotation );
  1324. virtual int GetAttributeToInit( void ) const
  1325. {
  1326. return PARTICLE_ATTRIBUTE_ROTATION;
  1327. }
  1328. };
  1329. DEFINE_PARTICLE_OPERATOR( C_INIT_RandomRotation, "Rotation Random", OPERATOR_PI_ROTATION );
  1330. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_RandomRotation )
  1331. DMXELEMENT_UNPACK_FIELD( "rotation_initial", "0", float, m_flDegrees )
  1332. DMXELEMENT_UNPACK_FIELD( "rotation_offset_min", "0", float, m_flDegreesMin )
  1333. DMXELEMENT_UNPACK_FIELD( "rotation_offset_max", "360", float, m_flDegreesMax )
  1334. DMXELEMENT_UNPACK_FIELD( "rotation_random_exponent", "1", float, m_flRotationRandExponent )
  1335. END_PARTICLE_OPERATOR_UNPACK( C_INIT_RandomRotation )
  1336. //-----------------------------------------------------------------------------
  1337. // Random rotation speed
  1338. //-----------------------------------------------------------------------------
  1339. class C_INIT_RandomRotationSpeed : public CAddGeneralRandomRotation
  1340. {
  1341. DECLARE_PARTICLE_OPERATOR( C_INIT_RandomRotationSpeed );
  1342. virtual int GetAttributeToInit( void ) const
  1343. {
  1344. return PARTICLE_ATTRIBUTE_ROTATION_SPEED;
  1345. }
  1346. };
  1347. DEFINE_PARTICLE_OPERATOR( C_INIT_RandomRotationSpeed, "Rotation Speed Random", OPERATOR_GENERIC );
  1348. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_RandomRotationSpeed )
  1349. DMXELEMENT_UNPACK_FIELD( "rotation_speed_constant", "0", float, m_flDegrees )
  1350. DMXELEMENT_UNPACK_FIELD( "rotation_speed_random_min", "0", float, m_flDegreesMin )
  1351. DMXELEMENT_UNPACK_FIELD( "rotation_speed_random_max", "360", float, m_flDegreesMax )
  1352. DMXELEMENT_UNPACK_FIELD( "rotation_speed_random_exponent", "1", float, m_flRotationRandExponent )
  1353. DMXELEMENT_UNPACK_FIELD( "randomly_flip_direction", "1", bool, m_bRandomlyFlipDirection )
  1354. END_PARTICLE_OPERATOR_UNPACK( C_INIT_RandomRotationSpeed )
  1355. //-----------------------------------------------------------------------------
  1356. // Random yaw
  1357. //-----------------------------------------------------------------------------
  1358. class C_INIT_RandomYaw : public CGeneralRandomRotation
  1359. {
  1360. DECLARE_PARTICLE_OPERATOR( C_INIT_RandomYaw );
  1361. virtual int GetAttributeToInit( void ) const
  1362. {
  1363. return PARTICLE_ATTRIBUTE_YAW;
  1364. }
  1365. };
  1366. DEFINE_PARTICLE_OPERATOR( C_INIT_RandomYaw, "Rotation Yaw Random", OPERATOR_PI_YAW );
  1367. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_RandomYaw )
  1368. DMXELEMENT_UNPACK_FIELD( "yaw_initial", "0", float, m_flDegrees )
  1369. DMXELEMENT_UNPACK_FIELD( "yaw_offset_min", "0", float, m_flDegreesMin )
  1370. DMXELEMENT_UNPACK_FIELD( "yaw_offset_max", "360", float, m_flDegreesMax )
  1371. DMXELEMENT_UNPACK_FIELD( "yaw_random_exponent", "1", float, m_flRotationRandExponent )
  1372. END_PARTICLE_OPERATOR_UNPACK( C_INIT_RandomYaw )
  1373. //-----------------------------------------------------------------------------
  1374. // Random color
  1375. //-----------------------------------------------------------------------------
  1376. class C_INIT_RandomColor : public CParticleOperatorInstance
  1377. {
  1378. DECLARE_PARTICLE_OPERATOR( C_INIT_RandomColor );
  1379. uint32 GetWrittenAttributes( void ) const
  1380. {
  1381. return PARTICLE_ATTRIBUTE_TINT_RGB_MASK;
  1382. }
  1383. uint32 GetReadAttributes( void ) const
  1384. {
  1385. return 0;
  1386. }
  1387. struct C_OP_RandomColorContext_t
  1388. {
  1389. Vector m_vPrevPosition;
  1390. };
  1391. size_t GetRequiredContextBytes( void ) const
  1392. {
  1393. return sizeof( C_OP_RandomColorContext_t );
  1394. }
  1395. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  1396. {
  1397. C_OP_RandomColorContext_t *pCtx=reinterpret_cast<C_OP_RandomColorContext_t *>( pContext );
  1398. pCtx->m_vPrevPosition = vec3_origin;
  1399. }
  1400. virtual void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  1401. {
  1402. m_flNormColorMin[0] = (float) m_ColorMin[0] / 255.0f;
  1403. m_flNormColorMin[1] = (float) m_ColorMin[1] / 255.0f;
  1404. m_flNormColorMin[2] = (float) m_ColorMin[2] / 255.0f;
  1405. m_flNormColorMax[0] = (float) m_ColorMax[0] / 255.0f;
  1406. m_flNormColorMax[1] = (float) m_ColorMax[1] / 255.0f;
  1407. m_flNormColorMax[2] = (float) m_ColorMax[2] / 255.0f;
  1408. }
  1409. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p, int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  1410. {
  1411. C_OP_RandomColorContext_t *pCtx=reinterpret_cast<C_OP_RandomColorContext_t *>( pContext );
  1412. Color tint( 255, 255, 255, 255 );
  1413. // If we're factoring in luminosity or tint, then get our lighting info for this position
  1414. if ( m_flTintPerc )
  1415. {
  1416. if ( pParticles->m_pParent && pParticles->m_pParent->m_LocalLightingCP == m_nTintCP )
  1417. {
  1418. tint = pParticles->m_pParent->m_LocalLighting;
  1419. }
  1420. else
  1421. {
  1422. // FIXME: Really, we want the emission point for each particle, but for now, we do it more cheaply
  1423. // Get our control point
  1424. Vector vecOrigin;
  1425. pParticles->GetControlPointAtTime( m_nTintCP, pParticles->m_flCurTime, &vecOrigin );
  1426. if ( ( ( pCtx->m_vPrevPosition - vecOrigin ).Length() >= m_flUpdateThreshold ) || ( pParticles->m_LocalLightingCP == -1 ) )
  1427. {
  1428. g_pParticleSystemMgr->Query()->GetLightingAtPoint( vecOrigin, tint );
  1429. pParticles->m_LocalLighting = tint;
  1430. pParticles->m_LocalLightingCP = m_nTintCP;
  1431. pCtx->m_vPrevPosition = vecOrigin;
  1432. }
  1433. else
  1434. tint = pParticles->m_LocalLighting;
  1435. }
  1436. tint[0] = max ( m_TintMin[0], min( tint[0], m_TintMax[0] ) );
  1437. tint[1] = max ( m_TintMin[1], min( tint[1], m_TintMax[1] ) );
  1438. tint[2] = max ( m_TintMin[2], min( tint[2], m_TintMax[2] ) );
  1439. }
  1440. float randomPerc;
  1441. float *pColor;
  1442. for( ; nParticleCount--; start_p++ )
  1443. {
  1444. pColor = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_TINT_RGB, start_p );
  1445. randomPerc = pParticles->RandomFloat( 0.0f, 1.0f );
  1446. // Randomly choose a range between the two colors
  1447. pColor[0] = m_flNormColorMin[0] + ( ( m_flNormColorMax[0] - m_flNormColorMin[0] ) * randomPerc );
  1448. pColor[4] = m_flNormColorMin[1] + ( ( m_flNormColorMax[1] - m_flNormColorMin[1] ) * randomPerc );
  1449. pColor[8] = m_flNormColorMin[2] + ( ( m_flNormColorMax[2] - m_flNormColorMin[2] ) * randomPerc );
  1450. // Tint the particles
  1451. if ( m_flTintPerc )
  1452. {
  1453. pColor[0] = Lerp( m_flTintPerc, (float) pColor[0], (float) tint.r() / 255.0f );
  1454. pColor[4] = Lerp( m_flTintPerc, (float) pColor[4], (float) tint.g() / 255.0f );
  1455. pColor[8] = Lerp( m_flTintPerc, (float) pColor[8], (float) tint.b() / 255.0f );
  1456. }
  1457. }
  1458. }
  1459. virtual void InitNewParticlesBlock( CParticleCollection *pParticles,
  1460. int start_block, int n_blocks, int nAttributeWriteMask,
  1461. void *pContext ) const
  1462. {
  1463. C_OP_RandomColorContext_t *pCtx=reinterpret_cast<C_OP_RandomColorContext_t *>( pContext );
  1464. Color tint( 255, 255, 255, 255 );
  1465. size_t attr_stride;
  1466. FourVectors *pColor = pParticles->Get4VAttributePtrForWrite( PARTICLE_ATTRIBUTE_TINT_RGB, &attr_stride );
  1467. pColor += attr_stride * start_block;
  1468. FourVectors fvColorMin;
  1469. fvColorMin.DuplicateVector( Vector (m_flNormColorMin[0], m_flNormColorMin[1], m_flNormColorMin[2] ) );
  1470. FourVectors fvColorWidth;
  1471. fvColorWidth.DuplicateVector( Vector (m_flNormColorMax[0] - m_flNormColorMin[0], m_flNormColorMax[1] - m_flNormColorMin[1], m_flNormColorMax[2] - m_flNormColorMin[2] ) );
  1472. int nRandContext = GetSIMDRandContext();
  1473. // If we're factoring in luminosity or tint, then get our lighting info for this position
  1474. if ( m_flTintPerc )
  1475. {
  1476. if ( pParticles->m_pParent && pParticles->m_pParent->m_LocalLightingCP == m_nTintCP )
  1477. {
  1478. tint = pParticles->m_pParent->m_LocalLighting;
  1479. }
  1480. else
  1481. {
  1482. // FIXME: Really, we want the emission point for each particle, but for now, we do it more cheaply
  1483. // Get our control point
  1484. Vector vecOrigin;
  1485. pParticles->GetControlPointAtTime( m_nTintCP, pParticles->m_flCurTime, &vecOrigin );
  1486. if ( ( ( pCtx->m_vPrevPosition - vecOrigin ).Length() >= m_flUpdateThreshold ) || ( pParticles->m_LocalLightingCP == -1 ) )
  1487. {
  1488. g_pParticleSystemMgr->Query()->GetLightingAtPoint( vecOrigin, tint );
  1489. pParticles->m_LocalLighting = tint;
  1490. pParticles->m_LocalLightingCP = m_nTintCP;
  1491. pCtx->m_vPrevPosition = vecOrigin;
  1492. }
  1493. else
  1494. tint = pParticles->m_LocalLighting;
  1495. }
  1496. tint[0] = max ( m_TintMin[0], min( tint[0], m_TintMax[0] ) );
  1497. tint[1] = max ( m_TintMin[1], min( tint[1], m_TintMax[1] ) );
  1498. tint[2] = max ( m_TintMin[2], min( tint[2], m_TintMax[2] ) );
  1499. FourVectors fvTint;
  1500. fvTint.DuplicateVector( Vector ( tint[0], tint[1], tint[2] ) );
  1501. fltx4 fl4Divisor = ReplicateX4( 1.0f / 255.0f );
  1502. fvTint *= fl4Divisor;
  1503. fltx4 fl4TintPrc = ReplicateX4( m_flTintPerc );
  1504. while( n_blocks-- )
  1505. {
  1506. FourVectors fvColor = fvColorWidth;
  1507. FourVectors fvColor2 = fvTint;
  1508. fvColor *= RandSIMD( nRandContext );
  1509. fvColor += fvColorMin;
  1510. fvColor2 -= fvColor;
  1511. fvColor2 *= fl4TintPrc;
  1512. fvColor2 += fvColor;
  1513. *pColor = fvColor2;
  1514. pColor += attr_stride;
  1515. }
  1516. }
  1517. else
  1518. {
  1519. while( n_blocks-- )
  1520. {
  1521. FourVectors fvColor = fvColorWidth;
  1522. fvColor *= RandSIMD( nRandContext );
  1523. fvColor += fvColorMin;
  1524. *pColor = fvColor;
  1525. pColor += attr_stride;
  1526. }
  1527. }
  1528. ReleaseSIMDRandContext( nRandContext );
  1529. }
  1530. virtual uint64 GetReadControlPointMask() const
  1531. {
  1532. return 1ULL << m_nTintCP;
  1533. }
  1534. float m_flNormColorMin[3];
  1535. float m_flNormColorMax[3];
  1536. Color m_ColorMin;
  1537. Color m_ColorMax;
  1538. Color m_TintMin;
  1539. Color m_TintMax;
  1540. float m_flTintPerc;
  1541. float m_flUpdateThreshold;
  1542. int m_nTintCP;
  1543. };
  1544. DEFINE_PARTICLE_OPERATOR( C_INIT_RandomColor, "Color Random", OPERATOR_PI_TINT_RGB );
  1545. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_RandomColor )
  1546. DMXELEMENT_UNPACK_FIELD( "color1", "255 255 255 255", Color, m_ColorMin )
  1547. DMXELEMENT_UNPACK_FIELD( "color2", "255 255 255 255", Color, m_ColorMax )
  1548. DMXELEMENT_UNPACK_FIELD( "tint_perc", "0.0", float, m_flTintPerc )
  1549. DMXELEMENT_UNPACK_FIELD( "tint control point", "0", int, m_nTintCP )
  1550. DMXELEMENT_UNPACK_FIELD( "tint clamp min", "0 0 0 0", Color, m_TintMin )
  1551. DMXELEMENT_UNPACK_FIELD( "tint clamp max", "255 255 255 255", Color, m_TintMax )
  1552. DMXELEMENT_UNPACK_FIELD( "tint update movement threshold", "32", float, m_flUpdateThreshold )
  1553. END_PARTICLE_OPERATOR_UNPACK( C_INIT_RandomColor )
  1554. //-----------------------------------------------------------------------------
  1555. // Trail Length
  1556. //-----------------------------------------------------------------------------
  1557. class C_INIT_RandomTrailLength : public CParticleOperatorInstance
  1558. {
  1559. DECLARE_PARTICLE_OPERATOR( C_INIT_RandomTrailLength );
  1560. uint32 GetWrittenAttributes( void ) const
  1561. {
  1562. return PARTICLE_ATTRIBUTE_TRAIL_LENGTH_MASK;
  1563. }
  1564. uint32 GetReadAttributes( void ) const
  1565. {
  1566. return 0;
  1567. }
  1568. virtual void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  1569. {
  1570. }
  1571. virtual void InitNewParticlesBlock( CParticleCollection *pParticles,
  1572. int start_block, int n_blocks, int nAttributeWriteMask,
  1573. void *pContext ) const
  1574. {
  1575. if ( m_flLengthRandExponent != 1.0f )
  1576. {
  1577. InitScalarAttributeRandomRangeExpBlock( PARTICLE_ATTRIBUTE_TRAIL_LENGTH,
  1578. m_flMinLength, m_flMaxLength, m_flLengthRandExponent,
  1579. pParticles, start_block, n_blocks );
  1580. }
  1581. else
  1582. {
  1583. InitScalarAttributeRandomRangeBlock( PARTICLE_ATTRIBUTE_TRAIL_LENGTH,
  1584. m_flMinLength, m_flMaxLength,
  1585. pParticles, start_block, n_blocks );
  1586. }
  1587. }
  1588. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p, int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  1589. {
  1590. float *pLength;
  1591. for( ; nParticleCount--; start_p++ )
  1592. {
  1593. pLength = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_TRAIL_LENGTH, start_p );
  1594. *pLength = pParticles->RandomFloatExp( m_flMinLength, m_flMaxLength, m_flLengthRandExponent );
  1595. }
  1596. }
  1597. float m_flMinLength;
  1598. float m_flMaxLength;
  1599. float m_flLengthRandExponent;
  1600. };
  1601. DEFINE_PARTICLE_OPERATOR( C_INIT_RandomTrailLength, "Trail Length Random", OPERATOR_GENERIC );
  1602. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_RandomTrailLength )
  1603. DMXELEMENT_UNPACK_FIELD( "length_min", "0.1", float, m_flMinLength )
  1604. DMXELEMENT_UNPACK_FIELD( "length_max", "0.1", float, m_flMaxLength )
  1605. DMXELEMENT_UNPACK_FIELD( "length_random_exponent", "1", float, m_flLengthRandExponent )
  1606. END_PARTICLE_OPERATOR_UNPACK( C_INIT_RandomTrailLength )
  1607. //-----------------------------------------------------------------------------
  1608. // Random sequence
  1609. //-----------------------------------------------------------------------------
  1610. class C_INIT_RandomSequence : public CParticleOperatorInstance
  1611. {
  1612. DECLARE_PARTICLE_OPERATOR( C_INIT_RandomSequence );
  1613. uint32 GetWrittenAttributes( void ) const
  1614. {
  1615. return PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER_MASK;
  1616. }
  1617. uint32 GetReadAttributes( void ) const
  1618. {
  1619. return 0;
  1620. }
  1621. virtual void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  1622. {
  1623. // TODO: Validate the ranges here!
  1624. }
  1625. virtual void InitNewParticlesBlock( CParticleCollection *pParticles,
  1626. int start_block, int n_blocks, int nAttributeWriteMask,
  1627. void *pContext ) const
  1628. {
  1629. InitScalarAttributeRandomRangeBlock( PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER,
  1630. m_nSequenceMin, m_nSequenceMax,
  1631. pParticles, start_block, n_blocks );
  1632. }
  1633. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p, int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  1634. {
  1635. float *pSequence;
  1636. for( ; nParticleCount--; start_p++ )
  1637. {
  1638. pSequence = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER, start_p );
  1639. *pSequence = pParticles->RandomInt( m_nSequenceMin, m_nSequenceMax );
  1640. }
  1641. }
  1642. int m_nSequenceMin;
  1643. int m_nSequenceMax;
  1644. };
  1645. DEFINE_PARTICLE_OPERATOR( C_INIT_RandomSequence, "Sequence Random", OPERATOR_GENERIC );
  1646. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_RandomSequence )
  1647. DMXELEMENT_UNPACK_FIELD( "sequence_min", "0", int, m_nSequenceMin )
  1648. DMXELEMENT_UNPACK_FIELD( "sequence_max", "0", int, m_nSequenceMax )
  1649. END_PARTICLE_OPERATOR_UNPACK( C_INIT_RandomSequence )
  1650. //-----------------------------------------------------------------------------
  1651. // Position Warp Initializer
  1652. // Scales initial position and velocity of particles within a random vector range
  1653. //-----------------------------------------------------------------------------
  1654. class C_INIT_PositionWarp : public CParticleOperatorInstance
  1655. {
  1656. DECLARE_PARTICLE_OPERATOR( C_INIT_PositionOffset );
  1657. Vector m_vecWarpMin;
  1658. Vector m_vecWarpMax;
  1659. int m_nControlPointNumber;
  1660. float m_flWarpTime, m_flWarpStartTime;
  1661. bool m_bInvertWarp;
  1662. uint32 GetWrittenAttributes( void ) const
  1663. {
  1664. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  1665. }
  1666. uint32 GetReadAttributes( void ) const
  1667. {
  1668. return PARTICLE_ATTRIBUTE_CREATION_TIME;
  1669. }
  1670. virtual uint64 GetReadControlPointMask() const
  1671. {
  1672. return 1ULL << m_nControlPointNumber;
  1673. }
  1674. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  1675. int nParticleCount, int nAttributeWriteMask,
  1676. void *pContext) const;
  1677. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  1678. {
  1679. m_nControlPointNumber = max( 0, min( MAX_PARTICLE_CONTROL_POINTS-1, m_nControlPointNumber ) );
  1680. }
  1681. bool InitMultipleOverride ( void ) { return true; }
  1682. };
  1683. DEFINE_PARTICLE_OPERATOR( C_INIT_PositionWarp, "Position Modify Warp Random", OPERATOR_GENERIC );
  1684. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_PositionWarp )
  1685. DMXELEMENT_UNPACK_FIELD( "control point number", "0", int, m_nControlPointNumber )
  1686. DMXELEMENT_UNPACK_FIELD( "warp min", "1 1 1", Vector, m_vecWarpMin )
  1687. DMXELEMENT_UNPACK_FIELD( "warp max", "1 1 1", Vector, m_vecWarpMax )
  1688. DMXELEMENT_UNPACK_FIELD( "warp transition time (treats min/max as start/end sizes)", "0", float , m_flWarpTime )
  1689. DMXELEMENT_UNPACK_FIELD( "warp transition start time", "0", float , m_flWarpStartTime )
  1690. DMXELEMENT_UNPACK_FIELD( "reverse warp (0/1)", "0", bool , m_bInvertWarp )
  1691. END_PARTICLE_OPERATOR_UNPACK( C_INIT_PositionWarp )
  1692. void C_INIT_PositionWarp::InitNewParticlesScalar(
  1693. CParticleCollection *pParticles, int start_p,
  1694. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  1695. {
  1696. Vector vecWarpStart = m_vecWarpMin;
  1697. Vector vecWarpEnd = m_vecWarpMax;
  1698. if ( m_bInvertWarp )
  1699. {
  1700. vecWarpStart = m_vecWarpMax;
  1701. vecWarpEnd = m_vecWarpMin;
  1702. }
  1703. for( ; nParticleCount--; start_p++ )
  1704. {
  1705. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, start_p );
  1706. float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, start_p );
  1707. const float *ct = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, start_p );
  1708. Vector randpos;
  1709. if ( m_flWarpTime != 0.0f )
  1710. {
  1711. float flWarpEnd = m_flWarpStartTime + m_flWarpTime;
  1712. float flPercentage = RemapValClamped( *ct, m_flWarpStartTime, flWarpEnd, 0.0, 1.0 );
  1713. VectorLerp( vecWarpStart, vecWarpEnd, flPercentage, randpos );
  1714. }
  1715. else
  1716. {
  1717. pParticles->RandomVector( m_vecWarpMin, m_vecWarpMax, &randpos );
  1718. }
  1719. matrix3x4_t mat;
  1720. pParticles->GetControlPointTransformAtTime( m_nControlPointNumber, *ct, &mat );
  1721. Vector vecTransformLocal = vec3_origin;
  1722. Vector vecParticlePosition, vecParticlePosition_prev ;
  1723. SetVectorFromAttribute( vecParticlePosition, xyz );
  1724. SetVectorFromAttribute( vecParticlePosition_prev, pxyz );
  1725. // rotate particles from world space into local
  1726. VectorITransform( vecParticlePosition, mat, vecTransformLocal );
  1727. // multiply position by desired amount
  1728. vecTransformLocal.x *= randpos.x;
  1729. vecTransformLocal.y *= randpos.y;
  1730. vecTransformLocal.z *= randpos.z;
  1731. // rotate back into world space
  1732. VectorTransform( vecTransformLocal, mat, vecParticlePosition );
  1733. // rinse, repeat
  1734. VectorITransform( vecParticlePosition_prev, mat, vecTransformLocal );
  1735. vecTransformLocal.x *= randpos.x;
  1736. vecTransformLocal.y *= randpos.y;
  1737. vecTransformLocal.z *= randpos.z;
  1738. VectorTransform( vecTransformLocal, mat, vecParticlePosition_prev );
  1739. // set positions into floats
  1740. SetVectorAttribute( xyz, vecParticlePosition );
  1741. SetVectorAttribute( pxyz, vecParticlePosition_prev );
  1742. }
  1743. }
  1744. //-----------------------------------------------------------------------------
  1745. // noise initializer
  1746. //-----------------------------------------------------------------------------
  1747. class C_INIT_CreationNoise : public CParticleOperatorInstance
  1748. {
  1749. DECLARE_PARTICLE_OPERATOR( C_INIT_CreationNoise );
  1750. uint32 GetWrittenAttributes( void ) const
  1751. {
  1752. return 1 << m_nFieldOutput;
  1753. }
  1754. uint32 GetReadAttributes( void ) const
  1755. {
  1756. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_XYZ_MASK;
  1757. }
  1758. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  1759. int nParticleCount, int nAttributeWriteMask,
  1760. void *pContext) const;
  1761. void InitNewParticlesBlock( CParticleCollection *pParticles,
  1762. int start_block, int n_blocks, int nAttributeWriteMask,
  1763. void *pContext ) const;
  1764. virtual bool IsScrubSafe() { return true; }
  1765. int m_nFieldOutput;
  1766. bool m_bAbsVal, m_bAbsValInv;
  1767. float m_flOffset;
  1768. float m_flOutputMin;
  1769. float m_flOutputMax;
  1770. float m_flNoiseScale, m_flNoiseScaleLoc;
  1771. Vector m_vecOffsetLoc;
  1772. float m_flWorldTimeScale;
  1773. };
  1774. DEFINE_PARTICLE_OPERATOR( C_INIT_CreationNoise, "Remap Noise to Scalar", OPERATOR_GENERIC );
  1775. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_CreationNoise )
  1776. DMXELEMENT_UNPACK_FIELD( "time noise coordinate scale","0.1",float,m_flNoiseScale)
  1777. DMXELEMENT_UNPACK_FIELD( "spatial noise coordinate scale","0.001",float,m_flNoiseScaleLoc)
  1778. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "3", int, m_nFieldOutput, "intchoice particlefield_scalar" )
  1779. DMXELEMENT_UNPACK_FIELD( "time coordinate offset","0", float, m_flOffset )
  1780. DMXELEMENT_UNPACK_FIELD( "spatial coordinate offset","0 0 0", Vector, m_vecOffsetLoc )
  1781. DMXELEMENT_UNPACK_FIELD( "absolute value","0", bool, m_bAbsVal )
  1782. DMXELEMENT_UNPACK_FIELD( "invert absolute value","0", bool, m_bAbsValInv )
  1783. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  1784. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  1785. DMXELEMENT_UNPACK_FIELD( "world time noise coordinate scale","0", float, m_flWorldTimeScale )
  1786. END_PARTICLE_OPERATOR_UNPACK( C_INIT_CreationNoise );
  1787. void C_INIT_CreationNoise::InitNewParticlesBlock( CParticleCollection *pParticles,
  1788. int start_block, int n_blocks, int nAttributeWriteMask,
  1789. void *pContext ) const
  1790. {
  1791. float flAbsScale;
  1792. fltx4 fl4AbsVal;
  1793. fl4AbsVal = CmpEqSIMD( Four_Zeros, Four_Zeros );
  1794. flAbsScale = 0.5;
  1795. // Set up values for more optimal absolute value calculations inside the loop
  1796. if ( m_bAbsVal )
  1797. {
  1798. fl4AbsVal = LoadAlignedSIMD( (float *) g_SIMD_clear_signmask );
  1799. flAbsScale = 1.0;
  1800. }
  1801. float fMin = m_flOutputMin;
  1802. float fMax = m_flOutputMax;
  1803. if ( ATTRIBUTES_WHICH_ARE_ANGLES & (1 << m_nFieldOutput ) )
  1804. {
  1805. fMin *= ( M_PI / 180.0f );
  1806. fMax *= ( M_PI / 180.0f );
  1807. }
  1808. float CoordScale = m_flNoiseScale;
  1809. float CoordScaleLoc = m_flNoiseScaleLoc;
  1810. float ValueScale, ValueBase;
  1811. ValueScale = ( flAbsScale *( fMax - fMin ) );
  1812. ValueBase = ( fMin+ ( ( 1.0 - flAbsScale ) *( fMax - fMin ) ) );
  1813. fltx4 fl4ValueBase = ReplicateX4( ValueBase );
  1814. fltx4 fl4ValueScale = ReplicateX4( ValueScale );
  1815. size_t attr_stride;
  1816. fltx4 *pAttr = pParticles->GetM128AttributePtrForWrite( m_nFieldOutput, &attr_stride );
  1817. pAttr += attr_stride * start_block;
  1818. const FourVectors *pxyz = pParticles->Get4VAttributePtr( PARTICLE_ATTRIBUTE_XYZ, &attr_stride );
  1819. pxyz += attr_stride * start_block;
  1820. const fltx4 *pCreationTime = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, &attr_stride );
  1821. pCreationTime += attr_stride * start_block;
  1822. //setup
  1823. fltx4 fl4Offset = ReplicateX4( m_flOffset );
  1824. FourVectors fvOffsetLoc;
  1825. fvOffsetLoc.DuplicateVector( m_vecOffsetLoc );
  1826. FourVectors fvCoordBase;
  1827. fvCoordBase.x = AddSIMD(*pCreationTime, fl4Offset);
  1828. fvCoordBase.y = AddSIMD(*pCreationTime, fl4Offset);
  1829. fvCoordBase.z = AddSIMD(*pCreationTime, fl4Offset);
  1830. fvCoordBase *= CoordScale;
  1831. while( n_blocks-- )
  1832. {
  1833. FourVectors fvCoordLoc = *pxyz;
  1834. fvCoordLoc += fvOffsetLoc;
  1835. FourVectors fvCoord = fvCoordBase;
  1836. fvCoordLoc *= CoordScaleLoc;
  1837. fvCoord += fvCoordLoc;
  1838. fltx4 fl4Noise;
  1839. fl4Noise = NoiseSIMD( fvCoord );
  1840. fl4Noise = AndSIMD ( fl4Noise, fl4AbsVal );
  1841. if ( m_bAbsValInv )
  1842. {
  1843. fl4Noise = SubSIMD( Four_Ones, fl4Noise );
  1844. }
  1845. fltx4 fl4InitialNoise;
  1846. fl4InitialNoise = AddSIMD( fl4ValueBase, ( MulSIMD( fl4ValueScale, fl4Noise ) ) );
  1847. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & (1 << m_nFieldOutput ) )
  1848. {
  1849. fl4InitialNoise = MinSIMD( Four_Ones, fl4InitialNoise );
  1850. fl4InitialNoise = MaxSIMD( Four_Zeros, fl4InitialNoise );
  1851. }
  1852. *( pAttr ) = fl4InitialNoise;
  1853. pAttr += attr_stride;
  1854. pxyz += attr_stride;
  1855. }
  1856. }
  1857. void C_INIT_CreationNoise::InitNewParticlesScalar(
  1858. CParticleCollection *pParticles, int start_p,
  1859. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  1860. {
  1861. float flAbsScale;
  1862. int nAbsVal;
  1863. nAbsVal = 0xffffffff;
  1864. flAbsScale = 0.5;
  1865. if ( m_bAbsVal )
  1866. {
  1867. nAbsVal = 0x7fffffff;
  1868. flAbsScale = 1.0;
  1869. }
  1870. float fMin = m_flOutputMin;
  1871. float fMax = m_flOutputMax;
  1872. if ( ATTRIBUTES_WHICH_ARE_ANGLES & (1 << m_nFieldOutput ) )
  1873. {
  1874. fMin *= ( M_PI / 180.0f );
  1875. fMax *= ( M_PI / 180.0f );
  1876. }
  1877. float CoordScale = m_flNoiseScale;
  1878. float CoordScaleLoc = m_flNoiseScaleLoc;
  1879. float ValueScale, ValueBase;
  1880. ValueScale = ( flAbsScale *( fMax - fMin ) );
  1881. ValueBase = ( fMin+ ( ( 1.0 - flAbsScale ) *( fMax - fMin ) ) );
  1882. Vector CoordLoc, CoordWorldTime, CoordBase;
  1883. const float *pCreationTime = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, start_p );
  1884. float Offset = m_flOffset;
  1885. CoordBase = Vector ( (*pCreationTime + Offset), (*pCreationTime + Offset), (*pCreationTime + Offset) );
  1886. CoordBase *= CoordScale;
  1887. CoordWorldTime = Vector( (Plat_MSTime() * m_flWorldTimeScale), (Plat_MSTime() * m_flWorldTimeScale), (Plat_MSTime() * m_flWorldTimeScale) );
  1888. CoordBase += CoordWorldTime;
  1889. for( ; nParticleCount--; start_p++ )
  1890. {
  1891. const float *pxyz = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_XYZ, start_p );
  1892. float *pAttr = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, start_p );
  1893. Vector Coord = CoordBase;
  1894. CoordLoc.x = pxyz[0];
  1895. CoordLoc.y = pxyz[4];
  1896. CoordLoc.z = pxyz[8];
  1897. CoordLoc += m_vecOffsetLoc;
  1898. CoordLoc *= CoordScaleLoc;
  1899. Coord += CoordLoc;
  1900. fltx4 flNoise128;
  1901. FourVectors fvNoise;
  1902. fvNoise.DuplicateVector( Coord );
  1903. flNoise128 = NoiseSIMD( fvNoise );
  1904. float flNoise = SubFloat( flNoise128, 0 );
  1905. *( (int *) &flNoise) &= nAbsVal;
  1906. if ( m_bAbsValInv )
  1907. {
  1908. flNoise = 1.0 - flNoise;
  1909. }
  1910. float flInitialNoise = ( ValueBase + ( ValueScale * flNoise ) );
  1911. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & (1 << m_nFieldOutput ) )
  1912. {
  1913. flInitialNoise = clamp(flInitialNoise, 0.0f, 1.0f );
  1914. }
  1915. *( pAttr ) = flInitialNoise;
  1916. }
  1917. }
  1918. class C_INIT_CreateAlongPath : public CParticleOperatorInstance
  1919. {
  1920. DECLARE_PARTICLE_OPERATOR( C_INIT_CreateAlongPath );
  1921. float m_fMaxDistance;
  1922. struct CPathParameters m_PathParams;
  1923. uint32 GetWrittenAttributes( void ) const
  1924. {
  1925. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  1926. }
  1927. uint32 GetReadAttributes( void ) const
  1928. {
  1929. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  1930. }
  1931. virtual uint64 GetReadControlPointMask() const
  1932. {
  1933. uint64 nStartMask = ( 1ULL << m_PathParams.m_nStartControlPointNumber ) - 1;
  1934. uint64 nEndMask = ( 1ULL << ( m_PathParams.m_nEndControlPointNumber + 1 ) ) - 1;
  1935. return nEndMask & (~nStartMask);
  1936. }
  1937. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  1938. {
  1939. m_PathParams.ClampControlPointIndices();
  1940. }
  1941. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  1942. int nParticleCount, int nAttributeWriteMask,
  1943. void *pContext) const;
  1944. };
  1945. DEFINE_PARTICLE_OPERATOR( C_INIT_CreateAlongPath, "Position Along Path Random", OPERATOR_PI_POSITION );
  1946. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_CreateAlongPath )
  1947. DMXELEMENT_UNPACK_FIELD( "maximum distance", "0", float, m_fMaxDistance )
  1948. DMXELEMENT_UNPACK_FIELD( "bulge", "0", float, m_PathParams.m_flBulge )
  1949. DMXELEMENT_UNPACK_FIELD( "start control point number", "0", int, m_PathParams.m_nStartControlPointNumber )
  1950. DMXELEMENT_UNPACK_FIELD( "end control point number", "0", int, m_PathParams.m_nEndControlPointNumber )
  1951. DMXELEMENT_UNPACK_FIELD( "bulge control 0=random 1=orientation of start pnt 2=orientation of end point", "0", int, m_PathParams.m_nBulgeControl )
  1952. DMXELEMENT_UNPACK_FIELD( "mid point position", "0.5", float, m_PathParams.m_flMidPoint )
  1953. END_PARTICLE_OPERATOR_UNPACK( C_INIT_CreateAlongPath )
  1954. void C_INIT_CreateAlongPath::InitNewParticlesScalar(
  1955. CParticleCollection *pParticles, int start_p,
  1956. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  1957. {
  1958. for( ; nParticleCount--; start_p++ )
  1959. {
  1960. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, start_p );
  1961. const float *ct = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, start_p );
  1962. float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, start_p );
  1963. Vector StartPnt, MidP, EndPnt;
  1964. pParticles->CalculatePathValues( m_PathParams, *ct, &StartPnt, &MidP, &EndPnt);
  1965. float t=pParticles->RandomFloat( 0.0, 1.0 );
  1966. Vector randpos;
  1967. pParticles->RandomVector( -m_fMaxDistance, m_fMaxDistance, &randpos );
  1968. // form delta terms needed for quadratic bezier
  1969. Vector Delta0=MidP-StartPnt;
  1970. Vector Delta1 = EndPnt-MidP;
  1971. Vector L0 = StartPnt+t*Delta0;
  1972. Vector L1 = MidP+t*Delta1;
  1973. Vector Pnt = L0+(L1-L0)*t;
  1974. Pnt+=randpos;
  1975. xyz[0] = Pnt.x;
  1976. xyz[4] = Pnt.y;
  1977. xyz[8] = Pnt.z;
  1978. if ( pxyz && ( nAttributeWriteMask & PARTICLE_ATTRIBUTE_PREV_XYZ_MASK ) )
  1979. {
  1980. pxyz[0] = Pnt.x;
  1981. pxyz[4] = Pnt.y;
  1982. pxyz[8] = Pnt.z;
  1983. }
  1984. }
  1985. }
  1986. class C_INIT_MoveBetweenPoints : public CParticleOperatorInstance
  1987. {
  1988. DECLARE_PARTICLE_OPERATOR( C_INIT_MoveBetweenPoints );
  1989. float m_flSpeedMin, m_flSpeedMax;
  1990. float m_flEndSpread;
  1991. float m_flStartOffset;
  1992. int m_nEndControlPointNumber;
  1993. uint32 GetWrittenAttributes( void ) const
  1994. {
  1995. return PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_XYZ_MASK;
  1996. }
  1997. uint32 GetReadAttributes( void ) const
  1998. {
  1999. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  2000. }
  2001. virtual uint64 GetReadControlPointMask() const
  2002. {
  2003. return 1ULL << m_nEndControlPointNumber;
  2004. }
  2005. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  2006. int nParticleCount, int nAttributeWriteMask,
  2007. void *pContext) const;
  2008. };
  2009. DEFINE_PARTICLE_OPERATOR( C_INIT_MoveBetweenPoints, "Move Particles Between 2 Control Points", OPERATOR_GENERIC );
  2010. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_MoveBetweenPoints )
  2011. DMXELEMENT_UNPACK_FIELD( "minimum speed", "1", float, m_flSpeedMin )
  2012. DMXELEMENT_UNPACK_FIELD( "maximum speed", "1", float, m_flSpeedMax )
  2013. DMXELEMENT_UNPACK_FIELD( "end spread", "0", float, m_flEndSpread )
  2014. DMXELEMENT_UNPACK_FIELD( "start offset", "0", float, m_flStartOffset )
  2015. DMXELEMENT_UNPACK_FIELD( "end control point", "1", int, m_nEndControlPointNumber )
  2016. END_PARTICLE_OPERATOR_UNPACK( C_INIT_MoveBetweenPoints )
  2017. void C_INIT_MoveBetweenPoints::InitNewParticlesScalar(
  2018. CParticleCollection *pParticles, int start_p,
  2019. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  2020. {
  2021. bool bMoveStartPnt = ( m_flStartOffset > 0.0 );
  2022. for( ; nParticleCount--; start_p++ )
  2023. {
  2024. float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, start_p );
  2025. float *pPrevXYZ = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, start_p );
  2026. const float *ct = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, start_p );
  2027. float *dtime = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_LIFE_DURATION, start_p );
  2028. Vector StartPnt( pxyz[0], pxyz[4], pxyz[8] );
  2029. Vector vecControlPoint;
  2030. pParticles->GetControlPointAtTime( m_nEndControlPointNumber, *ct, &vecControlPoint );
  2031. Vector randpos(0,0,0);
  2032. if ( m_flEndSpread > 0.0 )
  2033. {
  2034. pParticles->RandomVectorInUnitSphere( &randpos );
  2035. randpos *= m_flEndSpread;
  2036. }
  2037. vecControlPoint += randpos;
  2038. Vector vDelta = vecControlPoint - StartPnt;
  2039. float flLen = VectorLength( vDelta );
  2040. if ( bMoveStartPnt )
  2041. {
  2042. StartPnt += ( m_flStartOffset/(flLen+FLT_EPSILON) ) * vDelta;
  2043. vDelta = vecControlPoint - StartPnt;
  2044. flLen = VectorLength( vDelta );
  2045. }
  2046. float flVel = pParticles->RandomFloat( m_flSpeedMin, m_flSpeedMax );
  2047. *dtime = flLen/( flVel+FLT_EPSILON);
  2048. Vector poffset = vDelta * (flVel/flLen ) ;
  2049. poffset *= pParticles->m_flPreviousDt;
  2050. if ( bMoveStartPnt )
  2051. {
  2052. pxyz[0] = StartPnt.x;
  2053. pxyz[1] = StartPnt.y;
  2054. pxyz[2] = StartPnt.z;
  2055. }
  2056. pPrevXYZ[0] = pxyz[0] - poffset.x;
  2057. pPrevXYZ[4] = pxyz[4] - poffset.y;
  2058. pPrevXYZ[8] = pxyz[8] - poffset.z;
  2059. }
  2060. }
  2061. //-----------------------------------------------------------------------------
  2062. // Remap Scalar Initializer
  2063. //-----------------------------------------------------------------------------
  2064. class C_INIT_RemapScalar : public CParticleOperatorInstance
  2065. {
  2066. DECLARE_PARTICLE_OPERATOR( C_INIT_RemapScalar );
  2067. uint32 GetWrittenAttributes( void ) const
  2068. {
  2069. return 1 << m_nFieldOutput;
  2070. }
  2071. uint32 GetReadAttributes( void ) const
  2072. {
  2073. return 1 << m_nFieldInput;
  2074. }
  2075. bool InitMultipleOverride ( void ) { return true; }
  2076. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  2077. int nParticleCount, int nAttributeWriteMask,
  2078. void *pContext) const;
  2079. int m_nFieldInput;
  2080. int m_nFieldOutput;
  2081. float m_flInputMin;
  2082. float m_flInputMax;
  2083. float m_flOutputMin;
  2084. float m_flOutputMax;
  2085. float m_flStartTime;
  2086. float m_flEndTime;
  2087. bool m_bScaleInitialRange;
  2088. bool m_bActiveRange;
  2089. };
  2090. DEFINE_PARTICLE_OPERATOR( C_INIT_RemapScalar, "Remap Initial Scalar", OPERATOR_GENERIC );
  2091. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_RemapScalar )
  2092. DMXELEMENT_UNPACK_FIELD( "emitter lifetime start time (seconds)", "-1", float, m_flStartTime )
  2093. DMXELEMENT_UNPACK_FIELD( "emitter lifetime end time (seconds)", "-1", float, m_flEndTime )
  2094. DMXELEMENT_UNPACK_FIELD_USERDATA( "input field", "8", int, m_nFieldInput, "intchoice particlefield_scalar" )
  2095. DMXELEMENT_UNPACK_FIELD( "input minimum","0", float, m_flInputMin )
  2096. DMXELEMENT_UNPACK_FIELD( "input maximum","1", float, m_flInputMax )
  2097. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "3", int, m_nFieldOutput, "intchoice particlefield_scalar" )
  2098. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  2099. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  2100. DMXELEMENT_UNPACK_FIELD( "output is scalar of initial random range","0", bool, m_bScaleInitialRange )
  2101. DMXELEMENT_UNPACK_FIELD( "only active within specified input range","0", bool, m_bActiveRange )
  2102. END_PARTICLE_OPERATOR_UNPACK( C_INIT_RemapScalar )
  2103. void C_INIT_RemapScalar::InitNewParticlesScalar(
  2104. CParticleCollection *pParticles, int start_p,
  2105. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  2106. {
  2107. const float *pCreationTime;
  2108. // clamp the result to 0 and 1 if it's alpha
  2109. float flMin=m_flOutputMin;
  2110. float flMax=m_flOutputMax;
  2111. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & ( 1 << m_nFieldOutput ) )
  2112. {
  2113. flMin = clamp(m_flOutputMin, 0.0f, 1.0f );
  2114. flMax = clamp(m_flOutputMax, 0.0f, 1.0f );
  2115. }
  2116. // FIXME: SSE-ize
  2117. for( ; nParticleCount--; start_p++ )
  2118. {
  2119. pCreationTime = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, start_p );
  2120. // using raw creation time to map to emitter lifespan
  2121. float flLifeTime = *pCreationTime;
  2122. float flInput;
  2123. if ( ATTRIBUTES_WHICH_ARE_INTS & ( 1 << m_nFieldInput ) )
  2124. {
  2125. const int *pInput = pParticles->GetIntAttributePtr( m_nFieldInput, start_p );
  2126. flInput = float( *pInput );
  2127. }
  2128. else
  2129. {
  2130. const float *pInput = pParticles->GetFloatAttributePtr( m_nFieldInput, start_p );
  2131. flInput = *pInput;
  2132. }
  2133. // only use within start/end time frame and, if set, active input range
  2134. if ( ( ( ( flLifeTime < m_flStartTime ) || ( flLifeTime >= m_flEndTime ) ) && ( ( m_flStartTime != -1.0f) && ( m_flEndTime != -1.0f) ) ) || ( m_bActiveRange && ( flInput < m_flInputMin || flInput > m_flInputMax ) ) )
  2135. continue;
  2136. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, start_p );
  2137. float flOutput = RemapValClamped( flInput, m_flInputMin, m_flInputMax, flMin, flMax );
  2138. if ( m_bScaleInitialRange )
  2139. {
  2140. flOutput = *pOutput * flOutput;
  2141. }
  2142. if ( ATTRIBUTES_WHICH_ARE_INTS & ( 1 << m_nFieldOutput ) )
  2143. {
  2144. *pOutput = int ( flOutput );
  2145. }
  2146. else
  2147. {
  2148. *pOutput = flOutput;
  2149. }
  2150. }
  2151. }
  2152. //-----------------------------------------------------------------------------
  2153. // Inherit Velocity Initializer
  2154. // Causes particles to inherit the velocity of their CP at spawn
  2155. //
  2156. //-----------------------------------------------------------------------------
  2157. class C_INIT_InheritVelocity : public CParticleOperatorInstance
  2158. {
  2159. DECLARE_PARTICLE_OPERATOR( C_INIT_InheritVelocity );
  2160. int m_nControlPointNumber;
  2161. float m_flVelocityScale;
  2162. uint32 GetWrittenAttributes( void ) const
  2163. {
  2164. return PARTICLE_ATTRIBUTE_XYZ_MASK ;
  2165. }
  2166. uint32 GetReadAttributes( void ) const
  2167. {
  2168. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_CREATION_TIME;
  2169. }
  2170. virtual uint64 GetReadControlPointMask() const
  2171. {
  2172. return 1ULL << m_nControlPointNumber;
  2173. }
  2174. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  2175. int nParticleCount, int nAttributeWriteMask,
  2176. void *pContext) const;
  2177. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  2178. {
  2179. m_nControlPointNumber = max( 0, min( MAX_PARTICLE_CONTROL_POINTS-1, m_nControlPointNumber ) );
  2180. }
  2181. bool InitMultipleOverride ( void ) { return true; }
  2182. };
  2183. DEFINE_PARTICLE_OPERATOR( C_INIT_InheritVelocity, "Velocity Inherit from Control Point", OPERATOR_GENERIC );
  2184. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_InheritVelocity )
  2185. DMXELEMENT_UNPACK_FIELD( "control point number", "0", int, m_nControlPointNumber )
  2186. DMXELEMENT_UNPACK_FIELD( "velocity scale", "1", float, m_flVelocityScale )
  2187. END_PARTICLE_OPERATOR_UNPACK( C_INIT_InheritVelocity )
  2188. void C_INIT_InheritVelocity::InitNewParticlesScalar(
  2189. CParticleCollection *pParticles, int start_p,
  2190. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  2191. {
  2192. for( ; nParticleCount--; start_p++ )
  2193. {
  2194. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, start_p );
  2195. const float *ct = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, start_p );
  2196. Vector vecControlPoint;
  2197. pParticles->GetControlPointAtTime( m_nControlPointNumber, *ct, &vecControlPoint );
  2198. Vector vecControlPointPrev;
  2199. pParticles->GetControlPointAtPrevTime( m_nControlPointNumber, &vecControlPointPrev );
  2200. Vector vecDeltaPos = (vecControlPoint - vecControlPointPrev);
  2201. //Vector vecDeltaPos = (vecControlPoint - vecControlPointPrev) * pParticles->m_flDt;
  2202. vecDeltaPos.x *= m_flVelocityScale;
  2203. vecDeltaPos.y *= m_flVelocityScale;
  2204. vecDeltaPos.z *= m_flVelocityScale;
  2205. xyz[0] += vecDeltaPos.x;
  2206. xyz[4] += vecDeltaPos.y;
  2207. xyz[8] += vecDeltaPos.z;
  2208. }
  2209. }
  2210. //-----------------------------------------------------------------------------
  2211. // Pre-Age Noise
  2212. // Sets particle creation time back to treat newly spawned particle as if
  2213. // part of its life has already elapsed.
  2214. //-----------------------------------------------------------------------------
  2215. class C_INIT_AgeNoise : public CParticleOperatorInstance
  2216. {
  2217. DECLARE_PARTICLE_OPERATOR( C_INIT_AgeNoise );
  2218. uint32 GetWrittenAttributes( void ) const
  2219. {
  2220. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  2221. }
  2222. uint32 GetReadAttributes( void ) const
  2223. {
  2224. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK;
  2225. }
  2226. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  2227. int nParticleCount, int nAttributeWriteMask,
  2228. void *pContext) const;
  2229. bool InitMultipleOverride ( void ) { return true; }
  2230. bool m_bAbsVal, m_bAbsValInv;
  2231. float m_flOffset;
  2232. float m_flAgeMin;
  2233. float m_flAgeMax;
  2234. float m_flNoiseScale, m_flNoiseScaleLoc;
  2235. Vector m_vecOffsetLoc;
  2236. };
  2237. DEFINE_PARTICLE_OPERATOR( C_INIT_AgeNoise, "Lifetime Pre-Age Noise", OPERATOR_GENERIC );
  2238. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_AgeNoise )
  2239. DMXELEMENT_UNPACK_FIELD( "time noise coordinate scale","1.0",float,m_flNoiseScale)
  2240. DMXELEMENT_UNPACK_FIELD( "spatial noise coordinate scale","1.0",float,m_flNoiseScaleLoc)
  2241. DMXELEMENT_UNPACK_FIELD( "time coordinate offset","0", float, m_flOffset )
  2242. DMXELEMENT_UNPACK_FIELD( "spatial coordinate offset","0 0 0", Vector, m_vecOffsetLoc )
  2243. DMXELEMENT_UNPACK_FIELD( "absolute value","0", bool, m_bAbsVal )
  2244. DMXELEMENT_UNPACK_FIELD( "invert absolute value","0", bool, m_bAbsValInv )
  2245. DMXELEMENT_UNPACK_FIELD( "start age minimum","0", float, m_flAgeMin )
  2246. DMXELEMENT_UNPACK_FIELD( "start age maximum","1", float, m_flAgeMax )
  2247. END_PARTICLE_OPERATOR_UNPACK( C_INIT_AgeNoise );
  2248. void C_INIT_AgeNoise::InitNewParticlesScalar(
  2249. CParticleCollection *pParticles, int start_p,
  2250. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  2251. {
  2252. float flAbsScale;
  2253. int nAbsVal;
  2254. nAbsVal = 0xffffffff;
  2255. flAbsScale = 0.5;
  2256. if ( m_bAbsVal )
  2257. {
  2258. nAbsVal = 0x7fffffff;
  2259. flAbsScale = 1.0;
  2260. }
  2261. float fMin = m_flAgeMin;
  2262. float fMax = m_flAgeMax;
  2263. float CoordScale = m_flNoiseScale;
  2264. float CoordScaleLoc = m_flNoiseScaleLoc;
  2265. for( ; nParticleCount--; start_p++ )
  2266. {
  2267. const float *pxyz = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_XYZ, start_p );
  2268. const float *pCreationTime = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, start_p );
  2269. const float *pLifespan = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_LIFE_DURATION, start_p );
  2270. float *pAttr = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_CREATION_TIME, start_p );
  2271. float ValueScale, ValueBase;
  2272. Vector Coord, CoordLoc;
  2273. CoordLoc.x = pxyz[0];
  2274. CoordLoc.y = pxyz[4];
  2275. CoordLoc.z = pxyz[8];
  2276. CoordLoc += m_vecOffsetLoc;
  2277. float Offset = m_flOffset;
  2278. Coord = Vector ( (*pCreationTime + Offset), (*pCreationTime + Offset), (*pCreationTime + Offset) );
  2279. Coord *= CoordScale;
  2280. CoordLoc *= CoordScaleLoc;
  2281. Coord += CoordLoc;
  2282. fltx4 flNoise128;
  2283. FourVectors fvNoise;
  2284. fvNoise.DuplicateVector( Coord );
  2285. flNoise128 = NoiseSIMD( fvNoise );
  2286. float flNoise = SubFloat( flNoise128, 0 );
  2287. *( (int *) &flNoise) &= nAbsVal;
  2288. ValueScale = ( flAbsScale *( fMax - fMin ) );
  2289. ValueBase = ( fMin+ ( ( 1.0 - flAbsScale ) *( fMax - fMin ) ) );
  2290. if ( m_bAbsValInv )
  2291. {
  2292. flNoise = 1.0 - flNoise;
  2293. }
  2294. float flInitialNoise = ( ValueBase + ( ValueScale * flNoise ) );
  2295. flInitialNoise = clamp(flInitialNoise, 0.0f, 1.0f );
  2296. flInitialNoise *= *pLifespan;
  2297. *( pAttr ) = *pCreationTime - flInitialNoise;
  2298. }
  2299. }
  2300. //-----------------------------------------------------------------------------
  2301. // LifeTime Sequence Length
  2302. //-----------------------------------------------------------------------------
  2303. class C_INIT_SequenceLifeTime : public CParticleOperatorInstance
  2304. {
  2305. DECLARE_PARTICLE_OPERATOR( C_INIT_SequenceLifeTime );
  2306. float m_flFramerate;
  2307. uint32 GetWrittenAttributes( void ) const
  2308. {
  2309. return PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK;
  2310. }
  2311. uint32 GetReadAttributes( void ) const
  2312. {
  2313. return PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER_MASK;
  2314. }
  2315. bool InitMultipleOverride ( void ) { return true; }
  2316. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  2317. int nParticleCount, int nAttributeWriteMask, void *pContext ) const;
  2318. };
  2319. DEFINE_PARTICLE_OPERATOR( C_INIT_SequenceLifeTime, "Lifetime From Sequence", OPERATOR_GENERIC );
  2320. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_SequenceLifeTime )
  2321. DMXELEMENT_UNPACK_FIELD( "Frames Per Second", "30", float, m_flFramerate )
  2322. END_PARTICLE_OPERATOR_UNPACK( C_INIT_SequenceLifeTime )
  2323. void C_INIT_SequenceLifeTime::InitNewParticlesScalar(
  2324. CParticleCollection *pParticles, int start_p,
  2325. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  2326. {
  2327. if ( ( m_flFramerate != 0.0f ) && ( pParticles->m_Sheet() ) )
  2328. {
  2329. for( ; nParticleCount--; start_p++ )
  2330. {
  2331. const float *flSequence = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER, start_p );
  2332. float *dtime = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_LIFE_DURATION, start_p );
  2333. int nSequence = *flSequence;
  2334. if ( pParticles->m_Sheet()->m_flFrameSpan[nSequence] != 0 )
  2335. {
  2336. *dtime = pParticles->m_Sheet()->m_flFrameSpan[nSequence] / m_flFramerate;
  2337. }
  2338. else
  2339. {
  2340. *dtime = 1.0;
  2341. }
  2342. }
  2343. }
  2344. }
  2345. //-----------------------------------------------------------------------------
  2346. // Create In Hierarchy
  2347. //-----------------------------------------------------------------------------
  2348. class C_INIT_CreateInHierarchy : public CParticleOperatorInstance
  2349. {
  2350. DECLARE_PARTICLE_OPERATOR( C_INIT_CreateInHierarchy );
  2351. float m_fMaxDistance;
  2352. float m_flGrowthTime;
  2353. //float m_flTraceDist;
  2354. float m_flDesiredMidPoint;
  2355. int m_nOrientation;
  2356. float m_flBulgeFactor;
  2357. int m_nDesiredEndPoint;
  2358. int m_nDesiredStartPoint;
  2359. bool m_bUseHighestEndCP;
  2360. Vector m_vecDistanceBias, m_vecDistanceBiasAbs;
  2361. bool m_bDistanceBias, m_bDistanceBiasAbs;
  2362. uint32 GetWrittenAttributes( void ) const
  2363. {
  2364. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  2365. }
  2366. uint32 GetReadAttributes( void ) const
  2367. {
  2368. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  2369. }
  2370. virtual uint64 GetReadControlPointMask() const
  2371. {
  2372. uint64 nStartMask = ( 1ULL << m_nDesiredStartPoint ) - 1;
  2373. uint64 nEndMask = m_bUseHighestEndCP ? 0xFFFFFFFFFFFFFFFFll : ( 1ULL << ( m_nDesiredEndPoint + 1 ) ) - 1;
  2374. return nEndMask & (~nStartMask);
  2375. }
  2376. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  2377. {
  2378. //fixme - confirm CPs
  2379. // m_PathParams.ClampControlPointIndices();
  2380. m_bDistanceBias = ( m_vecDistanceBias.x != 1.0f ) || ( m_vecDistanceBias.y != 1.0f ) || ( m_vecDistanceBias.z != 1.0f );
  2381. m_bDistanceBiasAbs = ( m_vecDistanceBiasAbs.x != 0.0f ) || ( m_vecDistanceBiasAbs.y != 0.0f ) || ( m_vecDistanceBiasAbs.z != 0.0f );
  2382. }
  2383. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  2384. int nParticleCount, int nAttributeWriteMask,
  2385. void *pContext) const;
  2386. };
  2387. DEFINE_PARTICLE_OPERATOR( C_INIT_CreateInHierarchy, "Position In CP Hierarchy", OPERATOR_PI_POSITION );
  2388. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_CreateInHierarchy )
  2389. DMXELEMENT_UNPACK_FIELD( "maximum distance", "0", float, m_fMaxDistance )
  2390. DMXELEMENT_UNPACK_FIELD( "bulge", "0", float, m_flBulgeFactor )
  2391. DMXELEMENT_UNPACK_FIELD( "start control point number", "0", int, m_nDesiredStartPoint )
  2392. DMXELEMENT_UNPACK_FIELD( "end control point number", "1", int, m_nDesiredEndPoint )
  2393. DMXELEMENT_UNPACK_FIELD( "bulge control 0=random 1=orientation of start pnt 2=orientation of end point", "0", int, m_nOrientation )
  2394. DMXELEMENT_UNPACK_FIELD( "mid point position", "0.5", float, m_flDesiredMidPoint )
  2395. DMXELEMENT_UNPACK_FIELD( "growth time", "0.0", float, m_flGrowthTime )
  2396. //DMXELEMENT_UNPACK_FIELD( "trace distance for optional culling", "0.0", float, m_flTraceDist )
  2397. DMXELEMENT_UNPACK_FIELD( "use highest supplied end point", "0", bool, m_bUseHighestEndCP )
  2398. DMXELEMENT_UNPACK_FIELD( "distance_bias", "1 1 1", Vector, m_vecDistanceBias )
  2399. DMXELEMENT_UNPACK_FIELD( "distance_bias_absolute_value", "0 0 0", Vector, m_vecDistanceBiasAbs )
  2400. END_PARTICLE_OPERATOR_UNPACK( C_INIT_CreateInHierarchy )
  2401. void C_INIT_CreateInHierarchy::InitNewParticlesScalar(
  2402. CParticleCollection *pParticles, int start_p,
  2403. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  2404. {
  2405. int nEndCP;
  2406. float flGrowth;
  2407. struct CPathParameters PathParams;
  2408. PathParams.m_flBulge = m_flBulgeFactor;
  2409. PathParams.m_nBulgeControl = m_nOrientation;
  2410. PathParams.m_flMidPoint = m_flDesiredMidPoint;
  2411. int nRealEndPoint;
  2412. if ( m_bUseHighestEndCP )
  2413. {
  2414. nRealEndPoint = pParticles->GetHighestControlPoint();
  2415. }
  2416. else
  2417. {
  2418. nRealEndPoint = m_nDesiredEndPoint;
  2419. }
  2420. for( ; nParticleCount--; start_p++ )
  2421. {
  2422. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, start_p );
  2423. const float *ct = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, start_p );
  2424. float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, start_p );
  2425. if ( ( pParticles->m_flCurTime <= m_flGrowthTime ) && ( nRealEndPoint > 0 ) )
  2426. {
  2427. float flCurrentEndCP = RemapValClamped( *ct, 0.0f, m_flGrowthTime, min( m_nDesiredStartPoint + 1, nRealEndPoint ), nRealEndPoint );
  2428. nEndCP = pParticles->RandomInt( min( m_nDesiredStartPoint + 1, (int)flCurrentEndCP ), flCurrentEndCP );
  2429. // clamp growth to the appropriate values...
  2430. float flEndTime = flCurrentEndCP / float(nRealEndPoint) ;
  2431. flGrowth = RemapValClamped( *ct, 0.0f, m_flGrowthTime, 0.0, flEndTime );
  2432. }
  2433. else
  2434. {
  2435. int nLowestStartPoint = min( m_nDesiredStartPoint + 1, nRealEndPoint );
  2436. nEndCP = pParticles->RandomInt( nLowestStartPoint, nRealEndPoint );
  2437. flGrowth = 1.0;
  2438. }
  2439. PathParams.m_nStartControlPointNumber = pParticles->m_ControlPoints[nEndCP].m_nParent;
  2440. PathParams.m_nEndControlPointNumber = nEndCP;
  2441. Vector StartPnt, MidP, EndPnt;
  2442. pParticles->CalculatePathValues( PathParams, *ct, &StartPnt, &MidP, &EndPnt);
  2443. EndPnt *= flGrowth;
  2444. float t=pParticles->RandomFloat( 0.0, 1.0 );
  2445. Vector randpos;
  2446. pParticles->RandomVector( -m_fMaxDistance, m_fMaxDistance, &randpos );
  2447. if ( m_bDistanceBiasAbs )
  2448. {
  2449. if ( m_vecDistanceBiasAbs.x != 0.0f )
  2450. {
  2451. randpos.x = fabs(randpos.x);
  2452. }
  2453. if ( m_vecDistanceBiasAbs.y != 0.0f )
  2454. {
  2455. randpos.y = fabs(randpos.y);
  2456. }
  2457. if ( m_vecDistanceBiasAbs.z != 0.0f )
  2458. {
  2459. randpos.z = fabs(randpos.z);
  2460. }
  2461. }
  2462. randpos *= m_vecDistanceBias;
  2463. // form delta terms needed for quadratic bezier
  2464. Vector Delta0=MidP-StartPnt;
  2465. Vector Delta1 = EndPnt-MidP;
  2466. Vector L0 = StartPnt+t*Delta0;
  2467. Vector L1 = MidP+t*Delta1;
  2468. Vector Pnt = L0+(L1-L0)*t;
  2469. Pnt+=randpos;
  2470. // Optional Culling based on configurable trace distance. Failing particle are destroyed
  2471. //disabled for now.
  2472. //if ( m_flTraceDist != 0.0f )
  2473. //{
  2474. // // Trace down
  2475. // Vector TraceDir=Vector(0, 0, -1);
  2476. // // now set the trace distance
  2477. // // note - probably need to offset Pnt upwards for some fudge factor on irregular surfaces
  2478. // CBaseTrace tr;
  2479. // Vector RayStart=Pnt;
  2480. // float flRadius = m_flTraceDist;
  2481. // g_pParticleSystemMgr->Query()->TraceLine( RayStart, ( RayStart + ( TraceDir * flRadius ) ), MASK_SOLID, NULL, COLLISION_GROUP_NONE, &tr );
  2482. // if ( tr.fraction == 1.0 )
  2483. // {
  2484. // //If the trace hit nothing, kill the particle.
  2485. // pParticles->KillParticle( start_p );
  2486. // }
  2487. // else
  2488. // {
  2489. // //If we hit something, set particle position to collision position
  2490. // Pnt += tr.endpos;
  2491. // //FIXME - if we add a concept of a particle normal (for example, aligned quads or decals, set it here)
  2492. // }
  2493. //}
  2494. xyz[0] = Pnt.x;
  2495. xyz[4] = Pnt.y;
  2496. xyz[8] = Pnt.z;
  2497. if ( pxyz && ( nAttributeWriteMask & PARTICLE_ATTRIBUTE_PREV_XYZ_MASK ) )
  2498. {
  2499. pxyz[0] = Pnt.x;
  2500. pxyz[4] = Pnt.y;
  2501. pxyz[8] = Pnt.z;
  2502. }
  2503. }
  2504. }
  2505. //-----------------------------------------------------------------------------
  2506. // Remap initial Scalar to Vector Initializer
  2507. //-----------------------------------------------------------------------------
  2508. class C_INIT_RemapScalarToVector : public CParticleOperatorInstance
  2509. {
  2510. DECLARE_PARTICLE_OPERATOR( C_INIT_RemapScalarToVector );
  2511. uint32 GetWrittenAttributes( void ) const
  2512. {
  2513. return 1 << m_nFieldOutput | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  2514. }
  2515. uint32 GetReadAttributes( void ) const
  2516. {
  2517. return 1 << m_nFieldInput;
  2518. }
  2519. virtual uint64 GetReadControlPointMask() const
  2520. {
  2521. return 1ULL << m_nControlPointNumber;
  2522. }
  2523. bool InitMultipleOverride ( void ) { return true; }
  2524. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  2525. int nParticleCount, int nAttributeWriteMask,
  2526. void *pContext) const;
  2527. int m_nFieldInput;
  2528. int m_nFieldOutput;
  2529. float m_flInputMin;
  2530. float m_flInputMax;
  2531. Vector m_vecOutputMin;
  2532. Vector m_vecOutputMax;
  2533. float m_flStartTime;
  2534. float m_flEndTime;
  2535. bool m_bScaleInitialRange;
  2536. int m_nControlPointNumber;
  2537. bool m_bLocalCoords;
  2538. };
  2539. DEFINE_PARTICLE_OPERATOR( C_INIT_RemapScalarToVector, "Remap Scalar to Vector", OPERATOR_GENERIC );
  2540. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_RemapScalarToVector )
  2541. DMXELEMENT_UNPACK_FIELD( "emitter lifetime start time (seconds)", "-1", float, m_flStartTime )
  2542. DMXELEMENT_UNPACK_FIELD( "emitter lifetime end time (seconds)", "-1", float, m_flEndTime )
  2543. DMXELEMENT_UNPACK_FIELD_USERDATA( "input field", "8", int, m_nFieldInput, "intchoice particlefield_scalar" )
  2544. DMXELEMENT_UNPACK_FIELD( "input minimum","0", float, m_flInputMin )
  2545. DMXELEMENT_UNPACK_FIELD( "input maximum","1", float, m_flInputMax )
  2546. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "0", int, m_nFieldOutput, "intchoice particlefield_vector" )
  2547. DMXELEMENT_UNPACK_FIELD( "output minimum","0 0 0", Vector, m_vecOutputMin )
  2548. DMXELEMENT_UNPACK_FIELD( "output maximum","1 1 1", Vector, m_vecOutputMax )
  2549. DMXELEMENT_UNPACK_FIELD( "output is scalar of initial random range","0", bool, m_bScaleInitialRange )
  2550. DMXELEMENT_UNPACK_FIELD( "use local system", "1", bool, m_bLocalCoords )
  2551. DMXELEMENT_UNPACK_FIELD( "control_point_number", "0", int, m_nControlPointNumber )
  2552. END_PARTICLE_OPERATOR_UNPACK( C_INIT_RemapScalarToVector )
  2553. void C_INIT_RemapScalarToVector::InitNewParticlesScalar(
  2554. CParticleCollection *pParticles, int start_p,
  2555. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  2556. {
  2557. const float *pCreationTime;
  2558. // FIXME: SSE-ize
  2559. for( ; nParticleCount--; start_p++ )
  2560. {
  2561. pCreationTime = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, start_p );
  2562. // using raw creation time to map to emitter lifespan
  2563. float flLifeTime = *pCreationTime;
  2564. // only use within start/end time frame
  2565. if ( ( ( flLifeTime < m_flStartTime ) || ( flLifeTime >= m_flEndTime ) ) && ( ( m_flStartTime != -1.0f) && ( m_flEndTime != -1.0f) ) )
  2566. continue;
  2567. const float *pInput = pParticles->GetFloatAttributePtr( m_nFieldInput, start_p );
  2568. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, start_p );
  2569. Vector vecOutput = vec3_origin;
  2570. vecOutput.x = RemapValClamped( *pInput, m_flInputMin, m_flInputMax, m_vecOutputMin.x, m_vecOutputMax.x );
  2571. vecOutput.y = RemapValClamped( *pInput, m_flInputMin, m_flInputMax, m_vecOutputMin.y, m_vecOutputMax.y );
  2572. vecOutput.z = RemapValClamped( *pInput, m_flInputMin, m_flInputMax, m_vecOutputMin.z, m_vecOutputMax.z );
  2573. if ( m_nFieldOutput == 0 )
  2574. {
  2575. float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, start_p );
  2576. if ( !m_bLocalCoords )
  2577. {
  2578. Vector vecControlPoint;
  2579. pParticles->GetControlPointAtTime( m_nControlPointNumber, *pCreationTime, &vecControlPoint );
  2580. vecOutput += vecControlPoint;
  2581. Vector vecOutputPrev = vecOutput;
  2582. if ( m_bScaleInitialRange )
  2583. {
  2584. Vector vecScaleInitial;
  2585. Vector vecScaleInitialPrev;
  2586. SetVectorFromAttribute ( vecScaleInitial, pOutput );
  2587. SetVectorFromAttribute ( vecScaleInitialPrev, pxyz );
  2588. vecOutput *= vecScaleInitial;
  2589. vecOutputPrev *= vecScaleInitialPrev;
  2590. }
  2591. SetVectorAttribute( pOutput, vecOutput );
  2592. SetVectorAttribute( pxyz, vecOutputPrev );
  2593. }
  2594. else
  2595. {
  2596. matrix3x4_t mat;
  2597. pParticles->GetControlPointTransformAtTime( m_nControlPointNumber, *pCreationTime, &mat );
  2598. Vector vecTransformLocal = vec3_origin;
  2599. VectorTransform( vecOutput, mat, vecTransformLocal );
  2600. vecOutput = vecTransformLocal;
  2601. Vector vecOutputPrev = vecOutput;
  2602. if ( m_bScaleInitialRange )
  2603. {
  2604. Vector vecScaleInitial;
  2605. Vector vecScaleInitialPrev;
  2606. SetVectorFromAttribute ( vecScaleInitial, pOutput );
  2607. SetVectorFromAttribute ( vecScaleInitialPrev, pxyz );
  2608. vecOutput *= vecScaleInitial;
  2609. vecOutputPrev *= vecScaleInitialPrev;
  2610. }
  2611. SetVectorAttribute( pOutput, vecOutput );
  2612. SetVectorAttribute( pxyz, vecOutput );
  2613. }
  2614. }
  2615. else
  2616. {
  2617. if ( m_bScaleInitialRange )
  2618. {
  2619. Vector vecScaleInitial;
  2620. SetVectorFromAttribute ( vecScaleInitial, pOutput );
  2621. vecOutput *= vecScaleInitial;
  2622. }
  2623. SetVectorAttribute( pOutput, vecOutput );
  2624. }
  2625. }
  2626. }
  2627. //-----------------------------------------------------------------------------
  2628. // Create particles sequentially along a path
  2629. //-----------------------------------------------------------------------------
  2630. struct SequentialPathContext_t
  2631. {
  2632. int m_nParticleCount;
  2633. float m_flStep;
  2634. int m_nCountAmount;
  2635. };
  2636. class C_INIT_CreateSequentialPath : public CParticleOperatorInstance
  2637. {
  2638. DECLARE_PARTICLE_OPERATOR( C_INIT_CreateSequentialPath );
  2639. float m_fMaxDistance;
  2640. float m_flNumToAssign;
  2641. bool m_bLoop;
  2642. struct CPathParameters m_PathParams;
  2643. uint32 GetWrittenAttributes( void ) const
  2644. {
  2645. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  2646. }
  2647. uint32 GetReadAttributes( void ) const
  2648. {
  2649. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  2650. }
  2651. virtual uint64 GetReadControlPointMask() const
  2652. {
  2653. uint64 nStartMask = ( 1ULL << m_PathParams.m_nStartControlPointNumber ) - 1;
  2654. uint64 nEndMask = ( 1ULL << ( m_PathParams.m_nEndControlPointNumber + 1 ) ) - 1;
  2655. return nEndMask & (~nStartMask);
  2656. }
  2657. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  2658. {
  2659. SequentialPathContext_t *pCtx = reinterpret_cast<SequentialPathContext_t *>( pContext );
  2660. pCtx->m_nParticleCount = 0;
  2661. if ( m_flNumToAssign > 1.0f )
  2662. {
  2663. pCtx->m_flStep = 1.0f / ( m_flNumToAssign - 1 );
  2664. }
  2665. else
  2666. {
  2667. pCtx->m_flStep = 0.0f;
  2668. }
  2669. pCtx->m_nCountAmount = 1;
  2670. }
  2671. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  2672. {
  2673. m_PathParams.ClampControlPointIndices();
  2674. }
  2675. size_t GetRequiredContextBytes( void ) const
  2676. {
  2677. return sizeof( SequentialPathContext_t );
  2678. }
  2679. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  2680. int nParticleCount, int nAttributeWriteMask,
  2681. void *pContext) const;
  2682. };
  2683. DEFINE_PARTICLE_OPERATOR( C_INIT_CreateSequentialPath, "Position Along Path Sequential", OPERATOR_PI_POSITION );
  2684. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_CreateSequentialPath )
  2685. DMXELEMENT_UNPACK_FIELD( "maximum distance", "0", float, m_fMaxDistance )
  2686. DMXELEMENT_UNPACK_FIELD( "bulge", "0", float, m_PathParams.m_flBulge )
  2687. DMXELEMENT_UNPACK_FIELD( "start control point number", "0", int, m_PathParams.m_nStartControlPointNumber )
  2688. DMXELEMENT_UNPACK_FIELD( "end control point number", "0", int, m_PathParams.m_nEndControlPointNumber )
  2689. DMXELEMENT_UNPACK_FIELD( "bulge control 0=random 1=orientation of start pnt 2=orientation of end point", "0", int, m_PathParams.m_nBulgeControl )
  2690. DMXELEMENT_UNPACK_FIELD( "mid point position", "0.5", float, m_PathParams.m_flMidPoint )
  2691. DMXELEMENT_UNPACK_FIELD( "particles to map from start to end", "100", float, m_flNumToAssign )
  2692. DMXELEMENT_UNPACK_FIELD( "restart behavior (0 = bounce, 1 = loop )", "1", bool, m_bLoop )
  2693. END_PARTICLE_OPERATOR_UNPACK( C_INIT_CreateSequentialPath )
  2694. void C_INIT_CreateSequentialPath::InitNewParticlesScalar(
  2695. CParticleCollection *pParticles, int start_p,
  2696. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  2697. {
  2698. // NOTE: Using C_OP_ContinuousEmitter:: avoids a virtual function call
  2699. SequentialPathContext_t *pCtx = reinterpret_cast<SequentialPathContext_t *>( pContext );
  2700. for( ; nParticleCount--; start_p++ )
  2701. {
  2702. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, start_p );
  2703. const float *ct = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, start_p );
  2704. float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, start_p );
  2705. Vector StartPnt, MidP, EndPnt;
  2706. pParticles->CalculatePathValues( m_PathParams, *ct, &StartPnt, &MidP, &EndPnt);
  2707. if ( pCtx->m_nParticleCount >= m_flNumToAssign || pCtx->m_nParticleCount < 0 )
  2708. {
  2709. if ( m_bLoop )
  2710. {
  2711. pCtx->m_nParticleCount = 0;
  2712. }
  2713. else
  2714. {
  2715. pCtx->m_nCountAmount *= -1;
  2716. pCtx->m_nParticleCount = min ( pCtx->m_nParticleCount, (int)( m_flNumToAssign - 1) );
  2717. pCtx->m_nParticleCount = max ( pCtx->m_nParticleCount, 1 );
  2718. }
  2719. }
  2720. float t= pCtx->m_nParticleCount * pCtx->m_flStep;
  2721. Vector randpos;
  2722. pParticles->RandomVector( -m_fMaxDistance, m_fMaxDistance, &randpos );
  2723. // form delta terms needed for quadratic bezier
  2724. Vector Delta0=MidP-StartPnt;
  2725. Vector Delta1 = EndPnt-MidP;
  2726. Vector L0 = StartPnt+t*Delta0;
  2727. Vector L1 = MidP+t*Delta1;
  2728. Vector Pnt = L0+(L1-L0)*t;
  2729. Pnt+=randpos;
  2730. xyz[0] = Pnt.x;
  2731. xyz[4] = Pnt.y;
  2732. xyz[8] = Pnt.z;
  2733. if ( pxyz && ( nAttributeWriteMask & PARTICLE_ATTRIBUTE_PREV_XYZ_MASK ) )
  2734. {
  2735. pxyz[0] = Pnt.x;
  2736. pxyz[4] = Pnt.y;
  2737. pxyz[8] = Pnt.z;
  2738. }
  2739. pCtx->m_nParticleCount += pCtx->m_nCountAmount;
  2740. }
  2741. }
  2742. //-----------------------------------------------------------------------------
  2743. // Initial Repulsion Velocity - repulses the particles from nearby surfaces
  2744. // on spawn
  2745. //-----------------------------------------------------------------------------
  2746. class C_INIT_InitialRepulsionVelocity : public CParticleOperatorInstance
  2747. {
  2748. DECLARE_PARTICLE_OPERATOR( C_INIT_InitialRepulsionVelocity );
  2749. uint32 GetWrittenAttributes( void ) const
  2750. {
  2751. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  2752. }
  2753. uint32 GetReadAttributes( void ) const
  2754. {
  2755. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK | PARTICLE_ATTRIBUTE_RADIUS_MASK;
  2756. }
  2757. virtual uint64 GetReadControlPointMask() const
  2758. {
  2759. return 1ULL << m_nControlPointNumber;
  2760. }
  2761. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  2762. int nParticleCount, int nAttributeWriteMask,
  2763. void *pContext) const;
  2764. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  2765. {
  2766. m_nCollisionGroupNumber = g_pParticleSystemMgr->Query()->GetCollisionGroupFromName( m_CollisionGroupName );
  2767. m_nControlPointNumber = max( 0, min( MAX_PARTICLE_CONTROL_POINTS-1, m_nControlPointNumber ) );
  2768. }
  2769. bool InitMultipleOverride ( void ) { return true; }
  2770. char m_CollisionGroupName[128];
  2771. int m_nCollisionGroupNumber;
  2772. Vector m_vecOutputMin;
  2773. Vector m_vecOutputMax;
  2774. int nRemainingBlocks;
  2775. int m_nControlPointNumber;
  2776. bool m_bPerParticle;
  2777. bool m_bTranslate;
  2778. bool m_bProportional;
  2779. float m_flTraceLength;
  2780. bool m_bPerParticleTR;
  2781. bool m_bInherit;
  2782. int m_nChildCP;
  2783. int m_nChildGroupID;
  2784. };
  2785. DEFINE_PARTICLE_OPERATOR( C_INIT_InitialRepulsionVelocity, "Velocity Repulse from World", OPERATOR_GENERIC );
  2786. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_InitialRepulsionVelocity )
  2787. DMXELEMENT_UNPACK_FIELD( "minimum velocity","0 0 0", Vector, m_vecOutputMin )
  2788. DMXELEMENT_UNPACK_FIELD( "maximum velocity","1 1 1", Vector, m_vecOutputMax )
  2789. DMXELEMENT_UNPACK_FIELD_STRING( "collision group", "NONE", m_CollisionGroupName )
  2790. DMXELEMENT_UNPACK_FIELD( "control_point_number", "0", int, m_nControlPointNumber )
  2791. DMXELEMENT_UNPACK_FIELD( "Per Particle World Collision Tests", "0", bool, m_bPerParticle )
  2792. DMXELEMENT_UNPACK_FIELD( "Use radius for Per Particle Trace Length", "0", bool, m_bPerParticleTR )
  2793. DMXELEMENT_UNPACK_FIELD( "Offset instead of accelerate", "0", bool, m_bTranslate )
  2794. DMXELEMENT_UNPACK_FIELD( "Offset proportional to radius 0/1", "0", bool, m_bProportional )
  2795. DMXELEMENT_UNPACK_FIELD( "Trace Length", "64.0", float, m_flTraceLength )
  2796. DMXELEMENT_UNPACK_FIELD( "Inherit from Parent", "0", bool, m_bInherit )
  2797. DMXELEMENT_UNPACK_FIELD( "control points to broadcast to children (n + 1)", "-1", int, m_nChildCP )
  2798. DMXELEMENT_UNPACK_FIELD( "Child Group ID to affect", "0", int, m_nChildGroupID )
  2799. END_PARTICLE_OPERATOR_UNPACK( C_INIT_InitialRepulsionVelocity );
  2800. void C_INIT_InitialRepulsionVelocity::InitNewParticlesScalar(
  2801. CParticleCollection *pParticles, int start_p,
  2802. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  2803. {
  2804. Vector d[6];
  2805. //All cardinal directions
  2806. d[0] = Vector( 1, 0, 0 );
  2807. d[1] = Vector( -1, 0, 0 );
  2808. d[2] = Vector( 0, 1, 0 );
  2809. d[3] = Vector( 0, -1, 0 );
  2810. d[4] = Vector( 0, 0, 1 );
  2811. d[5] = Vector( 0, 0, -1 );
  2812. //Init the results
  2813. Vector resultDirection;
  2814. float resultForce;
  2815. if ( m_bPerParticle )
  2816. {
  2817. for( ; nParticleCount--; start_p++ )
  2818. {
  2819. float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, start_p );
  2820. float *pxyz_prev = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, start_p );
  2821. const float *radius = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_RADIUS, start_p );
  2822. Vector vecCurrentPos;
  2823. SetVectorFromAttribute( vecCurrentPos, pxyz );
  2824. resultDirection.Init();
  2825. resultForce = 0.0f;
  2826. //Get the aggregate force vector
  2827. for ( int i = 0; i < 6; i++ )
  2828. {
  2829. //Press out
  2830. float flTraceDistance = m_flTraceLength;
  2831. if ( m_bPerParticleTR )
  2832. {
  2833. flTraceDistance = *radius;
  2834. }
  2835. Vector endpos = vecCurrentPos + ( d[i] * flTraceDistance );
  2836. //Trace into the world
  2837. CBaseTrace tr;
  2838. g_pParticleSystemMgr->Query()->TraceLine( vecCurrentPos, endpos, CONTENTS_SOLID, NULL, m_nCollisionGroupNumber, &tr );
  2839. //Push back a proportional amount to the probe
  2840. d[i] = -d[i] * (1.0f-tr.fraction);
  2841. assert(( 1.0f - tr.fraction ) >= 0.0f );
  2842. resultForce += 1.0f-tr.fraction;
  2843. resultDirection += d[i];
  2844. }
  2845. //If we've hit nothing, then point up
  2846. if ( resultDirection == vec3_origin )
  2847. {
  2848. resultDirection = Vector( 0, 0, 1 );
  2849. resultForce = 0.0f;
  2850. }
  2851. //Just return the direction
  2852. VectorNormalize( resultDirection );
  2853. resultDirection *= resultForce;
  2854. Vector vecRepulsionAmount;
  2855. vecRepulsionAmount.x = Lerp( resultForce, m_vecOutputMin.x, m_vecOutputMax.x );
  2856. vecRepulsionAmount.y = Lerp( resultForce, m_vecOutputMin.y, m_vecOutputMax.y );
  2857. vecRepulsionAmount.z = Lerp( resultForce, m_vecOutputMin.z, m_vecOutputMax.z );
  2858. vecRepulsionAmount *= resultDirection;
  2859. if ( m_bProportional )
  2860. {
  2861. vecRepulsionAmount *= *radius;
  2862. }
  2863. pxyz[0] += vecRepulsionAmount.x;
  2864. pxyz[4] += vecRepulsionAmount.y;
  2865. pxyz[8] += vecRepulsionAmount.z;
  2866. if ( m_bTranslate )
  2867. {
  2868. pxyz_prev[0] += vecRepulsionAmount.x;
  2869. pxyz_prev[4] += vecRepulsionAmount.y;
  2870. pxyz_prev[8] += vecRepulsionAmount.z;
  2871. }
  2872. }
  2873. }
  2874. else
  2875. {
  2876. Vector vecRepulsionAmount;
  2877. if ( m_bInherit )
  2878. {
  2879. float *ct = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_CREATION_TIME, start_p );
  2880. pParticles->GetControlPointAtTime( m_nControlPointNumber, *ct, &resultDirection );
  2881. Vector vecPassedForce;
  2882. pParticles->GetControlPointAtTime( m_nControlPointNumber+1, *ct, &vecPassedForce );
  2883. vecRepulsionAmount.x = Lerp( vecPassedForce.x, m_vecOutputMin.x, m_vecOutputMax.x );
  2884. vecRepulsionAmount.y = Lerp( vecPassedForce.x, m_vecOutputMin.y, m_vecOutputMax.y );
  2885. vecRepulsionAmount.z = Lerp( vecPassedForce.x, m_vecOutputMin.z, m_vecOutputMax.z );
  2886. vecRepulsionAmount *= resultDirection;
  2887. }
  2888. else
  2889. {
  2890. float *ct = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_CREATION_TIME, start_p );
  2891. Vector vecControlPoint;
  2892. pParticles->GetControlPointAtTime( m_nControlPointNumber, *ct, &vecControlPoint );
  2893. Vector vecCurrentPos = vecControlPoint;
  2894. resultDirection.Init();
  2895. resultForce = 0.0f;
  2896. //Get the aggregate force vector
  2897. for ( int i = 0; i < 6; i++ )
  2898. {
  2899. //Press out
  2900. Vector endpos = vecCurrentPos + ( d[i] * m_flTraceLength );
  2901. //Trace into the world
  2902. CBaseTrace tr;
  2903. g_pParticleSystemMgr->Query()->TraceLine( vecCurrentPos, endpos, CONTENTS_SOLID, NULL, m_nCollisionGroupNumber, &tr );
  2904. //Push back a proportional amount to the probe
  2905. d[i] = -d[i] * (1.0f-tr.fraction);
  2906. assert(( 1.0f - tr.fraction ) >= 0.0f );
  2907. resultForce += 1.0f-tr.fraction;
  2908. resultDirection += d[i];
  2909. }
  2910. //If we've hit nothing, then point up
  2911. if ( resultDirection == vec3_origin )
  2912. {
  2913. resultDirection = Vector( 0, 0, 1 );
  2914. resultForce = 0.0f;
  2915. }
  2916. //Just return the direction
  2917. VectorNormalize( resultDirection );
  2918. resultDirection *= resultForce;
  2919. vecRepulsionAmount.x = Lerp( resultForce, m_vecOutputMin.x, m_vecOutputMax.x );
  2920. vecRepulsionAmount.y = Lerp( resultForce, m_vecOutputMin.y, m_vecOutputMax.y );
  2921. vecRepulsionAmount.z = Lerp( resultForce, m_vecOutputMin.z, m_vecOutputMax.z );
  2922. vecRepulsionAmount *= resultDirection;
  2923. if ( m_nChildCP != -1 )
  2924. {
  2925. for( CParticleCollection *pChild = pParticles->m_Children.m_pHead; pChild; pChild = pChild->m_pNext )
  2926. {
  2927. if ( pChild->GetGroupID() == m_nChildGroupID )
  2928. {
  2929. Vector vecPassForce = Vector(resultForce, 0, 0);
  2930. pChild->SetControlPoint( m_nChildCP, resultDirection );
  2931. pChild->SetControlPoint( m_nChildCP+1, vecPassForce );
  2932. }
  2933. }
  2934. }
  2935. }
  2936. for( ; nParticleCount--; start_p++ )
  2937. {
  2938. float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, start_p );
  2939. float *pxyz_prev = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, start_p );
  2940. const float *radius = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_RADIUS, start_p );
  2941. if ( m_bProportional )
  2942. {
  2943. vecRepulsionAmount *= *radius;
  2944. }
  2945. pxyz[0] += vecRepulsionAmount.x;
  2946. pxyz[4] += vecRepulsionAmount.y;
  2947. pxyz[8] += vecRepulsionAmount.z;
  2948. if ( m_bTranslate )
  2949. {
  2950. pxyz_prev[0] += vecRepulsionAmount.x;
  2951. pxyz_prev[4] += vecRepulsionAmount.y;
  2952. pxyz_prev[8] += vecRepulsionAmount.z;
  2953. }
  2954. }
  2955. }
  2956. }
  2957. //-----------------------------------------------------------------------------
  2958. // Random Yaw Flip
  2959. //-----------------------------------------------------------------------------
  2960. class C_INIT_RandomYawFlip : public CParticleOperatorInstance
  2961. {
  2962. DECLARE_PARTICLE_OPERATOR( C_INIT_RandomYawFlip );
  2963. uint32 GetWrittenAttributes( void ) const
  2964. {
  2965. return PARTICLE_ATTRIBUTE_YAW_MASK;
  2966. }
  2967. uint32 GetReadAttributes( void ) const
  2968. {
  2969. return 0;
  2970. }
  2971. bool InitMultipleOverride ( void ) { return true; }
  2972. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  2973. int nParticleCount, int nAttributeWriteMask, void *pContext ) const;
  2974. float m_flPercent;
  2975. };
  2976. DEFINE_PARTICLE_OPERATOR( C_INIT_RandomYawFlip, "Rotation Yaw Flip Random", OPERATOR_GENERIC );
  2977. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_RandomYawFlip )
  2978. DMXELEMENT_UNPACK_FIELD( "Flip Percentage", ".5", float, m_flPercent )
  2979. END_PARTICLE_OPERATOR_UNPACK( C_INIT_RandomYawFlip )
  2980. void C_INIT_RandomYawFlip::InitNewParticlesScalar(
  2981. CParticleCollection *pParticles, int start_p,
  2982. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  2983. {
  2984. for( ; nParticleCount--; start_p++ )
  2985. {
  2986. float flChance = pParticles->RandomFloat( 0.0, 1.0 );
  2987. if ( flChance < m_flPercent )
  2988. {
  2989. float flRadians = 180 * ( M_PI / 180.0f );
  2990. float *drot = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_YAW, start_p );
  2991. *drot += flRadians;
  2992. }
  2993. }
  2994. }
  2995. //-----------------------------------------------------------------------------
  2996. // Random second sequence
  2997. //-----------------------------------------------------------------------------
  2998. class C_INIT_RandomSecondSequence : public CParticleOperatorInstance
  2999. {
  3000. DECLARE_PARTICLE_OPERATOR( C_INIT_RandomSecondSequence );
  3001. uint32 GetWrittenAttributes( void ) const
  3002. {
  3003. return PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER1_MASK;
  3004. }
  3005. uint32 GetReadAttributes( void ) const
  3006. {
  3007. return 0;
  3008. }
  3009. virtual void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  3010. {
  3011. // TODO: Validate the ranges here!
  3012. }
  3013. virtual void InitNewParticlesBlock( CParticleCollection *pParticles,
  3014. int start_block, int n_blocks, int nAttributeWriteMask,
  3015. void *pContext ) const
  3016. {
  3017. InitScalarAttributeRandomRangeBlock( PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER1,
  3018. m_nSequenceMin, m_nSequenceMax,
  3019. pParticles, start_block, n_blocks );
  3020. }
  3021. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p, int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  3022. {
  3023. float *pSequence;
  3024. for( ; nParticleCount--; start_p++ )
  3025. {
  3026. pSequence = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER1, start_p );
  3027. *pSequence = pParticles->RandomInt( m_nSequenceMin, m_nSequenceMax );
  3028. }
  3029. }
  3030. int m_nSequenceMin;
  3031. int m_nSequenceMax;
  3032. };
  3033. DEFINE_PARTICLE_OPERATOR( C_INIT_RandomSecondSequence, "Sequence Two Random", OPERATOR_GENERIC );
  3034. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_RandomSecondSequence )
  3035. DMXELEMENT_UNPACK_FIELD( "sequence_min", "0", int, m_nSequenceMin )
  3036. DMXELEMENT_UNPACK_FIELD( "sequence_max", "0", int, m_nSequenceMax )
  3037. END_PARTICLE_OPERATOR_UNPACK( C_INIT_RandomSecondSequence )
  3038. //-----------------------------------------------------------------------------
  3039. // Remap CP to Scalar Initializer
  3040. //-----------------------------------------------------------------------------
  3041. class C_INIT_RemapCPtoScalar : public CParticleOperatorInstance
  3042. {
  3043. DECLARE_PARTICLE_OPERATOR( C_INIT_RemapCPtoScalar );
  3044. uint32 GetWrittenAttributes( void ) const
  3045. {
  3046. return 1 << m_nFieldOutput;
  3047. }
  3048. uint32 GetReadAttributes( void ) const
  3049. {
  3050. return 0;
  3051. }
  3052. virtual uint64 GetReadControlPointMask() const
  3053. {
  3054. return 1ULL << m_nCPInput;
  3055. }
  3056. bool InitMultipleOverride ( void ) { return true; }
  3057. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  3058. int nParticleCount, int nAttributeWriteMask,
  3059. void *pContext) const;
  3060. virtual void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  3061. {
  3062. m_nField = int (clamp (m_nField, 0, 2));
  3063. }
  3064. int m_nCPInput;
  3065. int m_nFieldOutput;
  3066. int m_nField;
  3067. float m_flInputMin;
  3068. float m_flInputMax;
  3069. float m_flOutputMin;
  3070. float m_flOutputMax;
  3071. float m_flStartTime;
  3072. float m_flEndTime;
  3073. bool m_bScaleInitialRange;
  3074. };
  3075. DEFINE_PARTICLE_OPERATOR( C_INIT_RemapCPtoScalar, "Remap Control Point to Scalar", OPERATOR_GENERIC );
  3076. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_RemapCPtoScalar )
  3077. DMXELEMENT_UNPACK_FIELD( "emitter lifetime start time (seconds)", "-1", float, m_flStartTime )
  3078. DMXELEMENT_UNPACK_FIELD( "emitter lifetime end time (seconds)", "-1", float, m_flEndTime )
  3079. DMXELEMENT_UNPACK_FIELD( "input control point number", "0", int, m_nCPInput )
  3080. DMXELEMENT_UNPACK_FIELD( "input minimum","0", float, m_flInputMin )
  3081. DMXELEMENT_UNPACK_FIELD( "input maximum","1", float, m_flInputMax )
  3082. DMXELEMENT_UNPACK_FIELD( "input field 0-2 X/Y/Z","0", int, m_nField )
  3083. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "3", int, m_nFieldOutput, "intchoice particlefield_scalar" )
  3084. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  3085. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  3086. DMXELEMENT_UNPACK_FIELD( "output is scalar of initial random range","0", bool, m_bScaleInitialRange )
  3087. END_PARTICLE_OPERATOR_UNPACK( C_INIT_RemapCPtoScalar )
  3088. void C_INIT_RemapCPtoScalar::InitNewParticlesScalar(
  3089. CParticleCollection *pParticles, int start_p,
  3090. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  3091. {
  3092. const float *pCreationTime;
  3093. // clamp the result to 0 and 1 if it's alpha
  3094. float flMin=m_flOutputMin;
  3095. float flMax=m_flOutputMax;
  3096. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & ( 1 << m_nFieldOutput ) )
  3097. {
  3098. flMin = clamp(m_flOutputMin, 0.0f, 1.0f );
  3099. flMax = clamp(m_flOutputMax, 0.0f, 1.0f );
  3100. }
  3101. Vector vecControlPoint;
  3102. float *ct = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_CREATION_TIME, start_p );
  3103. pParticles->GetControlPointAtTime( m_nCPInput, *ct, &vecControlPoint );
  3104. float flInput = vecControlPoint[m_nField];
  3105. // FIXME: SSE-ize
  3106. for( ; nParticleCount--; start_p++ )
  3107. {
  3108. pCreationTime = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, start_p );
  3109. // using raw creation time to map to emitter lifespan
  3110. float flLifeTime = *pCreationTime;
  3111. // only use within start/end time frame
  3112. if ( ( ( flLifeTime < m_flStartTime ) || ( flLifeTime >= m_flEndTime ) ) && ( ( m_flStartTime != -1.0f) && ( m_flEndTime != -1.0f) ) )
  3113. continue;
  3114. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, start_p );
  3115. float flOutput = RemapValClamped( flInput, m_flInputMin, m_flInputMax, flMin, flMax );
  3116. if ( m_bScaleInitialRange )
  3117. {
  3118. flOutput = *pOutput * flOutput;
  3119. }
  3120. if ( ATTRIBUTES_WHICH_ARE_INTS & ( 1 << m_nFieldOutput ) )
  3121. {
  3122. *pOutput = int ( flOutput );
  3123. }
  3124. else
  3125. {
  3126. *pOutput = flOutput;
  3127. }
  3128. }
  3129. }
  3130. //-----------------------------------------------------------------------------
  3131. // Remap CP to Vector Initializer
  3132. //-----------------------------------------------------------------------------
  3133. class C_INIT_RemapCPtoVector : public CParticleOperatorInstance
  3134. {
  3135. DECLARE_PARTICLE_OPERATOR( C_INIT_RemapCPtoVector );
  3136. uint32 GetWrittenAttributes( void ) const
  3137. {
  3138. return 1 << m_nFieldOutput | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK;
  3139. }
  3140. uint32 GetReadAttributes( void ) const
  3141. {
  3142. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  3143. }
  3144. virtual uint64 GetReadControlPointMask() const
  3145. {
  3146. uint64 nMask = ( 1ULL << m_nCPInput );
  3147. if ( m_nLocalSpaceCP != -1 )
  3148. {
  3149. nMask |= ( 1ULL << m_nLocalSpaceCP );
  3150. }
  3151. return nMask;
  3152. }
  3153. bool InitMultipleOverride ( void ) { return true; }
  3154. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  3155. int nParticleCount, int nAttributeWriteMask,
  3156. void *pContext) const;
  3157. virtual void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  3158. {
  3159. m_nField = int (clamp (m_nField, 0, 2));
  3160. }
  3161. int m_nCPInput;
  3162. int m_nFieldOutput;
  3163. int m_nField;
  3164. Vector m_vInputMin;
  3165. Vector m_vInputMax;
  3166. Vector m_vOutputMin;
  3167. Vector m_vOutputMax;
  3168. float m_flStartTime;
  3169. float m_flEndTime;
  3170. bool m_bScaleInitialRange;
  3171. bool m_bOffset;
  3172. bool m_bAccelerate;
  3173. int m_nLocalSpaceCP;
  3174. };
  3175. DEFINE_PARTICLE_OPERATOR( C_INIT_RemapCPtoVector, "Remap Control Point to Vector", OPERATOR_GENERIC );
  3176. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_RemapCPtoVector )
  3177. DMXELEMENT_UNPACK_FIELD( "emitter lifetime start time (seconds)", "-1", float, m_flStartTime )
  3178. DMXELEMENT_UNPACK_FIELD( "emitter lifetime end time (seconds)", "-1", float, m_flEndTime )
  3179. DMXELEMENT_UNPACK_FIELD( "input control point number", "0", int, m_nCPInput )
  3180. DMXELEMENT_UNPACK_FIELD( "input minimum","0 0 0", Vector, m_vInputMin )
  3181. DMXELEMENT_UNPACK_FIELD( "input maximum","0 0 0", Vector, m_vInputMax )
  3182. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "0", int, m_nFieldOutput, "intchoice particlefield_vector" )
  3183. DMXELEMENT_UNPACK_FIELD( "output minimum","0 0 0", Vector, m_vOutputMin )
  3184. DMXELEMENT_UNPACK_FIELD( "output maximum","0 0 0", Vector, m_vOutputMax )
  3185. DMXELEMENT_UNPACK_FIELD( "output is scalar of initial random range","0", bool, m_bScaleInitialRange )
  3186. DMXELEMENT_UNPACK_FIELD( "offset position","0", bool, m_bOffset )
  3187. DMXELEMENT_UNPACK_FIELD( "accelerate position","0", bool, m_bAccelerate )
  3188. DMXELEMENT_UNPACK_FIELD( "local space CP","-1", int, m_nLocalSpaceCP )
  3189. END_PARTICLE_OPERATOR_UNPACK( C_INIT_RemapCPtoVector )
  3190. void C_INIT_RemapCPtoVector::InitNewParticlesScalar(
  3191. CParticleCollection *pParticles, int start_p,
  3192. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  3193. {
  3194. Vector vecControlPoint;
  3195. pParticles->GetControlPointAtTime( m_nCPInput, pParticles->m_flCurTime, &vecControlPoint );
  3196. Vector vOutputMinLocal = m_vOutputMin;
  3197. Vector vOutputMaxLocal = m_vOutputMax;
  3198. if ( m_nLocalSpaceCP != -1 )
  3199. {
  3200. matrix3x4_t mat;
  3201. pParticles->GetControlPointTransformAtTime( m_nLocalSpaceCP, pParticles->m_flCurTime, &mat );
  3202. Vector vecTransformLocal = vec3_origin;
  3203. VectorRotate( vOutputMinLocal, mat, vecTransformLocal );
  3204. vOutputMinLocal = vecTransformLocal;
  3205. VectorRotate( vOutputMaxLocal, mat, vecTransformLocal );
  3206. vOutputMaxLocal = vecTransformLocal;
  3207. }
  3208. // FIXME: SSE-ize
  3209. for( ; nParticleCount--; start_p++ )
  3210. {
  3211. const float *pCreationTime = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, start_p );
  3212. // using raw creation time to map to emitter lifespan
  3213. float flLifeTime = *pCreationTime;
  3214. // only use within start/end time frame
  3215. if ( ( ( flLifeTime < m_flStartTime ) || ( flLifeTime >= m_flEndTime ) ) && ( ( m_flStartTime != -1.0f) && ( m_flEndTime != -1.0f) ) )
  3216. continue;
  3217. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, start_p );
  3218. Vector vOutput;
  3219. vOutput.x = RemapValClamped( vecControlPoint.x, m_vInputMin.x, m_vInputMax.x, vOutputMinLocal.x, vOutputMaxLocal.x );
  3220. vOutput.y = RemapValClamped( vecControlPoint.y, m_vInputMin.y, m_vInputMax.y, vOutputMinLocal.y, vOutputMaxLocal.y );
  3221. vOutput.z = RemapValClamped( vecControlPoint.z, m_vInputMin.z, m_vInputMax.z, vOutputMinLocal.z, vOutputMaxLocal.z );
  3222. if ( m_bScaleInitialRange )
  3223. {
  3224. Vector vOrgValue;
  3225. SetVectorFromAttribute ( vOrgValue, pOutput );
  3226. vOutput *= vOrgValue;
  3227. }
  3228. if ( m_nFieldOutput == 6 )
  3229. {
  3230. pOutput[0] = max( 0.0f, min( vOutput.x, 1.0f) );
  3231. pOutput[4] = max( 0.0f, min( vOutput.y, 1.0f) );
  3232. pOutput[8] = max( 0.0f, min( vOutput.z, 1.0f) );
  3233. }
  3234. else
  3235. {
  3236. float *pXYZ_Prev = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, start_p );
  3237. Vector vXYZPrev;
  3238. if ( m_bAccelerate )
  3239. {
  3240. if ( m_bOffset )
  3241. {
  3242. Vector vOrgValue;
  3243. SetVectorFromAttribute ( vOrgValue, pOutput );
  3244. SetVectorFromAttribute ( vXYZPrev, pXYZ_Prev );
  3245. vOutput += vOrgValue;
  3246. vXYZPrev += vOutput;
  3247. vOutput += vOutput * pParticles->m_flDt;
  3248. SetVectorAttribute ( pOutput, vOutput );
  3249. SetVectorAttribute ( pXYZ_Prev, vXYZPrev );
  3250. }
  3251. else
  3252. {
  3253. vOutput *= pParticles->m_flDt;
  3254. SetVectorAttribute ( pOutput, vOutput );
  3255. }
  3256. }
  3257. else
  3258. {
  3259. vXYZPrev = vOutput;
  3260. if ( m_bOffset )
  3261. {
  3262. Vector vOrgValue;
  3263. SetVectorFromAttribute ( vOrgValue, pOutput );
  3264. SetVectorFromAttribute ( vXYZPrev, pXYZ_Prev );
  3265. vOutput += vOrgValue;
  3266. vXYZPrev += vOutput;
  3267. }
  3268. SetVectorAttribute ( pOutput, vOutput );
  3269. SetVectorAttribute ( pXYZ_Prev, vXYZPrev );
  3270. }
  3271. }
  3272. }
  3273. }
  3274. class C_INIT_CreateFromParentParticles : public CParticleOperatorInstance
  3275. {
  3276. DECLARE_PARTICLE_OPERATOR( C_INIT_CreateFromParentParticles );
  3277. struct ParentParticlesContext_t
  3278. {
  3279. int m_nCurrentParentParticle;
  3280. };
  3281. uint32 GetWrittenAttributes( void ) const
  3282. {
  3283. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK;
  3284. }
  3285. uint32 GetReadAttributes( void ) const
  3286. {
  3287. return PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  3288. }
  3289. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  3290. {
  3291. ParentParticlesContext_t *pCtx = reinterpret_cast<ParentParticlesContext_t *>( pContext );
  3292. pCtx->m_nCurrentParentParticle = 0;
  3293. }
  3294. size_t GetRequiredContextBytes( void ) const
  3295. {
  3296. return sizeof( ParentParticlesContext_t );
  3297. }
  3298. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  3299. int nParticleCount, int nAttributeWriteMask,
  3300. void *pContext) const;
  3301. float m_flVelocityScale;
  3302. bool m_bRandomDistribution;
  3303. };
  3304. DEFINE_PARTICLE_OPERATOR( C_INIT_CreateFromParentParticles, "Position From Parent Particles", OPERATOR_PI_POSITION );
  3305. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_CreateFromParentParticles )
  3306. DMXELEMENT_UNPACK_FIELD( "Inherited Velocity Scale","0", float, m_flVelocityScale )
  3307. DMXELEMENT_UNPACK_FIELD( "Random Parent Particle Distribution","0", bool, m_bRandomDistribution )
  3308. END_PARTICLE_OPERATOR_UNPACK( C_INIT_CreateFromParentParticles )
  3309. void C_INIT_CreateFromParentParticles::InitNewParticlesScalar(
  3310. CParticleCollection *pParticles, int start_p,
  3311. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  3312. {
  3313. if ( !pParticles->m_pParent )
  3314. {
  3315. for( ; nParticleCount--; start_p++ )
  3316. {
  3317. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, start_p );
  3318. float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, start_p );
  3319. SetVectorAttribute( xyz, vec3_origin );
  3320. SetVectorAttribute( pxyz, vec3_origin );
  3321. }
  3322. return;
  3323. }
  3324. ParentParticlesContext_t *pCtx = reinterpret_cast<ParentParticlesContext_t *>( pContext );
  3325. int nActiveParticles = pParticles->m_pParent->m_nActiveParticles;
  3326. if ( nActiveParticles == 0 )
  3327. {
  3328. while( nParticleCount-- )
  3329. {
  3330. float *lifespan = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_LIFE_DURATION, start_p );
  3331. *lifespan = 0.0f;
  3332. start_p++;
  3333. }
  3334. return;
  3335. }
  3336. nActiveParticles = max ( 0, nActiveParticles - 1 );
  3337. for( ; nParticleCount--; start_p++ )
  3338. {
  3339. if ( m_bRandomDistribution )
  3340. {
  3341. pCtx->m_nCurrentParentParticle = pParticles->RandomInt( 0, nActiveParticles );
  3342. }
  3343. else if ( pCtx->m_nCurrentParentParticle > nActiveParticles )
  3344. {
  3345. pCtx->m_nCurrentParentParticle = 0;
  3346. }
  3347. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, start_p );
  3348. float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, start_p );
  3349. const float *ct = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, start_p );
  3350. const float *pParent_xyz = pParticles->m_pParent->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_XYZ, pCtx->m_nCurrentParentParticle );
  3351. const float *pParent_pxyz = pParticles->m_pParent->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_PREV_XYZ, pCtx->m_nCurrentParentParticle );
  3352. Vector vecParentXYZ;
  3353. Vector vecParentPrevXYZ;
  3354. Vector vecScaledXYZ;
  3355. float flPrevTime = pParticles->m_flCurTime - pParticles->m_flDt;
  3356. float flSubFrame = RemapValClamped( *ct, flPrevTime, pParticles->m_flCurTime, 0, 1 );
  3357. vecParentXYZ.x = pParent_xyz[0];
  3358. vecParentXYZ.y = pParent_xyz[4];
  3359. vecParentXYZ.z = pParent_xyz[8];
  3360. vecParentPrevXYZ.x = pParent_pxyz[0];
  3361. vecParentPrevXYZ.y = pParent_pxyz[4];
  3362. vecParentPrevXYZ.z = pParent_pxyz[8];
  3363. VectorLerp( vecParentPrevXYZ, vecParentXYZ, flSubFrame, vecParentXYZ );
  3364. VectorLerp( vecParentXYZ, vecParentPrevXYZ, m_flVelocityScale, vecScaledXYZ );
  3365. SetVectorAttribute( pxyz, vecScaledXYZ );
  3366. SetVectorAttribute( xyz, vecParentXYZ );
  3367. pCtx->m_nCurrentParentParticle++;
  3368. }
  3369. }
  3370. //-----------------------------------------------------------------------------
  3371. // Distance to CP Initializer
  3372. //-----------------------------------------------------------------------------
  3373. class C_INIT_DistanceToCPInit : public CParticleOperatorInstance
  3374. {
  3375. DECLARE_PARTICLE_OPERATOR( C_INIT_DistanceToCPInit );
  3376. uint32 GetWrittenAttributes( void ) const
  3377. {
  3378. return 1 << m_nFieldOutput;
  3379. }
  3380. uint32 GetReadAttributes( void ) const
  3381. {
  3382. return PARTICLE_ATTRIBUTE_XYZ_MASK;
  3383. }
  3384. virtual uint64 GetReadControlPointMask() const
  3385. {
  3386. return 1ULL << m_nStartCP;
  3387. }
  3388. bool InitMultipleOverride ( void ) { return true; }
  3389. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  3390. {
  3391. m_nCollisionGroupNumber = g_pParticleSystemMgr->Query()->GetCollisionGroupFromName( m_CollisionGroupName );
  3392. m_nStartCP = max( 0, min( MAX_PARTICLE_CONTROL_POINTS-1, m_nStartCP ) );
  3393. }
  3394. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  3395. int nParticleCount, int nAttributeWriteMask,
  3396. void *pContext) const;
  3397. int m_nFieldOutput;
  3398. float m_flInputMin;
  3399. float m_flInputMax;
  3400. float m_flOutputMin;
  3401. float m_flOutputMax;
  3402. int m_nStartCP;
  3403. bool m_bLOS;
  3404. char m_CollisionGroupName[128];
  3405. int m_nCollisionGroupNumber;
  3406. float m_flMaxTraceLength;
  3407. float m_flLOSScale;
  3408. bool m_bScaleInitialRange;
  3409. bool m_bActiveRange;
  3410. };
  3411. DEFINE_PARTICLE_OPERATOR( C_INIT_DistanceToCPInit, "Remap Initial Distance to Control Point to Scalar", OPERATOR_GENERIC );
  3412. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_DistanceToCPInit )
  3413. DMXELEMENT_UNPACK_FIELD( "distance minimum","0", float, m_flInputMin )
  3414. DMXELEMENT_UNPACK_FIELD( "distance maximum","128", float, m_flInputMax )
  3415. DMXELEMENT_UNPACK_FIELD_USERDATA( "output field", "3", int, m_nFieldOutput, "intchoice particlefield_scalar" )
  3416. DMXELEMENT_UNPACK_FIELD( "output minimum","0", float, m_flOutputMin )
  3417. DMXELEMENT_UNPACK_FIELD( "output maximum","1", float, m_flOutputMax )
  3418. DMXELEMENT_UNPACK_FIELD( "control point","0", int, m_nStartCP )
  3419. DMXELEMENT_UNPACK_FIELD( "ensure line of sight","0", bool, m_bLOS )
  3420. DMXELEMENT_UNPACK_FIELD_STRING( "LOS collision group", "NONE", m_CollisionGroupName )
  3421. DMXELEMENT_UNPACK_FIELD( "Maximum Trace Length", "-1", float, m_flMaxTraceLength )
  3422. DMXELEMENT_UNPACK_FIELD( "LOS Failure Scalar", "0", float, m_flLOSScale )
  3423. DMXELEMENT_UNPACK_FIELD( "output is scalar of initial random range","0", bool, m_bScaleInitialRange )
  3424. DMXELEMENT_UNPACK_FIELD( "only active within specified distance","0", bool, m_bActiveRange )
  3425. END_PARTICLE_OPERATOR_UNPACK( C_INIT_DistanceToCPInit )
  3426. void C_INIT_DistanceToCPInit::InitNewParticlesScalar(
  3427. CParticleCollection *pParticles, int start_p,
  3428. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  3429. {
  3430. // clamp the result to 0 and 1 if it's alpha
  3431. float flMin=m_flOutputMin;
  3432. float flMax=m_flOutputMax;
  3433. if ( ATTRIBUTES_WHICH_ARE_0_TO_1 & ( 1 << m_nFieldOutput ) )
  3434. {
  3435. flMin = clamp(m_flOutputMin, 0.0f, 1.0f );
  3436. flMax = clamp(m_flOutputMax, 0.0f, 1.0f );
  3437. }
  3438. Vector vecControlPoint1 = pParticles->GetControlPointAtCurrentTime( m_nStartCP );
  3439. // FIXME: SSE-ize
  3440. for( ; nParticleCount--; start_p++ )
  3441. {
  3442. Vector vecPosition2;
  3443. const float *pXYZ = pParticles->GetFloatAttributePtr(PARTICLE_ATTRIBUTE_XYZ, start_p );
  3444. vecPosition2 = Vector(pXYZ[0], pXYZ[4], pXYZ[8]);
  3445. Vector vecDelta = vecControlPoint1 - vecPosition2;
  3446. float flDistance = vecDelta.Length();
  3447. if ( m_bActiveRange && ( flDistance < m_flInputMin || flDistance > m_flInputMax ) )
  3448. {
  3449. continue;
  3450. }
  3451. if ( m_bLOS )
  3452. {
  3453. Vector vecEndPoint = vecPosition2;
  3454. if ( m_flMaxTraceLength != -1.0f && m_flMaxTraceLength < flDistance )
  3455. {
  3456. VectorNormalize(vecEndPoint);
  3457. vecEndPoint *= m_flMaxTraceLength;
  3458. vecEndPoint += vecControlPoint1;
  3459. }
  3460. CBaseTrace tr;
  3461. g_pParticleSystemMgr->Query()->TraceLine( vecControlPoint1, vecEndPoint, MASK_OPAQUE_AND_NPCS, NULL , m_nCollisionGroupNumber, &tr );
  3462. if (tr.fraction != 1.0f)
  3463. {
  3464. flDistance *= tr.fraction * m_flLOSScale;
  3465. }
  3466. }
  3467. float flOutput = RemapValClamped( flDistance, m_flInputMin, m_flInputMax, flMin, flMax );
  3468. if ( m_bScaleInitialRange )
  3469. {
  3470. const float *pInitialOutput = pParticles->GetFloatAttributePtr( m_nFieldOutput, start_p );
  3471. flOutput = *pInitialOutput * flOutput;
  3472. }
  3473. float *pOutput = pParticles->GetFloatAttributePtrForWrite( m_nFieldOutput, start_p );
  3474. *pOutput = flOutput;
  3475. }
  3476. }
  3477. class C_INIT_LifespanFromVelocity : public CParticleOperatorInstance
  3478. {
  3479. DECLARE_PARTICLE_OPERATOR( C_INIT_LifespanFromVelocity );
  3480. Vector m_vecComponentScale;
  3481. float m_flTraceOffset;
  3482. float m_flMaxTraceLength;
  3483. float m_flTraceTolerance;
  3484. int m_nCollisionGroupNumber;
  3485. int m_nMaxPlanes;
  3486. int m_nAllowedPlanes;
  3487. char m_CollisionGroupName[128];
  3488. uint32 GetWrittenAttributes( void ) const
  3489. {
  3490. return PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK;
  3491. }
  3492. uint32 GetReadAttributes( void ) const
  3493. {
  3494. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_CREATION_TIME_MASK;
  3495. }
  3496. void InitializeContextData( CParticleCollection *pParticles,
  3497. void *pContext ) const
  3498. {
  3499. }
  3500. size_t GetRequiredContextBytes( ) const
  3501. {
  3502. return sizeof( CWorldCollideContextData );
  3503. }
  3504. bool InitMultipleOverride ( void ) { return true; }
  3505. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  3506. {
  3507. m_nCollisionGroupNumber = g_pParticleSystemMgr->Query()->GetCollisionGroupFromName( m_CollisionGroupName );
  3508. m_nAllowedPlanes = ( min ( MAX_WORLD_PLANAR_CONSTRAINTS, m_nMaxPlanes ) - 1 );
  3509. }
  3510. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  3511. int nParticleCount, int nAttributeWriteMask,
  3512. void *pContext) const;
  3513. virtual void InitNewParticlesBlock( CParticleCollection *pParticles,
  3514. int start_block, int n_blocks, int nAttributeWriteMask,
  3515. void *pContext ) const;
  3516. };
  3517. DEFINE_PARTICLE_OPERATOR( C_INIT_LifespanFromVelocity, "Lifetime from Time to Impact", OPERATOR_GENERIC );
  3518. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_LifespanFromVelocity )
  3519. DMXELEMENT_UNPACK_FIELD_STRING( "trace collision group", "NONE", m_CollisionGroupName )
  3520. DMXELEMENT_UNPACK_FIELD( "maximum trace length", "1024", float, m_flMaxTraceLength )
  3521. DMXELEMENT_UNPACK_FIELD( "trace offset", "0", float, m_flTraceOffset )
  3522. DMXELEMENT_UNPACK_FIELD( "trace recycle tolerance", "64", float, m_flTraceTolerance )
  3523. DMXELEMENT_UNPACK_FIELD( "maximum points to cache", "16", int, m_nMaxPlanes )
  3524. DMXELEMENT_UNPACK_FIELD( "bias distance", "1 1 1", Vector, m_vecComponentScale )
  3525. END_PARTICLE_OPERATOR_UNPACK( C_INIT_LifespanFromVelocity )
  3526. void C_INIT_LifespanFromVelocity::InitNewParticlesScalar(
  3527. CParticleCollection *pParticles, int start_p,
  3528. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  3529. {
  3530. CWorldCollideContextData **ppCtx;
  3531. if ( pParticles->m_pParent )
  3532. ppCtx = &( pParticles->m_pParent->m_pCollisionCacheData[COLLISION_MODE_INITIAL_TRACE_DOWN] );
  3533. else
  3534. ppCtx = &( pParticles->m_pCollisionCacheData[COLLISION_MODE_INITIAL_TRACE_DOWN] );
  3535. CWorldCollideContextData *pCtx = NULL;
  3536. if ( ! *ppCtx )
  3537. {
  3538. *ppCtx = new CWorldCollideContextData;
  3539. (*ppCtx)->m_nActivePlanes = 0;
  3540. (*ppCtx)->m_nActivePlanes = 0;
  3541. (*ppCtx)->m_nNumFixedPlanes = 0;
  3542. }
  3543. pCtx = *ppCtx;
  3544. float flTol = m_flTraceTolerance * m_flTraceTolerance;
  3545. //Trace length takes the max trace and subtracts the offset to get the actual total.
  3546. float flTotalTraceDist = m_flMaxTraceLength - m_flTraceOffset;
  3547. //Offset percentage to account for if we've hit something within the offset (but not spawn) area
  3548. float flOffsetPct = m_flMaxTraceLength / ( flTotalTraceDist + FLT_EPSILON );
  3549. FourVectors v4ComponentScale;
  3550. v4ComponentScale.DuplicateVector( m_vecComponentScale );
  3551. while( nParticleCount-- )
  3552. {
  3553. float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, start_p );
  3554. float *pPrevXYZ = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, start_p );
  3555. float *dtime = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_LIFE_DURATION, start_p );
  3556. Vector vecXYZ( pxyz[0], pxyz[4], pxyz[8] );
  3557. Vector vecXYZ_Prev( pPrevXYZ[0], pPrevXYZ[4], pPrevXYZ[8] );
  3558. //Calculate velocity and account for frame delta time
  3559. Vector vDelta = vecXYZ - vecXYZ_Prev;
  3560. float flVelocity = VectorLength( vDelta );
  3561. flVelocity /= pParticles->m_flPreviousDt;
  3562. fltx4 fl4TraceOffset = ReplicateX4( m_flTraceOffset );
  3563. //Normalize the delta and get the offset to use from the normalized delta times the offset
  3564. VectorNormalize( vDelta );
  3565. Vector vecOffset = vDelta * m_flTraceOffset;
  3566. Vector vecStartPnt = vecXYZ + vecOffset;
  3567. Vector vecEndPnt = ( vDelta * flTotalTraceDist ) + vecStartPnt;
  3568. // Use SIMD section to interface with plane cache, even though we're not SIMD here
  3569. // Test versus existing Data
  3570. FourVectors fvStartPnt;
  3571. fvStartPnt.DuplicateVector( vecStartPnt );
  3572. FourVectors fvEndPnt;
  3573. fvEndPnt.DuplicateVector( vecEndPnt );
  3574. FourVectors v4PointOnPlane;
  3575. FourVectors v4PlaneNormal;
  3576. FourVectors v4Delta;
  3577. fltx4 fl4ClosestDist = Four_FLT_MAX;
  3578. for( int i = 0 ; i < pCtx->m_nActivePlanes; i++ )
  3579. {
  3580. if ( pCtx->m_bPlaneActive[i] )
  3581. {
  3582. fltx4 fl4TrialDistance = MaxSIMD(
  3583. fvStartPnt.DistSqrToLineSegment( pCtx->m_TraceStartPnt[i], pCtx->m_TraceEndPnt[i] ),
  3584. fvEndPnt.DistSqrToLineSegment( pCtx->m_TraceStartPnt[i], pCtx->m_TraceEndPnt[i] ) );
  3585. // If the trial distance is closer than the existing closest, replace.
  3586. if ( !IsAllGreaterThan( fl4TrialDistance, fl4ClosestDist ) )
  3587. {
  3588. fl4ClosestDist = fl4TrialDistance;
  3589. v4PointOnPlane = pCtx->m_PointOnPlane[i];
  3590. }
  3591. }
  3592. }
  3593. fl4ClosestDist = fabs( fl4ClosestDist );
  3594. // If we're outside the tolerance range, do a new trace and store it.
  3595. if ( IsAllGreaterThan( fl4ClosestDist, ReplicateX4( flTol ) ) )
  3596. {
  3597. //replace this with fast raycaster when available
  3598. CBaseTrace tr;
  3599. tr.plane.normal = vec3_invalid;
  3600. g_pParticleSystemMgr->Query()->TraceLine( vecStartPnt, vecEndPnt, CONTENTS_SOLID, NULL , m_nCollisionGroupNumber, &tr );
  3601. //Set the lifespan to 0 if we start solid, our trace distance is 0, or we hit within the offset area
  3602. if ( ( tr.fraction < ( 1 - flOffsetPct ) ) || tr.startsolid || flTotalTraceDist == 0.0f )
  3603. {
  3604. *dtime = 0.0f;
  3605. fl4TraceOffset = ReplicateX4( 0.0f );
  3606. fvStartPnt.DuplicateVector( vec3_origin );
  3607. v4PointOnPlane.DuplicateVector( vec3_origin );
  3608. }
  3609. else
  3610. {
  3611. int nIndex = pCtx->m_nNumFixedPlanes;
  3612. Vector vPointOnPlane = vecStartPnt + ( tr.fraction * ( vecEndPnt - vecStartPnt ) ) ;
  3613. pCtx->m_bPlaneActive[nIndex] = true;
  3614. pCtx->m_PointOnPlane[nIndex].DuplicateVector( vPointOnPlane );
  3615. pCtx->m_PlaneNormal[nIndex].DuplicateVector( tr.plane.normal );
  3616. pCtx->m_TraceStartPnt[nIndex].DuplicateVector( vecStartPnt );
  3617. pCtx->m_TraceEndPnt[nIndex].DuplicateVector( vecEndPnt );
  3618. fvStartPnt.DuplicateVector( vecStartPnt );
  3619. v4PointOnPlane.DuplicateVector( vPointOnPlane );
  3620. pCtx->m_nNumFixedPlanes = pCtx->m_nNumFixedPlanes + 1;
  3621. if ( pCtx->m_nNumFixedPlanes > m_nAllowedPlanes )
  3622. pCtx->m_nNumFixedPlanes = 0;
  3623. pCtx->m_nActivePlanes = min( m_nAllowedPlanes, pCtx->m_nActivePlanes + 1 );
  3624. }
  3625. }
  3626. fvStartPnt -= v4PointOnPlane;
  3627. //Scale components to remove undesired axis
  3628. fvStartPnt *= v4ComponentScale;
  3629. //Find the length of the trace
  3630. //Need to use the adjusted value of the trace length and collision point to account for the offset
  3631. fltx4 fl4Dist = AddSIMD ( fvStartPnt.length(), fl4TraceOffset );
  3632. flVelocity += FLT_EPSILON;
  3633. //Divide by Velocity to get Lifespan
  3634. *dtime = SubFloat( fl4Dist, 0) / flVelocity;
  3635. }
  3636. }
  3637. void C_INIT_LifespanFromVelocity::InitNewParticlesBlock( CParticleCollection *pParticles,
  3638. int start_block, int n_blocks, int nAttributeWriteMask,
  3639. void *pContext ) const
  3640. {
  3641. CWorldCollideContextData **ppCtx;
  3642. if ( pParticles->m_pParent )
  3643. ppCtx = &( pParticles->m_pParent->m_pCollisionCacheData[COLLISION_MODE_INITIAL_TRACE_DOWN] );
  3644. else
  3645. ppCtx = &( pParticles->m_pCollisionCacheData[COLLISION_MODE_INITIAL_TRACE_DOWN] );
  3646. CWorldCollideContextData *pCtx = NULL;
  3647. if ( ! *ppCtx )
  3648. {
  3649. *ppCtx = new CWorldCollideContextData;
  3650. (*ppCtx)->m_nActivePlanes = 0;
  3651. (*ppCtx)->m_nActivePlanes = 0;
  3652. (*ppCtx)->m_nNumFixedPlanes = 0;
  3653. }
  3654. pCtx = *ppCtx;
  3655. float flTol = m_flTraceTolerance * m_flTraceTolerance;
  3656. size_t attr_stride;
  3657. FourVectors *pXYZ = pParticles->Get4VAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, &attr_stride );
  3658. pXYZ += attr_stride * start_block;
  3659. FourVectors *pPrev_XYZ = pParticles->Get4VAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, &attr_stride );
  3660. pPrev_XYZ += attr_stride * start_block;
  3661. fltx4 *pLifespan = pParticles->GetM128AttributePtrForWrite( PARTICLE_ATTRIBUTE_LIFE_DURATION, &attr_stride );
  3662. pLifespan += attr_stride * start_block;
  3663. //Trace length takes the max trace and subtracts the offset to get the actual total.
  3664. float flTotalTraceDist = m_flMaxTraceLength - m_flTraceOffset;
  3665. fltx4 fl4TotalTraceDist = ReplicateX4( flTotalTraceDist );
  3666. //Offset percentage to account for if we've hit something within the offset (but not spawn) area
  3667. float flOffsetPct = m_flMaxTraceLength / ( flTotalTraceDist + FLT_EPSILON );
  3668. fltx4 fl4PrevDT = ReplicateX4( 1.0f / pParticles->m_flPreviousDt );
  3669. FourVectors v4ComponentScale;
  3670. v4ComponentScale.DuplicateVector( m_vecComponentScale );
  3671. while( n_blocks-- )
  3672. {
  3673. // Determine Velocity
  3674. FourVectors fvDelta = *pXYZ;
  3675. fvDelta -= *pPrev_XYZ;
  3676. fltx4 fl4Velocity = fvDelta.length();
  3677. fl4Velocity = MulSIMD ( fl4Velocity, fl4PrevDT );
  3678. fltx4 fl4TraceOffset = ReplicateX4( m_flTraceOffset );
  3679. //Normalize the delta and get the offset to use from the normalized delta times the offset
  3680. FourVectors fvDeltaNormalized = fvDelta;
  3681. fvDeltaNormalized.VectorNormalizeFast();
  3682. FourVectors fvOffset = fvDeltaNormalized;
  3683. fvOffset *= m_flTraceOffset;
  3684. //Start/Endpoints for our traces
  3685. FourVectors fvStartPnt = *pXYZ;
  3686. fvStartPnt += fvOffset;
  3687. FourVectors fvEndPnt = fvDeltaNormalized;
  3688. fvEndPnt *= fl4TotalTraceDist;
  3689. fvEndPnt += fvStartPnt;
  3690. // Test versus existing Data
  3691. FourVectors v4PointOnPlane;
  3692. FourVectors v4PlaneNormal;
  3693. fltx4 fl4ClosestDist = Four_FLT_MAX;
  3694. for( int i = 0 ; i < pCtx->m_nActivePlanes; i++ )
  3695. {
  3696. if ( pCtx->m_bPlaneActive[i] )
  3697. {
  3698. fltx4 fl4TrialDistance = MaxSIMD(
  3699. fvStartPnt.DistSqrToLineSegment( pCtx->m_TraceStartPnt[i], pCtx->m_TraceEndPnt[i] ),
  3700. fvEndPnt.DistSqrToLineSegment( pCtx->m_TraceStartPnt[i], pCtx->m_TraceEndPnt[i] ) );
  3701. fltx4 fl4Nearestmask = CmpLeSIMD( fl4TrialDistance, fl4ClosestDist );
  3702. fl4ClosestDist = MaskedAssign( fl4ClosestDist, fl4TrialDistance, fl4Nearestmask );
  3703. v4PointOnPlane.x = MaskedAssign( fl4Nearestmask, pCtx->m_PointOnPlane[i].x, v4PointOnPlane.x );
  3704. v4PointOnPlane.y = MaskedAssign( fl4Nearestmask, pCtx->m_PointOnPlane[i].y, v4PointOnPlane.y );
  3705. v4PointOnPlane.z = MaskedAssign( fl4Nearestmask, pCtx->m_PointOnPlane[i].z, v4PointOnPlane.z );
  3706. }
  3707. }
  3708. // If we're outside the tolerance range, do a new trace and store it.
  3709. fltx4 fl4OutOfRange = CmpGtSIMD( fl4ClosestDist, ReplicateX4( flTol ) );
  3710. if ( IsAnyNegative( fl4OutOfRange ) )
  3711. {
  3712. int nMask = TestSignSIMD( fl4OutOfRange );
  3713. for(int i=0; i < 4; i++ )
  3714. {
  3715. if ( nMask & ( 1 << i ) )
  3716. {
  3717. Vector start = fvStartPnt.Vec( i );
  3718. Vector end = fvEndPnt.Vec( i );
  3719. //replace this with fast raycaster when available
  3720. CBaseTrace tr;
  3721. tr.plane.normal = vec3_invalid;
  3722. g_pParticleSystemMgr->Query()->TraceLine( start, end, CONTENTS_SOLID, NULL , m_nCollisionGroupNumber, &tr );
  3723. //Set the lifespan to 0 if we start solid, our trace distance is 0, or we hit within the offset area
  3724. if ( ( tr.fraction < ( 1 - flOffsetPct ) ) || tr.startsolid || flTotalTraceDist == 0.0f )
  3725. {
  3726. SubFloat( fvStartPnt.x, i ) = 0.0f;
  3727. SubFloat( fvStartPnt.y, i ) = 0.0f;
  3728. SubFloat( fvStartPnt.z, i ) = 0.0f;
  3729. SubFloat( v4PointOnPlane.x, i ) = 0.0f;
  3730. SubFloat( v4PointOnPlane.y, i ) = 0.0f;
  3731. SubFloat( v4PointOnPlane.z, i ) = 0.0f;
  3732. SubFloat( fl4TraceOffset, i ) = 0.0f;
  3733. }
  3734. else
  3735. {
  3736. int nIndex = pCtx->m_nNumFixedPlanes;
  3737. Vector vPointOnPlane = start + ( tr.fraction * ( end - start ) ) ;
  3738. SubFloat( v4PointOnPlane.x, i ) = vPointOnPlane.x;
  3739. SubFloat( v4PointOnPlane.y, i ) = vPointOnPlane.y;
  3740. SubFloat( v4PointOnPlane.z, i ) = vPointOnPlane.z;
  3741. pCtx->m_bPlaneActive[nIndex] = true;
  3742. pCtx->m_PointOnPlane[nIndex].DuplicateVector( vPointOnPlane );
  3743. pCtx->m_PlaneNormal[nIndex].DuplicateVector( tr.plane.normal );
  3744. pCtx->m_TraceStartPnt[nIndex].DuplicateVector( start );
  3745. pCtx->m_TraceEndPnt[nIndex].DuplicateVector( end );
  3746. pCtx->m_nNumFixedPlanes = pCtx->m_nNumFixedPlanes + 1;
  3747. if ( pCtx->m_nNumFixedPlanes > m_nAllowedPlanes )
  3748. pCtx->m_nNumFixedPlanes = 0;
  3749. pCtx->m_nActivePlanes = min( m_nAllowedPlanes, pCtx->m_nActivePlanes + 1 );
  3750. }
  3751. }
  3752. }
  3753. }
  3754. //Find the length of the trace
  3755. fvStartPnt -= v4PointOnPlane;
  3756. fvStartPnt *= v4ComponentScale;
  3757. //Need to use the adjusted value of the trace length and collision point to account for the offset
  3758. fltx4 fl4Dist = AddSIMD ( fvStartPnt.length(), fl4TraceOffset );
  3759. fl4Velocity = AddSIMD( fl4Velocity, Four_Epsilons );
  3760. //Divide by Velocity to get Lifespan
  3761. *pLifespan = DivSIMD( fl4Dist, fl4Velocity );
  3762. pXYZ += attr_stride;
  3763. pPrev_XYZ += attr_stride;
  3764. pLifespan += attr_stride;
  3765. }
  3766. }
  3767. class C_INIT_CreateFromPlaneCache : public CParticleOperatorInstance
  3768. {
  3769. DECLARE_PARTICLE_OPERATOR( C_INIT_CreateFromPlaneCache );
  3770. uint32 GetWrittenAttributes( void ) const
  3771. {
  3772. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK;
  3773. }
  3774. uint32 GetReadAttributes( void ) const
  3775. {
  3776. return 0;
  3777. }
  3778. size_t GetRequiredContextBytes( ) const
  3779. {
  3780. return sizeof( CWorldCollideContextData );
  3781. }
  3782. void InitNewParticlesScalar( CParticleCollection *pParticles, int start_p,
  3783. int nParticleCount, int nAttributeWriteMask,
  3784. void *pContext) const;
  3785. };
  3786. DEFINE_PARTICLE_OPERATOR( C_INIT_CreateFromPlaneCache, "Position from Parent Cache", OPERATOR_PI_POSITION );
  3787. BEGIN_PARTICLE_OPERATOR_UNPACK( C_INIT_CreateFromPlaneCache )
  3788. END_PARTICLE_OPERATOR_UNPACK( C_INIT_CreateFromPlaneCache )
  3789. void C_INIT_CreateFromPlaneCache::InitNewParticlesScalar(
  3790. CParticleCollection *pParticles, int start_p,
  3791. int nParticleCount, int nAttributeWriteMask, void *pContext ) const
  3792. {
  3793. if ( !pParticles->m_pParent )
  3794. {
  3795. for( ; nParticleCount--; start_p++ )
  3796. {
  3797. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, start_p );
  3798. float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, start_p );
  3799. SetVectorAttribute( xyz, vec3_origin );
  3800. SetVectorAttribute( pxyz, vec3_origin );
  3801. }
  3802. return;
  3803. }
  3804. CWorldCollideContextData **ppCtx;
  3805. if ( pParticles->m_pParent )
  3806. ppCtx = &( pParticles->m_pParent->m_pCollisionCacheData[COLLISION_MODE_INITIAL_TRACE_DOWN] );
  3807. else
  3808. ppCtx = &( pParticles->m_pCollisionCacheData[COLLISION_MODE_INITIAL_TRACE_DOWN] );
  3809. CWorldCollideContextData *pCtx = NULL;
  3810. if ( ! *ppCtx )
  3811. {
  3812. *ppCtx = new CWorldCollideContextData;
  3813. (*ppCtx)->m_nActivePlanes = 0;
  3814. (*ppCtx)->m_nNumFixedPlanes = 0;
  3815. FourVectors fvEmpty;
  3816. fvEmpty.DuplicateVector( vec3_origin );
  3817. (*ppCtx)->m_PointOnPlane[0] = fvEmpty;
  3818. }
  3819. pCtx = *ppCtx;
  3820. if ( pCtx->m_nActivePlanes > 0 )
  3821. {
  3822. for( ; nParticleCount--; start_p++ )
  3823. {
  3824. int nIndex = pParticles->RandomInt( 0, pCtx->m_nActivePlanes - 1 );
  3825. if ( pCtx->m_PlaneNormal[nIndex].Vec( 0 ) == vec3_invalid )
  3826. {
  3827. float *plifespan = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_LIFE_DURATION, start_p );
  3828. *plifespan = 0.0f;
  3829. }
  3830. else
  3831. {
  3832. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, start_p );
  3833. float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, start_p );
  3834. FourVectors fvPoint = pCtx->m_PointOnPlane[nIndex];
  3835. Vector vPoint = fvPoint.Vec( 0 );
  3836. SetVectorAttribute( xyz, vPoint );
  3837. SetVectorAttribute( pxyz, vPoint );
  3838. }
  3839. }
  3840. }
  3841. else
  3842. {
  3843. for( ; nParticleCount--; start_p++ )
  3844. {
  3845. float *xyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_XYZ, start_p );
  3846. float *pxyz = pParticles->GetFloatAttributePtrForWrite( PARTICLE_ATTRIBUTE_PREV_XYZ, start_p );
  3847. SetVectorAttribute( xyz, vec3_origin );
  3848. SetVectorAttribute( pxyz, vec3_origin );
  3849. }
  3850. }
  3851. }
  3852. //
  3853. //
  3854. //
  3855. //
  3856. //-----------------------------------------------------------------------------
  3857. // Purpose: Add all operators to be considered active, here
  3858. //-----------------------------------------------------------------------------
  3859. void AddBuiltInParticleInitializers( void )
  3860. {
  3861. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_CreateAlongPath );
  3862. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_MoveBetweenPoints );
  3863. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_CreateWithinSphere );
  3864. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_VelocityRandom );
  3865. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_CreateOnModel );
  3866. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_CreateWithinBox );
  3867. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_RandomRotationSpeed );
  3868. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_RandomLifeTime );
  3869. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_RandomAlpha );
  3870. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_RandomRadius );
  3871. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_RandomRotation );
  3872. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_RandomYaw );
  3873. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_RandomColor );
  3874. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_RandomTrailLength );
  3875. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_RandomSequence );
  3876. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_PositionOffset );
  3877. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_PositionWarp );
  3878. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_CreationNoise );
  3879. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_InitialVelocityNoise );
  3880. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_RemapScalar );
  3881. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_InheritVelocity );
  3882. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_AgeNoise );
  3883. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_SequenceLifeTime );
  3884. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_CreateInHierarchy );
  3885. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_RemapScalarToVector );
  3886. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_CreateSequentialPath );
  3887. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_InitialRepulsionVelocity );
  3888. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_RandomYawFlip );
  3889. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_RandomSecondSequence );
  3890. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_RemapCPtoScalar );
  3891. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_RemapCPtoVector );
  3892. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_CreateFromParentParticles );
  3893. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_DistanceToCPInit );
  3894. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_LifespanFromVelocity );
  3895. REGISTER_PARTICLE_OPERATOR( FUNCTION_INITIALIZER, C_INIT_CreateFromPlaneCache );
  3896. }