summaryrefslogtreecommitdiff
path: root/vphysics/physics_spring.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /vphysics/physics_spring.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'vphysics/physics_spring.cpp')
-rw-r--r--vphysics/physics_spring.cpp286
1 files changed, 286 insertions, 0 deletions
diff --git a/vphysics/physics_spring.cpp b/vphysics/physics_spring.cpp
new file mode 100644
index 0000000..17f77a2
--- /dev/null
+++ b/vphysics/physics_spring.cpp
@@ -0,0 +1,286 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#include "cbase.h"
+
+#include "ivp_actuator.hxx"
+#include "ivp_actuator_spring.hxx"
+#include "ivp_listener_object.hxx"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+struct vphysics_save_cphysicsspring_t : public springparams_t
+{
+ CPhysicsObject *pObjStart;
+ CPhysicsObject *pObjEnd;
+ DECLARE_SIMPLE_DATADESC();
+};
+
+BEGIN_SIMPLE_DATADESC( vphysics_save_cphysicsspring_t )
+ DEFINE_FIELD( constant, FIELD_FLOAT ),
+ DEFINE_FIELD( naturalLength, FIELD_FLOAT ),
+ DEFINE_FIELD( damping, FIELD_FLOAT ),
+ DEFINE_FIELD( relativeDamping, FIELD_FLOAT ),
+
+ // NOTE: These are stored as *relative* vectors, so we don't use FIELD_POSITION_VECTOR
+ DEFINE_FIELD( startPosition, FIELD_VECTOR ),
+ DEFINE_FIELD( endPosition, FIELD_VECTOR ),
+ DEFINE_FIELD( useLocalPositions, FIELD_BOOLEAN ),
+ DEFINE_FIELD( onlyStretch, FIELD_BOOLEAN ),
+
+ DEFINE_VPHYSPTR( pObjStart ),
+ DEFINE_VPHYSPTR( pObjEnd ),
+END_DATADESC()
+
+
+// BUGBUG: No way to delete a spring because springs get auto-deleted without notification
+// when an object they are attached to is deleted.
+// So there is no way to tell if the pointer is valid.
+class CPhysicsSpring : public IPhysicsSpring, public IVP_Listener_Object
+{
+public:
+ CPhysicsSpring( CPhysicsObject *pObjectStart, CPhysicsObject *pObjectEnd, IVP_Actuator_Spring *pSpring );
+ ~CPhysicsSpring();
+
+ // IPhysicsSpring
+ void GetEndpoints( Vector* worldPositionStart, Vector* worldPositionEnd );
+ void SetSpringConstant( float flSpringContant);
+ void SetSpringDamping( float flSpringDamping);
+ void SetSpringLength( float flSpringLength);
+ IPhysicsObject *GetStartObject( void ) { return m_pObjStart; }
+ IPhysicsObject *GetEndObject( void ) { return m_pObjEnd; }
+
+ void AttachListener();
+ void DetachListener();
+
+ // Object listener
+ virtual void event_object_deleted( IVP_Event_Object *);
+ virtual void event_object_created( IVP_Event_Object *) {}
+ virtual void event_object_revived( IVP_Event_Object *) {}
+ virtual void event_object_frozen ( IVP_Event_Object *) {}
+ void WriteToTemplate( vphysics_save_cphysicsspring_t &params );
+
+private:
+
+ CPhysicsSpring( void );
+ IVP_Actuator_Spring *m_pSpring;
+ CPhysicsObject *m_pObjStart;
+ CPhysicsObject *m_pObjEnd;
+};
+
+CPhysicsSpring::CPhysicsSpring( CPhysicsObject *pObjectStart, CPhysicsObject *pObjectEnd, IVP_Actuator_Spring *pSpring ) : m_pSpring(pSpring)
+{
+ m_pObjStart = pObjectStart;
+ m_pObjEnd = pObjectEnd;
+ AttachListener();
+}
+
+void CPhysicsSpring::AttachListener()
+{
+ if ( !(m_pObjStart->CallbackFlags() & CALLBACK_NEVER_DELETED) )
+ {
+ m_pObjStart->GetObject()->add_listener_object( this );
+ }
+
+ if ( !(m_pObjEnd->CallbackFlags() & CALLBACK_NEVER_DELETED) )
+ {
+ m_pObjEnd->GetObject()->add_listener_object( this );
+ }
+}
+
+CPhysicsSpring::~CPhysicsSpring()
+{
+ if ( m_pSpring )
+ {
+ delete m_pSpring;
+ DetachListener();
+ }
+}
+
+void CPhysicsSpring::DetachListener()
+{
+ if ( !(m_pObjStart->CallbackFlags() & CALLBACK_NEVER_DELETED) )
+ {
+ m_pObjStart->GetObject()->remove_listener_object( this );
+ }
+
+ if ( !(m_pObjEnd->CallbackFlags() & CALLBACK_NEVER_DELETED) )
+ {
+ m_pObjEnd->GetObject()->remove_listener_object( this );
+ }
+
+ m_pObjStart = NULL;
+ m_pObjEnd = NULL;
+ m_pSpring = NULL;
+}
+
+void CPhysicsSpring::event_object_deleted( IVP_Event_Object * )
+{
+ // the spring is going to delete itself now, so NULL it.
+ DetachListener();
+}
+
+void CPhysicsSpring::GetEndpoints( Vector* worldPositionStart, Vector* worldPositionEnd )
+{
+ Vector localHL;
+
+ if ( !m_pSpring )
+ return;
+
+ if ( worldPositionStart )
+ {
+ const IVP_Anchor *anchor = m_pSpring->get_actuator_anchor(0);
+ ConvertPositionToHL( anchor->object_pos, localHL );
+ m_pObjStart->LocalToWorld( worldPositionStart, localHL );
+ }
+
+ if ( worldPositionEnd )
+ {
+ const IVP_Anchor *anchor = m_pSpring->get_actuator_anchor(1);
+ ConvertPositionToHL( anchor->object_pos, localHL );
+ m_pObjEnd->LocalToWorld( worldPositionEnd, localHL );
+ }
+}
+
+void CPhysicsSpring::SetSpringConstant( float flSpringConstant )
+{
+ if ( m_pSpring )
+ {
+ float currentConstant = m_pSpring->get_constant();
+ if ( currentConstant != flSpringConstant )
+ {
+ m_pSpring->set_constant(flSpringConstant);
+ }
+ }
+}
+
+void CPhysicsSpring::SetSpringDamping( float flSpringDamping )
+{
+ if ( m_pSpring )
+ {
+ m_pSpring->set_damp(flSpringDamping);
+ }
+}
+
+
+
+void CPhysicsSpring::SetSpringLength( float flSpringLength )
+{
+ if ( m_pSpring )
+ {
+ float currentLengthIVP = m_pSpring->get_spring_length_zero_force();
+ float desiredLengthIVP = ConvertDistanceToIVP(flSpringLength);
+
+ // must change enough, or skip to keep objects sleeping
+ const float SPRING_LENGTH_EPSILON = 1e-3f;
+ if ( fabs(desiredLengthIVP-currentLengthIVP) < ConvertDistanceToIVP(SPRING_LENGTH_EPSILON) )
+ return;
+
+ m_pSpring->set_len( desiredLengthIVP );
+ }
+}
+
+void CPhysicsSpring::WriteToTemplate( vphysics_save_cphysicsspring_t &params )
+{
+ if ( !m_pSpring )
+ {
+ memset(&params, 0, sizeof(params));
+ return;
+ }
+ params.constant = m_pSpring->get_constant();
+ params.naturalLength = ConvertDistanceToHL( m_pSpring->get_spring_length_zero_force() );
+ params.damping = m_pSpring->get_damp_factor();
+ params.relativeDamping = m_pSpring->get_rel_pos_damp();
+
+ const IVP_Anchor *anchor0 = m_pSpring->get_actuator_anchor(0);
+ ConvertPositionToHL( anchor0->object_pos, params.startPosition );
+ const IVP_Anchor *anchor1 = m_pSpring->get_actuator_anchor(1);
+ ConvertPositionToHL( anchor1->object_pos, params.endPosition );
+ params.useLocalPositions = true;
+
+ params.onlyStretch = m_pSpring->get_only_stretch() ? true : false;
+ params.pObjStart = m_pObjStart;
+ params.pObjEnd = m_pObjEnd;
+}
+
+
+IPhysicsSpring *CreateSpring( IVP_Environment *pEnvironment, CPhysicsObject *pObjectStart, CPhysicsObject *pObjectEnd, springparams_t *pParams )
+{
+ // fill in template
+ IVP_Template_Spring spring_template;
+
+ spring_template.spring_values_are_relative=IVP_FALSE;
+ spring_template.spring_constant = pParams->constant;
+ spring_template.spring_len = ConvertDistanceToIVP( pParams->naturalLength );
+ spring_template.spring_damp = pParams->damping;
+ spring_template.rel_pos_damp = pParams->relativeDamping;
+
+ spring_template.spring_force_only_on_stretch = pParams->onlyStretch ? IVP_TRUE : IVP_FALSE;
+
+ // Create anchors for the objects
+ IVP_Template_Anchor anchorTemplateObjectStart, anchorTemplateObjectEnd;
+ // create spring
+
+ IVP_U_Float_Point ivpPosStart;
+ IVP_U_Float_Point ivpPosEnd;
+
+ if ( !pParams->useLocalPositions )
+ {
+ Vector local;
+ pObjectStart->WorldToLocal( &local, pParams->startPosition );
+ ConvertPositionToIVP( local, ivpPosStart );
+
+ pObjectEnd->WorldToLocal( &local, pParams->endPosition );
+ ConvertPositionToIVP( local, ivpPosEnd );
+ }
+ else
+ {
+ ConvertPositionToIVP( pParams->startPosition, ivpPosStart );
+ ConvertPositionToIVP( pParams->endPosition, ivpPosEnd );
+ }
+
+ anchorTemplateObjectStart.set_anchor_position_os( pObjectStart->GetObject(), &ivpPosStart );
+ anchorTemplateObjectEnd.set_anchor_position_os( pObjectEnd->GetObject(), &ivpPosEnd );
+
+ spring_template.anchors[0] = &anchorTemplateObjectStart;
+ spring_template.anchors[1] = &anchorTemplateObjectEnd;
+ IVP_Actuator_Spring *pSpring = pEnvironment->create_spring( &spring_template );
+
+ return new CPhysicsSpring( pObjectStart, pObjectEnd, pSpring );
+}
+
+
+bool SavePhysicsSpring( const physsaveparams_t &params, CPhysicsSpring *pSpring )
+{
+ vphysics_save_cphysicsspring_t springTemplate;
+ memset( &springTemplate, 0, sizeof(springTemplate) );
+
+ pSpring->WriteToTemplate( springTemplate );
+ params.pSave->WriteAll( &springTemplate );
+ return true;
+}
+
+bool RestorePhysicsSpring( const physrestoreparams_t &params, CPhysicsSpring **ppSpring )
+{
+ vphysics_save_cphysicsspring_t springTemplate;
+ memset( &springTemplate, 0, sizeof(springTemplate) );
+ params.pRestore->ReadAll( &springTemplate );
+ CPhysicsEnvironment *pEnvironment = (CPhysicsEnvironment *)params.pEnvironment;
+ if ( springTemplate.pObjStart && springTemplate.pObjEnd )
+ {
+ *ppSpring = (CPhysicsSpring *)pEnvironment->CreateSpring( springTemplate.pObjStart, springTemplate.pObjEnd, &springTemplate );
+ }
+ else
+ {
+ DevMsg( "Failed to restore spring enpoints\n");
+ *ppSpring = NULL;
+ }
+
+ return true;
+}
+