Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1591 lines
44 KiB

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