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

449 lines
14 KiB

  1. //===================== Copyright (c) Valve Corporation. All Rights Reserved. ======================
  2. #ifndef FINITE_ELEMENT_MODEL_BUILDER_HDR
  3. #define FINITE_ELEMENT_MODEL_BUILDER_HDR
  4. #include "tier1/utlvector.h"
  5. #include "tier1/utlhashtable.h"
  6. #include "tier1/utlsortvector.h"
  7. #include "mathlib/femodel.h"
  8. #include "tier1/utlbufferstrider.h"
  9. template <typename T>
  10. class CUtlVectorOfPointers: public CUtlVector< T * >
  11. {
  12. public:
  13. ~CUtlVectorOfPointers( )
  14. {
  15. Purge( );
  16. }
  17. template <typename Functor>
  18. void SetCountAndInit( int nCount, Functor fn )
  19. {
  20. CUtlVector< T * >::SetCount( nCount );
  21. for ( int i = 0; i < nCount; ++i )
  22. {
  23. CUtlVector< T * >::Element( i ) = fn( i );
  24. }
  25. }
  26. void Purge( )
  27. {
  28. for ( int i = 0; i < CUtlVector< T * >::Count( ); ++i )
  29. {
  30. delete ( *this )[ i ];
  31. }
  32. CUtlVector< T * >::Purge( );
  33. }
  34. };
  35. class CFeModelBuilder: public CFeModel, public CMultiBufferHelper< CFeModelBuilder >
  36. {
  37. public:
  38. struct BuildElem_t;
  39. CFeModelBuilder( )
  40. {
  41. V_memset( static_cast< CFeModel* >( this ), 0, sizeof( CFeModel ) );
  42. m_bIdentityCtrlOrder = false;
  43. m_bEnableExplicitNodeMasses = false;
  44. m_bUnitlessDamping = false;
  45. m_bAddStiffnessRods = true;
  46. m_bUsePerNodeLocalForceAndRotation = false;
  47. m_flQuadBendTolerance = 0.05f;
  48. m_bRigidEdgeHinges = false;
  49. m_nFitMatrixMinInfluences = 8;
  50. m_bNeedBacksolvedBasesOnly = false;
  51. }
  52. typedef CUtlVectorFixedGrowable< FeFitWeight_t, 8 > FitWeightArray_t;
  53. void EnableUnitlessDamping( bool bEnableUnitlessDamping ) { m_bUnitlessDamping = bEnableUnitlessDamping; }
  54. void EnableIdentityCtrlOrder( ) { m_bIdentityCtrlOrder = true; }
  55. void EnableExplicitNodeMasses( bool bExplicit ) { m_bEnableExplicitNodeMasses = bExplicit; }
  56. void EnableRigidStiffnessRods( bool bRigidStiffnessRods ) { m_bRigidEdgeHinges = bRigidStiffnessRods; }
  57. void SetQuadBendTolerance( float flQuadBendTolerance ) { m_flQuadBendTolerance = flQuadBendTolerance; }
  58. bool Finish( bool bTriangulate, float flAddCurvature, float flAddSlack );
  59. void AdjustQuads();
  60. float ElemNormalLength( const uint nNode[4] );
  61. float NodeDist( uint nNode0, uint nNode1 );
  62. Vector TriNormal( uint nNode0, uint nNode1, uint nNode2 );
  63. void AddBendCurvature( float k )
  64. {
  65. for ( int i = 0; i < m_KelagerBends.Count( ); ++i )
  66. {
  67. FeKelagerBend_t &kbend = m_KelagerBends[ i ];
  68. float flMinSide = FLT_MAX;
  69. for ( int j = 0; j < 4; ++j )
  70. {
  71. uint n0 = kbend.m_nNode[ j ], n1 = kbend.m_nNode[ ( j + 1 ) % 4 ];
  72. if ( n1 != n0 )
  73. {
  74. float flSide = ( m_Nodes[ n0 ].transform.m_vPosition - m_Nodes[ n1 ].transform.m_vPosition ).Length( );
  75. if ( flSide < flMinSide )
  76. flMinSide = flSide;
  77. }
  78. }
  79. kbend.flHeight0 += flMinSide * k;
  80. }
  81. for ( int i = 0; i < m_AxialEdges.Count( ); ++i )
  82. {
  83. FeAxialEdgeBend_t &edge = m_AxialEdges[ i ];
  84. Vector f01 = m_Nodes[ edge.nNode[ 0 ] ].transform.m_vPosition * edge.te + m_Nodes[ edge.nNode[ 1 ] ].transform.m_vPosition * ( 1 - edge.te );
  85. float h = ( m_Nodes[ edge.nNode[ 2 ] ].transform.m_vPosition - f01 ).Length( ) + ( m_Nodes[ edge.nNode[ 3 ] ].transform.m_vPosition - f01 ).Length( );
  86. edge.flDist += h * k;
  87. }
  88. }
  89. struct MbaContext_t;
  90. int FindBuildNodeIndex( const char *pName );
  91. void BuildAxialEdges( );
  92. void BuildOldFeEdges( );
  93. void BuildKelagerBends( );
  94. void BuildAndSortRods( float flCurvatureAngle, bool bTriangulate );
  95. void BuildRod( float flCurvatureAngle, uint v0, uint v1, uint nElem0, uint nElem1, uint nEdge0, uint nEdge1, CUtlHashtable< uint32, uint32 > &edgeToRod );
  96. void BuildQuads( CUtlVector< FeQuad_t > &quads, bool bSkipTris );
  97. void BuildTris( CUtlVector< FeTri_t > &quads, bool bTriangulate );
  98. void BuildNodeSlack( float flSlackMultiplier );
  99. void BuildFeEdgeDesc( );
  100. void BuildInvMassesAndSortNodes( );
  101. int ReconcileElemStaticNodes();
  102. int RemoveFullyStaticElems();
  103. void BuildBaseRecovery( );
  104. void BuildRopes( );
  105. void BuildFreeNodes( MbaContext_t &context );
  106. void BuildCtrlOffsets( );
  107. void BuildNodeFollowers( CUtlVector< FeFollowNode_t > &nodeFollowers );
  108. uint BuildCollisionSpheres( CUtlVector< FeCollisionSphere_t > &collisionSpheres );
  109. void BuildCollisionPlanes( CUtlVector< FeCollisionPlane_t > &collisionPlanes );
  110. void BuildWorldCollisionNodes( CUtlVector< FeWorldCollisionParams_t > &worldCollisionParams, CUtlVector< uint16 > &worldCollisionNodes );
  111. void BuildFitMatrices( MbaContext_t &context );
  112. void RemoveStandaloneNodeBases( MbaContext_t &context );
  113. Vector ComputeCenter( const FitWeightArray_t &weights );
  114. void CheckIdentityCtrlOrder( );
  115. void BuildSprings( CUtlVector< FeSpringIntegrator_t > &springs );
  116. void ValidateBases( );
  117. void PrintNodeTree( uint nNode, const CUtlString &prefix );
  118. void CleanupElements();
  119. void RecomputeMasses( CUtlVector< float >& nodeMass );
  120. void BalanceGlobalMassMultipliers( CUtlVector< float >& nodeMass );
  121. int CountSimulatedNodesIn( const FeRodConstraint_t & rod );
  122. int CountSimulatedNodesIn( const BuildElem_t& elem );
  123. void BuildTree();
  124. FeTri_t BuildTri( const BuildElem_t &buildElem, int nTriStaticNodes, int nSubTri );
  125. uint GetDampingFlags( )const
  126. {
  127. uint nFlags = 0;
  128. for ( int i = 0; i < m_Nodes.Count( ); ++i )
  129. {
  130. nFlags |= m_Nodes[ i ].GetDampingFlags( );
  131. }
  132. return nFlags;
  133. }
  134. bool HasLegacyStretchForce( ) const;
  135. struct MbaContext_t
  136. {
  137. CUtlVector< FeQuad_t > quads;
  138. CUtlVector< FeTri_t > tris;
  139. CUtlVectorAligned< FeSimdRodConstraint_t > simdRods;
  140. CUtlVectorAligned< FeSimdQuad_t > simdQuads[ 3 ];
  141. CUtlVectorAligned< FeSimdTri_t > simdTris[ 3 ];
  142. CUtlVectorAligned< FeSimdNodeBase_t > simdBases;
  143. CUtlVector< FeSpringIntegrator_t > springs;
  144. CUtlVectorAligned< FeSimdSpringIntegrator_t > simdSprings;
  145. CUtlVector< FeFollowNode_t > nodeFollowers;;
  146. CUtlVector< FeCollisionSphere_t > collisionSpheres;
  147. CUtlVector< FeCollisionPlane_t > collisionPlanes;
  148. CUtlVector< FeWorldCollisionParams_t > worldCollisionParams;
  149. CUtlVector< uint16 > worldCollisionNodes;
  150. CUtlVectorAligned< FeFitMatrix_t > fitMatrices;
  151. FitWeightArray_t fitWeights;
  152. uint m_nFitMatrices1;
  153. uint m_nFitMatrices2;
  154. uint nLegacyStretchForceCount;
  155. uint nCollisionEllipsoidsInclusive;
  156. uint nNodeIntegratorCount;
  157. uint nStringsMemSize;
  158. uint nCtrlNameCount;
  159. bool m_bHasNodeCollisionRadii;
  160. bool m_bUsePerNodeLocalRotation;
  161. bool m_bUsePerNodeLocalForce;
  162. };
  163. template <typename Allocator > void OnAllocateMultiBuffer( Allocator &a, MbaContext_t &context );
  164. protected:
  165. void ConvertCtrlToNode( int &refCtrl )
  166. {
  167. if ( refCtrl >= 0 )
  168. {
  169. Assert( refCtrl < m_CtrlToNode.Count() );
  170. refCtrl = m_CtrlToNode[ refCtrl ];
  171. }
  172. }
  173. void ConvertCtrlToNode( uint16 &refCtrl )
  174. {
  175. Assert( int( refCtrl ) < m_CtrlToNode.Count() );
  176. refCtrl = m_CtrlToNode[ refCtrl ];
  177. }
  178. void ConvertCtrlToNode( uint32 &refCtrl )
  179. {
  180. Assert( int( refCtrl ) < m_CtrlToNode.Count() );
  181. refCtrl = m_CtrlToNode[ refCtrl ];
  182. }
  183. float GetRank( const FeAxialEdgeBend_t &bend )const
  184. {
  185. float flRank = 0;
  186. // ad-hoc ranking of bends; if a bend affects some node a lot, then it's ranked closer to that node.
  187. // Ranks of nodes within one bend shouldn't differ by more than 2, because the bends are comprised
  188. // of adjacent quads' nodes, so this won't deviate much from strict ranking by the lowest-rank node in the bend
  189. flRank += bend.flWeight[ 0 ] * m_Nodes[ bend.nNode[ 0 ] ].nRank;
  190. flRank += bend.flWeight[ 1 ] * m_Nodes[ bend.nNode[ 1 ] ].nRank;
  191. flRank += bend.flWeight[ 2 ] * m_Nodes[ bend.nNode[ 2 ] ].nRank;
  192. flRank += bend.flWeight[ 2 ] * m_Nodes[ bend.nNode[ 3 ] ].nRank;
  193. flRank += bend.flWeight[ 3 ] * m_Nodes[ bend.nNode[ 4 ] ].nRank;
  194. flRank += bend.flWeight[ 3 ] * m_Nodes[ bend.nNode[ 5 ] ].nRank;
  195. return flRank;
  196. }
  197. public:
  198. struct BuildElem_t
  199. {
  200. enum { MAX_NODES = 4 };
  201. BuildElem_t()
  202. {
  203. nRank = 0;
  204. flSlack = 0;
  205. nStaticNodes = 0;
  206. for ( int i = 0; i < MAX_NODES; ++i )
  207. nNode[ i ] = 0;
  208. }
  209. uint nNode[ MAX_NODES ];
  210. uint NumNodes( )const { return nNode[ 3 ] == nNode[ 2 ] ? 3 : 4; }
  211. uint nStaticNodes; // 0..2
  212. float flSlack;
  213. int nRank; // 0 means static, then it means "how many elements removed from the closest static"
  214. static bool Order( const BuildElem_t &left, const BuildElem_t &right )
  215. {
  216. int nDelta = int( right.nStaticNodes ) - int( left.nStaticNodes );
  217. if ( nDelta == 0 )
  218. {
  219. return left.nRank < right.nRank;
  220. }
  221. return nDelta < 0;
  222. }
  223. };
  224. struct BuildSpring_t
  225. {
  226. uint16 nNode[ 2 ];
  227. float32 flSpringConstant;
  228. float32 flSpringDamping;
  229. float32 flStretchiness; // Not Implemented!
  230. };
  231. struct BuildCollisionSphere_t
  232. {
  233. int m_nParent;
  234. int m_nChild;
  235. float m_flRadius;
  236. Vector m_vOrigin;
  237. bool m_bInclusive;
  238. float m_flStickiness;
  239. BuildCollisionSphere_t( )
  240. {
  241. m_nParent = -1;
  242. m_nChild = -1;
  243. m_flRadius = 0;
  244. m_vOrigin = vec3_origin;
  245. m_bInclusive = true;
  246. m_flStickiness = 0;
  247. }
  248. bool IsDegenerate( )const
  249. {
  250. return m_nParent < 0 || m_nChild < 0 || ( !m_bInclusive && m_flRadius < 1e-3f );
  251. }
  252. };
  253. struct BuildCollisionPlane_t
  254. {
  255. int m_nParent;
  256. int m_nChild;
  257. RnPlane_t m_Plane;
  258. float m_flStickiness;
  259. BuildCollisionPlane_t( )
  260. {
  261. m_nParent = -1;
  262. m_nChild = -1;
  263. m_Plane.m_flOffset = 0;
  264. m_flStickiness = 0;
  265. m_Plane.m_vNormal = vec3_origin;
  266. }
  267. bool IsDegenerate( )const
  268. {
  269. return m_nParent < 0 || m_nChild < 0 || m_Plane.m_vNormal.LengthSqr( ) < 1e-12f;
  270. }
  271. };
  272. struct BuildNode_t
  273. {
  274. CTransform transform; // relaxed position
  275. float flMassMultiplier;
  276. float flMassBias;
  277. float invMass;
  278. float flSlack;
  279. float flGravityZ;
  280. float flCollisionRadius;
  281. FeNodeIntegrator_t integrator;
  282. const char *pName;
  283. int nParent;
  284. int nRank; // 0 means static, then it means "how many elements removed from the closest static"
  285. uint nCollisionMask;
  286. int nFollowParent;
  287. float flFollowWeight;
  288. float flWorldFriction; // not really a friction coefficient, this corresponds to WorldFriction coefficient from Source1 cloth
  289. float flGroundFriction;
  290. float flLegacyStretchForce;
  291. float flLocalForce;
  292. float flLocalRotation;
  293. bool bSimulated : 1;
  294. bool bForceSimulated : 1;
  295. bool bFreeRotation : 1;
  296. bool bAnimRotation : 1;
  297. bool bMassMultiplierGlobal : 1; // if true, the mass multipliers are gathered and distributed so that all nodes with "global" multipliers keep the mass ratio = multiplier ratio
  298. bool bVirtual : 1;
  299. bool bNeedNodeBase : 1;
  300. bool bWorldCollision : 1;
  301. bool bOsOffset : 1;
  302. BuildNode_t( )
  303. {
  304. bSimulated = false;
  305. bForceSimulated = false;
  306. bFreeRotation = false; // true only makes sense for non-simulated
  307. bAnimRotation = false;
  308. bMassMultiplierGlobal = false;
  309. bVirtual = false;
  310. bNeedNodeBase = false;
  311. bWorldCollision = false;
  312. bOsOffset = false;
  313. flWorldFriction = 1.0f;
  314. flGroundFriction = 0.0f;
  315. flLegacyStretchForce = 0;
  316. transform = g_TransformIdentity;
  317. flMassMultiplier = 1.0f; // can be 0
  318. flMassBias = 0.0f;
  319. invMass = 0.0f; // can be arbitrary
  320. flSlack = 0.0f;
  321. flCollisionRadius = 0;
  322. flGravityZ = 360;
  323. pName = NULL;
  324. nRank = 0;
  325. nParent = -1;
  326. nFollowParent = -1;
  327. flFollowWeight = 0;
  328. nCollisionMask = 0;
  329. flLocalForce = 1.0f;
  330. flLocalRotation = 0.0f;
  331. integrator.Init();
  332. }
  333. uint GetDampingFlags( )const
  334. {
  335. uint nFlags = 0;
  336. if ( integrator.flPointDamping != 0 )
  337. nFlags |= FE_FLAG_HAS_NODE_DAMPING;
  338. if ( integrator.flAnimationVertexAttraction != 0 )
  339. nFlags |= FE_FLAG_HAS_ANIMATION_VERTEX_ATTRACTION;
  340. if ( integrator.flAnimationForceAttraction != 0 )
  341. nFlags |= FE_FLAG_HAS_ANIMATION_FORCE_ATTRACTION;
  342. if ( integrator.flGravity != 360 )
  343. nFlags |= FE_FLAG_HAS_CUSTOM_GRAVITY;
  344. if ( bSimulated && flLegacyStretchForce != 0 )
  345. nFlags |= FE_FLAG_HAS_STRETCH_VELOCITY_DAMPING;
  346. return nFlags;
  347. }
  348. };
  349. public:
  350. // this is to precompute orientations of bones that we have the freedom to orient
  351. static FeNodeBase_t BuildNodeBasisFast( const CUtlVectorAligned< BuildNode_t > &nodes, uint nNode, const CUtlSortVector< int > &neighbors );
  352. static void BuildNodeBases( const CUtlVectorAligned< BuildNode_t > &nodes, const CUtlVector< BuildElem_t > &elems, const CUtlVector< FeNodeBase_t > &presetNodeBases, CUtlVector< FeNodeBase_t > &nodeBases, CUtlVectorOfPointers< CUtlSortVector< int > > &neighbors );
  353. void BuildNodeBases();
  354. FeNodeBase_t BuildNodeBasisFast( uint nNode );
  355. public:
  356. // class CFitMatrix
  357. // {
  358. // public:
  359. // int m_nStaticWeights; // should normally be 0,1 or 2. If 3+ static nodes influence this fit matrix, maybe we should only keep those static node influences and say we have 0 static nodes, so that it back-soves to static nodes only
  360. // CUtlVector< InfluenceWeight_t > m_Weights;
  361. // };
  362. // generated
  363. CUtlVectorOfPointers< CUtlSortVector< int > > m_NodeNeighbors;
  364. CUtlVector< FeCtrlOffset_t > m_CtrlOffsets;
  365. CUtlVector< FeCtrlOsOffset_t > m_CtrlOsOffsets;
  366. CUtlVector< FeAxialEdgeBend_t > m_AxialEdges;
  367. CUtlVector< OldFeEdge_t > m_OldFeEdges;
  368. CUtlVector< FeKelagerBend_t > m_KelagerBends;
  369. CUtlVector< FeEdgeDesc_t > m_FeEdgeDesc;
  370. CUtlVector< int > m_NodeToCtrl;
  371. CUtlVector< int > m_CtrlToNode;
  372. CUtlVectorOfPointers< CUtlVector< int > > m_Ropes;
  373. CUtlVector< FeNodeBase_t > m_NodeBases;
  374. CUtlVector< FeNodeReverseOffset_t > m_ReverseOffsets;
  375. CUtlVector< uint16 > m_TreeParents; // dynamic nodes (N) + clusters (N-1)
  376. CUtlVector< FeTreeChildren_t > m_TreeChildren; // clusters (N-1) * 2
  377. CUtlVector< uint16 > m_FreeNodes;
  378. // input
  379. CUtlVector< FeNodeBase_t > m_PresetNodeBases;
  380. CUtlVector< FeTaperedCapsuleStretch_t > m_TaperedCapsuleStretches;
  381. CUtlVector< FeTaperedCapsuleRigid_t > m_TaperedCapsuleRigids;
  382. CUtlVector< FeSphereRigid_t > m_SphereRigids;
  383. CUtlVector< BuildCollisionSphere_t > m_CollisionSpheres;
  384. CUtlVector< BuildCollisionPlane_t > m_CollisionPlanes;
  385. CUtlVector< BuildSpring_t > m_Springs;
  386. CUtlVector< FeRodConstraint_t > m_Rods;
  387. CUtlVector< BuildElem_t > m_Elems;
  388. CUtlVectorAligned< BuildNode_t > m_Nodes; // in-out
  389. CUtlVector< FeFitInfluence_t > m_FitInfluences;
  390. CUtlVectorOfPointers< CUtlSortVector< int > > m_Neighbors;
  391. bool m_bIdentityCtrlOrder;
  392. bool m_bEnableExplicitNodeMasses;
  393. bool m_bUnitlessDamping;
  394. bool m_bAddStiffnessRods;
  395. bool m_bUsePerNodeLocalForceAndRotation;
  396. bool m_bRigidEdgeHinges;
  397. float m_flQuadBendTolerance;
  398. int m_nFitMatrixMinInfluences;
  399. bool m_bNeedBacksolvedBasesOnly;
  400. };
  401. #endif