diff --git a/game/client/c_baseanimating.cpp b/game/client/c_baseanimating.cpp index d66339e53e..f1a1007acc 100644 --- a/game/client/c_baseanimating.cpp +++ b/game/client/c_baseanimating.cpp @@ -738,6 +738,8 @@ C_BaseAnimating::C_BaseAnimating() : Q_memset(&m_mouth, 0, sizeof(m_mouth)); m_flCycle = 0; m_flOldCycle = 0; + m_flAnimTime = gpGlobals->curtime; + m_flOldAnimTime = gpGlobals->curtime; } //----------------------------------------------------------------------------- @@ -1759,7 +1761,7 @@ CollideType_t C_BaseAnimating::GetCollideType( void ) //----------------------------------------------------------------------------- // Purpose: if the active sequence changes, keep track of the previous ones and decay them based on their decay rate //----------------------------------------------------------------------------- -void C_BaseAnimating::MaintainSequenceTransitions( IBoneSetup &boneSetup, float flCycle, Vector pos[], Quaternion q[] ) +void C_BaseAnimating::MaintainSequenceTransitions( IBoneSetup &boneSetup, float flCycle, float currentTime, Vector pos[], Quaternion q[] ) { VPROF( "C_BaseAnimating::MaintainSequenceTransitions" ); @@ -1787,7 +1789,7 @@ void C_BaseAnimating::MaintainSequenceTransitions( IBoneSetup &boneSetup, float GetSequence(), flCycle, m_flPlaybackRate, - gpGlobals->curtime + currentTime ); @@ -1796,18 +1798,18 @@ void C_BaseAnimating::MaintainSequenceTransitions( IBoneSetup &boneSetup, float { C_AnimationLayer *blend = &m_SequenceTransitioner.m_animationQueue[i]; - float dt = (gpGlobals->curtime - blend->m_flLayerAnimtime); + float dt = (currentTime - blend->m_flLayerAnimtime); flCycle = blend->m_flCycle + dt * blend->m_flPlaybackRate * GetSequenceCycleRate( boneSetup.GetStudioHdr(), blend->m_nSequence ); flCycle = ClampCycle( flCycle, IsSequenceLooping( boneSetup.GetStudioHdr(), blend->m_nSequence ) ); #if 1 // _DEBUG if (/*Q_stristr( hdr->pszName(), r_sequence_debug.GetString()) != NULL || */ r_sequence_debug.GetInt() == entindex()) { - DevMsgRT( "%8.4f : %30s : %5.3f : %4.2f +\n", gpGlobals->curtime, boneSetup.GetStudioHdr()->pSeqdesc( blend->m_nSequence ).pszLabel(), flCycle, (float)blend->m_flWeight ); + DevMsgRT( "%8.4f : %30s : %5.3f : %4.2f +\n", currentTime, boneSetup.GetStudioHdr()->pSeqdesc( blend->m_nSequence ).pszLabel(), flCycle, (float)blend->m_flWeight ); } #endif - boneSetup.AccumulatePose( pos, q, blend->m_nSequence, flCycle, blend->m_flWeight, gpGlobals->curtime, m_pIk ); + boneSetup.AccumulatePose( pos, q, blend->m_nSequence, flCycle, blend->m_flWeight, currentTime, m_pIk ); } } @@ -1934,7 +1936,7 @@ void C_BaseAnimating::StandardBlendingRules( CStudioHdr *hdr, Vector pos[], Quat // debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), 0, 0, "%30s %6.2f : %6.2f", hdr->pSeqdesc( GetSequence() )->pszLabel( ), fCycle, 1.0 ); - MaintainSequenceTransitions( boneSetup, fCycle, pos, q ); + MaintainSequenceTransitions( boneSetup, fCycle, currentTime, pos, q ); AccumulateLayers( boneSetup, pos, q, currentTime ); @@ -2699,6 +2701,82 @@ void C_BaseAnimating::ThreadedBoneSetup() g_PreviousBoneSetups.RemoveAll(); } +void C_BaseAnimating::BuildMatricesWithBoneMerge( + const CStudioHdr *pStudioHdr, + const QAngle& angles, + const Vector& origin, + const Vector pos[MAXSTUDIOBONES], + const Quaternion q[MAXSTUDIOBONES], + matrix3x4_t bonetoworld[MAXSTUDIOBONES], + C_BaseAnimating *pParent, + CBoneCache *pParentCache + ) +{ + CStudioHdr *fhdr = pParent->GetModelPtr(); + mstudiobone_t *pbones = pStudioHdr->pBone( 0 ); + + matrix3x4_t rotationmatrix; // model to world transformation + AngleMatrix( angles, origin, rotationmatrix); + + for ( int i=0; i < pStudioHdr->numbones(); i++ ) + { + // Now find the bone in the parent entity. + bool merged = false; + int parentBoneIndex = Studio_BoneIndexByName( fhdr, pbones[i].pszName() ); + if ( parentBoneIndex >= 0 ) + { + matrix3x4_t *pMat = pParentCache->GetCachedBone( parentBoneIndex ); + if ( pMat ) + { + MatrixCopy( *pMat, bonetoworld[ i ] ); + merged = true; + } + } + + if ( !merged ) + { + // If we get down here, then the bone wasn't merged. + matrix3x4_t bonematrix; + QuaternionMatrix( q[i], pos[i], bonematrix ); + + if (pbones[i].parent == -1) + { + ConcatTransforms (rotationmatrix, bonematrix, bonetoworld[i]); + } + else + { + ConcatTransforms (bonetoworld[pbones[i].parent], bonematrix, bonetoworld[i]); + } + } + } +} + +void C_BaseAnimating::GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], int boneMask, float currentTime ) +{ + if(!pStudioHdr) + { + Assert(!"C_BaseAnimating::GetSkeleton() without a model"); + return; + } + + IBoneSetup boneSetup( pStudioHdr, boneMask, m_flPoseParameter ); + boneSetup.InitPose( pos, q ); + + boneSetup.AccumulatePose( pos, q, GetSequence(), GetCycle(), 1.0, currentTime, m_pIk ); + + if ( m_pIk ) + { + CIKContext auto_ik; + auto_ik.Init( pStudioHdr, GetRenderAngles(), GetRenderOrigin(), currentTime, 0, boneMask ); + boneSetup.CalcAutoplaySequences( pos, q, currentTime, &auto_ik ); + } + else + { + boneSetup.CalcAutoplaySequences( pos, q, currentTime, NULL ); + } + boneSetup.CalcBoneAdj( pos, q, m_flEncodedController ); +} + bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ) { VPROF_BUDGET( "C_BaseAnimating::SetupBones", VPROF_BUDGETGROUP_CLIENT_ANIMATION ); @@ -2905,7 +2983,7 @@ bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, i } BuildTransformations( hdr, pos, q, parentTransform, bonesMaskNeedRecalc, boneComputed ); - + RemoveFlag( EFL_SETTING_UP_BONES ); ControlMouth( hdr ); } @@ -5004,7 +5082,17 @@ float C_BaseAnimating::GetAnimTimeInterval( void ) const { #define MAX_ANIMTIME_INTERVAL 0.2f - float flInterval = MIN( gpGlobals->curtime - m_flAnimTime, MAX_ANIMTIME_INTERVAL ); + float flInterval; + if (m_flAnimTime < gpGlobals->curtime) + { + // estimate what it'll be this frame + flInterval = clamp( gpGlobals->curtime - m_flAnimTime, 0.f, MAX_ANIMTIME_INTERVAL ); + } + else + { + // report actual + flInterval = clamp( m_flAnimTime - m_flOldAnimTime, 0.f, MAX_ANIMTIME_INTERVAL ); + } return flInterval; } @@ -5046,6 +5134,24 @@ void C_BaseAnimating::SetSequence( int nSequence ) } } +float C_BaseAnimating::GetLastVisibleCycle( CStudioHdr *pStudioHdr, int iSequence ) +{ + if ( !pStudioHdr ) + { + DevWarning( 2, "C_BaseAnimating::LastVisibleCycle( %d ) NULL pstudiohdr on %s!\n", iSequence, GetClassname() ); + return 1.0; + } + + if (!(GetSequenceFlags( pStudioHdr, iSequence ) & STUDIO_LOOPING)) + { + return 1.0f - (pStudioHdr->pSeqdesc( iSequence ).fadeouttime) * GetSequenceCycleRate( pStudioHdr, iSequence ) * m_flPlaybackRate; + } + else + { + return 1.0; + } +} + //========================================================= // StudioFrameAdvance - advance the animation frame up some interval (default 0.1) into the future diff --git a/game/client/c_baseanimating.h b/game/client/c_baseanimating.h index f91745ef1b..53c417529f 100644 --- a/game/client/c_baseanimating.h +++ b/game/client/c_baseanimating.h @@ -12,6 +12,7 @@ #pragma once #endif +#include "bone_setup.h" #include "c_baseentity.h" #include "studio.h" #include "utlvector.h" @@ -143,6 +144,11 @@ public: virtual int VPhysicsGetObjectList( IPhysicsObject **pList, int listMax ); // model specific + void BuildMatricesWithBoneMerge( const CStudioHdr *pStudioHdr, const QAngle& angles, + const Vector& origin, const Vector pos[MAXSTUDIOBONES], + const Quaternion q[MAXSTUDIOBONES], matrix3x4_t bonetoworld[MAXSTUDIOBONES], + CBaseAnimating *pParent, CBoneCache *pParentCache ); + virtual void GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], int boneMask, float currentTime ); virtual bool SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ); virtual void UpdateIKLocks( float currentTime ); virtual void CalculateIKLocks( float currentTime ); @@ -182,7 +188,7 @@ public: virtual void StandardBlendingRules( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], float currentTime, int boneMask ); void UnragdollBlend( CStudioHdr *hdr, Vector pos[], Quaternion q[], float currentTime ); - void MaintainSequenceTransitions( IBoneSetup &boneSetup, float flCycle, Vector pos[], Quaternion q[] ); + void MaintainSequenceTransitions( IBoneSetup &boneSetup, float flCycle, float currentTime, Vector pos[], Quaternion q[] ); virtual void AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime ); virtual void ChildLayerBlend( Vector pos[], Quaternion q[], float currentTime, int boneMask ); @@ -333,6 +339,7 @@ public: char const *GetSequenceActivityName( int iSequence ); Activity GetSequenceActivity( int iSequence ); KeyValues *GetSequenceKeyValues( int iSequence ); + float GetLastVisibleCycle( CStudioHdr *pStudioHdr, int iSequence ); virtual void StudioFrameAdvance(); // advance animation frame to some time in the future // Clientside animation