diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /vphysics/physics_spring.cpp | |
| download | archived-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.cpp | 286 |
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 ¶ms ); + +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 ¶ms ) +{ + if ( !m_pSpring ) + { + memset(¶ms, 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 ¶ms, 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 ¶ms, 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; +} + |