mirror of
https://github.com/celisej567/source-engine.git
synced 2026-01-03 05:49:41 +03:00
1
This commit is contained in:
286
vphysics/physics_spring.cpp
Normal file
286
vphysics/physics_spring.cpp
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user