diff --git a/game/client/c_baseanimating.cpp b/game/client/c_baseanimating.cpp index 97634c31ae..5d26f52bbf 100644 --- a/game/client/c_baseanimating.cpp +++ b/game/client/c_baseanimating.cpp @@ -12,6 +12,7 @@ #include "convar.h" #include "iconvar.h" #include "interpolatedvar.h" +#include "mathlib/mathlib.h" #include "model_types.h" #include "bone_setup.h" #include "ivrenderview.h" @@ -1498,7 +1499,7 @@ void C_BaseAnimating::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quater m_pBoneMergeCache = new CBoneMergeCache; m_pBoneMergeCache->Init( this ); } - m_pBoneMergeCache->MergeMatchingBones( boneMask ); + m_pBoneMergeCache->MergeMatchingBones( boneMask, m_BoneAccessor.GetBoneArrayForWrite() ); } else { @@ -1890,7 +1891,7 @@ void C_BaseAnimating::AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Qua void C_BaseAnimating::ChildLayerBlend( Vector pos[], Quaternion q[], float currentTime, int boneMask ) { - return; + return; Vector childPos[MAXSTUDIOBONES]; Quaternion childQ[MAXSTUDIOBONES]; @@ -2743,82 +2744,6 @@ 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 ); diff --git a/game/client/c_baseanimating.h b/game/client/c_baseanimating.h index 0d9fb02190..4cb2a00bfc 100644 --- a/game/client/c_baseanimating.h +++ b/game/client/c_baseanimating.h @@ -144,11 +144,6 @@ 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 ); diff --git a/game/client/c_baseanimatingoverlay.cpp b/game/client/c_baseanimatingoverlay.cpp index 4f9dc37bd4..1ea6b99062 100644 --- a/game/client/c_baseanimatingoverlay.cpp +++ b/game/client/c_baseanimatingoverlay.cpp @@ -370,66 +370,3 @@ CStudioHdr *C_BaseAnimatingOverlay::OnNewModel() return hdr; } - -void C_BaseAnimatingOverlay::GetSkeleton( CStudioHdr* pStudioHdr, Vector pos[], Quaternion q[], int boneMask, float currentTime ) -{ - if(!pStudioHdr) - { - Assert(!"C_BaseAnimating::GetSkeleton() without a model"); - return; - } - - if (!pStudioHdr->SequencesAvailable()) - { - return; - } - - float poseparameters[MAXSTUDIOPOSEPARAM]; - GetPoseParameters(pStudioHdr, poseparameters); - - IBoneSetup boneSetup( pStudioHdr, boneMask, poseparameters ); - boneSetup.InitPose( pos, q ); - - boneSetup.AccumulatePose( pos, q, GetSequence(), GetCycle(), 1.0, currentTime, m_pIk ); - - // sort the layers - int layer[MAX_OVERLAYS] = {}; - int i; - for (i = 0; i < m_AnimOverlay.Count(); i++) - { - layer[i] = MAX_OVERLAYS; - } - for (i = 0; i < m_AnimOverlay.Count(); i++) - { - CAnimationLayer &pLayer = m_AnimOverlay[i]; - if( (pLayer.m_flWeight > 0) && pLayer.IsActive() && pLayer.m_nOrder >= 0 && pLayer.m_nOrder < m_AnimOverlay.Count()) - { - layer[pLayer.m_nOrder] = i; - } - } - for (i = 0; i < m_AnimOverlay.Count(); i++) - { - if (layer[i] >= 0 && layer[i] < m_AnimOverlay.Count()) - { - CAnimationLayer &pLayer = m_AnimOverlay[layer[i]]; - // UNDONE: Is it correct to use overlay weight for IK too? - boneSetup.AccumulatePose( pos, q, pLayer.m_nSequence, pLayer.m_flCycle, pLayer.m_flWeight, 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); - } - - float controllers[MAXSTUDIOBONECTRLS]; - GetBoneControllers(controllers); - - boneSetup.CalcBoneAdj( pos, q, controllers ); -} \ No newline at end of file diff --git a/game/client/c_baseanimatingoverlay.h b/game/client/c_baseanimatingoverlay.h index f82def41b1..e8527df5b9 100644 --- a/game/client/c_baseanimatingoverlay.h +++ b/game/client/c_baseanimatingoverlay.h @@ -38,8 +38,6 @@ public: // model specific virtual void AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime ); virtual void DoAnimationEvents( CStudioHdr *pStudioHdr ); - virtual void GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], int boneMask, float currentTime ); - enum { MAX_OVERLAYS = 15, diff --git a/game/client/client_base.vpc b/game/client/client_base.vpc index 90e16cb81d..24f145928b 100644 --- a/game/client/client_base.vpc +++ b/game/client/client_base.vpc @@ -204,7 +204,7 @@ $Project $File "beamdraw.cpp" $File "$SRCDIR\game\shared\beam_shared.cpp" $File "$SRCDIR\public\bone_accessor.cpp" - $File "bone_merge_cache.cpp" + $File "$SRCDIR\game\shared\bone_merge_cache.cpp" $File "c_ai_basehumanoid.cpp" $File "c_ai_basenpc.cpp" $File "c_baseanimating.cpp" @@ -674,7 +674,7 @@ $Project $File "baseanimatedtextureproxy.h" $File "baseclientrendertargets.h" $File "beamdraw.h" - $File "bone_merge_cache.h" + $File "$SRCDIR\game\shared\bone_merge_cache.h" $File "c_ai_basenpc.h" $File "c_baseanimating.h" $File "c_baseanimatingoverlay.h" diff --git a/game/client/cstrike/c_cs_player.cpp b/game/client/cstrike/c_cs_player.cpp index 6c618cd771..e63fa5bc99 100644 --- a/game/client/cstrike/c_cs_player.cpp +++ b/game/client/cstrike/c_cs_player.cpp @@ -2598,103 +2598,12 @@ float C_CSPlayer::GetDeathCamInterpolationTime() return spec_freeze_time.GetFloat(); else return CS_DEATH_ANIMATION_TIME; - } -ConVar cl_server_setup_bones("cl_server_setup_bones", "1"); bool C_CSPlayer::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ) { - if (cl_server_setup_bones.GetBool()) - { - AUTO_LOCK( m_BoneSetupLock ); - - MDLCACHE_CRITICAL_SECTION(); - - Assert( GetModelPtr() ); - - CStudioHdr *pStudioHdr = GetModelPtr( ); - - if(!pStudioHdr) - { - Assert(!"C_BaseAnimating::GetSkeleton() without a model"); - return false; - } - - Assert( !IsEFlagSet( EFL_SETTING_UP_BONES ) ); - - AddEFlags( EFL_SETTING_UP_BONES ); - - Vector pos[MAXSTUDIOBONES]; - Quaternion q[MAXSTUDIOBONES]; - - // adjust hit boxes based on IK driven offset - Vector adjOrigin = GetRenderOrigin(); - - if ( m_pIk ) - { - // FIXME: pass this into Studio_BuildMatrices to skip transforms - CBoneBitList boneComputed; - m_iIKCounter++; - m_pIk->Init( pStudioHdr, GetRenderAngles(), adjOrigin, currentTime, m_iIKCounter, boneMask ); - GetSkeleton( pStudioHdr, pos, q, boneMask, currentTime ); - - m_pIk->UpdateTargets( pos, q, m_BoneAccessor.GetBoneArrayForWrite(), boneComputed ); - CalculateIKLocks( currentTime ); - m_pIk->SolveDependencies( pos, q, m_BoneAccessor.GetBoneArrayForWrite(), boneComputed ); - } - else - { - // Msg( "%.03f : %s:%s\n", gpGlobals->curtime, GetClassname(), GetEntityName().ToCStr() ); - GetSkeleton( pStudioHdr, pos, q, boneMask, currentTime ); - } - - CBaseAnimating *pParent = dynamic_cast< CBaseAnimating* >( GetMoveParent() ); - if ( pParent ) - { - // We're doing bone merging, so do special stuff here. - CBoneCache *pParentCache = pParent->GetBoneCache(pParent->GetModelPtr()); - if ( pParentCache ) - { - BuildMatricesWithBoneMerge( - pStudioHdr, - GetRenderAngles(), - adjOrigin, - pos, - q, - m_BoneAccessor.GetBoneArrayForWrite(), - pParent, - pParentCache ); - - RemoveEFlags( EFL_SETTING_UP_BONES ); - return true; - } - } - - Studio_BuildMatrices( - pStudioHdr, - GetRenderAngles(), - adjOrigin, - pos, - q, - -1, - GetModelScale(), // Scaling - m_BoneAccessor.GetBoneArrayForWrite(), - boneMask ); - - RemoveEFlags(EFL_SETTING_UP_BONES); - - if ( pBoneToWorldOut ) - { - memcpy( pBoneToWorldOut, m_BoneAccessor.GetBoneArrayForWrite(), sizeof( matrix3x4_t ) * MAXSTUDIOBONES ); - } - - return true; - } - else - { - return BaseClass::SetupBones( pBoneToWorldOut, nMaxBones, boneMask, currentTime ); - } + return BaseClass::SetupBones( pBoneToWorldOut, nMaxBones, boneMask, currentTime ); } //============================================================================= diff --git a/game/server/BaseAnimatingOverlay.cpp b/game/server/BaseAnimatingOverlay.cpp index 36534bc0fa..2a969ba9fb 100644 --- a/game/server/BaseAnimatingOverlay.cpp +++ b/game/server/BaseAnimatingOverlay.cpp @@ -447,7 +447,12 @@ void CBaseAnimatingOverlay::GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Q return; } - IBoneSetup boneSetup( pStudioHdr, boneMask, GetPoseParameterArray() ); + float flPoseParams[MAXSTUDIOPOSEPARAM]; + float flEncodedParams[MAXSTUDIOBONECTRLS]; + + GetPoseParameters( pStudioHdr, flPoseParams ); + + IBoneSetup boneSetup( pStudioHdr, boneMask, flPoseParams ); boneSetup.InitPose( pos, q ); boneSetup.AccumulatePose( pos, q, GetSequence(), GetCycle(), 1.0, gpGlobals->curtime, m_pIk ); @@ -486,12 +491,12 @@ void CBaseAnimatingOverlay::GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Q else { boneSetup.CalcAutoplaySequences( pos, q, gpGlobals->curtime, NULL ); - } - boneSetup.CalcBoneAdj( pos, q, GetEncodedControllerArray() ); + } + GetEncodedControllers( pStudioHdr, flEncodedParams ); + boneSetup.CalcBoneAdj( pos, q, flEncodedParams ); } - //----------------------------------------------------------------------------- // Purpose: zero's out all non-restore safe fields // Output : diff --git a/game/server/baseanimating.cpp b/game/server/baseanimating.cpp index 5b3d3a11c4..d8b784147f 100644 --- a/game/server/baseanimating.cpp +++ b/game/server/baseanimating.cpp @@ -14,6 +14,8 @@ #include "enginecallback.h" #include "entitylist_base.h" #include "mathlib/vector.h" +#include "mathlib/vmatrix.h" +#include "player.h" #include "shareddefs.h" #include "studio.h" #include "bone_setup.h" @@ -289,6 +291,8 @@ CBaseAnimating::CBaseAnimating() m_fadeMaxDist = 0; m_flFadeScale = 0.0f; m_fBoneCacheFlags = 0; + m_pBoneMergeCache = NULL; + m_pBoneCache = NULL; } CBaseAnimating::~CBaseAnimating() @@ -1693,6 +1697,32 @@ void CBaseAnimating::Teleport( const Vector *newPosition, const QAngle *newAngle } +void CBaseAnimating::GetPoseParameters( CStudioHdr *pStudioHdr, float poseParameter[MAXSTUDIOPOSEPARAM]) +{ + if ( !pStudioHdr ) + return; + + // interpolate pose parameters + int i; + for( i=0; i < pStudioHdr->GetNumPoseParameters(); i++) + { + poseParameter[i] = m_flPoseParameter[i]; + } +} + +void CBaseAnimating::GetEncodedControllers(CStudioHdr* pStudioHdr, float encodedControllers[MAXSTUDIOBONECTRLS]) +{ + if ( !pStudioHdr ) + return; + + // interpolate pose parameters + int i; + for( i=0; i < pStudioHdr->GetNumPoseParameters(); i++) + { + encodedControllers[i] = m_flEncodedController[i]; + } +} + //----------------------------------------------------------------------------- // Purpose: build matrices first from the parent, then from the passed in arrays if the bone doesn't exist on the parent //----------------------------------------------------------------------------- @@ -1704,45 +1734,56 @@ void CBaseAnimating::BuildMatricesWithBoneMerge( const Vector pos[MAXSTUDIOBONES], const Quaternion q[MAXSTUDIOBONES], matrix3x4_t bonetoworld[MAXSTUDIOBONES], - CBaseAnimating *pParent, - CBoneCache *pParentCache + int boneMask ) { - 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++ ) + bool boneMerge = IsEffectActive(EF_BONEMERGE); + if ( boneMerge || m_pBoneMergeCache ) { - // Now find the bone in the parent entity. - bool merged = false; - int parentBoneIndex = Studio_BoneIndexByName( fhdr, pbones[i].pszName() ); - if ( parentBoneIndex >= 0 ) + if ( boneMerge ) { - matrix3x4_t *pMat = pParentCache->GetCachedBone( parentBoneIndex ); - if ( pMat ) + if ( !m_pBoneMergeCache ) { - MatrixCopy( *pMat, bonetoworld[ i ] ); - merged = true; + m_pBoneMergeCache = new CBoneMergeCache; + m_pBoneMergeCache->Init( this ); } + m_pBoneMergeCache->MergeMatchingBones( boneMask, bonetoworld ); } - - if ( !merged ) + else { - // If we get down here, then the bone wasn't merged. - matrix3x4_t bonematrix; - QuaternionMatrix( q[i], pos[i], bonematrix ); + delete m_pBoneMergeCache; + m_pBoneMergeCache = NULL; + } + } + + for ( int i=0; i < pStudioHdr->numbones(); i++ ) + { + if (!(pStudioHdr->boneFlags(i) & boneMask)) + { + continue; + } + + if (m_pBoneMergeCache && m_pBoneMergeCache->IsBoneMerged(i)) + { + continue; + } - if (pbones[i].parent == -1) - { - ConcatTransforms (rotationmatrix, bonematrix, bonetoworld[i]); - } - else - { - ConcatTransforms (bonetoworld[pbones[i].parent], bonematrix, bonetoworld[i]); - } + // 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]); } } } @@ -1772,24 +1813,56 @@ inline bool CBaseAnimating::CanSkipAnimation( void ) } -void CBaseAnimating::SetupBones( matrix3x4_t *pBoneToWorld, int boneMask ) +void CBaseAnimating::SetupBones( CStudioHdr* pStudioHdr, matrix3x4_t *pBoneToWorld, int boneMask ) { + static constexpr auto flDebugDuration = 60.f; AUTO_LOCK( m_BoneSetupMutex ); VPROF_BUDGET( "CBaseAnimating::SetupBones", VPROF_BUDGETGROUP_SERVER_ANIM ); MDLCACHE_CRITICAL_SECTION(); - Assert( GetModelPtr() ); + m_pBoneCache = Studio_GetBoneCache(m_boneCacheHandle); - CStudioHdr *pStudioHdr = GetModelPtr( ); + if ( m_pBoneCache ) + { + if ( m_pBoneCache->IsValid( gpGlobals->curtime ) && (m_pBoneCache->m_boneMask & boneMask) == boneMask && m_pBoneCache->m_timeValid <= gpGlobals->curtime) + { + // Msg("%s:%s:%s (%x:%x:%8.4f) cache\n", GetClassname(), GetDebugName(), STRING(GetModelName()), boneMask, pcache->m_boneMask, pcache->m_timeValid ); + // in memory and still valid, use it! + m_pBoneCache->ReadCachedBones(pBoneToWorld); + return; + } + + // in memory, but missing some of the bone masks + if ( (m_pBoneCache->m_boneMask & boneMask) != boneMask ) + { + Studio_DestroyBoneCache( m_boneCacheHandle ); + m_boneCacheHandle = 0; + m_pBoneCache = NULL; + } + } + + if ( !m_pBoneCache ) + { + bonecacheparams_t params; + params.pStudioHdr = pStudioHdr; + params.pBoneToWorld = pBoneToWorld; + params.curtime = gpGlobals->curtime; + params.boneMask = boneMask; + + m_boneCacheHandle = Studio_CreateBoneCache(params); + m_pBoneCache = Studio_GetBoneCache(m_boneCacheHandle); + } + + Assert( pStudioHdr ); if(!pStudioHdr) { Assert(!"CBaseAnimating::GetSkeleton() without a model"); return; } - + Assert( !IsEFlagSet( EFL_SETTING_UP_BONES ) ); AddEFlags( EFL_SETTING_UP_BONES ); @@ -1797,8 +1870,8 @@ void CBaseAnimating::SetupBones( matrix3x4_t *pBoneToWorld, int boneMask ) Vector pos[MAXSTUDIOBONES]; Quaternion q[MAXSTUDIOBONES]; - // adjust hit boxes based on IK driven offset - Vector adjOrigin = GetAbsOrigin() + Vector( 0, 0, m_flEstIkOffset ); + // Remove IK to respect more the client hitboxes. + Vector adjOrigin = GetAbsOrigin(); if ( CanSkipAnimation() ) { @@ -1825,49 +1898,16 @@ void CBaseAnimating::SetupBones( matrix3x4_t *pBoneToWorld, int boneMask ) // Msg( "%.03f : %s:%s\n", gpGlobals->curtime, GetClassname(), GetEntityName().ToCStr() ); GetSkeleton( pStudioHdr, pos, q, boneMask ); } - } - - CBaseAnimating *pParent = dynamic_cast< CBaseAnimating* >( GetMoveParent() ); - if ( pParent ) - { - // We're doing bone merging, so do special stuff here. - CBoneCache *pParentCache = pParent->GetBoneCache(); - if ( pParentCache ) - { - BuildMatricesWithBoneMerge( - pStudioHdr, - GetAbsAngles(), - adjOrigin, - pos, - q, - pBoneToWorld, - pParent, - pParentCache ); - - RemoveEFlags( EFL_SETTING_UP_BONES ); - if (ai_setupbones_debug.GetBool()) - { - DrawRawSkeleton( pBoneToWorld, boneMask, true, 0.11 ); - } - return; - } - } + } - Studio_BuildMatrices( - pStudioHdr, - GetAbsAngles(), - adjOrigin, - pos, - q, - -1, - GetModelScale(), // Scaling - pBoneToWorld, - boneMask ); + BuildMatricesWithBoneMerge(pStudioHdr, GetAbsAngles(), adjOrigin, pos, q, pBoneToWorld, boneMask); + + m_pBoneCache->UpdateBones(pBoneToWorld, pStudioHdr->numbones(), gpGlobals->curtime); if (ai_setupbones_debug.GetBool()) { // Msg("%s:%s:%s (%x)\n", GetClassname(), GetDebugName(), STRING(GetModelName()), boneMask ); - DrawRawSkeleton( pBoneToWorld, boneMask, true, 0.11 ); + DrawRawSkeleton( pBoneToWorld, boneMask, true, flDebugDuration ); } RemoveEFlags( EFL_SETTING_UP_BONES ); } @@ -2588,51 +2628,33 @@ CBoneCache *CBaseAnimating::GetBoneCache( void ) CStudioHdr *pStudioHdr = GetModelPtr( ); Assert(pStudioHdr); - CBoneCache *pcache = Studio_GetBoneCache( m_boneCacheHandle ); - int boneMask = BONE_USED_BY_HITBOX | BONE_USED_BY_ATTACHMENT; + int boneMask = BONE_USED_BY_HITBOX | BONE_USED_BY_ATTACHMENT | BONE_USED_BY_BONE_MERGE; // TF queries these bones to position weapons when players are killed #if defined( TF_DLL ) boneMask |= BONE_USED_BY_BONE_MERGE; #endif - if ( pcache ) - { - if ( pcache->IsValid( gpGlobals->curtime ) && (pcache->m_boneMask & boneMask) == boneMask && pcache->m_timeValid <= gpGlobals->curtime) - { - // Msg("%s:%s:%s (%x:%x:%8.4f) cache\n", GetClassname(), GetDebugName(), STRING(GetModelName()), boneMask, pcache->m_boneMask, pcache->m_timeValid ); - // in memory and still valid, use it! - return pcache; - } - // in memory, but missing some of the bone masks - if ( (pcache->m_boneMask & boneMask) != boneMask ) - { - Studio_DestroyBoneCache( m_boneCacheHandle ); - m_boneCacheHandle = 0; - pcache = NULL; - } - } matrix3x4_t bonetoworld[MAXSTUDIOBONES]; - SetupBones( bonetoworld, boneMask ); + SetupBones( GetModelPtr(), bonetoworld, boneMask ); - if ( pcache ) - { - // still in memory but out of date, refresh the bones. - pcache->UpdateBones( bonetoworld, pStudioHdr->numbones(), gpGlobals->curtime ); - } - else - { - bonecacheparams_t params; - params.pStudioHdr = pStudioHdr; - params.pBoneToWorld = bonetoworld; - params.curtime = gpGlobals->curtime; - params.boneMask = boneMask; + for (auto pChild = FirstMoveChild(); pChild; pChild = pChild->NextMovePeer()) + { + auto pChildAnimating = dynamic_cast(pChild); - m_boneCacheHandle = Studio_CreateBoneCache( params ); - pcache = Studio_GetBoneCache( m_boneCacheHandle ); - } - Assert(pcache); - return pcache; + if (!pChildAnimating || !pChildAnimating->GetModelPtr()) + { + continue; + } + + printf("animating: %i %s %s\n", pChildAnimating->entindex(), pChildAnimating->GetDebugName(), pChildAnimating->GetModelName().ToCStr()); + + matrix3x4_t childbones[MAXSTUDIOBONES]; + pChildAnimating->SetupBones(pChildAnimating->GetModelPtr(), childbones, boneMask); + } + + Assert(m_pBoneCache); + return m_pBoneCache; } @@ -2810,7 +2832,12 @@ void CBaseAnimating::GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Quaterni return; } - IBoneSetup boneSetup( pStudioHdr, boneMask, GetPoseParameterArray() ); + float flPoseParams[MAXSTUDIOPOSEPARAM]; + float flEncodedParams[MAXSTUDIOBONECTRLS]; + + GetPoseParameters( pStudioHdr, flPoseParams ); + + IBoneSetup boneSetup( pStudioHdr, boneMask, flPoseParams ); boneSetup.InitPose( pos, q ); boneSetup.AccumulatePose( pos, q, GetSequence(), GetCycle(), 1.0, gpGlobals->curtime, m_pIk ); @@ -2825,7 +2852,8 @@ void CBaseAnimating::GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Quaterni { boneSetup.CalcAutoplaySequences( pos, q, gpGlobals->curtime, NULL ); } - boneSetup.CalcBoneAdj( pos, q, GetEncodedControllerArray() ); + GetEncodedControllers( pStudioHdr, flEncodedParams ); + boneSetup.CalcBoneAdj( pos, q, flEncodedParams ); } int CBaseAnimating::DrawDebugTextOverlays(void) @@ -3067,8 +3095,14 @@ void CBaseAnimating::DrawRawSkeleton( matrix3x4_t boneToWorld[], int boneMask, b int i; int r = 255; int g = 255; - int b = monocolor ? 255 : 0; - + int b = monocolor ? 255 : 0; + + if (boneMask & 0x00080000) + { + r = 0; + g = 0; + b = 255; + } for (i = 0; i < pStudioHdr->numbones(); i++) { @@ -3080,6 +3114,14 @@ void CBaseAnimating::DrawRawSkeleton( matrix3x4_t boneToWorld[], int boneMask, b { Vector p2; MatrixPosition( boneToWorld[pStudioHdr->pBone( i )->parent], p2 ); + if (pStudioHdr->pBone(i)->flags & BONE_USED_BY_BONE_MERGE) + { + r = 255; + } + else + { + r = 0; + } NDebugOverlay::Line( p1, p2, r, g, b, noDepthTest, duration ); } } @@ -3605,6 +3647,12 @@ CStudioHdr *CBaseAnimating::OnNewModel() { (void) BaseClass::OnNewModel(); + if ( m_pBoneMergeCache ) + { + delete m_pBoneMergeCache; + m_pBoneMergeCache = NULL; + } + // TODO: if dynamic, validate m_Sequence and apply queued body group settings? if ( IsDynamicModelLoading() ) { diff --git a/game/server/baseanimating.h b/game/server/baseanimating.h index d96d01e697..666dcf5590 100644 --- a/game/server/baseanimating.h +++ b/game/server/baseanimating.h @@ -18,6 +18,7 @@ #include "studio.h" #include "datacache/idatacache.h" #include "tier0/threadtools.h" +#include "bone_merge_cache.h" class CBasePlayer; struct animevent_t; @@ -136,7 +137,7 @@ public: virtual void GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], int boneMask ); virtual void GetBoneTransform( int iBone, matrix3x4_t &pBoneToWorld ); - virtual void SetupBones( matrix3x4_t *pBoneToWorld, int boneMask ); + virtual void SetupBones( CStudioHdr *pStudioHdr, matrix3x4_t *pBoneToWorld, int boneMask ); virtual void CalculateIKLocks( float currentTime ); virtual void Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity ); @@ -160,7 +161,8 @@ public: bool HasPoseParameter( int iSequence, const char *szName ); bool HasPoseParameter( int iSequence, int iParameter ); float EdgeLimitPoseParameter( int iParameter, float flValue, float flBase = 0.0f ); - + virtual void GetPoseParameters(CStudioHdr* pStudioHdr, float poseParameter[MAXSTUDIOPOSEPARAM]); + virtual void GetEncodedControllers(CStudioHdr* pStudioHdr, float encodedControllers[MAXSTUDIOBONECTRLS]); protected: // The modus operandi for pose parameters is that you should not use the const char * version of the functions // in general code -- it causes many many string comparisons, which is slower than you think. Better is to @@ -326,8 +328,7 @@ public: 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 ); + const Quaternion q[MAXSTUDIOBONES], matrix3x4_t bonetoworld[MAXSTUDIOBONES], int boneMask ); void SetFadeDistance( float minFadeDist, float maxFadeDist ); @@ -336,10 +337,10 @@ public: inline void ClearBoneCacheFlags( unsigned short fFlag ) { m_fBoneCacheFlags &= ~fFlag; } bool PrefetchSequence( int iSequence ); + virtual void LockStudioHdr(); + virtual void UnlockStudioHdr(); private: - void LockStudioHdr(); - void UnlockStudioHdr(); void StudioFrameAdvanceInternal( CStudioHdr *pStudioHdr, float flInterval ); void InputSetLightingOriginRelative( inputdata_t &inputdata ); @@ -422,10 +423,12 @@ protected: public: COutputEvent m_OnIgnite; -private: +public: CStudioHdr *m_pStudioHdr; CThreadFastMutex m_StudioHdrInitLock; CThreadFastMutex m_BoneSetupMutex; + CBoneCache *m_pBoneCache; + CBoneMergeCache *m_pBoneMergeCache; // FIXME: necessary so that cyclers can hack m_bSequenceFinished friend class CFlexCycler; diff --git a/game/server/hl2/npc_barnacle.cpp b/game/server/hl2/npc_barnacle.cpp index 9e82435180..72566bcf76 100644 --- a/game/server/hl2/npc_barnacle.cpp +++ b/game/server/hl2/npc_barnacle.cpp @@ -1100,13 +1100,13 @@ void CNPC_Barnacle::LiftRagdoll( float flBiteZOffset ) // Get the current bone matrix matrix3x4_t pBoneToWorld[MAXSTUDIOBONES]; - pAnimating->SetupBones( pBoneToWorld, BONE_USED_BY_ANYTHING ); + pAnimating->SetupBones( pAnimating->GetModelPtr(), pBoneToWorld, BONE_USED_BY_ANYTHING ); // Apply the forces to the ragdoll RagdollApplyAnimationAsVelocity( *(m_hRagdoll->GetRagdoll()), m_pRagdollBones, pBoneToWorld, 0.2 ); // Store off the current bone matrix for next time - pAnimating->SetupBones( m_pRagdollBones, BONE_USED_BY_ANYTHING ); + pAnimating->SetupBones( pAnimating->GetModelPtr(), m_pRagdollBones, BONE_USED_BY_ANYTHING ); } } } @@ -1540,7 +1540,7 @@ You can use this stanza to try to counterplace the constraint on the player's he UpdateTongue(); // Store off the current bone matrix so we have it next frame - pAnimating->SetupBones( m_pRagdollBones, BONE_USED_BY_ANYTHING ); + pAnimating->SetupBones( pAnimating->GetModelPtr(), m_pRagdollBones, BONE_USED_BY_ANYTHING ); } diff --git a/game/server/physics_prop_ragdoll.cpp b/game/server/physics_prop_ragdoll.cpp index 72635ea897..5e83ae57f3 100644 --- a/game/server/physics_prop_ragdoll.cpp +++ b/game/server/physics_prop_ragdoll.cpp @@ -174,7 +174,7 @@ void CRagdollProp::Spawn( void ) } matrix3x4_t pBoneToWorld[MAXSTUDIOBONES]; - BaseClass::SetupBones( pBoneToWorld, BONE_USED_BY_ANYTHING ); // FIXME: shouldn't this be a subset of the bones + BaseClass::SetupBones( GetModelPtr(), pBoneToWorld, BONE_USED_BY_ANYTHING ); // FIXME: shouldn't this be a subset of the bones // this is useless info after the initial conditions are set SetAbsAngles( vec3_angle ); int collisionGroup = (m_spawnflags & SF_RAGDOLLPROP_DEBRIS) ? COLLISION_GROUP_DEBRIS : COLLISION_GROUP_NONE; @@ -827,7 +827,7 @@ void CRagdollProp::SetupBones( matrix3x4_t *pBoneToWorld, int boneMask ) // no ragdoll, fall through to base class if ( !m_ragdoll.listCount ) { - BaseClass::SetupBones( pBoneToWorld, boneMask ); + BaseClass::SetupBones( GetModelPtr(), pBoneToWorld, boneMask ); return; } @@ -1338,10 +1338,10 @@ CBaseEntity *CreateServerRagdoll( CBaseAnimating *pAnimating, int forceBone, con float fPreviousCycle = clamp(pAnimating->GetCycle()-( dt * ( 1 / fSequenceDuration ) ),0.f,1.f); float fCurCycle = pAnimating->GetCycle(); // Get current bones positions - pAnimating->SetupBones( pBoneToWorldNext, BONE_USED_BY_ANYTHING ); + pAnimating->SetupBones( pAnimating->GetModelPtr(), pBoneToWorldNext, BONE_USED_BY_ANYTHING ); // Get previous bones positions pAnimating->SetCycle( fPreviousCycle ); - pAnimating->SetupBones( pBoneToWorld, BONE_USED_BY_ANYTHING ); + pAnimating->SetupBones( pAnimating->GetModelPtr(), pBoneToWorld, BONE_USED_BY_ANYTHING ); // Restore current cycle pAnimating->SetCycle( fCurCycle ); @@ -1579,7 +1579,7 @@ CRagdollProp *CreateServerRagdollAttached( CBaseAnimating *pAnimating, const Vec pRagdoll->InitRagdollAnimation(); matrix3x4_t pBoneToWorld[MAXSTUDIOBONES]; - pAnimating->SetupBones( pBoneToWorld, BONE_USED_BY_ANYTHING ); + pAnimating->SetupBones( pAnimating->GetModelPtr(), pBoneToWorld, BONE_USED_BY_ANYTHING ); pRagdoll->InitRagdollAttached( pAttached, vecForce, forceBone, pBoneToWorld, pBoneToWorld, 0.1, collisionGroup, pParentEntity, boneAttach, boneOrigin, parentBoneAttach, originAttached ); return pRagdoll; diff --git a/game/server/player_lagcompensation.cpp b/game/server/player_lagcompensation.cpp index 9d43980cc1..52d269bed0 100644 --- a/game/server/player_lagcompensation.cpp +++ b/game/server/player_lagcompensation.cpp @@ -32,7 +32,7 @@ ConVar sv_unlag( "sv_unlag", "1", FCVAR_DEVELOPMENTONLY, "Enables player lag compensation" ); ConVar sv_maxunlag( "sv_maxunlag", "1.0", FCVAR_DEVELOPMENTONLY, "Maximum lag compensation in seconds", true, 0.0f, true, 1.0f ); -ConVar sv_lagflushbonecache( "sv_lagflushbonecache", "1", FCVAR_DEVELOPMENTONLY, "Flushes entity bone cache on lag compensation" ); +ConVar sv_lagflushbonecache( "sv_lagflushbonecache", "0", FCVAR_DEVELOPMENTONLY, "Flushes entity bone cache on lag compensation" ); ConVar sv_unlag_fixstuck( "sv_unlag_fixstuck", "0", FCVAR_DEVELOPMENTONLY, "Disallow backtracking a player for lag compensation if it will cause them to become stuck" ); //----------------------------------------------------------------------------- diff --git a/game/server/server_base.vpc b/game/server/server_base.vpc index 6d78d55dc8..cfa14816be 100644 --- a/game/server/server_base.vpc +++ b/game/server/server_base.vpc @@ -78,6 +78,7 @@ $Project $Folder "Source Files" { + $File "$SRCDIR\game\shared\bone_merge_cache.cpp" $File "$SRCDIR\game\shared\achievement_saverestore.cpp" $File "$SRCDIR\game\shared\achievement_saverestore.h" $File "$SRCDIR\game\shared\achievementmgr.cpp" @@ -785,6 +786,7 @@ $Project $Folder "Header Files" { + $File "$SRCDIR\game\shared\bone_merge_cache.h" $File "$SRCDIR\public\mathlib\amd3dx.h" $File "$SRCDIR\game\shared\ammodef.h" $File "$SRCDIR\game\shared\base_playeranimstate.h" diff --git a/game/shared/basecombatweapon_shared.cpp b/game/shared/basecombatweapon_shared.cpp index 0b35d14700..bafbbaa938 100644 --- a/game/shared/basecombatweapon_shared.cpp +++ b/game/shared/basecombatweapon_shared.cpp @@ -15,6 +15,8 @@ // NVNT start extra includes #include "haptics/haptic_utils.h" +#include "studio.h" +#include "tier3/tier3.h" #ifdef CLIENT_DLL #include "prediction.h" #endif @@ -90,6 +92,7 @@ CBaseCombatWeapon::CBaseCombatWeapon() : BASECOMBATWEAPON_DERIVED_FROM() #if !defined( CLIENT_DLL ) m_pConstraint = NULL; OnBaseCombatWeaponCreated( this ); + m_pStudioWorldHdr = NULL; #endif m_hWeaponFileInfo = GetInvalidWeaponInfoHandle(); @@ -117,10 +120,76 @@ CBaseCombatWeapon::~CBaseCombatWeapon( void ) physenv->DestroyConstraint( m_pConstraint ); m_pConstraint = NULL; } - OnBaseCombatWeaponDestroyed( this ); + OnBaseCombatWeaponDestroyed(this); + delete m_pStudioWorldHdr; #endif } +#ifndef CLIENT_DLL +void CBaseCombatWeapon::LockStudioHdr() +{ + BaseClass::LockStudioHdr(); + + AUTO_LOCK( m_StudioHdrInitLock ); + const auto worldModel = modelinfo->GetModel(m_iWorldModelIndex); + if (worldModel) + { + MDLHandle_t hStudioHdr = modelinfo->GetCacheHandle( worldModel ); + if ( hStudioHdr != MDLHANDLE_INVALID ) + { + const studiohdr_t *pStudioHdr = mdlcache->LockStudioHdr( hStudioHdr ); + CStudioHdr *pStudioHdrContainer = NULL; + if ( !m_pStudioWorldHdr ) + { + if ( pStudioHdr ) + { + pStudioHdrContainer = new CStudioHdr; + pStudioHdrContainer->Init( pStudioHdr, mdlcache ); + } + } + else + { + pStudioHdrContainer = m_pStudioWorldHdr; + } + + Assert( ( pStudioHdr == NULL && pStudioHdrContainer == NULL ) || pStudioHdrContainer->GetRenderHdr() == pStudioHdr ); + + if ( pStudioHdrContainer && pStudioHdrContainer->GetVirtualModel() ) + { + MDLHandle_t hVirtualModel = VoidPtrToMDLHandle( pStudioHdrContainer->GetRenderHdr()->VirtualModel() ); + mdlcache->LockStudioHdr( hVirtualModel ); + } + m_pStudioWorldHdr = pStudioHdrContainer; // must be last to ensure virtual model correctly set up + } + } +} + +void CBaseCombatWeapon::UnlockStudioHdr() +{ + BaseClass::UnlockStudioHdr(); + + if ( m_pStudioWorldHdr ) + { + const auto worldModel = modelinfo->GetModel(m_iWorldModelIndex); + if (worldModel) + { + mdlcache->UnlockStudioHdr( modelinfo->GetCacheHandle( worldModel ) ); + if ( m_pStudioWorldHdr->GetVirtualModel() ) + { + MDLHandle_t hVirtualModel = VoidPtrToMDLHandle( m_pStudioWorldHdr->GetRenderHdr()->VirtualModel() ); + mdlcache->UnlockStudioHdr( hVirtualModel ); + } + } + } +} + +void CBaseCombatWeapon::SetupBones(CStudioHdr* pStudioHdr, matrix3x4_t* pBoneToWorld, int boneMask) +{ + // hooked m_pStudioHdr to world model instead (m_pStudioWorldHdr) + BaseClass::SetupBones(m_pStudioWorldHdr, pBoneToWorld, boneMask); +} +#endif + void CBaseCombatWeapon::Activate( void ) { BaseClass::Activate(); diff --git a/game/shared/basecombatweapon_shared.h b/game/shared/basecombatweapon_shared.h index 701403a07f..3dc95ea97a 100644 --- a/game/shared/basecombatweapon_shared.h +++ b/game/shared/basecombatweapon_shared.h @@ -6,6 +6,7 @@ #ifndef COMBATWEAPON_SHARED_H #define COMBATWEAPON_SHARED_H +#include "studio.h" #ifdef _WIN32 #pragma once #endif @@ -162,7 +163,11 @@ public: CBaseCombatWeapon(); virtual ~CBaseCombatWeapon(); - +#ifndef CLIENT_DLL + virtual void LockStudioHdr(); + virtual void UnlockStudioHdr(); + virtual void SetupBones( CStudioHdr* pStudioHdr, matrix3x4_t *pBoneToWorld, int boneMask ); +#endif virtual bool IsBaseCombatWeapon( void ) const { return true; } virtual CBaseCombatWeapon *MyCombatWeaponPointer( void ) { return this; } @@ -612,9 +617,9 @@ private: bool m_bReloadHudHintDisplayed; // Have we displayed a reload HUD hint since this weapon was deployed? float m_flHudHintPollTime; // When to poll the weapon again for whether it should display a hud hint. float m_flHudHintMinDisplayTime; // if the hint is squelched before this, reset my counter so we'll display it again. - // Server only #if !defined( CLIENT_DLL ) + CStudioHdr *m_pStudioWorldHdr; // Outputs protected: diff --git a/game/client/bone_merge_cache.cpp b/game/shared/bone_merge_cache.cpp similarity index 72% rename from game/client/bone_merge_cache.cpp rename to game/shared/bone_merge_cache.cpp index 6ef767eadc..1138604b6b 100644 --- a/game/client/bone_merge_cache.cpp +++ b/game/shared/bone_merge_cache.cpp @@ -11,6 +11,8 @@ #include "bone_setup.h" // memdbgon must be the last include file in a .cpp file!!! +#include "mathlib/mathlib.h" +#include "studio.h" #include "tier0/memdbgon.h" //----------------------------------------------------------------------------- @@ -27,7 +29,7 @@ CBoneMergeCache::CBoneMergeCache() m_nFollowBoneSetupMask = 0; } -void CBoneMergeCache::Init( C_BaseAnimating *pOwner ) +void CBoneMergeCache::Init( CBaseAnimating *pOwner ) { m_pOwner = pOwner; m_pFollow = NULL; @@ -40,7 +42,7 @@ void CBoneMergeCache::Init( C_BaseAnimating *pOwner ) void CBoneMergeCache::UpdateCache() { CStudioHdr *pOwnerHdr = m_pOwner ? m_pOwner->GetModelPtr() : NULL; - if ( !pOwnerHdr ) + if ( !pOwnerHdr || !m_pOwner->GetFollowedEntity()) { if ( m_pOwnerHdr ) { @@ -56,7 +58,11 @@ void CBoneMergeCache::UpdateCache() return; } - C_BaseAnimating *pTestFollow = m_pOwner->FindFollowedEntity(); +#ifdef CLIENT_DLL + C_BaseAnimating* pTestFollow = m_pOwner->FindFollowedEntity(); +#else + CBaseAnimating* pTestFollow = dynamic_cast(m_pOwner->GetFollowedEntity()); +#endif CStudioHdr *pTestHdr = (pTestFollow ? pTestFollow->GetModelPtr() : NULL); const studiohdr_t *pTestStudioHDR = (pTestHdr ? pTestHdr->GetRenderHdr() : NULL); if ( pTestFollow != m_pFollow || pTestHdr != m_pFollowHdr || pTestStudioHDR != m_pFollowRenderHdr || pOwnerHdr != m_pOwnerHdr ) @@ -83,7 +89,9 @@ void CBoneMergeCache::UpdateCache() int parentBoneIndex = Studio_BoneIndexByName( m_pFollowHdr, pOwnerBones[i].pszName() ); if ( parentBoneIndex < 0 ) continue; - +#ifdef CLIENT_DLL + printf("bone attach: (%i - %i) (%s - %s) (%s - %s)\n", m_pFollow->entindex(), m_pOwner->entindex(), m_pFollow->GetDebugName(), m_pOwner->GetDebugName(), m_pFollow->GetModelName(), m_pOwner->GetModelName()); +#endif // Add a merged bone here. CMergedBone mergedBone; mergedBone.m_iMyBone = i; @@ -122,7 +130,7 @@ void CBoneMergeCache::UpdateCache() ConVar r_captain_canteen_is_angry ( "r_captain_canteen_is_angry", "1" ); #endif -void CBoneMergeCache::MergeMatchingBones( int boneMask ) +void CBoneMergeCache::MergeMatchingBones( int boneMask , matrix3x4_t mergedbones[MAXSTUDIOBONES] ) { UpdateCache(); @@ -130,55 +138,29 @@ void CBoneMergeCache::MergeMatchingBones( int boneMask ) if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 ) return; - // Have the entity we're following setup its bones. - bool bWorked = m_pFollow->SetupBones( NULL, -1, m_nFollowBoneSetupMask, gpGlobals->curtime ); - // We suspect there's some cases where SetupBones couldn't do its thing, and then this causes Captain Canteen. - Assert ( bWorked ); - if ( !bWorked ) - { - // Usually this means your parent is invisible or gone or whatever. - // This routine has no way to tell its caller not to draw itself unfortunately. - // But we can shrink all the bones down to zero size. - // But it might still spawn particle systems? :-( - matrix3x4_t NewBone; - MatrixScaleByZero ( NewBone ); - MatrixSetTranslation ( Vector ( 0.0f, 0.0f, 0.0f ), NewBone ); -#ifdef STAGING_ONLY - if ( r_captain_canteen_is_angry.GetBool() ) - { - // We actually want to see when Captain Canteen happened, and make it really obvious that (a) he was here and (b) this code would have fixed him. - float HowAngry = 20.0f; // Leon's getting larger! - MatrixSetColumn ( Vector ( HowAngry, 0.0f, 0.0f ), 0, NewBone ); - MatrixSetColumn ( Vector ( 0.0f, HowAngry, 0.0f ), 1, NewBone ); - MatrixSetColumn ( Vector ( 0.0f, 0.0f, HowAngry ), 2, NewBone ); - } + matrix3x4_t bones[MAXSTUDIOBONES]; + // Have the entity we're following setup its bones. +#ifdef CLIENT_DLL + m_pFollow->SetupBones(bones, MAXSTUDIOBONES, m_nFollowBoneSetupMask, gpGlobals->curtime); +#else + m_pFollow->SetupBones(m_pFollow->GetModelPtr(), bones, m_nFollowBoneSetupMask); #endif - for ( int i=0; i < m_MergedBones.Count(); i++ ) - { - int iOwnerBone = m_MergedBones[i].m_iMyBone; - - // Only update bones reference by the bone mask. - if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) ) - continue; - - m_pOwner->GetBoneForWrite( iOwnerBone ) = NewBone; - } - } - else + // Now copy the bone matrices. + for ( int i=0; i < m_MergedBones.Count(); i++ ) { - // Now copy the bone matrices. - for ( int i=0; i < m_MergedBones.Count(); i++ ) - { - int iOwnerBone = m_MergedBones[i].m_iMyBone; - int iParentBone = m_MergedBones[i].m_iParentBone; + int iOwnerBone = m_MergedBones[i].m_iMyBone; + int iParentBone = m_MergedBones[i].m_iParentBone; + + // Only update bones reference by the bone mask. + if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) ) + continue; - // Only update bones reference by the bone mask. - if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) ) - continue; - - MatrixCopy( m_pFollow->GetBone( iParentBone ), m_pOwner->GetBoneForWrite( iOwnerBone ) ); - } +#ifdef CLIENT_DLL + MatrixCopy( bones[ iParentBone ], mergedbones[ iOwnerBone ] ); +#else + MatrixCopy( bones[ iParentBone ], mergedbones[ iOwnerBone ] ); +#endif } } @@ -255,8 +237,14 @@ bool CBoneMergeCache::GetAimEntOrigin( Vector *pAbsOrigin, QAngle *pAbsAngles ) // all over the place, then this won't get the right results. // Get mFollowBone. - m_pFollow->SetupBones( NULL, -1, m_nFollowBoneSetupMask, gpGlobals->curtime ); - const matrix3x4_t &mFollowBone = m_pFollow->GetBone( m_MergedBones[0].m_iParentBone ); + matrix3x4_t bones[MAXSTUDIOBONES]; + // Have the entity we're following setup its bones. +#ifdef CLIENT_DLL + m_pFollow->SetupBones(bones, MAXSTUDIOBONES, m_nFollowBoneSetupMask, gpGlobals->curtime); +#else + m_pFollow->SetupBones(m_pFollow->GetModelPtr(), bones, m_nFollowBoneSetupMask); +#endif + const matrix3x4_t &mFollowBone = bones[ m_MergedBones[0].m_iParentBone ]; // Get Inverse( mBoneLocal ) matrix3x4_t mBoneLocal, mBoneLocalInv; @@ -280,8 +268,14 @@ bool CBoneMergeCache::GetRootBone( matrix3x4_t &rootBone ) return false; // Get mFollowBone. - m_pFollow->SetupBones( NULL, -1, m_nFollowBoneSetupMask, gpGlobals->curtime ); - rootBone = m_pFollow->GetBone( m_MergedBones[0].m_iParentBone ); + matrix3x4_t bones[MAXSTUDIOBONES]; + // Have the entity we're following setup its bones. +#ifdef CLIENT_DLL + m_pFollow->SetupBones(bones, MAXSTUDIOBONES, m_nFollowBoneSetupMask, gpGlobals->curtime); +#else + m_pFollow->SetupBones(m_pFollow->GetModelPtr(), bones, m_nFollowBoneSetupMask); +#endif + rootBone = bones[ m_MergedBones[0].m_iParentBone ]; return true; } diff --git a/game/client/bone_merge_cache.h b/game/shared/bone_merge_cache.h similarity index 85% rename from game/client/bone_merge_cache.h rename to game/shared/bone_merge_cache.h index 6123c9b4a8..16f47e941b 100644 --- a/game/client/bone_merge_cache.h +++ b/game/shared/bone_merge_cache.h @@ -6,12 +6,21 @@ #ifndef BONE_MERGE_CACHE_H #define BONE_MERGE_CACHE_H +#include "mathlib/mathlib.h" +#include "studio.h" #ifdef _WIN32 #pragma once #endif - +#ifdef CLIENT_DLL class C_BaseAnimating; +#ifndef CBaseAnimating +#define CBaseAnimating C_BaseAnimating +#endif +#else +class CBaseAnimating; +#endif + class CStudioHdr; @@ -24,14 +33,14 @@ public: CBoneMergeCache(); - void Init( C_BaseAnimating *pOwner ); + void Init( CBaseAnimating *pOwner ); // Updates the lookups that let it merge bones quickly. void UpdateCache(); // This copies the transform from all bones in the followed entity that have // names that match our bones. - void MergeMatchingBones( int boneMask ); + void MergeMatchingBones( int boneMask, matrix3x4_t mergedbones[MAXSTUDIOBONES] ); // copy bones instead of matrices void CopyParentToChild( const Vector parentPos[], const Quaternion parentQ[], Vector childPos[], Quaternion childQ[], int boneMask ); @@ -48,11 +57,11 @@ public: private: // This is the entity that we're keeping the cache updated for. - C_BaseAnimating *m_pOwner; + CBaseAnimating *m_pOwner; // All the cache data is based off these. When they change, the cache data is regenerated. // These are either all valid pointers or all NULL. - C_BaseAnimating *m_pFollow; + CBaseAnimating *m_pFollow; CStudioHdr *m_pFollowHdr; const studiohdr_t *m_pFollowRenderHdr; CStudioHdr *m_pOwnerHdr; diff --git a/public/bone_setup.h b/public/bone_setup.h index dbe50db93d..39a23eb116 100644 --- a/public/bone_setup.h +++ b/public/bone_setup.h @@ -419,7 +419,7 @@ public: float m_timeValid; int m_boneMask; -private: +public: matrix3x4_t *BoneArray(); short *StudioToCached(); short *CachedToStudio();