Advertisement
Guest User

interpolation

a guest
Nov 20th, 2015
2,018
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 44.86 KB | None | 0 0
  1. //========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6.  
  7. #ifndef INTERPOLATEDVAR_H
  8. #define INTERPOLATEDVAR_H
  9. #ifdef _WIN32
  10. #pragma once
  11. #endif
  12.  
  13. #include "tier1/utllinkedlist.h"
  14. #include "rangecheckedvar.h"
  15. #include "lerp_functions.h"
  16. #include "animationlayer.h"
  17. #include "convar.h"
  18.  
  19.  
  20. #include "tier0/memdbgon.h"
  21.  
  22. #define COMPARE_HISTORY(a,b) \
  23.     ( memcmp( m_VarHistory[a].GetValue(), m_VarHistory[b].GetValue(), sizeof(Type)*GetMaxCount() ) == 0 )          
  24.  
  25. // Define this to have it measure whether or not the interpolated entity list
  26. // is accurate.
  27. //#define INTERPOLATEDVAR_PARANOID_MEASUREMENT
  28.  
  29.  
  30. #define LATCH_ANIMATION_VAR  (1<<0)     // use AnimTime as sample basis
  31. #define LATCH_SIMULATION_VAR (1<<1)     // use SimulationTime as sample basis
  32.  
  33. #define EXCLUDE_AUTO_LATCH          (1<<2)
  34. #define EXCLUDE_AUTO_INTERPOLATE    (1<<3)
  35.  
  36. #define INTERPOLATE_LINEAR_ONLY     (1<<4)  // don't do hermite interpolation
  37. #define INTERPOLATE_OMIT_UPDATE_LAST_NETWORKED (1<<5)
  38.  
  39.  
  40.  
  41. #define EXTRA_INTERPOLATION_HISTORY_STORED 0.05f    // It stores this much extra interpolation history,
  42.                                                     // so you can always call Interpolate() this far
  43.                                                     // in the past from your last call and be able to
  44.                                                     // get an interpolated value.
  45.  
  46. // this global keeps the last known server packet tick (to avoid calling engine->GetLastTimestamp() all the time)
  47. extern float g_flLastPacketTimestamp;
  48.  
  49. inline void Interpolation_SetLastPacketTimeStamp( float timestamp)
  50. {
  51.     Assert( timestamp > 0 );
  52.     g_flLastPacketTimestamp = timestamp;
  53. }
  54.  
  55.  
  56. // Before calling Interpolate(), you can use this use this to setup the context if
  57. // you want to enable extrapolation.
  58. class CInterpolationContext
  59. {
  60. public:
  61.    
  62.     CInterpolationContext()
  63.     {
  64.         m_bOldAllowExtrapolation = s_bAllowExtrapolation;
  65.         m_flOldLastTimeStamp = s_flLastTimeStamp;
  66.  
  67.         // By default, disable extrapolation unless they call EnableExtrapolation.
  68.         s_bAllowExtrapolation = false;
  69.  
  70.         // this is the context stack
  71.         m_pNext = s_pHead;
  72.         s_pHead = this;
  73.     }
  74.    
  75.     ~CInterpolationContext()
  76.     {
  77.         // restore values from prev stack element
  78.         s_bAllowExtrapolation = m_bOldAllowExtrapolation;
  79.         s_flLastTimeStamp = m_flOldLastTimeStamp;
  80.  
  81.         Assert( s_pHead == this );
  82.         s_pHead = m_pNext;
  83.     }
  84.  
  85.     static void EnableExtrapolation(bool state)
  86.     {
  87.         s_bAllowExtrapolation = state;
  88.     }
  89.  
  90.     static bool IsThereAContext()
  91.     {
  92.         return s_pHead != NULL;
  93.     }
  94.  
  95.     static bool IsExtrapolationAllowed()
  96.     {
  97.         return s_bAllowExtrapolation;
  98.     }
  99.  
  100.     static void SetLastTimeStamp(float timestamp)
  101.     {
  102.         s_flLastTimeStamp = timestamp;
  103.     }
  104.    
  105.     static float GetLastTimeStamp()
  106.     {
  107.         return s_flLastTimeStamp;
  108.     }
  109.  
  110.  
  111. private:
  112.  
  113.     CInterpolationContext *m_pNext;
  114.     bool m_bOldAllowExtrapolation;
  115.     float m_flOldLastTimeStamp;
  116.  
  117.     static CInterpolationContext *s_pHead;
  118.     static bool s_bAllowExtrapolation;
  119.     static float s_flLastTimeStamp;
  120. };
  121.  
  122.  
  123. extern ConVar cl_extrapolate_amount;
  124.  
  125.  
  126. template< class T >
  127. inline T ExtrapolateInterpolatedVarType( const T &oldVal, const T &newVal, float divisor, float flExtrapolationAmount )
  128. {
  129.     return newVal;
  130. }
  131.  
  132. inline Vector ExtrapolateInterpolatedVarType( const Vector &oldVal, const Vector &newVal, float divisor, float flExtrapolationAmount )
  133. {
  134.     return Lerp( 1.0f + flExtrapolationAmount * divisor, oldVal, newVal );
  135. }
  136.  
  137. inline float ExtrapolateInterpolatedVarType( const float &oldVal, const float &newVal, float divisor, float flExtrapolationAmount )
  138. {
  139.     return Lerp( 1.0f + flExtrapolationAmount * divisor, oldVal, newVal );
  140. }
  141.  
  142. inline QAngle ExtrapolateInterpolatedVarType( const QAngle &oldVal, const QAngle &newVal, float divisor, float flExtrapolationAmount )
  143. {
  144.     return Lerp<QAngle>( 1.0f + flExtrapolationAmount * divisor, oldVal, newVal );
  145. }
  146.  
  147.  
  148. // -------------------------------------------------------------------------------------------------------------- //
  149. // IInterpolatedVar interface.
  150. // -------------------------------------------------------------------------------------------------------------- //
  151.  
  152. abstract_class IInterpolatedVar
  153. {
  154. public:
  155.     virtual      ~IInterpolatedVar() {}
  156.  
  157.     virtual void Setup( void *pValue, int type ) = 0;
  158.     virtual void SetInterpolationAmount( float seconds ) = 0;
  159.    
  160.     // Returns true if the new value is different from the prior most recent value.
  161.     virtual void NoteLastNetworkedValue() = 0;
  162.     virtual bool NoteChanged( float changetime, bool bUpdateLastNetworkedValue ) = 0;
  163.     virtual void Reset() = 0;
  164.    
  165.     // Returns 1 if the value will always be the same if currentTime is always increasing.
  166.     virtual int Interpolate( float currentTime ) = 0;
  167.    
  168.     virtual int  GetType() const = 0;
  169.     virtual void RestoreToLastNetworked() = 0;
  170.     virtual void Copy( IInterpolatedVar *pSrc ) = 0;
  171.  
  172.     virtual const char *GetDebugName() = 0;
  173.     virtual void SetDebugName( const char* pName )  = 0;
  174. };
  175.  
  176. template< typename Type, bool IS_ARRAY >
  177. struct CInterpolatedVarEntryBase
  178. {
  179.     CInterpolatedVarEntryBase()
  180.     {
  181.         value = NULL;
  182.         count = 0;
  183.         changetime = 0;
  184.     }
  185.     ~CInterpolatedVarEntryBase()
  186.     {
  187.         delete[] value;
  188.         value = NULL;
  189.     }
  190.  
  191.     // This will transfer the data from another varentry.  This is used to avoid allocation
  192.     // pointers can be transferred (only one varentry has a copy), but not trivially copied
  193.     void FastTransferFrom( CInterpolatedVarEntryBase &src )
  194.     {
  195.         Assert(!value);
  196.         value = src.value;
  197.         count = src.count;
  198.         changetime = src.changetime;
  199.         src.value = 0;
  200.         src.count = 0;
  201.     }
  202.  
  203.     CInterpolatedVarEntryBase& operator=( const CInterpolatedVarEntryBase& src )
  204.     {
  205.         delete[] value;
  206.         value = NULL;
  207.         count = 0;
  208.         if ( src.value )
  209.         {
  210.             count = src.count;
  211.             value = new Type[count];
  212.             for ( int i = 0; i < count; i++ )
  213.             {
  214.                 value[i] = src.value[i];
  215.             }
  216.         }
  217.         return *this;
  218.     }
  219.  
  220.     Type *GetValue() { return value; }
  221.     const Type *GetValue() const { return value; }
  222.  
  223.     void Init(int maxCount)
  224.     {
  225.         if ( !maxCount )
  226.         {
  227.             DeleteEntry();
  228.         }
  229.         else
  230.         {
  231.             // resize
  232.             if ( maxCount != count )
  233.             {
  234.                 DeleteEntry();
  235.             }
  236.  
  237.             if ( !value )
  238.             {
  239.                 count = maxCount;
  240.                 value = new Type[maxCount];
  241.             }
  242.         }
  243.         Assert(count==maxCount);
  244.     }
  245.     Type *NewEntry( const Type *pValue, int maxCount, float time )
  246.     {
  247.         changetime = time;
  248.         Init(maxCount);
  249.         if ( value && maxCount)
  250.         {
  251.             memcpy( value, pValue, maxCount*sizeof(Type) );
  252.         }
  253.         return value;
  254.     }
  255.  
  256.     void DeleteEntry()
  257.     {
  258.         delete[] value;
  259.         value = NULL;
  260.         count = 0;
  261.     }
  262.  
  263.     float       changetime;
  264.     int         count;
  265.     Type *      value;
  266.  
  267. private:
  268.     CInterpolatedVarEntryBase( const CInterpolatedVarEntryBase &src );
  269. };
  270.  
  271. template<typename Type>
  272. struct CInterpolatedVarEntryBase<Type, false>
  273. {
  274.     CInterpolatedVarEntryBase() {}
  275.     ~CInterpolatedVarEntryBase() {}
  276.  
  277.     const Type *GetValue() const { return &value; }
  278.     Type *GetValue() { return &value; }
  279.  
  280.     void Init(int maxCount)
  281.     {
  282.         Assert(maxCount==1);
  283.     }
  284.     Type *NewEntry( const Type *pValue, int maxCount, float time )
  285.     {
  286.         Assert(maxCount==1);
  287.         changetime = time;
  288.         memcpy( &value, pValue, maxCount*sizeof(Type) );
  289.         return &value;
  290.     }
  291.     void FastTransferFrom( CInterpolatedVarEntryBase &src )
  292.     {
  293.         *this = src;
  294.     }
  295.  
  296.     void DeleteEntry() {}
  297.  
  298.     float       changetime;
  299.     Type        value;
  300. };
  301.  
  302. template<typename T>
  303. class CSimpleRingBuffer
  304. {
  305. public:
  306.     CSimpleRingBuffer( int startSize = 4 )
  307.     {
  308.         m_pElements = 0;
  309.         m_maxElement = 0;
  310.         m_firstElement = 0;
  311.         m_count = 0;
  312.         m_growSize = 16;
  313.         EnsureCapacity(startSize);
  314.     }
  315.     ~CSimpleRingBuffer()
  316.     {
  317.         delete[] m_pElements;
  318.         m_pElements = NULL;
  319.     }
  320.  
  321.     inline int Count() const { return m_count; }
  322.  
  323.     int Head() const { return (m_count>0) ? 0 : InvalidIndex(); }
  324.  
  325.     bool IsIdxValid( int i ) const { return (i >= 0 && i < m_count) ? true : false; }
  326.     bool IsValidIndex(int i) const { return IsIdxValid(i); }
  327.     static int InvalidIndex() { return -1; }
  328.  
  329.     T& operator[]( int i )
  330.     {
  331.         Assert( IsIdxValid(i) );
  332.         i += m_firstElement;
  333.         i = WrapRange(i);
  334.         return m_pElements[i];
  335.     }
  336.  
  337.     const T& operator[]( int i ) const
  338.     {
  339.         Assert( IsIdxValid(i) );
  340.         i += m_firstElement;
  341.         i = WrapRange(i);
  342.         return m_pElements[i];
  343.     }
  344.  
  345.     void EnsureCapacity( int capSize )
  346.     {
  347.         if ( capSize > m_maxElement )
  348.         {
  349.             int newMax = m_maxElement + ((capSize+m_growSize-1)/m_growSize) * m_growSize;
  350.             T *pNew = new T[newMax];
  351.             for ( int i = 0; i < m_maxElement; i++ )
  352.             {
  353.                 // ------------
  354.                 // If you wanted to make this a more generic container you'd probably want this code
  355.                 // instead - since FastTransferFrom() is an optimization dependent on types stored
  356.                 // here defining this operation.
  357.                 //pNew[i] = m_pElements[WrapRange(i+m_firstElement)];
  358.                 pNew[i].FastTransferFrom( m_pElements[WrapRange(i+m_firstElement)] );
  359.                 // ------------
  360.             }
  361.             m_firstElement = 0;
  362.             m_maxElement = newMax;
  363.             delete[] m_pElements;
  364.             m_pElements = pNew;
  365.         }
  366.     }
  367.  
  368.     int AddToHead()
  369.     {
  370.         EnsureCapacity( m_count + 1 );
  371.         int i = m_firstElement + m_maxElement - 1;
  372.         m_count++;
  373.         i = WrapRange(i);
  374.         m_firstElement = i;
  375.         return 0;
  376.     }
  377.  
  378.     int AddToHead( const T &elem )
  379.     {
  380.         AddToHead();
  381.         m_pElements[m_firstElement] = elem;
  382.         return 0;
  383.     }
  384.  
  385.     int AddToTail()
  386.     {
  387.         EnsureCapacity( m_count + 1 );
  388.         m_count++;
  389.         return WrapRange(m_firstElement+m_count-1);
  390.     }
  391.  
  392.     void RemoveAll()
  393.     {
  394.         m_count = 0;
  395.         m_firstElement = 0;
  396.     }
  397.  
  398.     void RemoveAtHead()
  399.     {
  400.         if ( m_count > 0 )
  401.         {
  402.             m_firstElement = WrapRange(m_firstElement+1);
  403.             m_count--;
  404.         }
  405.     }
  406.  
  407.     void Truncate( int newLength )
  408.     {
  409.         if ( newLength < m_count )
  410.         {
  411.             Assert(newLength>=0);
  412.             m_count = newLength;
  413.         }
  414.     }
  415.  
  416. private:
  417.     inline int WrapRange( int i ) const
  418.     {
  419.         return ( i >= m_maxElement ) ? (i - m_maxElement) : i;
  420.     }
  421.  
  422.     T *m_pElements;
  423.     unsigned short m_maxElement;
  424.     unsigned short m_firstElement;
  425.     unsigned short m_count;
  426.     unsigned short m_growSize;
  427. };
  428.  
  429. // -------------------------------------------------------------------------------------------------------------- //
  430. // CInterpolatedVarArrayBase - the main implementation of IInterpolatedVar.
  431. // -------------------------------------------------------------------------------------------------------------- //
  432.  
  433. template< typename Type, bool IS_ARRAY>
  434. class CInterpolatedVarArrayBase : public IInterpolatedVar
  435. {
  436. public:
  437.     friend class CInterpolatedVarPrivate;
  438.  
  439.     CInterpolatedVarArrayBase( const char *pDebugName="no debug name" );
  440.     virtual ~CInterpolatedVarArrayBase();
  441.  
  442.    
  443.     // IInterpolatedVar overrides.
  444. public:
  445.    
  446.     virtual void Setup( void *pValue, int type );
  447.     virtual void SetInterpolationAmount( float seconds );
  448.     virtual void NoteLastNetworkedValue();
  449.     virtual bool NoteChanged( float changetime, bool bUpdateLastNetworkedValue );
  450.     virtual void Reset();
  451.     virtual int Interpolate( float currentTime );
  452.     virtual int GetType() const;
  453.     virtual void RestoreToLastNetworked();
  454.     virtual void Copy( IInterpolatedVar *pInSrc );
  455.     virtual const char *GetDebugName() { return m_pDebugName; }
  456.  
  457.  
  458. public:
  459.  
  460.     // Just like the IInterpolatedVar functions, but you can specify an interpolation amount.
  461.     bool NoteChanged( float changetime, float interpolation_amount, bool bUpdateLastNetworkedValue );
  462.     int Interpolate( float currentTime, float interpolation_amount );
  463.  
  464.     void DebugInterpolate( Type *pOut, float currentTime );
  465.  
  466.     void GetDerivative( Type *pOut, float currentTime );
  467.     void GetDerivative_SmoothVelocity( Type *pOut, float currentTime ); // See notes on ::Derivative_HermiteLinearVelocity for info.
  468.  
  469.     void ClearHistory();
  470.     void AddToHead( float changeTime, const Type* values, bool bFlushNewer );
  471.     const Type& GetPrev( int iArrayIndex=0 ) const;
  472.     const Type& GetCurrent( int iArrayIndex=0 ) const;
  473.    
  474.     // Returns the time difference betweem the most recent sample and its previous sample.
  475.     float   GetInterval() const;
  476.     bool    IsValidIndex( int i );
  477.     Type    *GetHistoryValue( int index, float& changetime, int iArrayIndex=0 );
  478.     int     GetHead() { return 0; }
  479.     int     GetNext( int i )
  480.     {
  481.         int next = i + 1;
  482.         if ( !m_VarHistory.IsValidIndex(next) )
  483.             return m_VarHistory.InvalidIndex();
  484.         return next;
  485.     }
  486.  
  487.     void SetHistoryValuesForItem( int item, Type& value );
  488.     void    SetLooping( bool looping, int iArrayIndex=0 );
  489.    
  490.     void SetMaxCount( int newmax );
  491.     int GetMaxCount() const;
  492.  
  493.     // Get the time of the oldest entry.
  494.     float GetOldestEntry();
  495.  
  496.     // set a debug name (if not provided by constructor)
  497.     void    SetDebugName(const char *pName ) { m_pDebugName = pName; }
  498.  
  499.     bool GetInterpolationInfo( float currentTime, int *pNewer, int *pOlder, int *pOldest );
  500.  
  501. protected:
  502.  
  503.     typedef CInterpolatedVarEntryBase<Type, IS_ARRAY> CInterpolatedVarEntry;
  504.     typedef CSimpleRingBuffer< CInterpolatedVarEntry > CVarHistory;
  505.     friend class CInterpolationInfo;
  506.  
  507.     class CInterpolationInfo
  508.     {
  509.     public:
  510.         bool m_bHermite;
  511.         int oldest; // Only set if using hermite.
  512.         int older;
  513.         int newer;
  514.         float frac;
  515.     };
  516.  
  517.  
  518. protected:
  519.  
  520.     void RemoveOldEntries( float oldesttime );
  521.     void RemoveEntriesPreviousTo( float flTime );
  522.  
  523.     bool GetInterpolationInfo(
  524.         CInterpolationInfo *pInfo,
  525.         float currentTime,
  526.         float interpolation_amount,
  527.         int *pNoMoreChanges );
  528.  
  529.     void TimeFixup_Hermite(
  530.         CInterpolatedVarEntry &fixup,
  531.         CInterpolatedVarEntry*& prev,
  532.         CInterpolatedVarEntry*& start,
  533.         CInterpolatedVarEntry*& end );
  534.  
  535.     // Force the time between prev and start to be dt (and extend prev out farther if necessary).
  536.     void TimeFixup2_Hermite(
  537.         CInterpolatedVarEntry &fixup,
  538.         CInterpolatedVarEntry*& prev,
  539.         CInterpolatedVarEntry*& start,
  540.         float dt
  541.         );
  542.  
  543.     void _Extrapolate(
  544.         Type *pOut,
  545.         CInterpolatedVarEntry *pOld,
  546.         CInterpolatedVarEntry *pNew,
  547.         float flDestinationTime,
  548.         float flMaxExtrapolationAmount
  549.         );
  550.  
  551.     void _Interpolate( Type *out, float frac, CInterpolatedVarEntry *start, CInterpolatedVarEntry *end );
  552.     void _Interpolate_Hermite( Type *out, float frac, CInterpolatedVarEntry *pOriginalPrev, CInterpolatedVarEntry *start, CInterpolatedVarEntry *end, bool looping = false );
  553.    
  554.     void _Derivative_Hermite( Type *out, float frac, CInterpolatedVarEntry *pOriginalPrev, CInterpolatedVarEntry *start, CInterpolatedVarEntry *end );
  555.     void _Derivative_Hermite_SmoothVelocity( Type *out, float frac, CInterpolatedVarEntry *b, CInterpolatedVarEntry *c, CInterpolatedVarEntry *d );
  556.     void _Derivative_Linear( Type *out, CInterpolatedVarEntry *start, CInterpolatedVarEntry *end );
  557.    
  558.     bool ValidOrder();
  559.  
  560. protected:
  561.     // The underlying data element
  562.     Type                                *m_pValue;
  563.     CVarHistory                         m_VarHistory;
  564.     // Store networked values so when we latch we can detect which values were changed via networking
  565.     Type *                              m_LastNetworkedValue;
  566.     float                               m_LastNetworkedTime;
  567.     byte                                m_fType;
  568.     byte                                m_nMaxCount;
  569.     byte *                              m_bLooping;
  570.     float                               m_InterpolationAmount;
  571.     const char *                        m_pDebugName;
  572. };
  573.  
  574.  
  575. template< typename Type, bool IS_ARRAY >
  576. inline CInterpolatedVarArrayBase<Type, IS_ARRAY>::CInterpolatedVarArrayBase( const char *pDebugName )
  577. {
  578.     m_pDebugName = pDebugName;
  579.     m_pValue = NULL;
  580.     m_fType = LATCH_ANIMATION_VAR;
  581.     m_InterpolationAmount = 0.0f;
  582.     m_nMaxCount = 0;
  583.     m_LastNetworkedTime = 0;
  584.     m_LastNetworkedValue = NULL;
  585.     m_bLooping = NULL;
  586. }
  587.  
  588. template< typename Type, bool IS_ARRAY >
  589. inline CInterpolatedVarArrayBase<Type, IS_ARRAY>::~CInterpolatedVarArrayBase()
  590. {
  591.     ClearHistory();
  592.     delete [] m_bLooping;
  593.     delete [] m_LastNetworkedValue;
  594. }
  595.  
  596. template< typename Type, bool IS_ARRAY >
  597. inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::Setup( void *pValue, int type )
  598. {
  599.     m_pValue = ( Type * )pValue;
  600.     m_fType = type;
  601. }
  602.  
  603. template< typename Type, bool IS_ARRAY >
  604. inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::SetInterpolationAmount( float seconds )
  605. {
  606.     m_InterpolationAmount = seconds;
  607. }
  608.  
  609. template< typename Type, bool IS_ARRAY >
  610. inline int CInterpolatedVarArrayBase<Type, IS_ARRAY>::GetType() const
  611. {
  612.     return m_fType;
  613. }
  614.  
  615. template< typename Type, bool IS_ARRAY >
  616. void CInterpolatedVarArrayBase<Type, IS_ARRAY>::NoteLastNetworkedValue()
  617. {
  618.     memcpy( m_LastNetworkedValue, m_pValue, m_nMaxCount * sizeof( Type ) );
  619.     m_LastNetworkedTime = g_flLastPacketTimestamp;
  620. }
  621.  
  622. template< typename Type, bool IS_ARRAY >
  623. inline bool CInterpolatedVarArrayBase<Type, IS_ARRAY>::NoteChanged( float changetime, float interpolation_amount, bool bUpdateLastNetworkedValue )
  624. {
  625.     Assert( m_pValue );
  626.  
  627.     // This is a big optimization where it can potentially avoid expensive interpolation
  628.     // involving this variable if it didn't get an actual new value in here.
  629.     bool bRet = true;
  630.     if ( m_VarHistory.Count() )
  631.     {
  632.         if ( memcmp( m_pValue, m_VarHistory[0].GetValue(), sizeof( Type ) * m_nMaxCount ) == 0 )
  633.         {
  634.             bRet = false;
  635.         }
  636.     }
  637.    
  638.     AddToHead( changetime, m_pValue, true );
  639.  
  640.     if ( bUpdateLastNetworkedValue )
  641.     {
  642.         NoteLastNetworkedValue();
  643.     }
  644.    
  645. #if 0
  646.     // Since we don't clean out the old entries until Interpolate(), make sure that there
  647.     // aren't any super old entries hanging around.
  648.     RemoveOldEntries( gpGlobals->curtime - interpolation_amount - 2.0f );
  649. #else
  650.     // JAY: It doesn't seem like the above code is correct.  This is keeping more than two seconds of history
  651.     // for variables that aren't being interpolated for some reason.  For example, the player model isn't drawn
  652.     // in first person, so the history is only truncated here and will accumulate ~40 entries instead of 2 or 3
  653.     // changing over to the method in Interpolate() means that we always have a 3-sample neighborhood around
  654.     // any data we're going to need.  Unless gpGlobals->curtime is different when samples are added vs. when
  655.     // they are interpolated I can't see this having any ill effects.  
  656.     RemoveEntriesPreviousTo( gpGlobals->curtime - interpolation_amount - EXTRA_INTERPOLATION_HISTORY_STORED );
  657. #endif
  658.    
  659.     return bRet;
  660. }
  661.  
  662.  
  663. template< typename Type, bool IS_ARRAY >
  664. inline bool CInterpolatedVarArrayBase<Type, IS_ARRAY>::NoteChanged( float changetime, bool bUpdateLastNetworkedValue )
  665. {
  666.     return NoteChanged( changetime, m_InterpolationAmount, bUpdateLastNetworkedValue );
  667. }
  668.  
  669.  
  670. template< typename Type, bool IS_ARRAY >
  671. inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::RestoreToLastNetworked()
  672. {
  673.     Assert( m_pValue );
  674.     memcpy( m_pValue, m_LastNetworkedValue, m_nMaxCount * sizeof( Type ) );
  675. }
  676.  
  677. template< typename Type, bool IS_ARRAY >
  678. inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::ClearHistory()
  679. {
  680.     for ( int i = 0; i < m_VarHistory.Count(); i++ )
  681.     {
  682.         m_VarHistory[i].DeleteEntry();
  683.     }
  684.     m_VarHistory.RemoveAll();
  685. }
  686.  
  687. template< typename Type, bool IS_ARRAY >
  688. inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::AddToHead( float changeTime, const Type* values, bool bFlushNewer )
  689. {
  690.     MEM_ALLOC_CREDIT_CLASS();
  691.     int newslot;
  692.    
  693.     if ( bFlushNewer )
  694.     {
  695.         // Get rid of anything that has a timestamp after this sample. The server might have
  696.         // corrected our clock and moved us back, so our current changeTime is less than a
  697.         // changeTime we added samples during previously.
  698.         while ( m_VarHistory.Count() )
  699.         {
  700.             if ( (m_VarHistory[0].changetime+0.0001f) > changeTime )
  701.             {
  702.                 m_VarHistory.RemoveAtHead();
  703.             }
  704.             else
  705.             {
  706.                 break;
  707.             }
  708.         }
  709.  
  710.         newslot = m_VarHistory.AddToHead();
  711.     }
  712.     else
  713.     {
  714.         newslot = m_VarHistory.AddToHead();
  715.         for ( int i = 1; i < m_VarHistory.Count(); i++ )
  716.         {
  717.             if ( m_VarHistory[i].changetime <= changeTime )
  718.                 break;
  719.             m_VarHistory[newslot].FastTransferFrom( m_VarHistory[i] );
  720.             newslot = i;
  721.         }
  722.         }
  723.  
  724.     CInterpolatedVarEntry *e = &m_VarHistory[ newslot ];
  725.     e->NewEntry( values, m_nMaxCount, changeTime );
  726. }
  727.  
  728. template< typename Type, bool IS_ARRAY >
  729. inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::Reset()
  730. {
  731.     ClearHistory();
  732.  
  733.     if ( m_pValue )
  734.     {
  735.         AddToHead( gpGlobals->curtime, m_pValue, false );
  736.         AddToHead( gpGlobals->curtime, m_pValue, false );
  737.         AddToHead( gpGlobals->curtime, m_pValue, false );
  738.  
  739.         memcpy( m_LastNetworkedValue, m_pValue, m_nMaxCount * sizeof( Type ) );
  740.     }
  741. }
  742.  
  743.  
  744. template< typename Type, bool IS_ARRAY >
  745. inline float CInterpolatedVarArrayBase<Type, IS_ARRAY>::GetOldestEntry()
  746. {
  747.     float lastVal = 0;
  748.     if ( m_VarHistory.Count() )
  749.     {
  750.         lastVal = m_VarHistory[m_VarHistory.Count()-1].changetime;
  751.     }
  752.     return lastVal;
  753. }
  754.  
  755.  
  756. template< typename Type, bool IS_ARRAY >
  757. inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::RemoveOldEntries( float oldesttime )
  758. {
  759.     int newCount = m_VarHistory.Count();
  760.     for ( int i = m_VarHistory.Count(); --i > 2; )
  761.     {
  762.         if ( m_VarHistory[i].changetime > oldesttime )
  763.             break;
  764.         newCount = i;
  765.     }
  766.     m_VarHistory.Truncate(newCount);
  767. }
  768.  
  769.  
  770. template< typename Type, bool IS_ARRAY >
  771. inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::RemoveEntriesPreviousTo( float flTime )
  772. {
  773.     for ( int i = 0; i < m_VarHistory.Count(); i++ )
  774.     {
  775.         if ( m_VarHistory[i].changetime < flTime )
  776.         {
  777.             // We need to preserve this sample (ie: the one right before this timestamp)
  778.             // and the sample right before it (for hermite blending), and we can get rid
  779.             // of everything else.
  780.             m_VarHistory.Truncate( i + 3 );
  781.             break;
  782.         }
  783.     }
  784. }
  785.  
  786.  
  787. template< typename Type, bool IS_ARRAY >
  788. inline bool CInterpolatedVarArrayBase<Type, IS_ARRAY>::GetInterpolationInfo(
  789.     typename CInterpolatedVarArrayBase<Type, IS_ARRAY>::CInterpolationInfo *pInfo,
  790.     float currentTime,
  791.     float interpolation_amount,
  792.     int *pNoMoreChanges
  793.     )
  794. {
  795.     Assert( m_pValue );
  796.  
  797.     CVarHistory &varHistory = m_VarHistory;
  798.  
  799.     float targettime = currentTime - interpolation_amount;
  800.  
  801.     pInfo->m_bHermite = false;
  802.     pInfo->frac = 0;
  803.     pInfo->oldest = pInfo->older = pInfo->newer = varHistory.InvalidIndex();
  804.    
  805.     for ( int i = 0; i < varHistory.Count(); i++ )
  806.     {
  807.         pInfo->older = i;
  808.        
  809.         float older_change_time = m_VarHistory[ i ].changetime;
  810.         if ( older_change_time == 0.0f )
  811.             break;
  812.  
  813.         if ( targettime < older_change_time )
  814.         {
  815.             pInfo->newer = pInfo->older;
  816.             continue;
  817.         }
  818.  
  819.         if ( pInfo->newer == varHistory.InvalidIndex() )
  820.         {
  821.             // Have it linear interpolate between the newest 2 entries.
  822.             pInfo->newer = pInfo->older;
  823.  
  824.             // Since the time given is PAST all of our entries, then as long
  825.             // as time continues to increase, we'll be returning the same value.
  826.             if ( pNoMoreChanges )
  827.                 *pNoMoreChanges = 1;
  828.             return true;
  829.         }
  830.  
  831.         float newer_change_time = varHistory[ pInfo->newer ].changetime;
  832.         float dt = newer_change_time - older_change_time;
  833.         if ( dt > 0.0001f )
  834.         {
  835.             pInfo->frac = ( targettime - older_change_time ) / ( newer_change_time - older_change_time );
  836.             pInfo->frac = min( pInfo->frac, 2.0f );
  837.  
  838.             int oldestindex = i+1;
  839.                                                            
  840.             if ( !(m_fType & INTERPOLATE_LINEAR_ONLY) && varHistory.IsIdxValid(oldestindex) )
  841.             {
  842.                 pInfo->oldest = oldestindex;
  843.                 float oldest_change_time = varHistory[ oldestindex ].changetime;
  844.                 float dt2 = older_change_time - oldest_change_time;
  845.                 if ( dt2 > 0.0001f )
  846.                 {
  847.                     pInfo->m_bHermite = true;
  848.                 }
  849.             }
  850.  
  851.             // If pInfo->newer is the most recent entry we have, and all 2 or 3 other
  852.             // entries are identical, then we're always going to return the same value
  853.             // if currentTime increases.
  854.             if ( pNoMoreChanges && pInfo->newer == m_VarHistory.Head() )
  855.             {
  856.                  if ( COMPARE_HISTORY( pInfo->newer, pInfo->older ) )
  857.                  {
  858.                     if ( !pInfo->m_bHermite || COMPARE_HISTORY( pInfo->newer, pInfo->oldest ) )
  859.                         *pNoMoreChanges = 1;
  860.                  }
  861.             }
  862.         }
  863.         return true;
  864.     }
  865.  
  866.     // Didn't find any, return last entry???
  867.     if ( pInfo->newer != varHistory.InvalidIndex() )
  868.     {
  869.         pInfo->older = pInfo->newer;
  870.         return true;
  871.     }
  872.  
  873.  
  874.     // This is the single-element case
  875.     pInfo->newer = pInfo->older;
  876.     return (pInfo->older != varHistory.InvalidIndex());
  877. }
  878.  
  879.  
  880. template< typename Type, bool IS_ARRAY >
  881. inline bool CInterpolatedVarArrayBase<Type, IS_ARRAY>::GetInterpolationInfo( float currentTime, int *pNewer, int *pOlder, int *pOldest )
  882. {
  883.     CInterpolationInfo info;
  884.     bool result = GetInterpolationInfo( &info, currentTime, m_InterpolationAmount, NULL );
  885.  
  886.     if (pNewer)
  887.         *pNewer = (int)info.newer;
  888.  
  889.     if (pOlder)
  890.         *pOlder = (int)info.older;
  891.  
  892.     if (pOldest)
  893.         *pOldest = (int)info.oldest;
  894.  
  895.     return result;
  896. }
  897.  
  898.  
  899. template< typename Type, bool IS_ARRAY >
  900. inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::DebugInterpolate( Type *pOut, float currentTime )
  901. {
  902.     float interpolation_amount = m_InterpolationAmount;
  903.  
  904.     int noMoreChanges = 0;
  905.  
  906.     CInterpolationInfo info;
  907.     GetInterpolationInfo( &info, currentTime, interpolation_amount, &noMoreChanges );
  908.  
  909.     CVarHistory &history = m_VarHistory;
  910.  
  911.     if ( info.m_bHermite )
  912.     {
  913.         // base cast, we have 3 valid sample point
  914.         _Interpolate_Hermite( pOut, info.frac, &history[info.oldest], &history[info.older], &history[info.newer] );
  915.     }
  916.     else if ( info.newer == info.older  )
  917.     {
  918.         // This means the server clock got way behind the client clock. Extrapolate the value here based on its
  919.         // previous velocity (out to a certain amount).
  920.         int realOlder = info.newer+1;
  921.         if ( CInterpolationContext::IsExtrapolationAllowed() &&
  922.             IsValidIndex( realOlder ) &&
  923.             history[realOlder].changetime != 0.0 &&
  924.             interpolation_amount > 0.000001f &&
  925.             CInterpolationContext::GetLastTimeStamp() <= m_LastNetworkedTime )
  926.         {
  927.             // At this point, we know we're out of data and we have the ability to get a velocity to extrapolate with.
  928.             //
  929.             // However, we only want to extraploate if the server is choking. We don't want to extrapolate if
  930.             // the object legimately stopped moving and the server stopped sending updates for it.
  931.             //
  932.             // The way we know that the server is choking is if we haven't heard ANYTHING from it for a while.
  933.             // The server's update interval should be at least as often as our interpolation amount (otherwise,
  934.             // we wouldn't have the ability to interpolate).
  935.             //
  936.             // So right here, if we see that we haven't gotten any server updates since the last interpolation
  937.             // history update to this entity (and since we're in here, we know that we're out of interpolation data),
  938.             // then we can assume that the server is choking and decide to extrapolate.
  939.             //
  940.             // The End
  941.  
  942.             // Use the velocity here (extrapolate up to 1/4 of a second).
  943.             _Extrapolate( pOut, &history[realOlder], &history[info.newer], currentTime - interpolation_amount, cl_extrapolate_amount.GetFloat() );
  944.         }
  945.         else
  946.         {
  947.             _Interpolate( pOut, info.frac, &history[info.older], &history[info.newer] );
  948.         }
  949.     }
  950.     else
  951.     {
  952.         _Interpolate( pOut, info.frac, &history[info.older], &history[info.newer] );
  953.     }
  954. }
  955.  
  956. template< typename Type, bool IS_ARRAY >
  957. inline int CInterpolatedVarArrayBase<Type, IS_ARRAY>::Interpolate( float currentTime, float interpolation_amount )
  958. {
  959.     int noMoreChanges = 0;
  960.    
  961.     CInterpolationInfo info;
  962.     if (!GetInterpolationInfo( &info, currentTime, interpolation_amount, &noMoreChanges ))
  963.         return noMoreChanges;
  964.  
  965.    
  966.     CVarHistory &history = m_VarHistory;
  967.  
  968. #ifdef INTERPOLATEDVAR_PARANOID_MEASUREMENT
  969.     Type *backupValues = (Type*)_alloca( m_nMaxCount * sizeof(Type) );
  970.     memcpy( backupValues, m_pValue, sizeof( Type ) * m_nMaxCount );
  971. #endif
  972.  
  973.     if ( info.m_bHermite )
  974.     {
  975.         // base cast, we have 3 valid sample point
  976.         _Interpolate_Hermite( m_pValue, info.frac, &history[info.oldest], &history[info.older], &history[info.newer] );
  977.     }
  978.     else if ( info.newer == info.older  )
  979.     {
  980.         // This means the server clock got way behind the client clock. Extrapolate the value here based on its
  981.         // previous velocity (out to a certain amount).
  982.         int realOlder = info.newer+1;
  983.         if ( CInterpolationContext::IsExtrapolationAllowed() &&
  984.             IsValidIndex( realOlder ) &&
  985.             history[realOlder].changetime != 0.0 &&
  986.             interpolation_amount > 0.000001f &&
  987.             CInterpolationContext::GetLastTimeStamp() <= m_LastNetworkedTime )
  988.         {
  989.             // At this point, we know we're out of data and we have the ability to get a velocity to extrapolate with.
  990.             //
  991.             // However, we only want to extraploate if the server is choking. We don't want to extrapolate if
  992.             // the object legimately stopped moving and the server stopped sending updates for it.
  993.             //
  994.             // The way we know that the server is choking is if we haven't heard ANYTHING from it for a while.
  995.             // The server's update interval should be at least as often as our interpolation amount (otherwise,
  996.             // we wouldn't have the ability to interpolate).
  997.             //
  998.             // So right here, if we see that we haven't gotten any server updates since the last interpolation
  999.             // history update to this entity (and since we're in here, we know that we're out of interpolation data),
  1000.             // then we can assume that the server is choking and decide to extrapolate.
  1001.             //
  1002.             // The End
  1003.  
  1004.             // Use the velocity here (extrapolate up to 1/4 of a second).
  1005.             _Extrapolate( m_pValue, &history[realOlder], &history[info.newer], currentTime - interpolation_amount, cl_extrapolate_amount.GetFloat() );
  1006.         }
  1007.         else
  1008.         {
  1009.             _Interpolate( m_pValue, info.frac, &history[info.older], &history[info.newer] );
  1010.         }
  1011.     }
  1012.     else
  1013.     {
  1014.         _Interpolate( m_pValue, info.frac, &history[info.older], &history[info.newer] );
  1015.     }
  1016.  
  1017. #ifdef INTERPOLATEDVAR_PARANOID_MEASUREMENT
  1018.     if ( memcmp( backupValues, m_pValue, sizeof( Type ) * m_nMaxCount ) != 0 )
  1019.     {
  1020.         extern int g_nInterpolatedVarsChanged;
  1021.         extern bool g_bRestoreInterpolatedVarValues;
  1022.        
  1023.         ++g_nInterpolatedVarsChanged;
  1024.  
  1025.         // This undoes the work that we do in here so if someone is in the debugger, they
  1026.         // can find out which variable changed.
  1027.         if ( g_bRestoreInterpolatedVarValues )
  1028.         {
  1029.             memcpy( m_pValue, backupValues, sizeof( Type ) * m_nMaxCount );
  1030.             return noMoreChanges;
  1031.         }
  1032.     }
  1033. #endif
  1034.  
  1035.     // Clear out all entries before the oldest since we should never access them again.
  1036.     // Usually, Interpolate() calls never go backwards in time, but C_BaseAnimating::BecomeRagdollOnClient for one
  1037.     // goes slightly back in time
  1038.     RemoveEntriesPreviousTo( currentTime - interpolation_amount - EXTRA_INTERPOLATION_HISTORY_STORED );
  1039.     return noMoreChanges;
  1040. }
  1041.  
  1042.  
  1043. template< typename Type, bool IS_ARRAY >
  1044. void CInterpolatedVarArrayBase<Type, IS_ARRAY>::GetDerivative( Type *pOut, float currentTime )
  1045. {
  1046.     CInterpolationInfo info;
  1047.     if (!GetInterpolationInfo( &info, currentTime, m_InterpolationAmount, NULL ))
  1048.         return;
  1049.  
  1050.     if ( info.m_bHermite )
  1051.     {
  1052.         _Derivative_Hermite( pOut, info.frac, &m_VarHistory[info.oldest], &m_VarHistory[info.older], &m_VarHistory[info.newer] );
  1053.     }
  1054.     else
  1055.     {
  1056.         _Derivative_Linear( pOut, &m_VarHistory[info.older], &m_VarHistory[info.newer] );
  1057.     }
  1058. }
  1059.  
  1060.  
  1061. template< typename Type, bool IS_ARRAY >
  1062. void CInterpolatedVarArrayBase<Type, IS_ARRAY>::GetDerivative_SmoothVelocity( Type *pOut, float currentTime )
  1063. {
  1064.     CInterpolationInfo info;
  1065.     if (!GetInterpolationInfo( &info, currentTime, m_InterpolationAmount, NULL ))
  1066.         return;
  1067.  
  1068.     CVarHistory &history = m_VarHistory;
  1069.     bool bExtrapolate = false;
  1070.     int realOlder = 0;
  1071.    
  1072.     if ( info.m_bHermite )
  1073.     {
  1074.         _Derivative_Hermite_SmoothVelocity( pOut, info.frac, &history[info.oldest], &history[info.older], &history[info.newer] );
  1075.         return;
  1076.     }
  1077.     else if ( info.newer == info.older && CInterpolationContext::IsExtrapolationAllowed() )
  1078.     {
  1079.         // This means the server clock got way behind the client clock. Extrapolate the value here based on its
  1080.         // previous velocity (out to a certain amount).
  1081.         realOlder = info.newer+1;
  1082.         if ( IsValidIndex( realOlder ) && history[realOlder].changetime != 0.0 )
  1083.         {
  1084.             // At this point, we know we're out of data and we have the ability to get a velocity to extrapolate with.
  1085.             //
  1086.             // However, we only want to extraploate if the server is choking. We don't want to extrapolate if
  1087.             // the object legimately stopped moving and the server stopped sending updates for it.
  1088.             //
  1089.             // The way we know that the server is choking is if we haven't heard ANYTHING from it for a while.
  1090.             // The server's update interval should be at least as often as our interpolation amount (otherwise,
  1091.             // we wouldn't have the ability to interpolate).
  1092.             //
  1093.             // So right here, if we see that we haven't gotten any server updates for a whole interpolation
  1094.             // interval, then we know the server is choking.
  1095.             //
  1096.             // The End
  1097.             if ( m_InterpolationAmount > 0.000001f &&
  1098.                  CInterpolationContext::GetLastTimeStamp() <= (currentTime - m_InterpolationAmount) )
  1099.             {
  1100.                 bExtrapolate = true;
  1101.             }
  1102.         }
  1103.     }
  1104.  
  1105.     if ( bExtrapolate )
  1106.     {
  1107.         // Get the velocity from the last segment.
  1108.         _Derivative_Linear( pOut, &history[realOlder], &history[info.newer] );
  1109.  
  1110.         // Now ramp it to zero after cl_extrapolate_amount..
  1111.         float flDestTime = currentTime - m_InterpolationAmount;
  1112.         float diff = flDestTime - history[info.newer].changetime;
  1113.         diff = clamp( diff, 0, cl_extrapolate_amount.GetFloat() * 2 );
  1114.         if ( diff > cl_extrapolate_amount.GetFloat() )
  1115.         {
  1116.             float scale = 1 - (diff - cl_extrapolate_amount.GetFloat()) / cl_extrapolate_amount.GetFloat();
  1117.             for ( int i=0; i < m_nMaxCount; i++ )
  1118.             {
  1119.                 pOut[i] *= scale;
  1120.             }
  1121.         }
  1122.     }
  1123.     else
  1124.     {
  1125.         _Derivative_Linear( pOut, &history[info.older], &history[info.newer] );
  1126.     }
  1127.  
  1128. }
  1129.  
  1130.  
  1131. template< typename Type, bool IS_ARRAY >
  1132. inline int CInterpolatedVarArrayBase<Type, IS_ARRAY>::Interpolate( float currentTime )
  1133. {
  1134.     return Interpolate( currentTime, m_InterpolationAmount );
  1135. }
  1136.  
  1137. template< typename Type, bool IS_ARRAY >
  1138. inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::Copy( IInterpolatedVar *pInSrc )
  1139. {
  1140.     CInterpolatedVarArrayBase<Type, IS_ARRAY> *pSrc = dynamic_cast< CInterpolatedVarArrayBase<Type, IS_ARRAY>* >( pInSrc );
  1141.  
  1142.     if ( !pSrc || pSrc->m_nMaxCount != m_nMaxCount )
  1143.     {
  1144.         Assert( false );
  1145.         return;
  1146.     }
  1147.  
  1148.     Assert( (m_fType & ~EXCLUDE_AUTO_INTERPOLATE) == (pSrc->m_fType & ~EXCLUDE_AUTO_INTERPOLATE) );
  1149.     Assert( m_pDebugName == pSrc->GetDebugName() );
  1150.  
  1151.     for ( int i=0; i < m_nMaxCount; i++ )
  1152.     {
  1153.         m_LastNetworkedValue[i] = pSrc->m_LastNetworkedValue[i];
  1154.         m_bLooping[i] = pSrc->m_bLooping[i];
  1155.     }
  1156.  
  1157.     m_LastNetworkedTime = pSrc->m_LastNetworkedTime;
  1158.  
  1159.     // Copy the entries.
  1160.     m_VarHistory.RemoveAll();
  1161.  
  1162.     for ( int i = 0; i < pSrc->m_VarHistory.Count(); i++ )
  1163.     {
  1164.         int newslot = m_VarHistory.AddToTail();
  1165.  
  1166.         CInterpolatedVarEntry *dest = &m_VarHistory[newslot];
  1167.         CInterpolatedVarEntry *src  = &pSrc->m_VarHistory[i];
  1168.         dest->NewEntry( src->GetValue(), m_nMaxCount, src->changetime );
  1169.     }
  1170. }
  1171.  
  1172. template< typename Type, bool IS_ARRAY >
  1173. inline const Type& CInterpolatedVarArrayBase<Type, IS_ARRAY>::GetPrev( int iArrayIndex ) const
  1174. {
  1175.     Assert( m_pValue );
  1176.     Assert( iArrayIndex >= 0 && iArrayIndex < m_nMaxCount );
  1177.  
  1178.     if ( m_VarHistory.Count() > 1 )
  1179.     {
  1180.         return m_VarHistory[1].GetValue()[iArrayIndex];
  1181.     }
  1182.     return m_pValue[ iArrayIndex ];
  1183. }
  1184.  
  1185. template< typename Type, bool IS_ARRAY >
  1186. inline const Type& CInterpolatedVarArrayBase<Type, IS_ARRAY>::GetCurrent( int iArrayIndex ) const
  1187. {
  1188.     Assert( m_pValue );
  1189.     Assert( iArrayIndex >= 0 && iArrayIndex < m_nMaxCount );
  1190.  
  1191.     if ( m_VarHistory.Count() > 0 )
  1192.     {
  1193.         return m_VarHistory[0].GetValue()[iArrayIndex];
  1194.     }
  1195.     return m_pValue[ iArrayIndex ];
  1196. }
  1197.  
  1198. template< typename Type, bool IS_ARRAY >
  1199. inline float CInterpolatedVarArrayBase<Type, IS_ARRAY>::GetInterval() const
  1200. {  
  1201.     if ( m_VarHistory.Count() > 1 )
  1202.     {
  1203.         return m_VarHistory[0].changetime - m_VarHistory[1].changetime;
  1204.         }
  1205.  
  1206.     return 0.0f;
  1207. }
  1208.  
  1209. template< typename Type, bool IS_ARRAY >
  1210. inline bool CInterpolatedVarArrayBase<Type, IS_ARRAY>::IsValidIndex( int i )
  1211. {
  1212.     return m_VarHistory.IsValidIndex( i );
  1213. }
  1214.  
  1215. template< typename Type, bool IS_ARRAY >
  1216. inline Type *CInterpolatedVarArrayBase<Type, IS_ARRAY>::GetHistoryValue( int index, float& changetime, int iArrayIndex )
  1217. {
  1218.     Assert( iArrayIndex >= 0 && iArrayIndex < m_nMaxCount );
  1219.     if ( m_VarHistory.IsIdxValid(index) )
  1220.     {
  1221.         CInterpolatedVarEntry *entry = &m_VarHistory[ index ];
  1222.         changetime = entry->changetime;
  1223.         return &entry->GetValue()[ iArrayIndex ];
  1224.     }
  1225.     else
  1226.     {
  1227.         changetime = 0.0f;
  1228.         return NULL;
  1229.     }
  1230. }
  1231.  
  1232. template< typename Type, bool IS_ARRAY >
  1233. inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::SetHistoryValuesForItem( int item, Type& value )
  1234. {
  1235.     Assert( item >= 0 && item < m_nMaxCount );
  1236.  
  1237.     for ( int i = 0; i < m_VarHistory.Count(); i++ )
  1238.     {
  1239.         CInterpolatedVarEntry *entry = &m_VarHistory[ i ];
  1240.         entry->GetValue()[ item ] = value;
  1241.     }
  1242. }
  1243.  
  1244. template< typename Type, bool IS_ARRAY >
  1245. inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::SetLooping( bool looping, int iArrayIndex )
  1246. {
  1247.     Assert( iArrayIndex >= 0 && iArrayIndex < m_nMaxCount );
  1248.     m_bLooping[ iArrayIndex ] = looping;
  1249. }
  1250.  
  1251. template< typename Type, bool IS_ARRAY >
  1252. inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::SetMaxCount( int newmax )
  1253. {
  1254.     bool changed = ( newmax != m_nMaxCount ) ? true : false;
  1255.  
  1256.     // BUGBUG: Support 0 length properly?
  1257.     newmax = max(1,newmax);
  1258.  
  1259.     m_nMaxCount = newmax;
  1260.     // Wipe everything any time this changes!!!
  1261.     if ( changed )
  1262.     {
  1263.         delete [] m_bLooping;
  1264.         delete [] m_LastNetworkedValue;
  1265.         m_bLooping = new byte[m_nMaxCount];
  1266.         m_LastNetworkedValue = new Type[m_nMaxCount];
  1267.         memset( m_bLooping, 0, sizeof(byte) * m_nMaxCount);
  1268.         memset( m_LastNetworkedValue, 0, sizeof(Type) * m_nMaxCount);
  1269.  
  1270.         Reset();
  1271.     }
  1272. }
  1273.  
  1274.  
  1275. template< typename Type, bool IS_ARRAY >
  1276. inline int CInterpolatedVarArrayBase<Type, IS_ARRAY>::GetMaxCount() const
  1277. {
  1278.     return m_nMaxCount;
  1279. }
  1280.  
  1281.  
  1282. template< typename Type, bool IS_ARRAY >
  1283. inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::_Interpolate( Type *out, float frac, CInterpolatedVarEntry *start, CInterpolatedVarEntry *end )
  1284. {
  1285.     Assert( start );
  1286.     Assert( end );
  1287.    
  1288.     if ( start == end )
  1289.     {
  1290.         // quick exit
  1291.         for ( int i = 0; i < m_nMaxCount; i++ )
  1292.         {
  1293.             out[i] = end->GetValue()[i];
  1294.             Lerp_Clamp( out[i] );
  1295.         }
  1296.         return;
  1297.     }
  1298.  
  1299.     Assert( frac >= 0.0f && frac <= 1.0f );
  1300.  
  1301.     // Note that QAngle has a specialization that will do quaternion interpolation here...
  1302.     for ( int i = 0; i < m_nMaxCount; i++ )
  1303.     {
  1304.         if ( m_bLooping[ i ] )
  1305.         {
  1306.             out[i] = LoopingLerp( frac, start->GetValue()[i], end->GetValue()[i] );
  1307.         }
  1308.         else
  1309.         {
  1310.             out[i] = Lerp( frac, start->GetValue()[i], end->GetValue()[i] );
  1311.         }
  1312.         Lerp_Clamp( out[i] );
  1313.     }
  1314. }
  1315.  
  1316.  
  1317. template< typename Type, bool IS_ARRAY >
  1318. inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::_Extrapolate(
  1319.     Type *pOut,
  1320.     CInterpolatedVarEntry *pOld,
  1321.     CInterpolatedVarEntry *pNew,
  1322.     float flDestinationTime,
  1323.     float flMaxExtrapolationAmount
  1324.     )
  1325. {
  1326.     if ( fabs( pOld->changetime - pNew->changetime ) < 0.001f || flDestinationTime <= pNew->changetime )
  1327.     {
  1328.         for ( int i=0; i < m_nMaxCount; i++ )
  1329.             pOut[i] = pNew->GetValue()[i];
  1330.     }
  1331.     else
  1332.     {
  1333.         float flExtrapolationAmount = min( flDestinationTime - pNew->changetime, flMaxExtrapolationAmount );
  1334.  
  1335.         float divisor = 1.0f / (pNew->changetime - pOld->changetime);
  1336.         for ( int i=0; i < m_nMaxCount; i++ )
  1337.         {
  1338.             pOut[i] = ExtrapolateInterpolatedVarType( pOld->GetValue()[i], pNew->GetValue()[i], divisor, flExtrapolationAmount );
  1339.         }
  1340.     }
  1341. }
  1342.  
  1343.  
  1344. template< typename Type, bool IS_ARRAY >
  1345. inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::TimeFixup2_Hermite(
  1346.     typename CInterpolatedVarArrayBase<Type, IS_ARRAY>::CInterpolatedVarEntry &fixup,
  1347.     typename CInterpolatedVarArrayBase<Type, IS_ARRAY>::CInterpolatedVarEntry*& prev,
  1348.     typename CInterpolatedVarArrayBase<Type, IS_ARRAY>::CInterpolatedVarEntry*& start,
  1349.     float dt1
  1350.     )
  1351. {
  1352.     float dt2 = start->changetime - prev->changetime;
  1353.  
  1354.     // If times are not of the same interval renormalize the earlier sample to allow for uniform hermite spline interpolation
  1355.     if ( fabs( dt1 - dt2 ) > 0.0001f &&
  1356.         dt2 > 0.0001f )
  1357.     {
  1358.         // Renormalize
  1359.         float frac = dt1 / dt2;
  1360.  
  1361.         // Fixed interval into past
  1362.         fixup.changetime = start->changetime - dt1;
  1363.  
  1364.         for ( int i = 0; i < m_nMaxCount; i++ )
  1365.         {
  1366.             if ( m_bLooping[i] )
  1367.             {
  1368.                 fixup.GetValue()[i] = LoopingLerp( 1-frac, prev->GetValue()[i], start->GetValue()[i] );
  1369.             }
  1370.             else
  1371.             {
  1372.                 fixup.GetValue()[i] = Lerp( 1-frac, prev->GetValue()[i], start->GetValue()[i] );
  1373.             }
  1374.         }
  1375.  
  1376.         // Point previous sample at fixed version
  1377.         prev = &fixup;
  1378.     }
  1379. }
  1380.  
  1381.  
  1382. template< typename Type, bool IS_ARRAY >
  1383. inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::TimeFixup_Hermite(
  1384.     typename CInterpolatedVarArrayBase<Type, IS_ARRAY>::CInterpolatedVarEntry &fixup,
  1385.     typename CInterpolatedVarArrayBase<Type, IS_ARRAY>::CInterpolatedVarEntry*& prev,
  1386.     typename CInterpolatedVarArrayBase<Type, IS_ARRAY>::CInterpolatedVarEntry*& start,
  1387.     typename CInterpolatedVarArrayBase<Type, IS_ARRAY>::CInterpolatedVarEntry*& end )
  1388. {
  1389.     TimeFixup2_Hermite( fixup, prev, start, end->changetime - start->changetime );
  1390. }
  1391.  
  1392.  
  1393. template< typename Type, bool IS_ARRAY >
  1394. inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::_Interpolate_Hermite(
  1395.     Type *out,
  1396.     float frac,
  1397.     CInterpolatedVarEntry *prev,
  1398.     CInterpolatedVarEntry *start,
  1399.     CInterpolatedVarEntry *end,
  1400.     bool looping )
  1401. {
  1402.     Assert( start );
  1403.     Assert( end );
  1404.  
  1405.     // Disable range checks because we can produce weird values here and it's not an error.
  1406.     // After interpolation, we will clamp the values.
  1407.     CDisableRangeChecks disableRangeChecks;
  1408.  
  1409.     CInterpolatedVarEntry fixup;
  1410.     fixup.Init(m_nMaxCount);
  1411.     TimeFixup_Hermite( fixup, prev, start, end );
  1412.  
  1413.     for( int i = 0; i < m_nMaxCount; i++ )
  1414.     {
  1415.         // Note that QAngle has a specialization that will do quaternion interpolation here...
  1416.         if ( m_bLooping[ i ] )
  1417.         {
  1418.             out[ i ] = LoopingLerp_Hermite( frac, prev->GetValue()[i], start->GetValue()[i], end->GetValue()[i] );
  1419.         }
  1420.         else
  1421.         {
  1422.             out[ i ] = Lerp_Hermite( frac, prev->GetValue()[i], start->GetValue()[i], end->GetValue()[i] );
  1423.         }
  1424.  
  1425.         // Clamp the output from interpolation. There are edge cases where something like m_flCycle
  1426.         // can get set to a really high or low value when we set it to zero after a really small
  1427.         // time interval (the hermite blender will think it's got a really high velocity and
  1428.         // skyrocket it off into la-la land).
  1429.         Lerp_Clamp( out[i] );
  1430.     }
  1431. }
  1432.  
  1433. template< typename Type, bool IS_ARRAY >
  1434. inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::_Derivative_Hermite(
  1435.     Type *out,
  1436.     float frac,
  1437.     CInterpolatedVarEntry *prev,
  1438.     CInterpolatedVarEntry *start,
  1439.     CInterpolatedVarEntry *end )
  1440. {
  1441.     Assert( start );
  1442.     Assert( end );
  1443.  
  1444.     // Disable range checks because we can produce weird values here and it's not an error.
  1445.     // After interpolation, we will clamp the values.
  1446.     CDisableRangeChecks disableRangeChecks;
  1447.  
  1448.     CInterpolatedVarEntry fixup;
  1449.     fixup.value = (Type*)_alloca( sizeof(Type) * m_nMaxCount );
  1450.     TimeFixup_Hermite( fixup, prev, start, end );
  1451.  
  1452.     float divisor = 1.0f / (end->changetime - start->changetime);
  1453.  
  1454.     for( int i = 0; i < m_nMaxCount; i++ )
  1455.     {
  1456.         Assert( !m_bLooping[ i ] );
  1457.         out[i] = Derivative_Hermite( frac, prev->GetValue()[i], start->GetValue()[i], end->GetValue()[i] );
  1458.         out[i] *= divisor;
  1459.     }
  1460. }
  1461.  
  1462.  
  1463. template< typename Type, bool IS_ARRAY >
  1464. inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::_Derivative_Hermite_SmoothVelocity(
  1465.     Type *out,
  1466.     float frac,
  1467.     CInterpolatedVarEntry *b,
  1468.     CInterpolatedVarEntry *c,
  1469.     CInterpolatedVarEntry *d )
  1470. {
  1471.     CInterpolatedVarEntry fixup;
  1472.     fixup.Init(m_nMaxCount);
  1473.     TimeFixup_Hermite( fixup, b, c, d );
  1474.     for ( int i=0; i < m_nMaxCount; i++ )
  1475.     {
  1476.         Type prevVel = (c->GetValue()[i] - b->GetValue()[i]) / (c->changetime - b->changetime);
  1477.         Type curVel  = (d->GetValue()[i] - c->GetValue()[i]) / (d->changetime - c->changetime);
  1478.         out[i] = Lerp( frac, prevVel, curVel );
  1479.     }
  1480. }
  1481.  
  1482.  
  1483. template< typename Type, bool IS_ARRAY >
  1484. inline void CInterpolatedVarArrayBase<Type, IS_ARRAY>::_Derivative_Linear(
  1485.     Type *out,
  1486.     CInterpolatedVarEntry *start,
  1487.     CInterpolatedVarEntry *end )
  1488. {
  1489.     if ( start == end || fabs( start->changetime - end->changetime ) < 0.0001f )
  1490.     {
  1491.         for( int i = 0; i < m_nMaxCount; i++ )
  1492.         {
  1493.             out[ i ] = start->GetValue()[i] * 0;
  1494.         }
  1495.     }
  1496.     else
  1497.     {
  1498.         float divisor = 1.0f / (end->changetime - start->changetime);
  1499.         for( int i = 0; i < m_nMaxCount; i++ )
  1500.         {
  1501.             out[ i ] = (end->GetValue()[i] - start->GetValue()[i]) * divisor;
  1502.         }
  1503.     }
  1504. }
  1505.  
  1506.  
  1507. template< typename Type, bool IS_ARRAY >
  1508. inline bool CInterpolatedVarArrayBase<Type, IS_ARRAY>::ValidOrder()
  1509. {
  1510.     float newestchangetime = 0.0f;
  1511.     bool first = true;
  1512.     for ( int i = 0; i < m_VarHistory.Count(); i++ )
  1513.     {
  1514.         CInterpolatedVarEntry *entry = &m_VarHistory[ i ];
  1515.         if ( first )
  1516.         {
  1517.             first = false;
  1518.             newestchangetime = entry->changetime;
  1519.             continue;
  1520.         }
  1521.  
  1522.         // They should get older as wel walk backwards
  1523.         if ( entry->changetime > newestchangetime )
  1524.         {
  1525.             Assert( 0 );
  1526.             return false;
  1527.         }
  1528.  
  1529.         newestchangetime = entry->changetime;
  1530.     }
  1531.  
  1532.     return true;
  1533. }
  1534.  
  1535. template< typename Type, int COUNT >
  1536. class CInterpolatedVarArray : public CInterpolatedVarArrayBase<Type, true >
  1537. {
  1538. public:
  1539.     CInterpolatedVarArray( const char *pDebugName = "no debug name" )
  1540.         : CInterpolatedVarArrayBase<Type, true>( pDebugName )
  1541.     {
  1542.         SetMaxCount( COUNT );
  1543.     }
  1544. };
  1545.  
  1546.  
  1547. // -------------------------------------------------------------------------------------------------------------- //
  1548. // CInterpolatedVar.
  1549. // -------------------------------------------------------------------------------------------------------------- //
  1550.  
  1551. template< typename Type >
  1552. class CInterpolatedVar : public CInterpolatedVarArrayBase< Type, false >
  1553. {
  1554. public:
  1555.     CInterpolatedVar( const char *pDebugName = NULL )
  1556.         : CInterpolatedVarArrayBase< Type, false >(pDebugName)
  1557.     {
  1558.         SetMaxCount( 1 );
  1559.     }
  1560. };
  1561.  
  1562. #include "tier0/memdbgoff.h"
  1563.  
  1564. #endif // INTERPOLATEDVAR_H
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement