summaryrefslogtreecommitdiff
path: root/game/server/baseanimating.h
diff options
context:
space:
mode:
Diffstat (limited to 'game/server/baseanimating.h')
-rw-r--r--game/server/baseanimating.h536
1 files changed, 536 insertions, 0 deletions
diff --git a/game/server/baseanimating.h b/game/server/baseanimating.h
new file mode 100644
index 0000000..0550683
--- /dev/null
+++ b/game/server/baseanimating.h
@@ -0,0 +1,536 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef BASEANIMATING_H
+#define BASEANIMATING_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "baseentity.h"
+#include "entityoutput.h"
+#include "studio.h"
+#include "datacache/idatacache.h"
+#include "tier0/threadtools.h"
+
+
+struct animevent_t;
+struct matrix3x4_t;
+class CIKContext;
+class KeyValues;
+FORWARD_DECLARE_HANDLE( memhandle_t );
+
+#define BCF_NO_ANIMATION_SKIP ( 1 << 0 ) // Do not allow PVS animation skipping (mostly for attachments being critical to an entity)
+#define BCF_IS_IN_SPAWN ( 1 << 1 ) // Is currently inside of spawn, always evaluate animations
+
+class CBaseAnimating : public CBaseEntity
+{
+public:
+ DECLARE_CLASS( CBaseAnimating, CBaseEntity );
+
+ CBaseAnimating();
+ ~CBaseAnimating();
+
+ DECLARE_PREDICTABLE();
+
+ enum
+ {
+ NUM_POSEPAREMETERS = 24,
+ NUM_BONECTRLS = 4
+ };
+
+ DECLARE_DATADESC();
+ DECLARE_SERVERCLASS();
+
+ virtual void SetModel( const char *szModelName );
+ virtual void Activate();
+ virtual void Spawn();
+ virtual void Precache();
+ virtual void SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways );
+
+ virtual int Restore( IRestore &restore );
+ virtual void OnRestore();
+
+ CStudioHdr *GetModelPtr( void );
+ void InvalidateMdlCache();
+
+ virtual CStudioHdr *OnNewModel();
+
+ virtual CBaseAnimating* GetBaseAnimating() { return this; }
+
+ // Cycle access
+ void SetCycle( float flCycle );
+ float GetCycle() const;
+
+ float GetAnimTimeInterval( void ) const;
+
+ // Call this in your constructor to tell it that you will not use animtime. Then the
+ // interpolation will be done correctly on the client.
+ // This defaults to off.
+ void UseClientSideAnimation();
+
+ // Tells whether or not we're using client-side animation. Used for controlling
+ // the transmission of animtime.
+ bool IsUsingClientSideAnimation() { return m_bClientSideAnimation; }
+
+
+ // Basic NPC Animation functions
+ virtual float GetIdealSpeed( ) const;
+ virtual float GetIdealAccel( ) const;
+ virtual void StudioFrameAdvance(); // advance animation frame to some time in the future
+ void StudioFrameAdvanceManual( float flInterval );
+ bool IsValidSequence( int iSequence );
+
+ inline float GetPlaybackRate();
+ inline void SetPlaybackRate( float rate );
+
+ inline int GetSequence() { return m_nSequence; }
+ virtual void SetSequence(int nSequence);
+ /* inline */ void ResetSequence(int nSequence);
+ // FIXME: push transitions support down into CBaseAnimating?
+ virtual bool IsActivityFinished( void ) { return m_bSequenceFinished; }
+ inline bool IsSequenceFinished( void ) { return m_bSequenceFinished; }
+ inline bool SequenceLoops( void ) { return m_bSequenceLoops; }
+ bool IsSequenceLooping( CStudioHdr *pStudioHdr, int iSequence );
+ inline bool IsSequenceLooping( int iSequence ) { return IsSequenceLooping(GetModelPtr(),iSequence); }
+ inline float SequenceDuration( void ) { return SequenceDuration( m_nSequence ); }
+ float SequenceDuration( CStudioHdr *pStudioHdr, int iSequence );
+ inline float SequenceDuration( int iSequence ) { return SequenceDuration(GetModelPtr(), iSequence); }
+ float GetSequenceCycleRate( CStudioHdr *pStudioHdr, int iSequence );
+ inline float GetSequenceCycleRate( int iSequence ) { return GetSequenceCycleRate(GetModelPtr(),iSequence); }
+ float GetLastVisibleCycle( CStudioHdr *pStudioHdr, int iSequence );
+ virtual float GetSequenceGroundSpeed( CStudioHdr *pStudioHdr, int iSequence );
+ inline float GetSequenceGroundSpeed( int iSequence ) { return GetSequenceGroundSpeed(GetModelPtr(), iSequence); }
+ void ResetActivityIndexes ( void );
+ void ResetEventIndexes ( void );
+ int SelectWeightedSequence ( Activity activity );
+ int SelectWeightedSequence ( Activity activity, int curSequence );
+ int SelectWeightedSequenceFromModifiers( Activity activity, CUtlSymbol *pActivityModifiers, int iModifierCount );
+ int SelectHeaviestSequence ( Activity activity );
+ int LookupActivity( const char *label );
+ int LookupSequence ( const char *label );
+ KeyValues *GetSequenceKeyValues( int iSequence );
+
+ float GetSequenceMoveYaw( int iSequence );
+ float GetSequenceMoveDist( CStudioHdr *pStudioHdr, int iSequence );
+ inline float GetSequenceMoveDist( int iSequence ) { return GetSequenceMoveDist(GetModelPtr(),iSequence);}
+ void GetSequenceLinearMotion( int iSequence, Vector *pVec );
+ const char *GetSequenceName( int iSequence );
+ const char *GetSequenceActivityName( int iSequence );
+ Activity GetSequenceActivity( int iSequence );
+
+ void ResetSequenceInfo ( );
+ // This will stop animation until you call ResetSequenceInfo() at some point in the future
+ inline void StopAnimation( void ) { m_flPlaybackRate = 0; }
+
+ virtual void ClampRagdollForce( const Vector &vecForceIn, Vector *vecForceOut ) { *vecForceOut = vecForceIn; } // Base class does nothing.
+ virtual bool BecomeRagdollOnClient( const Vector &force );
+ virtual bool IsRagdoll();
+ virtual bool CanBecomeRagdoll( void ); //Check if this entity will ragdoll when dead.
+
+ 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 CalculateIKLocks( float currentTime );
+ virtual void Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity );
+
+ bool HasAnimEvent( int nSequence, int nEvent );
+ virtual void DispatchAnimEvents ( CBaseAnimating *eventHandler ); // Handle events that have happend since last time called up until X seconds into the future
+ virtual void HandleAnimEvent( animevent_t *pEvent );
+
+ 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( const char *szName );
+ float GetPoseParameter( int iParameter );
+ bool GetPoseParameterRange( int index, float &minValue, float &maxValue );
+ bool HasPoseParameter( int iSequence, const char *szName );
+ bool HasPoseParameter( int iSequence, int iParameter );
+ float EdgeLimitPoseParameter( int iParameter, float flValue, float flBase = 0.0f );
+
+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
+ // save off your pose parameters in member variables in your derivation of this function:
+ virtual void PopulatePoseParameters( void );
+
+
+public:
+
+ int LookupBone( const char *szName );
+ void GetBonePosition( const char *szName, Vector &origin, QAngle &angles );
+ void GetBonePosition( int iBone, Vector &origin, QAngle &angles );
+ int GetPhysicsBone( int boneIndex );
+
+ int GetNumBones ( void );
+
+ int FindTransitionSequence( int iCurrentSequence, int iGoalSequence, int *piDir );
+ bool GotoSequence( int iCurrentSequence, float flCurrentCycle, float flCurrentRate, int iGoalSequence, int &iNextSequence, float &flCycle, int &iDir );
+ int GetEntryNode( int iSequence );
+ int GetExitNode( int iSequence );
+
+ void GetEyeballs( Vector &origin, QAngle &angles ); // ?? remove ??
+
+ int LookupAttachment( const char *szName );
+
+ // These return the attachment in world space
+ bool GetAttachment( const char *szName, Vector &absOrigin, QAngle &absAngles );
+ bool GetAttachment( int iAttachment, Vector &absOrigin, QAngle &absAngles );
+ int GetAttachmentBone( int iAttachment );
+ virtual bool GetAttachment( int iAttachment, matrix3x4_t &attachmentToWorld );
+
+ // These return the attachment in the space of the entity
+ bool GetAttachmentLocal( const char *szName, Vector &origin, QAngle &angles );
+ bool GetAttachmentLocal( int iAttachment, Vector &origin, QAngle &angles );
+ bool GetAttachmentLocal( int iAttachment, matrix3x4_t &attachmentToLocal );
+
+ // Non-angle versions of the attachments in world space
+ bool GetAttachment( const char *szName, Vector &absOrigin, Vector *forward = NULL, Vector *right = NULL, Vector *up = NULL );
+ bool GetAttachment( int iAttachment, Vector &absOrigin, Vector *forward = NULL, Vector *right = NULL, Vector *up = NULL );
+
+ 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 );
+
+ void SetHitboxSet( int setnum );
+ void SetHitboxSetByName( const char *setname );
+ int GetHitboxSet( void );
+ char const *GetHitboxSetName( void );
+ int GetHitboxSetCount( void );
+ int GetHitboxBone( int hitboxIndex );
+ bool LookupHitbox( const char *szName, int& outSet, int& outBox );
+
+ // Computes a box that surrounds all hitboxes
+ bool ComputeHitboxSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs );
+ bool ComputeEntitySpaceHitboxSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs );
+
+ // Clone a CBaseAnimating from another (copies model & sequence data)
+ void CopyAnimationDataFrom( CBaseAnimating *pSource );
+
+ int ExtractBbox( int sequence, Vector& mins, Vector& maxs );
+ void SetSequenceBox( void );
+ int RegisterPrivateActivity( const char *pszActivityName );
+
+ void ResetClientsideFrame( void );
+
+// Controllers.
+ virtual void InitBoneControllers ( void );
+
+ // Return's the controller's angle/position in bone space.
+ float GetBoneController ( int iController );
+
+ // Maps the angle/position value you specify into the bone's start/end and sets the specified controller to the value.
+ float SetBoneController ( int iController, float flValue );
+
+ void GetVelocity(Vector *vVelocity, AngularImpulse *vAngVelocity);
+
+ // these two need to move somewhere else
+ LocalFlexController_t GetNumFlexControllers( void );
+ const char *GetFlexDescFacs( int iFlexDesc );
+ const char *GetFlexControllerName( LocalFlexController_t iFlexController );
+ const char *GetFlexControllerType( LocalFlexController_t iFlexController );
+
+ virtual Vector GetGroundSpeedVelocity( void );
+
+ bool GetIntervalMovement( float flIntervalUsed, bool &bMoveSeqFinished, Vector &newPosition, QAngle &newAngles );
+ bool GetSequenceMovement( int nSequence, float fromCycle, float toCycle, Vector &deltaPosition, QAngle &deltaAngles );
+ float GetInstantaneousVelocity( float flInterval = 0.0 );
+ float GetEntryVelocity( int iSequence );
+ float GetExitVelocity( int iSequence );
+ float GetMovementFrame( float flDist );
+ bool HasMovement( int iSequence );
+
+ void ReportMissingActivity( int iActivity );
+ 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 );
+ class CBoneCache *GetBoneCache( void );
+ void InvalidateBoneCache();
+ void InvalidateBoneCacheIfOlderThan( float deltaTime );
+ virtual int DrawDebugTextOverlays( void );
+
+ // See note in code re: bandwidth usage!!!
+ void DrawServerHitboxes( float duration = 0.0f, bool monocolor = false );
+ void DrawRawSkeleton( matrix3x4_t boneToWorld[], int boneMask, bool noDepthTest = true, float duration = 0.0f, bool monocolor = false );
+
+ void SetModelScale( float scale, float change_duration = 0.0f );
+ float GetModelScale() const { return m_flModelScale; }
+
+ void UpdateModelScale();
+ virtual void RefreshCollisionBounds( void );
+
+ // also calculate IK on server? (always done on client)
+ void EnableServerIK();
+ void DisableServerIK();
+
+ // for ragdoll vs. car
+ int GetHitboxesFrontside( int *boxList, int boxMax, const Vector &normal, float dist );
+
+ void GetInputDispatchEffectPosition( const char *sInputString, Vector &pOrigin, QAngle &pAngles );
+
+ virtual void ModifyOrAppendCriteria( AI_CriteriaSet& set );
+
+ // Send a muzzle flash event to the client for this entity.
+ void DoMuzzleFlash();
+
+ // Fire
+ virtual void Ignite( float flFlameLifetime, bool bNPCOnly = true, float flSize = 0.0f, bool bCalledByLevelDesigner = false );
+ virtual void IgniteLifetime( float flFlameLifetime );
+ virtual void IgniteNumHitboxFires( int iNumHitBoxFires );
+ virtual void IgniteHitboxFireScale( float flHitboxFireScale );
+ virtual void Extinguish() { RemoveFlag( FL_ONFIRE ); }
+ bool IsOnFire() { return ( (GetFlags() & FL_ONFIRE) != 0 ); }
+ void Scorch( int rate, int floor );
+ void InputIgnite( inputdata_t &inputdata );
+ void InputIgniteLifetime( inputdata_t &inputdata );
+ void InputIgniteNumHitboxFires( inputdata_t &inputdata );
+ void InputIgniteHitboxFireScale( inputdata_t &inputdata );
+ void InputBecomeRagdoll( inputdata_t &inputdata );
+
+ // Dissolve, returns true if the ragdoll has been created
+ bool Dissolve( const char *pMaterialName, float flStartTime, bool bNPCOnly = true, int nDissolveType = 0, Vector vDissolverOrigin = vec3_origin, int iMagnitude = 0 );
+ bool IsDissolving() { return ( (GetFlags() & FL_DISSOLVING) != 0 ); }
+ void TransferDissolveFrom( CBaseAnimating *pAnim );
+
+ // animation needs
+ float m_flGroundSpeed; // computed linear movement rate for current sequence
+ float m_flLastEventCheck; // cycle index of when events were last checked
+
+ virtual void SetLightingOriginRelative( CBaseEntity *pLightingOriginRelative );
+ void SetLightingOriginRelative( string_t strLightingOriginRelative );
+ CBaseEntity *GetLightingOriginRelative();
+
+ virtual void SetLightingOrigin( CBaseEntity *pLightingOrigin );
+ void SetLightingOrigin( string_t strLightingOrigin );
+ CBaseEntity *GetLightingOrigin();
+
+ const float* GetPoseParameterArray() { return m_flPoseParameter.Base(); }
+ const float* GetEncodedControllerArray() { return m_flEncodedController.Base(); }
+
+ 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 );
+
+ void SetFadeDistance( float minFadeDist, float maxFadeDist );
+
+ int GetBoneCacheFlags( void ) { return m_fBoneCacheFlags; }
+ inline void SetBoneCacheFlags( unsigned short fFlag ) { m_fBoneCacheFlags |= fFlag; }
+ inline void ClearBoneCacheFlags( unsigned short fFlag ) { m_fBoneCacheFlags &= ~fFlag; }
+
+ bool PrefetchSequence( int iSequence );
+
+private:
+ void LockStudioHdr();
+ void UnlockStudioHdr();
+
+ void StudioFrameAdvanceInternal( CStudioHdr *pStudioHdr, float flInterval );
+ void InputSetLightingOriginRelative( inputdata_t &inputdata );
+ void InputSetLightingOrigin( inputdata_t &inputdata );
+ void InputSetModelScale( inputdata_t &inputdata );
+
+ bool CanSkipAnimation( void );
+
+public:
+ CNetworkVar( int, m_nForceBone );
+ CNetworkVector( m_vecForce );
+
+ CNetworkVar( int, m_nSkin );
+ CNetworkVar( int, m_nBody );
+ CNetworkVar( int, m_nHitboxSet );
+
+ // For making things thin during barnacle swallowing, e.g.
+ CNetworkVar( float, m_flModelScale );
+
+ // was pev->framerate
+ CNetworkVar( float, m_flPlaybackRate );
+
+public:
+ void InitStepHeightAdjust( void );
+ void SetIKGroundContactInfo( float minHeight, float maxHeight );
+ void UpdateStepOrigin( void );
+
+protected:
+ float m_flIKGroundContactTime;
+ float m_flIKGroundMinHeight;
+ float m_flIKGroundMaxHeight;
+
+ float m_flEstIkFloor; // debounced
+ float m_flEstIkOffset;
+
+ CIKContext *m_pIk;
+ int m_iIKCounter;
+
+public:
+ Vector GetStepOrigin( void ) const;
+ QAngle GetStepAngles( void ) const;
+
+private:
+ bool m_bSequenceFinished;// flag set when StudioAdvanceFrame moves across a frame boundry
+ bool m_bSequenceLoops; // true if the sequence loops
+ bool m_bResetSequenceInfoOnLoad; // true if a ResetSequenceInfo was queued up during dynamic load
+ float m_flDissolveStartTime;
+
+ // was pev->frame
+ CNetworkVar( float, m_flCycle );
+ CNetworkVar( int, m_nSequence );
+ CNetworkArray( float, m_flPoseParameter, NUM_POSEPAREMETERS ); // must be private so manual mode works!
+ CNetworkArray( float, m_flEncodedController, NUM_BONECTRLS ); // bone controller setting (0..1)
+
+ // Client-side animation (useful for looping animation objects)
+ CNetworkVar( bool, m_bClientSideAnimation );
+ CNetworkVar( bool, m_bClientSideFrameReset );
+
+ CNetworkVar( int, m_nNewSequenceParity );
+ CNetworkVar( int, m_nResetEventsParity );
+
+ // Incremented each time the entity is told to do a muzzle flash.
+ // The client picks up the change and draws the flash.
+ CNetworkVar( unsigned char, m_nMuzzleFlashParity );
+
+ CNetworkHandle( CBaseEntity, m_hLightingOrigin );
+ CNetworkHandle( CBaseEntity, m_hLightingOriginRelative );
+
+ string_t m_iszLightingOriginRelative; // for reading from the file only
+ string_t m_iszLightingOrigin; // for reading from the file only
+
+ memhandle_t m_boneCacheHandle;
+ unsigned short m_fBoneCacheFlags; // Used for bone cache state on model
+
+protected:
+ CNetworkVar( float, m_fadeMinDist ); // Point at which fading is absolute
+ CNetworkVar( float, m_fadeMaxDist ); // Point at which fading is inactive
+ CNetworkVar( float, m_flFadeScale ); // Scale applied to min / max
+
+public:
+ COutputEvent m_OnIgnite;
+
+private:
+ CStudioHdr *m_pStudioHdr;
+ CThreadFastMutex m_StudioHdrInitLock;
+ CThreadFastMutex m_BoneSetupMutex;
+
+// FIXME: necessary so that cyclers can hack m_bSequenceFinished
+friend class CFlexCycler;
+friend class CCycler;
+friend class CBlendingCycler;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: return a pointer to an updated studiomdl cache cache
+//-----------------------------------------------------------------------------
+inline CStudioHdr *CBaseAnimating::GetModelPtr( void )
+{
+ if ( IsDynamicModelLoading() )
+ return NULL;
+
+#ifdef _DEBUG
+ if ( !HushAsserts() )
+ {
+ // 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 && GetModel() )
+ {
+ LockStudioHdr();
+ }
+ return ( m_pStudioHdr && m_pStudioHdr->IsValid() ) ? m_pStudioHdr : NULL;
+}
+
+inline void CBaseAnimating::InvalidateMdlCache()
+{
+ UnlockStudioHdr();
+ if ( m_pStudioHdr != NULL )
+ {
+ delete m_pStudioHdr;
+ m_pStudioHdr = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Serves the 90% case of calling SetSequence / ResetSequenceInfo.
+//-----------------------------------------------------------------------------
+
+/*
+inline void CBaseAnimating::ResetSequence(int nSequence)
+{
+ m_nSequence = nSequence;
+ ResetSequenceInfo();
+}
+*/
+
+inline float CBaseAnimating::GetPlaybackRate()
+{
+ return m_flPlaybackRate;
+}
+
+inline void CBaseAnimating::SetPlaybackRate( float rate )
+{
+ m_flPlaybackRate = rate;
+}
+
+inline void CBaseAnimating::SetLightingOrigin( CBaseEntity *pLightingOrigin )
+{
+ m_hLightingOrigin = pLightingOrigin;
+}
+
+inline CBaseEntity *CBaseAnimating::GetLightingOrigin()
+{
+ return m_hLightingOrigin;
+}
+
+inline void CBaseAnimating::SetLightingOriginRelative( CBaseEntity *pLightingOriginRelative )
+{
+ m_hLightingOriginRelative = pLightingOriginRelative;
+}
+
+inline CBaseEntity *CBaseAnimating::GetLightingOriginRelative()
+{
+ return m_hLightingOriginRelative;
+}
+
+//-----------------------------------------------------------------------------
+// Cycle access
+//-----------------------------------------------------------------------------
+inline float CBaseAnimating::GetCycle() const
+{
+ return m_flCycle;
+}
+
+inline void CBaseAnimating::SetCycle( float flCycle )
+{
+ m_flCycle = flCycle;
+}
+
+
+EXTERN_SEND_TABLE(DT_BaseAnimating);
+
+
+
+#define ANIMATION_SEQUENCE_BITS 12 // 4096 sequences
+#define ANIMATION_SKIN_BITS 10 // 1024 body skin selections FIXME: this seems way high
+#define ANIMATION_BODY_BITS 32 // body combinations
+#define ANIMATION_HITBOXSET_BITS 2 // hit box sets
+#if defined( TF_DLL )
+#define ANIMATION_POSEPARAMETER_BITS 8 // pose parameter resolution
+#else
+#define ANIMATION_POSEPARAMETER_BITS 11 // pose parameter resolution
+#endif
+#define ANIMATION_PLAYBACKRATE_BITS 8 // default playback rate, only used on leading edge detect sequence changes
+
+#endif // BASEANIMATING_H