css_enhanced_waf/game/client/c_baseanimating.h
Kamay Xutax 9d17d2252c Improved lag compensation for animations
Now we can debug properly lag compensation for animations and make it
more perfect without using the CUserCmd struct
For now it's used to sync better with client but in theory this can be
removed soon.
There's a lot of work to do in anim layers too.
2024-07-10 16:14:53 +02:00

828 lines
29 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $NoKeywords: $
//=============================================================================//
#ifndef C_BASEANIMATING_H
#define C_BASEANIMATING_H
#ifdef _WIN32
#pragma once
#endif
#include "bone_setup.h"
#include "c_baseentity.h"
#include "studio.h"
#include "utlvector.h"
#include "ragdoll.h"
#include "mouthinfo.h"
// Shared activities
#include "ai_activity.h"
#include "animationlayer.h"
#include "sequence_Transitioner.h"
#include "bone_accessor.h"
#include "bone_merge_cache.h"
#include "ragdoll_shared.h"
#include "tier0/threadtools.h"
#include "datacache/idatacache.h"
#define LIPSYNC_POSEPARAM_NAME "mouth"
#define NUM_HITBOX_FIRES 10
/*
class C_BaseClientShader
{
virtual void RenderMaterial( C_BaseEntity *pEntity, int count, const vec4_t *verts, const vec4_t *normals, const vec2_t *texcoords, vec4_t *lightvalues );
};
*/
class IRagdoll;
class CIKContext;
class CIKState;
class ConVar;
class C_RopeKeyframe;
class CBoneBitList;
class CBoneList;
class KeyValues;
class CJiggleBones;
class IBoneSetup;
FORWARD_DECLARE_HANDLE( memhandle_t );
typedef unsigned short MDLHandle_t;
extern ConVar vcollide_wireframe;
struct ClientModelRenderInfo_t : public ModelRenderInfo_t
{
// Added space for lighting origin override. Just allocated space, need to set base pointer
matrix3x4_t lightingOffset;
// Added space for model to world matrix. Just allocated space, need to set base pointer
matrix3x4_t modelToWorld;
};
struct RagdollInfo_t
{
bool m_bActive;
float m_flSaveTime;
int m_nNumBones;
Vector m_rgBonePos[MAXSTUDIOBONES];
Quaternion m_rgBoneQuaternion[MAXSTUDIOBONES];
};
class CAttachmentData
{
public:
matrix3x4_t m_AttachmentToWorld;
QAngle m_angRotation;
Vector m_vOriginVelocity;
int m_nLastFramecount : 31;
int m_bAnglesComputed : 1;
};
typedef unsigned int ClientSideAnimationListHandle_t;
#define INVALID_CLIENTSIDEANIMATION_LIST_HANDLE (ClientSideAnimationListHandle_t)~0
class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback
{
public:
DECLARE_CLASS( C_BaseAnimating, C_BaseEntity );
DECLARE_CLIENTCLASS();
DECLARE_PREDICTABLE();
DECLARE_INTERPOLATION();
enum
{
NUM_POSEPAREMETERS = 24,
NUM_BONECTRLS = 4
};
C_BaseAnimating();
~C_BaseAnimating();
virtual C_BaseAnimating* GetBaseAnimating() { return this; }
bool UsesPowerOfTwoFrameBufferTexture( void );
virtual bool Interpolate( float currentTime );
virtual void Simulate();
virtual void Release();
float GetAnimTimeInterval( void ) const;
virtual unsigned char GetClientSideFade( void );
// Get bone controller values.
virtual void GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS]);
virtual float SetBoneController ( int iController, float flValue );
LocalFlexController_t GetNumFlexControllers( void );
const char *GetFlexDescFacs( int iFlexDesc );
const char *GetFlexControllerName( LocalFlexController_t iFlexController );
const char *GetFlexControllerType( LocalFlexController_t iFlexController );
virtual void GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pAbsOrigin, QAngle *pAbsAngles );
// Computes a box that surrounds all hitboxes
bool ComputeHitboxSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs );
bool ComputeEntitySpaceHitboxSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs );
// Gets the hitbox-to-world transforms, returns false if there was a problem
bool HitboxToWorldTransforms( matrix3x4_t *pHitboxToWorld[MAXSTUDIOBONES] );
// base model functionality
float ClampCycle( float cycle, bool isLooping );
virtual void GetPoseParameters( CStudioHdr *pStudioHdr, float poseParameter[MAXSTUDIOPOSEPARAM] );
virtual void BuildTransformations( CStudioHdr *pStudioHdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed, float currentTime );
virtual void ApplyBoneMatrixTransform( matrix3x4_t& transform );
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 );
virtual bool ShouldDraw();
virtual int DrawModel( int flags );
virtual int InternalDrawModel( int flags );
virtual bool OnInternalDrawModel( ClientModelRenderInfo_t *pInfo );
virtual bool OnPostInternalDrawModel( ClientModelRenderInfo_t *pInfo );
void DoInternalDrawModel( ClientModelRenderInfo_t *pInfo, DrawModelState_t *pState, matrix3x4_t *pBoneToWorldArray = NULL );
//
virtual CMouthInfo *GetMouth();
virtual void ControlMouth( CStudioHdr *pStudioHdr );
// override in sub-classes
virtual void DoAnimationEvents( CStudioHdr *pStudio );
virtual void FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options );
virtual void FireObsoleteEvent( const Vector& origin, const QAngle& angles, int event, const char *options );
virtual const char* ModifyEventParticles( const char* token ) { return token; }
// Parses and distributes muzzle flash events
virtual bool DispatchMuzzleEffect( const char *options, bool isFirstPerson );
// virtual void AllocateMaterials( void );
// virtual void FreeMaterials( void );
virtual void ValidateModelIndex( void );
virtual CStudioHdr *OnNewModel( void );
CStudioHdr *GetModelPtr() const;
void InvalidateMdlCache();
virtual void SetPredictable( bool state );
void UseClientSideAnimation();
// C_BaseClientShader **p_ClientShaders;
virtual void StandardBlendingRules( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], float currentTime, int boneMask );
void UnragdollBlend( CStudioHdr *hdr, Vector pos[], Quaternion q[], float currentTime );
void MaintainSequenceTransitions( IBoneSetup &boneSetup, float flCycle, float currentTime, Vector pos[], Quaternion q[] );
virtual void AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime );
virtual void ChildLayerBlend( Vector pos[], Quaternion q[], float currentTime, int boneMask );
// Attachments
int LookupAttachment( const char *pAttachmentName );
int LookupRandomAttachment( const char *pAttachmentNameSubstring );
int LookupPoseParameter( CStudioHdr *pStudioHdr, const char *szName );
inline int LookupPoseParameter( const char *szName ) { return LookupPoseParameter(GetModelPtr(), szName); }
float SetPoseParameter( CStudioHdr *pStudioHdr, const char *szName, float flValue );
inline float SetPoseParameter( const char *szName, float flValue ) { return SetPoseParameter( GetModelPtr(), szName, flValue ); }
float SetPoseParameter( CStudioHdr *pStudioHdr, int iParameter, float flValue );
inline float SetPoseParameter( int iParameter, float flValue ) { return SetPoseParameter( GetModelPtr(), iParameter, flValue ); }
float GetPoseParameter( int iPoseParameter );
bool GetPoseParameterRange( int iPoseParameter, float &minValue, float &maxValue );
int LookupBone( const char *szName );
void GetBonePosition( int iBone, Vector &origin, QAngle &angles );
void GetBoneTransform( int iBone, matrix3x4_t &pBoneToWorld );
//=============================================================================
// HPE_BEGIN:
// [menglish] Finds the bone associated with the given hitbox
//=============================================================================
int GetHitboxBone( int hitboxIndex );
//=============================================================================
// HPE_END
//=============================================================================
// Bone attachments
virtual void AttachEntityToBone( C_BaseAnimating* attachTarget, int boneIndexAttached=-1, Vector bonePosition=Vector(0,0,0), QAngle boneAngles=QAngle(0,0,0) );
void AddBoneAttachment( C_BaseAnimating* newBoneAttachment );
void RemoveBoneAttachment( C_BaseAnimating* boneAttachment );
void RemoveBoneAttachments();
void DestroyBoneAttachments();
void MoveBoneAttachments( C_BaseAnimating* attachTarget );
int GetNumBoneAttachments();
C_BaseAnimating* GetBoneAttachment( int i );
virtual void NotifyBoneAttached( C_BaseAnimating* attachTarget );
virtual void UpdateBoneAttachments( void );
//bool solveIK(float a, float b, const Vector &Foot, const Vector &Knee1, Vector &Knee2);
//void DebugIK( mstudioikchain_t *pikchain );
virtual void PreDataUpdate( DataUpdateType_t updateType );
virtual void PostDataUpdate( DataUpdateType_t updateType );
virtual int RestoreData( const char *context, int slot, int type );
virtual void NotifyShouldTransmit( ShouldTransmitState_t state );
virtual void OnPreDataChanged( DataUpdateType_t updateType );
virtual void OnDataChanged( DataUpdateType_t updateType );
virtual void AddEntity( void );
// This can be used to force client side animation to be on. Only use if you know what you're doing!
// Normally, the server entity should set this.
void ForceClientSideAnimationOn();
void AddToClientSideAnimationList();
void RemoveFromClientSideAnimationList();
virtual bool IsSelfAnimating();
virtual void ResetLatched();
// implements these so ragdolls can handle frustum culling & leaf visibility
virtual void GetRenderBounds( Vector& theMins, Vector& theMaxs );
virtual const Vector& GetRenderOrigin( void );
virtual const QAngle& GetRenderAngles( void );
virtual bool GetSoundSpatialization( SpatializationInfo_t& info );
// Attachments.
bool GetAttachment( const char *szName, Vector &absOrigin );
bool GetAttachment( const char *szName, Vector &absOrigin, QAngle &absAngles );
// Inherited from C_BaseEntity
virtual bool GetAttachment( int number, Vector &origin );
virtual bool GetAttachment( int number, Vector &origin, QAngle &angles );
virtual bool GetAttachment( int number, matrix3x4_t &matrix );
virtual bool GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel );
// Returns the attachment in local space
bool GetAttachmentLocal( int iAttachment, matrix3x4_t &attachmentToLocal );
bool GetAttachmentLocal( int iAttachment, Vector &origin, QAngle &angles );
bool GetAttachmentLocal( int iAttachment, Vector &origin );
bool GetRootBone( matrix3x4_t &rootBone );
// Should this object cast render-to-texture shadows?
virtual ShadowType_t ShadowCastType();
// Should we collide?
virtual CollideType_t GetCollideType( void );
virtual bool TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr );
virtual bool TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr );
// returns true if we're currently being ragdolled
bool IsRagdoll() const;
bool IsAboutToRagdoll() const;
virtual C_BaseAnimating *BecomeRagdollOnClient();
C_BaseAnimating *CreateRagdollCopy();
bool InitAsClientRagdoll( const matrix3x4_t *pDeltaBones0, const matrix3x4_t *pDeltaBones1, const matrix3x4_t *pCurrentBonePosition, float boneDt, bool bFixedConstraints=false );
void IgniteRagdoll( C_BaseAnimating *pSource );
void TransferDissolveFrom( C_BaseAnimating *pSource );
virtual void SaveRagdollInfo( int numbones, const matrix3x4_t &cameraTransform, CBoneAccessor &pBoneToWorld );
virtual bool RetrieveRagdollInfo( Vector *pos, Quaternion *q );
virtual void Clear( void );
void ClearRagdoll();
void CreateUnragdollInfo( C_BaseAnimating *pRagdoll );
void ForceSetupBonesAtTime( matrix3x4_t *pBonesOut, float flTime );
virtual void GetRagdollInitBoneArrays( matrix3x4_t *pDeltaBones0, matrix3x4_t *pDeltaBones1, matrix3x4_t *pCurrentBones, float boneDt );
// For shadows rendering the correct body + sequence...
virtual int GetBody() { return m_nBody; }
virtual int GetSkin() { return m_nSkin; }
bool IsOnFire() { return ( (GetFlags() & FL_ONFIRE) != 0 ); }
inline float GetPlaybackRate();
inline void SetPlaybackRate( float rate );
void SetModelScale( float scale, float change_duration = 0.0f );
float GetModelScale() const { return m_flModelScale; }
inline bool IsModelScaleFractional() const; /// very fast way to ask if the model scale is < 1.0f (faster than if (GetModelScale() < 1.0f) )
inline bool IsModelScaled() const;
void UpdateModelScale( void );
virtual void RefreshCollisionBounds( void );
int GetSequence();
virtual void SetSequence(int nSequence);
inline void ResetSequence(int nSequence);
float GetSequenceGroundSpeed( CStudioHdr *pStudioHdr, int iSequence );
inline float GetSequenceGroundSpeed( int iSequence ) { return GetSequenceGroundSpeed(GetModelPtr(), iSequence); }
bool IsSequenceLooping( CStudioHdr *pStudioHdr, int iSequence );
inline bool IsSequenceLooping( int iSequence ) { return IsSequenceLooping(GetModelPtr(),iSequence); }
float GetSequenceMoveDist( CStudioHdr *pStudioHdr, int iSequence );
void GetSequenceLinearMotion( int iSequence, Vector *pVec );
void GetBlendedLinearVelocity( Vector *pVec );
int LookupSequence ( const char *label );
int LookupActivity( const char *label );
char const *GetSequenceName( int iSequence );
char const *GetSequenceActivityName( int iSequence );
Activity GetSequenceActivity( int iSequence );
KeyValues *GetSequenceKeyValues( int iSequence );
float GetLastVisibleCycle( CStudioHdr *pStudioHdr, int iSequence );
virtual void StudioFrameAdvance(); // advance animation frame to some time in the future
// Clientside animation
virtual float FrameAdvance( float flInterval = 0.0f );
virtual float GetSequenceCycleRate( CStudioHdr *pStudioHdr, int iSequence );
virtual void UpdateClientSideAnimation();
void ClientSideAnimationChanged();
virtual unsigned int ComputeClientSideAnimationFlags();
virtual void ResetClientsideFrame( void ) { SetCycle( 0 ); }
void SetCycle( float flCycle );
float GetCycle() const;
void SetBodygroup( int iGroup, int iValue );
int GetBodygroup( int iGroup );
const char *GetBodygroupName( int iGroup );
int FindBodygroupByName( const char *name );
int GetBodygroupCount( int iGroup );
int GetNumBodyGroups( void );
class CBoneCache *GetBoneCache( CStudioHdr *pStudioHdr );
void InvalidateBoneCacheIfOlderThan( float deltaTime );
void SetHitboxSet( int setnum );
void SetHitboxSetByName( const char *setname );
int GetHitboxSet( void );
char const *GetHitboxSetName( void );
int GetHitboxSetCount( void );
void DrawClientHitboxes( float duration = 0.0f, bool monocolor = false );
C_BaseAnimating* FindFollowedEntity();
virtual bool IsActivityFinished( void ) { return m_bSequenceFinished; }
inline bool IsSequenceFinished( void );
inline bool SequenceLoops( void ) { return m_bSequenceLoops; }
// All view model attachments origins are stretched so you can place entities at them and
// they will match up with where the attachment winds up being drawn on the view model, since
// the view models are drawn with a different FOV.
//
// If you're drawing something inside of a view model's DrawModel() function, then you want the
// original attachment origin instead of the adjusted one. To get that, call this on the
// adjusted attachment origin.
virtual void UncorrectViewModelAttachment( Vector &vOrigin ) {}
// Call this if SetupBones() has already been called this frame but you need to move the
// entity and rerender.
void InvalidateBoneCache();
bool IsBoneCacheValid() const; // Returns true if the bone cache is considered good for this frame.
void GetCachedBoneMatrix( int boneIndex, matrix3x4_t &out );
// Wrappers for CBoneAccessor.
const matrix3x4_t& GetBone( int iBone ) const;
matrix3x4_t& GetBoneForWrite( int iBone );
// Used for debugging. Will produce asserts if someone tries to setup bones or
// attachments before it's allowed.
// Use the "AutoAllowBoneAccess" class to auto push/pop bone access.
// Use a distinct "tag" when pushing/popping - asserts when push/pop tags do not match.
struct AutoAllowBoneAccess
{
AutoAllowBoneAccess( bool bAllowForNormalModels, bool bAllowForViewModels );
~AutoAllowBoneAccess( void );
};
static void PushAllowBoneAccess( bool bAllowForNormalModels, bool bAllowForViewModels, char const *tagPush );
static void PopBoneAccess( char const *tagPop );
static void ThreadedBoneSetup();
static void InitBoneSetupThreadPool();
static void ShutdownBoneSetupThreadPool();
// Invalidate bone caches so all SetupBones() calls force bone transforms to be regenerated.
static void InvalidateBoneCaches();
// Purpose: My physics object has been updated, react or extract data
virtual void VPhysicsUpdate( IPhysicsObject *pPhysics );
void DisableMuzzleFlash(); // Turn off the muzzle flash (ie: signal that we handled the server's event).
virtual void DoMuzzleFlash(); // Force a muzzle flash event. Note: this only QUEUES an event, so
// ProcessMuzzleFlashEvent will get called later.
bool ShouldMuzzleFlash() const; // Is the muzzle flash event on?
// This is called to do the actual muzzle flash effect.
virtual void ProcessMuzzleFlashEvent();
// Update client side animations
static void UpdateClientSideAnimations();
// Load the model's keyvalues section and create effects listed inside it
void InitModelEffects( void );
// Sometimes the server wants to update the client's cycle to get the two to run in sync (for proper hit detection)
virtual void SetServerIntendedCycle( float intended ) { (void)intended; }
virtual float GetServerIntendedCycle( void ) { return -1.0f; }
// For prediction
int SelectWeightedSequence ( int activity );
void ResetSequenceInfo( void );
float SequenceDuration( void );
float SequenceDuration( CStudioHdr *pStudioHdr, int iSequence );
inline float SequenceDuration( int iSequence ) { return SequenceDuration(GetModelPtr(), iSequence); }
int FindTransitionSequence( int iCurrentSequence, int iGoalSequence, int *piDir );
void RagdollMoved( void );
virtual void GetToolRecordingState( KeyValues *msg );
virtual void CleanupToolRecordingState( KeyValues *msg );
void SetReceivedSequence( void );
virtual bool ShouldResetSequenceOnNewModel( void );
virtual bool IsViewModel() const;
protected:
// View models scale their attachment positions to account for FOV. To get the unmodified
// attachment position (like if you're rendering something else during the view model's DrawModel call),
// use TransformViewModelAttachmentToWorld.
virtual void FormatViewModelAttachment( int nAttachment, matrix3x4_t &attachmentToWorld ) {}
// View models say yes to this.
bool IsBoneAccessAllowed() const;
CMouthInfo& MouthInfo();
// Models used in a ModelPanel say yes to this
virtual bool IsMenuModel() const;
// Allow studio models to tell C_BaseEntity what their m_nBody value is
virtual int GetStudioBody( void ) { return m_nBody; }
virtual bool CalcAttachments();
private:
// This method should return true if the bones have changed + SetupBones needs to be called
virtual float LastBoneChangedTime() { return FLT_MAX; }
CBoneList* RecordBones( CStudioHdr *hdr, matrix3x4_t *pBoneState );
bool PutAttachment( int number, const matrix3x4_t &attachmentToWorld );
void TermRopes();
void DelayedInitModelEffects( void );
void UpdateRelevantInterpolatedVars();
void AddBaseAnimatingInterpolatedVars();
void RemoveBaseAnimatingInterpolatedVars();
public:
CRagdoll *m_pRagdoll;
// Texture group to use
int m_nSkin;
// Object bodygroup
int m_nBody;
// Hitbox set to use (default 0)
int m_nHitboxSet;
CSequenceTransitioner m_SequenceTransitioner;
int m_iIKCounter;
protected:
CIKContext *m_pIk;
int m_iEyeAttachment;
// Animation playback framerate
float m_flPlaybackRate;
// Decomposed ragdoll info
bool m_bStoreRagdollInfo;
RagdollInfo_t *m_pRagdollInfo;
Vector m_vecForce;
int m_nForceBone;
// Is bone cache valid
// bone transformation matrix
unsigned long m_iMostRecentModelBoneCounter;
unsigned long m_iMostRecentBoneSetupRequest;
int m_iPrevBoneMask;
int m_iAccumulatedBoneMask;
CBoneAccessor m_BoneAccessor;
CThreadFastMutex m_BoneSetupLock;
ClientSideAnimationListHandle_t m_ClientSideAnimationListHandle;
// Client-side animation
bool m_bClientSideFrameReset;
// Bone attachments. Used for attaching one BaseAnimating to another's bones.
// Client side only.
CUtlVector<CHandle<C_BaseAnimating> > m_BoneAttachments;
int m_boneIndexAttached;
Vector m_bonePosition;
QAngle m_boneAngles;
CHandle<C_BaseAnimating> m_pAttachedTo;
protected:
float m_fadeMinDist;
float m_fadeMaxDist;
float m_flFadeScale;
private:
float m_flGroundSpeed; // computed linear movement rate for current sequence
float m_flLastEventCheck; // cycle index of when events were last checked
bool m_bSequenceFinished;// flag set when StudioAdvanceFrame moves across a frame boundry
bool m_bSequenceLoops; // true if the sequence loops
// Mouth lipsync/envelope following values
CMouthInfo m_mouth;
CNetworkVar( float, m_flModelScale );
// Animation blending factors
float m_flPoseParameter[MAXSTUDIOPOSEPARAM];
CInterpolatedVarArray< float, MAXSTUDIOPOSEPARAM > m_iv_flPoseParameter;
float m_flOldPoseParameters[MAXSTUDIOPOSEPARAM];
int m_nPrevSequence;
int m_nRestoreSequence;
// Ropes that got spawned when the model was created.
CUtlLinkedList<C_RopeKeyframe*,unsigned short> m_Ropes;
// event processing info
float m_flPrevEventCycle;
int m_nEventSequence;
float m_flEncodedController[MAXSTUDIOBONECTRLS];
CInterpolatedVarArray< float, MAXSTUDIOBONECTRLS > m_iv_flEncodedController;
float m_flOldEncodedController[MAXSTUDIOBONECTRLS];
// Clientside animation
bool m_bClientSideAnimation;
bool m_bLastClientSideFrameReset;
int m_nNewSequenceParity;
int m_nResetEventsParity;
int m_nPrevNewSequenceParity;
int m_nPrevResetEventsParity;
bool m_builtRagdoll;
Vector m_vecPreRagdollMins;
Vector m_vecPreRagdollMaxs;
// Current animation sequence
int m_nSequence;
bool m_bReceivedSequence;
// Current cycle location from server
protected:
float m_flCycle;
CInterpolatedVar< float > m_iv_flCycle;
float m_flOldCycle;
bool m_bNoModelParticles;
private:
float m_flOldModelScale;
int m_nOldSequence;
CBoneMergeCache *m_pBoneMergeCache; // This caches the strcmp lookups that it has to do
// when merg
CUtlVector< matrix3x4_t > m_CachedBoneData; // never access this directly. Use m_BoneAccessor.
memhandle_t m_hitboxBoneCacheHandle;
float m_flLastBoneSetupTime;
CJiggleBones *m_pJiggleBones;
// Calculated attachment points
CUtlVector<CAttachmentData> m_Attachments;
void SetupBones_AttachmentHelper( CStudioHdr *pStudioHdr );
EHANDLE m_hLightingOrigin;
EHANDLE m_hLightingOriginRelative;
// These are compared against each other to determine if the entity should muzzle flash.
CNetworkVar( unsigned char, m_nMuzzleFlashParity );
unsigned char m_nOldMuzzleFlashParity;
bool m_bInitModelEffects;
// Dynamic models
bool m_bDynamicModelAllowed;
bool m_bDynamicModelPending;
bool m_bResetSequenceInfoOnLoad;
CRefCountedModelIndex m_AutoRefModelIndex;
public:
void EnableDynamicModels() { m_bDynamicModelAllowed = true; }
bool IsDynamicModelLoading() const { return m_bDynamicModelPending; }
private:
virtual void OnModelLoadComplete( const model_t* pModel );
private:
void StudioFrameAdvanceInternal( CStudioHdr *pStudioHdr, float flInterval );
void LockStudioHdr();
void UnlockStudioHdr();
mutable CStudioHdr *m_pStudioHdr;
mutable MDLHandle_t m_hStudioHdr;
CThreadFastMutex m_StudioHdrInitLock;
};
enum
{
RAGDOLL_FRICTION_OFF = -2,
RAGDOLL_FRICTION_NONE,
RAGDOLL_FRICTION_IN,
RAGDOLL_FRICTION_HOLD,
RAGDOLL_FRICTION_OUT,
};
class C_ClientRagdoll : public C_BaseAnimating, public IPVSNotify
{
public:
C_ClientRagdoll( bool bRestoring = true );
DECLARE_CLASS( C_ClientRagdoll, C_BaseAnimating );
DECLARE_DATADESC();
// inherited from IPVSNotify
virtual void OnPVSStatusChanged( bool bInPVS );
virtual void Release( void );
virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights );
virtual void ImpactTrace( trace_t *pTrace, int iDamageType, const char *pCustomImpactName );
void ClientThink( void );
void ReleaseRagdoll( void ) { m_bReleaseRagdoll = true; }
bool ShouldSavePhysics( void ) { return true; }
virtual void OnSave();
virtual void OnRestore();
virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() | FCAP_SAVE_NON_NETWORKABLE; }
virtual IPVSNotify* GetPVSNotifyInterface() { return this; }
void HandleAnimatedFriction( void );
virtual void SUB_Remove( void );
void FadeOut( void );
virtual float LastBoneChangedTime();
bool m_bFadeOut;
bool m_bImportant;
float m_flEffectTime;
private:
int m_iCurrentFriction;
int m_iMinFriction;
int m_iMaxFriction;
float m_flFrictionModTime;
float m_flFrictionTime;
int m_iFrictionAnimState;
bool m_bReleaseRagdoll;
bool m_bFadingOut;
float m_flScaleEnd[NUM_HITBOX_FIRES];
float m_flScaleTimeStart[NUM_HITBOX_FIRES];
float m_flScaleTimeEnd[NUM_HITBOX_FIRES];
};
//-----------------------------------------------------------------------------
// Purpose: Serves the 90% case of calling SetSequence / ResetSequenceInfo.
//-----------------------------------------------------------------------------
inline void C_BaseAnimating::ResetSequence(int nSequence)
{
SetSequence( nSequence );
ResetSequenceInfo();
}
inline float C_BaseAnimating::GetPlaybackRate()
{
return m_flPlaybackRate;
}
inline void C_BaseAnimating::SetPlaybackRate( float rate )
{
m_flPlaybackRate = rate;
}
inline const matrix3x4_t& C_BaseAnimating::GetBone( int iBone ) const
{
return m_BoneAccessor.GetBone( iBone );
}
inline matrix3x4_t& C_BaseAnimating::GetBoneForWrite( int iBone )
{
return m_BoneAccessor.GetBoneForWrite( iBone );
}
inline bool C_BaseAnimating::ShouldMuzzleFlash() const
{
return m_nOldMuzzleFlashParity != m_nMuzzleFlashParity;
}
inline float C_BaseAnimating::GetCycle() const
{
return m_flCycle;
}
//-----------------------------------------------------------------------------
// Purpose: return a pointer to an updated studiomdl cache cache
//-----------------------------------------------------------------------------
inline CStudioHdr *C_BaseAnimating::GetModelPtr() const
{
if ( IsDynamicModelLoading() )
return NULL;
#ifdef _DEBUG
// GetModelPtr() is often called before OnNewModel() so go ahead and set it up first chance.
// static IDataCacheSection *pModelCache = datacache->FindSection( "ModelData" );
// AssertOnce( pModelCache->IsFrameLocking() );
#endif
if ( !m_pStudioHdr )
{
const_cast<C_BaseAnimating *>(this)->LockStudioHdr();
}
Assert( m_pStudioHdr ? m_pStudioHdr->GetRenderHdr() == mdlcache->GetStudioHdr(m_hStudioHdr) : m_hStudioHdr == MDLHANDLE_INVALID );
return m_pStudioHdr;
}
inline void C_BaseAnimating::InvalidateMdlCache()
{
if ( m_pStudioHdr )
{
UnlockStudioHdr();
delete m_pStudioHdr;
m_pStudioHdr = NULL;
}
}
inline bool C_BaseAnimating::IsModelScaleFractional() const /// very fast way to ask if the model scale is < 1.0f
{
COMPILE_TIME_ASSERT( sizeof( m_flModelScale ) == sizeof( int ) );
return *((const int *) &m_flModelScale) < 0x3f800000;
}
inline bool C_BaseAnimating::IsModelScaled() const
{
return ( m_flModelScale > 1.0f+FLT_EPSILON || m_flModelScale < 1.0f-FLT_EPSILON );
}
//-----------------------------------------------------------------------------
// Sequence access
//-----------------------------------------------------------------------------
inline int C_BaseAnimating::GetSequence()
{
return m_nSequence;
}
inline bool C_BaseAnimating::IsSequenceFinished( void )
{
return m_bSequenceFinished;
}
inline float C_BaseAnimating::SequenceDuration( void )
{
return SequenceDuration( GetSequence() );
}
//-----------------------------------------------------------------------------
// Mouth
//-----------------------------------------------------------------------------
inline CMouthInfo& C_BaseAnimating::MouthInfo()
{
return m_mouth;
}
// FIXME: move these to somewhere that makes sense
void GetColumn( matrix3x4_t& src, int column, Vector &dest );
void SetColumn( Vector &src, int column, matrix3x4_t& dest );
EXTERN_RECV_TABLE(DT_BaseAnimating);
extern void DevMsgRT( PRINTF_FORMAT_STRING char const* pMsg, ... );
#endif // C_BASEANIMATING_H