From f56bb35301836e56582a575a75864392a0177875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20P=2E=20Tjern=C3=B8?= Date: Mon, 2 Dec 2013 19:31:46 -0800 Subject: Fix line endings. WHAMMY. --- mp/src/game/client/ragdoll.cpp | 1734 ++++++++++++++++++++-------------------- 1 file changed, 867 insertions(+), 867 deletions(-) (limited to 'mp/src/game/client/ragdoll.cpp') 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( 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(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 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 : "" ); - 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<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 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( 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(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 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 : "" ); + 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<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 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 ); +} + -- cgit v1.2.3