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.

335 lines
10 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #ifndef FLEXRENDERDATA_H
  8. #define FLEXRENDERDATA_H
  9. #ifdef _WIN32
  10. #pragma once
  11. #endif
  12. #include "mathlib/vector.h"
  13. #include "utlvector.h"
  14. #include "studio.h"
  15. //-----------------------------------------------------------------------------
  16. // forward declarations
  17. //-----------------------------------------------------------------------------
  18. struct mstudiomesh_t;
  19. //-----------------------------------------------------------------------------
  20. // Used by flex vertex data cache
  21. //-----------------------------------------------------------------------------
  22. struct CachedPosNormTan_t
  23. {
  24. Vector m_Position;
  25. Vector m_Normal;
  26. Vector4D m_TangentS;
  27. CachedPosNormTan_t() {}
  28. CachedPosNormTan_t( CachedPosNormTan_t const& src )
  29. {
  30. VectorCopy( src.m_Position, m_Position );
  31. VectorCopy( src.m_Normal, m_Normal );
  32. Vector4DCopy( src.m_TangentS, m_TangentS );
  33. Assert( m_TangentS.w == 1.0f || m_TangentS.w == -1.0f );
  34. }
  35. };
  36. //-----------------------------------------------------------------------------
  37. // Used by world (decal) vertex data cache
  38. //-----------------------------------------------------------------------------
  39. struct CachedPosNorm_t
  40. {
  41. Vector4DAligned m_Position;
  42. Vector4DAligned m_Normal;
  43. CachedPosNorm_t() {}
  44. CachedPosNorm_t( CachedPosNorm_t const& src )
  45. {
  46. Vector4DCopy( src.m_Position, m_Position );
  47. Vector4DCopy( src.m_Normal, m_Normal );
  48. }
  49. };
  50. //-----------------------------------------------------------------------------
  51. // Stores flex vertex data and world (decal) vertex data for the lifetime of the model rendering
  52. //-----------------------------------------------------------------------------
  53. class CCachedRenderData
  54. {
  55. public:
  56. // Constructor
  57. CCachedRenderData();
  58. // Call this when we start to render a new model
  59. void StartModel();
  60. // Used to hook ourselves into a particular body part, model, and mesh
  61. void SetBodyPart( int bodypart );
  62. void SetModel( int model );
  63. void SetMesh( int mesh );
  64. // For faster setup in the decal code
  65. void SetBodyModelMesh( int body, int model, int mesh );
  66. // Used to set up a flex computation
  67. bool IsFlexComputationDone( ) const;
  68. // Used to set up a computation (for world or flex data)
  69. void SetupComputation( mstudiomesh_t *pMesh, bool flexComputation = false );
  70. // Is a particular vertex flexed?
  71. bool IsVertexFlexed( int vertex ) const;
  72. bool IsThinVertexFlexed( int vertex ) const;
  73. // Checks to see if the vertex is defined
  74. bool IsVertexPositionCached( int vertex ) const;
  75. // Gets a flexed vertex
  76. CachedPosNormTan_t* GetFlexVertex( int vertex );
  77. // Gets a flexed vertex
  78. CachedPosNorm_t* GetThinFlexVertex( int vertex );
  79. // Creates a new flexed vertex to be associated with a vertex
  80. CachedPosNormTan_t* CreateFlexVertex( int vertex );
  81. // Creates a new flexed vertex to be associated with a vertex
  82. CachedPosNorm_t* CreateThinFlexVertex( int vertex );
  83. // Renormalizes the normals and tangents of the flex verts
  84. void RenormalizeFlexVertices( bool bHasTangentData );
  85. // Gets a decal vertex
  86. CachedPosNorm_t* GetWorldVertex( int vertex );
  87. // Creates a new decal vertex to be associated with a vertex
  88. CachedPosNorm_t* CreateWorldVertex( int vertex );
  89. template< class T >
  90. void ComputeFlexedVertex_StreamOffset( studiohdr_t *pStudioHdr, mstudioflex_t *pflex, T *pvanim, int vertCount, float w1, float w2, float w3, float w4 );
  91. #ifdef PLATFORM_WINDOWS
  92. void ComputeFlexedVertex_StreamOffset_Optimized( studiohdr_t *pStudioHdr, mstudioflex_t *pflex, mstudiovertanim_t *pvanim, int vertCount, float w1, float w2, float w3, float w4);
  93. void ComputeFlexedVertexWrinkle_StreamOffset_Optimized( studiohdr_t *pStudioHdr, mstudioflex_t *pflex, mstudiovertanim_wrinkle_t *pvanim, int vertCount, float w1, float w2, float w3, float w4);
  94. #endif // PLATFORM_WINDOWS
  95. private:
  96. // Used to create the flex render data. maps
  97. struct CacheIndex_t
  98. {
  99. unsigned short m_Tag;
  100. unsigned short m_VertexIndex;
  101. };
  102. // A dictionary for the cached data
  103. struct CacheDict_t
  104. {
  105. unsigned short m_FirstIndex;
  106. unsigned short m_IndexCount;
  107. unsigned short m_Tag;
  108. unsigned short m_FlexTag;
  109. CacheDict_t() : m_Tag(0), m_FlexTag(0) {}
  110. };
  111. typedef CUtlVector< CacheDict_t > CacheMeshDict_t;
  112. typedef CUtlVector< CacheMeshDict_t > CacheModelDict_t;
  113. typedef CUtlVector< CacheModelDict_t > CacheBodyPartDict_t;
  114. // Flex data, allocated for the lifespan of rendering
  115. // Can't use UtlVector due to alignment issues
  116. int m_FlexVertexCount;
  117. CachedPosNormTan_t m_pFlexVerts[MAXSTUDIOFLEXVERTS+1];
  118. // Flex data, allocated for the lifespan of rendering
  119. // Can't use UtlVector due to alignment issues
  120. int m_ThinFlexVertexCount;
  121. CachedPosNorm_t m_pThinFlexVerts[MAXSTUDIOFLEXVERTS+1];
  122. // World data, allocated for the lifespan of rendering
  123. // Can't use UtlVector due to alignment issues
  124. int m_WorldVertexCount;
  125. CachedPosNorm_t m_pWorldVerts[MAXSTUDIOVERTS+1];
  126. // Maps actual mesh vertices into flex cache + world cache indices
  127. int m_IndexCount;
  128. CacheIndex_t m_pFlexIndex[MAXSTUDIOVERTS+1];
  129. CacheIndex_t m_pThinFlexIndex[MAXSTUDIOVERTS+1];
  130. CacheIndex_t m_pWorldIndex[MAXSTUDIOVERTS+1];
  131. CacheBodyPartDict_t m_CacheDict;
  132. // The flex tag
  133. unsigned short m_CurrentTag;
  134. // the current body, model, and mesh
  135. int m_Body;
  136. int m_Model;
  137. int m_Mesh;
  138. // mapping for the current mesh to flex data
  139. CacheIndex_t* m_pFirstFlexIndex;
  140. CacheIndex_t* m_pFirstThinFlexIndex;
  141. CacheIndex_t* m_pFirstWorldIndex;
  142. friend class CStudioRender;
  143. };
  144. //-----------------------------------------------------------------------------
  145. // Checks to see if the vertex is defined
  146. //-----------------------------------------------------------------------------
  147. inline bool CCachedRenderData::IsVertexFlexed( int vertex ) const
  148. {
  149. return (m_pFirstFlexIndex && (m_pFirstFlexIndex[vertex].m_Tag == m_CurrentTag));
  150. }
  151. inline bool CCachedRenderData::IsThinVertexFlexed( int vertex ) const
  152. {
  153. return (m_pFirstThinFlexIndex && (m_pFirstThinFlexIndex[vertex].m_Tag == m_CurrentTag));
  154. }
  155. //-----------------------------------------------------------------------------
  156. // Gets an existing flexed vertex associated with a vertex
  157. //-----------------------------------------------------------------------------
  158. inline CachedPosNormTan_t* CCachedRenderData::GetFlexVertex( int vertex )
  159. {
  160. Assert( m_pFirstFlexIndex );
  161. Assert( m_pFirstFlexIndex[vertex].m_Tag == m_CurrentTag );
  162. return &m_pFlexVerts[ m_pFirstFlexIndex[vertex].m_VertexIndex ];
  163. }
  164. inline CachedPosNorm_t* CCachedRenderData::GetThinFlexVertex( int vertex )
  165. {
  166. Assert( m_pFirstThinFlexIndex );
  167. Assert( m_pFirstThinFlexIndex[vertex].m_Tag == m_CurrentTag );
  168. return &m_pThinFlexVerts[ m_pFirstThinFlexIndex[vertex].m_VertexIndex ];
  169. }
  170. //-----------------------------------------------------------------------------
  171. // Checks to see if the vertex is defined
  172. //-----------------------------------------------------------------------------
  173. inline bool CCachedRenderData::IsVertexPositionCached( int vertex ) const
  174. {
  175. return (m_pFirstWorldIndex && (m_pFirstWorldIndex[vertex].m_Tag == m_CurrentTag));
  176. }
  177. //-----------------------------------------------------------------------------
  178. // Gets an existing world vertex associated with a vertex
  179. //-----------------------------------------------------------------------------
  180. inline CachedPosNorm_t* CCachedRenderData::GetWorldVertex( int vertex )
  181. {
  182. Assert( m_pFirstWorldIndex );
  183. Assert( m_pFirstWorldIndex[vertex].m_Tag == m_CurrentTag );
  184. return &m_pWorldVerts[ m_pFirstWorldIndex[vertex].m_VertexIndex ];
  185. }
  186. //-----------------------------------------------------------------------------
  187. // For faster setup in the decal code
  188. //-----------------------------------------------------------------------------
  189. inline void CCachedRenderData::SetBodyModelMesh( int body, int model, int mesh)
  190. {
  191. m_Body = body;
  192. m_Model = model;
  193. m_Mesh = mesh;
  194. Assert((m_Model >= 0) && (m_Body >= 0));
  195. m_CacheDict[m_Body][m_Model].EnsureCount(m_Mesh+1);
  196. // At this point, we should have all 3 defined.
  197. CacheDict_t& dict = m_CacheDict[m_Body][m_Model][m_Mesh];
  198. if (dict.m_Tag == m_CurrentTag)
  199. {
  200. m_pFirstFlexIndex = &m_pFlexIndex[dict.m_FirstIndex];
  201. m_pFirstThinFlexIndex = &m_pThinFlexIndex[dict.m_FirstIndex];
  202. m_pFirstWorldIndex = &m_pWorldIndex[dict.m_FirstIndex];
  203. }
  204. else
  205. {
  206. m_pFirstFlexIndex = 0;
  207. m_pFirstThinFlexIndex = 0;
  208. m_pFirstWorldIndex = 0;
  209. }
  210. }
  211. //-----------------------------------------------------------------------------
  212. // Purpose:
  213. //
  214. // ** Only execute this function if device supports stream offset **
  215. //
  216. // Input : pmesh - pointer to a studio mesh
  217. // lod - integer lod (0 is most detailed)
  218. // Output : none
  219. //-----------------------------------------------------------------------------
  220. template< class T >
  221. void CCachedRenderData::ComputeFlexedVertex_StreamOffset( studiohdr_t *pStudioHdr, mstudioflex_t *pflex,
  222. T *pvanim, int vertCount, float w1, float w2, float w3, float w4 )
  223. {
  224. float w12 = w1 - w2;
  225. float w34 = w3 - w4;
  226. float flVertAnimFixedPointScale = pStudioHdr->VertAnimFixedPointScale();
  227. CachedPosNorm_t *pFlexedVertex = NULL;
  228. for (int j = 0; j < pflex->numverts; j++)
  229. {
  230. int n = pvanim[j].index;
  231. // only flex the indices that are (still) part of this mesh at this lod
  232. if ( n >= vertCount )
  233. continue;
  234. float s = pvanim[j].speed;
  235. float b = pvanim[j].side;
  236. Vector4DAligned vPosition, vNormal;
  237. pvanim[j].GetDeltaFixed4DAligned( &vPosition, flVertAnimFixedPointScale );
  238. pvanim[j].GetNDeltaFixed4DAligned( &vNormal, flVertAnimFixedPointScale );
  239. if ( !IsThinVertexFlexed(n) )
  240. {
  241. // Add a new flexed vert to the flexed vertex list
  242. pFlexedVertex = CreateThinFlexVertex(n);
  243. Assert( pFlexedVertex != NULL);
  244. pFlexedVertex->m_Position.InitZero();
  245. pFlexedVertex->m_Normal.InitZero();
  246. }
  247. else
  248. {
  249. pFlexedVertex = GetThinFlexVertex(n);
  250. }
  251. s *= 1.0f / 255.0f;
  252. b *= 1.0f / 255.0f;
  253. float wa = w2 + w12 * s;
  254. float wb = w4 + w34 * s;
  255. float w = wa + ( wb - wa ) * b;
  256. Vector4DWeightMAD( w, vPosition, pFlexedVertex->m_Position, vNormal, pFlexedVertex->m_Normal );
  257. }
  258. }
  259. #endif // FLEXRENDERDATA_H