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.

152 lines
3.5 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "rope_physics.h"
  9. #include "tier0/dbg.h"
  10. // memdbgon must be the last include file in a .cpp file!!!
  11. #include "tier0/memdbgon.h"
  12. CBaseRopePhysics::CBaseRopePhysics( CSimplePhysics::CNode *pNodes, int nNodes, CRopeSpring *pSprings, float *flSpringDistsSqr )
  13. {
  14. m_pNodes = pNodes;
  15. m_pSprings = pSprings;
  16. m_flNodeSpringDistsSqr = flSpringDistsSqr;
  17. m_flSpringDist = m_flSpringDistSqr = 1;
  18. Restart();
  19. // Initialize the nodes.
  20. for ( int i=0; i < nNodes; i++ )
  21. {
  22. pNodes[i].m_vPos.Init();
  23. pNodes[i].m_vPrevPos.Init();
  24. pNodes[i].m_vPredicted.Init();
  25. }
  26. SetNumNodes( nNodes );
  27. m_pDelegate = NULL;
  28. }
  29. void CBaseRopePhysics::SetNumNodes( int nNodes )
  30. {
  31. m_nNodes = nNodes;
  32. // Setup the springs.
  33. for( int i=0; i < NumSprings(); i++ )
  34. {
  35. m_pSprings[i].m_pNode1 = &m_pNodes[i].m_vPos;
  36. m_pSprings[i].m_pNode2 = &m_pNodes[i+1].m_vPos;
  37. Assert( m_pSprings[i].m_pNode1->IsValid() );
  38. Assert( m_pSprings[i].m_pNode2->IsValid() );
  39. m_flNodeSpringDistsSqr[i] = m_flSpringDistSqr / NumSprings();
  40. }
  41. }
  42. void CBaseRopePhysics::Restart()
  43. {
  44. m_Physics.Init( 1.0 / 50 );
  45. }
  46. void CBaseRopePhysics::ResetSpringLength( float flSpringDist )
  47. {
  48. m_flSpringDist = max( flSpringDist, 0.f );
  49. m_flSpringDistSqr = m_flSpringDist * m_flSpringDist;
  50. for( int i=0; i < NumSprings(); i++ )
  51. {
  52. m_flNodeSpringDistsSqr[i] = m_flSpringDistSqr / NumSprings();
  53. }
  54. }
  55. float CBaseRopePhysics::GetSpringLength() const
  56. {
  57. return m_flSpringDist;
  58. }
  59. void CBaseRopePhysics::ResetNodeSpringLength( int iStartNode, float flSpringDist )
  60. {
  61. m_flNodeSpringDistsSqr[iStartNode] = flSpringDist * flSpringDist;
  62. }
  63. void CBaseRopePhysics::SetupSimulation( float flSpringDist, CSimplePhysics::IHelper *pDelegate )
  64. {
  65. ResetSpringLength( flSpringDist );
  66. SetDelegate( pDelegate );
  67. }
  68. void CBaseRopePhysics::SetDelegate( CSimplePhysics::IHelper *pDelegate )
  69. {
  70. m_pDelegate = pDelegate;
  71. }
  72. void CBaseRopePhysics::Simulate( float dt )
  73. {
  74. static float flEnergy = 0.98;
  75. m_Physics.Simulate( m_pNodes, m_nNodes, this, dt, flEnergy );
  76. }
  77. void CBaseRopePhysics::GetNodeForces( CSimplePhysics::CNode *pNodes, int iNode, Vector *pAccel )
  78. {
  79. if( m_pDelegate )
  80. m_pDelegate->GetNodeForces( pNodes, iNode, pAccel );
  81. else
  82. pAccel->Init( 0, 0, 0 );
  83. }
  84. void CBaseRopePhysics::ApplyConstraints( CSimplePhysics::CNode *pNodes, int nNodes )
  85. {
  86. // Handle springs..
  87. //
  88. // Iterate multiple times here. If we don't, then gravity tends to
  89. // win over the constraint solver and it's impossible to get straight ropes.
  90. static int nIterations = 3;
  91. for( int iIteration=0; iIteration < nIterations; iIteration++ )
  92. {
  93. for( int i=0; i < NumSprings(); i++ )
  94. {
  95. CRopeSpring *s = &m_pSprings[i];
  96. Vector vTo = *s->m_pNode1 - *s->m_pNode2;
  97. float flDistSqr = vTo.LengthSqr();
  98. // If we don't have an overall spring distance, see if we have a per-node one
  99. float flSpringDist = m_flSpringDistSqr;
  100. if ( !flSpringDist )
  101. {
  102. // TODO: This still isn't enough. Ropes with different spring lengths
  103. // per-node will oscillate forever.
  104. flSpringDist = m_flNodeSpringDistsSqr[i];
  105. }
  106. if( flDistSqr > flSpringDist )
  107. {
  108. float flDist = (float)sqrt( flDistSqr );
  109. vTo *= 1 - (m_flSpringDist / flDist);
  110. *s->m_pNode1 -= vTo * 0.5f;
  111. *s->m_pNode2 += vTo * 0.5f;
  112. }
  113. }
  114. if( m_pDelegate )
  115. m_pDelegate->ApplyConstraints( pNodes, nNodes );
  116. }
  117. }