Counter Strike : Global Offensive Source Code
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.

1572 lines
45 KiB

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