Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3718 lines
141 KiB

  1. //===== Copyright (c) 1996-2006, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: particle system code
  4. //
  5. //===========================================================================//
  6. #include "tier0/platform.h"
  7. #include "particles/particles.h"
  8. #include "filesystem.h"
  9. #include "tier2/tier2.h"
  10. #include "tier2/fileutils.h"
  11. #include "tier2/renderutils.h"
  12. #include "tier2/beamsegdraw.h"
  13. #include "tier1/UtlStringMap.h"
  14. #include "tier1/strtools.h"
  15. #include "materialsystem/imesh.h"
  16. #include "materialsystem/itexture.h"
  17. #include "materialsystem/imaterial.h"
  18. #include "materialsystem/imaterialvar.h"
  19. #include "bitmap/psheet.h"
  20. #include "particles_internal.h"
  21. #include "tier0/vprof.h"
  22. #ifdef USE_BLOBULATOR
  23. // TODO: These should be in public by the time the SDK ships
  24. #include "../common/blobulator/implicit/impdefines.h"
  25. #include "../common/blobulator/implicit/imprenderer.h"
  26. #include "../common/blobulator/implicit/imptiler.h"
  27. #include "../common/blobulator/implicit/userfunctions.h"
  28. #include "../common/blobulator/iblob_renderer.h"
  29. #endif
  30. // memdbgon must be the last include file in a .cpp file!!!
  31. #include "tier0/memdbgon.h"
  32. // Vertex instancing (1 vert submitted per particle, duplicated to 4 (a quad) on the GPU) is supported only on 360
  33. const bool bUseInstancing = IsX360();
  34. //-----------------------------------------------------------------------------
  35. // Utility method to compute the max # of particles per batch
  36. //-----------------------------------------------------------------------------
  37. static inline int GetMaxParticlesPerBatch( IMatRenderContext *pRenderContext, IMaterial *pMaterial, bool bWithInstancing )
  38. {
  39. int nMaxVertices = pRenderContext->GetMaxVerticesToRender( pMaterial );
  40. int nMaxIndices = pRenderContext->GetMaxIndicesToRender();
  41. if ( bWithInstancing )
  42. return nMaxVertices;
  43. else
  44. return MIN( (nMaxVertices / 4), (nMaxIndices / 6) );
  45. }
  46. void SetupParticleVisibility( CParticleCollection *pParticles, CParticleVisibilityData *pVisibilityData, const CParticleVisibilityInputs *pVisibilityInputs, int *nQueryHandle, IMatRenderContext *pRenderContext )
  47. {
  48. Vector vecOrigin;
  49. float flVisibility = 1.0f;
  50. if ( pVisibilityInputs->m_nCPin >= 0 )
  51. {
  52. vecOrigin = pParticles->GetControlPointAtCurrentTime( pVisibilityInputs->m_nCPin );
  53. // Pixel Visibility
  54. if ( pVisibilityInputs->m_flInputMin != pVisibilityInputs->m_flInputMax )
  55. {
  56. float flScale = pVisibilityInputs->m_flProxyRadius;
  57. flVisibility = g_pParticleSystemMgr->Query()->GetPixelVisibility( nQueryHandle, vecOrigin, flScale );
  58. flVisibility *= RemapValClamped( flScale, pVisibilityInputs->m_flInputMin, pVisibilityInputs->m_flInputMax, 0.0f , 1.0f );
  59. }
  60. // Dot
  61. if ( pVisibilityInputs->m_flDotInputMin != pVisibilityInputs->m_flDotInputMax )
  62. {
  63. CParticleSIMDTransformation pXForm1;
  64. pParticles->GetControlPointTransformAtTime( pVisibilityInputs->m_nCPin, pParticles->m_flCurTime, &pXForm1 );
  65. Vector vecInput1 = pXForm1.m_v4Fwd.Vec( 0 );
  66. Vector vecInput2 = pXForm1.m_v4Origin.Vec( 0 ) - g_pParticleSystemMgr->Query()->GetCurrentViewOrigin();
  67. VectorNormalize( vecInput2 );
  68. float flDotVisibility = DotProduct( vecInput1, vecInput2 );
  69. flVisibility *= RemapValClamped( flDotVisibility, pVisibilityInputs->m_flDotInputMin, pVisibilityInputs->m_flDotInputMax, 0.0f , 1.0f );
  70. }
  71. // Distance
  72. if ( pVisibilityInputs->m_flDistanceInputMin != pVisibilityInputs->m_flDistanceInputMax )
  73. {
  74. Vector vecCameraPos;
  75. if ( pParticles->m_pDef->IsScreenSpaceEffect() )
  76. {
  77. pRenderContext->MatrixMode( MATERIAL_VIEW );
  78. pRenderContext->PopMatrix();
  79. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  80. pRenderContext->PopMatrix();
  81. pRenderContext->GetWorldSpaceCameraPosition( &vecCameraPos );
  82. pRenderContext->MatrixMode( MATERIAL_VIEW );
  83. pRenderContext->PushMatrix();
  84. pRenderContext->LoadIdentity();
  85. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  86. pRenderContext->PushMatrix();
  87. pRenderContext->LoadIdentity();
  88. pRenderContext->Ortho( -100, -100, 100, 100, -100, 100 );
  89. }
  90. else
  91. {
  92. pRenderContext->GetWorldSpaceCameraPosition( &vecCameraPos );
  93. }
  94. Vector vecDelta = vecOrigin - vecCameraPos;
  95. float flDistance = vecDelta.Length();
  96. flVisibility *= RemapValClamped( flDistance, pVisibilityInputs->m_flDistanceInputMin, pVisibilityInputs->m_flDistanceInputMax, 0.0f , 1.0f );
  97. }
  98. }
  99. pVisibilityData->m_flAlphaVisibility = Lerp( flVisibility, pVisibilityInputs->m_flAlphaScaleMin, pVisibilityInputs->m_flAlphaScaleMax );
  100. pVisibilityData->m_flRadiusVisibility = Lerp( flVisibility, pVisibilityInputs->m_flRadiusScaleMin, pVisibilityInputs->m_flRadiusScaleMax );
  101. // FOV
  102. if ( pVisibilityInputs->m_flRadiusScaleFOVBase != 0.0f )
  103. {
  104. // m_flRadiusScaleFOVBase represents 'neutral'; scale particles up when FOV is higher and down when FOV is lower,
  105. // so their pixel width onscreen is constant as the camera zooms (though distance to the camera still has an effect)
  106. const float DEGREES_TO_RADIANS = 0.01745329f;
  107. matrix3x4_t projMatrix;
  108. pRenderContext->GetMatrix( MATERIAL_PROJECTION, &projMatrix );
  109. float flMatrixX = projMatrix.m_flMatVal[0][0];
  110. float flNeutralMatrixX = 1.0f / tanf( 0.5f*pVisibilityInputs->m_flRadiusScaleFOVBase*DEGREES_TO_RADIANS );
  111. pVisibilityData->m_flRadiusVisibility *= ( flNeutralMatrixX / flMatrixX );
  112. }
  113. }
  114. //-----------------------------------------------------------------------------
  115. // Cull systems by control point attributes
  116. // Cull if dot( camera.Position - controlpoint.Position, controlpoint.forward ) < 0
  117. //-----------------------------------------------------------------------------
  118. #define CULL_CP_NORMAL_DESCRIPTOR "cull system when CP normal faces away from camera"
  119. #define CULL_RECURSION_DEPTH_DESCRIPTOR "cull system starting at this recursion depth"
  120. struct CullSystemByControlPointData_t
  121. {
  122. int m_nCullControlPoint; // Control point who's position and orientation we use for culling (-1 for no culling)
  123. int m_nViewRecursionDepthStart; // Start culling at this view recursion depth (-1 for no culling)
  124. };
  125. bool ShouldCullParticleSystem( const CullSystemByControlPointData_t *pCullData, CParticleCollection *pParticles, IMatRenderContext *pRenderContext, int nViewResursionDepth )
  126. {
  127. // Not for screenspace effects
  128. if ( pParticles->m_pDef->IsScreenSpaceEffect() )
  129. return false;
  130. // If recursiondepthstart is -1 or m_nCullControlPoint is -1, then culling is disabled
  131. if ( pCullData->m_nCullControlPoint == -1 || pCullData->m_nViewRecursionDepthStart == -1 )
  132. return false;
  133. // Make sure we're at or past the recursion depth start
  134. if ( nViewResursionDepth < pCullData->m_nViewRecursionDepthStart )
  135. return false;
  136. // Otherwise cull when the control point is facing away from the camera
  137. Vector vCameraPos;
  138. pRenderContext->GetWorldSpaceCameraPosition( &vCameraPos );
  139. const Vector &vCullPosition = pParticles->GetControlPointAtCurrentTime( pCullData->m_nCullControlPoint );
  140. Vector vRight;
  141. Vector vUp;
  142. Vector vControlPointForward;
  143. pParticles->GetControlPointOrientationAtCurrentTime( pCullData->m_nCullControlPoint, &vRight, &vUp, &vControlPointForward );
  144. Vector vControlPointToCamera = vCameraPos - vCullPosition;
  145. vControlPointToCamera.NormalizeInPlace();
  146. float flDot = DotProduct( vControlPointToCamera, vControlPointForward );
  147. const float flCosAngleThreshold = -0.10f; // MAGIC NUMBER: cos of ~95 degrees
  148. return ( flDot < flCosAngleThreshold ) ? true : false;
  149. }
  150. static SheetSequenceSample_t s_DefaultSheetSequence =
  151. {
  152. 0.0f, 0.0f, 1.0f, 1.0f,
  153. 0.0f, 0.0f, 1.0f, 1.0f,
  154. 0.0f, 0.0f, 1.0f, 1.0f,
  155. 0.0f, 0.0f, 1.0f, 1.0f,
  156. 1.0f,
  157. };
  158. class C_OP_RenderPoints : public CParticleRenderOperatorInstance
  159. {
  160. DECLARE_PARTICLE_OPERATOR( C_OP_RenderPoints );
  161. uint32 GetWrittenAttributes( void ) const
  162. {
  163. return 0;
  164. }
  165. uint32 GetReadAttributes( void ) const
  166. {
  167. return PARTICLE_ATTRIBUTE_XYZ_MASK;
  168. }
  169. virtual uint64 GetReadControlPointMask() const
  170. {
  171. uint64 nMask = 0;
  172. if ( VisibilityInputs.m_nCPin >= 0 )
  173. nMask |= 1ULL << VisibilityInputs.m_nCPin;
  174. return nMask;
  175. }
  176. virtual void Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, int nViewRecursionDepth ) const;
  177. struct C_OP_RenderPointsContext_t
  178. {
  179. CParticleVisibilityData m_VisibilityData;
  180. int m_nQueryHandle;
  181. };
  182. size_t GetRequiredContextBytes( void ) const
  183. {
  184. return sizeof( C_OP_RenderPointsContext_t );
  185. }
  186. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  187. {
  188. C_OP_RenderPointsContext_t *pCtx = reinterpret_cast<C_OP_RenderPointsContext_t *>( pContext );
  189. pCtx->m_VisibilityData.m_bUseVisibility = false;
  190. pCtx->m_nQueryHandle = 0;
  191. }
  192. };
  193. DEFINE_PARTICLE_OPERATOR( C_OP_RenderPoints, "render_points", OPERATOR_SINGLETON );
  194. BEGIN_PARTICLE_RENDER_OPERATOR_UNPACK( C_OP_RenderPoints )
  195. END_PARTICLE_OPERATOR_UNPACK( C_OP_RenderPoints )
  196. void C_OP_RenderPoints::Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, int nViewRecursionDepth ) const
  197. {
  198. C_OP_RenderPointsContext_t *pCtx = reinterpret_cast<C_OP_RenderPointsContext_t *>( pContext );
  199. IMaterial *pMaterial = pParticles->m_pDef->GetMaterial();
  200. int nParticles;
  201. const ParticleRenderData_t *pRenderList =
  202. pParticles->GetRenderList( pRenderContext, true, &nParticles, &pCtx->m_VisibilityData );
  203. size_t xyz_stride;
  204. const fltx4 *xyz = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_XYZ, &xyz_stride );
  205. pRenderContext->Bind( pMaterial );
  206. CMeshBuilder meshBuilder;
  207. int nMaxVertices = pRenderContext->GetMaxVerticesToRender( pMaterial );
  208. while ( nParticles )
  209. {
  210. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  211. int nParticlesInBatch = MIN( nMaxVertices, nParticles );
  212. meshBuilder.Begin( pMesh, MATERIAL_POINTS, nParticlesInBatch );
  213. nParticles -= nParticlesInBatch;
  214. for( int i = 0; i < nParticlesInBatch; i++ )
  215. {
  216. int hParticle = (--pRenderList)->m_nIndex;
  217. int nIndex = ( hParticle / 4 ) * xyz_stride;
  218. int nOffset = hParticle & 0x3;
  219. meshBuilder.Position3f( SubFloat( xyz[nIndex], nOffset ), SubFloat( xyz[nIndex+1], nOffset ), SubFloat( xyz[nIndex+2], nOffset ) );
  220. meshBuilder.Color4ub( 255, 255, 255, 255 );
  221. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>();
  222. }
  223. meshBuilder.End();
  224. pMesh->DrawModulated( vecDiffuseModulation );
  225. }
  226. }
  227. //-----------------------------------------------------------------------------
  228. //
  229. // Sprite Rendering
  230. //
  231. //-----------------------------------------------------------------------------
  232. //-----------------------------------------------------------------------------
  233. // Utility struct to help with sprite rendering
  234. //-----------------------------------------------------------------------------
  235. struct SpriteRenderInfo_t
  236. {
  237. size_t m_nXYZStride;
  238. const fltx4 *m_pXYZ;
  239. size_t m_nRotStride;
  240. const fltx4 *m_pRot;
  241. size_t m_nYawStride;
  242. const fltx4 *m_pYaw;
  243. size_t m_nRGBStride;
  244. const fltx4 *m_pRGB;
  245. size_t m_nCreationTimeStride;
  246. const fltx4 *m_pCreationTimeStamp;
  247. size_t m_nSequenceStride;
  248. const fltx4 *m_pSequenceNumber;
  249. size_t m_nSequence1Stride;
  250. const fltx4 *m_pSequence1Number;
  251. float m_flAgeScale;
  252. float m_flAgeScale2;
  253. CSheet *m_pSheet;
  254. int m_nVertexOffset;
  255. CParticleCollection *m_pParticles;
  256. void Init( CParticleCollection *pParticles, int nVertexOffset, float flAgeScale, float flAgeScale2, CSheet *pSheet )
  257. {
  258. m_pParticles = pParticles;
  259. m_pXYZ = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_XYZ, &m_nXYZStride );
  260. m_pRot = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_ROTATION, &m_nRotStride );
  261. m_pYaw = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_YAW, &m_nYawStride );
  262. m_pRGB = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_TINT_RGB, &m_nRGBStride );
  263. m_pCreationTimeStamp = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, &m_nCreationTimeStride );
  264. m_pSequenceNumber = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER, &m_nSequenceStride );
  265. m_pSequence1Number = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER1, &m_nSequence1Stride );
  266. m_flAgeScale = flAgeScale;
  267. m_flAgeScale2 = flAgeScale2;
  268. m_pSheet = pSheet;
  269. m_nVertexOffset = nVertexOffset;
  270. }
  271. };
  272. class C_OP_RenderSprites : public C_OP_RenderPoints
  273. {
  274. DECLARE_PARTICLE_OPERATOR( C_OP_RenderSprites );
  275. struct C_OP_RenderSpritesContext_t
  276. {
  277. unsigned int m_nOrientationVarToken;
  278. unsigned int m_nOrientationMatrixVarToken;
  279. CParticleVisibilityData m_VisibilityData;
  280. int m_nQueryHandle;
  281. bool m_bDidPerfWarning;
  282. bool m_bPerParticleGlow;
  283. };
  284. size_t GetRequiredContextBytes( void ) const
  285. {
  286. return sizeof( C_OP_RenderSpritesContext_t );
  287. }
  288. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const;
  289. virtual uint64 GetReadControlPointMask() const
  290. {
  291. uint64 nMask = 0;
  292. if ( m_nOrientationControlPoint >= 0 )
  293. nMask |= 1ULL << m_nOrientationControlPoint;
  294. if ( VisibilityInputs.m_nCPin >= 0 )
  295. nMask |= 1ULL << VisibilityInputs.m_nCPin;
  296. return nMask;
  297. }
  298. uint32 GetReadAttributes( void ) const
  299. {
  300. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_ROTATION_MASK | PARTICLE_ATTRIBUTE_RADIUS_MASK |
  301. PARTICLE_ATTRIBUTE_TINT_RGB_MASK | PARTICLE_ATTRIBUTE_ALPHA_MASK | PARTICLE_ATTRIBUTE_CREATION_TIME_MASK |
  302. PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER1_MASK |
  303. PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK;
  304. }
  305. virtual int GetParticlesToRender( CParticleCollection *pParticles, void *pContext, int nFirstParticle, int nRemainingVertices, int nRemainingIndices, int *pVertsUsed, int *pIndicesUsed ) const;
  306. virtual void Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, int nViewRecursionDepth ) const;
  307. virtual void RenderUnsorted( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const;
  308. void RenderSpriteCard( CMeshBuilder &meshBuilder, SpriteRenderInfo_t& info, int hParticle, ParticleRenderData_t const *pSortList ) const;
  309. template<bool bPerParticleOutline, bool bDoNormals, class T> void RenderSpriteCardNew( CMeshBuilder &meshBuilder, SpriteRenderInfo_t& info, T const *pSortList ) const;
  310. void RenderTwoSequenceSpriteCardNew( CMeshBuilder &meshBuilder, SpriteRenderInfo_t& info, ParticleFullRenderData_Scalar_View const *pSortList ) const;
  311. void RenderNonSpriteCardCameraFacingOld( CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, IMatRenderContext *pRenderContext, IMaterial *pMaterial ) const;
  312. void RenderNonSpriteCardCameraFacing( CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, IMatRenderContext *pRenderContext, IMaterial *pMaterial ) const;
  313. void RenderNonSpriteCardZRotating( CMeshBuilder &meshBuilder, SpriteRenderInfo_t& info, int hParticle, const Vector& vecCameraPos, ParticleRenderData_t const *pSortList ) const;
  314. void RenderNonSpriteCardZRotating( CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, IMatRenderContext *pRenderContext, IMaterial *pMaterial ) const;
  315. void RenderUnsortedNonSpriteCardZRotating( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const;
  316. void RenderUnsortedNonSpriteCardZRotatingOld( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const;
  317. void RenderNonSpriteCardOriented( CMeshBuilder &meshBuilder, SpriteRenderInfo_t& info, int hParticle, const Vector& vecCameraPos, ParticleRenderData_t const *pSortList ) const;
  318. void RenderNonSpriteCardOriented( CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, IMatRenderContext *pRenderContext, IMaterial *pMaterial ) const;
  319. void RenderUnsortedNonSpriteCardOriented( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const;
  320. // cycles per second
  321. float m_flAnimationRate;
  322. float m_flAnimationRate2;
  323. bool m_bFitCycleToLifetime;
  324. bool m_bAnimateInFPS;
  325. int m_nOrientationType;
  326. int m_nOrientationControlPoint;
  327. CullSystemByControlPointData_t m_cullData;
  328. };
  329. DEFINE_PARTICLE_OPERATOR( C_OP_RenderSprites, "render_animated_sprites", OPERATOR_GENERIC );
  330. BEGIN_PARTICLE_RENDER_OPERATOR_UNPACK( C_OP_RenderSprites )
  331. DMXELEMENT_UNPACK_FIELD( "animation rate", ".1", float, m_flAnimationRate )
  332. DMXELEMENT_UNPACK_FIELD( "animation_fit_lifetime", "0", bool, m_bFitCycleToLifetime )
  333. DMXELEMENT_UNPACK_FIELD( "orientation_type", "0", int, m_nOrientationType )
  334. DMXELEMENT_UNPACK_FIELD( "orientation control point", "-1", int, m_nOrientationControlPoint )
  335. DMXELEMENT_UNPACK_FIELD( "second sequence animation rate", "0", float, m_flAnimationRate2 )
  336. DMXELEMENT_UNPACK_FIELD( "use animation rate as FPS", "0", bool, m_bAnimateInFPS )
  337. DMXELEMENT_UNPACK_FIELD( CULL_CP_NORMAL_DESCRIPTOR, "-1", int, m_cullData.m_nCullControlPoint )
  338. DMXELEMENT_UNPACK_FIELD( CULL_RECURSION_DEPTH_DESCRIPTOR, "-1", int, m_cullData.m_nViewRecursionDepthStart )
  339. END_PARTICLE_OPERATOR_UNPACK( C_OP_RenderSprites )
  340. void C_OP_RenderSprites::InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  341. {
  342. C_OP_RenderSpritesContext_t *pCtx = reinterpret_cast<C_OP_RenderSpritesContext_t *>( pContext );
  343. pCtx->m_nOrientationVarToken = 0;
  344. pCtx->m_nOrientationMatrixVarToken = 0;
  345. if ( ( VisibilityInputs.m_nCPin >= 0 ) || ( VisibilityInputs.m_flRadiusScaleFOVBase > 0 ) )
  346. pCtx->m_VisibilityData.m_bUseVisibility = true;
  347. else
  348. pCtx->m_VisibilityData.m_bUseVisibility = false;
  349. pCtx->m_bDidPerfWarning = false;
  350. IMaterial *pMaterial = pParticles->m_pDef->GetMaterial();
  351. IMaterialVar* pVar = pMaterial ? pMaterial->FindVarFast( "$perparticleoutline", &pParticles->m_pDef->m_nPerParticleOutlineMaterialVarToken ) : NULL;
  352. pCtx->m_bPerParticleGlow = ( pVar && ( pVar->GetIntValue() ) );
  353. pCtx->m_nQueryHandle = 0;
  354. }
  355. const SheetSequenceSample_t *GetSampleForSequence( CSheet *pSheet, float flAge, float flAgeScale, int nSequence )
  356. {
  357. if ( pSheet == NULL )
  358. return NULL;
  359. if ( pSheet->m_SheetInfo[nSequence].m_nNumFrames == 1 )
  360. return (const SheetSequenceSample_t *) &pSheet->m_SheetInfo[nSequence].m_pSamples[0];
  361. flAge *= flAgeScale;
  362. unsigned int nFrame = flAge;
  363. if ( pSheet->m_SheetInfo[nSequence].m_SeqFlags & SEQ_FLAG_CLAMP )
  364. {
  365. nFrame = MIN( nFrame, SEQUENCE_SAMPLE_COUNT-1 );
  366. }
  367. else
  368. {
  369. nFrame &= SEQUENCE_SAMPLE_COUNT-1;
  370. }
  371. return (const SheetSequenceSample_t *) &pSheet->m_SheetInfo[nSequence].m_pSamples[nFrame];
  372. }
  373. int C_OP_RenderSprites::GetParticlesToRender( CParticleCollection *pParticles,
  374. void *pContext, int nFirstParticle,
  375. int nRemainingVertices, int nRemainingIndices,
  376. int *pVertsUsed, int *pIndicesUsed ) const
  377. {
  378. int nMaxParticles = ( (nRemainingVertices / 4) > (nRemainingIndices / 6) ) ? nRemainingIndices / 6 : nRemainingVertices / 4;
  379. int nParticleCount = pParticles->m_nActiveParticles - nFirstParticle;
  380. if ( nParticleCount > nMaxParticles )
  381. {
  382. nParticleCount = nMaxParticles;
  383. }
  384. *pVertsUsed = nParticleCount * 4;
  385. *pIndicesUsed = nParticleCount * 6;
  386. return nParticleCount;
  387. }
  388. void C_OP_RenderSprites::RenderNonSpriteCardCameraFacingOld( CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, IMatRenderContext *pRenderContext, IMaterial *pMaterial ) const
  389. {
  390. C_OP_RenderSpritesContext_t *pCtx = reinterpret_cast<C_OP_RenderSpritesContext_t *>( pContext );
  391. // generate the sort list before this code starts messing with the matrices
  392. int nParticles;
  393. const ParticleRenderData_t *pSortList = pParticles->GetRenderList( pRenderContext, true, &nParticles, &pCtx->m_VisibilityData );
  394. // NOTE: This is interesting to support because at first we won't have all the various
  395. // pixel-shader versions of SpriteCard, like modulate, twotexture, etc. etc.
  396. VMatrix tempView;
  397. // Store matrices off so we can restore them in RenderEnd().
  398. pRenderContext->GetMatrix(MATERIAL_VIEW, &tempView);
  399. // Force the user clip planes to use the old view matrix
  400. pRenderContext->EnableUserClipTransformOverride( true );
  401. pRenderContext->UserClipTransform( tempView );
  402. // The particle renderers want to do things in camera space
  403. pRenderContext->MatrixMode( MATERIAL_VIEW );
  404. pRenderContext->PushMatrix();
  405. pRenderContext->LoadIdentity();
  406. size_t xyz_stride;
  407. const fltx4 *xyz = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_XYZ, &xyz_stride );
  408. size_t rot_stride;
  409. const fltx4 *pRot = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_ROTATION, &rot_stride );
  410. size_t rgb_stride;
  411. const fltx4 *pRGB = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_TINT_RGB, &rgb_stride );
  412. size_t ct_stride;
  413. const fltx4 *pCreationTimeStamp = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, &ct_stride );
  414. size_t seq_stride;
  415. const fltx4 *pSequenceNumber = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER, &seq_stride );
  416. size_t ld_stride;
  417. const fltx4 *pLifeDuration = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_LIFE_DURATION, &ld_stride );
  418. float flAgeScale;
  419. int nMaxParticlesInBatch = GetMaxParticlesPerBatch( pRenderContext, pMaterial, false );
  420. CSheet *pSheet = pParticles->m_Sheet();
  421. while ( nParticles )
  422. {
  423. int nParticlesInBatch = MIN( nMaxParticlesInBatch, nParticles );
  424. nParticles -= nParticlesInBatch;
  425. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  426. CMeshBuilder meshBuilder;
  427. meshBuilder.Begin( pMesh, MATERIAL_QUADS, nParticlesInBatch );
  428. for( int i = 0; i < nParticlesInBatch; i++ )
  429. {
  430. int hParticle = (--pSortList)->m_nIndex;
  431. int nGroup = hParticle / 4;
  432. int nOffset = hParticle & 0x3;
  433. unsigned char ac = pSortList->m_nAlpha;
  434. if ( ac == 0 )
  435. continue;
  436. int nColorIndex = nGroup * rgb_stride;
  437. float r = SubFloat( pRGB[nColorIndex], nOffset );
  438. float g = SubFloat( pRGB[nColorIndex+1], nOffset );
  439. float b = SubFloat( pRGB[nColorIndex+2], nOffset );
  440. Assert( IsFinite(r) && IsFinite(g) && IsFinite(b) );
  441. Assert( (r >= 0.0f) && (g >= 0.0f) && (b >= 0.0f) );
  442. Assert( (r <= 1.0f) && (g <= 1.0f) && (b <= 1.0f) );
  443. unsigned char rc = FastFToC( r );
  444. unsigned char gc = FastFToC( g );
  445. unsigned char bc = FastFToC( b );
  446. float rad = pSortList->m_flRadius;
  447. int nXYZIndex = nGroup * xyz_stride;
  448. Vector vecWorldPos( SubFloat( xyz[ nXYZIndex ], nOffset ), SubFloat( xyz[ nXYZIndex+1 ], nOffset ), SubFloat( xyz[ nXYZIndex+2 ], nOffset ) );
  449. Vector vecViewPos;
  450. Vector3DMultiplyPosition( tempView, vecWorldPos, vecViewPos );
  451. if (!IsFinite(vecViewPos.x))
  452. continue;
  453. float rot = SubFloat( pRot[ nGroup * rot_stride ], nOffset );
  454. float sa, ca;
  455. SinCos( rot, &sa, &ca );
  456. // Find the sample for this frame
  457. const SheetSequenceSample_t *pSample = &s_DefaultSheetSequence;
  458. if ( pSheet )
  459. {
  460. int nSequence = SubFloat( pSequenceNumber[ nGroup * seq_stride ], nOffset );
  461. if ( m_bFitCycleToLifetime )
  462. {
  463. float flLifetime = SubFloat( pLifeDuration[ nGroup * ld_stride ], nOffset );
  464. flAgeScale = ( flLifetime > 0.0f ) ? ( 1.0f / flLifetime ) * SEQUENCE_SAMPLE_COUNT : 0.0f;
  465. }
  466. else
  467. {
  468. flAgeScale = m_flAnimationRate * SEQUENCE_SAMPLE_COUNT;
  469. if ( m_bAnimateInFPS )
  470. {
  471. flAgeScale = flAgeScale / pSheet->m_SheetInfo[nSequence].m_flFrameSpan;
  472. }
  473. }
  474. pSample = GetSampleForSequence( pSheet,
  475. pParticles->m_flCurTime - SubFloat( pCreationTimeStamp[ nGroup * ct_stride ], nOffset ),
  476. flAgeScale,
  477. nSequence );
  478. }
  479. const SequenceSampleTextureCoords_t *pSample0 = &(pSample->m_TextureCoordData[0]);
  480. meshBuilder.Position3f( vecViewPos.x + (-ca + sa) * rad, vecViewPos.y + (-sa - ca) * rad, vecViewPos.z );
  481. meshBuilder.Color4ub( rc, gc, bc, ac );
  482. meshBuilder.TexCoord2f( 0, pSample0->m_fLeft_U0, pSample0->m_fBottom_V0 );
  483. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
  484. meshBuilder.Position3f( vecViewPos.x + (-ca - sa) * rad, vecViewPos.y + (-sa + ca) * rad, vecViewPos.z );
  485. meshBuilder.Color4ub( rc, gc, bc, ac );
  486. meshBuilder.TexCoord2f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0 );
  487. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
  488. meshBuilder.Position3f( vecViewPos.x + (ca - sa) * rad, vecViewPos.y + (sa + ca) * rad, vecViewPos.z );
  489. meshBuilder.Color4ub( rc, gc, bc, ac );
  490. meshBuilder.TexCoord2f( 0, pSample0->m_fRight_U0, pSample0->m_fTop_V0 );
  491. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
  492. meshBuilder.Position3f( vecViewPos.x + (ca + sa) * rad, vecViewPos.y + (sa - ca) * rad, vecViewPos.z );
  493. meshBuilder.Color4ub( rc, gc, bc, ac );
  494. meshBuilder.TexCoord2f( 0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  495. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
  496. }
  497. meshBuilder.End();
  498. pMesh->DrawModulated( vecDiffuseModulation );
  499. }
  500. pRenderContext->EnableUserClipTransformOverride( false );
  501. pRenderContext->MatrixMode( MATERIAL_VIEW );
  502. pRenderContext->PopMatrix();
  503. }
  504. void C_OP_RenderSprites::RenderNonSpriteCardCameraFacing( CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, IMatRenderContext *pRenderContext, IMaterial *pMaterial ) const
  505. {
  506. C_OP_RenderSpritesContext_t *pCtx = reinterpret_cast<C_OP_RenderSpritesContext_t *>( pContext );
  507. // generate the sort list before this code starts messing with the matrices
  508. int nParticles;
  509. ParticleFullRenderData_Scalar_View **pSortList = GetExtendedRenderList(
  510. pParticles, pRenderContext, true, &nParticles, &pCtx->m_VisibilityData );
  511. // NOTE: This is interesting to support because at first we won't have all the various
  512. // pixel-shader versions of SpriteCard, like modulate, twotexture, etc. etc.
  513. VMatrix tempView;
  514. // Store matrices off so we can restore them in RenderEnd().
  515. pRenderContext->GetMatrix(MATERIAL_VIEW, &tempView);
  516. // Force the user clip planes to use the old view matrix
  517. pRenderContext->EnableUserClipTransformOverride( true );
  518. pRenderContext->UserClipTransform( tempView );
  519. // The particle renderers want to do things in camera space
  520. pRenderContext->MatrixMode( MATERIAL_VIEW );
  521. pRenderContext->PushMatrix();
  522. pRenderContext->LoadIdentity();
  523. float flAgeScale;
  524. int nMaxParticlesInBatch = GetMaxParticlesPerBatch( pRenderContext, pMaterial, false );
  525. CSheet *pSheet = pParticles->m_Sheet();
  526. while ( nParticles )
  527. {
  528. int nParticlesInBatch = MIN( nMaxParticlesInBatch, nParticles );
  529. nParticles -= nParticlesInBatch;
  530. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  531. CMeshBuilder meshBuilder;
  532. meshBuilder.Begin( pMesh, MATERIAL_QUADS, nParticlesInBatch );
  533. for( int i = 0; i < nParticlesInBatch; i++ )
  534. {
  535. ParticleFullRenderData_Scalar_View *pParticle = *(--pSortList);
  536. unsigned char ac = pParticle->m_nAlpha;
  537. if ( ac == 0 )
  538. continue;
  539. unsigned char rc = pParticle->m_nRed;
  540. unsigned char gc = pParticle->m_nGreen;
  541. unsigned char bc = pParticle->m_nBlue;
  542. float rad = pParticle->m_flRadius;
  543. Vector vecWorldPos( pParticle->m_flX, pParticle->m_flY, pParticle->m_flZ );
  544. Vector vecViewPos;
  545. Vector3DMultiplyPosition( tempView, vecWorldPos, vecViewPos );
  546. if (!IsFinite(vecViewPos.x))
  547. continue;
  548. float rot = pParticle->m_flRotation;
  549. float sa, ca;
  550. SinCos( rot, &sa, &ca );
  551. // Find the sample for this frame
  552. const SheetSequenceSample_t *pSample = &s_DefaultSheetSequence;
  553. if ( pSheet )
  554. {
  555. int nSequence = pParticle->m_nSequenceID;
  556. flAgeScale = m_flAnimationRate * SEQUENCE_SAMPLE_COUNT;
  557. if ( m_bAnimateInFPS )
  558. {
  559. flAgeScale = flAgeScale / pSheet->m_SheetInfo[nSequence].m_flFrameSpan;
  560. }
  561. pSample = GetSampleForSequence( pSheet,
  562. pParticle->m_flAnimationTimeValue,
  563. flAgeScale,
  564. nSequence );
  565. }
  566. const SequenceSampleTextureCoords_t *pSample0 = &(pSample->m_TextureCoordData[0]);
  567. meshBuilder.Position3f( vecViewPos.x + (-ca + sa) * rad, vecViewPos.y + (-sa - ca) * rad, vecViewPos.z );
  568. meshBuilder.Color4ub( rc, gc, bc, ac );
  569. meshBuilder.TexCoord2f( 0, pSample0->m_fLeft_U0, pSample0->m_fBottom_V0 );
  570. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
  571. meshBuilder.Position3f( vecViewPos.x + (-ca - sa) * rad, vecViewPos.y + (-sa + ca) * rad, vecViewPos.z );
  572. meshBuilder.Color4ub( rc, gc, bc, ac );
  573. meshBuilder.TexCoord2f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0 );
  574. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
  575. meshBuilder.Position3f( vecViewPos.x + (ca - sa) * rad, vecViewPos.y + (sa + ca) * rad, vecViewPos.z );
  576. meshBuilder.Color4ub( rc, gc, bc, ac );
  577. meshBuilder.TexCoord2f( 0, pSample0->m_fRight_U0, pSample0->m_fTop_V0 );
  578. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
  579. meshBuilder.Position3f( vecViewPos.x + (ca + sa) * rad, vecViewPos.y + (sa - ca) * rad, vecViewPos.z );
  580. meshBuilder.Color4ub( rc, gc, bc, ac );
  581. meshBuilder.TexCoord2f( 0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  582. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
  583. }
  584. meshBuilder.End();
  585. pMesh->DrawModulated( vecDiffuseModulation );
  586. }
  587. pRenderContext->EnableUserClipTransformOverride( false );
  588. pRenderContext->MatrixMode( MATERIAL_VIEW );
  589. pRenderContext->PopMatrix();
  590. }
  591. void C_OP_RenderSprites::RenderNonSpriteCardZRotating( CMeshBuilder &meshBuilder, SpriteRenderInfo_t& info, int hParticle, const Vector& vecCameraPos, ParticleRenderData_t const *pSortList ) const
  592. {
  593. Assert( hParticle != -1 );
  594. int nGroup = hParticle / 4;
  595. int nOffset = hParticle & 0x3;
  596. unsigned char ac = pSortList->m_nAlpha;
  597. if ( ac == 0 )
  598. return;
  599. int nColorIndex = nGroup * info.m_nRGBStride;
  600. float r = SubFloat( info.m_pRGB[nColorIndex], nOffset );
  601. float g = SubFloat( info.m_pRGB[nColorIndex+1], nOffset );
  602. float b = SubFloat( info.m_pRGB[nColorIndex+2], nOffset );
  603. Assert( IsFinite(r) && IsFinite(g) && IsFinite(b) );
  604. Assert( (r >= 0.0f) && (g >= 0.0f) && (b >= 0.0f) );
  605. Assert( (r <= 1.0f) && (g <= 1.0f) && (b <= 1.0f) );
  606. unsigned char rc = FastFToC( r );
  607. unsigned char gc = FastFToC( g );
  608. unsigned char bc = FastFToC( b );
  609. float rad = pSortList->m_flRadius;
  610. float rot = SubFloat( info.m_pRot[ nGroup * info.m_nRotStride ], nOffset );
  611. float sa, ca;
  612. SinCos( -rot, &sa, &ca );
  613. int nXYZIndex = nGroup * info.m_nXYZStride;
  614. Vector vecWorldPos( SubFloat( info.m_pXYZ[ nXYZIndex ], nOffset ), SubFloat( info.m_pXYZ[ nXYZIndex+1 ], nOffset ), SubFloat( info.m_pXYZ[ nXYZIndex+2 ], nOffset ) );
  615. Vector vecViewToPos;
  616. VectorSubtract( vecWorldPos, vecCameraPos, vecViewToPos );
  617. float flLength = vecViewToPos.Length();
  618. if ( flLength < rad / 2 )
  619. return;
  620. Vector vecUp( 0, 0, 1 );
  621. Vector vecRight;
  622. CrossProduct( vecUp, vecCameraPos, vecRight );
  623. VectorNormalize( vecRight );
  624. // Find the sample for this frame
  625. const SheetSequenceSample_t *pSample = &s_DefaultSheetSequence;
  626. if ( info.m_pSheet )
  627. {
  628. pSample = GetSampleForSequence(
  629. info.m_pSheet,
  630. info.m_pParticles->m_flCurTime - SubFloat( info.m_pCreationTimeStamp[ nGroup * info.m_nCreationTimeStride ], nOffset ),
  631. info.m_flAgeScale,
  632. SubFloat( info.m_pSequenceNumber[ nGroup * info.m_nSequenceStride ], nOffset ) );
  633. }
  634. const SequenceSampleTextureCoords_t *pSample0 = &(pSample->m_TextureCoordData[0]);
  635. vecRight *= rad;
  636. float x, y;
  637. Vector vecCorner;
  638. x = - ca - sa; y = - ca + sa;
  639. VectorMA( vecWorldPos, x, vecRight, vecCorner );
  640. meshBuilder.Position3f( vecCorner.x, vecCorner.y, vecCorner.z + y * rad );
  641. meshBuilder.Color4ub( rc, gc, bc, ac );
  642. meshBuilder.TexCoord2f( 0, pSample0->m_fLeft_U0, pSample0->m_fBottom_V0 );
  643. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
  644. x = - ca + sa; y = + ca + sa;
  645. VectorMA( vecWorldPos, x, vecRight, vecCorner );
  646. meshBuilder.Position3f( vecCorner.x, vecCorner.y, vecCorner.z + y * rad );
  647. meshBuilder.Color4ub( rc, gc, bc, ac );
  648. meshBuilder.TexCoord2f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0 );
  649. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
  650. x = + ca + sa; y = + ca - sa;
  651. VectorMA( vecWorldPos, x, vecRight, vecCorner );
  652. meshBuilder.Position3f( vecCorner.x, vecCorner.y, vecCorner.z + y * rad );
  653. meshBuilder.Color4ub( rc, gc, bc, ac );
  654. meshBuilder.TexCoord2f( 0, pSample0->m_fRight_U0, pSample0->m_fTop_V0 );
  655. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
  656. x = + ca - sa; y = - ca - sa;
  657. VectorMA( vecWorldPos, x, vecRight, vecCorner );
  658. meshBuilder.Position3f( vecCorner.x, vecCorner.y, vecCorner.z + y * rad );
  659. meshBuilder.Color4ub( rc, gc, bc, ac );
  660. meshBuilder.TexCoord2f( 0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  661. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
  662. meshBuilder.FastQuad( info.m_nVertexOffset );
  663. info.m_nVertexOffset += 4;
  664. }
  665. //-----------------------------------------------------------------------------
  666. // Purpose:
  667. //-----------------------------------------------------------------------------
  668. void C_OP_RenderSprites::RenderNonSpriteCardZRotating( CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, IMatRenderContext *pRenderContext, IMaterial *pMaterial ) const
  669. {
  670. C_OP_RenderSpritesContext_t *pCtx = reinterpret_cast<C_OP_RenderSpritesContext_t *>( pContext );
  671. // NOTE: This is interesting to support because at first we won't have all the various
  672. // pixel-shader versions of SpriteCard, like modulate, twotexture, etc. etc.
  673. Vector vecCameraPos;
  674. pRenderContext->GetWorldSpaceCameraPosition( &vecCameraPos );
  675. float flAgeScale = m_flAnimationRate * SEQUENCE_SAMPLE_COUNT;
  676. SpriteRenderInfo_t info;
  677. info.Init( pParticles, 0, flAgeScale, 0, pParticles->m_Sheet() );
  678. int nParticles;
  679. const ParticleRenderData_t *pSortList = pParticles->GetRenderList( pRenderContext, true, &nParticles, &pCtx->m_VisibilityData );
  680. int nMaxParticlesInBatch = GetMaxParticlesPerBatch( pRenderContext, pMaterial, false );
  681. while ( nParticles )
  682. {
  683. int nParticlesInBatch = MIN( nMaxParticlesInBatch, nParticles );
  684. nParticles -= nParticlesInBatch;
  685. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  686. CMeshBuilder meshBuilder;
  687. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nParticlesInBatch * 4, nParticlesInBatch * 6 );
  688. info.m_nVertexOffset = 0;
  689. for( int i = 0; i < nParticlesInBatch; i++ )
  690. {
  691. int hParticle = (--pSortList)->m_nIndex;
  692. RenderNonSpriteCardZRotating( meshBuilder, info, hParticle, vecCameraPos, pSortList );
  693. }
  694. meshBuilder.End();
  695. pMesh->DrawModulated( vecDiffuseModulation );
  696. }
  697. }
  698. void C_OP_RenderSprites::RenderUnsortedNonSpriteCardZRotating( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const
  699. {
  700. C_OP_RenderSpritesContext_t *pCtx = reinterpret_cast<C_OP_RenderSpritesContext_t *>( pContext );
  701. // NOTE: This is interesting to support because at first we won't have all the various
  702. // pixel-shader versions of SpriteCard, like modulate, twotexture, etc. etc.
  703. Vector vecCameraPos;
  704. pRenderContext->GetWorldSpaceCameraPosition( &vecCameraPos );
  705. float flAgeScale = m_flAnimationRate * SEQUENCE_SAMPLE_COUNT;
  706. SpriteRenderInfo_t info;
  707. info.Init( pParticles, nVertexOffset, flAgeScale, 0, pParticles->m_Sheet() );
  708. int nParticles;
  709. const ParticleRenderData_t *pSortList = pParticles->GetRenderList( pRenderContext, false, &nParticles, &pCtx->m_VisibilityData );
  710. int hParticle = nFirstParticle;
  711. for( int i = 0; i < nParticleCount; i++, hParticle++ )
  712. {
  713. RenderNonSpriteCardZRotating( meshBuilder, info, hParticle, vecCameraPos, pSortList );
  714. }
  715. }
  716. //-----------------------------------------------------------------------------
  717. // Purpose:
  718. //-----------------------------------------------------------------------------
  719. void C_OP_RenderSprites::RenderNonSpriteCardOriented( CMeshBuilder &meshBuilder, SpriteRenderInfo_t& info, int hParticle, const Vector& vecCameraPos, ParticleRenderData_t const *pSortList ) const
  720. {
  721. Assert( hParticle != -1 );
  722. int nGroup = hParticle / 4;
  723. int nOffset = hParticle & 0x3;
  724. unsigned char ac = pSortList->m_nAlpha;
  725. if ( ac == 0 )
  726. return;
  727. int nColorIndex = nGroup * info.m_nRGBStride;
  728. float r = SubFloat( info.m_pRGB[nColorIndex], nOffset );
  729. float g = SubFloat( info.m_pRGB[nColorIndex+1], nOffset );
  730. float b = SubFloat( info.m_pRGB[nColorIndex+2], nOffset );
  731. Assert( IsFinite(r) && IsFinite(g) && IsFinite(b) ); // infinite color = bad
  732. Assert( (r >= 0.0f) && (g >= 0.0f) && (b >= 0.0f) ); // negative color = bad
  733. //Assert( (r <= 1.0f) && (g <= 1.0f) && (b <= 1.0f) );
  734. unsigned char rc = FastFToC( r );
  735. unsigned char gc = FastFToC( g );
  736. unsigned char bc = FastFToC( b );
  737. float rad = pSortList->m_flRadius;
  738. float rot = SubFloat( info.m_pRot[ nGroup * info.m_nRotStride ], nOffset );
  739. float sa, ca;
  740. SinCos( -rot, &sa, &ca );
  741. int nXYZIndex = nGroup * info.m_nXYZStride;
  742. Vector vecWorldPos( SubFloat( info.m_pXYZ[ nXYZIndex ], nOffset ), SubFloat( info.m_pXYZ[ nXYZIndex+1 ], nOffset ), SubFloat( info.m_pXYZ[ nXYZIndex+2 ], nOffset ) );
  743. Vector vecViewToPos;
  744. VectorSubtract( vecWorldPos, vecCameraPos, vecViewToPos );
  745. float flLength = vecViewToPos.Length();
  746. if ( flLength < rad / 2 )
  747. return;
  748. Vector vecNormal, vecRight, vecUp;
  749. if ( m_nOrientationControlPoint < 0 )
  750. {
  751. vecNormal.Init( 0, 0, 1 );
  752. vecRight.Init( 1, 0, 0 );
  753. vecUp.Init( 0, -1, 0 );
  754. }
  755. else
  756. {
  757. info.m_pParticles->GetControlPointOrientationAtCurrentTime(
  758. m_nOrientationControlPoint, &vecRight, &vecUp, &vecNormal );
  759. }
  760. // Find the sample for this frame
  761. const SheetSequenceSample_t *pSample = &s_DefaultSheetSequence;
  762. if ( info.m_pSheet )
  763. {
  764. pSample = GetSampleForSequence(
  765. info.m_pSheet,
  766. info.m_pParticles->m_flCurTime - SubFloat( info.m_pCreationTimeStamp[ nGroup * info.m_nCreationTimeStride ], nOffset ),
  767. info.m_flAgeScale,
  768. SubFloat( info.m_pSequenceNumber[ nGroup * info.m_nSequenceStride ], nOffset ) );
  769. }
  770. const SequenceSampleTextureCoords_t *pSample0 = &(pSample->m_TextureCoordData[0]);
  771. vecRight *= rad;
  772. vecUp *= rad;
  773. float x, y;
  774. Vector vecCorner;
  775. x = + ca - sa; y = - ca - sa;
  776. VectorMA( vecWorldPos, x, vecRight, vecCorner );
  777. VectorMA( vecCorner, y, vecUp, vecCorner );
  778. meshBuilder.Position3f( vecCorner.x, vecCorner.y, vecCorner.z );
  779. meshBuilder.Color4ub( rc, gc, bc, ac );
  780. meshBuilder.TexCoord2f( 0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  781. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
  782. x = + ca + sa; y = + ca - sa;
  783. VectorMA( vecWorldPos, x, vecRight, vecCorner );
  784. VectorMA( vecCorner, y, vecUp, vecCorner );
  785. meshBuilder.Position3f( vecCorner.x, vecCorner.y, vecCorner.z );
  786. meshBuilder.Color4ub( rc, gc, bc, ac );
  787. meshBuilder.TexCoord2f( 0, pSample0->m_fRight_U0, pSample0->m_fTop_V0 );
  788. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
  789. x = - ca + sa; y = + ca + sa;
  790. VectorMA( vecWorldPos, x, vecRight, vecCorner );
  791. VectorMA( vecCorner, y, vecUp, vecCorner );
  792. meshBuilder.Position3f( vecCorner.x, vecCorner.y, vecCorner.z );
  793. meshBuilder.Color4ub( rc, gc, bc, ac );
  794. meshBuilder.TexCoord2f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0 );
  795. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
  796. x = - ca - sa; y = - ca + sa;
  797. VectorMA( vecWorldPos, x, vecRight, vecCorner );
  798. VectorMA( vecCorner, y, vecUp, vecCorner );
  799. meshBuilder.Position3f( vecCorner.x, vecCorner.y, vecCorner.z );
  800. meshBuilder.Color4ub( rc, gc, bc, ac );
  801. meshBuilder.TexCoord2f( 0, pSample0->m_fLeft_U0, pSample0->m_fBottom_V0 );
  802. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>();
  803. meshBuilder.FastQuad( info.m_nVertexOffset );
  804. info.m_nVertexOffset += 4;
  805. }
  806. void C_OP_RenderSprites::RenderNonSpriteCardOriented( CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, IMatRenderContext *pRenderContext, IMaterial *pMaterial ) const
  807. {
  808. C_OP_RenderSpritesContext_t *pCtx = reinterpret_cast<C_OP_RenderSpritesContext_t *>( pContext );
  809. // NOTE: This is interesting to support because at first we won't have all the various
  810. // pixel-shader versions of SpriteCard, like modulate, twotexture, etc. etc.
  811. Vector vecCameraPos;
  812. pRenderContext->GetWorldSpaceCameraPosition( &vecCameraPos );
  813. float flAgeScale = m_flAnimationRate * SEQUENCE_SAMPLE_COUNT;
  814. SpriteRenderInfo_t info;
  815. info.Init( pParticles, 0, flAgeScale, 0, pParticles->m_Sheet() );
  816. int nParticles;
  817. const ParticleRenderData_t *pSortList = pParticles->GetRenderList( pRenderContext, true, &nParticles, &pCtx->m_VisibilityData );
  818. int nMaxParticlesInBatch = GetMaxParticlesPerBatch( pRenderContext, pMaterial, false );
  819. while ( nParticles )
  820. {
  821. int nParticlesInBatch = MIN( nMaxParticlesInBatch, nParticles );
  822. nParticles -= nParticlesInBatch;
  823. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  824. CMeshBuilder meshBuilder;
  825. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nParticlesInBatch * 4, nParticlesInBatch * 6 );
  826. info.m_nVertexOffset = 0;
  827. for( int i = 0; i < nParticlesInBatch; i++)
  828. {
  829. int hParticle = (--pSortList)->m_nIndex;
  830. RenderNonSpriteCardOriented( meshBuilder, info, hParticle, vecCameraPos, pSortList );
  831. }
  832. meshBuilder.End();
  833. pMesh->DrawModulated( vecDiffuseModulation );
  834. }
  835. }
  836. void C_OP_RenderSprites::RenderUnsortedNonSpriteCardOriented( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const
  837. {
  838. C_OP_RenderSpritesContext_t *pCtx = reinterpret_cast<C_OP_RenderSpritesContext_t *>( pContext );
  839. // NOTE: This is interesting to support because at first we won't have all the various
  840. // pixel-shader versions of SpriteCard, like modulate, twotexture, etc. etc.
  841. Vector vecCameraPos;
  842. pRenderContext->GetWorldSpaceCameraPosition( &vecCameraPos );
  843. float flAgeScale = m_flAnimationRate * SEQUENCE_SAMPLE_COUNT;
  844. SpriteRenderInfo_t info;
  845. info.Init( pParticles, nVertexOffset, flAgeScale, 0, pParticles->m_Sheet() );
  846. int nParticles;
  847. const ParticleRenderData_t *pSortList = pParticles->GetRenderList( pRenderContext, false, &nParticles, &pCtx->m_VisibilityData );
  848. int hParticle = nFirstParticle;
  849. for( int i = 0; i < nParticleCount; i++, hParticle++ )
  850. {
  851. RenderNonSpriteCardOriented( meshBuilder, info, hParticle, vecCameraPos, pSortList );
  852. }
  853. }
  854. template<bool bPerParticleOutline, bool bDoNormals, class T> void C_OP_RenderSprites::RenderSpriteCardNew( CMeshBuilder &meshBuilder, SpriteRenderInfo_t& info, T const *pSortList ) const
  855. {
  856. unsigned char ac = pSortList->m_nAlpha;
  857. if (! ac )
  858. return;
  859. unsigned char rc = pSortList->m_nRed;
  860. unsigned char gc = pSortList->m_nGreen;
  861. unsigned char bc = pSortList->m_nBlue;
  862. float rad = pSortList->m_flRadius;
  863. float rot = pSortList->m_flRotation;
  864. float yaw = pSortList->m_flYaw;
  865. float x = pSortList->m_flX;
  866. float y = pSortList->m_flY;
  867. float z = pSortList->m_flZ;
  868. // Find the sample for this frame
  869. const SheetSequenceSample_t *pSample = &s_DefaultSheetSequence;
  870. if ( info.m_pSheet )
  871. {
  872. float flAgeScale = info.m_flAgeScale;
  873. int nSequence = pSortList->m_nSequenceID;
  874. if ( m_bAnimateInFPS )
  875. {
  876. flAgeScale = flAgeScale / info.m_pParticles->m_Sheet()->m_SheetInfo[nSequence].m_flFrameSpan;
  877. }
  878. pSample = GetSampleForSequence( info.m_pSheet,
  879. pSortList->m_flAnimationTimeValue,
  880. flAgeScale,
  881. nSequence );
  882. }
  883. const SequenceSampleTextureCoords_t *pSample0 = &(pSample->m_TextureCoordData[0]);
  884. const SequenceSampleTextureCoords_t *pSecondTexture0 = &(pSample->m_TextureCoordData[1]);
  885. static float s_flCornerIds[] = { 0,0, 1,0, 1,1, 0,1 };
  886. float const *pIds = s_flCornerIds;
  887. for( int i = 0; i < ( bUseInstancing ? 1 : 4 ); i++ )
  888. {
  889. meshBuilder.Position3f( x, y, z );
  890. meshBuilder.Color4ub( rc, gc, bc, ac );
  891. meshBuilder.TexCoord4f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  892. meshBuilder.TexCoord4f( 1, pSample0->m_fLeft_U1, pSample0->m_fTop_V1, pSample0->m_fRight_U1, pSample0->m_fBottom_V1 );
  893. meshBuilder.TexCoord4f( 2, pSample->m_fBlendFactor, rot, rad, yaw );
  894. if ( ! bUseInstancing )
  895. {
  896. meshBuilder.TexCoord2fv( 3, pIds );
  897. pIds += 2;
  898. }
  899. meshBuilder.TexCoord4f( 4, pSecondTexture0->m_fLeft_U0, pSecondTexture0->m_fTop_V0, pSecondTexture0->m_fRight_U0, pSecondTexture0->m_fBottom_V0 );
  900. if ( bDoNormals )
  901. {
  902. meshBuilder.TexCoord3f( 5, pSortList->NormalX(), pSortList->NormalY(), pSortList->NormalZ() );
  903. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 6>();
  904. }
  905. else
  906. {
  907. if ( bPerParticleOutline )
  908. {
  909. meshBuilder.TexCoord4f( 5, pSortList->Red2(), pSortList->Green2(), pSortList->Blue2(), pSortList->Alpha2() );
  910. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 6>();
  911. }
  912. else
  913. {
  914. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 5>();
  915. }
  916. }
  917. }
  918. if ( ! bUseInstancing )
  919. {
  920. meshBuilder.FastQuad( info.m_nVertexOffset );
  921. info.m_nVertexOffset += 4;
  922. }
  923. }
  924. void C_OP_RenderSprites::RenderSpriteCard( CMeshBuilder &meshBuilder, SpriteRenderInfo_t& info, int hParticle, ParticleRenderData_t const *pSortList ) const
  925. {
  926. Assert( hParticle != -1 );
  927. unsigned char ac = pSortList->m_nAlpha;
  928. if (! ac )
  929. return;
  930. int nGroup = hParticle / 4;
  931. int nOffset = hParticle & 0x3;
  932. int nColorIndex = nGroup * info.m_nRGBStride;
  933. float r = SubFloat( info.m_pRGB[nColorIndex], nOffset );
  934. float g = SubFloat( info.m_pRGB[nColorIndex+1], nOffset );
  935. float b = SubFloat( info.m_pRGB[nColorIndex+2], nOffset );
  936. Assert( IsFinite(r) && IsFinite(g) && IsFinite(b) );
  937. Assert( (r >= 0.0f) && (g >= 0.0f) && (b >= 0.0f) );
  938. Assert( (r <= 1.0f) && (g <= 1.0f) && (b <= 1.0f) );
  939. unsigned char rc = FastFToC( r );
  940. unsigned char gc = FastFToC( g );
  941. unsigned char bc = FastFToC( b );
  942. float rad = pSortList->m_flRadius;
  943. float rot = SubFloat( info.m_pRot[ nGroup * info.m_nRotStride ], nOffset );
  944. float yaw = SubFloat( info.m_pYaw[ nGroup * info.m_nYawStride ], nOffset );
  945. int nXYZIndex = nGroup * info.m_nXYZStride;
  946. float x = SubFloat( info.m_pXYZ[ nXYZIndex ], nOffset );
  947. float y = SubFloat( info.m_pXYZ[ nXYZIndex+1 ], nOffset );
  948. float z = SubFloat( info.m_pXYZ[ nXYZIndex+2 ], nOffset );
  949. // Find the sample for this frame
  950. const SheetSequenceSample_t *pSample = &s_DefaultSheetSequence;
  951. if ( info.m_pSheet )
  952. {
  953. float flAgeScale = info.m_flAgeScale;
  954. // if ( m_bFitCycleToLifetime )
  955. // {
  956. // float flLifetime = SubFloat( pLifeDuration[ nGroup * ld_stride ], nOffset );
  957. // flAgeScale = ( flLifetime > 0.0f ) ? ( 1.0f / flLifetime ) * SEQUENCE_SAMPLE_COUNT : 0.0f;
  958. // }
  959. int nSequence = SubFloat( info.m_pSequenceNumber[ nGroup * info.m_nSequenceStride ], nOffset );
  960. if ( m_bAnimateInFPS )
  961. {
  962. flAgeScale = flAgeScale / info.m_pParticles->m_Sheet()->m_SheetInfo[nSequence].m_flFrameSpan;
  963. }
  964. pSample = GetSampleForSequence( info.m_pSheet,
  965. info.m_pParticles->m_flCurTime - SubFloat( info.m_pCreationTimeStamp[ nGroup * info.m_nCreationTimeStride ], nOffset ),
  966. flAgeScale,
  967. nSequence );
  968. }
  969. const SequenceSampleTextureCoords_t *pSample0 = &(pSample->m_TextureCoordData[0]);
  970. const SequenceSampleTextureCoords_t *pSecondTexture0 = &(pSample->m_TextureCoordData[1]);
  971. // Submit 1 (instanced) or 4 (non-instanced) verts (if we're instancing, we don't produce indices either)
  972. meshBuilder.Position3f( x, y, z );
  973. meshBuilder.Color4ub( rc, gc, bc, ac );
  974. meshBuilder.TexCoord4f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  975. meshBuilder.TexCoord4f( 1, pSample0->m_fLeft_U1, pSample0->m_fTop_V1, pSample0->m_fRight_U1, pSample0->m_fBottom_V1 );
  976. meshBuilder.TexCoord4f( 2, pSample->m_fBlendFactor, rot, rad, yaw );
  977. // FIXME: change the vertex decl (remove texcoord3/cornerid) if instancing - need to adjust elements beyond texcoord3 down, though
  978. if ( !bUseInstancing )
  979. meshBuilder.TexCoord2f( 3, 0, 0 );
  980. meshBuilder.TexCoord4f( 4, pSecondTexture0->m_fLeft_U0, pSecondTexture0->m_fTop_V0, pSecondTexture0->m_fRight_U0, pSecondTexture0->m_fBottom_V0 );
  981. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 5>();
  982. if ( !bUseInstancing )
  983. {
  984. meshBuilder.Position3f( x, y, z );
  985. meshBuilder.Color4ub( rc, gc, bc, ac );
  986. meshBuilder.TexCoord4f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  987. meshBuilder.TexCoord4f( 1, pSample0->m_fLeft_U1, pSample0->m_fTop_V1, pSample0->m_fRight_U1, pSample0->m_fBottom_V1 );
  988. meshBuilder.TexCoord4f( 2, pSample->m_fBlendFactor, rot, rad, yaw );
  989. meshBuilder.TexCoord2f( 3, 1, 0 );
  990. meshBuilder.TexCoord4f( 4, pSecondTexture0->m_fLeft_U0, pSecondTexture0->m_fTop_V0, pSecondTexture0->m_fRight_U0, pSecondTexture0->m_fBottom_V0 );
  991. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 5>();
  992. meshBuilder.Position3f( x, y, z );
  993. meshBuilder.Color4ub( rc, gc, bc, ac );
  994. meshBuilder.TexCoord4f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  995. meshBuilder.TexCoord4f( 1, pSample0->m_fLeft_U1, pSample0->m_fTop_V1, pSample0->m_fRight_U1, pSample0->m_fBottom_V1 );
  996. meshBuilder.TexCoord4f( 2, pSample->m_fBlendFactor, rot, rad, yaw );
  997. meshBuilder.TexCoord2f( 3, 1, 1 );
  998. meshBuilder.TexCoord4f( 4, pSecondTexture0->m_fLeft_U0, pSecondTexture0->m_fTop_V0, pSecondTexture0->m_fRight_U0, pSecondTexture0->m_fBottom_V0 );
  999. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 5>();
  1000. meshBuilder.Position3f( x, y, z );
  1001. meshBuilder.Color4ub( rc, gc, bc, ac );
  1002. meshBuilder.TexCoord4f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  1003. meshBuilder.TexCoord4f( 1, pSample0->m_fLeft_U1, pSample0->m_fTop_V1, pSample0->m_fRight_U1, pSample0->m_fBottom_V1 );
  1004. meshBuilder.TexCoord4f( 2, pSample->m_fBlendFactor, rot, rad, yaw );
  1005. meshBuilder.TexCoord2f( 3, 0, 1 );
  1006. meshBuilder.TexCoord4f( 4, pSecondTexture0->m_fLeft_U0, pSecondTexture0->m_fTop_V0, pSecondTexture0->m_fRight_U0, pSecondTexture0->m_fBottom_V0 );
  1007. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 5>();
  1008. meshBuilder.FastQuad( info.m_nVertexOffset );
  1009. info.m_nVertexOffset += 4;
  1010. }
  1011. }
  1012. void C_OP_RenderSprites::RenderTwoSequenceSpriteCardNew( CMeshBuilder &meshBuilder, SpriteRenderInfo_t& info, ParticleFullRenderData_Scalar_View const *pSortList ) const
  1013. {
  1014. unsigned char rc = pSortList->m_nRed;
  1015. unsigned char gc = pSortList->m_nGreen;
  1016. unsigned char bc = pSortList->m_nBlue;
  1017. unsigned char ac = pSortList->m_nAlpha;
  1018. if ( ac == 0 )
  1019. return;
  1020. float rad = pSortList->m_flRadius;
  1021. float rot = pSortList->m_flRotation;
  1022. float yaw = pSortList->m_flYaw;
  1023. float x = pSortList->m_flX;
  1024. float y = pSortList->m_flY;
  1025. float z = pSortList->m_flZ;
  1026. // Find the sample for this frame
  1027. const SheetSequenceSample_t *pSample = &s_DefaultSheetSequence;
  1028. const SheetSequenceSample_t *pSample1 = &s_DefaultSheetSequence;
  1029. if ( info.m_pSheet )
  1030. {
  1031. float flAgeScale = info.m_flAgeScale;
  1032. float flAgeScale2 = info.m_flAgeScale2;
  1033. float flAge = pSortList->m_flAnimationTimeValue;
  1034. if ( m_bAnimateInFPS )
  1035. {
  1036. flAgeScale = flAgeScale / info.m_pParticles->m_Sheet()->m_SheetInfo[pSortList->m_nSequenceID].m_flFrameSpan;
  1037. flAgeScale2 = flAgeScale2 / info.m_pParticles->m_Sheet()->m_SheetInfo[pSortList->m_nSequenceID1].m_flFrameSpan;;
  1038. }
  1039. pSample = GetSampleForSequence(
  1040. info.m_pSheet,
  1041. flAge,
  1042. flAgeScale,
  1043. pSortList->m_nSequenceID );
  1044. pSample1 = GetSampleForSequence(
  1045. info.m_pSheet,
  1046. flAge,
  1047. flAgeScale2,
  1048. pSortList->m_nSequenceID1 );
  1049. }
  1050. const SequenceSampleTextureCoords_t *pSample0 = &(pSample->m_TextureCoordData[0]);
  1051. const SequenceSampleTextureCoords_t *pSecondTexture0 = &(pSample->m_TextureCoordData[1]);
  1052. const SequenceSampleTextureCoords_t *pSample1Frame = &(pSample1->m_TextureCoordData[0]);
  1053. // Submit 1 (instanced) or 4 (non-instanced) verts (if we're instancing, we don't produce indices either)
  1054. meshBuilder.Position3f( x, y, z );
  1055. meshBuilder.Color4ub( rc, gc, bc, ac );
  1056. meshBuilder.TexCoord4f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  1057. meshBuilder.TexCoord4f( 1, pSample0->m_fLeft_U1, pSample0->m_fTop_V1, pSample0->m_fRight_U1, pSample0->m_fBottom_V1 );
  1058. meshBuilder.TexCoord4f( 2, pSample->m_fBlendFactor, rot, rad, yaw );
  1059. // FIXME: change the vertex decl (remove texcoord3/cornerid) if instancing - need to adjust elements beyond texcoord3 down, though
  1060. if ( ! bUseInstancing )
  1061. meshBuilder.TexCoord2f( 3, 0, 0 );
  1062. meshBuilder.TexCoord4f( 4, pSecondTexture0->m_fLeft_U0, pSecondTexture0->m_fTop_V0, pSecondTexture0->m_fRight_U0, pSecondTexture0->m_fBottom_V0 );
  1063. meshBuilder.TexCoord4f( 5, pSample1Frame->m_fLeft_U0, pSample1Frame->m_fTop_V0, pSample1Frame->m_fRight_U0, pSample1Frame->m_fBottom_V0 );
  1064. meshBuilder.TexCoord4f( 6, pSample1Frame->m_fLeft_U1, pSample1Frame->m_fTop_V1, pSample1Frame->m_fRight_U1, pSample1Frame->m_fBottom_V1 );
  1065. meshBuilder.TexCoord4f( 7, pSample1->m_fBlendFactor, 0, 0, 0 );
  1066. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 8>();
  1067. if ( !bUseInstancing )
  1068. {
  1069. meshBuilder.Position3f( x, y, z );
  1070. meshBuilder.Color4ub( rc, gc, bc, ac );
  1071. meshBuilder.TexCoord4f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  1072. meshBuilder.TexCoord4f( 1, pSample0->m_fLeft_U1, pSample0->m_fTop_V1, pSample0->m_fRight_U1, pSample0->m_fBottom_V1 );
  1073. meshBuilder.TexCoord4f( 2, pSample->m_fBlendFactor, rot, rad, yaw );
  1074. meshBuilder.TexCoord2f( 3, 1, 0 );
  1075. meshBuilder.TexCoord4f( 4, pSecondTexture0->m_fLeft_U0, pSecondTexture0->m_fTop_V0, pSecondTexture0->m_fRight_U0, pSecondTexture0->m_fBottom_V0 );
  1076. meshBuilder.TexCoord4f( 5, pSample1Frame->m_fLeft_U0, pSample1Frame->m_fTop_V0, pSample1Frame->m_fRight_U0, pSample1Frame->m_fBottom_V0 );
  1077. meshBuilder.TexCoord4f( 6, pSample1Frame->m_fLeft_U1, pSample1Frame->m_fTop_V1, pSample1Frame->m_fRight_U1, pSample1Frame->m_fBottom_V1 );
  1078. meshBuilder.TexCoord4f( 7, pSample1->m_fBlendFactor, 0, 0, 0 );
  1079. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 8>();
  1080. meshBuilder.Position3f( x, y, z );
  1081. meshBuilder.Color4ub( rc, gc, bc, ac );
  1082. meshBuilder.TexCoord4f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  1083. meshBuilder.TexCoord4f( 1, pSample0->m_fLeft_U1, pSample0->m_fTop_V1, pSample0->m_fRight_U1, pSample0->m_fBottom_V1 );
  1084. meshBuilder.TexCoord4f( 2, pSample->m_fBlendFactor, rot, rad, yaw );
  1085. meshBuilder.TexCoord2f( 3, 1, 1 );
  1086. meshBuilder.TexCoord4f( 4, pSecondTexture0->m_fLeft_U0, pSecondTexture0->m_fTop_V0, pSecondTexture0->m_fRight_U0, pSecondTexture0->m_fBottom_V0 );
  1087. meshBuilder.TexCoord4f( 5, pSample1Frame->m_fLeft_U0, pSample1Frame->m_fTop_V0, pSample1Frame->m_fRight_U0, pSample1Frame->m_fBottom_V0 );
  1088. meshBuilder.TexCoord4f( 6, pSample1Frame->m_fLeft_U1, pSample1Frame->m_fTop_V1, pSample1Frame->m_fRight_U1, pSample1Frame->m_fBottom_V1 );
  1089. meshBuilder.TexCoord4f( 7, pSample1->m_fBlendFactor, 0, 0, 0 );
  1090. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 8>();
  1091. meshBuilder.Position3f( x, y, z );
  1092. meshBuilder.Color4ub( rc, gc, bc, ac );
  1093. meshBuilder.TexCoord4f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  1094. meshBuilder.TexCoord4f( 1, pSample0->m_fLeft_U1, pSample0->m_fTop_V1, pSample0->m_fRight_U1, pSample0->m_fBottom_V1 );
  1095. meshBuilder.TexCoord4f( 2, pSample->m_fBlendFactor, rot, rad, yaw );
  1096. meshBuilder.TexCoord2f( 3, 0, 1 );
  1097. meshBuilder.TexCoord4f( 4, pSecondTexture0->m_fLeft_U0, pSecondTexture0->m_fTop_V0, pSecondTexture0->m_fRight_U0, pSecondTexture0->m_fBottom_V0 );
  1098. meshBuilder.TexCoord4f( 5, pSample1Frame->m_fLeft_U0, pSample1Frame->m_fTop_V0, pSample1Frame->m_fRight_U0, pSample1Frame->m_fBottom_V0 );
  1099. meshBuilder.TexCoord4f( 6, pSample1Frame->m_fLeft_U1, pSample1Frame->m_fTop_V1, pSample1Frame->m_fRight_U1, pSample1Frame->m_fBottom_V1 );
  1100. meshBuilder.TexCoord4f( 7, pSample1->m_fBlendFactor, 0, 0, 0 );
  1101. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 8>();
  1102. meshBuilder.FastQuad( info.m_nVertexOffset );
  1103. info.m_nVertexOffset += 4;
  1104. }
  1105. }
  1106. //-----------------------------------------------------------------------------
  1107. // Purpose:
  1108. //-----------------------------------------------------------------------------
  1109. void C_OP_RenderSprites::Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, int nViewRecursionDepth ) const
  1110. {
  1111. // See if we need to cull this system
  1112. if ( ShouldCullParticleSystem( &m_cullData, pParticles, pRenderContext, nViewRecursionDepth ) )
  1113. return;
  1114. IMaterial *pMaterial = pParticles->m_pDef->GetMaterial();
  1115. C_OP_RenderSpritesContext_t *pCtx = reinterpret_cast<C_OP_RenderSpritesContext_t *>( pContext );
  1116. Vector vecOrigin = vec3_origin;
  1117. if ( pCtx->m_VisibilityData.m_bUseVisibility )
  1118. {
  1119. SetupParticleVisibility( pParticles, &pCtx->m_VisibilityData, &VisibilityInputs, &pCtx->m_nQueryHandle, pRenderContext );
  1120. }
  1121. IMaterialVar* pVar = pMaterial->FindVarFast( "$orientation", &pCtx->m_nOrientationVarToken );
  1122. if ( pVar )
  1123. {
  1124. pVar->SetIntValue( MAX( 0, MIN( m_nOrientationType, MAX_PARTICLE_ORIENTATION_TYPES ) ) );
  1125. }
  1126. pRenderContext->Bind( pMaterial );
  1127. if ( !pMaterial->IsSpriteCard() )
  1128. {
  1129. if ( !pCtx->m_bDidPerfWarning )
  1130. {
  1131. pCtx->m_bDidPerfWarning = true;
  1132. // DevWarning( "** PERF WARNING! The particle system %s is using a non-spritecard based material.\n",
  1133. // pParticles->m_pDef->GetName() );
  1134. }
  1135. switch( m_nOrientationType )
  1136. {
  1137. case 0:
  1138. if ( (! m_bFitCycleToLifetime ) )
  1139. RenderNonSpriteCardCameraFacing( pParticles, vecDiffuseModulation, pContext, pRenderContext, pMaterial );
  1140. else
  1141. RenderNonSpriteCardCameraFacingOld( pParticles, vecDiffuseModulation, pContext, pRenderContext, pMaterial );
  1142. break;
  1143. case 1:
  1144. RenderNonSpriteCardZRotating( pParticles, vecDiffuseModulation, pContext, pRenderContext, pMaterial );
  1145. break;
  1146. case 2:
  1147. RenderNonSpriteCardOriented( pParticles, vecDiffuseModulation, pContext, pRenderContext, pMaterial );
  1148. break;
  1149. }
  1150. return;
  1151. }
  1152. if ( m_nOrientationType == 2 )
  1153. {
  1154. IMaterialVar* pVar = pMaterial->FindVarFast( "$orientationMatrix", &pCtx->m_nOrientationMatrixVarToken );
  1155. if ( pVar )
  1156. {
  1157. VMatrix mat;
  1158. if ( m_nOrientationControlPoint < 0 )
  1159. {
  1160. MatrixSetIdentity( mat );
  1161. }
  1162. else
  1163. {
  1164. pParticles->GetControlPointTransformAtCurrentTime( m_nOrientationControlPoint, &mat );
  1165. }
  1166. pVar->SetMatrixValue( mat );
  1167. }
  1168. }
  1169. float flAgeScale = m_flAnimationRate * SEQUENCE_SAMPLE_COUNT;
  1170. float flAgeScale2 = m_flAnimationRate2 * SEQUENCE_SAMPLE_COUNT;
  1171. SpriteRenderInfo_t info;
  1172. info.Init( pParticles, 0, flAgeScale, flAgeScale2, pParticles->m_Sheet() );
  1173. MaterialPrimitiveType_t primType = bUseInstancing ? MATERIAL_INSTANCED_QUADS : MATERIAL_TRIANGLES;
  1174. int nMaxParticlesInBatch = GetMaxParticlesPerBatch( pRenderContext, pMaterial, bUseInstancing );
  1175. // Reset the particle cache if we're sprite card material, it isn't sorted, and it doesn't use queries
  1176. bool bShouldSort = pParticles->m_pDef->m_bShouldSort;
  1177. CCachedParticleBatches *pCachedBatches = NULL;
  1178. MaterialThreadMode_t nThreadMode = g_pMaterialSystem->GetThreadMode();
  1179. if ( nThreadMode != MATERIAL_SINGLE_THREADED && !bShouldSort && !pCtx->m_VisibilityData.m_bUseVisibility )
  1180. {
  1181. pParticles->ResetParticleCache();
  1182. pCachedBatches = pParticles->GetCachedParticleBatches();
  1183. }
  1184. int nBatchCount = 0;
  1185. if ( pCtx->m_bPerParticleGlow )
  1186. {
  1187. int nParticles;
  1188. ParticleRenderDataWithOutlineInformation_Scalar_View **pSortList = GetExtendedRenderListWithPerParticleGlow(
  1189. pParticles, pRenderContext, true, &nParticles, &pCtx->m_VisibilityData );
  1190. while ( nParticles )
  1191. {
  1192. int nParticlesInBatch = MIN( nMaxParticlesInBatch, nParticles );
  1193. nParticles -= nParticlesInBatch;
  1194. int vertexCount = bUseInstancing ? nParticlesInBatch : nParticlesInBatch * 4;
  1195. int indexCount = bUseInstancing ? 0 : nParticlesInBatch * 6;
  1196. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  1197. // See if we have a cached batch
  1198. ICachedPerFrameMeshData *pCachedBatch = pCachedBatches ? pCachedBatches->GetCachedBatch( nBatchCount ) : NULL;
  1199. if ( pCachedBatch )
  1200. {
  1201. // This copies all of the VB/IB pointers and data out of the pCachedBatch back into the pMesh
  1202. pMesh->ReconstructFromCachedPerFrameMeshData( pCachedBatch );
  1203. pSortList -= nParticlesInBatch;
  1204. }
  1205. else
  1206. {
  1207. CMeshBuilder meshBuilder;
  1208. if ( bUseInstancing )
  1209. {
  1210. meshBuilder.Begin( pMesh, primType, vertexCount );
  1211. }
  1212. else
  1213. {
  1214. meshBuilder.Begin( pMesh, primType, vertexCount, indexCount );
  1215. }
  1216. info.m_nVertexOffset = 0;
  1217. for( int i = 0; i < nParticlesInBatch; i++ )
  1218. {
  1219. ParticleRenderDataWithOutlineInformation_Scalar_View *pParticle = *(--pSortList);
  1220. RenderSpriteCardNew<true, false>( meshBuilder, info, pParticle );
  1221. }
  1222. meshBuilder.End();
  1223. // If we have a list of cached batches, cache them off so that if we try to render this sytem again for the current frame,
  1224. // we have a cached all of the vb and ib pointers.
  1225. if ( pCachedBatches )
  1226. {
  1227. pCachedBatch = pMesh->GetCachedPerFrameMeshData();
  1228. pCachedBatches->SetCachedBatch( nBatchCount, pCachedBatch );
  1229. }
  1230. }
  1231. Vector vMins, vMaxs;
  1232. pParticles->GetBounds( &vMins, &vMaxs );
  1233. VMatrix MinMaxParms( vMins.x, vMins.y, vMins.z, 0.0f,
  1234. vMaxs.x, vMaxs.y, vMaxs.z, 0.0f,
  1235. 0.0f, 0.0f, 0.0f, 0.0f,
  1236. 0.0f, 0.0f, 0.0f, 0.0f );
  1237. pRenderContext->MatrixMode( MATERIAL_MATRIX_UNUSED0 );
  1238. pRenderContext->LoadMatrix( MinMaxParms );
  1239. nBatchCount++;
  1240. pMesh->DrawModulated( vecDiffuseModulation );
  1241. }
  1242. }
  1243. else
  1244. {
  1245. int nParticles;
  1246. ParticleFullRenderData_Scalar_View **pSortList = NULL;
  1247. ParticleRenderDataWithNormal_Scalar_View **pSortListWithNormal = NULL;
  1248. if ( m_nOrientationType == 3 )
  1249. {
  1250. pSortListWithNormal = GetExtendedRenderListWithNormals(
  1251. pParticles, pRenderContext, true, &nParticles, &pCtx->m_VisibilityData );
  1252. }
  1253. else
  1254. {
  1255. pSortList = GetExtendedRenderList(
  1256. pParticles, pRenderContext, true, &nParticles, &pCtx->m_VisibilityData );
  1257. }
  1258. while ( nParticles )
  1259. {
  1260. int nParticlesInBatch = MIN( nMaxParticlesInBatch, nParticles );
  1261. nParticles -= nParticlesInBatch;
  1262. int vertexCount = bUseInstancing ? nParticlesInBatch : nParticlesInBatch * 4;
  1263. int indexCount = bUseInstancing ? 0 : nParticlesInBatch * 6;
  1264. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  1265. Vector vMins, vMaxs;
  1266. pParticles->GetBounds( &vMins, &vMaxs );
  1267. // See if we have a cached batch
  1268. ICachedPerFrameMeshData *pCachedBatch = pCachedBatches ? pCachedBatches->GetCachedBatch( nBatchCount ) : NULL;
  1269. if ( pCachedBatch )
  1270. {
  1271. // This copies all of the VB/IB pointers and data out of the pCachedBatch back into the pMesh
  1272. pMesh->ReconstructFromCachedPerFrameMeshData( pCachedBatch );
  1273. pSortList -= nParticlesInBatch;
  1274. }
  1275. else
  1276. {
  1277. CMeshBuilder meshBuilder;
  1278. if ( bUseInstancing )
  1279. {
  1280. meshBuilder.Begin( pMesh, primType, vertexCount );
  1281. }
  1282. else
  1283. {
  1284. meshBuilder.Begin( pMesh, primType, vertexCount, indexCount );
  1285. }
  1286. info.m_nVertexOffset = 0;
  1287. if ( pSortListWithNormal ) // align to particle normal
  1288. {
  1289. for( int i = 0; i < nParticlesInBatch; i++ )
  1290. {
  1291. ParticleRenderDataWithNormal_Scalar_View *pParticle = *( --pSortListWithNormal );
  1292. RenderSpriteCardNew<false, true>( meshBuilder, info, pParticle );
  1293. }
  1294. }
  1295. else
  1296. {
  1297. if ( meshBuilder.TextureCoordinateSize( 5 ) ) // second sequence? per particle outline?
  1298. {
  1299. for( int i = 0; i < nParticlesInBatch; i++ )
  1300. {
  1301. ParticleFullRenderData_Scalar_View *pParticle = *(--pSortList);
  1302. RenderTwoSequenceSpriteCardNew( meshBuilder, info, pParticle );
  1303. }
  1304. }
  1305. else
  1306. {
  1307. for( int i = 0; i < nParticlesInBatch; i++ )
  1308. {
  1309. ParticleFullRenderData_Scalar_View *pParticle = *(--pSortList);
  1310. RenderSpriteCardNew<false, false>( meshBuilder, info, pParticle );
  1311. }
  1312. }
  1313. }
  1314. meshBuilder.End();
  1315. // If we have a list of cached batches, cache them off so that if we try to render this sytem again for the current frame,
  1316. // we have a cached all of the vb and ib pointers.
  1317. if ( pCachedBatches )
  1318. {
  1319. pCachedBatch = pMesh->GetCachedPerFrameMeshData();
  1320. pCachedBatches->SetCachedBatch( nBatchCount, pCachedBatch );
  1321. }
  1322. }
  1323. VMatrix MinMaxParms( vMins.x, vMins.y, vMins.z, 0.0f,
  1324. vMaxs.x, vMaxs.y, vMaxs.z, 0.0f,
  1325. 0.0f, 0.0f, 0.0f, 0.0f,
  1326. 0.0f, 0.0f, 0.0f, 0.0f );
  1327. pRenderContext->MatrixMode( MATERIAL_MATRIX_UNUSED0 );
  1328. pRenderContext->LoadMatrix( MinMaxParms );
  1329. nBatchCount++;
  1330. pMesh->DrawModulated( vecDiffuseModulation );
  1331. }
  1332. }
  1333. }
  1334. void C_OP_RenderSprites::RenderUnsorted( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const
  1335. {
  1336. if ( !pParticles->m_pDef->GetMaterial()->IsSpriteCard() )
  1337. {
  1338. switch( m_nOrientationType )
  1339. {
  1340. case 0:
  1341. // FIXME: Implement! Requires removing MATERIAL_VIEW modification from sorted version
  1342. Warning( "C_OP_RenderSprites::RenderUnsorted: Attempting to use an unimplemented sprite renderer for system \"%s\"!\n",
  1343. pParticles->m_pDef->GetName() );
  1344. // RenderUnsortedNonSpriteCardCameraFacing( pParticles, pContext, pRenderContext, meshBuilder, nVertexOffset, nFirstParticle, nParticleCount );
  1345. break;
  1346. case 1:
  1347. RenderUnsortedNonSpriteCardZRotating( pParticles, pContext, pRenderContext, meshBuilder, nVertexOffset, nFirstParticle, nParticleCount );
  1348. break;
  1349. case 2:
  1350. RenderUnsortedNonSpriteCardOriented( pParticles, pContext, pRenderContext, meshBuilder, nVertexOffset, nFirstParticle, nParticleCount );
  1351. break;
  1352. }
  1353. return;
  1354. }
  1355. C_OP_RenderSpritesContext_t *pCtx = reinterpret_cast<C_OP_RenderSpritesContext_t *>( pContext );
  1356. float flAgeScale = m_flAnimationRate * SEQUENCE_SAMPLE_COUNT;
  1357. float flAgeScale2 = m_flAnimationRate2 * SEQUENCE_SAMPLE_COUNT;
  1358. SpriteRenderInfo_t info;
  1359. info.Init( pParticles, 0, flAgeScale, flAgeScale2, pParticles->m_Sheet() );
  1360. int hParticle = nFirstParticle;
  1361. int nParticles;
  1362. const ParticleRenderData_t *pSortList = pParticles->GetRenderList( pRenderContext, false, &nParticles, &pCtx->m_VisibilityData );
  1363. for( int i = 0; i < nParticleCount; i++, hParticle++ )
  1364. {
  1365. RenderSpriteCard( meshBuilder, info, hParticle, pSortList );
  1366. }
  1367. }
  1368. //
  1369. //
  1370. //
  1371. //
  1372. struct SpriteTrailRenderInfo_t : public SpriteRenderInfo_t
  1373. {
  1374. size_t m_nPrevXYZStride;
  1375. const fltx4 *m_pPrevXYZ;
  1376. size_t length_stride;
  1377. const fltx4 *m_pLength;
  1378. const fltx4 *m_pCreationTime;
  1379. size_t m_nCreationTimeStride;
  1380. void Init( CParticleCollection *pParticles, int nVertexOffset, float flAgeScale, CSheet *pSheet )
  1381. {
  1382. SpriteRenderInfo_t::Init( pParticles, nVertexOffset, flAgeScale, 0, pSheet );
  1383. m_pParticles = pParticles;
  1384. m_pPrevXYZ = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_PREV_XYZ, &m_nPrevXYZStride );
  1385. m_pLength = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_TRAIL_LENGTH, &length_stride );
  1386. m_pCreationTime = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, &m_nCreationTimeStride );
  1387. }
  1388. };
  1389. struct FastSpriteTrailVertex_t
  1390. {
  1391. Vector m_vPos;
  1392. int m_nColor;
  1393. Vector4D m_vTexcoord[ 6 ];
  1394. };
  1395. class C_OP_RenderSpritesTrail : public CParticleRenderOperatorInstance
  1396. {
  1397. DECLARE_PARTICLE_OPERATOR( C_OP_RenderSpritesTrail );
  1398. struct C_OP_RenderSpriteTrailContext_t
  1399. {
  1400. CParticleVisibilityData m_VisibilityData;
  1401. int m_nQueryHandle;
  1402. };
  1403. virtual uint64 GetReadControlPointMask() const
  1404. {
  1405. uint64 nMask = 0;
  1406. if ( VisibilityInputs.m_nCPin >= 0 )
  1407. nMask |= 1ULL << VisibilityInputs.m_nCPin;
  1408. return nMask;
  1409. }
  1410. size_t GetRequiredContextBytes( void ) const
  1411. {
  1412. return sizeof( C_OP_RenderSpriteTrailContext_t );
  1413. }
  1414. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  1415. {
  1416. C_OP_RenderSpriteTrailContext_t *pCtx = reinterpret_cast<C_OP_RenderSpriteTrailContext_t *>( pContext );
  1417. if ( ( VisibilityInputs.m_nCPin >= 0 ) || ( VisibilityInputs.m_flRadiusScaleFOVBase > 0 ) )
  1418. pCtx->m_VisibilityData.m_bUseVisibility = true;
  1419. else
  1420. pCtx->m_VisibilityData.m_bUseVisibility = false;
  1421. }
  1422. uint32 GetWrittenAttributes( void ) const
  1423. {
  1424. return 0;
  1425. }
  1426. void InitParams( CParticleSystemDefinition *pDef )
  1427. {
  1428. pDef->SetMaxTailLength( m_flMaxLength );
  1429. }
  1430. uint32 GetReadAttributes( void ) const
  1431. {
  1432. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_RADIUS_MASK |
  1433. PARTICLE_ATTRIBUTE_TINT_RGB_MASK | PARTICLE_ATTRIBUTE_ALPHA_MASK | PARTICLE_ATTRIBUTE_CREATION_TIME_MASK |
  1434. PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER_MASK | PARTICLE_ATTRIBUTE_TRAIL_LENGTH_MASK;
  1435. }
  1436. virtual int GetParticlesToRender( CParticleCollection *pParticles, void *pContext, int nFirstParticle, int nRemainingVertices, int nRemainingIndices, int *pVertsUsed, int *pIndicesUsed ) const ;
  1437. virtual void Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, int nViewRecursionDepth ) const;
  1438. virtual void RenderUnsorted( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const;
  1439. bool RenderSpriteTrail( CMeshBuilder &meshBuilder,
  1440. int nCurrentVertex, int nCurrentIndex,
  1441. SpriteTrailRenderInfo_t& info, int hParticle,
  1442. const Vector &vecCameraPos, float flOODt, ParticleRenderData_t const *pSortList ) const;
  1443. template <bool bFastPath>
  1444. bool RenderSpriteTrailSpriteCard( CMeshBuilder &meshBuilder, int nCurrentVertex, // Slow method params
  1445. FastSpriteTrailVertex_t *RESTRICT pVertices, uint32 *RESTRICT pIndices, int nIndexOffset, // Fast method params
  1446. SpriteTrailRenderInfo_t& info, int hParticle,
  1447. float flOODt, ParticleRenderData_t const *pSortlist ) const;
  1448. Vector4D m_FadeColor;
  1449. float m_flAnimationRate;
  1450. float m_flLengthFadeInTime;
  1451. float m_flMaxLength;
  1452. float m_flMinLength;
  1453. bool m_bConstrainRadius;
  1454. bool m_bIgnoreDT;
  1455. CullSystemByControlPointData_t m_cullData;
  1456. };
  1457. DEFINE_PARTICLE_OPERATOR( C_OP_RenderSpritesTrail, "render_sprite_trail", OPERATOR_SINGLETON );
  1458. BEGIN_PARTICLE_RENDER_OPERATOR_UNPACK( C_OP_RenderSpritesTrail )
  1459. DMXELEMENT_UNPACK_FIELD( "animation rate", ".1", float, m_flAnimationRate )
  1460. DMXELEMENT_UNPACK_FIELD( "length fade in time", "0", float, m_flLengthFadeInTime )
  1461. DMXELEMENT_UNPACK_FIELD( "max length", "2000", float, m_flMaxLength )
  1462. DMXELEMENT_UNPACK_FIELD( "min length", "0", float, m_flMinLength )
  1463. DMXELEMENT_UNPACK_FIELD( "constrain radius to length", "1", bool, m_bConstrainRadius )
  1464. DMXELEMENT_UNPACK_FIELD( "ignore delta time", "0", bool, m_bIgnoreDT )
  1465. DMXELEMENT_UNPACK_FIELD( "tail color and alpha scale factor", "1 1 1 1", Vector4D, m_FadeColor )
  1466. DMXELEMENT_UNPACK_FIELD( CULL_CP_NORMAL_DESCRIPTOR, "-1", int, m_cullData.m_nCullControlPoint )
  1467. DMXELEMENT_UNPACK_FIELD( CULL_RECURSION_DEPTH_DESCRIPTOR, "-1", int, m_cullData.m_nViewRecursionDepthStart )
  1468. END_PARTICLE_OPERATOR_UNPACK( C_OP_RenderSpritesTrail )
  1469. int C_OP_RenderSpritesTrail::GetParticlesToRender( CParticleCollection *pParticles,
  1470. void *pContext, int nFirstParticle, int nRemainingVertices,
  1471. int nRemainingIndices,
  1472. int *pVertsUsed, int *pIndicesUsed ) const
  1473. {
  1474. int nMaxParticles = ( (nRemainingVertices / 4) > (nRemainingIndices / 6) ) ? nRemainingIndices / 6 : nRemainingVertices / 4;
  1475. int nParticleCount = pParticles->m_nActiveParticles - nFirstParticle;
  1476. if ( nParticleCount > nMaxParticles )
  1477. {
  1478. nParticleCount = nMaxParticles;
  1479. }
  1480. *pVertsUsed = nParticleCount * 4;
  1481. *pIndicesUsed = nParticleCount * 6;
  1482. return nParticleCount;
  1483. }
  1484. template <bool bFastPath>
  1485. bool C_OP_RenderSpritesTrail::RenderSpriteTrailSpriteCard( CMeshBuilder &meshBuilder, int nCurrentVertex, // Slow method params
  1486. FastSpriteTrailVertex_t *RESTRICT pVertices, uint32 *RESTRICT pIndices, int nIndexOffset, // Fast method params
  1487. // Common params
  1488. SpriteTrailRenderInfo_t& info, int hParticle,
  1489. float flOODt, ParticleRenderData_t const *pSortList ) const
  1490. {
  1491. // Setup our alpha
  1492. unsigned char ac = pSortList->m_nAlpha;
  1493. if ( ac == 0 )
  1494. return false;
  1495. Assert( hParticle != -1 );
  1496. int nGroup = hParticle / 4;
  1497. int nOffset = hParticle & 0x3;
  1498. // Setup our colors
  1499. unsigned char rc = 255;
  1500. unsigned char gc = 255;
  1501. unsigned char bc = 255;
  1502. int nColorIndex = nGroup * info.m_nRGBStride;
  1503. float a = pSortList->m_nAlpha / 255.0f;
  1504. float r = SubFloat( info.m_pRGB[nColorIndex], nOffset );
  1505. float g = SubFloat( info.m_pRGB[nColorIndex+1], nOffset );
  1506. float b = SubFloat( info.m_pRGB[nColorIndex+2], nOffset );
  1507. Assert( IsFinite(r) && IsFinite(g) && IsFinite(b) );
  1508. Assert( (r >= -FLT_EPSILON) && (g >= -FLT_EPSILON) && (b >= -FLT_EPSILON) );
  1509. Assert( (r <= 1.0f + FLT_EPSILON) && (g <= 1.0f + FLT_EPSILON) && (b <= 1.0f + FLT_EPSILON) );
  1510. rc = FastFToC( r );
  1511. gc = FastFToC( g );
  1512. bc = FastFToC( b );
  1513. // Setup the scale and rotation
  1514. float rad = pSortList->m_flRadius;
  1515. // Find the sample for this frame
  1516. const SheetSequenceSample_t *pSample = &s_DefaultSheetSequence;
  1517. if ( info.m_pSheet )
  1518. {
  1519. pSample = GetSampleForSequence(
  1520. info.m_pSheet,
  1521. info.m_pParticles->m_flCurTime - SubFloat( info.m_pCreationTimeStamp[ nGroup * info.m_nCreationTimeStride ], nOffset ),
  1522. info.m_flAgeScale,
  1523. SubFloat( info.m_pSequenceNumber[ nGroup * info.m_nSequenceStride ], nOffset ) );
  1524. }
  1525. const SequenceSampleTextureCoords_t *pSample0 = &(pSample->m_TextureCoordData[0]);
  1526. int nCreationTimeIndex = nGroup * info.m_nCreationTimeStride;
  1527. float flAge = info.m_pParticles->m_flCurTime - SubFloat( info.m_pCreationTimeStamp[ nCreationTimeIndex ], nOffset );
  1528. float flLengthScale = MIN( 1.0, ( flAge / m_flLengthFadeInTime ) );
  1529. int nXYZIndex = nGroup * info.m_nXYZStride;
  1530. Vector vecWorldPos( SubFloat( info.m_pXYZ[ nXYZIndex ], nOffset ), SubFloat( info.m_pXYZ[ nXYZIndex+1 ], nOffset ), SubFloat( info.m_pXYZ[ nXYZIndex+2 ], nOffset ) );
  1531. Vector vecViewPos = vecWorldPos;
  1532. // Get our screenspace last position
  1533. int nPrevXYZIndex = nGroup * info.m_nPrevXYZStride;
  1534. Vector vecPrevWorldPos( SubFloat( info.m_pPrevXYZ[ nPrevXYZIndex ], nOffset ), SubFloat( info.m_pPrevXYZ[ nPrevXYZIndex+1 ], nOffset ), SubFloat( info.m_pPrevXYZ[ nPrevXYZIndex+2 ], nOffset ) );
  1535. Vector vecPrevViewPos = vecPrevWorldPos;
  1536. // Get the delta direction and find the magnitude, then scale the length by the desired length amount
  1537. Vector vecDelta;
  1538. VectorSubtract( vecPrevViewPos, vecViewPos, vecDelta );
  1539. float flMagSquared = vecDelta.LengthSqr();
  1540. float flInvMag = ( flMagSquared == 0.0f ) ? 0 : FastRSqrtFast( flMagSquared );
  1541. float flMag = flInvMag * flMagSquared;
  1542. vecDelta.x *= flInvMag;
  1543. vecDelta.y *= flInvMag;
  1544. vecDelta.z *= flInvMag;
  1545. float flLength = flLengthScale * flMag * flOODt * SubFloat( info.m_pLength[ nGroup * info.length_stride ], nOffset );
  1546. if ( flLength <= 0.0f )
  1547. return false;
  1548. flLength = MAX( m_flMinLength, MIN( m_flMaxLength, flLength ) );
  1549. vecDelta *= flLength;
  1550. // Fade the width as the length fades to keep it at a square aspect ratio
  1551. if ( m_bConstrainRadius )
  1552. {
  1553. rad = MIN( rad, flLength );
  1554. }
  1555. Vector p0 = vecWorldPos - vecDelta;
  1556. Vector p1 = vecWorldPos;
  1557. Vector p2 = vecWorldPos + vecDelta;
  1558. Vector p3 = vecWorldPos + 2 * vecDelta;
  1559. Vector4D vFadeColor = ( Vector4D( r, g, b, a ) * m_FadeColor );
  1560. int nColor = PackRGBToPlatformColor( rc, gc, bc, ac );
  1561. Vector4D vTextureRange( pSample0->m_fLeft_U0, pSample0->m_fTop_V0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  1562. if ( bFastPath )
  1563. {
  1564. // Vert0
  1565. pVertices->m_vPos.Init( 0, 1, 0 );
  1566. pVertices->m_nColor = nColor;
  1567. pVertices->m_vTexcoord[ 0 ].Init( p0.x, p0.y, p0.z, rad );
  1568. pVertices->m_vTexcoord[ 1 ].Init( p1.x, p1.y, p1.z, rad );
  1569. pVertices->m_vTexcoord[ 2 ].Init( p2.x, p2.y, p2.z, rad );
  1570. pVertices->m_vTexcoord[ 3 ].Init( p3.x, p3.y, p3.z, rad );
  1571. pVertices->m_vTexcoord[ 4 ] = vTextureRange;
  1572. pVertices->m_vTexcoord[ 5 ] = vFadeColor;
  1573. pVertices++;
  1574. // Vert1
  1575. pVertices->m_vPos.Init( 0, 1, 1 );
  1576. pVertices->m_nColor = nColor;
  1577. pVertices->m_vTexcoord[ 0 ].Init( p0.x, p0.y, p0.z, rad );
  1578. pVertices->m_vTexcoord[ 1 ].Init( p1.x, p1.y, p1.z, rad );
  1579. pVertices->m_vTexcoord[ 2 ].Init( p2.x, p2.y, p2.z, rad );
  1580. pVertices->m_vTexcoord[ 3 ].Init( p3.x, p3.y, p3.z, rad );
  1581. pVertices->m_vTexcoord[ 4 ] = vTextureRange;
  1582. pVertices->m_vTexcoord[ 5 ] = vFadeColor;
  1583. pVertices++;
  1584. // Vert2
  1585. pVertices->m_vPos.Init( 1, 0, 1 );
  1586. pVertices->m_nColor = nColor;
  1587. pVertices->m_vTexcoord[ 0 ].Init( p0.x, p0.y, p0.z, rad );
  1588. pVertices->m_vTexcoord[ 1 ].Init( p1.x, p1.y, p1.z, rad );
  1589. pVertices->m_vTexcoord[ 2 ].Init( p2.x, p2.y, p2.z, rad );
  1590. pVertices->m_vTexcoord[ 3 ].Init( p3.x, p3.y, p3.z, rad );
  1591. pVertices->m_vTexcoord[ 4 ] = vTextureRange;
  1592. pVertices->m_vTexcoord[ 5 ] = vFadeColor;
  1593. pVertices++;
  1594. // Vert3
  1595. pVertices->m_vPos.Init( 1, 0, 0 );
  1596. pVertices->m_nColor = nColor;
  1597. pVertices->m_vTexcoord[ 0 ].Init( p0.x, p0.y, p0.z, rad );
  1598. pVertices->m_vTexcoord[ 1 ].Init( p1.x, p1.y, p1.z, rad );
  1599. pVertices->m_vTexcoord[ 2 ].Init( p2.x, p2.y, p2.z, rad );
  1600. pVertices->m_vTexcoord[ 3 ].Init( p3.x, p3.y, p3.z, rad );
  1601. pVertices->m_vTexcoord[ 4 ] = vTextureRange;
  1602. pVertices->m_vTexcoord[ 5 ] = vFadeColor;
  1603. }
  1604. else
  1605. {
  1606. // Vert0
  1607. meshBuilder.Position3f( nCurrentVertex, 0.0f, 1.0f, 0.0f );
  1608. meshBuilder.Color4ub( nCurrentVertex, rc, gc, bc, ac );
  1609. meshBuilder.TexCoord4f( nCurrentVertex, 0, p0.x, p0.y, p0.z, rad );
  1610. meshBuilder.TexCoord4f( nCurrentVertex, 1, p1.x, p1.y, p1.z, rad );
  1611. meshBuilder.TexCoord4f( nCurrentVertex, 2, p2.x, p2.y, p2.z, rad );
  1612. meshBuilder.TexCoord4f( nCurrentVertex, 3, p3.x, p3.y, p3.z, rad );
  1613. meshBuilder.TexCoord4f( nCurrentVertex, 4, pSample0->m_fLeft_U0, pSample0->m_fTop_V0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  1614. meshBuilder.TexCoord4fv( nCurrentVertex, 5, vFadeColor.Base() );
  1615. // Vert1
  1616. meshBuilder.Position3f( nCurrentVertex + 1, 0.0f, 1.0f, 1.0f );
  1617. meshBuilder.Color4ub( nCurrentVertex + 1, rc, gc, bc, ac );
  1618. meshBuilder.TexCoord4f( nCurrentVertex + 1, 0, p0.x, p0.y, p0.z, rad );
  1619. meshBuilder.TexCoord4f( nCurrentVertex + 1, 1, p1.x, p1.y, p1.z, rad );
  1620. meshBuilder.TexCoord4f( nCurrentVertex + 1, 2, p2.x, p2.y, p2.z, rad );
  1621. meshBuilder.TexCoord4f( nCurrentVertex + 1, 3, p3.x, p3.y, p3.z, rad );
  1622. meshBuilder.TexCoord4f( nCurrentVertex + 1, 4, pSample0->m_fLeft_U0, pSample0->m_fTop_V0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  1623. meshBuilder.TexCoord4fv( nCurrentVertex + 1, 5, vFadeColor.Base() );
  1624. // Vert2
  1625. meshBuilder.Position3f( nCurrentVertex + 2, 1.0f, 0.0f, 1.0f );
  1626. meshBuilder.Color4ub( nCurrentVertex + 2, rc, gc, bc, ac );
  1627. meshBuilder.TexCoord4f( nCurrentVertex + 2, 0, p0.x, p0.y, p0.z, rad );
  1628. meshBuilder.TexCoord4f( nCurrentVertex + 2, 1, p1.x, p1.y, p1.z, rad );
  1629. meshBuilder.TexCoord4f( nCurrentVertex + 2, 2, p2.x, p2.y, p2.z, rad );
  1630. meshBuilder.TexCoord4f( nCurrentVertex + 2, 3, p3.x, p3.y, p3.z, rad );
  1631. meshBuilder.TexCoord4f( nCurrentVertex + 2, 4, pSample0->m_fLeft_U0, pSample0->m_fTop_V0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  1632. meshBuilder.TexCoord4fv( nCurrentVertex + 2, 5, vFadeColor.Base() );
  1633. // Vert3
  1634. meshBuilder.Position3f( nCurrentVertex + 3, 1.0f, 0.0f, 0.0f );
  1635. meshBuilder.Color4ub( nCurrentVertex + 3, rc, gc, bc, ac );
  1636. meshBuilder.TexCoord4f( nCurrentVertex + 3, 0, p0.x, p0.y, p0.z, rad );
  1637. meshBuilder.TexCoord4f( nCurrentVertex + 3, 1, p1.x, p1.y, p1.z, rad );
  1638. meshBuilder.TexCoord4f( nCurrentVertex + 3, 2, p2.x, p2.y, p2.z, rad );
  1639. meshBuilder.TexCoord4f( nCurrentVertex + 3, 3, p3.x, p3.y, p3.z, rad );
  1640. meshBuilder.TexCoord4f( nCurrentVertex + 3, 4, pSample0->m_fLeft_U0, pSample0->m_fTop_V0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  1641. meshBuilder.TexCoord4fv( nCurrentVertex + 3, 5, vFadeColor.Base() );
  1642. }
  1643. // Quad
  1644. unsigned short nIndex = info.m_nVertexOffset + nIndexOffset;
  1645. pIndices[ 0 ] = TwoIndices( nIndex, nIndex + 1 );
  1646. pIndices[ 1 ] = TwoIndices( nIndex + 2, nIndex );
  1647. pIndices[ 2 ] = TwoIndices( nIndex + 2, nIndex + 3 );
  1648. info.m_nVertexOffset += 4;
  1649. return true;
  1650. }
  1651. bool C_OP_RenderSpritesTrail::RenderSpriteTrail( CMeshBuilder &meshBuilder,
  1652. int nCurrentVertex, int nCurrentIndex,
  1653. SpriteTrailRenderInfo_t& info, int hParticle,
  1654. const Vector &vecCameraPos, float flOODt, ParticleRenderData_t const *pSortList ) const
  1655. {
  1656. Assert( hParticle != -1 );
  1657. // Setup our alpha
  1658. unsigned char ac = pSortList->m_nAlpha;
  1659. if ( ac == 0 )
  1660. return false;
  1661. int nGroup = hParticle / 4;
  1662. int nOffset = hParticle & 0x3;
  1663. // Setup our colors
  1664. int nColorIndex = nGroup * info.m_nRGBStride;
  1665. float r = SubFloat( info.m_pRGB[nColorIndex], nOffset );
  1666. float g = SubFloat( info.m_pRGB[nColorIndex+1], nOffset );
  1667. float b = SubFloat( info.m_pRGB[nColorIndex+2], nOffset );
  1668. Assert( IsFinite(r) && IsFinite(g) && IsFinite(b) );
  1669. Assert( (r >= 0.0f) && (g >= 0.0f) && (b >= 0.0f) );
  1670. Assert( (r <= 1.0f) && (g <= 1.0f) && (b <= 1.0f) );
  1671. unsigned char rc = FastFToC( r );
  1672. unsigned char gc = FastFToC( g );
  1673. unsigned char bc = FastFToC( b );
  1674. // Setup the scale and rotation
  1675. float rad = pSortList->m_flRadius;
  1676. // Find the sample for this frame
  1677. const SheetSequenceSample_t *pSample = &s_DefaultSheetSequence;
  1678. if ( info.m_pSheet )
  1679. {
  1680. pSample = GetSampleForSequence(
  1681. info.m_pSheet,
  1682. info.m_pParticles->m_flCurTime - SubFloat( info.m_pCreationTimeStamp[ nGroup * info.m_nCreationTimeStride ], nOffset ),
  1683. info.m_flAgeScale,
  1684. SubFloat( info.m_pSequenceNumber[ nGroup * info.m_nSequenceStride ], nOffset ) );
  1685. }
  1686. const SequenceSampleTextureCoords_t *pSample0 = &(pSample->m_TextureCoordData[0]);
  1687. int nCreationTimeIndex = nGroup * info.m_nCreationTimeStride;
  1688. float flAge = info.m_pParticles->m_flCurTime - SubFloat( info.m_pCreationTimeStamp[ nCreationTimeIndex ], nOffset );
  1689. float flLengthScale = ( flAge >= m_flLengthFadeInTime ) ? 1.0 : ( flAge / m_flLengthFadeInTime );
  1690. int nXYZIndex = nGroup * info.m_nXYZStride;
  1691. Vector vecWorldPos( SubFloat( info.m_pXYZ[ nXYZIndex ], nOffset ), SubFloat( info.m_pXYZ[ nXYZIndex+1 ], nOffset ), SubFloat( info.m_pXYZ[ nXYZIndex+2 ], nOffset ) );
  1692. Vector vecViewPos = vecWorldPos;
  1693. // Get our screenspace last position
  1694. int nPrevXYZIndex = nGroup * info.m_nPrevXYZStride;
  1695. Vector vecPrevWorldPos( SubFloat( info.m_pPrevXYZ[ nPrevXYZIndex ], nOffset ), SubFloat( info.m_pPrevXYZ[ nPrevXYZIndex+1 ], nOffset ), SubFloat( info.m_pPrevXYZ[ nPrevXYZIndex+2 ], nOffset ) );
  1696. Vector vecPrevViewPos = vecPrevWorldPos;
  1697. // Get the delta direction and find the magnitude, then scale the length by the desired length amount
  1698. Vector vecDelta;
  1699. // Explicitely sub and find length here, since calling VectorSubtract/VectorNormalize causes
  1700. // the results to be stored in memory.
  1701. vecDelta.x = vecPrevViewPos.x - vecViewPos.x;
  1702. vecDelta.y = vecPrevViewPos.y - vecViewPos.y;
  1703. vecDelta.z = vecPrevViewPos.z - vecViewPos.z;
  1704. float flMag = sqrtf( vecDelta.x * vecDelta.x + vecDelta.y * vecDelta.y + vecDelta.z * vecDelta.z );
  1705. float flInvMag = 1.0f / flMag;
  1706. vecDelta.x *= flInvMag;
  1707. vecDelta.y *= flInvMag;
  1708. vecDelta.z *= flInvMag;
  1709. float flLength = flLengthScale * flMag * flOODt * SubFloat( info.m_pLength[ nGroup * info.length_stride ], nOffset );
  1710. if ( flLength <= 0.0f )
  1711. return false;
  1712. flLength = MAX( m_flMinLength, MIN( m_flMaxLength, flLength ) );
  1713. vecDelta *= flLength;
  1714. // Fade the width as the length fades to keep it at a square aspect ratio
  1715. if ( ( flLength < rad ) && ( m_bConstrainRadius ) )
  1716. {
  1717. rad = flLength;
  1718. }
  1719. // Find our tangent direction which "fattens" the line
  1720. Vector vDirToBeam, vTangentY;
  1721. VectorSubtract( vecWorldPos, vecCameraPos, vDirToBeam );
  1722. CrossProduct( vDirToBeam, vecDelta, vTangentY );
  1723. // VectorNormalizeFast stores in sse registers, does math, and then writes out... causing LHS on the consoles
  1724. flMag = sqrtf( vTangentY.x * vTangentY.x + vTangentY.y * vTangentY.y + vTangentY.z * vTangentY.z );
  1725. flInvMag = 1.0f / flMag;
  1726. vTangentY.x *= flInvMag;
  1727. vTangentY.y *= flInvMag;
  1728. vTangentY.z *= flInvMag;
  1729. // Calculate the verts we'll use as our points
  1730. Vector verts[4];
  1731. VectorMA( vecWorldPos, rad*0.5f, vTangentY, verts[0] );
  1732. VectorMA( vecWorldPos, -rad*0.5f, vTangentY, verts[1] );
  1733. VectorAdd( verts[0], vecDelta, verts[3] );
  1734. VectorAdd( verts[1], vecDelta, verts[2] );
  1735. Assert( verts[0].IsValid() && verts[1].IsValid() && verts[2].IsValid() && verts[3].IsValid() );
  1736. meshBuilder.Position3fv( nCurrentVertex, verts[0].Base() );
  1737. meshBuilder.Color4ub( nCurrentVertex, rc, gc, bc, ac );
  1738. meshBuilder.TexCoord2f( nCurrentVertex, 0, pSample0->m_fLeft_U0, pSample0->m_fBottom_V0 );
  1739. meshBuilder.Position3fv( nCurrentVertex + 1, verts[1].Base() );
  1740. meshBuilder.Color4ub( nCurrentVertex + 1, rc, gc, bc, ac );
  1741. meshBuilder.TexCoord2f( nCurrentVertex + 1, 0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  1742. meshBuilder.Position3fv( nCurrentVertex + 2, verts[2].Base() );
  1743. meshBuilder.Color4ub( nCurrentVertex + 2, rc, gc, bc, ac );
  1744. meshBuilder.TexCoord2f( nCurrentVertex + 2, 0, pSample0->m_fRight_U0, pSample0->m_fTop_V0 );
  1745. meshBuilder.Position3fv( nCurrentVertex + 3, verts[3].Base() );
  1746. meshBuilder.Color4ub( nCurrentVertex + 3, rc, gc, bc, ac );
  1747. meshBuilder.TexCoord2f( nCurrentVertex + 3, 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0 );
  1748. meshBuilder.FastQuad( nCurrentIndex, info.m_nVertexOffset );
  1749. info.m_nVertexOffset += 4;
  1750. return true;
  1751. }
  1752. void C_OP_RenderSpritesTrail::Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, int nViewRecursionDepth ) const
  1753. {
  1754. // See if we need to cull this system
  1755. if ( ShouldCullParticleSystem( &m_cullData, pParticles, pRenderContext, nViewRecursionDepth ) )
  1756. return;
  1757. C_OP_RenderSpriteTrailContext_t *pCtx = reinterpret_cast<C_OP_RenderSpriteTrailContext_t *>( pContext );
  1758. IMaterial *pMaterial = pParticles->m_pDef->GetMaterial();
  1759. if ( pCtx->m_VisibilityData.m_bUseVisibility )
  1760. {
  1761. SetupParticleVisibility( pParticles, &pCtx->m_VisibilityData, &VisibilityInputs, &pCtx->m_nQueryHandle, pRenderContext );
  1762. }
  1763. // Reset the particle cache if we're sprite card material, not sorted, and don't need visibility
  1764. bool bSpriteCard = pMaterial->IsSpriteCard();
  1765. bool bShouldSort = pParticles->m_pDef->m_bShouldSort;
  1766. CCachedParticleBatches *pCachedBatches = NULL;
  1767. MaterialThreadMode_t nThreadMode = g_pMaterialSystem->GetThreadMode();
  1768. if ( nThreadMode != MATERIAL_SINGLE_THREADED && bSpriteCard && !bShouldSort && !pCtx->m_VisibilityData.m_bUseVisibility )
  1769. {
  1770. pParticles->ResetParticleCache();
  1771. pCachedBatches = pParticles->GetCachedParticleBatches();
  1772. }
  1773. // Store matrices off so we can restore them in RenderEnd().
  1774. pRenderContext->Bind( pMaterial );
  1775. float flAgeScale = m_flAnimationRate * SEQUENCE_SAMPLE_COUNT;
  1776. // Get the camera's worldspace position
  1777. Vector vecCameraPos;
  1778. pRenderContext->GetWorldSpaceCameraPosition( &vecCameraPos );
  1779. SpriteTrailRenderInfo_t info;
  1780. info.Init( pParticles, 0, flAgeScale, pParticles->m_Sheet() );
  1781. int nSkipAheadParticles = 0;
  1782. int nParticles = 0;
  1783. const ParticleRenderData_t *pSortList = NULL;
  1784. // Only grab the render list if we're not cached, since this can be costly for large systems. Make sure that if we run out of cached batches below
  1785. // that we re-grab the render list and continue with the slow path
  1786. if ( !pCachedBatches || !pCachedBatches->GetCachedBatch( 0 ) )
  1787. {
  1788. pSortList = pParticles->GetRenderList( pRenderContext, true, &nParticles, &pCtx->m_VisibilityData );
  1789. if ( pCachedBatches )
  1790. {
  1791. pCachedBatches->SetCachedRenderListCount( nParticles );
  1792. }
  1793. }
  1794. else
  1795. {
  1796. nParticles = pCachedBatches->GetCachedRenderListCount();
  1797. }
  1798. int nMaxParticlesInBatch = GetMaxParticlesPerBatch( pRenderContext, pMaterial, false );
  1799. float flOODt = ( m_bIgnoreDT ? 1.0 : ( pParticles->m_flDt != 0.0f ) ? ( 1.0f / pParticles->m_flDt ) : 1.0f );
  1800. int nBatchCount = 0;
  1801. bool bFirstBatchBatched = false;
  1802. while ( nParticles )
  1803. {
  1804. int nParticlesInBatch = MIN( nMaxParticlesInBatch, nParticles );
  1805. nParticles -= nParticlesInBatch;
  1806. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  1807. if ( bSpriteCard )
  1808. {
  1809. ICachedPerFrameMeshData *pCachedBatch = pCachedBatches ? pCachedBatches->GetCachedBatch( nBatchCount ) : NULL;
  1810. if ( pCachedBatch )
  1811. {
  1812. // This copies all of the VB/IB pointers and data out of the pCachedBatch back into the pMesh
  1813. pMesh->ReconstructFromCachedPerFrameMeshData( pCachedBatch );
  1814. if ( nBatchCount == 0 )
  1815. bFirstBatchBatched = true;
  1816. nSkipAheadParticles += pMesh->IndexCount() / 6;
  1817. }
  1818. else
  1819. {
  1820. // This fires if the first batch was cached, but some subsequent batch is not. We can either increase MAX_CACHED_PARTICLE_BATCHES in particles.h
  1821. // or get the render list and continue unbatched
  1822. if ( bFirstBatchBatched )
  1823. {
  1824. // Get the render list and resume from where we stopped batching
  1825. int nNewParticles = 0;
  1826. pSortList = pParticles->GetRenderList( pRenderContext, true, &nNewParticles, &pCtx->m_VisibilityData );
  1827. pSortList -= nSkipAheadParticles;
  1828. // We have a different number of particles from when we cached in the beginning of the frame!
  1829. Assert( nNewParticles == nParticles );
  1830. bFirstBatchBatched = false;
  1831. }
  1832. CMeshBuilder meshBuilder;
  1833. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nParticlesInBatch * 4, nParticlesInBatch * 6 );
  1834. if ( meshBuilder.m_ActualVertexSize == 0 )
  1835. {
  1836. // We're likely in alt+tab, and since we're using fast vertex/index routines, we need to see if we're writing into valid vertex data
  1837. meshBuilder.End();
  1838. return;
  1839. }
  1840. // Grab index and vertex pointers. The VB will be NULL if the vertex size is not sizeof( FastSpriteTrailVertex_t )
  1841. uint32 *pIndices = (uint32*)( meshBuilder.BaseIndexData() + meshBuilder.GetCurrentIndex() );
  1842. FastSpriteTrailVertex_t *pVertices = (FastSpriteTrailVertex_t*)meshBuilder.GetVertexDataPtr( sizeof( FastSpriteTrailVertex_t ) );
  1843. int nIndexOffset = meshBuilder.GetIndexOffset();
  1844. int nVertices = 0;
  1845. int nIndices = 0;
  1846. info.m_nVertexOffset = 0;
  1847. if ( pVertices )
  1848. {
  1849. // Fast path uses the predetermined vertex format
  1850. for( int i = 0; i < nParticlesInBatch; i++ )
  1851. {
  1852. int hParticle = (--pSortList)->m_nIndex;
  1853. if ( RenderSpriteTrailSpriteCard<true>( meshBuilder, nVertices, pVertices, pIndices, nIndexOffset, info, hParticle, flOODt, pSortList ) )
  1854. {
  1855. pVertices += 4;
  1856. pIndices += 3;
  1857. nVertices += 4;
  1858. nIndices += 6;
  1859. }
  1860. }
  1861. }
  1862. else
  1863. {
  1864. // Slow path uses meshbuilder
  1865. for( int i = 0; i < nParticlesInBatch; i++ )
  1866. {
  1867. int hParticle = (--pSortList)->m_nIndex;
  1868. if ( RenderSpriteTrailSpriteCard<false>( meshBuilder, nVertices, pVertices, pIndices, nIndexOffset, info, hParticle, flOODt, pSortList ) )
  1869. {
  1870. pIndices += 3;
  1871. nVertices += 4;
  1872. nIndices += 6;
  1873. }
  1874. }
  1875. }
  1876. meshBuilder.AdvanceVerticesF<VTX_HAVEPOS | VTX_HAVECOLOR, 6>( nVertices );
  1877. meshBuilder.AdvanceIndices( nIndices );
  1878. meshBuilder.End();
  1879. // If we have a list of cached batches, cache them off so that if we try to render this sytem again for the current frame,
  1880. // we have a cached all of the vb and ib pointers.
  1881. if ( pCachedBatches )
  1882. {
  1883. pCachedBatch = pMesh->GetCachedPerFrameMeshData();
  1884. pCachedBatches->SetCachedBatch( nBatchCount, pCachedBatch );
  1885. }
  1886. }
  1887. }
  1888. else
  1889. {
  1890. CMeshBuilder meshBuilder;
  1891. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nParticlesInBatch * 4, nParticlesInBatch * 6 );
  1892. info.m_nVertexOffset = 0;
  1893. int nVertices = 0;
  1894. int nIndices = 0;
  1895. for( int i = 0; i < nParticlesInBatch; i++ )
  1896. {
  1897. int hParticle = (--pSortList)->m_nIndex;
  1898. if ( RenderSpriteTrail( meshBuilder, nVertices, nIndices, info, hParticle, vecCameraPos, flOODt, pSortList ) )
  1899. {
  1900. nVertices += 4;
  1901. nIndices += 6;
  1902. }
  1903. }
  1904. meshBuilder.AdvanceVerticesF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>( nVertices );
  1905. meshBuilder.AdvanceIndices( nIndices );
  1906. meshBuilder.End();
  1907. }
  1908. nBatchCount++;
  1909. pMesh->DrawModulated( vecDiffuseModulation );
  1910. }
  1911. }
  1912. void C_OP_RenderSpritesTrail::RenderUnsorted( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const
  1913. {
  1914. C_OP_RenderSpriteTrailContext_t *pCtx = reinterpret_cast<C_OP_RenderSpriteTrailContext_t *>( pContext );
  1915. // NOTE: This is interesting to support because at first we won't have all the various
  1916. // pixel-shader versions of SpriteCard, like modulate, twotexture, etc. etc.
  1917. Vector vecCameraPos;
  1918. pRenderContext->GetWorldSpaceCameraPosition( &vecCameraPos );
  1919. float flAgeScale = m_flAnimationRate * SEQUENCE_SAMPLE_COUNT;
  1920. SpriteTrailRenderInfo_t info;
  1921. info.Init( pParticles, nVertexOffset, flAgeScale, pParticles->m_Sheet() );
  1922. int nParticles;
  1923. const ParticleRenderData_t *pSortList = pParticles->GetRenderList( pRenderContext, false, &nParticles, &pCtx->m_VisibilityData );
  1924. float flOODt = ( m_bIgnoreDT ? 1.0 : ( pParticles->m_flDt != 0.0f ) ? ( 1.0f / pParticles->m_flDt ) : 1.0f );
  1925. int hParticle = nFirstParticle;
  1926. int nVertices = 0;
  1927. int nIndices = 0;
  1928. for( int i = 0; i < nParticleCount; i++, hParticle++ )
  1929. {
  1930. if ( RenderSpriteTrail( meshBuilder, nVertices, nIndices, info, hParticle, vecCameraPos, flOODt, pSortList ) )
  1931. {
  1932. nVertices += 4;
  1933. nIndices += 6;
  1934. }
  1935. }
  1936. meshBuilder.AdvanceVerticesF<VTX_HAVEPOS | VTX_HAVECOLOR, 1>( nVertices );
  1937. meshBuilder.AdvanceIndices( nIndices );
  1938. }
  1939. //-----------------------------------------------------------------------------
  1940. //
  1941. // Rope renderer
  1942. //
  1943. //-----------------------------------------------------------------------------
  1944. struct RopeRenderInfo_t
  1945. {
  1946. size_t m_nXYZStride;
  1947. const fltx4 *m_pXYZ;
  1948. size_t m_nRadStride;
  1949. const fltx4 *m_pRadius;
  1950. size_t m_nRGBStride;
  1951. const fltx4 *m_pRGB;
  1952. size_t m_nAlphaStride;
  1953. const fltx4 *m_pAlpha;
  1954. size_t m_nAlpha2Stride;
  1955. const fltx4 *m_pAlpha2;
  1956. CParticleCollection *m_pParticles;
  1957. void Init( CParticleCollection *pParticles )
  1958. {
  1959. m_pParticles = pParticles;
  1960. m_pXYZ = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_XYZ, &m_nXYZStride );
  1961. m_pRadius = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_RADIUS, &m_nRadStride );
  1962. m_pRGB = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_TINT_RGB, &m_nRGBStride );
  1963. m_pAlpha = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_ALPHA, &m_nAlphaStride );
  1964. m_pAlpha2 = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_ALPHA2, &m_nAlpha2Stride );
  1965. }
  1966. void GenerateSeg( int hParticle, BeamSeg_t& seg )
  1967. {
  1968. Assert( hParticle != -1 );
  1969. int nGroup = hParticle / 4;
  1970. int nOffset = hParticle & 0x3;
  1971. int nXYZIndex = nGroup * m_nXYZStride;
  1972. int nColorIndex = nGroup * m_nRGBStride;
  1973. seg.m_vPos.Init( SubFloat( m_pXYZ[ nXYZIndex ], nOffset ), SubFloat( m_pXYZ[ nXYZIndex+1 ], nOffset ), SubFloat( m_pXYZ[ nXYZIndex+2 ], nOffset ) );
  1974. seg.SetColor( SubFloat( m_pRGB[ nColorIndex ], nOffset ), SubFloat( m_pRGB[ nColorIndex+1 ], nOffset ), SubFloat( m_pRGB[nColorIndex+2], nOffset ), SubFloat( ( m_pAlpha[ nGroup * m_nAlphaStride ] * m_pAlpha2[ nGroup * m_nAlpha2Stride ] ), nOffset ) );
  1975. seg.m_flWidth = SubFloat( m_pRadius[ nGroup * m_nRadStride ], nOffset );
  1976. }
  1977. };
  1978. struct RenderRopeContext_t
  1979. {
  1980. float m_flRenderedRopeLength;
  1981. };
  1982. class C_OP_RenderRope : public CParticleOperatorInstance
  1983. {
  1984. DECLARE_PARTICLE_OPERATOR( C_OP_RenderRope );
  1985. uint32 GetWrittenAttributes( void ) const
  1986. {
  1987. return 0;
  1988. }
  1989. uint32 GetReadAttributes( void ) const
  1990. {
  1991. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_RADIUS_MASK |
  1992. PARTICLE_ATTRIBUTE_TINT_RGB_MASK | PARTICLE_ATTRIBUTE_ALPHA_MASK |
  1993. PARTICLE_ATTRIBUTE_ALPHA2_MASK;
  1994. }
  1995. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  1996. {
  1997. RenderRopeContext_t *pCtx = reinterpret_cast<RenderRopeContext_t *>( pContext );
  1998. pCtx->m_flRenderedRopeLength = false;
  1999. float *pSubdivList = (float*)( pCtx + 1 );
  2000. for ( int iSubdiv = 0; iSubdiv < m_nSubdivCount; iSubdiv++ )
  2001. {
  2002. pSubdivList[iSubdiv] = (float)iSubdiv / (float)m_nSubdivCount;
  2003. }
  2004. // NOTE: Has to happen here, and not in InitParams, since the material isn't set up yet
  2005. IMaterial *pMaterial = pParticles->m_pDef->GetMaterial();
  2006. float flTscale = 1.0;
  2007. if ( pMaterial )
  2008. {
  2009. flTscale = 1.0f / ( pMaterial->GetMappingHeight() * m_flTexelSizeInUnits );
  2010. }
  2011. const_cast<C_OP_RenderRope*>( this )->m_flTextureScale = flTscale; // this is a little bogus but safe
  2012. }
  2013. size_t GetRequiredContextBytes( void ) const
  2014. {
  2015. return sizeof( RenderRopeContext_t ) + m_nSubdivCount * sizeof(float);
  2016. }
  2017. virtual void InitParams( CParticleSystemDefinition *pDef )
  2018. {
  2019. if ( m_nSubdivCount <= 0 )
  2020. {
  2021. m_nSubdivCount = 1;
  2022. }
  2023. if ( m_flTexelSizeInUnits <= 0 )
  2024. {
  2025. m_flTexelSizeInUnits = 1.0f;
  2026. }
  2027. m_flTStep = 1.0 / m_nSubdivCount;
  2028. if ( ( m_bScaleByControlPointDistance || m_bScaleScrollByControlPointDistance || m_bScaleOffsetByControlPointDistance ) && ( m_nScaleCP1 > -1 && m_nScaleCP2 > -1 ) )
  2029. m_bUsesCPScaling = true;
  2030. else
  2031. m_bUsesCPScaling = false;
  2032. }
  2033. virtual uint64 GetReadControlPointMask() const
  2034. {
  2035. if ( m_bUsesCPScaling )
  2036. return ( 1ULL << m_nScaleCP1 ) | ( 1ULL << m_nScaleCP2 );
  2037. return 0;
  2038. }
  2039. virtual bool IsOrderImportant() const
  2040. {
  2041. return true;
  2042. }
  2043. virtual int GetParticlesToRender( CParticleCollection *pParticles, void *pContext, int nFirstParticle, int nRemainingVertices, int nRemainingIndices, int *pVertsUsed, int *pIndicesUsed ) const;
  2044. virtual void Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, int nViewRecursionDepth ) const;
  2045. void RenderSpriteCard( CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, IMaterial *pMaterial ) const;
  2046. virtual void RenderUnsorted( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const;
  2047. template< class T >
  2048. void RenderSpriteCard_Internal( T *pVertices, CCachedParticleBatches *pCachedBatches, IMesh *pMesh, CMeshBuilder &meshBuilder,
  2049. int nSegmentsAvailableInBuffer, int nNumSegmentsIWillRenderPerBatch, float flMaterialMappingHeight,
  2050. CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation ) const;
  2051. int m_nSubdivCount;
  2052. int m_nScaleCP1;
  2053. int m_nScaleCP2;
  2054. float m_flTexelSizeInUnits;
  2055. float m_flTextureScale;
  2056. float m_flTextureScrollRate;
  2057. float m_flTextureOffset;
  2058. float m_flTStep;
  2059. bool m_bScaleByControlPointDistance;
  2060. bool m_bScaleScrollByControlPointDistance;
  2061. bool m_bScaleOffsetByControlPointDistance;
  2062. bool m_bUsesCPScaling;
  2063. CullSystemByControlPointData_t m_cullData;
  2064. };
  2065. DEFINE_PARTICLE_OPERATOR( C_OP_RenderRope, "render_rope", OPERATOR_SINGLETON );
  2066. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RenderRope )
  2067. DMXELEMENT_UNPACK_FIELD( "subdivision_count", "3", int, m_nSubdivCount )
  2068. DMXELEMENT_UNPACK_FIELD( "texel_size", "4.0f", float, m_flTexelSizeInUnits )
  2069. DMXELEMENT_UNPACK_FIELD( "texture_scroll_rate", "0.0f", float, m_flTextureScrollRate )
  2070. DMXELEMENT_UNPACK_FIELD( "texture_offset", "0.0f", float, m_flTextureOffset )
  2071. DMXELEMENT_UNPACK_FIELD( "scale CP start", "-1", int, m_nScaleCP1 )
  2072. DMXELEMENT_UNPACK_FIELD( "scale CP end", "-1", int, m_nScaleCP2 )
  2073. DMXELEMENT_UNPACK_FIELD( "scale texture by CP distance", "0", bool, m_bScaleByControlPointDistance )
  2074. DMXELEMENT_UNPACK_FIELD( "scale scroll by CP distance", "0", bool, m_bScaleScrollByControlPointDistance )
  2075. DMXELEMENT_UNPACK_FIELD( "scale offset by CP distance", "0", bool, m_bScaleOffsetByControlPointDistance )
  2076. DMXELEMENT_UNPACK_FIELD( CULL_CP_NORMAL_DESCRIPTOR, "-1", int, m_cullData.m_nCullControlPoint )
  2077. DMXELEMENT_UNPACK_FIELD( CULL_RECURSION_DEPTH_DESCRIPTOR, "-1", int, m_cullData.m_nViewRecursionDepthStart )
  2078. END_PARTICLE_OPERATOR_UNPACK( C_OP_RenderRope )
  2079. //-----------------------------------------------------------------------------
  2080. // Returns the number of particles to render
  2081. //-----------------------------------------------------------------------------
  2082. int C_OP_RenderRope::GetParticlesToRender( CParticleCollection *pParticles,
  2083. void *pContext, int nFirstParticle, int nRemainingVertices, int nRemainingIndices,
  2084. int *pVertsUsed, int *pIndicesUsed ) const
  2085. {
  2086. if ( ( nFirstParticle >= pParticles->m_nActiveParticles - 1 ) || ( pParticles->m_nActiveParticles <= 1 ) )
  2087. {
  2088. *pVertsUsed = 0;
  2089. *pIndicesUsed = 0;
  2090. return 0;
  2091. }
  2092. // NOTE: This is only true for particles *after* the first particle.
  2093. // First particle takes 2 verts, no indices.
  2094. int nVertsPerParticle = 2 * m_nSubdivCount;
  2095. int nIndicesPerParticle = 6 * m_nSubdivCount;
  2096. // Subtract 2 is because the first particle uses an extra pair of vertices
  2097. int nMaxParticleCount = 1 + ( nRemainingVertices - 2 ) / nVertsPerParticle;
  2098. int nMaxParticleCount2 = nRemainingIndices / nIndicesPerParticle;
  2099. if ( nMaxParticleCount > nMaxParticleCount2 )
  2100. {
  2101. nMaxParticleCount = nMaxParticleCount2;
  2102. }
  2103. int nParticleCount = pParticles->m_nActiveParticles - nFirstParticle;
  2104. // We can't choose a max particle count so that we only have 1 particle to render next time
  2105. if ( nMaxParticleCount == nParticleCount - 1 )
  2106. {
  2107. --nMaxParticleCount;
  2108. Assert( nMaxParticleCount > 0 );
  2109. }
  2110. if ( nParticleCount > nMaxParticleCount )
  2111. {
  2112. nParticleCount = nMaxParticleCount;
  2113. }
  2114. *pVertsUsed = ( nParticleCount - 1 ) * m_nSubdivCount * 2 + 2;
  2115. *pIndicesUsed = nParticleCount * m_nSubdivCount * 6;
  2116. return nParticleCount;
  2117. }
  2118. struct FastRopeVertex_t
  2119. {
  2120. Vector m_vPosition;
  2121. int m_vColor;
  2122. Vector4D m_vP0;
  2123. Vector4D m_vP1;
  2124. Vector4D m_vP2;
  2125. Vector4D m_vP3;
  2126. Vector4D m_vCorners;
  2127. Vector4D m_vEndPointColor;
  2128. FORCEINLINE void SetNormals( Vector &vecNorm0, Vector &vecNorm1 )
  2129. {
  2130. // Intentionally do nothing, no normals on a FastRopeVertex_t
  2131. }
  2132. };
  2133. struct FastRopeVertexNormal_t
  2134. {
  2135. Vector m_vPosition;
  2136. int m_vColor;
  2137. Vector4D m_vP0;
  2138. Vector4D m_vP1;
  2139. Vector4D m_vP2;
  2140. Vector4D m_vP3;
  2141. Vector4D m_vCorners;
  2142. Vector4D m_vEndPointColor;
  2143. Vector m_vNormal0;
  2144. Vector m_vNormal1;
  2145. FORCEINLINE void SetNormals( Vector &vecNorm0, Vector &vecNorm1 )
  2146. {
  2147. m_vNormal0 = vecNorm0;
  2148. m_vNormal1 = vecNorm1;
  2149. }
  2150. };
  2151. struct FastRopeVertexNormalCacheAligned_t : public FastRopeVertexNormal_t
  2152. {
  2153. int m_nPadding[ 2 ];
  2154. // On the PC, vertex structures need to be sized in multiples of 16 bytes
  2155. FORCEINLINE void Check() { COMPILE_TIME_ASSERT( !IsPC() || ( sizeof( *this ) % 16 ) == 0 ); }
  2156. };
  2157. template < class T >
  2158. FORCEINLINE void Output2SplineVerts( T *&pVertices, int &nVertices, int nPackedColor, float flT, float flU, Vector4D &vecP0, Vector4D &vecP1, Vector4D &vecP2, Vector4D &vecP3, Vector4D &vecEndPointColor, Vector &vecNorm0, Vector &vecNorm1 )
  2159. {
  2160. pVertices->m_vPosition.Init( flT, flU, 0 );
  2161. pVertices->m_vColor = nPackedColor;
  2162. pVertices->m_vP0 = vecP0;
  2163. pVertices->m_vP1 = vecP1;
  2164. pVertices->m_vP2 = vecP2;
  2165. pVertices->m_vP3 = vecP3;
  2166. pVertices->m_vCorners.Init( 0, 0, 1, 1 );
  2167. pVertices->m_vEndPointColor = vecEndPointColor;
  2168. pVertices->SetNormals( vecNorm0, vecNorm1 );
  2169. pVertices++;
  2170. pVertices->m_vPosition.Init( flT, flU, 1 );
  2171. pVertices->m_vColor = nPackedColor;
  2172. pVertices->m_vP0 = vecP0;
  2173. pVertices->m_vP1 = vecP1;
  2174. pVertices->m_vP2 = vecP2;
  2175. pVertices->m_vP3 = vecP3;
  2176. pVertices->m_vCorners.Init( 0, 0, 1, 1 );
  2177. pVertices->m_vEndPointColor = vecEndPointColor;
  2178. pVertices->SetNormals( vecNorm0, vecNorm1 );
  2179. pVertices++;
  2180. nVertices += 2;
  2181. }
  2182. #define OUTPUT_SPLINE_INDICES( nCurIDX ) \
  2183. { \
  2184. unsigned short _nIndex = nCurIDX + nIndexOffset; \
  2185. *pIndices = TwoIndices( _nIndex, _nIndex + 1 ); pIndices++; \
  2186. *pIndices = TwoIndices( _nIndex + 2, _nIndex + 1 ); pIndices++; \
  2187. *pIndices = TwoIndices( _nIndex + 3, _nIndex + 2 ); pIndices++; \
  2188. nIndices += 6; \
  2189. }
  2190. template< class T >
  2191. void C_OP_RenderRope::RenderSpriteCard_Internal( T *pVertices, CCachedParticleBatches *pCachedBatches, IMesh *pMesh, CMeshBuilder &meshBuilder,
  2192. int nSegmentsAvailableInBuffer, int nNumSegmentsIWillRenderPerBatch, float flMaterialMappingHeight,
  2193. CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation ) const
  2194. {
  2195. uint32 *pIndices = (uint32*)( meshBuilder.BaseIndexData() + meshBuilder.GetCurrentIndex() );
  2196. int nIndexOffset = meshBuilder.GetIndexOffset();
  2197. int nParticles = pParticles->m_nActiveParticles;
  2198. int nSegmentsToRender = nParticles - 1;
  2199. const float *pXYZ = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_XYZ, 0 );
  2200. const float *pColor = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_TINT_RGB, 0 );
  2201. const float *pRadius = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_RADIUS, 0 );
  2202. const float *pAlpha = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_ALPHA, 0 );
  2203. const float *pAlpha2 = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_ALPHA2, 0 );
  2204. const float *pNorm = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_NORMAL, 0 );
  2205. bool bFirstPoint = true;
  2206. float flTextureScrollRate = m_flTextureScrollRate;
  2207. float flU = m_flTextureOffset;
  2208. float flDist = 0;
  2209. float flOffsetScaled = m_flTextureOffset / flMaterialMappingHeight;
  2210. float flTextureScale = m_flTexelSizeInUnits;
  2211. if ( m_bUsesCPScaling )
  2212. {
  2213. flDist = pParticles->GetControlPointAtCurrentTime( m_nScaleCP1 ).DistTo( pParticles->GetControlPointAtCurrentTime( m_nScaleCP2 ) );
  2214. if ( m_bScaleByControlPointDistance )
  2215. {
  2216. flTextureScale = 1.0f / ( ( flDist * m_flTexelSizeInUnits ) + FLT_EPSILON );
  2217. }
  2218. if ( m_bScaleScrollByControlPointDistance )
  2219. {
  2220. flTextureScrollRate *= ( flDist / flMaterialMappingHeight ) * flTextureScale;
  2221. }
  2222. if ( m_bScaleOffsetByControlPointDistance )
  2223. {
  2224. flOffsetScaled += flOffsetScaled * ( flDist / flMaterialMappingHeight );
  2225. }
  2226. }
  2227. flTextureScrollRate *= pParticles->m_flCurTime;
  2228. flOffsetScaled += flTextureScrollRate;
  2229. flU += flOffsetScaled;
  2230. // initialize first spline segment
  2231. Vector4D vecP1( pXYZ[0], pXYZ[4], pXYZ[8], pRadius[0] );
  2232. Vector4D vecP2( pXYZ[1], pXYZ[5], pXYZ[9], pRadius[1] );
  2233. Vector4D vecP0 = vecP1;
  2234. Vector vecNorm0( pNorm[0], pNorm[4], pNorm[8] );
  2235. Vector vecNorm1( pNorm[1], pNorm[5], pNorm[9] );
  2236. uint8 nRed = FastFToC( pColor[0] );
  2237. uint8 nGreen = FastFToC( pColor[4] );
  2238. uint8 nBlue = FastFToC( pColor[8] );
  2239. uint8 nAlpha = FastFToC( pAlpha[0] * pAlpha2[0] );
  2240. Vector4D vecDelta = vecP2;
  2241. vecDelta -= vecP1;
  2242. vecP0 -= vecDelta;
  2243. Vector4D vecP3;
  2244. Vector4D vecEndPointColor( pColor[1], pColor[5], pColor[9], pAlpha[1] * pAlpha2[1] );
  2245. if ( nParticles < 3 )
  2246. {
  2247. vecP3 = vecP2;
  2248. vecP3 += vecDelta;
  2249. }
  2250. else
  2251. {
  2252. vecP3.Init( pXYZ[2], pXYZ[6], pXYZ[10], pRadius[2] );
  2253. }
  2254. int nPnt = 3;
  2255. int nCurIDX = 0;
  2256. int nVertices = 0;
  2257. int nIndices = 0;
  2258. float flDUScale = ( m_flTStep * flTextureScale );
  2259. float flT = 0;
  2260. int nBatchCount = 0;
  2261. do
  2262. {
  2263. if ( !nSegmentsAvailableInBuffer )
  2264. {
  2265. meshBuilder.AdvanceVerticesF<VTX_HAVEPOS | VTX_HAVECOLOR, 8>( nVertices );
  2266. meshBuilder.AdvanceIndices( nIndices );
  2267. meshBuilder.End();
  2268. // Store this off for the next frame
  2269. if ( pCachedBatches )
  2270. {
  2271. pCachedBatches->SetCachedBatch( nBatchCount, pMesh->GetCachedPerFrameMeshData() );
  2272. nBatchCount++;
  2273. }
  2274. int nNumIndicesPerSegment = 6 * m_nSubdivCount;
  2275. int nNumVerticesPerSegment = 2 * m_nSubdivCount;
  2276. pMesh->DrawModulated( vecDiffuseModulation );
  2277. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 2 + nNumSegmentsIWillRenderPerBatch * nNumVerticesPerSegment,
  2278. nNumIndicesPerSegment * nNumSegmentsIWillRenderPerBatch );
  2279. pIndices = (uint32*)( meshBuilder.BaseIndexData() + meshBuilder.GetCurrentIndex() );
  2280. nIndexOffset = meshBuilder.GetIndexOffset();
  2281. pVertices = (T*)meshBuilder.GetVertexDataPtr( sizeof( T ) );
  2282. nVertices = 0;
  2283. nIndices = 0;
  2284. // copy the last emitted points
  2285. int nPackedColor = PackRGBToPlatformColor( nRed, nGreen, nBlue, nAlpha );
  2286. Output2SplineVerts( pVertices, nVertices, nPackedColor, flT, flU, vecP0, vecP1, vecP2, vecP3, vecEndPointColor, vecNorm0, vecNorm1 );
  2287. nSegmentsAvailableInBuffer = nNumSegmentsIWillRenderPerBatch;
  2288. nCurIDX = 0;
  2289. }
  2290. nSegmentsAvailableInBuffer--;
  2291. flT = 0.;
  2292. float flDu = flDUScale * ( vecP2.AsVector3D() - vecP1.AsVector3D() ).Length();
  2293. // Vertices first
  2294. int nPackedColor = PackRGBToPlatformColor( nRed, nGreen, nBlue, nAlpha );
  2295. for( int nSlice = 0 ; nSlice < m_nSubdivCount; nSlice++ )
  2296. {
  2297. Output2SplineVerts( pVertices, nVertices, nPackedColor, flT, flU, vecP0, vecP1, vecP2, vecP3, vecEndPointColor, vecNorm0, vecNorm1 );
  2298. flT += m_flTStep;
  2299. flU += flDu;
  2300. }
  2301. // Indices second, but output m_nSubdivCount-1 indices if it's our first time through
  2302. for( int nSlice = bFirstPoint ? 1 : 0 ; nSlice < m_nSubdivCount; nSlice++ )
  2303. {
  2304. OUTPUT_SPLINE_INDICES( nCurIDX );
  2305. nCurIDX += 2;
  2306. }
  2307. bFirstPoint = false;
  2308. // next segment
  2309. if ( nSegmentsToRender > 1 )
  2310. {
  2311. vecP0 = vecP1;
  2312. vecP1 = vecP2;
  2313. vecP2 = vecP3;
  2314. nRed = FastFToC( vecEndPointColor.x );
  2315. nGreen = FastFToC( vecEndPointColor.y );
  2316. nBlue = FastFToC( vecEndPointColor.z );
  2317. nAlpha = FastFToC( vecEndPointColor.w );
  2318. vecNorm0 = vecNorm1;
  2319. const float *pRadius = pParticles->GetFloatAttributePtr(
  2320. PARTICLE_ATTRIBUTE_RADIUS, nPnt );
  2321. const float *pAlpha = pParticles->GetFloatAttributePtr(
  2322. PARTICLE_ATTRIBUTE_ALPHA, nPnt -1 );
  2323. const float *pAlpha2 = pParticles->GetFloatAttributePtr(
  2324. PARTICLE_ATTRIBUTE_ALPHA2, nPnt - 1 );
  2325. const float *pColor = pParticles->GetFloatAttributePtr(
  2326. PARTICLE_ATTRIBUTE_TINT_RGB, nPnt - 1 );
  2327. vecEndPointColor.Init( pColor[0], pColor[4], pColor[8], pAlpha[0] * pAlpha2[0] );
  2328. if ( nPnt < nParticles )
  2329. {
  2330. pXYZ = pParticles->GetFloatAttributePtr(
  2331. PARTICLE_ATTRIBUTE_XYZ, nPnt );
  2332. vecP3.Init( pXYZ[0], pXYZ[4], pXYZ[8], pRadius[0] );
  2333. pNorm = pParticles->GetFloatAttributePtr(
  2334. PARTICLE_ATTRIBUTE_NORMAL, nPnt );
  2335. vecNorm1.Init( pNorm[0], pNorm[4], pNorm[8] );
  2336. nPnt++;
  2337. }
  2338. else
  2339. {
  2340. // fake last point by extrapolating
  2341. vecP3 += vecP2;
  2342. vecP3 -= vecP1;
  2343. }
  2344. }
  2345. } while( --nSegmentsToRender );
  2346. // output last piece
  2347. int nPackedColor = PackRGBToPlatformColor( nRed, nGreen, nBlue, nAlpha );
  2348. Output2SplineVerts( pVertices, nVertices, nPackedColor, 1.0, flU, vecP0, vecP1, vecP2, vecP3, vecEndPointColor, vecNorm0, vecNorm1 );
  2349. OUTPUT_SPLINE_INDICES( nCurIDX );
  2350. meshBuilder.AdvanceVerticesF<VTX_HAVEPOS | VTX_HAVECOLOR, 8>( nVertices );
  2351. meshBuilder.AdvanceIndices( nIndices );
  2352. meshBuilder.End();
  2353. // Store this off for the next frame
  2354. if ( pCachedBatches )
  2355. {
  2356. pCachedBatches->SetCachedBatch( nBatchCount, pMesh->GetCachedPerFrameMeshData() );
  2357. }
  2358. pMesh->DrawModulated( vecDiffuseModulation );
  2359. }
  2360. void C_OP_RenderRope::RenderSpriteCard( CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, IMaterial *pMaterial ) const
  2361. {
  2362. int nParticles = pParticles->m_nActiveParticles;
  2363. int nSegmentsToRender = nParticles - 1;
  2364. if ( ! nSegmentsToRender )
  2365. return;
  2366. // Reset the particle cache if we're sprite card material (doesn't use camerapos) and isn't sorted
  2367. bool bShouldSort = pParticles->m_pDef->m_bShouldSort;
  2368. CCachedParticleBatches *pCachedBatches = NULL;
  2369. MaterialThreadMode_t nThreadMode = g_pMaterialSystem->GetThreadMode();
  2370. if ( nThreadMode != MATERIAL_SINGLE_THREADED && !bShouldSort )
  2371. {
  2372. pParticles->ResetParticleCache();
  2373. pCachedBatches = pParticles->GetCachedParticleBatches();
  2374. }
  2375. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  2376. pRenderContext->Bind( pMaterial );
  2377. int nMaxVertices = pRenderContext->GetMaxVerticesToRender( pMaterial );
  2378. int nMaxIndices = pRenderContext->GetMaxIndicesToRender();
  2379. int nNumIndicesPerSegment = 6 * m_nSubdivCount;
  2380. int nNumVerticesPerSegment = 2 * m_nSubdivCount;
  2381. int nNumSegmentsPerBatch = MIN( ( nMaxVertices - 2 )/nNumVerticesPerSegment,
  2382. ( nMaxIndices ) / nNumIndicesPerSegment );
  2383. int nNumSegmentsIWillRenderPerBatch = MIN( nNumSegmentsPerBatch, nSegmentsToRender );
  2384. int nSegmentsAvailableInBuffer = nNumSegmentsIWillRenderPerBatch;
  2385. // Early out in the case of having cached batches
  2386. int nBatchCount = 0;
  2387. ICachedPerFrameMeshData *pCachedBatch = pCachedBatches ? pCachedBatches->GetCachedBatch( nBatchCount ) : NULL;
  2388. if ( pCachedBatch )
  2389. {
  2390. do
  2391. {
  2392. if ( !nSegmentsAvailableInBuffer )
  2393. {
  2394. IMesh *pMesh = pRenderContext->GetDynamicMesh( true );
  2395. pMesh->ReconstructFromCachedPerFrameMeshData( pCachedBatch );
  2396. pMesh->DrawModulated( vecDiffuseModulation );
  2397. nSegmentsAvailableInBuffer = nNumSegmentsIWillRenderPerBatch;
  2398. // Next cached batch
  2399. pCachedBatch = pCachedBatches->GetCachedBatch( ++nBatchCount );
  2400. }
  2401. int nSegs = MIN(nSegmentsToRender, nSegmentsAvailableInBuffer);
  2402. nSegmentsToRender -= nSegs;
  2403. nSegmentsAvailableInBuffer -= nSegs;
  2404. } while( nSegmentsToRender );
  2405. // Render the last batch
  2406. IMesh *pMesh = pRenderContext->GetDynamicMesh( true );
  2407. pMesh->ReconstructFromCachedPerFrameMeshData( pCachedBatch );
  2408. pMesh->DrawModulated( vecDiffuseModulation );
  2409. return;
  2410. }
  2411. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  2412. CMeshBuilder meshBuilder;
  2413. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES,
  2414. 2 + nNumSegmentsIWillRenderPerBatch * nNumVerticesPerSegment,
  2415. nNumIndicesPerSegment * nNumSegmentsIWillRenderPerBatch );
  2416. if ( meshBuilder.m_ActualVertexSize == 0 )
  2417. {
  2418. // We're likely in alt+tab, and since we're using fast vertex/index routines, we need to see if we're writing into valid vertex data
  2419. meshBuilder.End();
  2420. return;
  2421. }
  2422. FastRopeVertex_t *pVertices = (FastRopeVertex_t*)meshBuilder.GetVertexDataPtr( sizeof( FastRopeVertex_t ) );
  2423. if ( pVertices )
  2424. {
  2425. // No normal components in ropes
  2426. RenderSpriteCard_Internal( pVertices, pCachedBatches, pMesh, meshBuilder, nSegmentsAvailableInBuffer, nNumSegmentsIWillRenderPerBatch, pMaterial->GetMappingHeight(), pParticles, vecDiffuseModulation );
  2427. }
  2428. else
  2429. {
  2430. // Two normal components in ropes
  2431. FastRopeVertexNormal_t *pVerticesNormal = (FastRopeVertexNormal_t*)meshBuilder.GetVertexDataPtr( sizeof( FastRopeVertexNormal_t ) );
  2432. if ( pVerticesNormal )
  2433. {
  2434. RenderSpriteCard_Internal( pVerticesNormal, pCachedBatches, pMesh, meshBuilder, nSegmentsAvailableInBuffer, nNumSegmentsIWillRenderPerBatch, pMaterial->GetMappingHeight(), pParticles, vecDiffuseModulation );
  2435. }
  2436. else
  2437. {
  2438. // Cached aligned
  2439. FastRopeVertexNormalCacheAligned_t *pVerticesNormalCacheAligned = (FastRopeVertexNormalCacheAligned_t*)meshBuilder.GetVertexDataPtr( sizeof( FastRopeVertexNormalCacheAligned_t ) );
  2440. if ( pVerticesNormalCacheAligned )
  2441. {
  2442. RenderSpriteCard_Internal( pVerticesNormalCacheAligned, pCachedBatches, pMesh, meshBuilder, nSegmentsAvailableInBuffer, nNumSegmentsIWillRenderPerBatch, pMaterial->GetMappingHeight(), pParticles, vecDiffuseModulation );
  2443. }
  2444. else
  2445. {
  2446. Assert( 0 );
  2447. }
  2448. }
  2449. }
  2450. }
  2451. //-----------------------------------------------------------------------------
  2452. // Renders particles, sorts them (?)
  2453. //-----------------------------------------------------------------------------
  2454. void C_OP_RenderRope::Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, int nViewRecursionDepth ) const
  2455. {
  2456. // See if we need to cull this system
  2457. if ( ShouldCullParticleSystem( &m_cullData, pParticles, pRenderContext, nViewRecursionDepth ) )
  2458. return;
  2459. IMaterial *pMaterial = pParticles->m_pDef->GetMaterial();
  2460. if ( pMaterial->IsSpriteCard() )
  2461. {
  2462. RenderSpriteCard( pParticles, vecDiffuseModulation, pContext, pMaterial );
  2463. return;
  2464. }
  2465. pRenderContext->Bind( pMaterial );
  2466. int nMaxVertices = pRenderContext->GetMaxVerticesToRender( pMaterial );
  2467. int nMaxIndices = pRenderContext->GetMaxIndicesToRender();
  2468. int nParticles = pParticles->m_nActiveParticles;
  2469. int nFirstParticle = 0;
  2470. while ( nParticles )
  2471. {
  2472. int nVertCount, nIndexCount;
  2473. int nParticlesInBatch = GetParticlesToRender( pParticles, pContext, nFirstParticle, nMaxVertices, nMaxIndices, &nVertCount, &nIndexCount );
  2474. if ( nParticlesInBatch == 0 )
  2475. break;
  2476. nParticles -= nParticlesInBatch;
  2477. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  2478. CMeshBuilder meshBuilder;
  2479. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nVertCount, nIndexCount );
  2480. RenderUnsorted( pParticles, pContext, pRenderContext, meshBuilder, 0, nFirstParticle, nParticlesInBatch );
  2481. meshBuilder.End();
  2482. pMesh->DrawModulated( vecDiffuseModulation );
  2483. nFirstParticle += nParticlesInBatch;
  2484. }
  2485. }
  2486. //-----------------------------------------------------------------------------
  2487. // Purpose:
  2488. //-----------------------------------------------------------------------------
  2489. void C_OP_RenderRope::RenderUnsorted( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const
  2490. {
  2491. IMaterial *pMaterial = pParticles->m_pDef->GetMaterial();
  2492. // Right now we only have a meshbuilder version!
  2493. Assert( pMaterial->IsSpriteCard() == false );
  2494. if ( pMaterial->IsSpriteCard() )
  2495. return;
  2496. RenderRopeContext_t *pCtx = reinterpret_cast<RenderRopeContext_t *>( pContext );
  2497. float *pSubdivList = (float*)( pCtx + 1 );
  2498. if ( nFirstParticle == 0 )
  2499. {
  2500. pCtx->m_flRenderedRopeLength = 0.0f;
  2501. }
  2502. float flTexOffset = m_flTextureScrollRate;
  2503. float flTextureScale = m_flTextureScale;
  2504. RopeRenderInfo_t info;
  2505. info.Init( pParticles );
  2506. flTexOffset *= pParticles->m_flCurTime;
  2507. float flDist = 0;
  2508. float flOffsetScaled = m_flTextureOffset;
  2509. if ( m_bUsesCPScaling )
  2510. {
  2511. flDist = pParticles->GetControlPointAtCurrentTime( m_nScaleCP1 ).DistTo( pParticles->GetControlPointAtCurrentTime( m_nScaleCP2 ) );
  2512. if ( m_bScaleByControlPointDistance ) // scale by distance to first control point?
  2513. {
  2514. flTextureScale = 1.0f / ( ( flDist * m_flTexelSizeInUnits ) + FLT_EPSILON );
  2515. }
  2516. if ( m_bScaleScrollByControlPointDistance )
  2517. {
  2518. flOffsetScaled *= ( flDist / pMaterial->GetMappingHeight() );
  2519. }
  2520. if ( m_bScaleOffsetByControlPointDistance )
  2521. {
  2522. flOffsetScaled += m_flTextureOffset * ( flDist / pMaterial->GetMappingHeight() );
  2523. }
  2524. }
  2525. flTexOffset += flOffsetScaled;
  2526. CBeamSegDraw beamSegment;
  2527. beamSegment.Start( pRenderContext, ( nParticleCount - 1 ) * m_nSubdivCount + 1, pMaterial, &meshBuilder, nVertexOffset );
  2528. Vector vecCatmullRom[4];
  2529. BeamSeg_t seg[2];
  2530. info.GenerateSeg( nFirstParticle, seg[0] );
  2531. seg[0].m_flTexCoord = ( pCtx->m_flRenderedRopeLength + flTexOffset ) * flTextureScale;
  2532. beamSegment.NextSeg( &seg[0] );
  2533. vecCatmullRom[1] = seg[0].m_vPos;
  2534. if ( nFirstParticle == 0 )
  2535. {
  2536. vecCatmullRom[0] = vecCatmullRom[1];
  2537. }
  2538. else
  2539. {
  2540. int nGroup = ( nFirstParticle-1 ) / 4;
  2541. int nOffset = ( nFirstParticle-1 ) & 0x3;
  2542. int nXYZIndex = nGroup * info.m_nXYZStride;
  2543. vecCatmullRom[0].Init( SubFloat( info.m_pXYZ[ nXYZIndex ], nOffset ), SubFloat( info.m_pXYZ[ nXYZIndex+1 ], nOffset ), SubFloat( info.m_pXYZ[ nXYZIndex+2 ], nOffset ) );
  2544. }
  2545. float flOOSubDivCount = 1.0f / m_nSubdivCount;
  2546. int hParticle = nFirstParticle + 1;
  2547. for ( int i = 1; i < nParticleCount; ++i, ++hParticle )
  2548. {
  2549. int nCurr = i & 1;
  2550. int nPrev = 1 - nCurr;
  2551. info.GenerateSeg( hParticle, seg[nCurr] );
  2552. pCtx->m_flRenderedRopeLength += seg[nCurr].m_vPos.DistTo( seg[nPrev].m_vPos );
  2553. seg[nCurr].m_flTexCoord = ( pCtx->m_flRenderedRopeLength + flTexOffset ) * flTextureScale;
  2554. if ( m_nSubdivCount > 1 )
  2555. {
  2556. vecCatmullRom[ (i+1) & 0x3 ] = seg[nCurr].m_vPos;
  2557. if ( hParticle != info.m_pParticles->m_nActiveParticles - 1 )
  2558. {
  2559. int nGroup = ( hParticle+1 ) / 4;
  2560. int nOffset = ( hParticle+1 ) & 0x3;
  2561. int nXYZIndex = nGroup * info.m_nXYZStride;
  2562. vecCatmullRom[ (i+2) & 0x3 ].Init( SubFloat( info.m_pXYZ[ nXYZIndex ], nOffset ), SubFloat( info.m_pXYZ[ nXYZIndex+1 ], nOffset ), SubFloat( info.m_pXYZ[ nXYZIndex+2 ], nOffset ) );
  2563. }
  2564. else
  2565. {
  2566. vecCatmullRom[ (i+2) & 0x3 ] = vecCatmullRom[ (i+1) & 0x3 ];
  2567. }
  2568. BeamSeg_t &subDivSeg = seg[nPrev];
  2569. Vector4D vecColor, vecNextColor;
  2570. seg[nPrev].GetColor( &vecColor );
  2571. seg[nCurr].GetColor( &vecNextColor );
  2572. Vector4D vecColorInc;
  2573. Vector4DSubtract( vecNextColor, vecColor, vecColorInc );
  2574. vecColorInc *= flOOSubDivCount;
  2575. float flTexcoordInc = ( seg[nCurr].m_flTexCoord - seg[nPrev].m_flTexCoord ) * flOOSubDivCount;
  2576. float flWidthInc = ( seg[nCurr].m_flWidth - seg[nPrev].m_flWidth ) * flOOSubDivCount;
  2577. for( int iSubdiv = 1; iSubdiv < m_nSubdivCount; ++iSubdiv )
  2578. {
  2579. vecColor += vecColorInc;
  2580. subDivSeg.SetColor( vecColor.x, vecColor.y, vecColor.z, vecColor.w );
  2581. subDivSeg.m_flTexCoord += flTexcoordInc;
  2582. subDivSeg.m_flWidth += flWidthInc;
  2583. Catmull_Rom_Spline( vecCatmullRom[ (i+3) & 0x3 ], vecCatmullRom[ i & 0x3 ],
  2584. vecCatmullRom[ (i+1) & 0x3 ], vecCatmullRom[ (i+2) & 0x3 ],
  2585. pSubdivList[iSubdiv], subDivSeg.m_vPos );
  2586. beamSegment.NextSeg( &subDivSeg );
  2587. }
  2588. }
  2589. beamSegment.NextSeg( &seg[nCurr] );
  2590. }
  2591. beamSegment.End();
  2592. }
  2593. #ifdef USE_BLOBULATOR // Enable blobulator for EP3
  2594. //-----------------------------------------------------------------------------
  2595. // Installs renderers
  2596. //-----------------------------------------------------------------------------
  2597. class C_OP_RenderBlobs : public CParticleRenderOperatorInstance
  2598. {
  2599. DECLARE_PARTICLE_OPERATOR( C_OP_RenderBlobs );
  2600. float m_cubeWidth;
  2601. float m_cutoffRadius;
  2602. float m_renderRadius;
  2603. struct C_OP_RenderBlobsContext_t
  2604. {
  2605. CParticleVisibilityData m_VisibilityData;
  2606. int m_nQueryHandle;
  2607. };
  2608. virtual uint64 GetReadControlPointMask() const
  2609. {
  2610. uint64 nMask = 0;
  2611. if ( VisibilityInputs.m_nCPin >= 0 )
  2612. nMask |= 1ULL << VisibilityInputs.m_nCPin;
  2613. return nMask;
  2614. }
  2615. size_t GetRequiredContextBytes( void ) const
  2616. {
  2617. return sizeof( C_OP_RenderBlobsContext_t );
  2618. }
  2619. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  2620. {
  2621. C_OP_RenderBlobsContext_t *pCtx = reinterpret_cast<C_OP_RenderBlobsContext_t *>( pContext );
  2622. if ( ( VisibilityInputs.m_nCPin >= 0 ) || ( VisibilityInputs.m_flRadiusScaleFOVBase > 0 ) )
  2623. pCtx->m_VisibilityData.m_bUseVisibility = true;
  2624. else
  2625. pCtx->m_VisibilityData.m_bUseVisibility = false;
  2626. }
  2627. uint32 GetWrittenAttributes( void ) const
  2628. {
  2629. return 0;
  2630. }
  2631. uint32 GetReadAttributes( void ) const
  2632. {
  2633. return PARTICLE_ATTRIBUTE_XYZ_MASK;
  2634. }
  2635. virtual void Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, int nViewRecursionDepth ) const;
  2636. virtual bool IsBatchable() const
  2637. {
  2638. return false;
  2639. }
  2640. };
  2641. DEFINE_PARTICLE_OPERATOR( C_OP_RenderBlobs, "render_blobs", OPERATOR_SINGLETON );
  2642. BEGIN_PARTICLE_RENDER_OPERATOR_UNPACK( C_OP_RenderBlobs )
  2643. DMXELEMENT_UNPACK_FIELD( "cube_width", "1.0f", float, m_cubeWidth )
  2644. DMXELEMENT_UNPACK_FIELD( "cutoff_radius", "3.3f", float, m_cutoffRadius )
  2645. DMXELEMENT_UNPACK_FIELD( "render_radius", "1.3f", float, m_renderRadius )
  2646. END_PARTICLE_OPERATOR_UNPACK( C_OP_RenderBlobs )
  2647. void C_OP_RenderBlobs::Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, int nViewRecursionDepth ) const
  2648. {
  2649. C_OP_RenderBlobsContext_t *pCtx = reinterpret_cast<C_OP_RenderBlobsContext_t *>( pContext );
  2650. if ( pCtx->m_VisibilityData.m_bUseVisibility )
  2651. {
  2652. SetupParticleVisibility( pParticles, &pCtx->m_VisibilityData, &VisibilityInputs, &pCtx->m_nQueryHandle, pRenderContext );
  2653. }
  2654. #if 0
  2655. // Note: it is not good to have these static variables here.
  2656. static RENDERER_CLASS* sweepRenderer = NULL;
  2657. static ImpTiler* tiler = NULL;
  2658. if(!sweepRenderer)
  2659. {
  2660. sweepRenderer = new RENDERER_CLASS();
  2661. tiler = new ImpTiler(sweepRenderer);
  2662. }
  2663. #endif
  2664. IMaterial *pMaterial = pParticles->m_pDef->GetMaterial();
  2665. // TODO: I don't need to load this as a sorted list. See Lennard Jones forces for better way!
  2666. int nParticles;
  2667. const ParticleRenderData_t *pSortList = pParticles->GetRenderList( pRenderContext, false, &nParticles, &pCtx->m_VisibilityData );
  2668. size_t xyz_stride;
  2669. const fltx4 *xyz = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_XYZ, &xyz_stride );
  2670. Vector bbMin;
  2671. Vector bbMax;
  2672. pParticles->GetBounds( &bbMin, &bbMax );
  2673. Vector bbCenter = 0.5f * ( bbMin + bbMax );
  2674. // FIXME: Make this configurable. Not all shaders perform lighting. Although it's pretty likely for isosurface shaders.
  2675. g_pParticleSystemMgr->Query()->SetUpLightingEnvironment( bbCenter );
  2676. ImpParticleList particleList;
  2677. particleList.EnsureCount( nParticles );
  2678. for( int i = 0; i < nParticles; i++ )
  2679. {
  2680. int hParticle = (--pSortList)->m_nIndex;
  2681. int nIndex = ( hParticle / 4 ) * xyz_stride;
  2682. int nOffset = hParticle & 0x3;
  2683. float x = SubFloat( xyz[nIndex], nOffset );
  2684. float y = SubFloat( xyz[nIndex+1], nOffset );
  2685. float z = SubFloat( xyz[nIndex+2], nOffset );
  2686. ImpParticle* imp_particle = &particleList[i];
  2687. imp_particle->center[0]=x;
  2688. imp_particle->center[1]=y;
  2689. imp_particle->center[2]=z;
  2690. imp_particle->setFieldScale(1.0f);
  2691. }
  2692. Blobulator::BlobRenderInfo_t blobRenderInfo;
  2693. blobRenderInfo.m_flCubeWidth = m_cubeWidth;
  2694. blobRenderInfo.m_flCutoffRadius = m_cutoffRadius;
  2695. blobRenderInfo.m_flRenderRadius = m_renderRadius;
  2696. blobRenderInfo.m_flViewScale = ( nViewRecursionDepth == 0 ) ? 1.f : 1.6f;
  2697. blobRenderInfo.m_nViewID = nViewRecursionDepth;
  2698. Blobulator::RenderBlob( true, pRenderContext, pMaterial, blobRenderInfo, NULL, 0, particleList.Base(), nParticles );
  2699. }
  2700. #endif //blobs
  2701. //-----------------------------------------------------------------------------
  2702. // Installs renderers
  2703. //-----------------------------------------------------------------------------
  2704. class C_OP_RenderScreenVelocityRotate : public CParticleRenderOperatorInstance
  2705. {
  2706. DECLARE_PARTICLE_OPERATOR( C_OP_RenderScreenVelocityRotate );
  2707. float m_flRotateRateDegrees;
  2708. float m_flForwardDegrees;
  2709. struct C_OP_RenderScreenVelocityRotateContext_t
  2710. {
  2711. CParticleVisibilityData m_VisibilityData;
  2712. int m_nQueryHandle;
  2713. };
  2714. size_t GetRequiredContextBytes( void ) const
  2715. {
  2716. return sizeof( C_OP_RenderScreenVelocityRotateContext_t );
  2717. }
  2718. virtual uint64 GetReadControlPointMask() const
  2719. {
  2720. uint64 nMask = 0;
  2721. if ( VisibilityInputs.m_nCPin >= 0 )
  2722. nMask |= 1ULL << VisibilityInputs.m_nCPin;
  2723. return nMask;
  2724. }
  2725. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  2726. {
  2727. C_OP_RenderScreenVelocityRotateContext_t *pCtx = reinterpret_cast<C_OP_RenderScreenVelocityRotateContext_t *>( pContext );
  2728. if ( ( VisibilityInputs.m_nCPin >= 0 ) || ( VisibilityInputs.m_flRadiusScaleFOVBase > 0 ) )
  2729. pCtx->m_VisibilityData.m_bUseVisibility = true;
  2730. else
  2731. pCtx->m_VisibilityData.m_bUseVisibility = false;
  2732. }
  2733. uint32 GetWrittenAttributes( void ) const
  2734. {
  2735. return PARTICLE_ATTRIBUTE_ROTATION_MASK;
  2736. }
  2737. uint32 GetReadAttributes( void ) const
  2738. {
  2739. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_ROTATION_MASK ;
  2740. }
  2741. virtual void Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, int nViewRecursionDepth ) const;
  2742. };
  2743. DEFINE_PARTICLE_OPERATOR( C_OP_RenderScreenVelocityRotate, "render_screen_velocity_rotate", OPERATOR_SINGLETON );
  2744. BEGIN_PARTICLE_RENDER_OPERATOR_UNPACK( C_OP_RenderScreenVelocityRotate )
  2745. DMXELEMENT_UNPACK_FIELD( "rotate_rate(dps)", "0.0f", float, m_flRotateRateDegrees )
  2746. DMXELEMENT_UNPACK_FIELD( "forward_angle", "-90.0f", float, m_flForwardDegrees )
  2747. END_PARTICLE_OPERATOR_UNPACK( C_OP_RenderScreenVelocityRotate )
  2748. void C_OP_RenderScreenVelocityRotate::Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, int nViewRecursionDepth ) const
  2749. {
  2750. C_OP_RenderScreenVelocityRotateContext_t *pCtx = reinterpret_cast<C_OP_RenderScreenVelocityRotateContext_t *>( pContext );
  2751. if ( pCtx->m_VisibilityData.m_bUseVisibility )
  2752. {
  2753. SetupParticleVisibility( pParticles, &pCtx->m_VisibilityData, &VisibilityInputs, &pCtx->m_nQueryHandle, pRenderContext );
  2754. }
  2755. // NOTE: This is interesting to support because at first we won't have all the various
  2756. // pixel-shader versions of SpriteCard, like modulate, twotexture, etc. etc.
  2757. VMatrix tempView;
  2758. // Store matrices off so we can restore them in RenderEnd().
  2759. pRenderContext->GetMatrix(MATERIAL_VIEW, &tempView);
  2760. int nParticles;
  2761. const ParticleRenderData_t *pSortList = pParticles->GetRenderList( pRenderContext, false, &nParticles, &pCtx->m_VisibilityData );
  2762. size_t xyz_stride;
  2763. const fltx4 *xyz = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_XYZ, &xyz_stride );
  2764. size_t prev_xyz_stride;
  2765. const fltx4 *prev_xyz = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_PREV_XYZ, &prev_xyz_stride );
  2766. size_t rot_stride;
  2767. // const fltx4 *pRot = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_ROTATION, &rot_stride );
  2768. fltx4 *pRot = pParticles->GetM128AttributePtrForWrite( PARTICLE_ATTRIBUTE_ROTATION, &rot_stride );
  2769. float flForwardRadians = m_flForwardDegrees * ( M_PI / 180.0f );
  2770. //float flRotateRateRadians = m_flRotateRateDegrees * ( M_PI / 180.0f );
  2771. for( int i = 0; i < nParticles; i++ )
  2772. {
  2773. int hParticle = (--pSortList)->m_nIndex;
  2774. int nGroup = ( hParticle / 4 );
  2775. int nOffset = hParticle & 0x3;
  2776. int nXYZIndex = nGroup * xyz_stride;
  2777. Vector vecWorldPos( SubFloat( xyz[ nXYZIndex ], nOffset ), SubFloat( xyz[ nXYZIndex+1 ], nOffset ), SubFloat( xyz[ nXYZIndex+2 ], nOffset ) );
  2778. Vector vecViewPos;
  2779. Vector3DMultiplyPosition( tempView, vecWorldPos, vecViewPos );
  2780. if (!IsFinite(vecViewPos.x))
  2781. continue;
  2782. int nPrevXYZIndex = nGroup * prev_xyz_stride;
  2783. Vector vecPrevWorldPos( SubFloat( prev_xyz[ nPrevXYZIndex ], nOffset ), SubFloat( prev_xyz[ nPrevXYZIndex+1 ], nOffset ), SubFloat( prev_xyz[ nPrevXYZIndex+2 ], nOffset ) );
  2784. Vector vecPrevViewPos;
  2785. Vector3DMultiplyPosition( tempView, vecPrevWorldPos, vecPrevViewPos );
  2786. float rot = atan2( vecViewPos.y - vecPrevViewPos.y, vecViewPos.x - vecPrevViewPos.x ) + flForwardRadians;
  2787. SubFloat( pRot[ nGroup * rot_stride ], nOffset ) = rot;
  2788. }
  2789. }
  2790. #define MAX_MODEL_CHOICES 1
  2791. class C_OP_RenderModels : public CParticleRenderOperatorInstance
  2792. {
  2793. DECLARE_PARTICLE_OPERATOR( C_OP_RenderModels );
  2794. uint32 GetReadAttributes( void ) const
  2795. {
  2796. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER_MASK | PARTICLE_ATTRIBUTE_TINT_RGB_MASK | PARTICLE_ATTRIBUTE_ALPHA_MASK | PARTICLE_ATTRIBUTE_ALPHA2_MASK | PARTICLE_ATTRIBUTE_RADIUS_MASK |
  2797. PARTICLE_ATTRIBUTE_ROTATION_MASK | PARTICLE_ATTRIBUTE_YAW_MASK | PARTICLE_ATTRIBUTE_PITCH_MASK | PARTICLE_ATTRIBUTE_NORMAL_MASK | 1 << m_nAnimationScaleField;
  2798. }
  2799. uint32 GetWrittenAttributes( void ) const
  2800. {
  2801. return 0;
  2802. }
  2803. virtual bool IsBatchable() const
  2804. {
  2805. return false;
  2806. }
  2807. virtual void Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, int nViewRecursionDepth ) const;
  2808. virtual void Precache( void );
  2809. char m_ActivityName[256];
  2810. char m_pszModelNames[ MAX_MODEL_CHOICES ][256];
  2811. void *m_pModels[ MAX_MODEL_CHOICES ];
  2812. bool m_bOrientZ;
  2813. bool m_bScaleAnimationRate;
  2814. int m_nAnimationScaleField;
  2815. int m_nSkin;
  2816. int m_nActivity;
  2817. float m_flAnimationRate;
  2818. };
  2819. DEFINE_PARTICLE_OPERATOR( C_OP_RenderModels, "Render models", OPERATOR_SINGLETON );
  2820. BEGIN_PARTICLE_RENDER_OPERATOR_UNPACK( C_OP_RenderModels )
  2821. DMXELEMENT_UNPACK_FIELD_STRING_USERDATA( "sequence 0 model", "NONE", m_pszModelNames[0], "mdlPicker" )
  2822. DMXELEMENT_UNPACK_FIELD( "animation rate", "30.0", float, m_flAnimationRate )
  2823. DMXELEMENT_UNPACK_FIELD( "scale animation rate", "0", bool, m_bScaleAnimationRate )
  2824. DMXELEMENT_UNPACK_FIELD_USERDATA( "animation rate scale field", "10", int, m_nAnimationScaleField, "intchoice particlefield_scalar" )
  2825. DMXELEMENT_UNPACK_FIELD( "orient model z to normal", "0", bool, m_bOrientZ )
  2826. DMXELEMENT_UNPACK_FIELD( "skin number", "0", int, m_nSkin )
  2827. DMXELEMENT_UNPACK_FIELD_STRING( "activity override", "", m_ActivityName )
  2828. END_PARTICLE_OPERATOR_UNPACK( C_OP_RenderModels )
  2829. void C_OP_RenderModels::Precache( void )
  2830. {
  2831. // this is the the render operator sequences above, as each one has to be hard coded
  2832. Assert( MAX_MODEL_CHOICES == 1 );
  2833. for( int i = 0; i < MAX_MODEL_CHOICES ; i++ )
  2834. {
  2835. m_pModels[ i ] = g_pParticleSystemMgr->Query()->GetModel( m_pszModelNames[i] );
  2836. }
  2837. // Have to do this here or the model isn't loaded yet
  2838. if ( V_strcmp( m_ActivityName, "" ) )
  2839. m_nActivity = g_pParticleSystemMgr->Query()->GetActivityNumber( m_pModels[ 0 ], m_ActivityName );
  2840. else
  2841. m_nActivity = -1;
  2842. }
  2843. // return a vector perpendicular to another, with smooth variation
  2844. static void AVectorPerpendicularToVector( Vector const &in, Vector *pvecOut )
  2845. {
  2846. float flY = in.y * in.y;
  2847. pvecOut->x = RemapVal( flY, 0, 1, in.z, 1 );
  2848. pvecOut->y = 0;
  2849. pvecOut->z = -in.x;
  2850. pvecOut->NormalizeInPlace();
  2851. float flDot = DotProduct( *pvecOut, in );
  2852. *pvecOut -= flDot * in;
  2853. pvecOut->NormalizeInPlace();
  2854. }
  2855. void C_OP_RenderModels::Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, int nViewRecursionDepth ) const
  2856. {
  2857. int nNumParticles;
  2858. CParticleVisibilityData visibilityData;
  2859. visibilityData.m_flAlphaVisibility = 1.0;
  2860. visibilityData.m_flRadiusVisibility = 1.0;
  2861. visibilityData.m_bUseVisibility = false;
  2862. const ParticleRenderData_t *pRenderList =
  2863. pParticles->GetRenderList( pRenderContext, false, &nNumParticles, &visibilityData );
  2864. g_pParticleSystemMgr->Query()->BeginDrawModels( nNumParticles, pParticles->m_Center, pParticles );
  2865. size_t xyz_stride;
  2866. const fltx4 *xyz = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_XYZ, &xyz_stride );
  2867. size_t seq_stride;
  2868. const fltx4 *pSequenceNumber = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER, &seq_stride );
  2869. size_t seq1_stride;
  2870. const fltx4 *pSequence1Number = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER1, &seq1_stride );
  2871. size_t rgb_stride;
  2872. const fltx4 *pRGB = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_TINT_RGB, &rgb_stride );
  2873. size_t nAlphaStride;
  2874. const fltx4 *pAlpha = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_ALPHA, &nAlphaStride );
  2875. size_t nAlpha2Stride;
  2876. const fltx4 *pAlpha2 = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_ALPHA2, &nAlpha2Stride );
  2877. size_t nRadStride;
  2878. const fltx4 *pRadius = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_RADIUS, &nRadStride );
  2879. size_t nRotStride;
  2880. const fltx4 *pRot = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_ROTATION, &nRotStride );
  2881. size_t nYawStride;
  2882. const fltx4 *pYaw = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_YAW, &nYawStride );
  2883. size_t nPitchStride;
  2884. const fltx4 *pPitch = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_PITCH, &nPitchStride );
  2885. size_t nScalerStride;
  2886. const fltx4 *pAnimationScale = pParticles->GetM128AttributePtr( m_nAnimationScaleField, &nScalerStride );
  2887. for( int i = 0; i < nNumParticles; i++ )
  2888. {
  2889. int hParticle = ( --pRenderList )->m_nIndex;
  2890. int nGroup = ( hParticle / 4 );
  2891. int nOffset = hParticle & 0x3;
  2892. int nSequence = ( int )SubFloat( pSequenceNumber[ nGroup * seq_stride ], nOffset );
  2893. int nAnimationSequence = m_nActivity;
  2894. if ( nAnimationSequence == -1 )
  2895. nAnimationSequence = ( int )SubFloat( pSequence1Number[ nGroup * seq1_stride ], nOffset );
  2896. float flAnimationRate = m_flAnimationRate;
  2897. if ( m_bScaleAnimationRate )
  2898. flAnimationRate *= SubFloat( pAnimationScale[ nGroup * nScalerStride ], nOffset );
  2899. int nXYZIndex = nGroup * xyz_stride;
  2900. Vector vecWorldPos( SubFloat( xyz[ nXYZIndex ], nOffset ), SubFloat( xyz[ nXYZIndex+1 ], nOffset ), SubFloat( xyz[ nXYZIndex+2 ], nOffset ) );
  2901. const float *pNormal = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_NORMAL, hParticle );
  2902. Vector vecFwd, vecRight, vecUp;
  2903. SetVectorFromAttribute( vecFwd, pNormal);
  2904. vecFwd.NormalizeInPlace();
  2905. AVectorPerpendicularToVector( vecFwd, &vecRight );
  2906. float flDot = fabs( DotProduct( vecFwd, vecRight ) );
  2907. Assert( flDot < 0.1f );
  2908. if ( flDot >= 0.1f )
  2909. {
  2910. AVectorPerpendicularToVector( vecFwd, &vecRight );
  2911. }
  2912. vecUp = CrossProduct( vecFwd, vecRight );
  2913. Assert( fabs( DotProduct( vecFwd, vecUp ) ) < 0.1f );
  2914. Assert( fabs( DotProduct( vecRight, vecUp ) ) < 0.1f );
  2915. int nColorIndex = nGroup * rgb_stride;
  2916. float r = SubFloat( pRGB[ nColorIndex ], nOffset );
  2917. float g = SubFloat( pRGB[ nColorIndex + 1 ], nOffset );
  2918. float b = SubFloat( pRGB[ nColorIndex + 2 ], nOffset );
  2919. float a = SubFloat( ( pAlpha[ nGroup * nAlphaStride ] * pAlpha2[ nGroup * nAlpha2Stride ] ), nOffset );
  2920. float flScale = SubFloat( pRadius[ nGroup * nRadStride ], nOffset );
  2921. float rot = SubFloat( pRot[ nGroup * nRotStride ], nOffset );
  2922. float yaw = SubFloat( pYaw[ nGroup * nRotStride ], nOffset );
  2923. float pitch = SubFloat( pPitch[ nGroup * nRotStride ], nOffset );
  2924. matrix3x4_t matRotate, matDir, matFinal;
  2925. QAngle qa( RAD2DEG( pitch ), RAD2DEG( yaw ), RAD2DEG( rot ) );
  2926. AngleMatrix( qa, matRotate );
  2927. if ( m_bOrientZ )
  2928. {
  2929. matDir = matrix3x4_t( vecUp * flScale, -vecRight * flScale, vecFwd * flScale, vec3_origin );
  2930. }
  2931. else
  2932. {
  2933. matDir = matrix3x4_t( vecFwd * flScale, vecRight * flScale, vecUp * flScale, vec3_origin );
  2934. }
  2935. MatrixMultiply( matDir, matRotate, matFinal );
  2936. matFinal.SetOrigin( vecWorldPos );
  2937. g_pParticleSystemMgr->Query()->DrawModel( m_pModels[ 0 ], matFinal, pParticles, hParticle, nSequence, 1, m_nSkin, nAnimationSequence, flAnimationRate, r, g, b, a );
  2938. }
  2939. g_pParticleSystemMgr->Query()->FinishDrawModels( pParticles );
  2940. }
  2941. // rj: this is just temporary until I get another aspect of this done
  2942. //-----------------------------------------------------------------------------
  2943. //
  2944. // Projected renderer
  2945. //
  2946. //-----------------------------------------------------------------------------
  2947. class C_OP_RenderProjected : public CParticleRenderOperatorInstance
  2948. {
  2949. DECLARE_PARTICLE_OPERATOR( C_OP_RenderProjected );
  2950. uint32 GetReadAttributes( void ) const
  2951. {
  2952. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PARTICLE_ID_MASK | PARTICLE_ATTRIBUTE_TINT_RGB_MASK | PARTICLE_ATTRIBUTE_ALPHA_MASK | PARTICLE_ATTRIBUTE_ALPHA2_MASK |
  2953. PARTICLE_ATTRIBUTE_RADIUS_MASK | PARTICLE_ATTRIBUTE_ROTATION_MASK;
  2954. }
  2955. uint32 GetWrittenAttributes( void ) const
  2956. {
  2957. return 0;
  2958. }
  2959. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  2960. {
  2961. void **pCtx = reinterpret_cast< void ** >( pContext );
  2962. *pCtx = NULL;
  2963. }
  2964. size_t GetRequiredContextBytes( void ) const
  2965. {
  2966. return sizeof( void * );
  2967. }
  2968. virtual void PostSimulate( CParticleCollection *pParticles, void *pContext ) const
  2969. {
  2970. void **pCtx = reinterpret_cast< void ** >( pContext );
  2971. IMaterial *pMaterial = pParticles->m_pDef->GetMaterial();
  2972. // size_t xyz_stride;
  2973. // const fltx4 *xyz = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_XYZ, &xyz_stride );
  2974. if ( pParticles->m_nActiveParticles >= 1 )
  2975. {
  2976. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  2977. {
  2978. Vector vPosition;
  2979. const float *pflXYZ = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_XYZ, i );
  2980. SetVectorFromAttribute( vPosition, pflXYZ );
  2981. const int *pParticleID = pParticles->GetIntAttributePtr( PARTICLE_ATTRIBUTE_PARTICLE_ID, i );
  2982. const float *pAlpha = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_ALPHA, i );
  2983. const float *pAlpha2 = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_ALPHA2, i );
  2984. const float *pColor = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_TINT_RGB, i );
  2985. const float *pRadius = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_RADIUS, i );
  2986. const float *pRotation = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_ROTATION, i );
  2987. g_pParticleSystemMgr->Query()->UpdateProjectedTexture( *pParticleID, pMaterial, vPosition, pRadius[ 0 ], pRotation[ 0 ], pColor[ 0 ], pColor[ 1 ], pColor[ 2 ], pAlpha[ 0 ] * pAlpha2[ 0 ], *pCtx );
  2988. break;
  2989. }
  2990. }
  2991. else
  2992. {
  2993. *pCtx = NULL;
  2994. }
  2995. }
  2996. virtual void Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, int nViewRecursionDepth ) const;
  2997. };
  2998. DEFINE_PARTICLE_OPERATOR( C_OP_RenderProjected, "Render projected", OPERATOR_SINGLETON );
  2999. BEGIN_PARTICLE_RENDER_OPERATOR_UNPACK( C_OP_RenderProjected )
  3000. END_PARTICLE_OPERATOR_UNPACK( C_OP_RenderProjected )
  3001. void C_OP_RenderProjected::Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, int nViewRecursionDepth ) const
  3002. {
  3003. if ( g_pParticleSystemMgr->Query()->IsEditor() == false )
  3004. {
  3005. return;
  3006. }
  3007. IMaterial *pMaterial = pParticles->m_pDef->GetMaterial();
  3008. pRenderContext->Bind( pMaterial );
  3009. for ( int i = 0; i < pParticles->m_nActiveParticles; ++i )
  3010. {
  3011. Vector vPosition;
  3012. const float *pflXYZ = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_XYZ, i );
  3013. SetVectorFromAttribute( vPosition, pflXYZ );
  3014. // const int *pParticleID = pParticles->GetIntAttributePtr( PARTICLE_ATTRIBUTE_PARTICLE_ID, i );
  3015. const float *pAlpha = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_ALPHA, i );
  3016. const float *pAlpha2 = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_ALPHA2, i );
  3017. const float *pColor = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_TINT_RGB, i );
  3018. const float *pRadius = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_RADIUS, i );
  3019. const float *pRotation = pParticles->GetFloatAttributePtr( PARTICLE_ATTRIBUTE_ROTATION, i );
  3020. FlashlightState_t state;
  3021. VMatrix WorldToTexture;
  3022. state.m_vecLightOrigin = Vector( pflXYZ[ 0 ], pflXYZ[ 1 ] , pflXYZ[ 2 ] );
  3023. float flAlpha = pAlpha[ 0 ] * pAlpha2[ 0 ];
  3024. state.m_Color[0] = pColor[ 0 ] * flAlpha;
  3025. state.m_Color[1] = pColor[ 1 ] * flAlpha;
  3026. state.m_Color[2] = pColor[ 2 ] * flAlpha;
  3027. state.m_Color[3] = 0.0f; // fixme: need to make ambient work m_flAmbient;
  3028. state.m_flProjectionSize = pRadius[ 0 ];
  3029. state.m_flProjectionRotation = pRotation[ 0 ];
  3030. pRenderContext->SetFlashlightState( state, WorldToTexture );
  3031. // g_pParticleSystemMgr->Query()->UpdateProjectedTexture( *pParticleID, pMaterial, vPosition, pRadius[ 0 ], pRotation[ 0 ], pColor[ 0 ], pColor[ 1 ], pColor[ 2 ], pAlpha[ 0 ] * pAlpha2[ 0 ], *pCtx );
  3032. CMeshBuilder meshBuilder;
  3033. IMesh *pMesh = pRenderContext->GetDynamicMesh( true );
  3034. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  3035. meshBuilder.Position3f( -1000.0f, -1000.0f, 0.0f );
  3036. meshBuilder.AdvanceVertexF<VTX_HAVEPOS, 0>();
  3037. meshBuilder.Position3f( 1000.0f, -1000.0f, 0.0f );
  3038. meshBuilder.AdvanceVertexF<VTX_HAVEPOS, 0>();
  3039. meshBuilder.Position3f( 1000.0f, 1000.0f, 0.0f );
  3040. meshBuilder.AdvanceVertexF<VTX_HAVEPOS, 0>();
  3041. meshBuilder.Position3f( -1000.0f, 1000.0f, 0.0f );
  3042. meshBuilder.AdvanceVertexF<VTX_HAVEPOS, 0>();
  3043. meshBuilder.End();
  3044. pMesh->DrawModulated( vecDiffuseModulation );
  3045. break;
  3046. }
  3047. }
  3048. //-----------------------------------------------------------------------------
  3049. // Installs renderers
  3050. //-----------------------------------------------------------------------------
  3051. void AddBuiltInParticleRenderers( void )
  3052. {
  3053. #ifdef _DEBUG
  3054. REGISTER_PARTICLE_OPERATOR( FUNCTION_RENDERER, C_OP_RenderPoints );
  3055. #endif
  3056. REGISTER_PARTICLE_OPERATOR( FUNCTION_RENDERER, C_OP_RenderSprites );
  3057. REGISTER_PARTICLE_OPERATOR( FUNCTION_RENDERER, C_OP_RenderSpritesTrail );
  3058. REGISTER_PARTICLE_OPERATOR( FUNCTION_RENDERER, C_OP_RenderRope );
  3059. REGISTER_PARTICLE_OPERATOR( FUNCTION_RENDERER, C_OP_RenderScreenVelocityRotate );
  3060. REGISTER_PARTICLE_OPERATOR( FUNCTION_RENDERER, C_OP_RenderModels );
  3061. #ifdef USE_BLOBULATOR
  3062. REGISTER_PARTICLE_OPERATOR( FUNCTION_RENDERER, C_OP_RenderBlobs );
  3063. #endif // blobs
  3064. REGISTER_PARTICLE_OPERATOR( FUNCTION_RENDERER, C_OP_RenderProjected );
  3065. }