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.

286 lines
8.2 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "cbase.h"
  9. #include "ivp_actuator.hxx"
  10. #include "ivp_actuator_spring.hxx"
  11. #include "ivp_listener_object.hxx"
  12. // memdbgon must be the last include file in a .cpp file!!!
  13. #include "tier0/memdbgon.h"
  14. struct vphysics_save_cphysicsspring_t : public springparams_t
  15. {
  16. CPhysicsObject *pObjStart;
  17. CPhysicsObject *pObjEnd;
  18. DECLARE_SIMPLE_DATADESC();
  19. };
  20. BEGIN_SIMPLE_DATADESC( vphysics_save_cphysicsspring_t )
  21. DEFINE_FIELD( constant, FIELD_FLOAT ),
  22. DEFINE_FIELD( naturalLength, FIELD_FLOAT ),
  23. DEFINE_FIELD( damping, FIELD_FLOAT ),
  24. DEFINE_FIELD( relativeDamping, FIELD_FLOAT ),
  25. // NOTE: These are stored as *relative* vectors, so we don't use FIELD_POSITION_VECTOR
  26. DEFINE_FIELD( startPosition, FIELD_VECTOR ),
  27. DEFINE_FIELD( endPosition, FIELD_VECTOR ),
  28. DEFINE_FIELD( useLocalPositions, FIELD_BOOLEAN ),
  29. DEFINE_FIELD( onlyStretch, FIELD_BOOLEAN ),
  30. DEFINE_VPHYSPTR( pObjStart ),
  31. DEFINE_VPHYSPTR( pObjEnd ),
  32. END_DATADESC()
  33. // BUGBUG: No way to delete a spring because springs get auto-deleted without notification
  34. // when an object they are attached to is deleted.
  35. // So there is no way to tell if the pointer is valid.
  36. class CPhysicsSpring : public IPhysicsSpring, public IVP_Listener_Object
  37. {
  38. public:
  39. CPhysicsSpring( CPhysicsObject *pObjectStart, CPhysicsObject *pObjectEnd, IVP_Actuator_Spring *pSpring );
  40. ~CPhysicsSpring();
  41. // IPhysicsSpring
  42. void GetEndpoints( Vector* worldPositionStart, Vector* worldPositionEnd );
  43. void SetSpringConstant( float flSpringContant);
  44. void SetSpringDamping( float flSpringDamping);
  45. void SetSpringLength( float flSpringLength);
  46. IPhysicsObject *GetStartObject( void ) { return m_pObjStart; }
  47. IPhysicsObject *GetEndObject( void ) { return m_pObjEnd; }
  48. void AttachListener();
  49. void DetachListener();
  50. // Object listener
  51. virtual void event_object_deleted( IVP_Event_Object *);
  52. virtual void event_object_created( IVP_Event_Object *) {}
  53. virtual void event_object_revived( IVP_Event_Object *) {}
  54. virtual void event_object_frozen ( IVP_Event_Object *) {}
  55. void WriteToTemplate( vphysics_save_cphysicsspring_t &params );
  56. private:
  57. CPhysicsSpring( void );
  58. IVP_Actuator_Spring *m_pSpring;
  59. CPhysicsObject *m_pObjStart;
  60. CPhysicsObject *m_pObjEnd;
  61. };
  62. CPhysicsSpring::CPhysicsSpring( CPhysicsObject *pObjectStart, CPhysicsObject *pObjectEnd, IVP_Actuator_Spring *pSpring ) : m_pSpring(pSpring)
  63. {
  64. m_pObjStart = pObjectStart;
  65. m_pObjEnd = pObjectEnd;
  66. AttachListener();
  67. }
  68. void CPhysicsSpring::AttachListener()
  69. {
  70. if ( !(m_pObjStart->CallbackFlags() & CALLBACK_NEVER_DELETED) )
  71. {
  72. m_pObjStart->GetObject()->add_listener_object( this );
  73. }
  74. if ( !(m_pObjEnd->CallbackFlags() & CALLBACK_NEVER_DELETED) )
  75. {
  76. m_pObjEnd->GetObject()->add_listener_object( this );
  77. }
  78. }
  79. CPhysicsSpring::~CPhysicsSpring()
  80. {
  81. if ( m_pSpring )
  82. {
  83. delete m_pSpring;
  84. DetachListener();
  85. }
  86. }
  87. void CPhysicsSpring::DetachListener()
  88. {
  89. if ( !(m_pObjStart->CallbackFlags() & CALLBACK_NEVER_DELETED) )
  90. {
  91. m_pObjStart->GetObject()->remove_listener_object( this );
  92. }
  93. if ( !(m_pObjEnd->CallbackFlags() & CALLBACK_NEVER_DELETED) )
  94. {
  95. m_pObjEnd->GetObject()->remove_listener_object( this );
  96. }
  97. m_pObjStart = NULL;
  98. m_pObjEnd = NULL;
  99. m_pSpring = NULL;
  100. }
  101. void CPhysicsSpring::event_object_deleted( IVP_Event_Object * )
  102. {
  103. // the spring is going to delete itself now, so NULL it.
  104. DetachListener();
  105. }
  106. void CPhysicsSpring::GetEndpoints( Vector* worldPositionStart, Vector* worldPositionEnd )
  107. {
  108. Vector localHL;
  109. if ( !m_pSpring )
  110. return;
  111. if ( worldPositionStart )
  112. {
  113. const IVP_Anchor *anchor = m_pSpring->get_actuator_anchor(0);
  114. ConvertPositionToHL( anchor->object_pos, localHL );
  115. m_pObjStart->LocalToWorld( worldPositionStart, localHL );
  116. }
  117. if ( worldPositionEnd )
  118. {
  119. const IVP_Anchor *anchor = m_pSpring->get_actuator_anchor(1);
  120. ConvertPositionToHL( anchor->object_pos, localHL );
  121. m_pObjEnd->LocalToWorld( worldPositionEnd, localHL );
  122. }
  123. }
  124. void CPhysicsSpring::SetSpringConstant( float flSpringConstant )
  125. {
  126. if ( m_pSpring )
  127. {
  128. float currentConstant = m_pSpring->get_constant();
  129. if ( currentConstant != flSpringConstant )
  130. {
  131. m_pSpring->set_constant(flSpringConstant);
  132. }
  133. }
  134. }
  135. void CPhysicsSpring::SetSpringDamping( float flSpringDamping )
  136. {
  137. if ( m_pSpring )
  138. {
  139. m_pSpring->set_damp(flSpringDamping);
  140. }
  141. }
  142. void CPhysicsSpring::SetSpringLength( float flSpringLength )
  143. {
  144. if ( m_pSpring )
  145. {
  146. float currentLengthIVP = m_pSpring->get_spring_length_zero_force();
  147. float desiredLengthIVP = ConvertDistanceToIVP(flSpringLength);
  148. // must change enough, or skip to keep objects sleeping
  149. const float SPRING_LENGTH_EPSILON = 1e-3f;
  150. if ( fabs(desiredLengthIVP-currentLengthIVP) < ConvertDistanceToIVP(SPRING_LENGTH_EPSILON) )
  151. return;
  152. m_pSpring->set_len( desiredLengthIVP );
  153. }
  154. }
  155. void CPhysicsSpring::WriteToTemplate( vphysics_save_cphysicsspring_t &params )
  156. {
  157. if ( !m_pSpring )
  158. {
  159. memset(&params, 0, sizeof(params));
  160. return;
  161. }
  162. params.constant = m_pSpring->get_constant();
  163. params.naturalLength = ConvertDistanceToHL( m_pSpring->get_spring_length_zero_force() );
  164. params.damping = m_pSpring->get_damp_factor();
  165. params.relativeDamping = m_pSpring->get_rel_pos_damp();
  166. const IVP_Anchor *anchor0 = m_pSpring->get_actuator_anchor(0);
  167. ConvertPositionToHL( anchor0->object_pos, params.startPosition );
  168. const IVP_Anchor *anchor1 = m_pSpring->get_actuator_anchor(1);
  169. ConvertPositionToHL( anchor1->object_pos, params.endPosition );
  170. params.useLocalPositions = true;
  171. params.onlyStretch = m_pSpring->get_only_stretch() ? true : false;
  172. params.pObjStart = m_pObjStart;
  173. params.pObjEnd = m_pObjEnd;
  174. }
  175. IPhysicsSpring *CreateSpring( IVP_Environment *pEnvironment, CPhysicsObject *pObjectStart, CPhysicsObject *pObjectEnd, springparams_t *pParams )
  176. {
  177. // fill in template
  178. IVP_Template_Spring spring_template;
  179. spring_template.spring_values_are_relative=IVP_FALSE;
  180. spring_template.spring_constant = pParams->constant;
  181. spring_template.spring_len = ConvertDistanceToIVP( pParams->naturalLength );
  182. spring_template.spring_damp = pParams->damping;
  183. spring_template.rel_pos_damp = pParams->relativeDamping;
  184. spring_template.spring_force_only_on_stretch = pParams->onlyStretch ? IVP_TRUE : IVP_FALSE;
  185. // Create anchors for the objects
  186. IVP_Template_Anchor anchorTemplateObjectStart, anchorTemplateObjectEnd;
  187. // create spring
  188. IVP_U_Float_Point ivpPosStart;
  189. IVP_U_Float_Point ivpPosEnd;
  190. if ( !pParams->useLocalPositions )
  191. {
  192. Vector local;
  193. pObjectStart->WorldToLocal( &local, pParams->startPosition );
  194. ConvertPositionToIVP( local, ivpPosStart );
  195. pObjectEnd->WorldToLocal( &local, pParams->endPosition );
  196. ConvertPositionToIVP( local, ivpPosEnd );
  197. }
  198. else
  199. {
  200. ConvertPositionToIVP( pParams->startPosition, ivpPosStart );
  201. ConvertPositionToIVP( pParams->endPosition, ivpPosEnd );
  202. }
  203. anchorTemplateObjectStart.set_anchor_position_os( pObjectStart->GetObject(), &ivpPosStart );
  204. anchorTemplateObjectEnd.set_anchor_position_os( pObjectEnd->GetObject(), &ivpPosEnd );
  205. spring_template.anchors[0] = &anchorTemplateObjectStart;
  206. spring_template.anchors[1] = &anchorTemplateObjectEnd;
  207. IVP_Actuator_Spring *pSpring = pEnvironment->create_spring( &spring_template );
  208. return new CPhysicsSpring( pObjectStart, pObjectEnd, pSpring );
  209. }
  210. bool SavePhysicsSpring( const physsaveparams_t &params, CPhysicsSpring *pSpring )
  211. {
  212. vphysics_save_cphysicsspring_t springTemplate;
  213. memset( &springTemplate, 0, sizeof(springTemplate) );
  214. pSpring->WriteToTemplate( springTemplate );
  215. params.pSave->WriteAll( &springTemplate );
  216. return true;
  217. }
  218. bool RestorePhysicsSpring( const physrestoreparams_t &params, CPhysicsSpring **ppSpring )
  219. {
  220. vphysics_save_cphysicsspring_t springTemplate;
  221. memset( &springTemplate, 0, sizeof(springTemplate) );
  222. params.pRestore->ReadAll( &springTemplate );
  223. CPhysicsEnvironment *pEnvironment = (CPhysicsEnvironment *)params.pEnvironment;
  224. if ( springTemplate.pObjStart && springTemplate.pObjEnd )
  225. {
  226. *ppSpring = (CPhysicsSpring *)pEnvironment->CreateSpring( springTemplate.pObjStart, springTemplate.pObjEnd, &springTemplate );
  227. }
  228. else
  229. {
  230. DevMsg( "Failed to restore spring enpoints\n");
  231. *ppSpring = NULL;
  232. }
  233. return true;
  234. }