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

2416 lines
91 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: particle system code
  4. //
  5. //===========================================================================//
  6. #include "tier0/platform.h"
  7. #include "particles/particles.h"
  8. #include "filesystem.h"
  9. #include "tier2/tier2.h"
  10. #include "tier2/fileutils.h"
  11. #include "tier2/renderutils.h"
  12. #include "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 "psheet.h"
  20. #include "tier0/vprof.h"
  21. #ifdef USE_BLOBULATOR
  22. // TODO: These should be in public by the time the SDK ships
  23. #include "../common/blobulator/Implicit/ImpDefines.h"
  24. #include "../common/blobulator/Implicit/ImpRenderer.h"
  25. #include "../common/blobulator/Implicit/ImpTiler.h"
  26. #include "../common/blobulator/Implicit/UserFunctions.h"
  27. #endif
  28. // memdbgon must be the last include file in a .cpp file!!!
  29. #include "tier0/memdbgon.h"
  30. // Vertex instancing (1 vert submitted per particle, duplicated to 4 (a quad) on the GPU) is supported only on 360
  31. const bool bUseInstancing = IsX360();
  32. //-----------------------------------------------------------------------------
  33. // Utility method to compute the max # of particles per batch
  34. //-----------------------------------------------------------------------------
  35. static inline int GetMaxParticlesPerBatch( IMatRenderContext *pRenderContext, IMaterial *pMaterial, bool bWithInstancing )
  36. {
  37. int nMaxVertices = pRenderContext->GetMaxVerticesToRender( pMaterial );
  38. int nMaxIndices = pRenderContext->GetMaxIndicesToRender();
  39. if ( bWithInstancing )
  40. return nMaxVertices;
  41. else
  42. return min( (nMaxVertices / 4), (nMaxIndices / 6) );
  43. }
  44. void SetupParticleVisibility( CParticleCollection *pParticles, CParticleVisibilityData *pVisibilityData, const CParticleVisibilityInputs *pVisibilityInputs, int *nQueryHandle )
  45. {
  46. float flScale = pVisibilityInputs->m_flProxyRadius;
  47. Vector vecOrigin;
  48. /*
  49. if ( pVisibilityInputs->m_bUseBBox )
  50. {
  51. Vector vecMinBounds;
  52. Vector vecMaxBounds;
  53. Vector mins;
  54. Vector maxs;
  55. pParticles->GetBounds( &vecMinBounds, &vecMaxBounds );
  56. vecOrigin = ( ( vecMinBounds + vecMaxBounds ) / 2 );
  57. Vector vecBounds = ( vecMaxBounds - vecMinBounds );
  58. flScale = ( max(vecBounds.x, max (vecBounds.y, vecBounds.z) ) * pVisibilityInputs->m_flBBoxScale );
  59. }
  60. if ( pVisibilityInputs->m_nCPin >= 0 )
  61. {
  62. vecOrigin = pParticles->GetControlPointAtCurrentTime( pVisibilityInputs->m_nCPin );
  63. }
  64. */
  65. vecOrigin = pParticles->GetControlPointAtCurrentTime( pVisibilityInputs->m_nCPin );
  66. float flVisibility = g_pParticleSystemMgr->Query()->GetPixelVisibility( nQueryHandle, vecOrigin, flScale );
  67. pVisibilityData->m_flAlphaVisibility = RemapValClamped( flVisibility, pVisibilityInputs->m_flInputMin,
  68. pVisibilityInputs->m_flInputMax, pVisibilityInputs->m_flAlphaScaleMin, pVisibilityInputs->m_flAlphaScaleMax );
  69. pVisibilityData->m_flRadiusVisibility = RemapValClamped( flVisibility, pVisibilityInputs->m_flInputMin,
  70. pVisibilityInputs->m_flInputMax, pVisibilityInputs->m_flRadiusScaleMin, pVisibilityInputs->m_flRadiusScaleMax );
  71. pVisibilityData->m_flCameraBias = pVisibilityInputs->m_flCameraBias;
  72. }
  73. static SheetSequenceSample_t s_DefaultSheetSequence =
  74. {
  75. {
  76. { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f }, // SequenceSampleTextureCoords_t image 0
  77. { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f } // SequenceSampleTextureCoords_t image 1
  78. },
  79. 1.0f // m_fBlendFactor
  80. };
  81. class C_OP_RenderPoints : public CParticleRenderOperatorInstance
  82. {
  83. DECLARE_PARTICLE_OPERATOR( C_OP_RenderPoints );
  84. uint32 GetWrittenAttributes( void ) const
  85. {
  86. return 0;
  87. }
  88. uint32 GetReadAttributes( void ) const
  89. {
  90. return PARTICLE_ATTRIBUTE_XYZ_MASK;
  91. }
  92. virtual void Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, void *pContext ) const;
  93. struct C_OP_RenderPointsContext_t
  94. {
  95. CParticleVisibilityData m_VisibilityData;
  96. int m_nQueryHandle;
  97. };
  98. size_t GetRequiredContextBytes( void ) const
  99. {
  100. return sizeof( C_OP_RenderPointsContext_t );
  101. }
  102. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  103. {
  104. C_OP_RenderPointsContext_t *pCtx = reinterpret_cast<C_OP_RenderPointsContext_t *>( pContext );
  105. pCtx->m_VisibilityData.m_bUseVisibility = false;
  106. pCtx->m_VisibilityData.m_flCameraBias = VisibilityInputs.m_flCameraBias;
  107. }
  108. };
  109. DEFINE_PARTICLE_OPERATOR( C_OP_RenderPoints, "render_points", OPERATOR_SINGLETON );
  110. BEGIN_PARTICLE_RENDER_OPERATOR_UNPACK( C_OP_RenderPoints )
  111. END_PARTICLE_OPERATOR_UNPACK( C_OP_RenderPoints )
  112. void C_OP_RenderPoints::Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, void *pContext ) const
  113. {
  114. C_OP_RenderPointsContext_t *pCtx = reinterpret_cast<C_OP_RenderPointsContext_t *>( pContext );
  115. IMaterial *pMaterial = pParticles->m_pDef->GetMaterial();
  116. int nParticles;
  117. const ParticleRenderData_t *pRenderList =
  118. pParticles->GetRenderList( pRenderContext, true, &nParticles, &pCtx->m_VisibilityData );
  119. size_t xyz_stride;
  120. const fltx4 *xyz = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_XYZ, &xyz_stride );
  121. pRenderContext->Bind( pMaterial );
  122. CMeshBuilder meshBuilder;
  123. int nMaxVertices = pRenderContext->GetMaxVerticesToRender( pMaterial );
  124. while ( nParticles )
  125. {
  126. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  127. int nParticlesInBatch = min( nMaxVertices, nParticles );
  128. nParticles -= nParticlesInBatch;
  129. g_pParticleSystemMgr->TallyParticlesRendered( nParticlesInBatch );
  130. meshBuilder.Begin( pMesh, MATERIAL_POINTS, nParticlesInBatch );
  131. for( int i = 0; i < nParticlesInBatch; i++ )
  132. {
  133. int hParticle = (--pRenderList)->m_nIndex;
  134. int nIndex = ( hParticle / 4 ) * xyz_stride;
  135. int nOffset = hParticle & 0x3;
  136. meshBuilder.Position3f( SubFloat( xyz[nIndex], nOffset ), SubFloat( xyz[nIndex+1], nOffset ), SubFloat( xyz[nIndex+2], nOffset ) );
  137. meshBuilder.Color4ub( 255, 255, 255, 255 );
  138. meshBuilder.AdvanceVertex();
  139. }
  140. meshBuilder.End();
  141. pMesh->Draw();
  142. }
  143. }
  144. //-----------------------------------------------------------------------------
  145. //
  146. // Sprite Rendering
  147. //
  148. //-----------------------------------------------------------------------------
  149. //-----------------------------------------------------------------------------
  150. // Utility struct to help with sprite rendering
  151. //-----------------------------------------------------------------------------
  152. struct SpriteRenderInfo_t
  153. {
  154. size_t m_nXYZStride;
  155. const fltx4 *m_pXYZ;
  156. size_t m_nRotStride;
  157. const fltx4 *m_pRot;
  158. size_t m_nYawStride;
  159. const fltx4 *m_pYaw;
  160. size_t m_nRGBStride;
  161. const fltx4 *m_pRGB;
  162. size_t m_nCreationTimeStride;
  163. const fltx4 *m_pCreationTimeStamp;
  164. size_t m_nSequenceStride;
  165. const fltx4 *m_pSequenceNumber;
  166. size_t m_nSequence1Stride;
  167. const fltx4 *m_pSequence1Number;
  168. float m_flAgeScale;
  169. float m_flAgeScale2;
  170. CSheet *m_pSheet;
  171. int m_nVertexOffset;
  172. CParticleCollection *m_pParticles;
  173. void Init( CParticleCollection *pParticles, int nVertexOffset, float flAgeScale, float flAgeScale2, CSheet *pSheet )
  174. {
  175. m_pParticles = pParticles;
  176. m_pXYZ = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_XYZ, &m_nXYZStride );
  177. m_pRot = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_ROTATION, &m_nRotStride );
  178. m_pYaw = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_YAW, &m_nYawStride );
  179. m_pRGB = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_TINT_RGB, &m_nRGBStride );
  180. m_pCreationTimeStamp = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, &m_nCreationTimeStride );
  181. m_pSequenceNumber = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER, &m_nSequenceStride );
  182. m_pSequence1Number = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER1, &m_nSequence1Stride );
  183. m_flAgeScale = flAgeScale;
  184. m_flAgeScale2 = flAgeScale2;
  185. m_pSheet = pSheet;
  186. m_nVertexOffset = nVertexOffset;
  187. }
  188. };
  189. class C_OP_RenderSprites : public C_OP_RenderPoints
  190. {
  191. DECLARE_PARTICLE_OPERATOR( C_OP_RenderSprites );
  192. struct C_OP_RenderSpritesContext_t
  193. {
  194. unsigned int m_nOrientationVarToken;
  195. unsigned int m_nOrientationMatrixVarToken;
  196. CParticleVisibilityData m_VisibilityData;
  197. int m_nQueryHandle;
  198. };
  199. size_t GetRequiredContextBytes( void ) const
  200. {
  201. return sizeof( C_OP_RenderSpritesContext_t );
  202. }
  203. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  204. {
  205. C_OP_RenderSpritesContext_t *pCtx = reinterpret_cast<C_OP_RenderSpritesContext_t *>( pContext );
  206. pCtx->m_nOrientationVarToken = 0;
  207. pCtx->m_nOrientationMatrixVarToken = 0;
  208. if ( VisibilityInputs.m_nCPin >= 0 )
  209. pCtx->m_VisibilityData.m_bUseVisibility = true;
  210. else
  211. pCtx->m_VisibilityData.m_bUseVisibility = false;
  212. pCtx->m_VisibilityData.m_flCameraBias = VisibilityInputs.m_flCameraBias;
  213. }
  214. virtual uint64 GetReadControlPointMask() const
  215. {
  216. if ( m_nOrientationControlPoint >= 0 )
  217. return 1ULL << m_nOrientationControlPoint;
  218. return 0;
  219. }
  220. uint32 GetReadAttributes( void ) const
  221. {
  222. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_ROTATION_MASK | PARTICLE_ATTRIBUTE_RADIUS_MASK |
  223. PARTICLE_ATTRIBUTE_TINT_RGB_MASK | PARTICLE_ATTRIBUTE_ALPHA_MASK | PARTICLE_ATTRIBUTE_CREATION_TIME_MASK |
  224. PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER1_MASK |
  225. PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER_MASK | PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK;
  226. }
  227. virtual void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement );
  228. virtual int GetParticlesToRender( CParticleCollection *pParticles, void *pContext, int nFirstParticle, int nRemainingVertices, int nRemainingIndices, int *pVertsUsed, int *pIndicesUsed ) const;
  229. virtual void Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, void *pContext ) const;
  230. virtual void RenderUnsorted( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const;
  231. void RenderSpriteCard( CMeshBuilder &meshBuilder, C_OP_RenderSpritesContext_t *pCtx, SpriteRenderInfo_t& info, int hParticle, ParticleRenderData_t const *pSortList, Vector *pCamera ) const;
  232. void RenderTwoSequenceSpriteCard( CMeshBuilder &meshBuilder, C_OP_RenderSpritesContext_t *pCtx, SpriteRenderInfo_t& info, int hParticle, ParticleRenderData_t const *pSortList, Vector *pCamera ) const;
  233. void RenderNonSpriteCardCameraFacing( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, IMaterial *pMaterial ) const;
  234. void RenderNonSpriteCardZRotating( CMeshBuilder &meshBuilder, C_OP_RenderSpritesContext_t *pCtx, SpriteRenderInfo_t& info, int hParticle, const Vector& vecCameraPos, ParticleRenderData_t const *pSortList ) const;
  235. void RenderNonSpriteCardZRotating( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, IMaterial *pMaterial ) const;
  236. void RenderUnsortedNonSpriteCardZRotating( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const;
  237. void RenderNonSpriteCardOriented( CMeshBuilder &meshBuilder, C_OP_RenderSpritesContext_t *pCtx, SpriteRenderInfo_t& info, int hParticle, const Vector& vecCameraPos, ParticleRenderData_t const *pSortList, bool bUseYaw ) const;
  238. void RenderNonSpriteCardOriented( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, IMaterial *pMaterial, bool bUseYaw ) const;
  239. void RenderUnsortedNonSpriteCardOriented( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const;
  240. // cycles per second
  241. float m_flAnimationRate;
  242. float m_flAnimationRate2;
  243. bool m_bFitCycleToLifetime;
  244. bool m_bAnimateInFPS;
  245. int m_nOrientationType;
  246. int m_nOrientationControlPoint;
  247. };
  248. DEFINE_PARTICLE_OPERATOR( C_OP_RenderSprites, "render_animated_sprites", OPERATOR_GENERIC );
  249. BEGIN_PARTICLE_RENDER_OPERATOR_UNPACK( C_OP_RenderSprites )
  250. DMXELEMENT_UNPACK_FIELD( "animation rate", ".1", float, m_flAnimationRate )
  251. DMXELEMENT_UNPACK_FIELD( "animation_fit_lifetime", "0", bool, m_bFitCycleToLifetime )
  252. DMXELEMENT_UNPACK_FIELD( "orientation_type", "0", int, m_nOrientationType )
  253. DMXELEMENT_UNPACK_FIELD( "orientation control point", "-1", int, m_nOrientationControlPoint )
  254. DMXELEMENT_UNPACK_FIELD( "second sequence animation rate", "0", float, m_flAnimationRate2 )
  255. DMXELEMENT_UNPACK_FIELD( "use animation rate as FPS", "0", bool, m_bAnimateInFPS )
  256. END_PARTICLE_OPERATOR_UNPACK( C_OP_RenderSprites )
  257. void C_OP_RenderSprites::InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  258. {
  259. }
  260. const SheetSequenceSample_t *GetSampleForSequence( CSheet *pSheet, float flCreationTime, float flCurTime, float flAgeScale, int nSequence )
  261. {
  262. if ( pSheet == NULL )
  263. return NULL;
  264. if ( pSheet->m_nNumFrames[nSequence] == 1 )
  265. return (const SheetSequenceSample_t *) &pSheet->m_pSamples[nSequence][0];
  266. float flAge = flCurTime - flCreationTime;
  267. flAge *= flAgeScale;
  268. unsigned int nFrame = flAge;
  269. if ( pSheet->m_bClamp[nSequence] )
  270. {
  271. nFrame = min( nFrame, (unsigned int)SEQUENCE_SAMPLE_COUNT-1 );
  272. }
  273. else
  274. {
  275. nFrame &= SEQUENCE_SAMPLE_COUNT-1;
  276. }
  277. return (const SheetSequenceSample_t *) &pSheet->m_pSamples[nSequence][nFrame];
  278. }
  279. int C_OP_RenderSprites::GetParticlesToRender( CParticleCollection *pParticles,
  280. void *pContext, int nFirstParticle,
  281. int nRemainingVertices, int nRemainingIndices,
  282. int *pVertsUsed, int *pIndicesUsed ) const
  283. {
  284. int nMaxParticles = ( (nRemainingVertices / 4) > (nRemainingIndices / 6) ) ? nRemainingIndices / 6 : nRemainingVertices / 4;
  285. int nParticleCount = pParticles->m_nActiveParticles - nFirstParticle;
  286. if ( nParticleCount > nMaxParticles )
  287. {
  288. nParticleCount = nMaxParticles;
  289. }
  290. *pVertsUsed = nParticleCount * 4;
  291. *pIndicesUsed = nParticleCount * 6;
  292. return nParticleCount;
  293. }
  294. void C_OP_RenderSprites::RenderNonSpriteCardCameraFacing( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, IMaterial *pMaterial ) const
  295. {
  296. C_OP_RenderSpritesContext_t *pCtx = reinterpret_cast<C_OP_RenderSpritesContext_t *>( pContext );
  297. // generate the sort list before this code starts messing with the matrices
  298. int nParticles;
  299. const ParticleRenderData_t *pSortList = pParticles->GetRenderList( pRenderContext, true, &nParticles, &pCtx->m_VisibilityData );
  300. bool bCameraBias = ( &pCtx->m_VisibilityData )->m_flCameraBias != 0.0f;
  301. float flCameraBias = (&pCtx->m_VisibilityData )->m_flCameraBias;
  302. Vector vecCamera;
  303. pRenderContext->GetWorldSpaceCameraPosition( &vecCamera );
  304. // NOTE: This is interesting to support because at first we won't have all the various
  305. // pixel-shader versions of SpriteCard, like modulate, twotexture, etc. etc.
  306. VMatrix tempView;
  307. // Store matrices off so we can restore them in RenderEnd().
  308. pRenderContext->GetMatrix(MATERIAL_VIEW, &tempView);
  309. // Force the user clip planes to use the old view matrix
  310. pRenderContext->EnableUserClipTransformOverride( true );
  311. pRenderContext->UserClipTransform( tempView );
  312. // The particle renderers want to do things in camera space
  313. pRenderContext->MatrixMode( MATERIAL_VIEW );
  314. pRenderContext->PushMatrix();
  315. pRenderContext->LoadIdentity();
  316. size_t xyz_stride;
  317. const fltx4 *xyz = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_XYZ, &xyz_stride );
  318. size_t rot_stride;
  319. const fltx4 *pRot = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_ROTATION, &rot_stride );
  320. size_t rgb_stride;
  321. const fltx4 *pRGB = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_TINT_RGB, &rgb_stride );
  322. size_t ct_stride;
  323. const fltx4 *pCreationTimeStamp = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, &ct_stride );
  324. size_t seq_stride;
  325. const fltx4 *pSequenceNumber = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER, &seq_stride );
  326. size_t ld_stride;
  327. const fltx4 *pLifeDuration = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_LIFE_DURATION, &ld_stride );
  328. float flAgeScale;
  329. int nMaxParticlesInBatch = GetMaxParticlesPerBatch( pRenderContext, pMaterial, false );
  330. CSheet *pSheet = pParticles->m_Sheet();
  331. while ( nParticles )
  332. {
  333. int nParticlesInBatch = min( nMaxParticlesInBatch, nParticles );
  334. nParticles -= nParticlesInBatch;
  335. g_pParticleSystemMgr->TallyParticlesRendered( nParticlesInBatch * 4 );
  336. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  337. CMeshBuilder meshBuilder;
  338. meshBuilder.Begin( pMesh, MATERIAL_QUADS, nParticlesInBatch );
  339. for( int i = 0; i < nParticlesInBatch; i++ )
  340. {
  341. int hParticle = (--pSortList)->m_nIndex;
  342. int nGroup = hParticle / 4;
  343. int nOffset = hParticle & 0x3;
  344. unsigned char ac = pSortList->m_nAlpha;
  345. if ( ac == 0 )
  346. continue;
  347. int nColorIndex = nGroup * rgb_stride;
  348. float r = SubFloat( pRGB[nColorIndex], nOffset );
  349. float g = SubFloat( pRGB[nColorIndex+1], nOffset );
  350. float b = SubFloat( pRGB[nColorIndex+2], nOffset );
  351. Assert( IsFinite(r) && IsFinite(g) && IsFinite(b) );
  352. Assert( (r >= 0.0f) && (g >= 0.0f) && (b >= 0.0f) );
  353. Assert( (r <= 1.0f) && (g <= 1.0f) && (b <= 1.0f) );
  354. unsigned char rc = FastFToC( r );
  355. unsigned char gc = FastFToC( g );
  356. unsigned char bc = FastFToC( b );
  357. float rad = pSortList->m_flRadius;
  358. int nXYZIndex = nGroup * xyz_stride;
  359. Vector vecWorldPos( SubFloat( xyz[ nXYZIndex ], nOffset ), SubFloat( xyz[ nXYZIndex+1 ], nOffset ), SubFloat( xyz[ nXYZIndex+2 ], nOffset ) );
  360. // Move the Particle if their is a camerabias
  361. if ( bCameraBias )
  362. {
  363. Vector vEyeDir = vecCamera - vecWorldPos;
  364. VectorNormalizeFast( vEyeDir );
  365. vEyeDir *= flCameraBias;
  366. vecWorldPos += vEyeDir;
  367. }
  368. Vector vecViewPos;
  369. Vector3DMultiplyPosition( tempView, vecWorldPos, vecViewPos );
  370. if ( !IsFinite( vecViewPos.x ) )
  371. continue;
  372. float rot = SubFloat( pRot[ nGroup * rot_stride ], nOffset );
  373. float ca = (float)cos(rot);
  374. float sa = (float)sin(rot);
  375. // Find the sample for this frame
  376. const SheetSequenceSample_t *pSample = &s_DefaultSheetSequence;
  377. if ( pSheet )
  378. {
  379. if ( m_bFitCycleToLifetime )
  380. {
  381. float flLifetime = SubFloat( pLifeDuration[ nGroup * ld_stride ], nOffset );
  382. flAgeScale = ( flLifetime > 0.0f ) ? ( 1.0f / flLifetime ) * SEQUENCE_SAMPLE_COUNT : 0.0f;
  383. }
  384. else
  385. {
  386. flAgeScale = m_flAnimationRate * SEQUENCE_SAMPLE_COUNT;
  387. if ( m_bAnimateInFPS )
  388. {
  389. int nSequence = SubFloat( pSequenceNumber[ nGroup * seq_stride ], nOffset );
  390. flAgeScale = flAgeScale / pSheet->m_flFrameSpan[nSequence];
  391. }
  392. }
  393. pSample = GetSampleForSequence( pSheet,
  394. SubFloat( pCreationTimeStamp[ nGroup * ct_stride ], nOffset ),
  395. pParticles->m_flCurTime,
  396. flAgeScale,
  397. SubFloat( pSequenceNumber[ nGroup * seq_stride ], nOffset ) );
  398. }
  399. const SequenceSampleTextureCoords_t *pSample0 = &(pSample->m_TextureCoordData[0]);
  400. meshBuilder.Position3f( vecViewPos.x + (-ca + sa) * rad, vecViewPos.y + (-sa - ca) * rad, vecViewPos.z );
  401. meshBuilder.Color4ub( rc, gc, bc, ac );
  402. meshBuilder.TexCoord2f( 0, pSample0->m_fLeft_U0, pSample0->m_fBottom_V0 );
  403. meshBuilder.AdvanceVertex();
  404. meshBuilder.Position3f( vecViewPos.x + (-ca - sa) * rad, vecViewPos.y + (-sa + ca) * rad, vecViewPos.z );
  405. meshBuilder.Color4ub( rc, gc, bc, ac );
  406. meshBuilder.TexCoord2f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0 );
  407. meshBuilder.AdvanceVertex();
  408. meshBuilder.Position3f( vecViewPos.x + (ca - sa) * rad, vecViewPos.y + (sa + ca) * rad, vecViewPos.z );
  409. meshBuilder.Color4ub( rc, gc, bc, ac );
  410. meshBuilder.TexCoord2f( 0, pSample0->m_fRight_U0, pSample0->m_fTop_V0 );
  411. meshBuilder.AdvanceVertex();
  412. meshBuilder.Position3f( vecViewPos.x + (ca + sa) * rad, vecViewPos.y + (sa - ca) * rad, vecViewPos.z );
  413. meshBuilder.Color4ub( rc, gc, bc, ac );
  414. meshBuilder.TexCoord2f( 0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  415. meshBuilder.AdvanceVertex();
  416. }
  417. meshBuilder.End();
  418. pMesh->Draw();
  419. }
  420. pRenderContext->EnableUserClipTransformOverride( false );
  421. pRenderContext->MatrixMode( MATERIAL_VIEW );
  422. pRenderContext->PopMatrix();
  423. }
  424. //-----------------------------------------------------------------------------
  425. // Purpose:
  426. //-----------------------------------------------------------------------------
  427. void C_OP_RenderSprites::RenderNonSpriteCardZRotating( CMeshBuilder &meshBuilder, C_OP_RenderSpritesContext_t *pCtx, SpriteRenderInfo_t& info, int hParticle, const Vector& vecCameraPos, ParticleRenderData_t const *pSortList ) const
  428. {
  429. Assert( hParticle != -1 );
  430. int nGroup = hParticle / 4;
  431. int nOffset = hParticle & 0x3;
  432. unsigned char ac = pSortList->m_nAlpha;
  433. if ( ac == 0 )
  434. return;
  435. bool bCameraBias = ( &pCtx->m_VisibilityData )->m_flCameraBias != 0.0f;
  436. float flCameraBias = ( &pCtx->m_VisibilityData )->m_flCameraBias;
  437. int nColorIndex = nGroup * info.m_nRGBStride;
  438. float r = SubFloat( info.m_pRGB[nColorIndex], nOffset );
  439. float g = SubFloat( info.m_pRGB[nColorIndex+1], nOffset );
  440. float b = SubFloat( info.m_pRGB[nColorIndex+2], nOffset );
  441. Assert( IsFinite(r) && IsFinite(g) && IsFinite(b) );
  442. Assert( (r >= 0.0f) && (g >= 0.0f) && (b >= 0.0f) );
  443. Assert( (r <= 1.0f) && (g <= 1.0f) && (b <= 1.0f) );
  444. unsigned char rc = FastFToC( r );
  445. unsigned char gc = FastFToC( g );
  446. unsigned char bc = FastFToC( b );
  447. float rad = pSortList->m_flRadius;
  448. float rot = SubFloat( info.m_pRot[ nGroup * info.m_nRotStride ], nOffset );
  449. float ca = (float)cos(-rot);
  450. float sa = (float)sin(-rot);
  451. int nXYZIndex = nGroup * info.m_nXYZStride;
  452. Vector vecWorldPos( SubFloat( info.m_pXYZ[ nXYZIndex ], nOffset ), SubFloat( info.m_pXYZ[ nXYZIndex+1 ], nOffset ), SubFloat( info.m_pXYZ[ nXYZIndex+2 ], nOffset ) );
  453. // Move the Particle if their is a camerabias
  454. if ( bCameraBias )
  455. {
  456. Vector vEyeDir = vecCameraPos - vecWorldPos;
  457. VectorNormalizeFast( vEyeDir );
  458. vEyeDir *= flCameraBias;
  459. vecWorldPos += vEyeDir;
  460. }
  461. Vector vecViewToPos;
  462. VectorSubtract( vecWorldPos, vecCameraPos, vecViewToPos );
  463. float flLength = vecViewToPos.Length();
  464. if ( flLength < rad / 2 )
  465. return;
  466. Vector vecUp( 0, 0, 1 );
  467. Vector vecRight;
  468. CrossProduct( vecUp, vecCameraPos, vecRight );
  469. VectorNormalize( vecRight );
  470. // Find the sample for this frame
  471. const SheetSequenceSample_t *pSample = &s_DefaultSheetSequence;
  472. if ( info.m_pSheet )
  473. {
  474. pSample = GetSampleForSequence( info.m_pSheet,
  475. SubFloat( info.m_pCreationTimeStamp[ nGroup * info.m_nCreationTimeStride ], nOffset ),
  476. info.m_pParticles->m_flCurTime,
  477. info.m_flAgeScale,
  478. SubFloat( info.m_pSequenceNumber[ nGroup * info.m_nSequenceStride ], nOffset ) );
  479. }
  480. const SequenceSampleTextureCoords_t *pSample0 = &(pSample->m_TextureCoordData[0]);
  481. vecRight *= rad;
  482. float x, y;
  483. Vector vecCorner;
  484. x = - ca - sa; y = - ca + sa;
  485. VectorMA( vecWorldPos, x, vecRight, vecCorner );
  486. meshBuilder.Position3f( vecCorner.x, vecCorner.y, vecCorner.z + y * rad );
  487. meshBuilder.Color4ub( rc, gc, bc, ac );
  488. meshBuilder.TexCoord2f( 0, pSample0->m_fLeft_U0, pSample0->m_fBottom_V0 );
  489. meshBuilder.AdvanceVertex();
  490. x = - ca + sa; y = + ca + sa;
  491. VectorMA( vecWorldPos, x, vecRight, vecCorner );
  492. meshBuilder.Position3f( vecCorner.x, vecCorner.y, vecCorner.z + y * rad );
  493. meshBuilder.Color4ub( rc, gc, bc, ac );
  494. meshBuilder.TexCoord2f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0 );
  495. meshBuilder.AdvanceVertex();
  496. x = + ca + sa; y = + ca - sa;
  497. VectorMA( vecWorldPos, x, vecRight, vecCorner );
  498. meshBuilder.Position3f( vecCorner.x, vecCorner.y, vecCorner.z + y * rad );
  499. meshBuilder.Color4ub( rc, gc, bc, ac );
  500. meshBuilder.TexCoord2f( 0, pSample0->m_fRight_U0, pSample0->m_fTop_V0 );
  501. meshBuilder.AdvanceVertex();
  502. x = + ca - sa; y = - ca - sa;
  503. VectorMA( vecWorldPos, x, vecRight, vecCorner );
  504. meshBuilder.Position3f( vecCorner.x, vecCorner.y, vecCorner.z + y * rad );
  505. meshBuilder.Color4ub( rc, gc, bc, ac );
  506. meshBuilder.TexCoord2f( 0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  507. meshBuilder.AdvanceVertex();
  508. meshBuilder.FastIndex( info.m_nVertexOffset );
  509. meshBuilder.FastIndex( info.m_nVertexOffset + 1 );
  510. meshBuilder.FastIndex( info.m_nVertexOffset + 2 );
  511. meshBuilder.FastIndex( info.m_nVertexOffset );
  512. meshBuilder.FastIndex( info.m_nVertexOffset + 2 );
  513. meshBuilder.FastIndex( info.m_nVertexOffset + 3 );
  514. info.m_nVertexOffset += 4;
  515. }
  516. //-----------------------------------------------------------------------------
  517. // Purpose:
  518. //-----------------------------------------------------------------------------
  519. void C_OP_RenderSprites::RenderNonSpriteCardZRotating( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, IMaterial *pMaterial ) const
  520. {
  521. C_OP_RenderSpritesContext_t *pCtx = reinterpret_cast<C_OP_RenderSpritesContext_t *>( pContext );
  522. // NOTE: This is interesting to support because at first we won't have all the various
  523. // pixel-shader versions of SpriteCard, like modulate, twotexture, etc. etc.
  524. Vector vecCameraPos;
  525. pRenderContext->GetWorldSpaceCameraPosition( &vecCameraPos );
  526. float flAgeScale = m_flAnimationRate * SEQUENCE_SAMPLE_COUNT;
  527. SpriteRenderInfo_t info;
  528. info.Init( pParticles, 0, flAgeScale, 0, pParticles->m_Sheet() );
  529. int nParticles;
  530. const ParticleRenderData_t *pSortList = pParticles->GetRenderList( pRenderContext, true, &nParticles, &pCtx->m_VisibilityData );
  531. int nMaxParticlesInBatch = GetMaxParticlesPerBatch( pRenderContext, pMaterial, false );
  532. while ( nParticles )
  533. {
  534. int nParticlesInBatch = min( nMaxParticlesInBatch, nParticles );
  535. nParticles -= nParticlesInBatch;
  536. g_pParticleSystemMgr->TallyParticlesRendered( nParticlesInBatch * 4 * 3, nParticlesInBatch * 6 * 3 );
  537. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  538. CMeshBuilder meshBuilder;
  539. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nParticlesInBatch * 4, nParticlesInBatch * 6 );
  540. info.m_nVertexOffset = 0;
  541. for( int i = 0; i < nParticlesInBatch; i++ )
  542. {
  543. int hParticle = (--pSortList)->m_nIndex;
  544. RenderNonSpriteCardZRotating( meshBuilder, pCtx, info, hParticle, vecCameraPos, pSortList );
  545. }
  546. meshBuilder.End();
  547. pMesh->Draw();
  548. }
  549. }
  550. void C_OP_RenderSprites::RenderUnsortedNonSpriteCardZRotating( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const
  551. {
  552. C_OP_RenderSpritesContext_t *pCtx = reinterpret_cast<C_OP_RenderSpritesContext_t *>( pContext );
  553. // NOTE: This is interesting to support because at first we won't have all the various
  554. // pixel-shader versions of SpriteCard, like modulate, twotexture, etc. etc.
  555. Vector vecCameraPos;
  556. pRenderContext->GetWorldSpaceCameraPosition( &vecCameraPos );
  557. float flAgeScale = m_flAnimationRate * SEQUENCE_SAMPLE_COUNT;
  558. SpriteRenderInfo_t info;
  559. info.Init( pParticles, nVertexOffset, flAgeScale, 0, pParticles->m_Sheet() );
  560. int nParticles;
  561. const ParticleRenderData_t *pSortList = pParticles->GetRenderList( pRenderContext, false, &nParticles, &pCtx->m_VisibilityData );
  562. int hParticle = nFirstParticle;
  563. for( int i = 0; i < nParticleCount; i++, hParticle++ )
  564. {
  565. RenderNonSpriteCardZRotating( meshBuilder, pCtx, info, hParticle, vecCameraPos, pSortList );
  566. }
  567. }
  568. //-----------------------------------------------------------------------------
  569. // Purpose:
  570. //-----------------------------------------------------------------------------
  571. void C_OP_RenderSprites::RenderNonSpriteCardOriented(
  572. CMeshBuilder &meshBuilder, C_OP_RenderSpritesContext_t *pCtx, SpriteRenderInfo_t& info, int hParticle, const Vector& vecCameraPos, ParticleRenderData_t const *pSortList, bool bUseYaw ) const
  573. {
  574. Assert( hParticle != -1 );
  575. int nGroup = hParticle / 4;
  576. int nOffset = hParticle & 0x3;
  577. unsigned char ac = pSortList->m_nAlpha;
  578. if ( ac == 0 )
  579. return;
  580. bool bCameraBias = ( &pCtx->m_VisibilityData )->m_flCameraBias != 0.0f;
  581. float flCameraBias = ( &pCtx->m_VisibilityData )->m_flCameraBias;
  582. int nColorIndex = nGroup * info.m_nRGBStride;
  583. float r = SubFloat( info.m_pRGB[nColorIndex], nOffset );
  584. float g = SubFloat( info.m_pRGB[nColorIndex+1], nOffset );
  585. float b = SubFloat( info.m_pRGB[nColorIndex+2], nOffset );
  586. Assert( IsFinite(r) && IsFinite(g) && IsFinite(b) );
  587. Assert( (r >= 0.0f) && (g >= 0.0f) && (b >= 0.0f) );
  588. Assert( (r <= 1.0f) && (g <= 1.0f) && (b <= 1.0f) );
  589. unsigned char rc = FastFToC( r );
  590. unsigned char gc = FastFToC( g );
  591. unsigned char bc = FastFToC( b );
  592. float rad = pSortList->m_flRadius;
  593. float rot = SubFloat( info.m_pRot[ nGroup * info.m_nRotStride ], nOffset );
  594. float ca = (float)cos(-rot);
  595. float sa = (float)sin(-rot);
  596. int nXYZIndex = nGroup * info.m_nXYZStride;
  597. Vector vecWorldPos( SubFloat( info.m_pXYZ[ nXYZIndex ], nOffset ), SubFloat( info.m_pXYZ[ nXYZIndex+1 ], nOffset ), SubFloat( info.m_pXYZ[ nXYZIndex+2 ], nOffset ) );
  598. // Move the Particle if their is a camerabias
  599. if ( bCameraBias )
  600. {
  601. Vector vEyeDir = vecCameraPos - vecWorldPos;
  602. VectorNormalizeFast( vEyeDir );
  603. vEyeDir *= flCameraBias;
  604. vecWorldPos += vEyeDir;
  605. }
  606. Vector vecViewToPos;
  607. VectorSubtract( vecWorldPos, vecCameraPos, vecViewToPos );
  608. float flLength = vecViewToPos.Length();
  609. if ( flLength < rad / 2 )
  610. return;
  611. Vector vecNormal, vecRight, vecUp;
  612. if ( m_nOrientationControlPoint < 0 )
  613. {
  614. vecNormal.Init( 0, 0, 1 );
  615. vecRight.Init( 1, 0, 0 );
  616. vecUp.Init( 0, -1, 0 );
  617. }
  618. else
  619. {
  620. info.m_pParticles->GetControlPointOrientationAtCurrentTime(
  621. m_nOrientationControlPoint, &vecRight, &vecUp, &vecNormal );
  622. }
  623. if ( bUseYaw )
  624. {
  625. float yaw = SubFloat( info.m_pYaw[nGroup * info.m_nYawStride], nOffset );
  626. if ( yaw != 0.0f )
  627. {
  628. Vector particleRight = Vector( 1, 0, 0 );
  629. yaw = RAD2DEG( yaw ); // I hate you source (VectorYawRotate will undo this)
  630. matrix3x4_t matRot;
  631. MatrixBuildRotationAboutAxis( vecUp, yaw, matRot );
  632. VectorRotate( vecRight, matRot, particleRight );
  633. vecRight = particleRight;
  634. }
  635. }
  636. // Find the sample for this frame
  637. const SheetSequenceSample_t *pSample = &s_DefaultSheetSequence;
  638. if ( info.m_pSheet )
  639. {
  640. pSample = GetSampleForSequence( info.m_pSheet,
  641. SubFloat( info.m_pCreationTimeStamp[ nGroup * info.m_nCreationTimeStride ], nOffset ),
  642. info.m_pParticles->m_flCurTime,
  643. info.m_flAgeScale,
  644. SubFloat( info.m_pSequenceNumber[ nGroup * info.m_nSequenceStride ], nOffset ) );
  645. }
  646. const SequenceSampleTextureCoords_t *pSample0 = &(pSample->m_TextureCoordData[0]);
  647. vecRight *= rad;
  648. vecUp *= rad;
  649. float x, y;
  650. Vector vecCorner;
  651. x = + ca - sa; y = - ca - sa;
  652. VectorMA( vecWorldPos, x, vecRight, vecCorner );
  653. VectorMA( vecCorner, y, vecUp, vecCorner );
  654. meshBuilder.Position3f( vecCorner.x, vecCorner.y, vecCorner.z );
  655. meshBuilder.Color4ub( rc, gc, bc, ac );
  656. meshBuilder.TexCoord2f( 0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  657. meshBuilder.AdvanceVertex();
  658. x = + ca + sa; y = + ca - sa;
  659. VectorMA( vecWorldPos, x, vecRight, vecCorner );
  660. VectorMA( vecCorner, y, vecUp, vecCorner );
  661. meshBuilder.Position3f( vecCorner.x, vecCorner.y, vecCorner.z );
  662. meshBuilder.Color4ub( rc, gc, bc, ac );
  663. meshBuilder.TexCoord2f( 0, pSample0->m_fRight_U0, pSample0->m_fTop_V0 );
  664. meshBuilder.AdvanceVertex();
  665. x = - ca + sa; y = + ca + sa;
  666. VectorMA( vecWorldPos, x, vecRight, vecCorner );
  667. VectorMA( vecCorner, y, vecUp, vecCorner );
  668. meshBuilder.Position3f( vecCorner.x, vecCorner.y, vecCorner.z );
  669. meshBuilder.Color4ub( rc, gc, bc, ac );
  670. meshBuilder.TexCoord2f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0 );
  671. meshBuilder.AdvanceVertex();
  672. x = - ca - sa; y = - ca + sa;
  673. VectorMA( vecWorldPos, x, vecRight, vecCorner );
  674. VectorMA( vecCorner, y, vecUp, vecCorner );
  675. meshBuilder.Position3f( vecCorner.x, vecCorner.y, vecCorner.z );
  676. meshBuilder.Color4ub( rc, gc, bc, ac );
  677. meshBuilder.TexCoord2f( 0, pSample0->m_fLeft_U0, pSample0->m_fBottom_V0 );
  678. meshBuilder.AdvanceVertex();
  679. meshBuilder.FastIndex( info.m_nVertexOffset );
  680. meshBuilder.FastIndex( info.m_nVertexOffset + 1 );
  681. meshBuilder.FastIndex( info.m_nVertexOffset + 2 );
  682. meshBuilder.FastIndex( info.m_nVertexOffset );
  683. meshBuilder.FastIndex( info.m_nVertexOffset + 2 );
  684. meshBuilder.FastIndex( info.m_nVertexOffset + 3 );
  685. info.m_nVertexOffset += 4;
  686. }
  687. void C_OP_RenderSprites::RenderNonSpriteCardOriented( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, IMaterial *pMaterial, bool bUseYaw ) const
  688. {
  689. C_OP_RenderSpritesContext_t *pCtx = reinterpret_cast<C_OP_RenderSpritesContext_t *>( pContext );
  690. // NOTE: This is interesting to support because at first we won't have all the various
  691. // pixel-shader versions of SpriteCard, like modulate, twotexture, etc. etc.
  692. Vector vecCameraPos;
  693. pRenderContext->GetWorldSpaceCameraPosition( &vecCameraPos );
  694. float flAgeScale = m_flAnimationRate * SEQUENCE_SAMPLE_COUNT;
  695. SpriteRenderInfo_t info;
  696. info.Init( pParticles, 0, flAgeScale, 0, pParticles->m_Sheet() );
  697. int nParticles;
  698. const ParticleRenderData_t *pSortList = pParticles->GetRenderList( pRenderContext, true, &nParticles, &pCtx->m_VisibilityData );
  699. int nMaxParticlesInBatch = GetMaxParticlesPerBatch( pRenderContext, pMaterial, false );
  700. while ( nParticles )
  701. {
  702. int nParticlesInBatch = min( nMaxParticlesInBatch, nParticles );
  703. nParticles -= nParticlesInBatch;
  704. g_pParticleSystemMgr->TallyParticlesRendered( nParticlesInBatch * 4 * 3, nParticlesInBatch * 6 * 3 );
  705. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  706. CMeshBuilder meshBuilder;
  707. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nParticlesInBatch * 4, nParticlesInBatch * 6 );
  708. info.m_nVertexOffset = 0;
  709. for( int i = 0; i < nParticlesInBatch; i++)
  710. {
  711. int hParticle = (--pSortList)->m_nIndex;
  712. RenderNonSpriteCardOriented( meshBuilder, pCtx, info, hParticle, vecCameraPos, pSortList, bUseYaw );
  713. }
  714. meshBuilder.End();
  715. pMesh->Draw();
  716. }
  717. }
  718. void C_OP_RenderSprites::RenderUnsortedNonSpriteCardOriented( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const
  719. {
  720. C_OP_RenderSpritesContext_t *pCtx = reinterpret_cast<C_OP_RenderSpritesContext_t *>( pContext );
  721. // NOTE: This is interesting to support because at first we won't have all the various
  722. // pixel-shader versions of SpriteCard, like modulate, twotexture, etc. etc.
  723. Vector vecCameraPos;
  724. pRenderContext->GetWorldSpaceCameraPosition( &vecCameraPos );
  725. float flAgeScale = m_flAnimationRate * SEQUENCE_SAMPLE_COUNT;
  726. SpriteRenderInfo_t info;
  727. info.Init( pParticles, nVertexOffset, flAgeScale, 0, pParticles->m_Sheet() );
  728. int nParticles;
  729. const ParticleRenderData_t *pSortList = pParticles->GetRenderList( pRenderContext, false, &nParticles, &pCtx->m_VisibilityData );
  730. int hParticle = nFirstParticle;
  731. for( int i = 0; i < nParticleCount; i++, hParticle++ )
  732. {
  733. RenderNonSpriteCardOriented( meshBuilder, pCtx, info, hParticle, vecCameraPos, pSortList, false );
  734. }
  735. }
  736. void C_OP_RenderSprites::RenderSpriteCard( CMeshBuilder &meshBuilder, C_OP_RenderSpritesContext_t *pCtx, SpriteRenderInfo_t& info, int hParticle, ParticleRenderData_t const *pSortList, Vector *pCamera ) const
  737. {
  738. Assert( hParticle != -1 );
  739. int nGroup = hParticle / 4;
  740. int nOffset = hParticle & 0x3;
  741. int nColorIndex = nGroup * info.m_nRGBStride;
  742. float r = SubFloat( info.m_pRGB[nColorIndex], nOffset );
  743. float g = SubFloat( info.m_pRGB[nColorIndex+1], nOffset );
  744. float b = SubFloat( info.m_pRGB[nColorIndex+2], nOffset );
  745. Assert( IsFinite(r) && IsFinite(g) && IsFinite(b) );
  746. Assert( (r >= -1e-6f) && (g >= -1e-6f) && (b >= -1e-6f) );
  747. if ( !HushAsserts() )
  748. Assert( (r <= 1.0f) && (g <= 1.0f) && (b <= 1.0f) );
  749. unsigned char rc = FastFToC( r );
  750. unsigned char gc = FastFToC( g );
  751. unsigned char bc = FastFToC( b );
  752. unsigned char ac = pSortList->m_nAlpha;
  753. float rad = pSortList->m_flRadius;
  754. if ( !IsFinite( rad ) )
  755. {
  756. return;
  757. }
  758. bool bCameraBias = ( &pCtx->m_VisibilityData )->m_flCameraBias != 0.0f;
  759. float flCameraBias = ( &pCtx->m_VisibilityData )->m_flCameraBias;
  760. float rot = SubFloat( info.m_pRot[ nGroup * info.m_nRotStride ], nOffset );
  761. float yaw = SubFloat( info.m_pYaw[ nGroup * info.m_nYawStride ], nOffset );
  762. int nXYZIndex = nGroup * info.m_nXYZStride;
  763. Vector vecWorldPos;
  764. vecWorldPos.x = SubFloat( info.m_pXYZ[ nXYZIndex ], nOffset );
  765. vecWorldPos.y = SubFloat( info.m_pXYZ[ nXYZIndex+1 ], nOffset );
  766. vecWorldPos.z = SubFloat( info.m_pXYZ[ nXYZIndex+2 ], nOffset );
  767. if ( bCameraBias )
  768. {
  769. Vector vEyeDir = *pCamera - vecWorldPos;
  770. VectorNormalizeFast( vEyeDir );
  771. vEyeDir *= flCameraBias;
  772. vecWorldPos += vEyeDir;
  773. }
  774. // Find the sample for this frame
  775. const SheetSequenceSample_t *pSample = &s_DefaultSheetSequence;
  776. if ( info.m_pSheet )
  777. {
  778. float flAgeScale = info.m_flAgeScale;
  779. // if ( m_bFitCycleToLifetime )
  780. // {
  781. // float flLifetime = SubFloat( pLifeDuration[ nGroup * ld_stride ], nOffset );
  782. // flAgeScale = ( flLifetime > 0.0f ) ? ( 1.0f / flLifetime ) * SEQUENCE_SAMPLE_COUNT : 0.0f;
  783. // }
  784. if ( m_bAnimateInFPS )
  785. {
  786. int nSequence = SubFloat( info.m_pSequenceNumber[ nGroup * info.m_nSequenceStride ], nOffset );
  787. flAgeScale = flAgeScale / info.m_pParticles->m_Sheet()->m_flFrameSpan[nSequence];
  788. }
  789. pSample = GetSampleForSequence( info.m_pSheet,
  790. SubFloat( info.m_pCreationTimeStamp[ nGroup * info.m_nCreationTimeStride ], nOffset ),
  791. info.m_pParticles->m_flCurTime,
  792. flAgeScale,
  793. SubFloat( info.m_pSequenceNumber[ nGroup * info.m_nSequenceStride ], nOffset ) );
  794. }
  795. const SequenceSampleTextureCoords_t *pSample0 = &(pSample->m_TextureCoordData[0]);
  796. const SequenceSampleTextureCoords_t *pSecondTexture0 = &(pSample->m_TextureCoordData[1]);
  797. // Submit 1 (instanced) or 4 (non-instanced) verts (if we're instancing, we don't produce indices either)
  798. meshBuilder.Position3f( vecWorldPos.x, vecWorldPos.y, vecWorldPos.z );
  799. meshBuilder.Color4ub( rc, gc, bc, ac );
  800. meshBuilder.TexCoord4f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  801. meshBuilder.TexCoord4f( 1, pSample0->m_fLeft_U1, pSample0->m_fTop_V1, pSample0->m_fRight_U1, pSample0->m_fBottom_V1 );
  802. meshBuilder.TexCoord4f( 2, pSample->m_fBlendFactor, rot, rad, yaw );
  803. // FIXME: change the vertex decl (remove texcoord3/cornerid) if instancing - need to adjust elements beyond texcoord3 down, though
  804. if ( !bUseInstancing )
  805. meshBuilder.TexCoord2f( 3, 0, 0 );
  806. meshBuilder.TexCoord4f( 4, pSecondTexture0->m_fLeft_U0, pSecondTexture0->m_fTop_V0, pSecondTexture0->m_fRight_U0, pSecondTexture0->m_fBottom_V0 );
  807. meshBuilder.AdvanceVertex();
  808. if ( !bUseInstancing )
  809. {
  810. meshBuilder.Position3f( vecWorldPos.x, vecWorldPos.y, vecWorldPos.z );
  811. meshBuilder.Color4ub( rc, gc, bc, ac );
  812. meshBuilder.TexCoord4f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  813. meshBuilder.TexCoord4f( 1, pSample0->m_fLeft_U1, pSample0->m_fTop_V1, pSample0->m_fRight_U1, pSample0->m_fBottom_V1 );
  814. meshBuilder.TexCoord4f( 2, pSample->m_fBlendFactor, rot, rad, yaw );
  815. meshBuilder.TexCoord2f( 3, 1, 0 );
  816. meshBuilder.TexCoord4f( 4, pSecondTexture0->m_fLeft_U0, pSecondTexture0->m_fTop_V0, pSecondTexture0->m_fRight_U0, pSecondTexture0->m_fBottom_V0 );
  817. meshBuilder.AdvanceVertex();
  818. meshBuilder.Position3f( vecWorldPos.x, vecWorldPos.y, vecWorldPos.z );
  819. meshBuilder.Color4ub( rc, gc, bc, ac );
  820. meshBuilder.TexCoord4f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  821. meshBuilder.TexCoord4f( 1, pSample0->m_fLeft_U1, pSample0->m_fTop_V1, pSample0->m_fRight_U1, pSample0->m_fBottom_V1 );
  822. meshBuilder.TexCoord4f( 2, pSample->m_fBlendFactor, rot, rad, yaw );
  823. meshBuilder.TexCoord2f( 3, 1, 1 );
  824. meshBuilder.TexCoord4f( 4, pSecondTexture0->m_fLeft_U0, pSecondTexture0->m_fTop_V0, pSecondTexture0->m_fRight_U0, pSecondTexture0->m_fBottom_V0 );
  825. meshBuilder.AdvanceVertex();
  826. meshBuilder.Position3f( vecWorldPos.x, vecWorldPos.y, vecWorldPos.z );
  827. meshBuilder.Color4ub( rc, gc, bc, ac );
  828. meshBuilder.TexCoord4f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  829. meshBuilder.TexCoord4f( 1, pSample0->m_fLeft_U1, pSample0->m_fTop_V1, pSample0->m_fRight_U1, pSample0->m_fBottom_V1 );
  830. meshBuilder.TexCoord4f( 2, pSample->m_fBlendFactor, rot, rad, yaw );
  831. meshBuilder.TexCoord2f( 3, 0, 1 );
  832. meshBuilder.TexCoord4f( 4, pSecondTexture0->m_fLeft_U0, pSecondTexture0->m_fTop_V0, pSecondTexture0->m_fRight_U0, pSecondTexture0->m_fBottom_V0 );
  833. meshBuilder.AdvanceVertex();
  834. meshBuilder.FastIndex( info.m_nVertexOffset );
  835. meshBuilder.FastIndex( info.m_nVertexOffset + 1 );
  836. meshBuilder.FastIndex( info.m_nVertexOffset + 2 );
  837. meshBuilder.FastIndex( info.m_nVertexOffset );
  838. meshBuilder.FastIndex( info.m_nVertexOffset + 2 );
  839. meshBuilder.FastIndex( info.m_nVertexOffset + 3 );
  840. info.m_nVertexOffset += 4;
  841. }
  842. }
  843. void C_OP_RenderSprites::RenderTwoSequenceSpriteCard( CMeshBuilder &meshBuilder, C_OP_RenderSpritesContext_t *pCtx, SpriteRenderInfo_t& info, int hParticle, ParticleRenderData_t const *pSortList, Vector *pCamera ) const
  844. {
  845. Assert( hParticle != -1 );
  846. int nGroup = hParticle / 4;
  847. int nOffset = hParticle & 0x3;
  848. int nColorIndex = nGroup * info.m_nRGBStride;
  849. float r = SubFloat( info.m_pRGB[nColorIndex], nOffset );
  850. float g = SubFloat( info.m_pRGB[nColorIndex+1], nOffset );
  851. float b = SubFloat( info.m_pRGB[nColorIndex+2], nOffset );
  852. Assert( IsFinite(r) && IsFinite(g) && IsFinite(b) );
  853. Assert( (r >= 0.0f) && (g >= 0.0f) && (b >= 0.0f) );
  854. Assert( (r <= 1.0f) && (g <= 1.0f) && (b <= 1.0f) );
  855. unsigned char rc = FastFToC( r );
  856. unsigned char gc = FastFToC( g );
  857. unsigned char bc = FastFToC( b );
  858. unsigned char ac = pSortList->m_nAlpha;
  859. bool bCameraBias = ( &pCtx->m_VisibilityData )->m_flCameraBias != 0.0f;
  860. float flCameraBias = ( &pCtx->m_VisibilityData )->m_flCameraBias;
  861. float rad = pSortList->m_flRadius;
  862. float rot = SubFloat( info.m_pRot[ nGroup * info.m_nRotStride ], nOffset );
  863. float yaw = SubFloat( info.m_pYaw[ nGroup * info.m_nYawStride ], nOffset );
  864. int nXYZIndex = nGroup * info.m_nXYZStride;
  865. Vector vecWorldPos;
  866. vecWorldPos.x = SubFloat( info.m_pXYZ[ nXYZIndex ], nOffset );
  867. vecWorldPos.y = SubFloat( info.m_pXYZ[ nXYZIndex+1 ], nOffset );
  868. vecWorldPos.z = SubFloat( info.m_pXYZ[ nXYZIndex+2 ], nOffset );
  869. if ( bCameraBias )
  870. {
  871. Vector vEyeDir = *pCamera - vecWorldPos;
  872. VectorNormalizeFast( vEyeDir );
  873. vEyeDir *= flCameraBias;
  874. vecWorldPos += vEyeDir;
  875. }
  876. // Find the sample for this frame
  877. const SheetSequenceSample_t *pSample = &s_DefaultSheetSequence;
  878. const SheetSequenceSample_t *pSample1 = &s_DefaultSheetSequence;
  879. if ( info.m_pSheet )
  880. {
  881. pSample = GetSampleForSequence( info.m_pSheet,
  882. SubFloat( info.m_pCreationTimeStamp[ nGroup * info.m_nCreationTimeStride ], nOffset ),
  883. info.m_pParticles->m_flCurTime,
  884. info.m_flAgeScale,
  885. SubFloat( info.m_pSequenceNumber[ nGroup * info.m_nSequenceStride ], nOffset ) );
  886. pSample1 = GetSampleForSequence( info.m_pSheet,
  887. SubFloat( info.m_pCreationTimeStamp[ nGroup * info.m_nCreationTimeStride ], nOffset ),
  888. info.m_pParticles->m_flCurTime,
  889. info.m_flAgeScale2,
  890. SubFloat( info.m_pSequence1Number[ nGroup * info.m_nSequence1Stride ], nOffset ) );
  891. }
  892. const SequenceSampleTextureCoords_t *pSample0 = &(pSample->m_TextureCoordData[0]);
  893. const SequenceSampleTextureCoords_t *pSecondTexture0 = &(pSample->m_TextureCoordData[1]);
  894. const SequenceSampleTextureCoords_t *pSample1Frame = &(pSample1->m_TextureCoordData[0]);
  895. // Submit 1 (instanced) or 4 (non-instanced) verts (if we're instancing, we don't produce indices either)
  896. meshBuilder.Position3f( vecWorldPos.x, vecWorldPos.y, vecWorldPos.z );
  897. meshBuilder.Color4ub( rc, gc, bc, ac );
  898. meshBuilder.TexCoord4f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  899. meshBuilder.TexCoord4f( 1, pSample0->m_fLeft_U1, pSample0->m_fTop_V1, pSample0->m_fRight_U1, pSample0->m_fBottom_V1 );
  900. meshBuilder.TexCoord4f( 2, pSample->m_fBlendFactor, rot, rad, yaw );
  901. // FIXME: change the vertex decl (remove texcoord3/cornerid) if instancing - need to adjust elements beyond texcoord3 down, though
  902. if ( ! bUseInstancing )
  903. meshBuilder.TexCoord2f( 3, 0, 0 );
  904. meshBuilder.TexCoord4f( 4, pSecondTexture0->m_fLeft_U0, pSecondTexture0->m_fTop_V0, pSecondTexture0->m_fRight_U0, pSecondTexture0->m_fBottom_V0 );
  905. meshBuilder.TexCoord4f( 5, pSample1Frame->m_fLeft_U0, pSample1Frame->m_fTop_V0, pSample1Frame->m_fRight_U0, pSample1Frame->m_fBottom_V0 );
  906. meshBuilder.TexCoord4f( 6, pSample1Frame->m_fLeft_U1, pSample1Frame->m_fTop_V1, pSample1Frame->m_fRight_U1, pSample1Frame->m_fBottom_V1 );
  907. meshBuilder.TexCoord4f( 7, pSample1->m_fBlendFactor, 0, 0, 0 );
  908. meshBuilder.AdvanceVertex();
  909. if ( !bUseInstancing )
  910. {
  911. meshBuilder.Position3f( vecWorldPos.x, vecWorldPos.y, vecWorldPos.z );
  912. meshBuilder.Color4ub( rc, gc, bc, ac );
  913. meshBuilder.TexCoord4f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  914. meshBuilder.TexCoord4f( 1, pSample0->m_fLeft_U1, pSample0->m_fTop_V1, pSample0->m_fRight_U1, pSample0->m_fBottom_V1 );
  915. meshBuilder.TexCoord4f( 2, pSample->m_fBlendFactor, rot, rad, yaw );
  916. meshBuilder.TexCoord2f( 3, 1, 0 );
  917. meshBuilder.TexCoord4f( 4, pSecondTexture0->m_fLeft_U0, pSecondTexture0->m_fTop_V0, pSecondTexture0->m_fRight_U0, pSecondTexture0->m_fBottom_V0 );
  918. meshBuilder.TexCoord4f( 5, pSample1Frame->m_fLeft_U0, pSample1Frame->m_fTop_V0, pSample1Frame->m_fRight_U0, pSample1Frame->m_fBottom_V0 );
  919. meshBuilder.TexCoord4f( 6, pSample1Frame->m_fLeft_U1, pSample1Frame->m_fTop_V1, pSample1Frame->m_fRight_U1, pSample1Frame->m_fBottom_V1 );
  920. meshBuilder.TexCoord4f( 7, pSample1->m_fBlendFactor, 0, 0, 0 );
  921. meshBuilder.AdvanceVertex();
  922. meshBuilder.Position3f( vecWorldPos.x, vecWorldPos.y, vecWorldPos.z );
  923. meshBuilder.Color4ub( rc, gc, bc, ac );
  924. meshBuilder.TexCoord4f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  925. meshBuilder.TexCoord4f( 1, pSample0->m_fLeft_U1, pSample0->m_fTop_V1, pSample0->m_fRight_U1, pSample0->m_fBottom_V1 );
  926. meshBuilder.TexCoord4f( 2, pSample->m_fBlendFactor, rot, rad, yaw );
  927. meshBuilder.TexCoord2f( 3, 1, 1 );
  928. meshBuilder.TexCoord4f( 4, pSecondTexture0->m_fLeft_U0, pSecondTexture0->m_fTop_V0, pSecondTexture0->m_fRight_U0, pSecondTexture0->m_fBottom_V0 );
  929. meshBuilder.TexCoord4f( 5, pSample1Frame->m_fLeft_U0, pSample1Frame->m_fTop_V0, pSample1Frame->m_fRight_U0, pSample1Frame->m_fBottom_V0 );
  930. meshBuilder.TexCoord4f( 6, pSample1Frame->m_fLeft_U1, pSample1Frame->m_fTop_V1, pSample1Frame->m_fRight_U1, pSample1Frame->m_fBottom_V1 );
  931. meshBuilder.TexCoord4f( 7, pSample1->m_fBlendFactor, 0, 0, 0 );
  932. meshBuilder.AdvanceVertex();
  933. meshBuilder.Position3f( vecWorldPos.x, vecWorldPos.y, vecWorldPos.z );
  934. meshBuilder.Color4ub( rc, gc, bc, ac );
  935. meshBuilder.TexCoord4f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  936. meshBuilder.TexCoord4f( 1, pSample0->m_fLeft_U1, pSample0->m_fTop_V1, pSample0->m_fRight_U1, pSample0->m_fBottom_V1 );
  937. meshBuilder.TexCoord4f( 2, pSample->m_fBlendFactor, rot, rad, yaw );
  938. meshBuilder.TexCoord2f( 3, 0, 1 );
  939. meshBuilder.TexCoord4f( 4, pSecondTexture0->m_fLeft_U0, pSecondTexture0->m_fTop_V0, pSecondTexture0->m_fRight_U0, pSecondTexture0->m_fBottom_V0 );
  940. meshBuilder.TexCoord4f( 5, pSample1Frame->m_fLeft_U0, pSample1Frame->m_fTop_V0, pSample1Frame->m_fRight_U0, pSample1Frame->m_fBottom_V0 );
  941. meshBuilder.TexCoord4f( 6, pSample1Frame->m_fLeft_U1, pSample1Frame->m_fTop_V1, pSample1Frame->m_fRight_U1, pSample1Frame->m_fBottom_V1 );
  942. meshBuilder.TexCoord4f( 7, pSample1->m_fBlendFactor, 0, 0, 0 );
  943. meshBuilder.AdvanceVertex();
  944. meshBuilder.FastIndex( info.m_nVertexOffset );
  945. meshBuilder.FastIndex( info.m_nVertexOffset + 1 );
  946. meshBuilder.FastIndex( info.m_nVertexOffset + 2 );
  947. meshBuilder.FastIndex( info.m_nVertexOffset );
  948. meshBuilder.FastIndex( info.m_nVertexOffset + 2 );
  949. meshBuilder.FastIndex( info.m_nVertexOffset + 3 );
  950. info.m_nVertexOffset += 4;
  951. }
  952. }
  953. //-----------------------------------------------------------------------------
  954. // Purpose:
  955. //-----------------------------------------------------------------------------
  956. void C_OP_RenderSprites::Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, void *pContext ) const
  957. {
  958. IMaterial *pMaterial = pParticles->m_pDef->GetMaterial();
  959. C_OP_RenderSpritesContext_t *pCtx = reinterpret_cast<C_OP_RenderSpritesContext_t *>( pContext );
  960. if ( pCtx->m_VisibilityData.m_bUseVisibility )
  961. {
  962. SetupParticleVisibility( pParticles, &pCtx->m_VisibilityData, &VisibilityInputs, &pCtx->m_nQueryHandle );
  963. }
  964. IMaterialVar* pVar = pMaterial->FindVarFast( "$orientation", &pCtx->m_nOrientationVarToken );
  965. if ( pVar )
  966. {
  967. pVar->SetIntValue( m_nOrientationType );
  968. }
  969. pRenderContext->Bind( pMaterial );
  970. if ( !pMaterial->IsSpriteCard() )
  971. {
  972. switch( m_nOrientationType )
  973. {
  974. case 0:
  975. RenderNonSpriteCardCameraFacing( pParticles, pContext, pRenderContext, pMaterial );
  976. break;
  977. case 1:
  978. RenderNonSpriteCardZRotating( pParticles, pContext, pRenderContext, pMaterial );
  979. break;
  980. case 2:
  981. RenderNonSpriteCardOriented( pParticles, pContext, pRenderContext, pMaterial, false );
  982. break;
  983. case 3:
  984. RenderNonSpriteCardOriented( pParticles, pContext, pRenderContext, pMaterial, true );
  985. break;
  986. }
  987. return;
  988. }
  989. if ( m_nOrientationType == 2 )
  990. {
  991. pVar = pMaterial->FindVarFast( "$orientationMatrix", &pCtx->m_nOrientationMatrixVarToken );
  992. if ( pVar )
  993. {
  994. VMatrix mat;
  995. if ( m_nOrientationControlPoint < 0 )
  996. {
  997. MatrixSetIdentity( mat );
  998. }
  999. else
  1000. {
  1001. pParticles->GetControlPointTransformAtCurrentTime( m_nOrientationControlPoint, &mat );
  1002. }
  1003. pVar->SetMatrixValue( mat );
  1004. }
  1005. }
  1006. float flAgeScale = m_flAnimationRate * SEQUENCE_SAMPLE_COUNT;
  1007. float flAgeScale2 = m_flAnimationRate2 * SEQUENCE_SAMPLE_COUNT;
  1008. SpriteRenderInfo_t info;
  1009. info.Init( pParticles, 0, flAgeScale, flAgeScale2, pParticles->m_Sheet() );
  1010. MaterialPrimitiveType_t primType = bUseInstancing ? MATERIAL_INSTANCED_QUADS : MATERIAL_TRIANGLES;
  1011. int nMaxParticlesInBatch = GetMaxParticlesPerBatch( pRenderContext, pMaterial, bUseInstancing );
  1012. int nParticles;
  1013. const ParticleRenderData_t *pSortList = pParticles->GetRenderList( pRenderContext, true, &nParticles, &pCtx->m_VisibilityData );
  1014. Vector vecCamera;
  1015. pRenderContext->GetWorldSpaceCameraPosition( &vecCamera );
  1016. while ( nParticles )
  1017. {
  1018. int nParticlesInBatch = min( nMaxParticlesInBatch, nParticles );
  1019. nParticles -= nParticlesInBatch;
  1020. int vertexCount = bUseInstancing ? nParticlesInBatch : nParticlesInBatch * 4;
  1021. int indexCount = bUseInstancing ? 0 : nParticlesInBatch * 6;
  1022. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  1023. CMeshBuilder meshBuilder;
  1024. if ( bUseInstancing )
  1025. {
  1026. g_pParticleSystemMgr->TallyParticlesRendered( vertexCount * ( primType == MATERIAL_TRIANGLES ? 3 : 4 ) );
  1027. meshBuilder.Begin( pMesh, primType, vertexCount );
  1028. }
  1029. else
  1030. {
  1031. g_pParticleSystemMgr->TallyParticlesRendered( vertexCount * ( primType == MATERIAL_TRIANGLES ? 3 : 4 ), indexCount * ( primType == MATERIAL_TRIANGLES ? 3 : 4 ) );
  1032. meshBuilder.Begin( pMesh, primType, vertexCount, indexCount );
  1033. }
  1034. info.m_nVertexOffset = 0;
  1035. if ( meshBuilder.TextureCoordinateSize( 5 ) ) // second sequence?
  1036. {
  1037. for( int i = 0; i < nParticlesInBatch; i++ )
  1038. {
  1039. int hParticle = (--pSortList)->m_nIndex;
  1040. RenderTwoSequenceSpriteCard( meshBuilder, pCtx, info, hParticle, pSortList, &vecCamera );
  1041. }
  1042. }
  1043. else
  1044. {
  1045. for( int i = 0; i < nParticlesInBatch; i++ )
  1046. {
  1047. int hParticle = (--pSortList)->m_nIndex;
  1048. RenderSpriteCard( meshBuilder, pCtx, info, hParticle, pSortList, &vecCamera );
  1049. }
  1050. }
  1051. meshBuilder.End();
  1052. pMesh->Draw();
  1053. }
  1054. }
  1055. void C_OP_RenderSprites::RenderUnsorted( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const
  1056. {
  1057. if ( !pParticles->m_pDef->GetMaterial()->IsSpriteCard() )
  1058. {
  1059. switch( m_nOrientationType )
  1060. {
  1061. case 0:
  1062. // FIXME: Implement! Requires removing MATERIAL_VIEW modification from sorted version
  1063. Warning( "C_OP_RenderSprites::RenderUnsorted: Attempting to use an unimplemented sprite renderer for system \"%s\"!\n",
  1064. pParticles->m_pDef->GetName() );
  1065. // RenderUnsortedNonSpriteCardCameraFacing( pParticles, pContext, pRenderContext, meshBuilder, nVertexOffset, nFirstParticle, nParticleCount );
  1066. break;
  1067. case 1:
  1068. RenderUnsortedNonSpriteCardZRotating( pParticles, pContext, pRenderContext, meshBuilder, nVertexOffset, nFirstParticle, nParticleCount );
  1069. break;
  1070. case 2:
  1071. RenderUnsortedNonSpriteCardOriented( pParticles, pContext, pRenderContext, meshBuilder, nVertexOffset, nFirstParticle, nParticleCount );
  1072. break;
  1073. }
  1074. return;
  1075. }
  1076. C_OP_RenderSpritesContext_t *pCtx = reinterpret_cast<C_OP_RenderSpritesContext_t *>( pContext );
  1077. float flAgeScale = m_flAnimationRate * SEQUENCE_SAMPLE_COUNT;
  1078. float flAgeScale2 = m_flAnimationRate2 * SEQUENCE_SAMPLE_COUNT;
  1079. SpriteRenderInfo_t info;
  1080. info.Init( pParticles, 0, flAgeScale, flAgeScale2, pParticles->m_Sheet() );
  1081. int hParticle = nFirstParticle;
  1082. int nParticles;
  1083. const ParticleRenderData_t *pSortList = pParticles->GetRenderList( pRenderContext, false, &nParticles, &pCtx->m_VisibilityData );
  1084. Vector vecCamera;
  1085. pRenderContext->GetWorldSpaceCameraPosition( &vecCamera );
  1086. for( int i = 0; i < nParticleCount; i++, hParticle++ )
  1087. {
  1088. RenderSpriteCard( meshBuilder, pCtx, info, hParticle, pSortList, &vecCamera );
  1089. }
  1090. }
  1091. //
  1092. //
  1093. //
  1094. //
  1095. struct SpriteTrailRenderInfo_t : public SpriteRenderInfo_t
  1096. {
  1097. size_t m_nPrevXYZStride;
  1098. const fltx4 *m_pPrevXYZ;
  1099. size_t length_stride;
  1100. const fltx4 *m_pLength;
  1101. const fltx4 *m_pCreationTime;
  1102. size_t m_nCreationTimeStride;
  1103. void Init( CParticleCollection *pParticles, int nVertexOffset, float flAgeScale, CSheet *pSheet )
  1104. {
  1105. SpriteRenderInfo_t::Init( pParticles, nVertexOffset, flAgeScale, 0, pSheet );
  1106. m_pParticles = pParticles;
  1107. m_pPrevXYZ = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_PREV_XYZ, &m_nPrevXYZStride );
  1108. m_pLength = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_TRAIL_LENGTH, &length_stride );
  1109. m_pCreationTime = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_CREATION_TIME, &m_nCreationTimeStride );
  1110. }
  1111. };
  1112. class C_OP_RenderSpritesTrail : public CParticleRenderOperatorInstance
  1113. {
  1114. DECLARE_PARTICLE_OPERATOR( C_OP_RenderSpritesTrail );
  1115. struct C_OP_RenderSpriteTrailContext_t
  1116. {
  1117. CParticleVisibilityData m_VisibilityData;
  1118. int m_nQueryHandle;
  1119. };
  1120. size_t GetRequiredContextBytes( void ) const
  1121. {
  1122. return sizeof( C_OP_RenderSpriteTrailContext_t );
  1123. }
  1124. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  1125. {
  1126. C_OP_RenderSpriteTrailContext_t *pCtx = reinterpret_cast<C_OP_RenderSpriteTrailContext_t *>( pContext );
  1127. if ( VisibilityInputs.m_nCPin >= 0 )
  1128. pCtx->m_VisibilityData.m_bUseVisibility = true;
  1129. else
  1130. pCtx->m_VisibilityData.m_bUseVisibility = false;
  1131. pCtx->m_VisibilityData.m_flCameraBias = VisibilityInputs.m_flCameraBias;
  1132. }
  1133. uint32 GetWrittenAttributes( void ) const
  1134. {
  1135. return 0;
  1136. }
  1137. void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  1138. {
  1139. }
  1140. uint32 GetReadAttributes( void ) const
  1141. {
  1142. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_RADIUS_MASK |
  1143. PARTICLE_ATTRIBUTE_TINT_RGB_MASK | PARTICLE_ATTRIBUTE_ALPHA_MASK | PARTICLE_ATTRIBUTE_CREATION_TIME_MASK |
  1144. PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER_MASK | PARTICLE_ATTRIBUTE_TRAIL_LENGTH_MASK;
  1145. }
  1146. virtual int GetParticlesToRender( CParticleCollection *pParticles, void *pContext, int nFirstParticle, int nRemainingVertices, int nRemainingIndices, int *pVertsUsed, int *pIndicesUsed ) const ;
  1147. virtual void Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, void *pContext ) const;
  1148. virtual void RenderUnsorted( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const;
  1149. void RenderSpriteTrail( CMeshBuilder &meshBuilder, SpriteTrailRenderInfo_t& info, int hParticle, const Vector &vecCameraPos, float flOODt, ParticleRenderData_t const *pSortlist ) const;
  1150. float m_flAnimationRate;
  1151. float m_flLengthFadeInTime;
  1152. float m_flMaxLength;
  1153. float m_flMinLength;
  1154. };
  1155. DEFINE_PARTICLE_OPERATOR( C_OP_RenderSpritesTrail, "render_sprite_trail", OPERATOR_SINGLETON );
  1156. BEGIN_PARTICLE_RENDER_OPERATOR_UNPACK( C_OP_RenderSpritesTrail )
  1157. DMXELEMENT_UNPACK_FIELD( "animation rate", ".1", float, m_flAnimationRate )
  1158. DMXELEMENT_UNPACK_FIELD( "length fade in time", "0", float, m_flLengthFadeInTime )
  1159. DMXELEMENT_UNPACK_FIELD( "max length", "2000", float, m_flMaxLength )
  1160. DMXELEMENT_UNPACK_FIELD( "min length", "0", float, m_flMinLength )
  1161. END_PARTICLE_OPERATOR_UNPACK( C_OP_RenderSpritesTrail )
  1162. int C_OP_RenderSpritesTrail::GetParticlesToRender( CParticleCollection *pParticles,
  1163. void *pContext, int nFirstParticle, int nRemainingVertices,
  1164. int nRemainingIndices,
  1165. int *pVertsUsed, int *pIndicesUsed ) const
  1166. {
  1167. int nMaxParticles = ( (nRemainingVertices / 4) > (nRemainingIndices / 6) ) ? nRemainingIndices / 6 : nRemainingVertices / 4;
  1168. int nParticleCount = pParticles->m_nActiveParticles - nFirstParticle;
  1169. if ( nParticleCount > nMaxParticles )
  1170. {
  1171. nParticleCount = nMaxParticles;
  1172. }
  1173. *pVertsUsed = nParticleCount * 4;
  1174. *pIndicesUsed = nParticleCount * 6;
  1175. return nParticleCount;
  1176. }
  1177. void C_OP_RenderSpritesTrail::RenderSpriteTrail( CMeshBuilder &meshBuilder,
  1178. SpriteTrailRenderInfo_t& info, int hParticle,
  1179. const Vector &vecCameraPos, float flOODt, ParticleRenderData_t const *pSortList ) const
  1180. {
  1181. Assert( hParticle != -1 );
  1182. int nGroup = hParticle / 4;
  1183. int nOffset = hParticle & 0x3;
  1184. // Setup our alpha
  1185. unsigned char ac = pSortList->m_nAlpha;
  1186. if ( ac == 0 )
  1187. return;
  1188. // Setup our colors
  1189. int nColorIndex = nGroup * info.m_nRGBStride;
  1190. float r = SubFloat( info.m_pRGB[nColorIndex], nOffset );
  1191. float g = SubFloat( info.m_pRGB[nColorIndex+1], nOffset );
  1192. float b = SubFloat( info.m_pRGB[nColorIndex+2], nOffset );
  1193. Assert( IsFinite(r) && IsFinite(g) && IsFinite(b) );
  1194. Assert( (r >= -1e-6f) && (g >= -1e-6f) && (b >= -1e-6f) );
  1195. Assert( (r <= 1.0f) && (g <= 1.0f) && (b <= 1.0f) );
  1196. unsigned char rc = FastFToC( r );
  1197. unsigned char gc = FastFToC( g );
  1198. unsigned char bc = FastFToC( b );
  1199. // Setup the scale and rotation
  1200. float rad = pSortList->m_flRadius;
  1201. // Find the sample for this frame
  1202. const SheetSequenceSample_t *pSample = &s_DefaultSheetSequence;
  1203. if ( info.m_pSheet )
  1204. {
  1205. pSample = GetSampleForSequence( info.m_pSheet,
  1206. SubFloat( info.m_pCreationTimeStamp[ nGroup * info.m_nCreationTimeStride ], nOffset ),
  1207. info.m_pParticles->m_flCurTime,
  1208. info.m_flAgeScale,
  1209. SubFloat( info.m_pSequenceNumber[ nGroup * info.m_nSequenceStride ], nOffset ) );
  1210. }
  1211. const SequenceSampleTextureCoords_t *pSample0 = &(pSample->m_TextureCoordData[0]);
  1212. int nCreationTimeIndex = nGroup * info.m_nCreationTimeStride;
  1213. float flAge = info.m_pParticles->m_flCurTime - SubFloat( info.m_pCreationTimeStamp[ nCreationTimeIndex ], nOffset );
  1214. float flLengthScale = ( flAge >= m_flLengthFadeInTime ) ? 1.0 : ( flAge / m_flLengthFadeInTime );
  1215. int nXYZIndex = nGroup * info.m_nXYZStride;
  1216. Vector vecWorldPos( SubFloat( info.m_pXYZ[ nXYZIndex ], nOffset ), SubFloat( info.m_pXYZ[ nXYZIndex+1 ], nOffset ), SubFloat( info.m_pXYZ[ nXYZIndex+2 ], nOffset ) );
  1217. Vector vecViewPos = vecWorldPos;
  1218. // Get our screenspace last position
  1219. int nPrevXYZIndex = nGroup * info.m_nPrevXYZStride;
  1220. Vector vecPrevWorldPos( SubFloat( info.m_pPrevXYZ[ nPrevXYZIndex ], nOffset ), SubFloat( info.m_pPrevXYZ[ nPrevXYZIndex+1 ], nOffset ), SubFloat( info.m_pPrevXYZ[ nPrevXYZIndex+2 ], nOffset ) );
  1221. Vector vecPrevViewPos = vecPrevWorldPos;
  1222. // Get the delta direction and find the magnitude, then scale the length by the desired length amount
  1223. Vector vecDelta;
  1224. VectorSubtract( vecPrevViewPos, vecViewPos, vecDelta );
  1225. float flMag = VectorNormalize( vecDelta );
  1226. float flLength = flLengthScale * flMag * flOODt * SubFloat( info.m_pLength[ nGroup * info.length_stride ], nOffset );
  1227. if ( flLength <= 0.0f )
  1228. return;
  1229. flLength = max( m_flMinLength, min( m_flMaxLength, flLength ) );
  1230. vecDelta *= flLength;
  1231. // Fade the width as the length fades to keep it at a square aspect ratio
  1232. if ( flLength < rad )
  1233. {
  1234. rad = flLength;
  1235. }
  1236. // Find our tangent direction which "fattens" the line
  1237. Vector vDirToBeam, vTangentY;
  1238. VectorSubtract( vecWorldPos, vecCameraPos, vDirToBeam );
  1239. CrossProduct( vDirToBeam, vecDelta, vTangentY );
  1240. VectorNormalizeFast( vTangentY );
  1241. // Calculate the verts we'll use as our points
  1242. Vector verts[4];
  1243. VectorMA( vecWorldPos, rad*0.5f, vTangentY, verts[0] );
  1244. VectorMA( vecWorldPos, -rad*0.5f, vTangentY, verts[1] );
  1245. VectorAdd( verts[0], vecDelta, verts[3] );
  1246. VectorAdd( verts[1], vecDelta, verts[2] );
  1247. Assert( verts[0].IsValid() && verts[1].IsValid() && verts[2].IsValid() && verts[3].IsValid() );
  1248. meshBuilder.Position3fv( verts[0].Base() );
  1249. meshBuilder.Color4ub( rc, gc, bc, ac );
  1250. meshBuilder.TexCoord2f( 0, pSample0->m_fLeft_U0, pSample0->m_fBottom_V0 );
  1251. meshBuilder.AdvanceVertex();
  1252. meshBuilder.Position3fv( verts[1].Base() );
  1253. meshBuilder.Color4ub( rc, gc, bc, ac );
  1254. meshBuilder.TexCoord2f( 0, pSample0->m_fRight_U0, pSample0->m_fBottom_V0 );
  1255. meshBuilder.AdvanceVertex();
  1256. meshBuilder.Position3fv( verts[2].Base() );
  1257. meshBuilder.Color4ub( rc, gc, bc, ac );
  1258. meshBuilder.TexCoord2f( 0, pSample0->m_fRight_U0, pSample0->m_fTop_V0 );
  1259. meshBuilder.AdvanceVertex();
  1260. meshBuilder.Position3fv( verts[3].Base() );
  1261. meshBuilder.Color4ub( rc, gc, bc, ac );
  1262. meshBuilder.TexCoord2f( 0, pSample0->m_fLeft_U0, pSample0->m_fTop_V0 );
  1263. meshBuilder.AdvanceVertex();
  1264. meshBuilder.FastIndex( info.m_nVertexOffset );
  1265. meshBuilder.FastIndex( info.m_nVertexOffset + 1 );
  1266. meshBuilder.FastIndex( info.m_nVertexOffset + 2 );
  1267. meshBuilder.FastIndex( info.m_nVertexOffset );
  1268. meshBuilder.FastIndex( info.m_nVertexOffset + 2 );
  1269. meshBuilder.FastIndex( info.m_nVertexOffset + 3 );
  1270. info.m_nVertexOffset += 4;
  1271. }
  1272. void C_OP_RenderSpritesTrail::Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, void *pContext ) const
  1273. {
  1274. C_OP_RenderSpriteTrailContext_t *pCtx = reinterpret_cast<C_OP_RenderSpriteTrailContext_t *>( pContext );
  1275. IMaterial *pMaterial = pParticles->m_pDef->GetMaterial();
  1276. if ( pCtx->m_VisibilityData.m_bUseVisibility )
  1277. {
  1278. SetupParticleVisibility( pParticles, &pCtx->m_VisibilityData, &VisibilityInputs, &pCtx->m_nQueryHandle );
  1279. }
  1280. // Right now we only have a meshbuilder version!
  1281. if ( !HushAsserts() )
  1282. Assert( pMaterial->IsSpriteCard() == false );
  1283. if ( pMaterial->IsSpriteCard() )
  1284. return;
  1285. // Store matrices off so we can restore them in RenderEnd().
  1286. pRenderContext->Bind( pMaterial );
  1287. float flAgeScale = m_flAnimationRate * SEQUENCE_SAMPLE_COUNT;
  1288. // Get the camera's worldspace position
  1289. Vector vecCameraPos;
  1290. pRenderContext->GetWorldSpaceCameraPosition( &vecCameraPos );
  1291. SpriteTrailRenderInfo_t info;
  1292. info.Init( pParticles, 0, flAgeScale, pParticles->m_Sheet() );
  1293. int nParticles;
  1294. const ParticleRenderData_t *pSortList = pParticles->GetRenderList( pRenderContext, true, &nParticles, &pCtx->m_VisibilityData );
  1295. int nMaxParticlesInBatch = GetMaxParticlesPerBatch( pRenderContext, pMaterial, false );
  1296. float flOODt = ( pParticles->m_flDt != 0.0f ) ? ( 1.0f / pParticles->m_flDt ) : 1.0f;
  1297. while ( nParticles )
  1298. {
  1299. int nParticlesInBatch = min( nMaxParticlesInBatch, nParticles );
  1300. nParticles -= nParticlesInBatch;
  1301. g_pParticleSystemMgr->TallyParticlesRendered( nParticlesInBatch * 4 * 3, nParticlesInBatch * 6 * 3 );
  1302. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  1303. CMeshBuilder meshBuilder;
  1304. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nParticlesInBatch * 4, nParticlesInBatch * 6 );
  1305. info.m_nVertexOffset = 0;
  1306. for( int i = 0; i < nParticlesInBatch; i++ )
  1307. {
  1308. int hParticle = (--pSortList)->m_nIndex;
  1309. RenderSpriteTrail( meshBuilder, info, hParticle, vecCameraPos, flOODt, pSortList );
  1310. }
  1311. meshBuilder.End();
  1312. pMesh->Draw();
  1313. }
  1314. }
  1315. void C_OP_RenderSpritesTrail::RenderUnsorted( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const
  1316. {
  1317. C_OP_RenderSpriteTrailContext_t *pCtx = reinterpret_cast<C_OP_RenderSpriteTrailContext_t *>( pContext );
  1318. // NOTE: This is interesting to support because at first we won't have all the various
  1319. // pixel-shader versions of SpriteCard, like modulate, twotexture, etc. etc.
  1320. Vector vecCameraPos;
  1321. pRenderContext->GetWorldSpaceCameraPosition( &vecCameraPos );
  1322. float flAgeScale = m_flAnimationRate * SEQUENCE_SAMPLE_COUNT;
  1323. SpriteTrailRenderInfo_t info;
  1324. info.Init( pParticles, nVertexOffset, flAgeScale, pParticles->m_Sheet() );
  1325. int nParticles;
  1326. const ParticleRenderData_t *pSortList = pParticles->GetRenderList( pRenderContext, false, &nParticles, &pCtx->m_VisibilityData );
  1327. float flOODt = ( pParticles->m_flDt != 0.0f ) ? ( 1.0f / pParticles->m_flDt ) : 1.0f;
  1328. int hParticle = nFirstParticle;
  1329. for( int i = 0; i < nParticleCount; i++, hParticle++ )
  1330. {
  1331. RenderSpriteTrail( meshBuilder, info, hParticle, vecCameraPos, flOODt, pSortList );
  1332. }
  1333. }
  1334. //-----------------------------------------------------------------------------
  1335. //
  1336. // Rope renderer
  1337. //
  1338. //-----------------------------------------------------------------------------
  1339. struct RopeRenderInfo_t
  1340. {
  1341. size_t m_nXYZStride;
  1342. const fltx4 *m_pXYZ;
  1343. size_t m_nRadStride;
  1344. const fltx4 *m_pRadius;
  1345. size_t m_nRGBStride;
  1346. const fltx4 *m_pRGB;
  1347. size_t m_nAlphaStride;
  1348. const fltx4 *m_pAlpha;
  1349. CParticleCollection *m_pParticles;
  1350. void Init( CParticleCollection *pParticles )
  1351. {
  1352. m_pParticles = pParticles;
  1353. m_pXYZ = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_XYZ, &m_nXYZStride );
  1354. m_pRadius = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_RADIUS, &m_nRadStride );
  1355. m_pRGB = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_TINT_RGB, &m_nRGBStride );
  1356. m_pAlpha = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_ALPHA, &m_nAlphaStride );
  1357. }
  1358. void GenerateSeg( int hParticle, BeamSeg_t& seg )
  1359. {
  1360. Assert( hParticle != -1 );
  1361. int nGroup = hParticle / 4;
  1362. int nOffset = hParticle & 0x3;
  1363. int nXYZIndex = nGroup * m_nXYZStride;
  1364. int nColorIndex = nGroup * m_nRGBStride;
  1365. seg.m_vPos.Init( SubFloat( m_pXYZ[ nXYZIndex ], nOffset ), SubFloat( m_pXYZ[ nXYZIndex+1 ], nOffset ), SubFloat( m_pXYZ[ nXYZIndex+2 ], nOffset ) );
  1366. seg.m_vColor.Init( SubFloat( m_pRGB[ nColorIndex ], nOffset ), SubFloat( m_pRGB[ nColorIndex+1 ], nOffset ), SubFloat( m_pRGB[nColorIndex+2], nOffset ) );
  1367. seg.m_flAlpha = SubFloat( m_pAlpha[ nGroup * m_nAlphaStride ], nOffset );
  1368. seg.m_flWidth = SubFloat( m_pRadius[ nGroup * m_nRadStride ], nOffset );
  1369. }
  1370. };
  1371. struct RenderRopeContext_t
  1372. {
  1373. float m_flRenderedRopeLength;
  1374. };
  1375. class C_OP_RenderRope : public CParticleOperatorInstance
  1376. {
  1377. DECLARE_PARTICLE_OPERATOR( C_OP_RenderRope );
  1378. uint32 GetWrittenAttributes( void ) const
  1379. {
  1380. return 0;
  1381. }
  1382. uint32 GetReadAttributes( void ) const
  1383. {
  1384. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_RADIUS_MASK |
  1385. PARTICLE_ATTRIBUTE_TINT_RGB_MASK | PARTICLE_ATTRIBUTE_ALPHA_MASK;
  1386. }
  1387. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  1388. {
  1389. RenderRopeContext_t *pCtx = reinterpret_cast<RenderRopeContext_t *>( pContext );
  1390. pCtx->m_flRenderedRopeLength = false;
  1391. float *pSubdivList = (float*)( pCtx + 1 );
  1392. for ( int iSubdiv = 0; iSubdiv < m_nSubdivCount; iSubdiv++ )
  1393. {
  1394. pSubdivList[iSubdiv] = (float)iSubdiv / (float)m_nSubdivCount;
  1395. }
  1396. // NOTE: Has to happen here, and not in InitParams, since the material isn't set up yet
  1397. const_cast<C_OP_RenderRope*>( this )->m_flTextureScale = 1.0f / ( pParticles->m_pDef->GetMaterial()->GetMappingHeight() * m_flTexelSizeInUnits );
  1398. }
  1399. size_t GetRequiredContextBytes( void ) const
  1400. {
  1401. return sizeof( RenderRopeContext_t ) + m_nSubdivCount * sizeof(float);
  1402. }
  1403. virtual void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  1404. {
  1405. if ( m_nSubdivCount <= 0 )
  1406. {
  1407. m_nSubdivCount = 1;
  1408. }
  1409. if ( m_flTexelSizeInUnits <= 0 )
  1410. {
  1411. m_flTexelSizeInUnits = 1.0f;
  1412. }
  1413. m_flTStep = 1.0 / m_nSubdivCount;
  1414. }
  1415. virtual int GetParticlesToRender( CParticleCollection *pParticles, void *pContext, int nFirstParticle, int nRemainingVertices, int nRemainingIndices, int *pVertsUsed, int *pIndicesUsed ) const;
  1416. virtual void Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, void *pContext ) const;
  1417. virtual void RenderSpriteCard( CParticleCollection *pParticles, void *pContext, IMaterial *pMaterial ) const;
  1418. virtual void RenderUnsorted( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const;
  1419. // We connect neighboring particle instances to each other, so if the order isn't maintained we will have a particle that jumps
  1420. // back to the wrong place and look terrible.
  1421. virtual bool RequiresOrderInvariance( void ) const OVERRIDE
  1422. {
  1423. return true;
  1424. }
  1425. int m_nSubdivCount;
  1426. float m_flTexelSizeInUnits;
  1427. float m_flTextureScale;
  1428. float m_flTextureScrollRate;
  1429. float m_flTStep;
  1430. };
  1431. DEFINE_PARTICLE_OPERATOR( C_OP_RenderRope, "render_rope", OPERATOR_SINGLETON );
  1432. BEGIN_PARTICLE_OPERATOR_UNPACK( C_OP_RenderRope )
  1433. DMXELEMENT_UNPACK_FIELD( "subdivision_count", "3", int, m_nSubdivCount )
  1434. DMXELEMENT_UNPACK_FIELD( "texel_size", "4.0f", float, m_flTexelSizeInUnits )
  1435. DMXELEMENT_UNPACK_FIELD( "texture_scroll_rate", "0.0f", float, m_flTextureScrollRate )
  1436. END_PARTICLE_OPERATOR_UNPACK( C_OP_RenderRope )
  1437. //-----------------------------------------------------------------------------
  1438. // Returns the number of particles to render
  1439. //-----------------------------------------------------------------------------
  1440. int C_OP_RenderRope::GetParticlesToRender( CParticleCollection *pParticles,
  1441. void *pContext, int nFirstParticle, int nRemainingVertices, int nRemainingIndices,
  1442. int *pVertsUsed, int *pIndicesUsed ) const
  1443. {
  1444. if ( ( nFirstParticle >= pParticles->m_nActiveParticles - 1 ) || ( pParticles->m_nActiveParticles <= 1 ) )
  1445. {
  1446. *pVertsUsed = 0;
  1447. *pIndicesUsed = 0;
  1448. return 0;
  1449. }
  1450. // NOTE: This is only true for particles *after* the first particle.
  1451. // First particle takes 2 verts, no indices.
  1452. int nVertsPerParticle = 2 * m_nSubdivCount;
  1453. int nIndicesPerParticle = 6 * m_nSubdivCount;
  1454. // Subtract 2 is because the first particle uses an extra pair of vertices
  1455. int nMaxParticleCount = 1 + ( nRemainingVertices - 2 ) / nVertsPerParticle;
  1456. int nMaxParticleCount2 = nRemainingIndices / nIndicesPerParticle;
  1457. if ( nMaxParticleCount > nMaxParticleCount2 )
  1458. {
  1459. nMaxParticleCount = nMaxParticleCount2;
  1460. }
  1461. int nParticleCount = pParticles->m_nActiveParticles - nFirstParticle;
  1462. // We can't choose a max particle count so that we only have 1 particle to render next time
  1463. if ( nMaxParticleCount == nParticleCount - 1 )
  1464. {
  1465. --nMaxParticleCount;
  1466. Assert( nMaxParticleCount > 0 );
  1467. }
  1468. if ( nParticleCount > nMaxParticleCount )
  1469. {
  1470. nParticleCount = nMaxParticleCount;
  1471. }
  1472. *pVertsUsed = ( nParticleCount - 1 ) * m_nSubdivCount * 2 + 2;
  1473. *pIndicesUsed = nParticleCount * m_nSubdivCount * 6;
  1474. return nParticleCount;
  1475. }
  1476. #define OUTPUT_2SPLINE_VERTS( t ) \
  1477. meshBuilder.Color4ub( FastFToC( vecColor.x ), FastFToC( vecColor.y), FastFToC( vecColor.z), FastFToC( vecColor.w ) ); \
  1478. meshBuilder.Position3f( (t), flU, 0 ); \
  1479. meshBuilder.TexCoord4fv( 0, vecP0.Base() ); \
  1480. meshBuilder.TexCoord4fv( 1, vecP1.Base() ); \
  1481. meshBuilder.TexCoord4fv( 2, vecP2.Base() ); \
  1482. meshBuilder.TexCoord4fv( 3, vecP3.Base() ); \
  1483. meshBuilder.AdvanceVertex(); \
  1484. meshBuilder.Color4ub( FastFToC( vecColor.x ), FastFToC( vecColor.y), FastFToC( vecColor.z), FastFToC( vecColor.w ) ); \
  1485. meshBuilder.Position3f( (t), flU, 1 ); \
  1486. meshBuilder.TexCoord4fv( 0, vecP0.Base() ); \
  1487. meshBuilder.TexCoord4fv( 1, vecP1.Base() ); \
  1488. meshBuilder.TexCoord4fv( 2, vecP2.Base() ); \
  1489. meshBuilder.TexCoord4fv( 3, vecP3.Base() ); \
  1490. meshBuilder.AdvanceVertex();
  1491. void C_OP_RenderRope::RenderSpriteCard( CParticleCollection *pParticles, void *pContext, IMaterial *pMaterial ) const
  1492. {
  1493. int nParticles = pParticles->m_nActiveParticles;
  1494. int nSegmentsToRender = nParticles - 1;
  1495. if ( ! nSegmentsToRender )
  1496. return;
  1497. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1498. pRenderContext->Bind( pMaterial );
  1499. int nMaxVertices = pRenderContext->GetMaxVerticesToRender( pMaterial );
  1500. int nMaxIndices = pRenderContext->GetMaxIndicesToRender();
  1501. int nNumIndicesPerSegment = 6 * m_nSubdivCount;
  1502. int nNumVerticesPerSegment = 2 * m_nSubdivCount;
  1503. int nNumSegmentsPerBatch = min( ( nMaxVertices - 2 )/nNumVerticesPerSegment,
  1504. ( nMaxIndices ) / nNumIndicesPerSegment );
  1505. const float *pXYZ = pParticles->GetFloatAttributePtr(
  1506. PARTICLE_ATTRIBUTE_XYZ, 0 );
  1507. const float *pColor = pParticles->GetFloatAttributePtr(
  1508. PARTICLE_ATTRIBUTE_TINT_RGB, 0 );
  1509. const float *pRadius = pParticles->GetFloatAttributePtr(
  1510. PARTICLE_ATTRIBUTE_RADIUS, 0 );
  1511. const float *pAlpha = pParticles->GetFloatAttributePtr(
  1512. PARTICLE_ATTRIBUTE_ALPHA, 0 );
  1513. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  1514. CMeshBuilder meshBuilder;
  1515. int nNumSegmentsIWillRenderPerBatch = min( nNumSegmentsPerBatch, nSegmentsToRender );
  1516. bool bFirstPoint = true;
  1517. float flTexOffset = m_flTextureScrollRate * pParticles->m_flCurTime;
  1518. float flU = flTexOffset;
  1519. // initialize first spline segment
  1520. Vector4D vecP1( pXYZ[0], pXYZ[4], pXYZ[8], pRadius[0] );
  1521. Vector4D vecP2( pXYZ[1], pXYZ[5], pXYZ[9], pRadius[1] );
  1522. Vector4D vecP0 = vecP1;
  1523. Vector4D vecColor( pColor[0], pColor[4], pColor[8], pAlpha[0] );
  1524. Vector4D vecDelta = vecP2;
  1525. vecDelta -= vecP1;
  1526. vecP0 -= vecDelta;
  1527. Vector4D vecP3;
  1528. if ( nParticles < 3 )
  1529. {
  1530. vecP3 = vecP2;
  1531. vecP3 += vecDelta;
  1532. }
  1533. else
  1534. {
  1535. vecP3.Init( pXYZ[2], pXYZ[6], pXYZ[10], pRadius[2] );
  1536. }
  1537. int nPnt = 3;
  1538. int nCurIDX = 0;
  1539. int nSegmentsAvailableInBuffer = nNumSegmentsIWillRenderPerBatch;
  1540. g_pParticleSystemMgr->TallyParticlesRendered( 2 + nNumSegmentsIWillRenderPerBatch * nNumVerticesPerSegment * 3, nNumIndicesPerSegment * nNumSegmentsIWillRenderPerBatch * 3 );
  1541. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES,
  1542. 2 + nNumSegmentsIWillRenderPerBatch * nNumVerticesPerSegment,
  1543. nNumIndicesPerSegment * nNumSegmentsIWillRenderPerBatch );
  1544. float flDUScale = ( m_flTStep * m_flTexelSizeInUnits );
  1545. float flT = 0;
  1546. do
  1547. {
  1548. if ( ! nSegmentsAvailableInBuffer )
  1549. {
  1550. meshBuilder.End();
  1551. pMesh->Draw();
  1552. g_pParticleSystemMgr->TallyParticlesRendered( 2 + nNumSegmentsIWillRenderPerBatch * nNumVerticesPerSegment * 3, nNumIndicesPerSegment * nNumSegmentsIWillRenderPerBatch * 3 );
  1553. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 2 + nNumSegmentsIWillRenderPerBatch * nNumVerticesPerSegment,
  1554. nNumIndicesPerSegment * nNumSegmentsIWillRenderPerBatch );
  1555. // copy the last emitted points
  1556. OUTPUT_2SPLINE_VERTS( flT );
  1557. nSegmentsAvailableInBuffer = nNumSegmentsIWillRenderPerBatch;
  1558. nCurIDX = 0;
  1559. }
  1560. nSegmentsAvailableInBuffer--;
  1561. flT = 0.;
  1562. float flDu = flDUScale * ( vecP2.AsVector3D() - vecP1.AsVector3D() ).Length();
  1563. for( int nSlice = 0 ; nSlice < m_nSubdivCount; nSlice++ )
  1564. {
  1565. OUTPUT_2SPLINE_VERTS( flT );
  1566. flT += m_flTStep;
  1567. flU += flDu;
  1568. if ( ! bFirstPoint )
  1569. {
  1570. meshBuilder.FastIndex( nCurIDX );
  1571. meshBuilder.FastIndex( nCurIDX+1 );
  1572. meshBuilder.FastIndex( nCurIDX+2 );
  1573. meshBuilder.FastIndex( nCurIDX+1 );
  1574. meshBuilder.FastIndex( nCurIDX+3 );
  1575. meshBuilder.FastIndex( nCurIDX+2 );
  1576. nCurIDX += 2;
  1577. }
  1578. bFirstPoint = false;
  1579. }
  1580. // next segment
  1581. if ( nSegmentsToRender > 1 )
  1582. {
  1583. vecP0 = vecP1;
  1584. vecP1 = vecP2;
  1585. vecP2 = vecP3;
  1586. pRadius = pParticles->GetFloatAttributePtr(
  1587. PARTICLE_ATTRIBUTE_RADIUS, nPnt );
  1588. pAlpha = pParticles->GetFloatAttributePtr(
  1589. PARTICLE_ATTRIBUTE_ALPHA, nPnt -2 );
  1590. vecColor.Init( pColor[0], pColor[4], pColor[8], pAlpha[0] );
  1591. if ( nPnt < nParticles )
  1592. {
  1593. pXYZ = pParticles->GetFloatAttributePtr(
  1594. PARTICLE_ATTRIBUTE_XYZ, nPnt );
  1595. vecP3.Init( pXYZ[0], pXYZ[4], pXYZ[8], pRadius[0] );
  1596. nPnt++;
  1597. }
  1598. else
  1599. {
  1600. // fake last point by extrapolating
  1601. vecP3 += vecP2;
  1602. vecP3 -= vecP1;
  1603. }
  1604. }
  1605. } while( --nSegmentsToRender );
  1606. // output last piece
  1607. OUTPUT_2SPLINE_VERTS( 1.0 );
  1608. meshBuilder.FastIndex( nCurIDX );
  1609. meshBuilder.FastIndex( nCurIDX+1 );
  1610. meshBuilder.FastIndex( nCurIDX+2 );
  1611. meshBuilder.FastIndex( nCurIDX+1 );
  1612. meshBuilder.FastIndex( nCurIDX+3 );
  1613. meshBuilder.FastIndex( nCurIDX+2 );
  1614. meshBuilder.End();
  1615. pMesh->Draw();
  1616. }
  1617. //-----------------------------------------------------------------------------
  1618. // Renders particles, sorts them (?)
  1619. //-----------------------------------------------------------------------------
  1620. void C_OP_RenderRope::Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, void *pContext ) const
  1621. {
  1622. // FIXME: What does this even mean? Ropes can't really be sorted.
  1623. IMaterial *pMaterial = pParticles->m_pDef->GetMaterial();
  1624. if ( pMaterial->IsSpriteCard() )
  1625. {
  1626. RenderSpriteCard( pParticles, pContext, pMaterial );
  1627. return;
  1628. }
  1629. pRenderContext->Bind( pMaterial );
  1630. int nMaxVertices = pRenderContext->GetMaxVerticesToRender( pMaterial );
  1631. int nMaxIndices = pRenderContext->GetMaxIndicesToRender();
  1632. int nParticles = pParticles->m_nActiveParticles;
  1633. int nFirstParticle = 0;
  1634. while ( nParticles )
  1635. {
  1636. int nVertCount, nIndexCount;
  1637. int nParticlesInBatch = GetParticlesToRender( pParticles, pContext, nFirstParticle, nMaxVertices, nMaxIndices, &nVertCount, &nIndexCount );
  1638. if ( nParticlesInBatch == 0 )
  1639. break;
  1640. nParticles -= nParticlesInBatch;
  1641. g_pParticleSystemMgr->TallyParticlesRendered( nVertCount * 3, nIndexCount * 3 );
  1642. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  1643. CMeshBuilder meshBuilder;
  1644. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nVertCount, nIndexCount );
  1645. RenderUnsorted( pParticles, pContext, pRenderContext, meshBuilder, 0, nFirstParticle, nParticlesInBatch );
  1646. meshBuilder.End();
  1647. pMesh->Draw();
  1648. nFirstParticle += nParticlesInBatch;
  1649. }
  1650. }
  1651. //-----------------------------------------------------------------------------
  1652. // Purpose:
  1653. //-----------------------------------------------------------------------------
  1654. void C_OP_RenderRope::RenderUnsorted( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const
  1655. {
  1656. IMaterial *pMaterial = pParticles->m_pDef->GetMaterial();
  1657. // Right now we only have a meshbuilder version!
  1658. Assert( pMaterial->IsSpriteCard() == false );
  1659. if ( pMaterial->IsSpriteCard() )
  1660. return;
  1661. RenderRopeContext_t *pCtx = reinterpret_cast<RenderRopeContext_t *>( pContext );
  1662. float *pSubdivList = (float*)( pCtx + 1 );
  1663. if ( nFirstParticle == 0 )
  1664. {
  1665. pCtx->m_flRenderedRopeLength = 0.0f;
  1666. }
  1667. float flTexOffset = m_flTextureScrollRate * pParticles->m_flCurTime;
  1668. RopeRenderInfo_t info;
  1669. info.Init( pParticles );
  1670. CBeamSegDraw beamSegment;
  1671. beamSegment.Start( pRenderContext, ( nParticleCount - 1 ) * m_nSubdivCount + 1, pMaterial, &meshBuilder, nVertexOffset );
  1672. Vector vecCatmullRom[4];
  1673. BeamSeg_t seg[2];
  1674. info.GenerateSeg( nFirstParticle, seg[0] );
  1675. seg[0].m_flTexCoord = ( pCtx->m_flRenderedRopeLength + flTexOffset ) * m_flTextureScale;
  1676. beamSegment.NextSeg( &seg[0] );
  1677. vecCatmullRom[1] = seg[0].m_vPos;
  1678. if ( nFirstParticle == 0 )
  1679. {
  1680. vecCatmullRom[0] = vecCatmullRom[1];
  1681. }
  1682. else
  1683. {
  1684. int nGroup = ( nFirstParticle-1 ) / 4;
  1685. int nOffset = ( nFirstParticle-1 ) & 0x3;
  1686. int nXYZIndex = nGroup * info.m_nXYZStride;
  1687. vecCatmullRom[0].Init( SubFloat( info.m_pXYZ[ nXYZIndex ], nOffset ), SubFloat( info.m_pXYZ[ nXYZIndex+1 ], nOffset ), SubFloat( info.m_pXYZ[ nXYZIndex+2 ], nOffset ) );
  1688. }
  1689. float flOOSubDivCount = 1.0f / m_nSubdivCount;
  1690. int hParticle = nFirstParticle + 1;
  1691. for ( int i = 1; i < nParticleCount; ++i, ++hParticle )
  1692. {
  1693. int nCurr = i & 1;
  1694. int nPrev = 1 - nCurr;
  1695. info.GenerateSeg( hParticle, seg[nCurr] );
  1696. pCtx->m_flRenderedRopeLength += seg[nCurr].m_vPos.DistTo( seg[nPrev].m_vPos );
  1697. seg[nCurr].m_flTexCoord = ( pCtx->m_flRenderedRopeLength + flTexOffset ) * m_flTextureScale;
  1698. if ( m_nSubdivCount > 1 )
  1699. {
  1700. vecCatmullRom[ (i+1) & 0x3 ] = seg[nCurr].m_vPos;
  1701. if ( hParticle != info.m_pParticles->m_nActiveParticles - 1 )
  1702. {
  1703. int nGroup = ( hParticle+1 ) / 4;
  1704. int nOffset = ( hParticle+1 ) & 0x3;
  1705. int nXYZIndex = nGroup * info.m_nXYZStride;
  1706. 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 ) );
  1707. }
  1708. else
  1709. {
  1710. vecCatmullRom[ (i+2) & 0x3 ] = vecCatmullRom[ (i+1) & 0x3 ];
  1711. }
  1712. BeamSeg_t &subDivSeg = seg[nPrev];
  1713. Vector vecColorInc = ( seg[nCurr].m_vColor - seg[nPrev].m_vColor ) * flOOSubDivCount;
  1714. float flAlphaInc = ( seg[nCurr].m_flAlpha - seg[nPrev].m_flAlpha ) * flOOSubDivCount;
  1715. float flTexcoordInc = ( seg[nCurr].m_flTexCoord - seg[nPrev].m_flTexCoord ) * flOOSubDivCount;
  1716. float flWidthInc = ( seg[nCurr].m_flWidth - seg[nPrev].m_flWidth ) * flOOSubDivCount;
  1717. for( int iSubdiv = 1; iSubdiv < m_nSubdivCount; ++iSubdiv )
  1718. {
  1719. subDivSeg.m_vColor += vecColorInc;
  1720. subDivSeg.m_vColor.x = clamp( subDivSeg.m_vColor.x, 0.0f, 1.0f );
  1721. subDivSeg.m_vColor.y = clamp( subDivSeg.m_vColor.y, 0.0f, 1.0f );
  1722. subDivSeg.m_vColor.z = clamp( subDivSeg.m_vColor.z, 0.0f, 1.0f );
  1723. subDivSeg.m_flAlpha += flAlphaInc;
  1724. subDivSeg.m_flAlpha = clamp( subDivSeg.m_flAlpha, 0.0f, 1.0f );
  1725. subDivSeg.m_flTexCoord += flTexcoordInc;
  1726. subDivSeg.m_flWidth += flWidthInc;
  1727. Catmull_Rom_Spline( vecCatmullRom[ (i+3) & 0x3 ], vecCatmullRom[ i & 0x3 ],
  1728. vecCatmullRom[ (i+1) & 0x3 ], vecCatmullRom[ (i+2) & 0x3 ],
  1729. pSubdivList[iSubdiv], subDivSeg.m_vPos );
  1730. beamSegment.NextSeg( &subDivSeg );
  1731. }
  1732. }
  1733. beamSegment.NextSeg( &seg[nCurr] );
  1734. }
  1735. beamSegment.End();
  1736. }
  1737. #ifdef USE_BLOBULATOR // Enable blobulator for EP3
  1738. //-----------------------------------------------------------------------------
  1739. // Installs renderers
  1740. //-----------------------------------------------------------------------------
  1741. class C_OP_RenderBlobs : public CParticleRenderOperatorInstance
  1742. {
  1743. DECLARE_PARTICLE_OPERATOR( C_OP_RenderBlobs );
  1744. float m_cubeWidth;
  1745. float m_cutoffRadius;
  1746. float m_renderRadius;
  1747. struct C_OP_RenderBlobsContext_t
  1748. {
  1749. CParticleVisibilityData m_VisibilityData;
  1750. int m_nQueryHandle;
  1751. };
  1752. size_t GetRequiredContextBytes( void ) const
  1753. {
  1754. return sizeof( C_OP_RenderBlobsContext_t );
  1755. }
  1756. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  1757. {
  1758. C_OP_RenderBlobsContext_t *pCtx = reinterpret_cast<C_OP_RenderBlobsContext_t *>( pContext );
  1759. if ( VisibilityInputs.m_nCPin >= 0 )
  1760. pCtx->m_VisibilityData.m_bUseVisibility = true;
  1761. else
  1762. pCtx->m_VisibilityData.m_bUseVisibility = false;
  1763. pCtx->m_VisibilityData.m_flCameraBias = VisibilityInputs.m_flCameraBias;
  1764. }
  1765. uint32 GetWrittenAttributes( void ) const
  1766. {
  1767. return 0;
  1768. }
  1769. uint32 GetReadAttributes( void ) const
  1770. {
  1771. return PARTICLE_ATTRIBUTE_XYZ_MASK;
  1772. }
  1773. virtual void Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, void *pContext ) const;
  1774. virtual bool IsBatchable() const
  1775. {
  1776. return false;
  1777. }
  1778. };
  1779. DEFINE_PARTICLE_OPERATOR( C_OP_RenderBlobs, "render_blobs", OPERATOR_SINGLETON );
  1780. BEGIN_PARTICLE_RENDER_OPERATOR_UNPACK( C_OP_RenderBlobs )
  1781. DMXELEMENT_UNPACK_FIELD( "cube_width", "1.0f", float, m_cubeWidth )
  1782. DMXELEMENT_UNPACK_FIELD( "cutoff_radius", "3.3f", float, m_cutoffRadius )
  1783. DMXELEMENT_UNPACK_FIELD( "render_radius", "1.3f", float, m_renderRadius )
  1784. END_PARTICLE_OPERATOR_UNPACK( C_OP_RenderBlobs )
  1785. void C_OP_RenderBlobs::Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, void *pContext ) const
  1786. {
  1787. ImpTiler* tiler = ImpTilerFactory::factory->getTiler();
  1788. //RENDERER_CLASS* sweepRenderer = tiler->getRenderer();
  1789. C_OP_RenderBlobsContext_t *pCtx = reinterpret_cast<C_OP_RenderBlobsContext_t *>( pContext );
  1790. if ( pCtx->m_VisibilityData.m_bUseVisibility )
  1791. {
  1792. SetupParticleVisibility( pParticles, &pCtx->m_VisibilityData, &VisibilityInputs, &pCtx->m_nQueryHandle );
  1793. }
  1794. #if 0
  1795. // Note: it is not good to have these static variables here.
  1796. static RENDERER_CLASS* sweepRenderer = NULL;
  1797. static ImpTiler* tiler = NULL;
  1798. if(!sweepRenderer)
  1799. {
  1800. sweepRenderer = new RENDERER_CLASS();
  1801. tiler = new ImpTiler(sweepRenderer);
  1802. }
  1803. #endif
  1804. // TODO: I should get rid of this static array and static calls
  1805. // to setCubeWidth, etc...
  1806. static SmartArray<ImpParticle> imp_particles_sa; // This doesn't specify alignment, might have problems with SSE
  1807. RENDERER_CLASS::setCubeWidth(m_cubeWidth);
  1808. RENDERER_CLASS::setRenderR(m_renderRadius);
  1809. RENDERER_CLASS::setCutoffR(m_cutoffRadius);
  1810. RENDERER_CLASS::setCalcSignFunc(calcSign);
  1811. RENDERER_CLASS::setCalcSign2Func(calcSign2);
  1812. #if 0
  1813. RENDERER_CLASS::setCalcCornerFunc(CALC_CORNER_NORMAL_COLOR_CI_SIZE, calcCornerNormalColor);
  1814. RENDERER_CLASS::setCalcVertexFunc(calcVertexNormalNColor);
  1815. #endif
  1816. #if 1
  1817. RENDERER_CLASS::setCalcCornerFunc(CALC_CORNER_NORMAL_CI_SIZE, calcCornerNormal);
  1818. RENDERER_CLASS::setCalcVertexFunc(calcVertexNormalDebugColor);
  1819. #endif
  1820. #if 0
  1821. RENDERER_CLASS::setCalcCornerFunc(CALC_CORNER_NORMAL_COLOR_CI_SIZE, calcCornerNormalHiFreqColor);
  1822. RENDERER_CLASS::setCalcVertexFunc(calcVertexNormalNColor);
  1823. #endif
  1824. IMaterial *pMaterial = pParticles->m_pDef->GetMaterial();
  1825. // TODO: I don't need to load this as a sorted list. See Lennard Jones forces for better way!
  1826. int nParticles;
  1827. const ParticleRenderData_t *pSortList = pParticles->GetRenderList( pRenderContext, false, &nParticles, &pCtx->m_VisibilityData );
  1828. size_t xyz_stride;
  1829. const fltx4 *xyz = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_XYZ, &xyz_stride );
  1830. Vector bbMin;
  1831. Vector bbMax;
  1832. pParticles->GetBounds( &bbMin, &bbMax );
  1833. Vector bbCenter = 0.5f * ( bbMin + bbMax );
  1834. // FIXME: Make this configurable. Not all shaders perform lighting. Although it's pretty likely for isosurface shaders.
  1835. g_pParticleSystemMgr->Query()->SetUpLightingEnvironment( bbCenter );
  1836. // FIXME: Ugly hack to get particle system location to a special blob shader lighting proxy
  1837. pRenderContext->Bind( pMaterial, &bbCenter );
  1838. //CMeshBuilder meshBuilder;
  1839. //int nMaxVertices = pRenderContext->GetMaxVerticesToRender( pMaterial );
  1840. tiler->beginFrame(Point3D(0.0f, 0.0f, 0.0f), (void*)&pRenderContext);
  1841. while(imp_particles_sa.size < nParticles)
  1842. {
  1843. imp_particles_sa.pushAutoSize(ImpParticle());
  1844. }
  1845. for( int i = 0; i < nParticles; i++ )
  1846. {
  1847. int hParticle = (--pSortList)->m_nIndex;
  1848. int nIndex = ( hParticle / 4 ) * xyz_stride;
  1849. int nOffset = hParticle & 0x3;
  1850. float x = SubFloat( xyz[nIndex], nOffset );
  1851. float y = SubFloat( xyz[nIndex+1], nOffset );
  1852. float z = SubFloat( xyz[nIndex+2], nOffset );
  1853. ImpParticle* imp_particle = &imp_particles_sa[i];
  1854. imp_particle->center[0]=x;
  1855. imp_particle->center[1]=y;
  1856. imp_particle->center[2]=z;
  1857. imp_particle->setFieldScale(1.0f);
  1858. //imp_particle->interpolants1.set(1.0f, 1.0f, 1.0f);
  1859. //imp_particle->interpolants1[3] = 0.0f; //m_flSurfaceV[i];
  1860. tiler->insertParticle(imp_particle);
  1861. }
  1862. tiler->drawSurface(); // NOTE: need to call drawSurfaceSorted for transparency
  1863. tiler->endFrame();
  1864. ImpTilerFactory::factory->returnTiler(tiler);
  1865. }
  1866. #endif //blobs
  1867. //-----------------------------------------------------------------------------
  1868. // Installs renderers
  1869. //-----------------------------------------------------------------------------
  1870. class C_OP_RenderScreenVelocityRotate : public CParticleRenderOperatorInstance
  1871. {
  1872. DECLARE_PARTICLE_OPERATOR( C_OP_RenderScreenVelocityRotate );
  1873. float m_flRotateRateDegrees;
  1874. float m_flForwardDegrees;
  1875. struct C_OP_RenderScreenVelocityRotateContext_t
  1876. {
  1877. CParticleVisibilityData m_VisibilityData;
  1878. int m_nQueryHandle;
  1879. };
  1880. size_t GetRequiredContextBytes( void ) const
  1881. {
  1882. return sizeof( C_OP_RenderScreenVelocityRotateContext_t );
  1883. }
  1884. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  1885. {
  1886. C_OP_RenderScreenVelocityRotateContext_t *pCtx = reinterpret_cast<C_OP_RenderScreenVelocityRotateContext_t *>( pContext );
  1887. if ( VisibilityInputs.m_nCPin >= 0 )
  1888. pCtx->m_VisibilityData.m_bUseVisibility = true;
  1889. else
  1890. pCtx->m_VisibilityData.m_bUseVisibility = false;
  1891. pCtx->m_VisibilityData.m_flCameraBias = VisibilityInputs.m_flCameraBias;
  1892. }
  1893. uint32 GetWrittenAttributes( void ) const
  1894. {
  1895. return PARTICLE_ATTRIBUTE_ROTATION_MASK;
  1896. }
  1897. uint32 GetReadAttributes( void ) const
  1898. {
  1899. return PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_ROTATION_MASK ;
  1900. }
  1901. virtual void Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, void *pContext ) const;
  1902. };
  1903. DEFINE_PARTICLE_OPERATOR( C_OP_RenderScreenVelocityRotate, "render_screen_velocity_rotate", OPERATOR_SINGLETON );
  1904. BEGIN_PARTICLE_RENDER_OPERATOR_UNPACK( C_OP_RenderScreenVelocityRotate )
  1905. DMXELEMENT_UNPACK_FIELD( "rotate_rate(dps)", "0.0f", float, m_flRotateRateDegrees )
  1906. DMXELEMENT_UNPACK_FIELD( "forward_angle", "-90.0f", float, m_flForwardDegrees )
  1907. END_PARTICLE_OPERATOR_UNPACK( C_OP_RenderScreenVelocityRotate )
  1908. void C_OP_RenderScreenVelocityRotate::Render( IMatRenderContext *pRenderContext, CParticleCollection *pParticles, void *pContext ) const
  1909. {
  1910. C_OP_RenderScreenVelocityRotateContext_t *pCtx = reinterpret_cast<C_OP_RenderScreenVelocityRotateContext_t *>( pContext );
  1911. if ( pCtx->m_VisibilityData.m_bUseVisibility )
  1912. {
  1913. SetupParticleVisibility( pParticles, &pCtx->m_VisibilityData, &VisibilityInputs, &pCtx->m_nQueryHandle );
  1914. }
  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. VMatrix tempView;
  1918. // Store matrices off so we can restore them in RenderEnd().
  1919. pRenderContext->GetMatrix(MATERIAL_VIEW, &tempView);
  1920. int nParticles;
  1921. const ParticleRenderData_t *pSortList = pParticles->GetRenderList( pRenderContext, false, &nParticles, &pCtx->m_VisibilityData );
  1922. size_t xyz_stride;
  1923. const fltx4 *xyz = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_XYZ, &xyz_stride );
  1924. size_t prev_xyz_stride;
  1925. const fltx4 *prev_xyz = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_PREV_XYZ, &prev_xyz_stride );
  1926. size_t rot_stride;
  1927. // const fltx4 *pRot = pParticles->GetM128AttributePtr( PARTICLE_ATTRIBUTE_ROTATION, &rot_stride );
  1928. fltx4 *pRot = pParticles->GetM128AttributePtrForWrite( PARTICLE_ATTRIBUTE_ROTATION, &rot_stride );
  1929. float flForwardRadians = m_flForwardDegrees * ( M_PI / 180.0f );
  1930. //float flRotateRateRadians = m_flRotateRateDegrees * ( M_PI / 180.0f );
  1931. for( int i = 0; i < nParticles; i++ )
  1932. {
  1933. int hParticle = (--pSortList)->m_nIndex;
  1934. int nGroup = ( hParticle / 4 );
  1935. int nOffset = hParticle & 0x3;
  1936. int nXYZIndex = nGroup * xyz_stride;
  1937. Vector vecWorldPos( SubFloat( xyz[ nXYZIndex ], nOffset ), SubFloat( xyz[ nXYZIndex+1 ], nOffset ), SubFloat( xyz[ nXYZIndex+2 ], nOffset ) );
  1938. Vector vecViewPos;
  1939. Vector3DMultiplyPosition( tempView, vecWorldPos, vecViewPos );
  1940. if (!IsFinite(vecViewPos.x))
  1941. continue;
  1942. int nPrevXYZIndex = nGroup * prev_xyz_stride;
  1943. Vector vecPrevWorldPos( SubFloat( prev_xyz[ nPrevXYZIndex ], nOffset ), SubFloat( prev_xyz[ nPrevXYZIndex+1 ], nOffset ), SubFloat( prev_xyz[ nPrevXYZIndex+2 ], nOffset ) );
  1944. Vector vecPrevViewPos;
  1945. Vector3DMultiplyPosition( tempView, vecPrevWorldPos, vecPrevViewPos );
  1946. float rot = atan2( vecViewPos.y - vecPrevViewPos.y, vecViewPos.x - vecPrevViewPos.x ) + flForwardRadians;
  1947. SubFloat( pRot[ nGroup * rot_stride ], nOffset ) = rot;
  1948. }
  1949. }
  1950. //-----------------------------------------------------------------------------
  1951. // Installs renderers
  1952. //-----------------------------------------------------------------------------
  1953. void AddBuiltInParticleRenderers( void )
  1954. {
  1955. #ifdef _DEBUG
  1956. REGISTER_PARTICLE_OPERATOR( FUNCTION_RENDERER, C_OP_RenderPoints );
  1957. #endif
  1958. REGISTER_PARTICLE_OPERATOR( FUNCTION_RENDERER, C_OP_RenderSprites );
  1959. REGISTER_PARTICLE_OPERATOR( FUNCTION_RENDERER, C_OP_RenderSpritesTrail );
  1960. REGISTER_PARTICLE_OPERATOR( FUNCTION_RENDERER, C_OP_RenderRope );
  1961. REGISTER_PARTICLE_OPERATOR( FUNCTION_RENDERER, C_OP_RenderScreenVelocityRotate );
  1962. #ifdef USE_BLOBULATOR
  1963. REGISTER_PARTICLE_OPERATOR( FUNCTION_RENDERER, C_OP_RenderBlobs );
  1964. #endif // blobs
  1965. }