Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
- //
- // Purpose:
- //
- //=============================================================================//
- #ifndef INTERPOLATEDVAR_H
- #define INTERPOLATEDVAR_H
- #ifdef _WIN32
- #pragma once
- #endif
- #include "tier1/utllinkedlist.h"
- #include "rangecheckedvar.h"
- #include "lerp_functions.h"
- #include "animationlayer.h"
- #include "convar.h"
- #include "tier0/memdbgon.h"
- #define COMPARE_HISTORY(a,b) \
- ( memcmp( m_VarHistory[a].GetValue(), m_VarHistory[b].GetValue(), sizeof(Type)*GetMaxCount() ) == 0 )
- // Define this to have it measure whether or not the interpolated entity list
- // is accurate.
- //#define INTERPOLATEDVAR_PARANOID_MEASUREMENT
- #define LATCH_ANIMATION_VAR (1<<0) // use AnimTime as sample basis
- #define LATCH_SIMULATION_VAR (1<<1) // use SimulationTime as sample basis
- #define EXCLUDE_AUTO_LATCH (1<<2)
- #define EXCLUDE_AUTO_INTERPOLATE (1<<3)
- #define INTERPOLATE_LINEAR_ONLY (1<<4) // don't do hermite interpolation
- #define INTERPOLATE_OMIT_UPDATE_LAST_NETWORKED (1<<5)
- #define EXTRA_INTERPOLATION_HISTORY_STORED 0.05f // It stores this much extra interpolation history,
- // so you can always call Interpolate() this far
- // in the past from your last call and be able to
- // get an interpolated value.
- // this global keeps the last known server packet tick (to avoid calling engine->GetLastTimestamp() all the time)
- extern float g_flLastPacketTimestamp;
- inline void Interpolation_SetLastPacketTimeStamp( float timestamp)
- {
- Assert( timestamp > 0 );
- g_flLastPacketTimestamp = timestamp;
- }
- // Before calling Interpolate(), you can use this use this to setup the context if
- // you want to enable extrapolation.
- class CInterpolationContext
- {
- public:
- CInterpolationContext()
- {
- m_bOldAllowExtrapolation = s_bAllowExtrapolation;
- m_flOldLastTimeStamp = s_flLastTimeStamp;
- // By default, disable extrapolation unless they call EnableExtrapolation.
- s_bAllowExtrapolation = false;
- // this is the context stack
- m_pNext = s_pHead;
- s_pHead = this;
- }
- ~CInterpolationContext()
- {
- // restore values from prev stack element
- s_bAllowExtrapolation = m_bOldAllowExtrapolation;
- s_flLastTimeStamp = m_flOldLastTimeStamp;
- Assert( s_pHead == this );
- s_pHead = m_pNext;
- }
- static void EnableExtrapolation(bool state)
- {
- s_bAllowExtrapolation = state;
- }
- static bool IsThereAContext()
- {
- return s_pHead != NULL;
- }
- static bool IsExtrapolationAllowed()
- {
- return s_bAllowExtrapolation;
- }
- static void SetLastTimeStamp(float timestamp)
- {
- s_flLastTimeStamp = timestamp;
- }
- static float GetLastTimeStamp()
- {
- return s_flLastTimeStamp;
- }
- private:
- CInterpolationContext *m_pNext;
- bool m_bOldAllowExtrapolation;
- float m_flOldLastTimeStamp;
- static CInterpolationContext *s_pHead;
- static bool s_bAllowExtrapolation;
- static float s_flLastTimeStamp;
- };
- extern ConVar cl_extrapolate_amount;
- template< class T >
- inline T ExtrapolateInterpolatedVarType( const T &oldVal, const T &newVal, float divisor, float flExtrapolationAmount )
- {
- return newVal;
- }
- inline Vector ExtrapolateInterpolatedVarType( const Vector &oldVal, const Vector &newVal, float divisor, float flExtrapolationAmount )
- {
- return Lerp( 1.0f + flExtrapolationAmount * divisor, oldVal, newVal );
- }
- inline float ExtrapolateInterpolatedVarType( const float &oldVal, const float &newVal, float divisor, float flExtrapolationAmount )
- {
- return Lerp( 1.0f + flExtrapolationAmount * divisor, oldVal, newVal );
- }
- inline QAngle ExtrapolateInterpolatedVarType( const QAngle &oldVal, const QAngle &newVal, float divisor, float flExtrapolationAmount )
- {
- return Lerp<QAngle>( 1.0f + flExtrapolationAmount * divisor, oldVal, newVal );
- }
- // -------------------------------------------------------------------------------------------------------------- //
- // IInterpolatedVar interface.
- // -------------------------------------------------------------------------------------------------------------- //
- abstract_class IInterpolatedVar
- {
- public:
- virtual ~IInterpolatedVar() {}
- virtual void Setup( void *pValue, int type ) = 0;
- virtual void SetInterpolationAmount( float seconds ) = 0;
- // Returns true if the new value is different from the prior most recent value.
- virtual void NoteLastNetworkedValue() = 0;
- virtual bool NoteChanged( float changetime, bool bUpdateLastNetworkedValue ) = 0;
- virtual void Reset() = 0;
- // Returns 1 if the value will always be the same if currentTime is always increasing.
- virtual int Interpolate( float currentTime ) = 0;
- virtual int GetType() const = 0;
- virtual void RestoreToLastNetworked() = 0;
- virtual void Copy( IInterpolatedVar *pSrc ) = 0;
- virtual const char *GetDebugName() = 0;
- virtual void SetDebugName( const char* pName ) = 0;
- };
- template< typename Type, bool IS_ARRAY >
- struct CInterpolatedVarEntryBase
- {
- CInterpolatedVarEntryBase()
- {
- value = NULL;
- count = 0;
- changetime = 0;
- }
- ~CInterpolatedVarEntryBase()
- {
- delete[] value;
- value = NULL;
- }
- // This will transfer the data from another varentry. This is used to avoid allocation
- // pointers can be transferred (only one varentry has a copy), but not trivially copied
- void FastTransferFrom( CInterpolatedVarEntryBase &src )
- {
- Assert(!value);
- value = src.value;
- count = src.count;
- changetime = src.changetime;
- src.value = 0;
- src.count = 0;
- }
- CInterpolatedVarEntryBase& operator=( const CInterpolatedVarEntryBase& src )
- {
- delete[] value;
- value = NULL;
- count = 0;
- if ( src.value )
- {
- count = src.count;
- value = new Type[count];
- for ( int i = 0; i < count; i++ )
- {
- value[i] = src.value[i];
- }
- }
- return *this;
- }
- Type *GetValue() { return value; }
- const Type *GetValue() const { return value; }
- void Init(int maxCount)
- {
- if ( !maxCount )
- {
- DeleteEntry();
- }
- else
- {
- // resize
- if ( maxCount != count )
- {
- DeleteEntry();
- }
- if ( !value )
- {
- count = maxCount;
- value = new Type[maxCount];
- }
- }
- Assert(count==maxCount);
- }
- Type *NewEntry( const Type *pValue, int maxCount, float time )
- {
- changetime = time;
- Init(maxCount);
- if ( value && maxCount)
- {
- memcpy( value, pValue, maxCount*sizeof(Type) );
- }
- return value;
- }
- void DeleteEntry()
- {
- delete[] value;
- value = NULL;
- count = 0;
- }
- float changetime;
- int count;
- Type * value;
- private:
- CInterpolatedVarEntryBase( const CInterpolatedVarEntryBase &src );
- };
- template<typename Type>
- struct CInterpolatedVarEntryBase<Type, false>
- {
- CInterpolatedVarEntryBase() {}
- ~CInterpolatedVarEntryBase() {}
- const Type *GetValue() const { return &value; }
- Type *GetValue() { return &value; }
- void Init(int maxCount)
- {
- Assert(maxCount==1);
- }
- Type *NewEntry( const Type *pValue, int maxCount, float time )
- {
- Assert(maxCount==1);
- changetime = time;
- memcpy( &value, pValue, maxCount*sizeof(Type) );
- return &value;
- }
- void FastTransferFrom( CInterpolatedVarEntryBase &src )
- {
- *this = src;
- }
- void DeleteEntry() {}
- float changetime;
- Type value;
- };
- template<typename T>
- class CSimpleRingBuffer
- {
- public:
- CSimpleRingBuffer( int startSize = 4 )
- {
- m_pElements = 0;
- m_maxElement = 0;
- m_firstElement = 0;
- m_count = 0;
- m_growSize = 16;
- EnsureCapacity(startSize);
- }
- ~CSimpleRingBuffer()
- {
- delete[] m_pElements;
- m_pElements = NULL;
- }
- inline int Count() const { return m_count; }
- int Head() const { return (m_count>0) ? 0 : InvalidIndex(); }
- bool IsIdxValid( int i ) const { return (i >= 0 && i < m_count) ? true : false; }
- bool IsValidIndex(int i) const { return IsIdxValid(i); }
- static int InvalidIndex() { return -1; }
- T& operator[]( int i )
- {
- Assert( IsIdxValid(i) );
- i += m_firstElement;
- i = WrapRange(i);
- return m_pElements[i];
- }
- const T& operator[]( int i ) const
- {
- Assert( IsIdxValid(i) );
- i += m_firstElement;
- i = WrapRange(i);
- return m_pElements[i];
- }
- void EnsureCapacity( int capSize )
- {
- if ( capSize > m_maxElement )
- {
- int newMax = m_maxElement + ((capSize+m_growSize-1)/m_growSize) * m_growSize;
- T *pNew = new T[newMax];
- for ( int i = 0; i < m_maxElement; i++ )
- {
- // ------------
- // If you wanted to make this a more generic container you'd probably want this code
- // instead - since FastTransferFrom() is an optimization dependent on types stored
- // here defining this operation.
- //pNew[i] = m_pElements[WrapRange(i+m_firstElement)];
- pNew[i].FastTransferFrom( m_pElements[WrapRange(i+m_firstElement)] );
- // ------------
- }
- m_firstElement = 0;
- m_maxElement = newMax;
- delete[] m_pElements;
- m_pElements = pNew;
- }
- }
- int AddToHead()
- {
- EnsureCapacity( m_count + 1 );
- int i = m_firstElement + m_maxElement - 1;
- m_count++;
- i = WrapRange(i);
- m_firstElement = i;
- return 0;
- }
- int AddToHead( const T &elem )
- {
- AddToHead();
- m_pElements[m_firstElement] = elem;
- return 0;
- }
- int AddToTail()
- {
- EnsureCapacity( m_count + 1 );
- m_count++;
- return WrapRange(m_firstElement+m_count-1);
- }
- void RemoveAll()
- {
- m_count = 0;
- m_firstElement = 0;
- }
- void RemoveAtHead()
- {
- if ( m_count > 0 )
- {
- m_firstElement = WrapRange(m_firstElement+1);
- m_count--;
- }
- }
- void Truncate( int newLength )
- {
- if ( newLength < m_count )
- {
- Assert(newLength>=0);
- m_count = newLength;
- }
- }
- private:
- inline int WrapRange( int i ) const
- {
- return ( i >= m_maxElement ) ? (i - m_maxElement) : i;
- }
- T *m_pElements;
- unsigned short m_maxElement;
- unsigned short m_firstElement;
- unsigned short m_count;
- unsigned short m_growSize;
- };
- // -------------------------------------------------------------------------------------------------------------- //
- // CInterpolatedVarArrayBase - the main implementation of IInterpolatedVar.
- // -------------------------------------------------------------------------------------------------------------- //
- template< typename Type, bool IS_ARRAY>
- class CInterpolatedVarArrayBase : public IInterpolatedVar
- {
- public:
- friend class CInterpolatedVarPrivate;
- CInterpolatedVarArrayBase( const char *pDebugName="no debug name" );
- virtual ~CInterpolatedVarArrayBase();
- // IInterpolatedVar overrides.
- public:
- virtual void Setup( void *pValue, int type );
- virtual void SetInterpolationAmount( float seconds );
- virtual void NoteLastNetworkedValue();
- virtual bool NoteChanged( float changetime, bool bUpdateLastNetworkedValue );
- virtual void Reset();
- virtual int Interpolate( float currentTime );
- virtual int GetType() const;
- virtual void RestoreToLastNetworked();
- virtual void Copy( IInterpolatedVar *pInSrc );
- virtual const char *GetDebugName() { return m_pDebugName; }
- public:
- // Just like the IInterpolatedVar functions, but you can specify an interpolation amount.
- bool NoteChanged( float changetime, float interpolation_amount, bool bUpdateLastNetworkedValue );
- int Interpolate( float currentTime, float interpolation_amount );
- void DebugInterpolate( Type *pOut, float currentTime );
- void GetDerivative( Type *pOut, float currentTime );
- void GetDerivative_SmoothVelocity( Type *pOut, float currentTime ); // See notes on ::Derivative_HermiteLinearVelocity for info.
- void ClearHistory();
- void AddToHead( float changeTime, const Type* values, bool bFlushNewer );
- const Type& GetPrev( int iArrayIndex=0 ) const;
- const Type& GetCurrent( int iArrayIndex=0 ) const;
- // Returns the time difference betweem the most recent sample and its previous sample.
- float GetInterval() const;
- bool IsValidIndex( int i );
- Type *GetHistoryValue( int index, float& changetime, int iArrayIndex=0 );
- int GetHead() { return 0; }
- int GetNext( int i )
- {
- int next = i + 1;
- if ( !m_VarHistory.IsValidIndex(next) )
- return m_VarHistory.InvalidIndex();
- return next;
- }
- void SetHistoryValuesForItem( int item, Type& value );
- void SetLooping( bool looping, int iArrayIndex=0 );
- void SetMaxCount( int newmax );
- int GetMaxCount() const;
- // Get the time of the oldest entry.
- float GetOldestEntry();
- // set a debug name (if not provided by constructor)
- void SetDebugName(const char *pName ) { m_pDebugName = pName; }
- bool GetInterpolationInfo( float currentTime, int *pNewer, int *pOlder, int *pOldest );
- protected:
- typedef CInterpolatedVarEntryBase<Type, IS_ARRAY> CInterpolatedVarEntry;
- typedef CSimpleRingBuffer< CInterpolatedVarEntry > CVarHistory;
- friend class CInterpolationInfo;
- class CInterpolationInfo
- {
- public:
- bool m_bHermite;
- int oldest; // Only set if using hermite.
- int older;
- int newer;
- float frac;
- };
- protected:
- void RemoveOldEntries( float oldesttime );
- void RemoveEntriesPreviousTo( float flTime );
- bool GetInterpolationInfo(
- CInterpolationInfo *pInfo,
- float currentTime,
- float interpolation_amount,
- int *pNoMoreChanges );
- void TimeFixup_Hermite(
- CInterpolatedVarEntry &fixup,
- CInterpolatedVarEntry*& prev,
- CInterpolatedVarEntry*& start,
- CInterpolatedVarEntry*& end );
- // Force the time between prev and start to be dt (and extend prev out farther if necessary).
- void TimeFixup2_Hermite(
- CInterpolatedVarEntry &fixup,
- CInterpolatedVarEntry*& prev,
- CInterpolatedVarEntry*& start,
- float dt
- );
- void _Extrapolate(
- Type *pOut,
- CInterpolatedVarEntry *pOld,
- CInterpolatedVarEntry *pNew,
- float flDestinationTime,
- float flMaxExtrapolationAmount
- );
- void _Interpolate( Type *out, float frac, CInterpolatedVarEntry *start, CInterpolatedVarEntry *end );
- void _Interpolate_Hermite( Type *out, float frac, CInterpolatedVarEntry *pOriginalPrev, CInterpolatedVarEntry *start, CInterpolatedVarEntry *end, bool looping = false );
- void _Derivative_Hermite( Type *out, float frac, CInterpolatedVarEntry *pOriginalPrev, CInterpolatedVarEntry *start, CInterpolatedVarEntry *end );
- void _Derivative_Hermite_SmoothVelocity( Type *out, float frac, CInterpolatedVarEntry *b, CInterpolatedVarEntry *c, CInterpolatedVarEntry *d );
- void _Derivative_Linear( Type *out, CInterpolatedVarEntry *start, CInterpolatedVarEntry *end );
- bool ValidOrder();
- protected:
- // The underlying data element
- Type *m_pValue;
- CVarHistory m_VarHistory;
- // Store networked values so when we latch we can detect which values were changed via networking
- Type * m_LastNetworkedValue;
- float m_LastNetworkedTime;
- byte m_fType;
- byte m_nMaxCount;
- byte * m_bLooping;
- float m_InterpolationAmount;
- const char * m_pDebugName;
- };
- template< typename Type, bool IS_ARRAY >
- inline CInterpolatedVarArrayBase<Type, IS_ARRAY>::CInterpolatedVarArrayBase( const char *pDebugName )
- {
- m_pDebugName = pDebugName;
- m_pValue = NULL;
- m_fType = LATCH_ANIMATION_VAR;
- m_InterpolationAmount = 0.0f;
- m_nMaxCount = 0;
- m_LastNetworkedTime = 0;
- m_LastNetworkedValue = NULL;
- m_bLooping = NULL;
- }
- template< typename Type, bool IS_ARRAY >
- inline CInterpolatedVarArrayBase<Type, IS_ARRAY>::~CInterpolatedVarArrayBase()
- {
- ClearHistory();
- delete [] m_bLooping;
- delete [] m_LastNetworkedValue;
- }
- template< typename Type, bool IS_ARRAY >
- inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::Setup( void *pValue, int type )
- {
- m_pValue = ( Type * )pValue;
- m_fType = type;
- }
- template< typename Type, bool IS_ARRAY >
- inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::SetInterpolationAmount( float seconds )
- {
- m_InterpolationAmount = seconds;
- }
- template< typename Type, bool IS_ARRAY >
- inline int CInterpolatedVarArrayBase<Type, IS_ARRAY>::GetType() const
- {
- return m_fType;
- }
- template< typename Type, bool IS_ARRAY >
- void CInterpolatedVarArrayBase<Type, IS_ARRAY>::NoteLastNetworkedValue()
- {
- memcpy( m_LastNetworkedValue, m_pValue, m_nMaxCount * sizeof( Type ) );
- m_LastNetworkedTime = g_flLastPacketTimestamp;
- }
- template< typename Type, bool IS_ARRAY >
- inline bool CInterpolatedVarArrayBase<Type, IS_ARRAY>::NoteChanged( float changetime, float interpolation_amount, bool bUpdateLastNetworkedValue )
- {
- Assert( m_pValue );
- // This is a big optimization where it can potentially avoid expensive interpolation
- // involving this variable if it didn't get an actual new value in here.
- bool bRet = true;
- if ( m_VarHistory.Count() )
- {
- if ( memcmp( m_pValue, m_VarHistory[0].GetValue(), sizeof( Type ) * m_nMaxCount ) == 0 )
- {
- bRet = false;
- }
- }
- AddToHead( changetime, m_pValue, true );
- if ( bUpdateLastNetworkedValue )
- {
- NoteLastNetworkedValue();
- }
- #if 0
- // Since we don't clean out the old entries until Interpolate(), make sure that there
- // aren't any super old entries hanging around.
- RemoveOldEntries( gpGlobals->curtime - interpolation_amount - 2.0f );
- #else
- // JAY: It doesn't seem like the above code is correct. This is keeping more than two seconds of history
- // for variables that aren't being interpolated for some reason. For example, the player model isn't drawn
- // in first person, so the history is only truncated here and will accumulate ~40 entries instead of 2 or 3
- // changing over to the method in Interpolate() means that we always have a 3-sample neighborhood around
- // any data we're going to need. Unless gpGlobals->curtime is different when samples are added vs. when
- // they are interpolated I can't see this having any ill effects.
- RemoveEntriesPreviousTo( gpGlobals->curtime - interpolation_amount - EXTRA_INTERPOLATION_HISTORY_STORED );
- #endif
- return bRet;
- }
- template< typename Type, bool IS_ARRAY >
- inline bool CInterpolatedVarArrayBase<Type, IS_ARRAY>::NoteChanged( float changetime, bool bUpdateLastNetworkedValue )
- {
- return NoteChanged( changetime, m_InterpolationAmount, bUpdateLastNetworkedValue );
- }
- template< typename Type, bool IS_ARRAY >
- inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::RestoreToLastNetworked()
- {
- Assert( m_pValue );
- memcpy( m_pValue, m_LastNetworkedValue, m_nMaxCount * sizeof( Type ) );
- }
- template< typename Type, bool IS_ARRAY >
- inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::ClearHistory()
- {
- for ( int i = 0; i < m_VarHistory.Count(); i++ )
- {
- m_VarHistory[i].DeleteEntry();
- }
- m_VarHistory.RemoveAll();
- }
- template< typename Type, bool IS_ARRAY >
- inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::AddToHead( float changeTime, const Type* values, bool bFlushNewer )
- {
- MEM_ALLOC_CREDIT_CLASS();
- int newslot;
- if ( bFlushNewer )
- {
- // Get rid of anything that has a timestamp after this sample. The server might have
- // corrected our clock and moved us back, so our current changeTime is less than a
- // changeTime we added samples during previously.
- while ( m_VarHistory.Count() )
- {
- if ( (m_VarHistory[0].changetime+0.0001f) > changeTime )
- {
- m_VarHistory.RemoveAtHead();
- }
- else
- {
- break;
- }
- }
- newslot = m_VarHistory.AddToHead();
- }
- else
- {
- newslot = m_VarHistory.AddToHead();
- for ( int i = 1; i < m_VarHistory.Count(); i++ )
- {
- if ( m_VarHistory[i].changetime <= changeTime )
- break;
- m_VarHistory[newslot].FastTransferFrom( m_VarHistory[i] );
- newslot = i;
- }
- }
- CInterpolatedVarEntry *e = &m_VarHistory[ newslot ];
- e->NewEntry( values, m_nMaxCount, changeTime );
- }
- template< typename Type, bool IS_ARRAY >
- inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::Reset()
- {
- ClearHistory();
- if ( m_pValue )
- {
- AddToHead( gpGlobals->curtime, m_pValue, false );
- AddToHead( gpGlobals->curtime, m_pValue, false );
- AddToHead( gpGlobals->curtime, m_pValue, false );
- memcpy( m_LastNetworkedValue, m_pValue, m_nMaxCount * sizeof( Type ) );
- }
- }
- template< typename Type, bool IS_ARRAY >
- inline float CInterpolatedVarArrayBase<Type, IS_ARRAY>::GetOldestEntry()
- {
- float lastVal = 0;
- if ( m_VarHistory.Count() )
- {
- lastVal = m_VarHistory[m_VarHistory.Count()-1].changetime;
- }
- return lastVal;
- }
- template< typename Type, bool IS_ARRAY >
- inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::RemoveOldEntries( float oldesttime )
- {
- int newCount = m_VarHistory.Count();
- for ( int i = m_VarHistory.Count(); --i > 2; )
- {
- if ( m_VarHistory[i].changetime > oldesttime )
- break;
- newCount = i;
- }
- m_VarHistory.Truncate(newCount);
- }
- template< typename Type, bool IS_ARRAY >
- inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::RemoveEntriesPreviousTo( float flTime )
- {
- for ( int i = 0; i < m_VarHistory.Count(); i++ )
- {
- if ( m_VarHistory[i].changetime < flTime )
- {
- // We need to preserve this sample (ie: the one right before this timestamp)
- // and the sample right before it (for hermite blending), and we can get rid
- // of everything else.
- m_VarHistory.Truncate( i + 3 );
- break;
- }
- }
- }
- template< typename Type, bool IS_ARRAY >
- inline bool CInterpolatedVarArrayBase<Type, IS_ARRAY>::GetInterpolationInfo(
- typename CInterpolatedVarArrayBase<Type, IS_ARRAY>::CInterpolationInfo *pInfo,
- float currentTime,
- float interpolation_amount,
- int *pNoMoreChanges
- )
- {
- Assert( m_pValue );
- CVarHistory &varHistory = m_VarHistory;
- float targettime = currentTime - interpolation_amount;
- pInfo->m_bHermite = false;
- pInfo->frac = 0;
- pInfo->oldest = pInfo->older = pInfo->newer = varHistory.InvalidIndex();
- for ( int i = 0; i < varHistory.Count(); i++ )
- {
- pInfo->older = i;
- float older_change_time = m_VarHistory[ i ].changetime;
- if ( older_change_time == 0.0f )
- break;
- if ( targettime < older_change_time )
- {
- pInfo->newer = pInfo->older;
- continue;
- }
- if ( pInfo->newer == varHistory.InvalidIndex() )
- {
- // Have it linear interpolate between the newest 2 entries.
- pInfo->newer = pInfo->older;
- // Since the time given is PAST all of our entries, then as long
- // as time continues to increase, we'll be returning the same value.
- if ( pNoMoreChanges )
- *pNoMoreChanges = 1;
- return true;
- }
- float newer_change_time = varHistory[ pInfo->newer ].changetime;
- float dt = newer_change_time - older_change_time;
- if ( dt > 0.0001f )
- {
- pInfo->frac = ( targettime - older_change_time ) / ( newer_change_time - older_change_time );
- pInfo->frac = min( pInfo->frac, 2.0f );
- int oldestindex = i+1;
- if ( !(m_fType & INTERPOLATE_LINEAR_ONLY) && varHistory.IsIdxValid(oldestindex) )
- {
- pInfo->oldest = oldestindex;
- float oldest_change_time = varHistory[ oldestindex ].changetime;
- float dt2 = older_change_time - oldest_change_time;
- if ( dt2 > 0.0001f )
- {
- pInfo->m_bHermite = true;
- }
- }
- // If pInfo->newer is the most recent entry we have, and all 2 or 3 other
- // entries are identical, then we're always going to return the same value
- // if currentTime increases.
- if ( pNoMoreChanges && pInfo->newer == m_VarHistory.Head() )
- {
- if ( COMPARE_HISTORY( pInfo->newer, pInfo->older ) )
- {
- if ( !pInfo->m_bHermite || COMPARE_HISTORY( pInfo->newer, pInfo->oldest ) )
- *pNoMoreChanges = 1;
- }
- }
- }
- return true;
- }
- // Didn't find any, return last entry???
- if ( pInfo->newer != varHistory.InvalidIndex() )
- {
- pInfo->older = pInfo->newer;
- return true;
- }
- // This is the single-element case
- pInfo->newer = pInfo->older;
- return (pInfo->older != varHistory.InvalidIndex());
- }
- template< typename Type, bool IS_ARRAY >
- inline bool CInterpolatedVarArrayBase<Type, IS_ARRAY>::GetInterpolationInfo( float currentTime, int *pNewer, int *pOlder, int *pOldest )
- {
- CInterpolationInfo info;
- bool result = GetInterpolationInfo( &info, currentTime, m_InterpolationAmount, NULL );
- if (pNewer)
- *pNewer = (int)info.newer;
- if (pOlder)
- *pOlder = (int)info.older;
- if (pOldest)
- *pOldest = (int)info.oldest;
- return result;
- }
- template< typename Type, bool IS_ARRAY >
- inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::DebugInterpolate( Type *pOut, float currentTime )
- {
- float interpolation_amount = m_InterpolationAmount;
- int noMoreChanges = 0;
- CInterpolationInfo info;
- GetInterpolationInfo( &info, currentTime, interpolation_amount, &noMoreChanges );
- CVarHistory &history = m_VarHistory;
- if ( info.m_bHermite )
- {
- // base cast, we have 3 valid sample point
- _Interpolate_Hermite( pOut, info.frac, &history[info.oldest], &history[info.older], &history[info.newer] );
- }
- else if ( info.newer == info.older )
- {
- // This means the server clock got way behind the client clock. Extrapolate the value here based on its
- // previous velocity (out to a certain amount).
- int realOlder = info.newer+1;
- if ( CInterpolationContext::IsExtrapolationAllowed() &&
- IsValidIndex( realOlder ) &&
- history[realOlder].changetime != 0.0 &&
- interpolation_amount > 0.000001f &&
- CInterpolationContext::GetLastTimeStamp() <= m_LastNetworkedTime )
- {
- // At this point, we know we're out of data and we have the ability to get a velocity to extrapolate with.
- //
- // However, we only want to extraploate if the server is choking. We don't want to extrapolate if
- // the object legimately stopped moving and the server stopped sending updates for it.
- //
- // The way we know that the server is choking is if we haven't heard ANYTHING from it for a while.
- // The server's update interval should be at least as often as our interpolation amount (otherwise,
- // we wouldn't have the ability to interpolate).
- //
- // So right here, if we see that we haven't gotten any server updates since the last interpolation
- // history update to this entity (and since we're in here, we know that we're out of interpolation data),
- // then we can assume that the server is choking and decide to extrapolate.
- //
- // The End
- // Use the velocity here (extrapolate up to 1/4 of a second).
- _Extrapolate( pOut, &history[realOlder], &history[info.newer], currentTime - interpolation_amount, cl_extrapolate_amount.GetFloat() );
- }
- else
- {
- _Interpolate( pOut, info.frac, &history[info.older], &history[info.newer] );
- }
- }
- else
- {
- _Interpolate( pOut, info.frac, &history[info.older], &history[info.newer] );
- }
- }
- template< typename Type, bool IS_ARRAY >
- inline int CInterpolatedVarArrayBase<Type, IS_ARRAY>::Interpolate( float currentTime, float interpolation_amount )
- {
- int noMoreChanges = 0;
- CInterpolationInfo info;
- if (!GetInterpolationInfo( &info, currentTime, interpolation_amount, &noMoreChanges ))
- return noMoreChanges;
- CVarHistory &history = m_VarHistory;
- #ifdef INTERPOLATEDVAR_PARANOID_MEASUREMENT
- Type *backupValues = (Type*)_alloca( m_nMaxCount * sizeof(Type) );
- memcpy( backupValues, m_pValue, sizeof( Type ) * m_nMaxCount );
- #endif
- if ( info.m_bHermite )
- {
- // base cast, we have 3 valid sample point
- _Interpolate_Hermite( m_pValue, info.frac, &history[info.oldest], &history[info.older], &history[info.newer] );
- }
- else if ( info.newer == info.older )
- {
- // This means the server clock got way behind the client clock. Extrapolate the value here based on its
- // previous velocity (out to a certain amount).
- int realOlder = info.newer+1;
- if ( CInterpolationContext::IsExtrapolationAllowed() &&
- IsValidIndex( realOlder ) &&
- history[realOlder].changetime != 0.0 &&
- interpolation_amount > 0.000001f &&
- CInterpolationContext::GetLastTimeStamp() <= m_LastNetworkedTime )
- {
- // At this point, we know we're out of data and we have the ability to get a velocity to extrapolate with.
- //
- // However, we only want to extraploate if the server is choking. We don't want to extrapolate if
- // the object legimately stopped moving and the server stopped sending updates for it.
- //
- // The way we know that the server is choking is if we haven't heard ANYTHING from it for a while.
- // The server's update interval should be at least as often as our interpolation amount (otherwise,
- // we wouldn't have the ability to interpolate).
- //
- // So right here, if we see that we haven't gotten any server updates since the last interpolation
- // history update to this entity (and since we're in here, we know that we're out of interpolation data),
- // then we can assume that the server is choking and decide to extrapolate.
- //
- // The End
- // Use the velocity here (extrapolate up to 1/4 of a second).
- _Extrapolate( m_pValue, &history[realOlder], &history[info.newer], currentTime - interpolation_amount, cl_extrapolate_amount.GetFloat() );
- }
- else
- {
- _Interpolate( m_pValue, info.frac, &history[info.older], &history[info.newer] );
- }
- }
- else
- {
- _Interpolate( m_pValue, info.frac, &history[info.older], &history[info.newer] );
- }
- #ifdef INTERPOLATEDVAR_PARANOID_MEASUREMENT
- if ( memcmp( backupValues, m_pValue, sizeof( Type ) * m_nMaxCount ) != 0 )
- {
- extern int g_nInterpolatedVarsChanged;
- extern bool g_bRestoreInterpolatedVarValues;
- ++g_nInterpolatedVarsChanged;
- // This undoes the work that we do in here so if someone is in the debugger, they
- // can find out which variable changed.
- if ( g_bRestoreInterpolatedVarValues )
- {
- memcpy( m_pValue, backupValues, sizeof( Type ) * m_nMaxCount );
- return noMoreChanges;
- }
- }
- #endif
- // Clear out all entries before the oldest since we should never access them again.
- // Usually, Interpolate() calls never go backwards in time, but C_BaseAnimating::BecomeRagdollOnClient for one
- // goes slightly back in time
- RemoveEntriesPreviousTo( currentTime - interpolation_amount - EXTRA_INTERPOLATION_HISTORY_STORED );
- return noMoreChanges;
- }
- template< typename Type, bool IS_ARRAY >
- void CInterpolatedVarArrayBase<Type, IS_ARRAY>::GetDerivative( Type *pOut, float currentTime )
- {
- CInterpolationInfo info;
- if (!GetInterpolationInfo( &info, currentTime, m_InterpolationAmount, NULL ))
- return;
- if ( info.m_bHermite )
- {
- _Derivative_Hermite( pOut, info.frac, &m_VarHistory[info.oldest], &m_VarHistory[info.older], &m_VarHistory[info.newer] );
- }
- else
- {
- _Derivative_Linear( pOut, &m_VarHistory[info.older], &m_VarHistory[info.newer] );
- }
- }
- template< typename Type, bool IS_ARRAY >
- void CInterpolatedVarArrayBase<Type, IS_ARRAY>::GetDerivative_SmoothVelocity( Type *pOut, float currentTime )
- {
- CInterpolationInfo info;
- if (!GetInterpolationInfo( &info, currentTime, m_InterpolationAmount, NULL ))
- return;
- CVarHistory &history = m_VarHistory;
- bool bExtrapolate = false;
- int realOlder = 0;
- if ( info.m_bHermite )
- {
- _Derivative_Hermite_SmoothVelocity( pOut, info.frac, &history[info.oldest], &history[info.older], &history[info.newer] );
- return;
- }
- else if ( info.newer == info.older && CInterpolationContext::IsExtrapolationAllowed() )
- {
- // This means the server clock got way behind the client clock. Extrapolate the value here based on its
- // previous velocity (out to a certain amount).
- realOlder = info.newer+1;
- if ( IsValidIndex( realOlder ) && history[realOlder].changetime != 0.0 )
- {
- // At this point, we know we're out of data and we have the ability to get a velocity to extrapolate with.
- //
- // However, we only want to extraploate if the server is choking. We don't want to extrapolate if
- // the object legimately stopped moving and the server stopped sending updates for it.
- //
- // The way we know that the server is choking is if we haven't heard ANYTHING from it for a while.
- // The server's update interval should be at least as often as our interpolation amount (otherwise,
- // we wouldn't have the ability to interpolate).
- //
- // So right here, if we see that we haven't gotten any server updates for a whole interpolation
- // interval, then we know the server is choking.
- //
- // The End
- if ( m_InterpolationAmount > 0.000001f &&
- CInterpolationContext::GetLastTimeStamp() <= (currentTime - m_InterpolationAmount) )
- {
- bExtrapolate = true;
- }
- }
- }
- if ( bExtrapolate )
- {
- // Get the velocity from the last segment.
- _Derivative_Linear( pOut, &history[realOlder], &history[info.newer] );
- // Now ramp it to zero after cl_extrapolate_amount..
- float flDestTime = currentTime - m_InterpolationAmount;
- float diff = flDestTime - history[info.newer].changetime;
- diff = clamp( diff, 0, cl_extrapolate_amount.GetFloat() * 2 );
- if ( diff > cl_extrapolate_amount.GetFloat() )
- {
- float scale = 1 - (diff - cl_extrapolate_amount.GetFloat()) / cl_extrapolate_amount.GetFloat();
- for ( int i=0; i < m_nMaxCount; i++ )
- {
- pOut[i] *= scale;
- }
- }
- }
- else
- {
- _Derivative_Linear( pOut, &history[info.older], &history[info.newer] );
- }
- }
- template< typename Type, bool IS_ARRAY >
- inline int CInterpolatedVarArrayBase<Type, IS_ARRAY>::Interpolate( float currentTime )
- {
- return Interpolate( currentTime, m_InterpolationAmount );
- }
- template< typename Type, bool IS_ARRAY >
- inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::Copy( IInterpolatedVar *pInSrc )
- {
- CInterpolatedVarArrayBase<Type, IS_ARRAY> *pSrc = dynamic_cast< CInterpolatedVarArrayBase<Type, IS_ARRAY>* >( pInSrc );
- if ( !pSrc || pSrc->m_nMaxCount != m_nMaxCount )
- {
- Assert( false );
- return;
- }
- Assert( (m_fType & ~EXCLUDE_AUTO_INTERPOLATE) == (pSrc->m_fType & ~EXCLUDE_AUTO_INTERPOLATE) );
- Assert( m_pDebugName == pSrc->GetDebugName() );
- for ( int i=0; i < m_nMaxCount; i++ )
- {
- m_LastNetworkedValue[i] = pSrc->m_LastNetworkedValue[i];
- m_bLooping[i] = pSrc->m_bLooping[i];
- }
- m_LastNetworkedTime = pSrc->m_LastNetworkedTime;
- // Copy the entries.
- m_VarHistory.RemoveAll();
- for ( int i = 0; i < pSrc->m_VarHistory.Count(); i++ )
- {
- int newslot = m_VarHistory.AddToTail();
- CInterpolatedVarEntry *dest = &m_VarHistory[newslot];
- CInterpolatedVarEntry *src = &pSrc->m_VarHistory[i];
- dest->NewEntry( src->GetValue(), m_nMaxCount, src->changetime );
- }
- }
- template< typename Type, bool IS_ARRAY >
- inline const Type& CInterpolatedVarArrayBase<Type, IS_ARRAY>::GetPrev( int iArrayIndex ) const
- {
- Assert( m_pValue );
- Assert( iArrayIndex >= 0 && iArrayIndex < m_nMaxCount );
- if ( m_VarHistory.Count() > 1 )
- {
- return m_VarHistory[1].GetValue()[iArrayIndex];
- }
- return m_pValue[ iArrayIndex ];
- }
- template< typename Type, bool IS_ARRAY >
- inline const Type& CInterpolatedVarArrayBase<Type, IS_ARRAY>::GetCurrent( int iArrayIndex ) const
- {
- Assert( m_pValue );
- Assert( iArrayIndex >= 0 && iArrayIndex < m_nMaxCount );
- if ( m_VarHistory.Count() > 0 )
- {
- return m_VarHistory[0].GetValue()[iArrayIndex];
- }
- return m_pValue[ iArrayIndex ];
- }
- template< typename Type, bool IS_ARRAY >
- inline float CInterpolatedVarArrayBase<Type, IS_ARRAY>::GetInterval() const
- {
- if ( m_VarHistory.Count() > 1 )
- {
- return m_VarHistory[0].changetime - m_VarHistory[1].changetime;
- }
- return 0.0f;
- }
- template< typename Type, bool IS_ARRAY >
- inline bool CInterpolatedVarArrayBase<Type, IS_ARRAY>::IsValidIndex( int i )
- {
- return m_VarHistory.IsValidIndex( i );
- }
- template< typename Type, bool IS_ARRAY >
- inline Type *CInterpolatedVarArrayBase<Type, IS_ARRAY>::GetHistoryValue( int index, float& changetime, int iArrayIndex )
- {
- Assert( iArrayIndex >= 0 && iArrayIndex < m_nMaxCount );
- if ( m_VarHistory.IsIdxValid(index) )
- {
- CInterpolatedVarEntry *entry = &m_VarHistory[ index ];
- changetime = entry->changetime;
- return &entry->GetValue()[ iArrayIndex ];
- }
- else
- {
- changetime = 0.0f;
- return NULL;
- }
- }
- template< typename Type, bool IS_ARRAY >
- inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::SetHistoryValuesForItem( int item, Type& value )
- {
- Assert( item >= 0 && item < m_nMaxCount );
- for ( int i = 0; i < m_VarHistory.Count(); i++ )
- {
- CInterpolatedVarEntry *entry = &m_VarHistory[ i ];
- entry->GetValue()[ item ] = value;
- }
- }
- template< typename Type, bool IS_ARRAY >
- inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::SetLooping( bool looping, int iArrayIndex )
- {
- Assert( iArrayIndex >= 0 && iArrayIndex < m_nMaxCount );
- m_bLooping[ iArrayIndex ] = looping;
- }
- template< typename Type, bool IS_ARRAY >
- inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::SetMaxCount( int newmax )
- {
- bool changed = ( newmax != m_nMaxCount ) ? true : false;
- // BUGBUG: Support 0 length properly?
- newmax = max(1,newmax);
- m_nMaxCount = newmax;
- // Wipe everything any time this changes!!!
- if ( changed )
- {
- delete [] m_bLooping;
- delete [] m_LastNetworkedValue;
- m_bLooping = new byte[m_nMaxCount];
- m_LastNetworkedValue = new Type[m_nMaxCount];
- memset( m_bLooping, 0, sizeof(byte) * m_nMaxCount);
- memset( m_LastNetworkedValue, 0, sizeof(Type) * m_nMaxCount);
- Reset();
- }
- }
- template< typename Type, bool IS_ARRAY >
- inline int CInterpolatedVarArrayBase<Type, IS_ARRAY>::GetMaxCount() const
- {
- return m_nMaxCount;
- }
- template< typename Type, bool IS_ARRAY >
- inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::_Interpolate( Type *out, float frac, CInterpolatedVarEntry *start, CInterpolatedVarEntry *end )
- {
- Assert( start );
- Assert( end );
- if ( start == end )
- {
- // quick exit
- for ( int i = 0; i < m_nMaxCount; i++ )
- {
- out[i] = end->GetValue()[i];
- Lerp_Clamp( out[i] );
- }
- return;
- }
- Assert( frac >= 0.0f && frac <= 1.0f );
- // Note that QAngle has a specialization that will do quaternion interpolation here...
- for ( int i = 0; i < m_nMaxCount; i++ )
- {
- if ( m_bLooping[ i ] )
- {
- out[i] = LoopingLerp( frac, start->GetValue()[i], end->GetValue()[i] );
- }
- else
- {
- out[i] = Lerp( frac, start->GetValue()[i], end->GetValue()[i] );
- }
- Lerp_Clamp( out[i] );
- }
- }
- template< typename Type, bool IS_ARRAY >
- inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::_Extrapolate(
- Type *pOut,
- CInterpolatedVarEntry *pOld,
- CInterpolatedVarEntry *pNew,
- float flDestinationTime,
- float flMaxExtrapolationAmount
- )
- {
- if ( fabs( pOld->changetime - pNew->changetime ) < 0.001f || flDestinationTime <= pNew->changetime )
- {
- for ( int i=0; i < m_nMaxCount; i++ )
- pOut[i] = pNew->GetValue()[i];
- }
- else
- {
- float flExtrapolationAmount = min( flDestinationTime - pNew->changetime, flMaxExtrapolationAmount );
- float divisor = 1.0f / (pNew->changetime - pOld->changetime);
- for ( int i=0; i < m_nMaxCount; i++ )
- {
- pOut[i] = ExtrapolateInterpolatedVarType( pOld->GetValue()[i], pNew->GetValue()[i], divisor, flExtrapolationAmount );
- }
- }
- }
- template< typename Type, bool IS_ARRAY >
- inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::TimeFixup2_Hermite(
- typename CInterpolatedVarArrayBase<Type, IS_ARRAY>::CInterpolatedVarEntry &fixup,
- typename CInterpolatedVarArrayBase<Type, IS_ARRAY>::CInterpolatedVarEntry*& prev,
- typename CInterpolatedVarArrayBase<Type, IS_ARRAY>::CInterpolatedVarEntry*& start,
- float dt1
- )
- {
- float dt2 = start->changetime - prev->changetime;
- // If times are not of the same interval renormalize the earlier sample to allow for uniform hermite spline interpolation
- if ( fabs( dt1 - dt2 ) > 0.0001f &&
- dt2 > 0.0001f )
- {
- // Renormalize
- float frac = dt1 / dt2;
- // Fixed interval into past
- fixup.changetime = start->changetime - dt1;
- for ( int i = 0; i < m_nMaxCount; i++ )
- {
- if ( m_bLooping[i] )
- {
- fixup.GetValue()[i] = LoopingLerp( 1-frac, prev->GetValue()[i], start->GetValue()[i] );
- }
- else
- {
- fixup.GetValue()[i] = Lerp( 1-frac, prev->GetValue()[i], start->GetValue()[i] );
- }
- }
- // Point previous sample at fixed version
- prev = &fixup;
- }
- }
- template< typename Type, bool IS_ARRAY >
- inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::TimeFixup_Hermite(
- typename CInterpolatedVarArrayBase<Type, IS_ARRAY>::CInterpolatedVarEntry &fixup,
- typename CInterpolatedVarArrayBase<Type, IS_ARRAY>::CInterpolatedVarEntry*& prev,
- typename CInterpolatedVarArrayBase<Type, IS_ARRAY>::CInterpolatedVarEntry*& start,
- typename CInterpolatedVarArrayBase<Type, IS_ARRAY>::CInterpolatedVarEntry*& end )
- {
- TimeFixup2_Hermite( fixup, prev, start, end->changetime - start->changetime );
- }
- template< typename Type, bool IS_ARRAY >
- inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::_Interpolate_Hermite(
- Type *out,
- float frac,
- CInterpolatedVarEntry *prev,
- CInterpolatedVarEntry *start,
- CInterpolatedVarEntry *end,
- bool looping )
- {
- Assert( start );
- Assert( end );
- // Disable range checks because we can produce weird values here and it's not an error.
- // After interpolation, we will clamp the values.
- CDisableRangeChecks disableRangeChecks;
- CInterpolatedVarEntry fixup;
- fixup.Init(m_nMaxCount);
- TimeFixup_Hermite( fixup, prev, start, end );
- for( int i = 0; i < m_nMaxCount; i++ )
- {
- // Note that QAngle has a specialization that will do quaternion interpolation here...
- if ( m_bLooping[ i ] )
- {
- out[ i ] = LoopingLerp_Hermite( frac, prev->GetValue()[i], start->GetValue()[i], end->GetValue()[i] );
- }
- else
- {
- out[ i ] = Lerp_Hermite( frac, prev->GetValue()[i], start->GetValue()[i], end->GetValue()[i] );
- }
- // Clamp the output from interpolation. There are edge cases where something like m_flCycle
- // can get set to a really high or low value when we set it to zero after a really small
- // time interval (the hermite blender will think it's got a really high velocity and
- // skyrocket it off into la-la land).
- Lerp_Clamp( out[i] );
- }
- }
- template< typename Type, bool IS_ARRAY >
- inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::_Derivative_Hermite(
- Type *out,
- float frac,
- CInterpolatedVarEntry *prev,
- CInterpolatedVarEntry *start,
- CInterpolatedVarEntry *end )
- {
- Assert( start );
- Assert( end );
- // Disable range checks because we can produce weird values here and it's not an error.
- // After interpolation, we will clamp the values.
- CDisableRangeChecks disableRangeChecks;
- CInterpolatedVarEntry fixup;
- fixup.value = (Type*)_alloca( sizeof(Type) * m_nMaxCount );
- TimeFixup_Hermite( fixup, prev, start, end );
- float divisor = 1.0f / (end->changetime - start->changetime);
- for( int i = 0; i < m_nMaxCount; i++ )
- {
- Assert( !m_bLooping[ i ] );
- out[i] = Derivative_Hermite( frac, prev->GetValue()[i], start->GetValue()[i], end->GetValue()[i] );
- out[i] *= divisor;
- }
- }
- template< typename Type, bool IS_ARRAY >
- inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::_Derivative_Hermite_SmoothVelocity(
- Type *out,
- float frac,
- CInterpolatedVarEntry *b,
- CInterpolatedVarEntry *c,
- CInterpolatedVarEntry *d )
- {
- CInterpolatedVarEntry fixup;
- fixup.Init(m_nMaxCount);
- TimeFixup_Hermite( fixup, b, c, d );
- for ( int i=0; i < m_nMaxCount; i++ )
- {
- Type prevVel = (c->GetValue()[i] - b->GetValue()[i]) / (c->changetime - b->changetime);
- Type curVel = (d->GetValue()[i] - c->GetValue()[i]) / (d->changetime - c->changetime);
- out[i] = Lerp( frac, prevVel, curVel );
- }
- }
- template< typename Type, bool IS_ARRAY >
- inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::_Derivative_Linear(
- Type *out,
- CInterpolatedVarEntry *start,
- CInterpolatedVarEntry *end )
- {
- if ( start == end || fabs( start->changetime - end->changetime ) < 0.0001f )
- {
- for( int i = 0; i < m_nMaxCount; i++ )
- {
- out[ i ] = start->GetValue()[i] * 0;
- }
- }
- else
- {
- float divisor = 1.0f / (end->changetime - start->changetime);
- for( int i = 0; i < m_nMaxCount; i++ )
- {
- out[ i ] = (end->GetValue()[i] - start->GetValue()[i]) * divisor;
- }
- }
- }
- template< typename Type, bool IS_ARRAY >
- inline bool CInterpolatedVarArrayBase<Type, IS_ARRAY>::ValidOrder()
- {
- float newestchangetime = 0.0f;
- bool first = true;
- for ( int i = 0; i < m_VarHistory.Count(); i++ )
- {
- CInterpolatedVarEntry *entry = &m_VarHistory[ i ];
- if ( first )
- {
- first = false;
- newestchangetime = entry->changetime;
- continue;
- }
- // They should get older as wel walk backwards
- if ( entry->changetime > newestchangetime )
- {
- Assert( 0 );
- return false;
- }
- newestchangetime = entry->changetime;
- }
- return true;
- }
- template< typename Type, int COUNT >
- class CInterpolatedVarArray : public CInterpolatedVarArrayBase<Type, true >
- {
- public:
- CInterpolatedVarArray( const char *pDebugName = "no debug name" )
- : CInterpolatedVarArrayBase<Type, true>( pDebugName )
- {
- SetMaxCount( COUNT );
- }
- };
- // -------------------------------------------------------------------------------------------------------------- //
- // CInterpolatedVar.
- // -------------------------------------------------------------------------------------------------------------- //
- template< typename Type >
- class CInterpolatedVar : public CInterpolatedVarArrayBase< Type, false >
- {
- public:
- CInterpolatedVar( const char *pDebugName = NULL )
- : CInterpolatedVarArrayBase< Type, false >(pDebugName)
- {
- SetMaxCount( 1 );
- }
- };
- #include "tier0/memdbgoff.h"
- #endif // INTERPOLATEDVAR_H
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement