aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/client/ragdoll.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/client/ragdoll.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/client/ragdoll.cpp')
-rw-r--r--mp/src/game/client/ragdoll.cpp1734
1 files changed, 867 insertions, 867 deletions
diff --git a/mp/src/game/client/ragdoll.cpp b/mp/src/game/client/ragdoll.cpp
index 1bf83ce3..3457b054 100644
--- a/mp/src/game/client/ragdoll.cpp
+++ b/mp/src/game/client/ragdoll.cpp
@@ -1,867 +1,867 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//===========================================================================//
-
-#include "cbase.h"
-#include "mathlib/vmatrix.h"
-#include "ragdoll_shared.h"
-#include "bone_setup.h"
-#include "materialsystem/imesh.h"
-#include "engine/ivmodelinfo.h"
-#include "iviewrender.h"
-#include "tier0/vprof.h"
-#include "view.h"
-#include "physics_saverestore.h"
-#include "vphysics/constraints.h"
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-#ifdef _DEBUG
-extern ConVar r_FadeProps;
-#endif
-
-CRagdoll::CRagdoll()
-{
- m_ragdoll.listCount = 0;
- m_vecLastOrigin.Init();
- m_flLastOriginChangeTime = - 1.0f;
-
- m_lastUpdate = -FLT_MAX;
-}
-
-#define DEFINE_RAGDOLL_ELEMENT( i ) \
- DEFINE_FIELD( m_ragdoll.list[i].originParentSpace, FIELD_VECTOR ), \
- DEFINE_PHYSPTR( m_ragdoll.list[i].pObject ), \
- DEFINE_PHYSPTR( m_ragdoll.list[i].pConstraint ), \
- DEFINE_FIELD( m_ragdoll.list[i].parentIndex, FIELD_INTEGER )
-
-BEGIN_SIMPLE_DATADESC( CRagdoll )
-
- DEFINE_AUTO_ARRAY( m_ragdoll.boneIndex, FIELD_INTEGER ),
- DEFINE_FIELD( m_ragdoll.listCount, FIELD_INTEGER ),
- DEFINE_FIELD( m_ragdoll.allowStretch, FIELD_BOOLEAN ),
- DEFINE_PHYSPTR( m_ragdoll.pGroup ),
-
- DEFINE_RAGDOLL_ELEMENT( 0 ),
- DEFINE_RAGDOLL_ELEMENT( 1 ),
- DEFINE_RAGDOLL_ELEMENT( 2 ),
- DEFINE_RAGDOLL_ELEMENT( 3 ),
- DEFINE_RAGDOLL_ELEMENT( 4 ),
- DEFINE_RAGDOLL_ELEMENT( 5 ),
- DEFINE_RAGDOLL_ELEMENT( 6 ),
- DEFINE_RAGDOLL_ELEMENT( 7 ),
- DEFINE_RAGDOLL_ELEMENT( 8 ),
- DEFINE_RAGDOLL_ELEMENT( 9 ),
- DEFINE_RAGDOLL_ELEMENT( 10 ),
- DEFINE_RAGDOLL_ELEMENT( 11 ),
- DEFINE_RAGDOLL_ELEMENT( 12 ),
- DEFINE_RAGDOLL_ELEMENT( 13 ),
- DEFINE_RAGDOLL_ELEMENT( 14 ),
- DEFINE_RAGDOLL_ELEMENT( 15 ),
- DEFINE_RAGDOLL_ELEMENT( 16 ),
- DEFINE_RAGDOLL_ELEMENT( 17 ),
- DEFINE_RAGDOLL_ELEMENT( 18 ),
- DEFINE_RAGDOLL_ELEMENT( 19 ),
- DEFINE_RAGDOLL_ELEMENT( 20 ),
- DEFINE_RAGDOLL_ELEMENT( 21 ),
- DEFINE_RAGDOLL_ELEMENT( 22 ),
- DEFINE_RAGDOLL_ELEMENT( 23 ),
-
-END_DATADESC()
-
-IPhysicsObject *CRagdoll::GetElement( int elementNum )
-{
- return m_ragdoll.list[elementNum].pObject;
-}
-
-void CRagdoll::BuildRagdollBounds( C_BaseEntity *ent )
-{
- Vector mins, maxs, size;
- modelinfo->GetModelBounds( ent->GetModel(), mins, maxs );
- size = (maxs - mins) * 0.5;
- m_radius = size.Length();
-
- m_mins.Init(-m_radius,-m_radius,-m_radius);
- m_maxs.Init(m_radius,m_radius,m_radius);
-}
-
-void CRagdoll::Init(
- C_BaseEntity *ent,
- CStudioHdr *pstudiohdr,
- const Vector &forceVector,
- int forceBone,
- const matrix3x4_t *pDeltaBones0,
- const matrix3x4_t *pDeltaBones1,
- const matrix3x4_t *pCurrentBonePosition,
- float dt,
- bool bFixedConstraints )
-{
- ragdollparams_t params;
- params.pGameData = static_cast<void *>( ent );
- params.modelIndex = ent->GetModelIndex();
- params.pCollide = modelinfo->GetVCollide( params.modelIndex );
- params.pStudioHdr = pstudiohdr;
- params.forceVector = forceVector;
- params.forceBoneIndex = forceBone;
- params.forcePosition.Init();
- params.pCurrentBones = pCurrentBonePosition;
- params.jointFrictionScale = 1.0;
- params.allowStretch = false;
- params.fixedConstraints = bFixedConstraints;
- RagdollCreate( m_ragdoll, params, physenv );
- ent->VPhysicsSetObject( NULL );
- ent->VPhysicsSetObject( m_ragdoll.list[0].pObject );
- // Mark the ragdoll as debris.
- ent->SetCollisionGroup( COLLISION_GROUP_DEBRIS );
-
- RagdollApplyAnimationAsVelocity( m_ragdoll, pDeltaBones0, pDeltaBones1, dt );
- RagdollActivate( m_ragdoll, params.pCollide, ent->GetModelIndex() );
-
- // It's moving now...
- m_flLastOriginChangeTime = gpGlobals->curtime;
-
- // So traces hit it.
- ent->AddEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID );
-
- if ( !m_ragdoll.listCount )
- return;
-
- BuildRagdollBounds( ent );
-
- for ( int i = 0; i < m_ragdoll.listCount; i++ )
- {
- g_pPhysSaveRestoreManager->AssociateModel( m_ragdoll.list[i].pObject, ent->GetModelIndex() );
- }
-
-#if RAGDOLL_VISUALIZE
- memcpy( m_savedBone1, &pDeltaBones0[0], sizeof(matrix3x4_t) * pstudiohdr->numbones() );
- memcpy( m_savedBone2, &pDeltaBones1[0], sizeof(matrix3x4_t) * pstudiohdr->numbones() );
- memcpy( m_savedBone3, &pCurrentBonePosition[0], sizeof(matrix3x4_t) * pstudiohdr->numbones() );
-#endif
-}
-
-CRagdoll::~CRagdoll( void )
-{
- for ( int i = 0; i < m_ragdoll.listCount; i++ )
- {
- IPhysicsObject *pObject = m_ragdoll.list[i].pObject;
- if ( pObject )
- {
- g_pPhysSaveRestoreManager->ForgetModel( m_ragdoll.list[i].pObject );
- // Disable collision on all ragdoll parts before calling RagdollDestroy
- // (which might cause touch callbacks on the ragdoll otherwise, which is
- // very bad for a half deleted ragdoll).
- pObject->EnableCollisions( false );
- }
- }
-
- RagdollDestroy( m_ragdoll );
-}
-
-
-void CRagdoll::RagdollBone( C_BaseEntity *ent, mstudiobone_t *pbones, int boneCount, bool *boneSimulated, CBoneAccessor &pBoneToWorld )
-{
- for ( int i = 0; i < m_ragdoll.listCount; i++ )
- {
- if ( RagdollGetBoneMatrix( m_ragdoll, pBoneToWorld, i ) )
- {
- boneSimulated[m_ragdoll.boneIndex[i]] = true;
- }
- }
-}
-
-const Vector& CRagdoll::GetRagdollOrigin( )
-{
- m_ragdoll.list[0].pObject->GetPosition( &m_origin, 0 );
- return m_origin;
-}
-
-void CRagdoll::GetRagdollBounds( Vector &theMins, Vector &theMaxs )
-{
- theMins = m_mins;
- theMaxs = m_maxs;
-}
-
-void CRagdoll::VPhysicsUpdate( IPhysicsObject *pPhysics )
-{
- if ( m_lastUpdate == gpGlobals->curtime )
- return;
- m_lastUpdate = gpGlobals->curtime;
- m_allAsleep = RagdollIsAsleep( m_ragdoll );
- if ( m_allAsleep )
- {
- // NOTE: This is the bbox of the ragdoll's physics
- // It's not always correct to use for culling, but it sure beats
- // using the radius box!
- Vector origin = GetRagdollOrigin();
- RagdollComputeExactBbox( m_ragdoll, origin, m_mins, m_maxs );
- m_mins -= origin;
- m_maxs -= origin;
- }
- else
- {
- m_mins.Init(-m_radius,-m_radius,-m_radius);
- m_maxs.Init(m_radius,m_radius,m_radius);
-
- if ( m_ragdoll.pGroup->IsInErrorState() )
- {
- C_BaseEntity *pEntity = static_cast<C_BaseEntity *>(m_ragdoll.list[0].pObject->GetGameData());
- RagdollSolveSeparation( m_ragdoll, pEntity );
- }
- }
-
- // See if we should go to sleep...
- CheckSettleStationaryRagdoll();
-}
-
-//=============================================================================
-// HPE_BEGIN:
-// [menglish] Transforms a vector from the given bone's space to world space
-//=============================================================================
-
-bool CRagdoll::TransformVectorToWorld(int iBoneIndex, const Vector *vPosition, Vector *vOut)
-{
- int listIndex = -1;
- if( iBoneIndex >= 0 && iBoneIndex < m_ragdoll.listCount)
- {
- for ( int i = 0; i < m_ragdoll.listCount; ++i )
- {
- if(m_ragdoll.boneIndex[i] == iBoneIndex)
- listIndex = i;
- }
- if(listIndex != -1)
- {
- m_ragdoll.list[listIndex].pObject->LocalToWorld(vOut, *vPosition);
- return true;
- }
- }
- return false;
-}
-
-//=============================================================================
-// HPE_END
-//=============================================================================
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : -
-//-----------------------------------------------------------------------------
-void CRagdoll::PhysForceRagdollToSleep()
-{
- for ( int i = 0; i < m_ragdoll.listCount; i++ )
- {
- if ( m_ragdoll.list[i].pObject )
- {
- PhysForceClearVelocity( m_ragdoll.list[i].pObject );
- m_ragdoll.list[i].pObject->Sleep();
- }
- }
-}
-
-#define RAGDOLL_SLEEP_TOLERANCE 1.0f
-static ConVar ragdoll_sleepaftertime( "ragdoll_sleepaftertime", "5.0f", 0, "After this many seconds of being basically stationary, the ragdoll will go to sleep." );
-
-void CRagdoll::CheckSettleStationaryRagdoll()
-{
- Vector delta = GetRagdollOrigin() - m_vecLastOrigin;
- m_vecLastOrigin = GetRagdollOrigin();
- for ( int i = 0; i < 3; ++i )
- {
- // It's still moving...
- if ( fabs( delta[ i ] ) > RAGDOLL_SLEEP_TOLERANCE )
- {
- m_flLastOriginChangeTime = gpGlobals->curtime;
- // Msg( "%d [%p] Still moving\n", gpGlobals->tickcount, this );
- return;
- }
- }
-
- // It's totally asleep, don't worry about forcing it to settle
- if ( m_allAsleep )
- return;
-
- // Msg( "%d [%p] Settling\n", gpGlobals->tickcount, this );
-
- // It has stopped moving, see if it
- float dt = gpGlobals->curtime - m_flLastOriginChangeTime;
- if ( dt < ragdoll_sleepaftertime.GetFloat() )
- return;
-
- // Msg( "%d [%p] FORCE SLEEP\n",gpGlobals->tickcount, this );
-
- // Force it to go to sleep
- PhysForceRagdollToSleep();
-}
-
-void CRagdoll::ResetRagdollSleepAfterTime( void )
-{
- m_flLastOriginChangeTime = gpGlobals->curtime;
-}
-
-void CRagdoll::DrawWireframe()
-{
- IMaterial *pWireframe = materials->FindMaterial("shadertest/wireframevertexcolor", TEXTURE_GROUP_OTHER);
-
- int i;
- matrix3x4_t matrix;
- for ( i = 0; i < m_ragdoll.listCount; i++ )
- {
- static color32 debugColor = {0,255,255,0};
-
- // draw the actual physics positions, not the cleaned up animation position
- m_ragdoll.list[i].pObject->GetPositionMatrix( &matrix );
- const CPhysCollide *pCollide = m_ragdoll.list[i].pObject->GetCollide();
- engine->DebugDrawPhysCollide( pCollide, pWireframe, matrix, debugColor );
- }
-
-#if RAGDOLL_VISUALIZE
- for ( i = 0; i < m_ragdoll.listCount; i++ )
- {
- static color32 debugColor = {255,0,0,0};
-
- const CPhysCollide *pCollide = m_ragdoll.list[i].pObject->GetCollide();
- engine->DebugDrawPhysCollide( pCollide, pWireframe, m_savedBone1[m_ragdoll.boneIndex[i]], debugColor );
- }
- for ( i = 0; i < m_ragdoll.listCount; i++ )
- {
- static color32 debugColor = {0,255,0,0};
-
- const CPhysCollide *pCollide = m_ragdoll.list[i].pObject->GetCollide();
- engine->DebugDrawPhysCollide( pCollide, pWireframe, m_savedBone2[m_ragdoll.boneIndex[i]], debugColor );
- }
-
- for ( i = 0; i < m_ragdoll.listCount; i++ )
- {
- static color32 debugColor = {0,0,255,0};
-
- const CPhysCollide *pCollide = m_ragdoll.list[i].pObject->GetCollide();
- engine->DebugDrawPhysCollide( pCollide, pWireframe, m_savedBone3[m_ragdoll.boneIndex[i]], debugColor );
- }
-#endif
-}
-
-
-CRagdoll *CreateRagdoll(
- C_BaseEntity *ent,
- CStudioHdr *pstudiohdr,
- const Vector &forceVector,
- int forceBone,
- const matrix3x4_t *pDeltaBones0,
- const matrix3x4_t *pDeltaBones1,
- const matrix3x4_t *pCurrentBonePosition,
- float dt,
- bool bFixedConstraints )
-{
- CRagdoll *pRagdoll = new CRagdoll;
- pRagdoll->Init( ent, pstudiohdr, forceVector, forceBone, pDeltaBones0, pDeltaBones1, pCurrentBonePosition, dt, bFixedConstraints );
-
- if ( !pRagdoll->IsValid() )
- {
- Msg("Bad ragdoll for %s\n", pstudiohdr->pszName() );
- delete pRagdoll;
- pRagdoll = NULL;
- }
- return pRagdoll;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-class C_ServerRagdoll : public C_BaseAnimating
-{
-public:
- DECLARE_CLASS( C_ServerRagdoll, C_BaseAnimating );
- DECLARE_CLIENTCLASS();
- DECLARE_INTERPOLATION();
-
- C_ServerRagdoll( void );
-
- virtual void PostDataUpdate( DataUpdateType_t updateType );
-
- virtual int InternalDrawModel( int flags );
- virtual CStudioHdr *OnNewModel( void );
- virtual unsigned char GetClientSideFade();
- virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights );
-
- void GetRenderBounds( Vector& theMins, Vector& theMaxs );
- virtual void AddEntity( void );
- virtual void AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime );
- virtual void BuildTransformations( CStudioHdr *pStudioHdr, Vector *pos, Quaternion q[], const matrix3x4_t &cameraTransform, int boneMask, CBoneBitList &boneComputed );
- IPhysicsObject *GetElement( int elementNum );
- virtual void UpdateOnRemove();
- virtual float LastBoneChangedTime();
-
- // Incoming from network
- Vector m_ragPos[RAGDOLL_MAX_ELEMENTS];
- QAngle m_ragAngles[RAGDOLL_MAX_ELEMENTS];
-
- CInterpolatedVarArray< Vector, RAGDOLL_MAX_ELEMENTS > m_iv_ragPos;
- CInterpolatedVarArray< QAngle, RAGDOLL_MAX_ELEMENTS > m_iv_ragAngles;
-
- int m_elementCount;
- int m_boneIndex[RAGDOLL_MAX_ELEMENTS];
-
-private:
- C_ServerRagdoll( const C_ServerRagdoll &src );
-
- typedef CHandle<C_BaseAnimating> CBaseAnimatingHandle;
- CNetworkVar( CBaseAnimatingHandle, m_hUnragdoll );
- CNetworkVar( float, m_flBlendWeight );
- float m_flBlendWeightCurrent;
- CNetworkVar( int, m_nOverlaySequence );
- float m_flLastBoneChangeTime;
-};
-
-
-EXTERN_RECV_TABLE(DT_Ragdoll);
-IMPLEMENT_CLIENTCLASS_DT(C_ServerRagdoll, DT_Ragdoll, CRagdollProp)
- RecvPropArray(RecvPropQAngles(RECVINFO(m_ragAngles[0])), m_ragAngles),
- RecvPropArray(RecvPropVector(RECVINFO(m_ragPos[0])), m_ragPos),
- RecvPropEHandle(RECVINFO(m_hUnragdoll)),
- RecvPropFloat(RECVINFO(m_flBlendWeight)),
- RecvPropInt(RECVINFO(m_nOverlaySequence)),
-END_RECV_TABLE()
-
-
-C_ServerRagdoll::C_ServerRagdoll( void ) :
- m_iv_ragPos("C_ServerRagdoll::m_iv_ragPos"),
- m_iv_ragAngles("C_ServerRagdoll::m_iv_ragAngles")
-{
- m_elementCount = 0;
- m_flLastBoneChangeTime = -FLT_MAX;
-
- AddVar( m_ragPos, &m_iv_ragPos, LATCH_SIMULATION_VAR );
- AddVar( m_ragAngles, &m_iv_ragAngles, LATCH_SIMULATION_VAR );
-
- m_flBlendWeight = 0.0f;
- m_flBlendWeightCurrent = 0.0f;
- m_nOverlaySequence = -1;
- m_flFadeScale = 1;
-}
-
-void C_ServerRagdoll::PostDataUpdate( DataUpdateType_t updateType )
-{
- BaseClass::PostDataUpdate( updateType );
-
- m_iv_ragPos.NoteChanged( gpGlobals->curtime, true );
- m_iv_ragAngles.NoteChanged( gpGlobals->curtime, true );
- // this is the local client time at which this update becomes stale
- m_flLastBoneChangeTime = gpGlobals->curtime + GetInterpolationAmount(m_iv_ragPos.GetType());
-}
-
-float C_ServerRagdoll::LastBoneChangedTime()
-{
- return m_flLastBoneChangeTime;
-}
-
-int C_ServerRagdoll::InternalDrawModel( int flags )
-{
- int ret = BaseClass::InternalDrawModel( flags );
- if ( vcollide_wireframe.GetBool() )
- {
- vcollide_t *pCollide = modelinfo->GetVCollide( GetModelIndex() );
- IMaterial *pWireframe = materials->FindMaterial("shadertest/wireframevertexcolor", TEXTURE_GROUP_OTHER);
-
- matrix3x4_t matrix;
- for ( int i = 0; i < m_elementCount; i++ )
- {
- static color32 debugColor = {0,255,255,0};
-
- AngleMatrix( m_ragAngles[i], m_ragPos[i], matrix );
- engine->DebugDrawPhysCollide( pCollide->solids[i], pWireframe, matrix, debugColor );
- }
- }
- return ret;
-}
-
-
-CStudioHdr *C_ServerRagdoll::OnNewModel( void )
-{
- CStudioHdr *hdr = BaseClass::OnNewModel();
-
- if ( !m_elementCount )
- {
- vcollide_t *pCollide = modelinfo->GetVCollide( GetModelIndex() );
- if ( !pCollide )
- {
- const char *pszName = modelinfo->GetModelName( modelinfo->GetModel( GetModelIndex() ) );
- Msg( "*** ERROR: C_ServerRagdoll::InitModel: %s missing vcollide data ***\n", (pszName) ? pszName : "<null>" );
- m_elementCount = 0;
- }
- else
- {
- m_elementCount = RagdollExtractBoneIndices( m_boneIndex, hdr, pCollide );
- }
- m_iv_ragPos.SetMaxCount( m_elementCount );
- m_iv_ragAngles.SetMaxCount( m_elementCount );
- }
-
- return hdr;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: clear out any face/eye values stored in the material system
-//-----------------------------------------------------------------------------
-void C_ServerRagdoll::SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights )
-{
- BaseClass::SetupWeights( pBoneToWorld, nFlexWeightCount, pFlexWeights, pFlexDelayedWeights );
-
- CStudioHdr *hdr = GetModelPtr();
- if ( !hdr )
- return;
-
- int nFlexDescCount = hdr->numflexdesc();
- if ( nFlexDescCount )
- {
- Assert( !pFlexDelayedWeights );
- memset( pFlexWeights, 0, nFlexWeightCount * sizeof(float) );
- }
-
- if ( m_iEyeAttachment > 0 )
- {
- matrix3x4_t attToWorld;
- if (GetAttachment( m_iEyeAttachment, attToWorld ))
- {
- Vector local, tmp;
- local.Init( 1000.0f, 0.0f, 0.0f );
- VectorTransform( local, attToWorld, tmp );
- modelrender->SetViewTarget( GetModelPtr(), GetBody(), tmp );
- }
- }
-}
-
-
-void C_ServerRagdoll::GetRenderBounds( Vector& theMins, Vector& theMaxs )
-{
- if( !CollisionProp()->IsBoundsDefinedInEntitySpace() )
- {
- IRotateAABB( EntityToWorldTransform(), CollisionProp()->OBBMins(), CollisionProp()->OBBMaxs(), theMins, theMaxs );
- }
- else
- {
- theMins = CollisionProp()->OBBMins();
- theMaxs = CollisionProp()->OBBMaxs();
- }
-}
-
-void C_ServerRagdoll::AddEntity( void )
-{
- BaseClass::AddEntity();
-
- // Move blend weight toward target over 0.2 seconds
- m_flBlendWeightCurrent = Approach( m_flBlendWeight, m_flBlendWeightCurrent, gpGlobals->frametime * 5.0f );
-}
-
-void C_ServerRagdoll::AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime )
-{
- BaseClass::AccumulateLayers( boneSetup, pos, q, currentTime );
-
- if ( m_nOverlaySequence >= 0 && m_nOverlaySequence < boneSetup.GetStudioHdr()->GetNumSeq() )
- {
- boneSetup.AccumulatePose( pos, q, m_nOverlaySequence, GetCycle(), m_flBlendWeightCurrent, currentTime, m_pIk );
- }
-}
-
-void C_ServerRagdoll::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quaternion q[], const matrix3x4_t &cameraTransform, int boneMask, CBoneBitList &boneComputed )
-{
- if ( !hdr )
- return;
- matrix3x4_t bonematrix;
- bool boneSimulated[MAXSTUDIOBONES];
-
- // no bones have been simulated
- memset( boneSimulated, 0, sizeof(boneSimulated) );
- mstudiobone_t *pbones = hdr->pBone( 0 );
-
- mstudioseqdesc_t *pSeqDesc = NULL;
- if ( m_nOverlaySequence >= 0 && m_nOverlaySequence < hdr->GetNumSeq() )
- {
- pSeqDesc = &hdr->pSeqdesc( m_nOverlaySequence );
- }
-
- int i;
- for ( i = 0; i < m_elementCount; i++ )
- {
- int index = m_boneIndex[i];
- if ( index >= 0 )
- {
- if ( hdr->boneFlags(index) & boneMask )
- {
- boneSimulated[index] = true;
- matrix3x4_t &matrix = GetBoneForWrite( index );
-
- if ( m_flBlendWeightCurrent != 0.0f && pSeqDesc &&
- // FIXME: this bone access is illegal
- pSeqDesc->weight( index ) != 0.0f )
- {
- // Use the animated bone position instead
- boneSimulated[index] = false;
- }
- else
- {
- AngleMatrix( m_ragAngles[i], m_ragPos[i], matrix );
- }
- }
- }
- }
-
- for ( i = 0; i < hdr->numbones(); i++ )
- {
- if ( !( hdr->boneFlags( i ) & boneMask ) )
- continue;
-
- // BUGBUG: Merge this code with the code in c_baseanimating somehow!!!
- // animate all non-simulated bones
- if ( boneSimulated[i] ||
- CalcProceduralBone( hdr, i, m_BoneAccessor ) )
- {
- continue;
- }
- else
- {
- QuaternionMatrix( q[i], pos[i], bonematrix );
-
- if (pbones[i].parent == -1)
- {
- ConcatTransforms( cameraTransform, bonematrix, GetBoneForWrite( i ) );
- }
- else
- {
- ConcatTransforms( GetBone( pbones[i].parent ), bonematrix, GetBoneForWrite( i ) );
- }
- }
-
- if ( pbones[i].parent == -1 )
- {
- // Apply client-side effects to the transformation matrix
- // ApplyBoneMatrixTransform( GetBoneForWrite( i ) );
- }
- }
-}
-
-IPhysicsObject *C_ServerRagdoll::GetElement( int elementNum )
-{
- return NULL;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Output : virtual void
-//-----------------------------------------------------------------------------
-void C_ServerRagdoll::UpdateOnRemove()
-{
- C_BaseAnimating *anim = m_hUnragdoll.Get();
- if ( NULL != anim &&
- anim->GetModel() &&
- ( anim->GetModel() == GetModel() ) )
- {
- // Need to tell C_BaseAnimating to blend out of the ragdoll data that we received last
- C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, false );
- anim->CreateUnragdollInfo( this );
- }
-
- // Do last to mimic destrictor order
- BaseClass::UpdateOnRemove();
-}
-
-//-----------------------------------------------------------------------------
-// Fade out
-//-----------------------------------------------------------------------------
-unsigned char C_ServerRagdoll::GetClientSideFade()
-{
- return UTIL_ComputeEntityFade( this, m_fadeMinDist, m_fadeMaxDist, m_flFadeScale );
-}
-
-static int GetHighestBit( int flags )
-{
- for ( int i = 31; i >= 0; --i )
- {
- if ( flags & (1<<i) )
- return (1<<i);
- }
-
- return 0;
-}
-
-#define ATTACH_INTERP_TIME 0.2
-class C_ServerRagdollAttached : public C_ServerRagdoll
-{
- DECLARE_CLASS( C_ServerRagdollAttached, C_ServerRagdoll );
-public:
- C_ServerRagdollAttached( void )
- {
- m_bHasParent = false;
- m_vecOffset.Init();
- }
- DECLARE_CLIENTCLASS();
- bool SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime )
- {
- if ( GetMoveParent() )
- {
- // HACKHACK: Force the attached bone to be set up
- int index = m_boneIndex[m_ragdollAttachedObjectIndex];
- int boneFlags = GetModelPtr()->boneFlags(index);
- if ( !(boneFlags & boneMask) )
- {
- // BUGBUG: The attached bone is required and this call is going to skip it, so force it
- // HACKHACK: Assume the highest bit numbered bone flag is the minimum bone set
- boneMask |= GetHighestBit( boneFlags );
- }
- }
- return BaseClass::SetupBones( pBoneToWorldOut, nMaxBones, boneMask, currentTime );
- }
-
- virtual void BuildTransformations( CStudioHdr *hdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed )
- {
- VPROF_BUDGET( "C_ServerRagdollAttached::SetupBones", VPROF_BUDGETGROUP_CLIENT_ANIMATION );
-
- if ( !hdr )
- return;
-
- float frac = RemapVal( gpGlobals->curtime, m_parentTime, m_parentTime+ATTACH_INTERP_TIME, 0, 1 );
- frac = clamp( frac, 0.f, 1.f );
- // interpolate offset over some time
- Vector offset = m_vecOffset * (1-frac);
-
- C_BaseAnimating *parent = assert_cast< C_BaseAnimating* >( GetMoveParent() );
- Vector worldOrigin;
- worldOrigin.Init();
-
-
- if ( parent )
- {
- Assert( parent != this );
- parent->SetupBones( NULL, -1, BONE_USED_BY_ANYTHING, gpGlobals->curtime );
-
- matrix3x4_t boneToWorld;
- parent->GetCachedBoneMatrix( m_boneIndexAttached, boneToWorld );
- VectorTransform( m_attachmentPointBoneSpace, boneToWorld, worldOrigin );
- }
- BaseClass::BuildTransformations( hdr, pos, q, cameraTransform, boneMask, boneComputed );
-
- if ( parent )
- {
- int index = m_boneIndex[m_ragdollAttachedObjectIndex];
- const matrix3x4_t &matrix = GetBone( index );
- Vector ragOrigin;
- VectorTransform( m_attachmentPointRagdollSpace, matrix, ragOrigin );
- offset = worldOrigin - ragOrigin;
- // fixes culling
- SetAbsOrigin( worldOrigin );
- m_vecOffset = offset;
- }
-
- for ( int i = 0; i < hdr->numbones(); i++ )
- {
- if ( !( hdr->boneFlags( i ) & boneMask ) )
- continue;
-
- Vector pos;
- matrix3x4_t &matrix = GetBoneForWrite( i );
- MatrixGetColumn( matrix, 3, pos );
- pos += offset;
- MatrixSetColumn( pos, 3, matrix );
- }
- }
- void OnDataChanged( DataUpdateType_t updateType );
- virtual float LastBoneChangedTime() { return FLT_MAX; }
-
- Vector m_attachmentPointBoneSpace;
- Vector m_vecOffset;
- Vector m_attachmentPointRagdollSpace;
- int m_ragdollAttachedObjectIndex;
- int m_boneIndexAttached;
- float m_parentTime;
- bool m_bHasParent;
-private:
- C_ServerRagdollAttached( const C_ServerRagdollAttached & );
-};
-
-EXTERN_RECV_TABLE(DT_Ragdoll_Attached);
-IMPLEMENT_CLIENTCLASS_DT(C_ServerRagdollAttached, DT_Ragdoll_Attached, CRagdollPropAttached)
- RecvPropInt( RECVINFO( m_boneIndexAttached ) ),
- RecvPropInt( RECVINFO( m_ragdollAttachedObjectIndex ) ),
- RecvPropVector(RECVINFO(m_attachmentPointBoneSpace) ),
- RecvPropVector(RECVINFO(m_attachmentPointRagdollSpace) ),
-END_RECV_TABLE()
-
-void C_ServerRagdollAttached::OnDataChanged( DataUpdateType_t updateType )
-{
- BaseClass::OnDataChanged( updateType );
-
- bool bParentNow = GetMoveParent() ? true : false;
- if ( m_bHasParent != bParentNow )
- {
- if ( m_bHasParent )
- {
- m_parentTime = gpGlobals->curtime;
- }
- m_bHasParent = bParentNow;
- }
-}
-
-struct ragdoll_remember_t
-{
- C_BaseEntity *ragdoll;
- int tickCount;
-};
-
-struct ragdoll_memory_list_t
-{
- CUtlVector<ragdoll_remember_t> list;
-
- int tickCount;
-
- void Update()
- {
- if ( tickCount > gpGlobals->tickcount )
- {
- list.RemoveAll();
- return;
- }
-
- for ( int i = list.Count()-1; i >= 0; --i )
- {
- if ( list[i].tickCount != gpGlobals->tickcount )
- {
- list.FastRemove(i);
- }
- }
- }
-
- bool IsInList( C_BaseEntity *pRagdoll )
- {
- for ( int i = list.Count()-1; i >= 0; --i )
- {
- if ( list[i].ragdoll == pRagdoll )
- return true;
- }
-
- return false;
- }
- void AddToList( C_BaseEntity *pRagdoll )
- {
- Update();
- int index = list.AddToTail();
- list[index].ragdoll = pRagdoll;
- list[index].tickCount = gpGlobals->tickcount;
- }
-};
-
-static ragdoll_memory_list_t gRagdolls;
-
-void NoteRagdollCreationTick( C_BaseEntity *pRagdoll )
-{
- gRagdolls.AddToList( pRagdoll );
-}
-
-// returns true if the ragdoll was created on this tick
-bool WasRagdollCreatedOnCurrentTick( C_BaseEntity *pRagdoll )
-{
- gRagdolls.Update();
- return gRagdolls.IsInList( pRagdoll );
-}
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+
+#include "cbase.h"
+#include "mathlib/vmatrix.h"
+#include "ragdoll_shared.h"
+#include "bone_setup.h"
+#include "materialsystem/imesh.h"
+#include "engine/ivmodelinfo.h"
+#include "iviewrender.h"
+#include "tier0/vprof.h"
+#include "view.h"
+#include "physics_saverestore.h"
+#include "vphysics/constraints.h"
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#ifdef _DEBUG
+extern ConVar r_FadeProps;
+#endif
+
+CRagdoll::CRagdoll()
+{
+ m_ragdoll.listCount = 0;
+ m_vecLastOrigin.Init();
+ m_flLastOriginChangeTime = - 1.0f;
+
+ m_lastUpdate = -FLT_MAX;
+}
+
+#define DEFINE_RAGDOLL_ELEMENT( i ) \
+ DEFINE_FIELD( m_ragdoll.list[i].originParentSpace, FIELD_VECTOR ), \
+ DEFINE_PHYSPTR( m_ragdoll.list[i].pObject ), \
+ DEFINE_PHYSPTR( m_ragdoll.list[i].pConstraint ), \
+ DEFINE_FIELD( m_ragdoll.list[i].parentIndex, FIELD_INTEGER )
+
+BEGIN_SIMPLE_DATADESC( CRagdoll )
+
+ DEFINE_AUTO_ARRAY( m_ragdoll.boneIndex, FIELD_INTEGER ),
+ DEFINE_FIELD( m_ragdoll.listCount, FIELD_INTEGER ),
+ DEFINE_FIELD( m_ragdoll.allowStretch, FIELD_BOOLEAN ),
+ DEFINE_PHYSPTR( m_ragdoll.pGroup ),
+
+ DEFINE_RAGDOLL_ELEMENT( 0 ),
+ DEFINE_RAGDOLL_ELEMENT( 1 ),
+ DEFINE_RAGDOLL_ELEMENT( 2 ),
+ DEFINE_RAGDOLL_ELEMENT( 3 ),
+ DEFINE_RAGDOLL_ELEMENT( 4 ),
+ DEFINE_RAGDOLL_ELEMENT( 5 ),
+ DEFINE_RAGDOLL_ELEMENT( 6 ),
+ DEFINE_RAGDOLL_ELEMENT( 7 ),
+ DEFINE_RAGDOLL_ELEMENT( 8 ),
+ DEFINE_RAGDOLL_ELEMENT( 9 ),
+ DEFINE_RAGDOLL_ELEMENT( 10 ),
+ DEFINE_RAGDOLL_ELEMENT( 11 ),
+ DEFINE_RAGDOLL_ELEMENT( 12 ),
+ DEFINE_RAGDOLL_ELEMENT( 13 ),
+ DEFINE_RAGDOLL_ELEMENT( 14 ),
+ DEFINE_RAGDOLL_ELEMENT( 15 ),
+ DEFINE_RAGDOLL_ELEMENT( 16 ),
+ DEFINE_RAGDOLL_ELEMENT( 17 ),
+ DEFINE_RAGDOLL_ELEMENT( 18 ),
+ DEFINE_RAGDOLL_ELEMENT( 19 ),
+ DEFINE_RAGDOLL_ELEMENT( 20 ),
+ DEFINE_RAGDOLL_ELEMENT( 21 ),
+ DEFINE_RAGDOLL_ELEMENT( 22 ),
+ DEFINE_RAGDOLL_ELEMENT( 23 ),
+
+END_DATADESC()
+
+IPhysicsObject *CRagdoll::GetElement( int elementNum )
+{
+ return m_ragdoll.list[elementNum].pObject;
+}
+
+void CRagdoll::BuildRagdollBounds( C_BaseEntity *ent )
+{
+ Vector mins, maxs, size;
+ modelinfo->GetModelBounds( ent->GetModel(), mins, maxs );
+ size = (maxs - mins) * 0.5;
+ m_radius = size.Length();
+
+ m_mins.Init(-m_radius,-m_radius,-m_radius);
+ m_maxs.Init(m_radius,m_radius,m_radius);
+}
+
+void CRagdoll::Init(
+ C_BaseEntity *ent,
+ CStudioHdr *pstudiohdr,
+ const Vector &forceVector,
+ int forceBone,
+ const matrix3x4_t *pDeltaBones0,
+ const matrix3x4_t *pDeltaBones1,
+ const matrix3x4_t *pCurrentBonePosition,
+ float dt,
+ bool bFixedConstraints )
+{
+ ragdollparams_t params;
+ params.pGameData = static_cast<void *>( ent );
+ params.modelIndex = ent->GetModelIndex();
+ params.pCollide = modelinfo->GetVCollide( params.modelIndex );
+ params.pStudioHdr = pstudiohdr;
+ params.forceVector = forceVector;
+ params.forceBoneIndex = forceBone;
+ params.forcePosition.Init();
+ params.pCurrentBones = pCurrentBonePosition;
+ params.jointFrictionScale = 1.0;
+ params.allowStretch = false;
+ params.fixedConstraints = bFixedConstraints;
+ RagdollCreate( m_ragdoll, params, physenv );
+ ent->VPhysicsSetObject( NULL );
+ ent->VPhysicsSetObject( m_ragdoll.list[0].pObject );
+ // Mark the ragdoll as debris.
+ ent->SetCollisionGroup( COLLISION_GROUP_DEBRIS );
+
+ RagdollApplyAnimationAsVelocity( m_ragdoll, pDeltaBones0, pDeltaBones1, dt );
+ RagdollActivate( m_ragdoll, params.pCollide, ent->GetModelIndex() );
+
+ // It's moving now...
+ m_flLastOriginChangeTime = gpGlobals->curtime;
+
+ // So traces hit it.
+ ent->AddEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID );
+
+ if ( !m_ragdoll.listCount )
+ return;
+
+ BuildRagdollBounds( ent );
+
+ for ( int i = 0; i < m_ragdoll.listCount; i++ )
+ {
+ g_pPhysSaveRestoreManager->AssociateModel( m_ragdoll.list[i].pObject, ent->GetModelIndex() );
+ }
+
+#if RAGDOLL_VISUALIZE
+ memcpy( m_savedBone1, &pDeltaBones0[0], sizeof(matrix3x4_t) * pstudiohdr->numbones() );
+ memcpy( m_savedBone2, &pDeltaBones1[0], sizeof(matrix3x4_t) * pstudiohdr->numbones() );
+ memcpy( m_savedBone3, &pCurrentBonePosition[0], sizeof(matrix3x4_t) * pstudiohdr->numbones() );
+#endif
+}
+
+CRagdoll::~CRagdoll( void )
+{
+ for ( int i = 0; i < m_ragdoll.listCount; i++ )
+ {
+ IPhysicsObject *pObject = m_ragdoll.list[i].pObject;
+ if ( pObject )
+ {
+ g_pPhysSaveRestoreManager->ForgetModel( m_ragdoll.list[i].pObject );
+ // Disable collision on all ragdoll parts before calling RagdollDestroy
+ // (which might cause touch callbacks on the ragdoll otherwise, which is
+ // very bad for a half deleted ragdoll).
+ pObject->EnableCollisions( false );
+ }
+ }
+
+ RagdollDestroy( m_ragdoll );
+}
+
+
+void CRagdoll::RagdollBone( C_BaseEntity *ent, mstudiobone_t *pbones, int boneCount, bool *boneSimulated, CBoneAccessor &pBoneToWorld )
+{
+ for ( int i = 0; i < m_ragdoll.listCount; i++ )
+ {
+ if ( RagdollGetBoneMatrix( m_ragdoll, pBoneToWorld, i ) )
+ {
+ boneSimulated[m_ragdoll.boneIndex[i]] = true;
+ }
+ }
+}
+
+const Vector& CRagdoll::GetRagdollOrigin( )
+{
+ m_ragdoll.list[0].pObject->GetPosition( &m_origin, 0 );
+ return m_origin;
+}
+
+void CRagdoll::GetRagdollBounds( Vector &theMins, Vector &theMaxs )
+{
+ theMins = m_mins;
+ theMaxs = m_maxs;
+}
+
+void CRagdoll::VPhysicsUpdate( IPhysicsObject *pPhysics )
+{
+ if ( m_lastUpdate == gpGlobals->curtime )
+ return;
+ m_lastUpdate = gpGlobals->curtime;
+ m_allAsleep = RagdollIsAsleep( m_ragdoll );
+ if ( m_allAsleep )
+ {
+ // NOTE: This is the bbox of the ragdoll's physics
+ // It's not always correct to use for culling, but it sure beats
+ // using the radius box!
+ Vector origin = GetRagdollOrigin();
+ RagdollComputeExactBbox( m_ragdoll, origin, m_mins, m_maxs );
+ m_mins -= origin;
+ m_maxs -= origin;
+ }
+ else
+ {
+ m_mins.Init(-m_radius,-m_radius,-m_radius);
+ m_maxs.Init(m_radius,m_radius,m_radius);
+
+ if ( m_ragdoll.pGroup->IsInErrorState() )
+ {
+ C_BaseEntity *pEntity = static_cast<C_BaseEntity *>(m_ragdoll.list[0].pObject->GetGameData());
+ RagdollSolveSeparation( m_ragdoll, pEntity );
+ }
+ }
+
+ // See if we should go to sleep...
+ CheckSettleStationaryRagdoll();
+}
+
+//=============================================================================
+// HPE_BEGIN:
+// [menglish] Transforms a vector from the given bone's space to world space
+//=============================================================================
+
+bool CRagdoll::TransformVectorToWorld(int iBoneIndex, const Vector *vPosition, Vector *vOut)
+{
+ int listIndex = -1;
+ if( iBoneIndex >= 0 && iBoneIndex < m_ragdoll.listCount)
+ {
+ for ( int i = 0; i < m_ragdoll.listCount; ++i )
+ {
+ if(m_ragdoll.boneIndex[i] == iBoneIndex)
+ listIndex = i;
+ }
+ if(listIndex != -1)
+ {
+ m_ragdoll.list[listIndex].pObject->LocalToWorld(vOut, *vPosition);
+ return true;
+ }
+ }
+ return false;
+}
+
+//=============================================================================
+// HPE_END
+//=============================================================================
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+//-----------------------------------------------------------------------------
+void CRagdoll::PhysForceRagdollToSleep()
+{
+ for ( int i = 0; i < m_ragdoll.listCount; i++ )
+ {
+ if ( m_ragdoll.list[i].pObject )
+ {
+ PhysForceClearVelocity( m_ragdoll.list[i].pObject );
+ m_ragdoll.list[i].pObject->Sleep();
+ }
+ }
+}
+
+#define RAGDOLL_SLEEP_TOLERANCE 1.0f
+static ConVar ragdoll_sleepaftertime( "ragdoll_sleepaftertime", "5.0f", 0, "After this many seconds of being basically stationary, the ragdoll will go to sleep." );
+
+void CRagdoll::CheckSettleStationaryRagdoll()
+{
+ Vector delta = GetRagdollOrigin() - m_vecLastOrigin;
+ m_vecLastOrigin = GetRagdollOrigin();
+ for ( int i = 0; i < 3; ++i )
+ {
+ // It's still moving...
+ if ( fabs( delta[ i ] ) > RAGDOLL_SLEEP_TOLERANCE )
+ {
+ m_flLastOriginChangeTime = gpGlobals->curtime;
+ // Msg( "%d [%p] Still moving\n", gpGlobals->tickcount, this );
+ return;
+ }
+ }
+
+ // It's totally asleep, don't worry about forcing it to settle
+ if ( m_allAsleep )
+ return;
+
+ // Msg( "%d [%p] Settling\n", gpGlobals->tickcount, this );
+
+ // It has stopped moving, see if it
+ float dt = gpGlobals->curtime - m_flLastOriginChangeTime;
+ if ( dt < ragdoll_sleepaftertime.GetFloat() )
+ return;
+
+ // Msg( "%d [%p] FORCE SLEEP\n",gpGlobals->tickcount, this );
+
+ // Force it to go to sleep
+ PhysForceRagdollToSleep();
+}
+
+void CRagdoll::ResetRagdollSleepAfterTime( void )
+{
+ m_flLastOriginChangeTime = gpGlobals->curtime;
+}
+
+void CRagdoll::DrawWireframe()
+{
+ IMaterial *pWireframe = materials->FindMaterial("shadertest/wireframevertexcolor", TEXTURE_GROUP_OTHER);
+
+ int i;
+ matrix3x4_t matrix;
+ for ( i = 0; i < m_ragdoll.listCount; i++ )
+ {
+ static color32 debugColor = {0,255,255,0};
+
+ // draw the actual physics positions, not the cleaned up animation position
+ m_ragdoll.list[i].pObject->GetPositionMatrix( &matrix );
+ const CPhysCollide *pCollide = m_ragdoll.list[i].pObject->GetCollide();
+ engine->DebugDrawPhysCollide( pCollide, pWireframe, matrix, debugColor );
+ }
+
+#if RAGDOLL_VISUALIZE
+ for ( i = 0; i < m_ragdoll.listCount; i++ )
+ {
+ static color32 debugColor = {255,0,0,0};
+
+ const CPhysCollide *pCollide = m_ragdoll.list[i].pObject->GetCollide();
+ engine->DebugDrawPhysCollide( pCollide, pWireframe, m_savedBone1[m_ragdoll.boneIndex[i]], debugColor );
+ }
+ for ( i = 0; i < m_ragdoll.listCount; i++ )
+ {
+ static color32 debugColor = {0,255,0,0};
+
+ const CPhysCollide *pCollide = m_ragdoll.list[i].pObject->GetCollide();
+ engine->DebugDrawPhysCollide( pCollide, pWireframe, m_savedBone2[m_ragdoll.boneIndex[i]], debugColor );
+ }
+
+ for ( i = 0; i < m_ragdoll.listCount; i++ )
+ {
+ static color32 debugColor = {0,0,255,0};
+
+ const CPhysCollide *pCollide = m_ragdoll.list[i].pObject->GetCollide();
+ engine->DebugDrawPhysCollide( pCollide, pWireframe, m_savedBone3[m_ragdoll.boneIndex[i]], debugColor );
+ }
+#endif
+}
+
+
+CRagdoll *CreateRagdoll(
+ C_BaseEntity *ent,
+ CStudioHdr *pstudiohdr,
+ const Vector &forceVector,
+ int forceBone,
+ const matrix3x4_t *pDeltaBones0,
+ const matrix3x4_t *pDeltaBones1,
+ const matrix3x4_t *pCurrentBonePosition,
+ float dt,
+ bool bFixedConstraints )
+{
+ CRagdoll *pRagdoll = new CRagdoll;
+ pRagdoll->Init( ent, pstudiohdr, forceVector, forceBone, pDeltaBones0, pDeltaBones1, pCurrentBonePosition, dt, bFixedConstraints );
+
+ if ( !pRagdoll->IsValid() )
+ {
+ Msg("Bad ragdoll for %s\n", pstudiohdr->pszName() );
+ delete pRagdoll;
+ pRagdoll = NULL;
+ }
+ return pRagdoll;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class C_ServerRagdoll : public C_BaseAnimating
+{
+public:
+ DECLARE_CLASS( C_ServerRagdoll, C_BaseAnimating );
+ DECLARE_CLIENTCLASS();
+ DECLARE_INTERPOLATION();
+
+ C_ServerRagdoll( void );
+
+ virtual void PostDataUpdate( DataUpdateType_t updateType );
+
+ virtual int InternalDrawModel( int flags );
+ virtual CStudioHdr *OnNewModel( void );
+ virtual unsigned char GetClientSideFade();
+ virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights );
+
+ void GetRenderBounds( Vector& theMins, Vector& theMaxs );
+ virtual void AddEntity( void );
+ virtual void AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime );
+ virtual void BuildTransformations( CStudioHdr *pStudioHdr, Vector *pos, Quaternion q[], const matrix3x4_t &cameraTransform, int boneMask, CBoneBitList &boneComputed );
+ IPhysicsObject *GetElement( int elementNum );
+ virtual void UpdateOnRemove();
+ virtual float LastBoneChangedTime();
+
+ // Incoming from network
+ Vector m_ragPos[RAGDOLL_MAX_ELEMENTS];
+ QAngle m_ragAngles[RAGDOLL_MAX_ELEMENTS];
+
+ CInterpolatedVarArray< Vector, RAGDOLL_MAX_ELEMENTS > m_iv_ragPos;
+ CInterpolatedVarArray< QAngle, RAGDOLL_MAX_ELEMENTS > m_iv_ragAngles;
+
+ int m_elementCount;
+ int m_boneIndex[RAGDOLL_MAX_ELEMENTS];
+
+private:
+ C_ServerRagdoll( const C_ServerRagdoll &src );
+
+ typedef CHandle<C_BaseAnimating> CBaseAnimatingHandle;
+ CNetworkVar( CBaseAnimatingHandle, m_hUnragdoll );
+ CNetworkVar( float, m_flBlendWeight );
+ float m_flBlendWeightCurrent;
+ CNetworkVar( int, m_nOverlaySequence );
+ float m_flLastBoneChangeTime;
+};
+
+
+EXTERN_RECV_TABLE(DT_Ragdoll);
+IMPLEMENT_CLIENTCLASS_DT(C_ServerRagdoll, DT_Ragdoll, CRagdollProp)
+ RecvPropArray(RecvPropQAngles(RECVINFO(m_ragAngles[0])), m_ragAngles),
+ RecvPropArray(RecvPropVector(RECVINFO(m_ragPos[0])), m_ragPos),
+ RecvPropEHandle(RECVINFO(m_hUnragdoll)),
+ RecvPropFloat(RECVINFO(m_flBlendWeight)),
+ RecvPropInt(RECVINFO(m_nOverlaySequence)),
+END_RECV_TABLE()
+
+
+C_ServerRagdoll::C_ServerRagdoll( void ) :
+ m_iv_ragPos("C_ServerRagdoll::m_iv_ragPos"),
+ m_iv_ragAngles("C_ServerRagdoll::m_iv_ragAngles")
+{
+ m_elementCount = 0;
+ m_flLastBoneChangeTime = -FLT_MAX;
+
+ AddVar( m_ragPos, &m_iv_ragPos, LATCH_SIMULATION_VAR );
+ AddVar( m_ragAngles, &m_iv_ragAngles, LATCH_SIMULATION_VAR );
+
+ m_flBlendWeight = 0.0f;
+ m_flBlendWeightCurrent = 0.0f;
+ m_nOverlaySequence = -1;
+ m_flFadeScale = 1;
+}
+
+void C_ServerRagdoll::PostDataUpdate( DataUpdateType_t updateType )
+{
+ BaseClass::PostDataUpdate( updateType );
+
+ m_iv_ragPos.NoteChanged( gpGlobals->curtime, true );
+ m_iv_ragAngles.NoteChanged( gpGlobals->curtime, true );
+ // this is the local client time at which this update becomes stale
+ m_flLastBoneChangeTime = gpGlobals->curtime + GetInterpolationAmount(m_iv_ragPos.GetType());
+}
+
+float C_ServerRagdoll::LastBoneChangedTime()
+{
+ return m_flLastBoneChangeTime;
+}
+
+int C_ServerRagdoll::InternalDrawModel( int flags )
+{
+ int ret = BaseClass::InternalDrawModel( flags );
+ if ( vcollide_wireframe.GetBool() )
+ {
+ vcollide_t *pCollide = modelinfo->GetVCollide( GetModelIndex() );
+ IMaterial *pWireframe = materials->FindMaterial("shadertest/wireframevertexcolor", TEXTURE_GROUP_OTHER);
+
+ matrix3x4_t matrix;
+ for ( int i = 0; i < m_elementCount; i++ )
+ {
+ static color32 debugColor = {0,255,255,0};
+
+ AngleMatrix( m_ragAngles[i], m_ragPos[i], matrix );
+ engine->DebugDrawPhysCollide( pCollide->solids[i], pWireframe, matrix, debugColor );
+ }
+ }
+ return ret;
+}
+
+
+CStudioHdr *C_ServerRagdoll::OnNewModel( void )
+{
+ CStudioHdr *hdr = BaseClass::OnNewModel();
+
+ if ( !m_elementCount )
+ {
+ vcollide_t *pCollide = modelinfo->GetVCollide( GetModelIndex() );
+ if ( !pCollide )
+ {
+ const char *pszName = modelinfo->GetModelName( modelinfo->GetModel( GetModelIndex() ) );
+ Msg( "*** ERROR: C_ServerRagdoll::InitModel: %s missing vcollide data ***\n", (pszName) ? pszName : "<null>" );
+ m_elementCount = 0;
+ }
+ else
+ {
+ m_elementCount = RagdollExtractBoneIndices( m_boneIndex, hdr, pCollide );
+ }
+ m_iv_ragPos.SetMaxCount( m_elementCount );
+ m_iv_ragAngles.SetMaxCount( m_elementCount );
+ }
+
+ return hdr;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: clear out any face/eye values stored in the material system
+//-----------------------------------------------------------------------------
+void C_ServerRagdoll::SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights )
+{
+ BaseClass::SetupWeights( pBoneToWorld, nFlexWeightCount, pFlexWeights, pFlexDelayedWeights );
+
+ CStudioHdr *hdr = GetModelPtr();
+ if ( !hdr )
+ return;
+
+ int nFlexDescCount = hdr->numflexdesc();
+ if ( nFlexDescCount )
+ {
+ Assert( !pFlexDelayedWeights );
+ memset( pFlexWeights, 0, nFlexWeightCount * sizeof(float) );
+ }
+
+ if ( m_iEyeAttachment > 0 )
+ {
+ matrix3x4_t attToWorld;
+ if (GetAttachment( m_iEyeAttachment, attToWorld ))
+ {
+ Vector local, tmp;
+ local.Init( 1000.0f, 0.0f, 0.0f );
+ VectorTransform( local, attToWorld, tmp );
+ modelrender->SetViewTarget( GetModelPtr(), GetBody(), tmp );
+ }
+ }
+}
+
+
+void C_ServerRagdoll::GetRenderBounds( Vector& theMins, Vector& theMaxs )
+{
+ if( !CollisionProp()->IsBoundsDefinedInEntitySpace() )
+ {
+ IRotateAABB( EntityToWorldTransform(), CollisionProp()->OBBMins(), CollisionProp()->OBBMaxs(), theMins, theMaxs );
+ }
+ else
+ {
+ theMins = CollisionProp()->OBBMins();
+ theMaxs = CollisionProp()->OBBMaxs();
+ }
+}
+
+void C_ServerRagdoll::AddEntity( void )
+{
+ BaseClass::AddEntity();
+
+ // Move blend weight toward target over 0.2 seconds
+ m_flBlendWeightCurrent = Approach( m_flBlendWeight, m_flBlendWeightCurrent, gpGlobals->frametime * 5.0f );
+}
+
+void C_ServerRagdoll::AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime )
+{
+ BaseClass::AccumulateLayers( boneSetup, pos, q, currentTime );
+
+ if ( m_nOverlaySequence >= 0 && m_nOverlaySequence < boneSetup.GetStudioHdr()->GetNumSeq() )
+ {
+ boneSetup.AccumulatePose( pos, q, m_nOverlaySequence, GetCycle(), m_flBlendWeightCurrent, currentTime, m_pIk );
+ }
+}
+
+void C_ServerRagdoll::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quaternion q[], const matrix3x4_t &cameraTransform, int boneMask, CBoneBitList &boneComputed )
+{
+ if ( !hdr )
+ return;
+ matrix3x4_t bonematrix;
+ bool boneSimulated[MAXSTUDIOBONES];
+
+ // no bones have been simulated
+ memset( boneSimulated, 0, sizeof(boneSimulated) );
+ mstudiobone_t *pbones = hdr->pBone( 0 );
+
+ mstudioseqdesc_t *pSeqDesc = NULL;
+ if ( m_nOverlaySequence >= 0 && m_nOverlaySequence < hdr->GetNumSeq() )
+ {
+ pSeqDesc = &hdr->pSeqdesc( m_nOverlaySequence );
+ }
+
+ int i;
+ for ( i = 0; i < m_elementCount; i++ )
+ {
+ int index = m_boneIndex[i];
+ if ( index >= 0 )
+ {
+ if ( hdr->boneFlags(index) & boneMask )
+ {
+ boneSimulated[index] = true;
+ matrix3x4_t &matrix = GetBoneForWrite( index );
+
+ if ( m_flBlendWeightCurrent != 0.0f && pSeqDesc &&
+ // FIXME: this bone access is illegal
+ pSeqDesc->weight( index ) != 0.0f )
+ {
+ // Use the animated bone position instead
+ boneSimulated[index] = false;
+ }
+ else
+ {
+ AngleMatrix( m_ragAngles[i], m_ragPos[i], matrix );
+ }
+ }
+ }
+ }
+
+ for ( i = 0; i < hdr->numbones(); i++ )
+ {
+ if ( !( hdr->boneFlags( i ) & boneMask ) )
+ continue;
+
+ // BUGBUG: Merge this code with the code in c_baseanimating somehow!!!
+ // animate all non-simulated bones
+ if ( boneSimulated[i] ||
+ CalcProceduralBone( hdr, i, m_BoneAccessor ) )
+ {
+ continue;
+ }
+ else
+ {
+ QuaternionMatrix( q[i], pos[i], bonematrix );
+
+ if (pbones[i].parent == -1)
+ {
+ ConcatTransforms( cameraTransform, bonematrix, GetBoneForWrite( i ) );
+ }
+ else
+ {
+ ConcatTransforms( GetBone( pbones[i].parent ), bonematrix, GetBoneForWrite( i ) );
+ }
+ }
+
+ if ( pbones[i].parent == -1 )
+ {
+ // Apply client-side effects to the transformation matrix
+ // ApplyBoneMatrixTransform( GetBoneForWrite( i ) );
+ }
+ }
+}
+
+IPhysicsObject *C_ServerRagdoll::GetElement( int elementNum )
+{
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : virtual void
+//-----------------------------------------------------------------------------
+void C_ServerRagdoll::UpdateOnRemove()
+{
+ C_BaseAnimating *anim = m_hUnragdoll.Get();
+ if ( NULL != anim &&
+ anim->GetModel() &&
+ ( anim->GetModel() == GetModel() ) )
+ {
+ // Need to tell C_BaseAnimating to blend out of the ragdoll data that we received last
+ C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, false );
+ anim->CreateUnragdollInfo( this );
+ }
+
+ // Do last to mimic destrictor order
+ BaseClass::UpdateOnRemove();
+}
+
+//-----------------------------------------------------------------------------
+// Fade out
+//-----------------------------------------------------------------------------
+unsigned char C_ServerRagdoll::GetClientSideFade()
+{
+ return UTIL_ComputeEntityFade( this, m_fadeMinDist, m_fadeMaxDist, m_flFadeScale );
+}
+
+static int GetHighestBit( int flags )
+{
+ for ( int i = 31; i >= 0; --i )
+ {
+ if ( flags & (1<<i) )
+ return (1<<i);
+ }
+
+ return 0;
+}
+
+#define ATTACH_INTERP_TIME 0.2
+class C_ServerRagdollAttached : public C_ServerRagdoll
+{
+ DECLARE_CLASS( C_ServerRagdollAttached, C_ServerRagdoll );
+public:
+ C_ServerRagdollAttached( void )
+ {
+ m_bHasParent = false;
+ m_vecOffset.Init();
+ }
+ DECLARE_CLIENTCLASS();
+ bool SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime )
+ {
+ if ( GetMoveParent() )
+ {
+ // HACKHACK: Force the attached bone to be set up
+ int index = m_boneIndex[m_ragdollAttachedObjectIndex];
+ int boneFlags = GetModelPtr()->boneFlags(index);
+ if ( !(boneFlags & boneMask) )
+ {
+ // BUGBUG: The attached bone is required and this call is going to skip it, so force it
+ // HACKHACK: Assume the highest bit numbered bone flag is the minimum bone set
+ boneMask |= GetHighestBit( boneFlags );
+ }
+ }
+ return BaseClass::SetupBones( pBoneToWorldOut, nMaxBones, boneMask, currentTime );
+ }
+
+ virtual void BuildTransformations( CStudioHdr *hdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed )
+ {
+ VPROF_BUDGET( "C_ServerRagdollAttached::SetupBones", VPROF_BUDGETGROUP_CLIENT_ANIMATION );
+
+ if ( !hdr )
+ return;
+
+ float frac = RemapVal( gpGlobals->curtime, m_parentTime, m_parentTime+ATTACH_INTERP_TIME, 0, 1 );
+ frac = clamp( frac, 0.f, 1.f );
+ // interpolate offset over some time
+ Vector offset = m_vecOffset * (1-frac);
+
+ C_BaseAnimating *parent = assert_cast< C_BaseAnimating* >( GetMoveParent() );
+ Vector worldOrigin;
+ worldOrigin.Init();
+
+
+ if ( parent )
+ {
+ Assert( parent != this );
+ parent->SetupBones( NULL, -1, BONE_USED_BY_ANYTHING, gpGlobals->curtime );
+
+ matrix3x4_t boneToWorld;
+ parent->GetCachedBoneMatrix( m_boneIndexAttached, boneToWorld );
+ VectorTransform( m_attachmentPointBoneSpace, boneToWorld, worldOrigin );
+ }
+ BaseClass::BuildTransformations( hdr, pos, q, cameraTransform, boneMask, boneComputed );
+
+ if ( parent )
+ {
+ int index = m_boneIndex[m_ragdollAttachedObjectIndex];
+ const matrix3x4_t &matrix = GetBone( index );
+ Vector ragOrigin;
+ VectorTransform( m_attachmentPointRagdollSpace, matrix, ragOrigin );
+ offset = worldOrigin - ragOrigin;
+ // fixes culling
+ SetAbsOrigin( worldOrigin );
+ m_vecOffset = offset;
+ }
+
+ for ( int i = 0; i < hdr->numbones(); i++ )
+ {
+ if ( !( hdr->boneFlags( i ) & boneMask ) )
+ continue;
+
+ Vector pos;
+ matrix3x4_t &matrix = GetBoneForWrite( i );
+ MatrixGetColumn( matrix, 3, pos );
+ pos += offset;
+ MatrixSetColumn( pos, 3, matrix );
+ }
+ }
+ void OnDataChanged( DataUpdateType_t updateType );
+ virtual float LastBoneChangedTime() { return FLT_MAX; }
+
+ Vector m_attachmentPointBoneSpace;
+ Vector m_vecOffset;
+ Vector m_attachmentPointRagdollSpace;
+ int m_ragdollAttachedObjectIndex;
+ int m_boneIndexAttached;
+ float m_parentTime;
+ bool m_bHasParent;
+private:
+ C_ServerRagdollAttached( const C_ServerRagdollAttached & );
+};
+
+EXTERN_RECV_TABLE(DT_Ragdoll_Attached);
+IMPLEMENT_CLIENTCLASS_DT(C_ServerRagdollAttached, DT_Ragdoll_Attached, CRagdollPropAttached)
+ RecvPropInt( RECVINFO( m_boneIndexAttached ) ),
+ RecvPropInt( RECVINFO( m_ragdollAttachedObjectIndex ) ),
+ RecvPropVector(RECVINFO(m_attachmentPointBoneSpace) ),
+ RecvPropVector(RECVINFO(m_attachmentPointRagdollSpace) ),
+END_RECV_TABLE()
+
+void C_ServerRagdollAttached::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+
+ bool bParentNow = GetMoveParent() ? true : false;
+ if ( m_bHasParent != bParentNow )
+ {
+ if ( m_bHasParent )
+ {
+ m_parentTime = gpGlobals->curtime;
+ }
+ m_bHasParent = bParentNow;
+ }
+}
+
+struct ragdoll_remember_t
+{
+ C_BaseEntity *ragdoll;
+ int tickCount;
+};
+
+struct ragdoll_memory_list_t
+{
+ CUtlVector<ragdoll_remember_t> list;
+
+ int tickCount;
+
+ void Update()
+ {
+ if ( tickCount > gpGlobals->tickcount )
+ {
+ list.RemoveAll();
+ return;
+ }
+
+ for ( int i = list.Count()-1; i >= 0; --i )
+ {
+ if ( list[i].tickCount != gpGlobals->tickcount )
+ {
+ list.FastRemove(i);
+ }
+ }
+ }
+
+ bool IsInList( C_BaseEntity *pRagdoll )
+ {
+ for ( int i = list.Count()-1; i >= 0; --i )
+ {
+ if ( list[i].ragdoll == pRagdoll )
+ return true;
+ }
+
+ return false;
+ }
+ void AddToList( C_BaseEntity *pRagdoll )
+ {
+ Update();
+ int index = list.AddToTail();
+ list[index].ragdoll = pRagdoll;
+ list[index].tickCount = gpGlobals->tickcount;
+ }
+};
+
+static ragdoll_memory_list_t gRagdolls;
+
+void NoteRagdollCreationTick( C_BaseEntity *pRagdoll )
+{
+ gRagdolls.AddToList( pRagdoll );
+}
+
+// returns true if the ragdoll was created on this tick
+bool WasRagdollCreatedOnCurrentTick( C_BaseEntity *pRagdoll )
+{
+ gRagdolls.Update();
+ return gRagdolls.IsInList( pRagdoll );
+}
+