Added bone merge; still a lot to fix

This commit is contained in:
Kamay Xutax 2024-08-21 05:04:20 +02:00
parent 9b270322f7
commit 95146c3867
18 changed files with 333 additions and 434 deletions

View file

@ -12,6 +12,7 @@
#include "convar.h" #include "convar.h"
#include "iconvar.h" #include "iconvar.h"
#include "interpolatedvar.h" #include "interpolatedvar.h"
#include "mathlib/mathlib.h"
#include "model_types.h" #include "model_types.h"
#include "bone_setup.h" #include "bone_setup.h"
#include "ivrenderview.h" #include "ivrenderview.h"
@ -1498,7 +1499,7 @@ void C_BaseAnimating::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quater
m_pBoneMergeCache = new CBoneMergeCache; m_pBoneMergeCache = new CBoneMergeCache;
m_pBoneMergeCache->Init( this ); m_pBoneMergeCache->Init( this );
} }
m_pBoneMergeCache->MergeMatchingBones( boneMask ); m_pBoneMergeCache->MergeMatchingBones( boneMask, m_BoneAccessor.GetBoneArrayForWrite() );
} }
else else
{ {
@ -2743,82 +2744,6 @@ void C_BaseAnimating::ThreadedBoneSetup()
g_PreviousBoneSetups.RemoveAll(); 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 ) bool C_BaseAnimating::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime )
{ {
VPROF_BUDGET( "C_BaseAnimating::SetupBones", VPROF_BUDGETGROUP_CLIENT_ANIMATION ); VPROF_BUDGET( "C_BaseAnimating::SetupBones", VPROF_BUDGETGROUP_CLIENT_ANIMATION );

View file

@ -144,11 +144,6 @@ public:
virtual int VPhysicsGetObjectList( IPhysicsObject **pList, int listMax ); virtual int VPhysicsGetObjectList( IPhysicsObject **pList, int listMax );
// model specific // 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 bool SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime );
virtual void UpdateIKLocks( float currentTime ); virtual void UpdateIKLocks( float currentTime );
virtual void CalculateIKLocks( float currentTime ); virtual void CalculateIKLocks( float currentTime );

View file

@ -370,66 +370,3 @@ CStudioHdr *C_BaseAnimatingOverlay::OnNewModel()
return hdr; 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 );
}

View file

@ -38,8 +38,6 @@ public:
// model specific // model specific
virtual void AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime ); virtual void AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime );
virtual void DoAnimationEvents( CStudioHdr *pStudioHdr ); virtual void DoAnimationEvents( CStudioHdr *pStudioHdr );
virtual void GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], int boneMask, float currentTime );
enum enum
{ {
MAX_OVERLAYS = 15, MAX_OVERLAYS = 15,

View file

@ -204,7 +204,7 @@ $Project
$File "beamdraw.cpp" $File "beamdraw.cpp"
$File "$SRCDIR\game\shared\beam_shared.cpp" $File "$SRCDIR\game\shared\beam_shared.cpp"
$File "$SRCDIR\public\bone_accessor.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_basehumanoid.cpp"
$File "c_ai_basenpc.cpp" $File "c_ai_basenpc.cpp"
$File "c_baseanimating.cpp" $File "c_baseanimating.cpp"
@ -674,7 +674,7 @@ $Project
$File "baseanimatedtextureproxy.h" $File "baseanimatedtextureproxy.h"
$File "baseclientrendertargets.h" $File "baseclientrendertargets.h"
$File "beamdraw.h" $File "beamdraw.h"
$File "bone_merge_cache.h" $File "$SRCDIR\game\shared\bone_merge_cache.h"
$File "c_ai_basenpc.h" $File "c_ai_basenpc.h"
$File "c_baseanimating.h" $File "c_baseanimating.h"
$File "c_baseanimatingoverlay.h" $File "c_baseanimatingoverlay.h"

View file

@ -2598,103 +2598,12 @@ float C_CSPlayer::GetDeathCamInterpolationTime()
return spec_freeze_time.GetFloat(); return spec_freeze_time.GetFloat();
else else
return CS_DEATH_ANIMATION_TIME; 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 ) 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 );
}
} }
//============================================================================= //=============================================================================

View file

@ -447,7 +447,12 @@ void CBaseAnimatingOverlay::GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Q
return; 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.InitPose( pos, q );
boneSetup.AccumulatePose( pos, q, GetSequence(), GetCycle(), 1.0, gpGlobals->curtime, m_pIk ); boneSetup.AccumulatePose( pos, q, GetSequence(), GetCycle(), 1.0, gpGlobals->curtime, m_pIk );
@ -487,11 +492,11 @@ void CBaseAnimatingOverlay::GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Q
{ {
boneSetup.CalcAutoplaySequences( pos, q, gpGlobals->curtime, NULL ); 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 // Purpose: zero's out all non-restore safe fields
// Output : // Output :

View file

@ -14,6 +14,8 @@
#include "enginecallback.h" #include "enginecallback.h"
#include "entitylist_base.h" #include "entitylist_base.h"
#include "mathlib/vector.h" #include "mathlib/vector.h"
#include "mathlib/vmatrix.h"
#include "player.h"
#include "shareddefs.h" #include "shareddefs.h"
#include "studio.h" #include "studio.h"
#include "bone_setup.h" #include "bone_setup.h"
@ -289,6 +291,8 @@ CBaseAnimating::CBaseAnimating()
m_fadeMaxDist = 0; m_fadeMaxDist = 0;
m_flFadeScale = 0.0f; m_flFadeScale = 0.0f;
m_fBoneCacheFlags = 0; m_fBoneCacheFlags = 0;
m_pBoneMergeCache = NULL;
m_pBoneCache = NULL;
} }
CBaseAnimating::~CBaseAnimating() 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 // Purpose: build matrices first from the parent, then from the passed in arrays if the bone doesn't exist on the parent
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -1704,33 +1734,45 @@ void CBaseAnimating::BuildMatricesWithBoneMerge(
const Vector pos[MAXSTUDIOBONES], const Vector pos[MAXSTUDIOBONES],
const Quaternion q[MAXSTUDIOBONES], const Quaternion q[MAXSTUDIOBONES],
matrix3x4_t bonetoworld[MAXSTUDIOBONES], matrix3x4_t bonetoworld[MAXSTUDIOBONES],
CBaseAnimating *pParent, int boneMask
CBoneCache *pParentCache
) )
{ {
CStudioHdr *fhdr = pParent->GetModelPtr();
mstudiobone_t *pbones = pStudioHdr->pBone( 0 ); mstudiobone_t *pbones = pStudioHdr->pBone( 0 );
matrix3x4_t rotationmatrix; // model to world transformation matrix3x4_t rotationmatrix; // model to world transformation
AngleMatrix( angles, origin, rotationmatrix); 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. if ( boneMerge )
bool merged = false;
int parentBoneIndex = Studio_BoneIndexByName( fhdr, pbones[i].pszName() );
if ( parentBoneIndex >= 0 )
{ {
matrix3x4_t *pMat = pParentCache->GetCachedBone( parentBoneIndex ); if ( !m_pBoneMergeCache )
if ( pMat )
{ {
MatrixCopy( *pMat, bonetoworld[ i ] ); m_pBoneMergeCache = new CBoneMergeCache;
merged = true; m_pBoneMergeCache->Init( this );
}
m_pBoneMergeCache->MergeMatchingBones( boneMask, bonetoworld );
}
else
{
delete m_pBoneMergeCache;
m_pBoneMergeCache = NULL;
} }
} }
if ( !merged ) for ( int i=0; i < pStudioHdr->numbones(); i++ )
{ {
if (!(pStudioHdr->boneFlags(i) & boneMask))
{
continue;
}
if (m_pBoneMergeCache && m_pBoneMergeCache->IsBoneMerged(i))
{
continue;
}
// If we get down here, then the bone wasn't merged. // If we get down here, then the bone wasn't merged.
matrix3x4_t bonematrix; matrix3x4_t bonematrix;
QuaternionMatrix( q[i], pos[i], bonematrix ); QuaternionMatrix( q[i], pos[i], bonematrix );
@ -1744,7 +1786,6 @@ void CBaseAnimating::BuildMatricesWithBoneMerge(
ConcatTransforms (bonetoworld[pbones[i].parent], bonematrix, bonetoworld[i]); ConcatTransforms (bonetoworld[pbones[i].parent], bonematrix, bonetoworld[i]);
} }
} }
}
} }
ConVar sv_pvsskipanimation( "sv_pvsskipanimation", "0", FCVAR_ARCHIVE, "Skips SetupBones when npc's are outside the PVS" ); ConVar sv_pvsskipanimation( "sv_pvsskipanimation", "0", FCVAR_ARCHIVE, "Skips SetupBones when npc's are outside the PVS" );
@ -1772,17 +1813,49 @@ 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 ); AUTO_LOCK( m_BoneSetupMutex );
VPROF_BUDGET( "CBaseAnimating::SetupBones", VPROF_BUDGETGROUP_SERVER_ANIM ); VPROF_BUDGET( "CBaseAnimating::SetupBones", VPROF_BUDGETGROUP_SERVER_ANIM );
MDLCACHE_CRITICAL_SECTION(); 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) if(!pStudioHdr)
{ {
@ -1797,8 +1870,8 @@ void CBaseAnimating::SetupBones( matrix3x4_t *pBoneToWorld, int boneMask )
Vector pos[MAXSTUDIOBONES]; Vector pos[MAXSTUDIOBONES];
Quaternion q[MAXSTUDIOBONES]; Quaternion q[MAXSTUDIOBONES];
// adjust hit boxes based on IK driven offset // Remove IK to respect more the client hitboxes.
Vector adjOrigin = GetAbsOrigin() + Vector( 0, 0, m_flEstIkOffset ); Vector adjOrigin = GetAbsOrigin();
if ( CanSkipAnimation() ) if ( CanSkipAnimation() )
{ {
@ -1827,47 +1900,14 @@ void CBaseAnimating::SetupBones( matrix3x4_t *pBoneToWorld, int boneMask )
} }
} }
CBaseAnimating *pParent = dynamic_cast< CBaseAnimating* >( GetMoveParent() ); BuildMatricesWithBoneMerge(pStudioHdr, GetAbsAngles(), adjOrigin, pos, q, pBoneToWorld, boneMask);
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 ); m_pBoneCache->UpdateBones(pBoneToWorld, pStudioHdr->numbones(), gpGlobals->curtime);
if (ai_setupbones_debug.GetBool())
{
DrawRawSkeleton( pBoneToWorld, boneMask, true, 0.11 );
}
return;
}
}
Studio_BuildMatrices(
pStudioHdr,
GetAbsAngles(),
adjOrigin,
pos,
q,
-1,
GetModelScale(), // Scaling
pBoneToWorld,
boneMask );
if (ai_setupbones_debug.GetBool()) if (ai_setupbones_debug.GetBool())
{ {
// Msg("%s:%s:%s (%x)\n", GetClassname(), GetDebugName(), STRING(GetModelName()), boneMask ); // 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 ); RemoveEFlags( EFL_SETTING_UP_BONES );
} }
@ -2588,51 +2628,33 @@ CBoneCache *CBaseAnimating::GetBoneCache( void )
CStudioHdr *pStudioHdr = GetModelPtr( ); CStudioHdr *pStudioHdr = GetModelPtr( );
Assert(pStudioHdr); Assert(pStudioHdr);
CBoneCache *pcache = Studio_GetBoneCache( m_boneCacheHandle ); int boneMask = BONE_USED_BY_HITBOX | BONE_USED_BY_ATTACHMENT | BONE_USED_BY_BONE_MERGE;
int boneMask = BONE_USED_BY_HITBOX | BONE_USED_BY_ATTACHMENT;
// TF queries these bones to position weapons when players are killed // TF queries these bones to position weapons when players are killed
#if defined( TF_DLL ) #if defined( TF_DLL )
boneMask |= BONE_USED_BY_BONE_MERGE; boneMask |= BONE_USED_BY_BONE_MERGE;
#endif #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]; matrix3x4_t bonetoworld[MAXSTUDIOBONES];
SetupBones( bonetoworld, boneMask ); SetupBones( GetModelPtr(), bonetoworld, boneMask );
if ( pcache ) for (auto pChild = FirstMoveChild(); pChild; pChild = pChild->NextMovePeer())
{ {
// still in memory but out of date, refresh the bones. auto pChildAnimating = dynamic_cast<CBaseAnimating*>(pChild);
pcache->UpdateBones( bonetoworld, pStudioHdr->numbones(), gpGlobals->curtime );
}
else
{
bonecacheparams_t params;
params.pStudioHdr = pStudioHdr;
params.pBoneToWorld = bonetoworld;
params.curtime = gpGlobals->curtime;
params.boneMask = boneMask;
m_boneCacheHandle = Studio_CreateBoneCache( params ); if (!pChildAnimating || !pChildAnimating->GetModelPtr())
pcache = Studio_GetBoneCache( m_boneCacheHandle ); {
continue;
} }
Assert(pcache);
return pcache; 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; 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.InitPose( pos, q );
boneSetup.AccumulatePose( pos, q, GetSequence(), GetCycle(), 1.0, gpGlobals->curtime, m_pIk ); 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.CalcAutoplaySequences( pos, q, gpGlobals->curtime, NULL );
} }
boneSetup.CalcBoneAdj( pos, q, GetEncodedControllerArray() ); GetEncodedControllers( pStudioHdr, flEncodedParams );
boneSetup.CalcBoneAdj( pos, q, flEncodedParams );
} }
int CBaseAnimating::DrawDebugTextOverlays(void) int CBaseAnimating::DrawDebugTextOverlays(void)
@ -3069,6 +3097,12 @@ void CBaseAnimating::DrawRawSkeleton( matrix3x4_t boneToWorld[], int boneMask, b
int g = 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++) for (i = 0; i < pStudioHdr->numbones(); i++)
{ {
@ -3080,6 +3114,14 @@ void CBaseAnimating::DrawRawSkeleton( matrix3x4_t boneToWorld[], int boneMask, b
{ {
Vector p2; Vector p2;
MatrixPosition( boneToWorld[pStudioHdr->pBone( i )->parent], 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 ); NDebugOverlay::Line( p1, p2, r, g, b, noDepthTest, duration );
} }
} }
@ -3605,6 +3647,12 @@ CStudioHdr *CBaseAnimating::OnNewModel()
{ {
(void) BaseClass::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? // TODO: if dynamic, validate m_Sequence and apply queued body group settings?
if ( IsDynamicModelLoading() ) if ( IsDynamicModelLoading() )
{ {

View file

@ -18,6 +18,7 @@
#include "studio.h" #include "studio.h"
#include "datacache/idatacache.h" #include "datacache/idatacache.h"
#include "tier0/threadtools.h" #include "tier0/threadtools.h"
#include "bone_merge_cache.h"
class CBasePlayer; class CBasePlayer;
struct animevent_t; struct animevent_t;
@ -136,7 +137,7 @@ public:
virtual void GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], int boneMask ); virtual void GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], int boneMask );
virtual void GetBoneTransform( int iBone, matrix3x4_t &pBoneToWorld ); 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 CalculateIKLocks( float currentTime );
virtual void Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity ); 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, const char *szName );
bool HasPoseParameter( int iSequence, int iParameter ); bool HasPoseParameter( int iSequence, int iParameter );
float EdgeLimitPoseParameter( int iParameter, float flValue, float flBase = 0.0f ); 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: protected:
// The modus operandi for pose parameters is that you should not use the const char * version of the functions // 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 // 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, void BuildMatricesWithBoneMerge( const CStudioHdr *pStudioHdr, const QAngle& angles,
const Vector& origin, const Vector pos[MAXSTUDIOBONES], const Vector& origin, const Vector pos[MAXSTUDIOBONES],
const Quaternion q[MAXSTUDIOBONES], matrix3x4_t bonetoworld[MAXSTUDIOBONES], const Quaternion q[MAXSTUDIOBONES], matrix3x4_t bonetoworld[MAXSTUDIOBONES], int boneMask );
CBaseAnimating *pParent, CBoneCache *pParentCache );
void SetFadeDistance( float minFadeDist, float maxFadeDist ); void SetFadeDistance( float minFadeDist, float maxFadeDist );
@ -336,10 +337,10 @@ public:
inline void ClearBoneCacheFlags( unsigned short fFlag ) { m_fBoneCacheFlags &= ~fFlag; } inline void ClearBoneCacheFlags( unsigned short fFlag ) { m_fBoneCacheFlags &= ~fFlag; }
bool PrefetchSequence( int iSequence ); bool PrefetchSequence( int iSequence );
virtual void LockStudioHdr();
virtual void UnlockStudioHdr();
private: private:
void LockStudioHdr();
void UnlockStudioHdr();
void StudioFrameAdvanceInternal( CStudioHdr *pStudioHdr, float flInterval ); void StudioFrameAdvanceInternal( CStudioHdr *pStudioHdr, float flInterval );
void InputSetLightingOriginRelative( inputdata_t &inputdata ); void InputSetLightingOriginRelative( inputdata_t &inputdata );
@ -422,10 +423,12 @@ protected:
public: public:
COutputEvent m_OnIgnite; COutputEvent m_OnIgnite;
private: public:
CStudioHdr *m_pStudioHdr; CStudioHdr *m_pStudioHdr;
CThreadFastMutex m_StudioHdrInitLock; CThreadFastMutex m_StudioHdrInitLock;
CThreadFastMutex m_BoneSetupMutex; CThreadFastMutex m_BoneSetupMutex;
CBoneCache *m_pBoneCache;
CBoneMergeCache *m_pBoneMergeCache;
// FIXME: necessary so that cyclers can hack m_bSequenceFinished // FIXME: necessary so that cyclers can hack m_bSequenceFinished
friend class CFlexCycler; friend class CFlexCycler;

View file

@ -1100,13 +1100,13 @@ void CNPC_Barnacle::LiftRagdoll( float flBiteZOffset )
// Get the current bone matrix // Get the current bone matrix
matrix3x4_t pBoneToWorld[MAXSTUDIOBONES]; 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 // Apply the forces to the ragdoll
RagdollApplyAnimationAsVelocity( *(m_hRagdoll->GetRagdoll()), m_pRagdollBones, pBoneToWorld, 0.2 ); RagdollApplyAnimationAsVelocity( *(m_hRagdoll->GetRagdoll()), m_pRagdollBones, pBoneToWorld, 0.2 );
// Store off the current bone matrix for next time // 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(); UpdateTongue();
// Store off the current bone matrix so we have it next frame // 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 );
} }

View file

@ -174,7 +174,7 @@ void CRagdollProp::Spawn( void )
} }
matrix3x4_t pBoneToWorld[MAXSTUDIOBONES]; 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 // this is useless info after the initial conditions are set
SetAbsAngles( vec3_angle ); SetAbsAngles( vec3_angle );
int collisionGroup = (m_spawnflags & SF_RAGDOLLPROP_DEBRIS) ? COLLISION_GROUP_DEBRIS : COLLISION_GROUP_NONE; 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 // no ragdoll, fall through to base class
if ( !m_ragdoll.listCount ) if ( !m_ragdoll.listCount )
{ {
BaseClass::SetupBones( pBoneToWorld, boneMask ); BaseClass::SetupBones( GetModelPtr(), pBoneToWorld, boneMask );
return; 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 fPreviousCycle = clamp(pAnimating->GetCycle()-( dt * ( 1 / fSequenceDuration ) ),0.f,1.f);
float fCurCycle = pAnimating->GetCycle(); float fCurCycle = pAnimating->GetCycle();
// Get current bones positions // Get current bones positions
pAnimating->SetupBones( pBoneToWorldNext, BONE_USED_BY_ANYTHING ); pAnimating->SetupBones( pAnimating->GetModelPtr(), pBoneToWorldNext, BONE_USED_BY_ANYTHING );
// Get previous bones positions // Get previous bones positions
pAnimating->SetCycle( fPreviousCycle ); pAnimating->SetCycle( fPreviousCycle );
pAnimating->SetupBones( pBoneToWorld, BONE_USED_BY_ANYTHING ); pAnimating->SetupBones( pAnimating->GetModelPtr(), pBoneToWorld, BONE_USED_BY_ANYTHING );
// Restore current cycle // Restore current cycle
pAnimating->SetCycle( fCurCycle ); pAnimating->SetCycle( fCurCycle );
@ -1579,7 +1579,7 @@ CRagdollProp *CreateServerRagdollAttached( CBaseAnimating *pAnimating, const Vec
pRagdoll->InitRagdollAnimation(); pRagdoll->InitRagdollAnimation();
matrix3x4_t pBoneToWorld[MAXSTUDIOBONES]; 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 ); pRagdoll->InitRagdollAttached( pAttached, vecForce, forceBone, pBoneToWorld, pBoneToWorld, 0.1, collisionGroup, pParentEntity, boneAttach, boneOrigin, parentBoneAttach, originAttached );
return pRagdoll; return pRagdoll;

View file

@ -32,7 +32,7 @@
ConVar sv_unlag( "sv_unlag", "1", FCVAR_DEVELOPMENTONLY, "Enables player lag compensation" ); 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_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" ); 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" );
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View file

@ -78,6 +78,7 @@ $Project
$Folder "Source Files" $Folder "Source Files"
{ {
$File "$SRCDIR\game\shared\bone_merge_cache.cpp"
$File "$SRCDIR\game\shared\achievement_saverestore.cpp" $File "$SRCDIR\game\shared\achievement_saverestore.cpp"
$File "$SRCDIR\game\shared\achievement_saverestore.h" $File "$SRCDIR\game\shared\achievement_saverestore.h"
$File "$SRCDIR\game\shared\achievementmgr.cpp" $File "$SRCDIR\game\shared\achievementmgr.cpp"
@ -785,6 +786,7 @@ $Project
$Folder "Header Files" $Folder "Header Files"
{ {
$File "$SRCDIR\game\shared\bone_merge_cache.h"
$File "$SRCDIR\public\mathlib\amd3dx.h" $File "$SRCDIR\public\mathlib\amd3dx.h"
$File "$SRCDIR\game\shared\ammodef.h" $File "$SRCDIR\game\shared\ammodef.h"
$File "$SRCDIR\game\shared\base_playeranimstate.h" $File "$SRCDIR\game\shared\base_playeranimstate.h"

View file

@ -15,6 +15,8 @@
// NVNT start extra includes // NVNT start extra includes
#include "haptics/haptic_utils.h" #include "haptics/haptic_utils.h"
#include "studio.h"
#include "tier3/tier3.h"
#ifdef CLIENT_DLL #ifdef CLIENT_DLL
#include "prediction.h" #include "prediction.h"
#endif #endif
@ -90,6 +92,7 @@ CBaseCombatWeapon::CBaseCombatWeapon() : BASECOMBATWEAPON_DERIVED_FROM()
#if !defined( CLIENT_DLL ) #if !defined( CLIENT_DLL )
m_pConstraint = NULL; m_pConstraint = NULL;
OnBaseCombatWeaponCreated( this ); OnBaseCombatWeaponCreated( this );
m_pStudioWorldHdr = NULL;
#endif #endif
m_hWeaponFileInfo = GetInvalidWeaponInfoHandle(); m_hWeaponFileInfo = GetInvalidWeaponInfoHandle();
@ -117,10 +120,76 @@ CBaseCombatWeapon::~CBaseCombatWeapon( void )
physenv->DestroyConstraint( m_pConstraint ); physenv->DestroyConstraint( m_pConstraint );
m_pConstraint = NULL; m_pConstraint = NULL;
} }
OnBaseCombatWeaponDestroyed( this ); OnBaseCombatWeaponDestroyed(this);
delete m_pStudioWorldHdr;
#endif #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 ) void CBaseCombatWeapon::Activate( void )
{ {
BaseClass::Activate(); BaseClass::Activate();

View file

@ -6,6 +6,7 @@
#ifndef COMBATWEAPON_SHARED_H #ifndef COMBATWEAPON_SHARED_H
#define COMBATWEAPON_SHARED_H #define COMBATWEAPON_SHARED_H
#include "studio.h"
#ifdef _WIN32 #ifdef _WIN32
#pragma once #pragma once
#endif #endif
@ -162,7 +163,11 @@ public:
CBaseCombatWeapon(); CBaseCombatWeapon();
virtual ~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 bool IsBaseCombatWeapon( void ) const { return true; }
virtual CBaseCombatWeapon *MyCombatWeaponPointer( void ) { return this; } 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? 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_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. float m_flHudHintMinDisplayTime; // if the hint is squelched before this, reset my counter so we'll display it again.
// Server only // Server only
#if !defined( CLIENT_DLL ) #if !defined( CLIENT_DLL )
CStudioHdr *m_pStudioWorldHdr;
// Outputs // Outputs
protected: protected:

View file

@ -11,6 +11,8 @@
#include "bone_setup.h" #include "bone_setup.h"
// memdbgon must be the last include file in a .cpp file!!! // memdbgon must be the last include file in a .cpp file!!!
#include "mathlib/mathlib.h"
#include "studio.h"
#include "tier0/memdbgon.h" #include "tier0/memdbgon.h"
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -27,7 +29,7 @@ CBoneMergeCache::CBoneMergeCache()
m_nFollowBoneSetupMask = 0; m_nFollowBoneSetupMask = 0;
} }
void CBoneMergeCache::Init( C_BaseAnimating *pOwner ) void CBoneMergeCache::Init( CBaseAnimating *pOwner )
{ {
m_pOwner = pOwner; m_pOwner = pOwner;
m_pFollow = NULL; m_pFollow = NULL;
@ -40,7 +42,7 @@ void CBoneMergeCache::Init( C_BaseAnimating *pOwner )
void CBoneMergeCache::UpdateCache() void CBoneMergeCache::UpdateCache()
{ {
CStudioHdr *pOwnerHdr = m_pOwner ? m_pOwner->GetModelPtr() : NULL; CStudioHdr *pOwnerHdr = m_pOwner ? m_pOwner->GetModelPtr() : NULL;
if ( !pOwnerHdr ) if ( !pOwnerHdr || !m_pOwner->GetFollowedEntity())
{ {
if ( m_pOwnerHdr ) if ( m_pOwnerHdr )
{ {
@ -56,7 +58,11 @@ void CBoneMergeCache::UpdateCache()
return; return;
} }
C_BaseAnimating *pTestFollow = m_pOwner->FindFollowedEntity(); #ifdef CLIENT_DLL
C_BaseAnimating* pTestFollow = m_pOwner->FindFollowedEntity();
#else
CBaseAnimating* pTestFollow = dynamic_cast<CBaseAnimating*>(m_pOwner->GetFollowedEntity());
#endif
CStudioHdr *pTestHdr = (pTestFollow ? pTestFollow->GetModelPtr() : NULL); CStudioHdr *pTestHdr = (pTestFollow ? pTestFollow->GetModelPtr() : NULL);
const studiohdr_t *pTestStudioHDR = (pTestHdr ? pTestHdr->GetRenderHdr() : NULL); const studiohdr_t *pTestStudioHDR = (pTestHdr ? pTestHdr->GetRenderHdr() : NULL);
if ( pTestFollow != m_pFollow || pTestHdr != m_pFollowHdr || pTestStudioHDR != m_pFollowRenderHdr || pOwnerHdr != m_pOwnerHdr ) 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() ); int parentBoneIndex = Studio_BoneIndexByName( m_pFollowHdr, pOwnerBones[i].pszName() );
if ( parentBoneIndex < 0 ) if ( parentBoneIndex < 0 )
continue; 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. // Add a merged bone here.
CMergedBone mergedBone; CMergedBone mergedBone;
mergedBone.m_iMyBone = i; mergedBone.m_iMyBone = i;
@ -122,7 +130,7 @@ void CBoneMergeCache::UpdateCache()
ConVar r_captain_canteen_is_angry ( "r_captain_canteen_is_angry", "1" ); ConVar r_captain_canteen_is_angry ( "r_captain_canteen_is_angry", "1" );
#endif #endif
void CBoneMergeCache::MergeMatchingBones( int boneMask ) void CBoneMergeCache::MergeMatchingBones( int boneMask , matrix3x4_t mergedbones[MAXSTUDIOBONES] )
{ {
UpdateCache(); UpdateCache();
@ -130,43 +138,14 @@ void CBoneMergeCache::MergeMatchingBones( int boneMask )
if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 ) if ( !m_pOwnerHdr || m_MergedBones.Count() == 0 )
return; return;
matrix3x4_t bones[MAXSTUDIOBONES];
// Have the entity we're following setup its bones. // Have the entity we're following setup its bones.
bool bWorked = m_pFollow->SetupBones( NULL, -1, m_nFollowBoneSetupMask, gpGlobals->curtime ); #ifdef CLIENT_DLL
// We suspect there's some cases where SetupBones couldn't do its thing, and then this causes Captain Canteen. m_pFollow->SetupBones(bones, MAXSTUDIOBONES, m_nFollowBoneSetupMask, gpGlobals->curtime);
Assert ( bWorked ); #else
if ( !bWorked ) m_pFollow->SetupBones(m_pFollow->GetModelPtr(), bones, m_nFollowBoneSetupMask);
{
// 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 );
}
#endif #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. // Now copy the bone matrices.
for ( int i=0; i < m_MergedBones.Count(); i++ ) for ( int i=0; i < m_MergedBones.Count(); i++ )
{ {
@ -177,8 +156,11 @@ void CBoneMergeCache::MergeMatchingBones( int boneMask )
if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) ) if ( !( m_pOwnerHdr->boneFlags( iOwnerBone ) & boneMask ) )
continue; 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. // all over the place, then this won't get the right results.
// Get mFollowBone. // Get mFollowBone.
m_pFollow->SetupBones( NULL, -1, m_nFollowBoneSetupMask, gpGlobals->curtime ); matrix3x4_t bones[MAXSTUDIOBONES];
const matrix3x4_t &mFollowBone = m_pFollow->GetBone( m_MergedBones[0].m_iParentBone ); // 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 ) // Get Inverse( mBoneLocal )
matrix3x4_t mBoneLocal, mBoneLocalInv; matrix3x4_t mBoneLocal, mBoneLocalInv;
@ -280,8 +268,14 @@ bool CBoneMergeCache::GetRootBone( matrix3x4_t &rootBone )
return false; return false;
// Get mFollowBone. // Get mFollowBone.
m_pFollow->SetupBones( NULL, -1, m_nFollowBoneSetupMask, gpGlobals->curtime ); matrix3x4_t bones[MAXSTUDIOBONES];
rootBone = m_pFollow->GetBone( m_MergedBones[0].m_iParentBone ); // 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; return true;
} }

View file

@ -6,12 +6,21 @@
#ifndef BONE_MERGE_CACHE_H #ifndef BONE_MERGE_CACHE_H
#define BONE_MERGE_CACHE_H #define BONE_MERGE_CACHE_H
#include "mathlib/mathlib.h"
#include "studio.h"
#ifdef _WIN32 #ifdef _WIN32
#pragma once #pragma once
#endif #endif
#ifdef CLIENT_DLL
class C_BaseAnimating; class C_BaseAnimating;
#ifndef CBaseAnimating
#define CBaseAnimating C_BaseAnimating
#endif
#else
class CBaseAnimating;
#endif
class CStudioHdr; class CStudioHdr;
@ -24,14 +33,14 @@ public:
CBoneMergeCache(); CBoneMergeCache();
void Init( C_BaseAnimating *pOwner ); void Init( CBaseAnimating *pOwner );
// Updates the lookups that let it merge bones quickly. // Updates the lookups that let it merge bones quickly.
void UpdateCache(); void UpdateCache();
// This copies the transform from all bones in the followed entity that have // This copies the transform from all bones in the followed entity that have
// names that match our bones. // names that match our bones.
void MergeMatchingBones( int boneMask ); void MergeMatchingBones( int boneMask, matrix3x4_t mergedbones[MAXSTUDIOBONES] );
// copy bones instead of matrices // copy bones instead of matrices
void CopyParentToChild( const Vector parentPos[], const Quaternion parentQ[], Vector childPos[], Quaternion childQ[], int boneMask ); void CopyParentToChild( const Vector parentPos[], const Quaternion parentQ[], Vector childPos[], Quaternion childQ[], int boneMask );
@ -48,11 +57,11 @@ public:
private: private:
// This is the entity that we're keeping the cache updated for. // 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. // 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. // These are either all valid pointers or all NULL.
C_BaseAnimating *m_pFollow; CBaseAnimating *m_pFollow;
CStudioHdr *m_pFollowHdr; CStudioHdr *m_pFollowHdr;
const studiohdr_t *m_pFollowRenderHdr; const studiohdr_t *m_pFollowRenderHdr;
CStudioHdr *m_pOwnerHdr; CStudioHdr *m_pOwnerHdr;

View file

@ -419,7 +419,7 @@ public:
float m_timeValid; float m_timeValid;
int m_boneMask; int m_boneMask;
private: public:
matrix3x4_t *BoneArray(); matrix3x4_t *BoneArray();
short *StudioToCached(); short *StudioToCached();
short *CachedToStudio(); short *CachedToStudio();