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.

6209 lines
173 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "movieobjects/dmelog.h"
  7. #include "datamodel/dmelementfactoryhelper.h"
  8. #include "datamodel/dmehandle.h"
  9. #include "vstdlib/random.h"
  10. #include "tier0/dbg.h"
  11. #include <limits.h>
  12. // memdbgon must be the last include file in a .cpp file!!!
  13. #include "tier0/memdbgon.h"
  14. LayerSelectionData_t::DataLayer_t::DataLayer_t( float frac, CDmeLogLayer *layer ) :
  15. m_flStartFraction( frac )
  16. {
  17. m_hData = layer;
  18. }
  19. LayerSelectionData_t::LayerSelectionData_t() :
  20. m_DataType( AT_UNKNOWN ),
  21. m_nDuration( 0 ),
  22. m_tStartOffset( DMETIME_ZERO )
  23. {
  24. m_nHoldTimes[ 0 ] = m_nHoldTimes[ 1 ] = 0;
  25. }
  26. void LayerSelectionData_t::Release()
  27. {
  28. for ( int i = 0; i < m_vecData.Count(); ++i )
  29. {
  30. DataLayer_t *dl = &m_vecData[ i ];
  31. if ( dl->m_hData.Get() )
  32. {
  33. g_pDataModel->DestroyElement( dl->m_hData->GetHandle() );
  34. }
  35. }
  36. m_vecData.Purge();
  37. }
  38. //-----------------------------------------------------------------------------
  39. // Interpolatable types
  40. //-----------------------------------------------------------------------------
  41. inline bool IsInterpolableType( DmAttributeType_t type )
  42. {
  43. return ( type == AT_FLOAT ) ||
  44. ( type == AT_COLOR ) ||
  45. ( type == AT_VECTOR2 ) ||
  46. ( type == AT_VECTOR3 ) ||
  47. ( type == AT_QANGLE ) ||
  48. ( type == AT_QUATERNION );
  49. }
  50. static Vector s_pInterolationPoints[ 4 ] =
  51. {
  52. Vector( 0.0f, 0.0f, 0.0f ),
  53. Vector( 0.0f, 0.0f, 0.0f ),
  54. Vector( 1.0f, 1.0f, 0.0f ),
  55. Vector( 1.0f, 1.0f, 0.0f )
  56. };
  57. static inline float ComputeInterpolationFactor( float flFactor, int nInterpolatorType )
  58. {
  59. Vector out;
  60. Interpolator_CurveInterpolate
  61. (
  62. nInterpolatorType,
  63. s_pInterolationPoints[ 0 ], // unused
  64. s_pInterolationPoints[ 1 ],
  65. s_pInterolationPoints[ 2 ],
  66. s_pInterolationPoints[ 3 ], // unused
  67. flFactor,
  68. out
  69. );
  70. return out.y; // clamp( out.y, 0.0f, 1.0f );
  71. }
  72. float DmeLog_TimeSelection_t::AdjustFactorForInterpolatorType( float flFactor, int nSide ) const
  73. {
  74. return ComputeInterpolationFactor( flFactor, m_nFalloffInterpolatorTypes[ nSide ] );
  75. }
  76. //-----------------------------------------------------------------------------
  77. // NOTE: See DmeTimeSelectionTimes_t for return values, -1 means before, TS_TIME_COUNT means after
  78. //-----------------------------------------------------------------------------
  79. static inline int ComputeRegionForTime( DmeTime_t t, const DmeTime_t *pRegionTimes )
  80. {
  81. if ( t >= pRegionTimes[TS_LEFT_HOLD] )
  82. {
  83. if ( t <= pRegionTimes[TS_RIGHT_HOLD] )
  84. return 2;
  85. return ( t <= pRegionTimes[TS_RIGHT_FALLOFF] ) ? 3 : 4;
  86. }
  87. return ( t >= pRegionTimes[TS_LEFT_FALLOFF] ) ? 1 : 0;
  88. }
  89. //-----------------------------------------------------------------------------
  90. // NOTE: See DmeTimeSelectionTimes_t for return values, -1 means before, TS_TIME_COUNT means after
  91. //-----------------------------------------------------------------------------
  92. int DmeLog_TimeSelection_t::ComputeRegionForTime( DmeTime_t curtime ) const
  93. {
  94. return ::ComputeRegionForTime( curtime, m_nTimes );
  95. }
  96. //-----------------------------------------------------------------------------
  97. // per-type averaging methods
  98. //-----------------------------------------------------------------------------
  99. float DmeLog_TimeSelection_t::GetAmountForTime( DmeTime_t dmetime ) const
  100. {
  101. float minfrac = 0.0f;
  102. float t = dmetime.GetSeconds();
  103. // FIXME, this is slow, we should cache this maybe?
  104. COMPILE_TIME_ASSERT( TS_TIME_COUNT == 4 );
  105. float times[ TS_TIME_COUNT ];
  106. times[ 0 ] = m_nTimes[ 0 ].GetSeconds();
  107. times[ 1 ] = m_nTimes[ 1 ].GetSeconds();
  108. times[ 2 ] = m_nTimes[ 2 ].GetSeconds();
  109. times[ 3 ] = m_nTimes[ 3 ].GetSeconds();
  110. float dt1, dt2;
  111. dt1 = times[ 1 ] - times[ 0 ];
  112. dt2 = times[ 3 ] - times[ 2 ];
  113. if ( dt1 > 0.0f && t >= times[ 0 ] && t < times[ 1 ] )
  114. {
  115. float f = ( t - times[ 0 ] ) / dt1;
  116. Vector out;
  117. Interpolator_CurveInterpolate
  118. (
  119. m_nFalloffInterpolatorTypes[ 0 ],
  120. s_pInterolationPoints[ 0 ], // unused
  121. s_pInterolationPoints[ 1 ],
  122. s_pInterolationPoints[ 2 ],
  123. s_pInterolationPoints[ 3 ], // unused
  124. f,
  125. out
  126. );
  127. return clamp( out.y, minfrac, 1.0f );
  128. }
  129. if ( t >= times[ 1 ] && t <= times[ 2 ] )
  130. return 1.0f;
  131. if ( dt2 > 0.0f && t > times[ 2 ] && t <= times[ 3 ] )
  132. {
  133. float f = ( times[ 3 ] - t ) / dt2;
  134. Vector out;
  135. Interpolator_CurveInterpolate
  136. (
  137. m_nFalloffInterpolatorTypes[ 1 ],
  138. s_pInterolationPoints[ 0 ], // unused
  139. s_pInterolationPoints[ 1 ],
  140. s_pInterolationPoints[ 2 ],
  141. s_pInterolationPoints[ 3 ], // unused
  142. f,
  143. out
  144. );
  145. return clamp( out.y, minfrac, 1.0f );
  146. }
  147. return minfrac;
  148. }
  149. // catch-all for non-interpolable types - just holds first value
  150. template < class T >
  151. T Average( const T *pValues, int nValues)
  152. {
  153. if ( IsInterpolableType( CDmAttributeInfo< T >::AttributeType() ) )
  154. {
  155. static bool first = true;
  156. if ( first )
  157. {
  158. first = false;
  159. Warning( "CDmeLog: interpolable type %s doesn't have an averaging function!", CDmAttributeInfo< T >::AttributeTypeName() );
  160. }
  161. }
  162. Assert( nValues > 0 );
  163. if ( nValues <= 0 )
  164. return T(); // uninitialized for most value classes!!!
  165. return pValues[ 0 ];
  166. }
  167. // float version
  168. template <>
  169. float Average( const float *pValues, int nValues )
  170. {
  171. Assert( nValues > 0 );
  172. if ( nValues <= 0 )
  173. return 0.0f;
  174. float sum = 0.0f;
  175. for ( int i = 0; i < nValues; ++i )
  176. {
  177. sum += pValues[ i ];
  178. }
  179. return sum / nValues;
  180. }
  181. // Color version
  182. template <>
  183. Color Average( const Color *pValues, int nValues )
  184. {
  185. Assert( nValues > 0 );
  186. if ( nValues <= 0 )
  187. return Color( 0, 0, 0, 0 );
  188. float r = 0.0f, g = 0.0f, b = 0.0f, a = 0.0f;
  189. for ( int i = 0; i < nValues; ++i )
  190. {
  191. r += pValues[ i ].r();
  192. g += pValues[ i ].g();
  193. b += pValues[ i ].b();
  194. a += pValues[ i ].a();
  195. }
  196. float inv = nValues;
  197. return Color( r * inv, g * inv, b * inv, a * inv );
  198. }
  199. // Vector2 version
  200. template <>
  201. Vector2D Average( const Vector2D *pValues, int nValues )
  202. {
  203. Assert( nValues > 0 );
  204. if ( nValues <= 0 )
  205. return Vector2D( 0.0f, 0.0f );
  206. Vector2D sum( 0.0f, 0.0f );
  207. for ( int i = 0; i < nValues; ++i )
  208. {
  209. sum += pValues[ i ];
  210. }
  211. return sum / nValues;
  212. }
  213. // Vector3 version
  214. template <>
  215. Vector Average( const Vector *pValues, int nValues )
  216. {
  217. Assert( nValues > 0 );
  218. if ( nValues <= 0 )
  219. return Vector( 0.0f, 0.0f, 0.0f );
  220. Vector sum( 0.0f, 0.0f, 0.0f );
  221. for ( int i = 0; i < nValues; ++i )
  222. {
  223. sum += pValues[ i ];
  224. }
  225. return sum / nValues;
  226. }
  227. // QAngle version
  228. template <>
  229. QAngle Average( const QAngle *pValues, int nValues )
  230. {
  231. Assert( nValues > 0 );
  232. if ( nValues <= 0 )
  233. return QAngle( 0.0f, 0.0f, 0.0f );
  234. Quaternion ave;
  235. AngleQuaternion( pValues[ 0 ], ave );
  236. // this is calculating the average by slerping with decreasing weights
  237. // for example: ave = 1/3 * q2 + 2/3 ( 1/2 * q1 + 1/2 * q0 )
  238. for ( int i = 1; i < nValues; ++i )
  239. {
  240. Quaternion quat;
  241. AngleQuaternion( pValues[ i ], quat );
  242. QuaternionSlerp( ave, quat, 1 / float( i + 1 ), ave );
  243. }
  244. QAngle qangle;
  245. QuaternionAngles( ave, qangle );
  246. return qangle;
  247. }
  248. // Quaternion version
  249. template <>
  250. Quaternion Average( const Quaternion *pValues, int nValues )
  251. {
  252. Assert( nValues > 0 );
  253. if ( nValues <= 0 )
  254. return Quaternion( 0.0f, 0.0f, 0.0f, 1.0f );
  255. Quaternion ave = pValues[ 0 ];
  256. // this is calculating the average by slerping with decreasing weights
  257. // for example: ave = 1/3 * q2 + 2/3 ( 1/2 * q1 + 1/2 * q0 )
  258. for ( int i = 1; i < nValues; ++i )
  259. {
  260. QuaternionSlerp( ave, pValues[ i ], 1 / float( i + 1 ), ave );
  261. }
  262. return ave;
  263. }
  264. //-----------------------------------------------------------------------------
  265. // per-type interpolation methods
  266. //-----------------------------------------------------------------------------
  267. // catch-all for non-interpolable types - just holds first value
  268. template < class T >
  269. T Interpolate( float t, const T& ti, const T& tj )
  270. {
  271. if ( IsInterpolableType( CDmAttributeInfo< T >::AttributeType() ) )
  272. {
  273. static bool first = true;
  274. if ( first )
  275. {
  276. first = false;
  277. Warning( "CDmeLog: interpolable type %s doesn't have an interpolation function!", CDmAttributeInfo< T >::AttributeTypeName() );
  278. }
  279. }
  280. return ti;
  281. }
  282. // float version
  283. template <>
  284. float Interpolate( float t, const float& ti, const float& tj )
  285. {
  286. return t * tj + (1.0f - t) * ti;
  287. }
  288. // Color version
  289. template <>
  290. Color Interpolate( float t, const Color& ti, const Color& tj )
  291. {
  292. int ri, gi, bi, ai;
  293. int rj, gj, bj, aj;
  294. ti.GetColor( ri, gi, bi, ai );
  295. tj.GetColor( rj, gj, bj, aj );
  296. return Color( t * rj + (1.0f - t) * ri,
  297. t * gj + (1.0f - t) * gi,
  298. t * bj + (1.0f - t) * bi,
  299. t * aj + (1.0f - t) * ai);
  300. }
  301. // Vector2 version
  302. template <>
  303. Vector2D Interpolate( float t, const Vector2D& ti, const Vector2D& tj )
  304. {
  305. return t * tj + (1.0f - t) * ti;
  306. }
  307. // Vector3 version
  308. template <>
  309. Vector Interpolate( float t, const Vector& ti, const Vector& tj )
  310. {
  311. return t * tj + (1.0f - t) * ti;
  312. }
  313. // QAngle version
  314. template <>
  315. QAngle Interpolate( float t, const QAngle& ti, const QAngle& tj )
  316. {
  317. QAngle qaResult;
  318. Quaternion q, qi, qj; // Some Quaternion temps for doing the slerp
  319. AngleQuaternion( ti, qi ); // Convert QAngles to Quaternions
  320. AngleQuaternion( tj, qj );
  321. QuaternionSlerp( qi, qj, t, q ); // Do a slerp as Quaternions
  322. QuaternionAngles( q, qaResult ); // Convert back to QAngles
  323. return qaResult;
  324. }
  325. // Quaternion version
  326. template <>
  327. Quaternion Interpolate( float t, const Quaternion& ti, const Quaternion& tj )
  328. {
  329. static Quaternion s_value;
  330. QuaternionSlerp( ti, tj, t, s_value );
  331. return s_value;
  332. }
  333. // catch-all for non-interpolable types - just holds first value
  334. template < class T >
  335. T Curve_Interpolate( float t, DmeTime_t times[ 4 ], const T values[ 4 ], int curveTypes[ 4 ], float fmin, float fmax )
  336. {
  337. if ( IsInterpolableType( CDmAttributeInfo< T >::AttributeType() ) )
  338. {
  339. static bool first = true;
  340. if ( first )
  341. {
  342. first = false;
  343. Warning( "CDmeLog: interpolable type %s doesn't have an interpolation function!", CDmAttributeInfo< T >::AttributeTypeName() );
  344. }
  345. }
  346. return t;
  347. }
  348. // float version
  349. template <>
  350. float Curve_Interpolate( float t, DmeTime_t times[ 4 ], const float values[ 4 ], int curveTypes[ 4 ], float fmin, float fmax )
  351. {
  352. Vector args[ 4 ];
  353. for ( int i = 0; i < 4; ++i )
  354. {
  355. args[ i ].Init( times[ i ].GetSeconds(), values[ i ], 0.0f );
  356. }
  357. Vector vOut;
  358. int dummy;
  359. int earlypart, laterpart;
  360. // Not holding out value of previous curve...
  361. Interpolator_CurveInterpolatorsForType( curveTypes[ 1 ], dummy, earlypart );
  362. Interpolator_CurveInterpolatorsForType( curveTypes[ 2 ], laterpart, dummy );
  363. if ( earlypart == INTERPOLATE_HOLD )
  364. {
  365. // Hold "out" of previous sample (can cause a discontinuity)
  366. VectorLerp( args[ 1 ], args[ 2 ], t, vOut );
  367. vOut.y = args[ 1 ].y;
  368. }
  369. else if ( laterpart == INTERPOLATE_HOLD )
  370. {
  371. // Hold "out" of previous sample (can cause a discontinuity)
  372. VectorLerp( args[ 1 ], args[ 2 ], t, vOut );
  373. vOut.y = args[ 2 ].y;
  374. }
  375. else
  376. {
  377. bool sameCurveType = earlypart == laterpart ? true : false;
  378. if ( sameCurveType )
  379. {
  380. Interpolator_CurveInterpolate( laterpart, args[ 0 ], args[ 1 ], args[ 2 ], args[ 3 ], t, vOut );
  381. }
  382. else // curves differ, sigh
  383. {
  384. Vector vOut1, vOut2;
  385. Interpolator_CurveInterpolate( earlypart, args[ 0 ], args[ 1 ], args[ 2 ], args[ 3 ], t, vOut1 );
  386. Interpolator_CurveInterpolate( laterpart, args[ 0 ], args[ 1 ], args[ 2 ], args[ 3 ], t, vOut2 );
  387. VectorLerp( vOut1, vOut2, t, vOut );
  388. }
  389. }
  390. // FIXME: This means we can only work with curves that range from 0.0 to 1.0f!!!
  391. float retval = clamp( vOut.y, fmin, fmax );
  392. return retval;
  393. }
  394. // Vector version
  395. template <>
  396. Vector Curve_Interpolate( float t, DmeTime_t times[ 4 ], const Vector values[ 4 ], int curveTypes[ 4 ], float fmin, float fmax )
  397. {
  398. Vector vOut;
  399. int dummy;
  400. int earlypart, laterpart;
  401. // Not holding out value of previous curve...
  402. Interpolator_CurveInterpolatorsForType( curveTypes[ 1 ], dummy, earlypart );
  403. Interpolator_CurveInterpolatorsForType( curveTypes[ 2 ], laterpart, dummy );
  404. if ( earlypart == INTERPOLATE_HOLD )
  405. {
  406. // Hold "out" of previous sample (can cause a discontinuity)
  407. vOut = values[ 1 ];
  408. }
  409. else if ( laterpart == INTERPOLATE_HOLD )
  410. {
  411. // Hold "out" of previous sample (can cause a discontinuity)
  412. vOut = values[ 2 ];
  413. }
  414. else
  415. {
  416. bool sameCurveType = earlypart == laterpart;
  417. if ( sameCurveType )
  418. {
  419. Interpolator_CurveInterpolate_NonNormalized( laterpart, values[ 0 ], values[ 1 ], values[ 2 ], values[ 3 ], t, vOut );
  420. }
  421. else // curves differ, sigh
  422. {
  423. Vector vOut1, vOut2;
  424. Interpolator_CurveInterpolate_NonNormalized( earlypart, values[ 0 ], values[ 1 ], values[ 2 ], values[ 3 ], t, vOut1 );
  425. Interpolator_CurveInterpolate_NonNormalized( laterpart, values[ 0 ], values[ 1 ], values[ 2 ], values[ 3 ], t, vOut2 );
  426. VectorLerp( vOut1, vOut2, t, vOut );
  427. }
  428. }
  429. return vOut;
  430. }
  431. // Quaternion version
  432. template <>
  433. Quaternion Curve_Interpolate( float t, DmeTime_t times[ 4 ], const Quaternion values[ 4 ], int curveTypes[ 4 ], float fmin, float fmax )
  434. {
  435. Quaternion vOut;
  436. int dummy;
  437. int earlypart, laterpart;
  438. // Not holding out value of previous curve...
  439. Interpolator_CurveInterpolatorsForType( curveTypes[ 1 ], dummy, earlypart );
  440. Interpolator_CurveInterpolatorsForType( curveTypes[ 2 ], laterpart, dummy );
  441. if ( earlypart == INTERPOLATE_HOLD )
  442. {
  443. // Hold "out" of previous sample (can cause a discontinuity)
  444. vOut = values[ 1 ];
  445. }
  446. else if ( laterpart == INTERPOLATE_HOLD )
  447. {
  448. // Hold "out" of previous sample (can cause a discontinuity)
  449. vOut = values[ 2 ];
  450. }
  451. else
  452. {
  453. bool sameCurveType = ( earlypart == laterpart ) ? true : false;
  454. if ( sameCurveType )
  455. {
  456. Interpolator_CurveInterpolate_NonNormalized( laterpart, values[ 0 ], values[ 1 ], values[ 2 ], values[ 3 ], t, vOut );
  457. }
  458. else // curves differ, sigh
  459. {
  460. Quaternion vOut1, vOut2;
  461. Interpolator_CurveInterpolate_NonNormalized( earlypart, values[ 0 ], values[ 1 ], values[ 2 ], values[ 3 ], t, vOut1 );
  462. Interpolator_CurveInterpolate_NonNormalized( laterpart, values[ 0 ], values[ 1 ], values[ 2 ], values[ 3 ], t, vOut2 );
  463. QuaternionSlerp( vOut1, vOut2, t, vOut );
  464. }
  465. }
  466. return vOut;
  467. }
  468. template< class T >
  469. T ScaleValue( const T& value, float scale )
  470. {
  471. return value * scale;
  472. }
  473. template<>
  474. bool ScaleValue( const bool& value, float scale )
  475. {
  476. Assert( 0 );
  477. return value;
  478. }
  479. template<>
  480. Color ScaleValue( const Color& value, float scale )
  481. {
  482. Assert( 0 );
  483. return value;
  484. }
  485. template<>
  486. Vector4D ScaleValue( const Vector4D& value, float scale )
  487. {
  488. return Vector4D( value.x * scale, value.y * scale, value.z * scale, value.w * scale );
  489. }
  490. template<>
  491. Quaternion ScaleValue( const Quaternion& value, float scale )
  492. {
  493. return Quaternion( value.x * scale, value.y * scale, value.z * scale, value.w * scale );
  494. }
  495. template<>
  496. VMatrix ScaleValue( const VMatrix& value, float scale )
  497. {
  498. Assert( 0 );
  499. return value;
  500. }
  501. template<>
  502. CUtlString ScaleValue( const CUtlString& value, float scale )
  503. {
  504. Assert( 0 );
  505. return value;
  506. }
  507. template< class T >
  508. float LengthOf( const T& value )
  509. {
  510. return value;
  511. }
  512. template<>
  513. float LengthOf( const bool& value )
  514. {
  515. if ( value )
  516. return 1.0f;
  517. return 0.0f;
  518. }
  519. template<>
  520. float LengthOf( const Color& value )
  521. {
  522. return (float)sqrt( (float)( value.r() * value.r() +
  523. value.g() * value.g() +
  524. value.b() * value.b() +
  525. value.a() * value.a()) );
  526. }
  527. template<>
  528. float LengthOf( const Vector4D& value )
  529. {
  530. return sqrt( value.x * value.x +
  531. value.y * value.y +
  532. value.z * value.z +
  533. value.w * value.w );
  534. }
  535. template<>
  536. float LengthOf( const Quaternion& value )
  537. {
  538. return sqrt( value.x * value.x +
  539. value.y * value.y +
  540. value.z * value.z +
  541. value.w * value.w );
  542. }
  543. template<>
  544. float LengthOf( const VMatrix& value )
  545. {
  546. return 0.0f;
  547. }
  548. template<>
  549. float LengthOf( const CUtlString& value )
  550. {
  551. return 0.0f;
  552. }
  553. template<>
  554. float LengthOf( const Vector2D& value )
  555. {
  556. return value.Length();
  557. }
  558. template<>
  559. float LengthOf( const Vector& value )
  560. {
  561. return value.Length();
  562. }
  563. template<>
  564. float LengthOf( const QAngle& value )
  565. {
  566. return value.Length();
  567. }
  568. template< class T >
  569. T Subtract( const T& v1, const T& v2 )
  570. {
  571. return v1 - v2;
  572. }
  573. template<>
  574. bool Subtract( const bool& v1, const bool& v2 )
  575. {
  576. return v1;
  577. }
  578. template<>
  579. CUtlString Subtract( const CUtlString& v1, const CUtlString& v2 )
  580. {
  581. return v1;
  582. }
  583. template<>
  584. Color Subtract( const Color& v1, const Color& v2 )
  585. {
  586. Color ret;
  587. for ( int i = 0; i < 4; ++i )
  588. {
  589. ret[ i ] = clamp( v1[ i ] - v2[ i ], 0, 255 );
  590. }
  591. return ret;
  592. }
  593. template<>
  594. Vector4D Subtract( const Vector4D& v1, const Vector4D& v2 )
  595. {
  596. Vector4D ret;
  597. for ( int i = 0; i < 4; ++i )
  598. {
  599. ret[ i ] = v1[ i ] - v2[ i ];
  600. }
  601. return ret;
  602. }
  603. template<>
  604. Quaternion Subtract( const Quaternion& v1, const Quaternion& v2 )
  605. {
  606. Quaternion ret;
  607. for ( int i = 0; i < 4; ++i )
  608. {
  609. ret[ i ] = v1[ i ];
  610. }
  611. return ret;
  612. }
  613. template< class T >
  614. T Add( const T& v1, const T& v2 )
  615. {
  616. return v1 + v2;
  617. }
  618. template<>
  619. bool Add( const bool& v1, const bool& v2 )
  620. {
  621. return v1;
  622. }
  623. template<>
  624. CUtlString Add( const CUtlString& v1, const CUtlString& v2 )
  625. {
  626. return v1;
  627. }
  628. template<>
  629. Color Add( const Color& v1, const Color& v2 )
  630. {
  631. Color ret;
  632. for ( int i = 0; i < 4; ++i )
  633. {
  634. ret[ i ] = clamp( v1[ i ] + v2[ i ], 0, 255 );
  635. }
  636. return ret;
  637. }
  638. template<>
  639. Vector4D Add( const Vector4D& v1, const Vector4D& v2 )
  640. {
  641. Vector4D ret;
  642. for ( int i = 0; i < 4; ++i )
  643. {
  644. ret[ i ] = v1[ i ] + v2[ i ];
  645. }
  646. return ret;
  647. }
  648. template<>
  649. Quaternion Add( const Quaternion& v1, const Quaternion& v2 )
  650. {
  651. return v1;
  652. }
  653. IMPLEMENT_ABSTRACT_ELEMENT( DmeLogLayer, CDmeLogLayer );
  654. IMPLEMENT_ELEMENT_FACTORY( DmeIntLogLayer, CDmeIntLogLayer );
  655. IMPLEMENT_ELEMENT_FACTORY( DmeFloatLogLayer, CDmeFloatLogLayer );
  656. IMPLEMENT_ELEMENT_FACTORY( DmeBoolLogLayer, CDmeBoolLogLayer );
  657. IMPLEMENT_ELEMENT_FACTORY( DmeColorLogLayer, CDmeColorLogLayer );
  658. IMPLEMENT_ELEMENT_FACTORY( DmeVector2LogLayer, CDmeVector2LogLayer );
  659. IMPLEMENT_ELEMENT_FACTORY( DmeVector3LogLayer, CDmeVector3LogLayer );
  660. IMPLEMENT_ELEMENT_FACTORY( DmeVector4LogLayer, CDmeVector4LogLayer );
  661. IMPLEMENT_ELEMENT_FACTORY( DmeQAngleLogLayer, CDmeQAngleLogLayer );
  662. IMPLEMENT_ELEMENT_FACTORY( DmeQuaternionLogLayer, CDmeQuaternionLogLayer );
  663. IMPLEMENT_ELEMENT_FACTORY( DmeVMatrixLogLayer, CDmeVMatrixLogLayer );
  664. IMPLEMENT_ELEMENT_FACTORY( DmeStringLogLayer, CDmeStringLogLayer );
  665. //-----------------------------------------------------------------------------
  666. // explicit template instantiation
  667. //-----------------------------------------------------------------------------
  668. template class CDmeTypedLogLayer<int>;
  669. template class CDmeTypedLogLayer<float>;
  670. template class CDmeTypedLogLayer<bool>;
  671. template class CDmeTypedLogLayer<Color>;
  672. template class CDmeTypedLogLayer<Vector2D>;
  673. template class CDmeTypedLogLayer<Vector>;
  674. template class CDmeTypedLogLayer<Vector4D>;
  675. template class CDmeTypedLogLayer<QAngle>;
  676. template class CDmeTypedLogLayer<Quaternion>;
  677. template class CDmeTypedLogLayer<VMatrix>;
  678. template class CDmeTypedLogLayer<CUtlString>;
  679. IMPLEMENT_ABSTRACT_ELEMENT( DmeCurveInfo, CDmeCurveInfo );
  680. IMPLEMENT_ELEMENT_FACTORY( DmeIntCurveInfo, CDmeIntCurveInfo );
  681. IMPLEMENT_ELEMENT_FACTORY( DmeFloatCurveInfo, CDmeFloatCurveInfo );
  682. IMPLEMENT_ELEMENT_FACTORY( DmeBoolCurveInfo, CDmeBoolCurveInfo );
  683. IMPLEMENT_ELEMENT_FACTORY( DmeColorCurveInfo, CDmeColorCurveInfo );
  684. IMPLEMENT_ELEMENT_FACTORY( DmeVector2CurveInfo, CDmeVector2CurveInfo );
  685. IMPLEMENT_ELEMENT_FACTORY( DmeVector3CurveInfo, CDmeVector3CurveInfo );
  686. IMPLEMENT_ELEMENT_FACTORY( DmeVector4CurveInfo, CDmeVector4CurveInfo );
  687. IMPLEMENT_ELEMENT_FACTORY( DmeQAngleCurveInfo, CDmeQAngleCurveInfo );
  688. IMPLEMENT_ELEMENT_FACTORY( DmeQuaternionCurveInfo, CDmeQuaternionCurveInfo );
  689. IMPLEMENT_ELEMENT_FACTORY( DmeVMatrixCurveInfo, CDmeVMatrixCurveInfo );
  690. IMPLEMENT_ELEMENT_FACTORY( DmeStringCurveInfo, CDmeStringCurveInfo );
  691. //-----------------------------------------------------------------------------
  692. // explicit template instantiation
  693. //-----------------------------------------------------------------------------
  694. template class CDmeTypedCurveInfo<int>;
  695. template class CDmeTypedCurveInfo<float>;
  696. template class CDmeTypedCurveInfo<bool>;
  697. template class CDmeTypedCurveInfo<Color>;
  698. template class CDmeTypedCurveInfo<Vector2D>;
  699. template class CDmeTypedCurveInfo<Vector>;
  700. template class CDmeTypedCurveInfo<Vector4D>;
  701. template class CDmeTypedCurveInfo<QAngle>;
  702. template class CDmeTypedCurveInfo<Quaternion>;
  703. template class CDmeTypedCurveInfo<VMatrix>;
  704. template class CDmeTypedCurveInfo<CUtlString>;
  705. //-----------------------------------------------------------------------------
  706. // Class factory
  707. //-----------------------------------------------------------------------------
  708. IMPLEMENT_ABSTRACT_ELEMENT( DmeLog, CDmeLog );
  709. IMPLEMENT_ELEMENT_FACTORY( DmeIntLog, CDmeIntLog );
  710. IMPLEMENT_ELEMENT_FACTORY( DmeFloatLog, CDmeFloatLog );
  711. IMPLEMENT_ELEMENT_FACTORY( DmeBoolLog, CDmeBoolLog );
  712. IMPLEMENT_ELEMENT_FACTORY( DmeColorLog, CDmeColorLog );
  713. IMPLEMENT_ELEMENT_FACTORY( DmeVector2Log, CDmeVector2Log );
  714. IMPLEMENT_ELEMENT_FACTORY( DmeVector3Log, CDmeVector3Log );
  715. IMPLEMENT_ELEMENT_FACTORY( DmeVector4Log, CDmeVector4Log );
  716. IMPLEMENT_ELEMENT_FACTORY( DmeQAngleLog, CDmeQAngleLog );
  717. IMPLEMENT_ELEMENT_FACTORY( DmeQuaternionLog, CDmeQuaternionLog );
  718. IMPLEMENT_ELEMENT_FACTORY( DmeVMatrixLog, CDmeVMatrixLog );
  719. IMPLEMENT_ELEMENT_FACTORY( DmeStringLog, CDmeStringLog );
  720. //-----------------------------------------------------------------------------
  721. // explicit template instantiation
  722. //-----------------------------------------------------------------------------
  723. template class CDmeTypedLog<int>;
  724. template class CDmeTypedLog<float>;
  725. template class CDmeTypedLog<bool>;
  726. template class CDmeTypedLog<Color>;
  727. template class CDmeTypedLog<Vector2D>;
  728. template class CDmeTypedLog<Vector>;
  729. template class CDmeTypedLog<Vector4D>;
  730. template class CDmeTypedLog<QAngle>;
  731. template class CDmeTypedLog<Quaternion>;
  732. template class CDmeTypedLog<VMatrix>;
  733. template class CDmeTypedLog<CUtlString>;
  734. //-----------------------------------------------------------------------------
  735. // instantiate and initialize static vars
  736. //-----------------------------------------------------------------------------
  737. float CDmeIntLog::s_defaultThreshold = 0.0f;
  738. float CDmeFloatLog::s_defaultThreshold = 0.0f;
  739. float CDmeBoolLog::s_defaultThreshold = 0.0f;
  740. float CDmeColorLog::s_defaultThreshold = 0.0f;
  741. float CDmeVector2Log::s_defaultThreshold = 0.0f;
  742. float CDmeVector3Log::s_defaultThreshold = 0.0f;
  743. float CDmeVector4Log::s_defaultThreshold = 0.0f;
  744. float CDmeQAngleLog::s_defaultThreshold = 0.0f;
  745. float CDmeQuaternionLog::s_defaultThreshold = 0.0f;
  746. float CDmeVMatrixLog::s_defaultThreshold = 0.0f;
  747. float CDmeStringLog::s_defaultThreshold = 0.0f;
  748. void CDmeLogLayer::OnConstruction()
  749. {
  750. m_pOwnerLog = NULL;
  751. m_lastKey = 0;
  752. m_times.Init( this, "times" );
  753. m_CurveTypes.Init( this, "curvetypes" );
  754. }
  755. void CDmeLogLayer::OnDestruction()
  756. {
  757. }
  758. CDmeLog *CDmeLogLayer::GetOwnerLog()
  759. {
  760. return m_pOwnerLog;
  761. }
  762. const CDmeLog *CDmeLogLayer::GetOwnerLog() const
  763. {
  764. return m_pOwnerLog;
  765. }
  766. DmeTime_t CDmeLogLayer::GetBeginTime() const
  767. {
  768. if ( m_times.Count() == 0 )
  769. return DmeTime_t::MinTime();
  770. return DmeTime_t( m_times[ 0 ] );
  771. }
  772. DmeTime_t CDmeLogLayer::GetEndTime() const
  773. {
  774. uint tn = m_times.Count();
  775. if ( tn == 0 )
  776. return DmeTime_t::MaxTime();
  777. return DmeTime_t( m_times[ tn - 1 ] );
  778. }
  779. // Validates that all keys are correctly sorted in time
  780. bool CDmeLogLayer::ValidateKeys() const
  781. {
  782. int nCount = m_times.Count();
  783. for ( int i = 1; i < nCount; ++i )
  784. {
  785. if ( m_times[i] <= m_times[i-1] )
  786. {
  787. Warning( "Error in log %s! Key times are out of order [keys %d->%d: %d->%d]!\n",
  788. GetName(), i-1, i, m_times[i-1], m_times[i] );
  789. return false;
  790. }
  791. }
  792. return true;
  793. }
  794. int CDmeLogLayer::FindKey( DmeTime_t time ) const
  795. {
  796. int tn = m_times.Count();
  797. if ( m_lastKey >= 0 && m_lastKey < tn )
  798. {
  799. if ( time >= DmeTime_t( m_times[ m_lastKey ] ) )
  800. {
  801. // common case - playing forward
  802. for ( ; m_lastKey < tn - 1; ++m_lastKey )
  803. {
  804. if ( time < DmeTime_t( m_times[ m_lastKey + 1 ] ) )
  805. return m_lastKey;
  806. }
  807. // if time past the end, return the last key
  808. return m_lastKey;
  809. }
  810. else
  811. {
  812. tn = m_lastKey;
  813. }
  814. }
  815. for ( int ti = tn - 1; ti >= 0; --ti )
  816. {
  817. if ( time >= DmeTime_t( m_times[ ti ] ) )
  818. {
  819. m_lastKey = ti;
  820. return ti;
  821. }
  822. }
  823. return -1;
  824. }
  825. //-----------------------------------------------------------------------------
  826. // Returns the number of keys
  827. //-----------------------------------------------------------------------------
  828. int CDmeLogLayer::GetKeyCount() const
  829. {
  830. return m_times.Count();
  831. }
  832. //-----------------------------------------------------------------------------
  833. // Purpose:
  834. // Input : nKeyIndex -
  835. // keyTime -
  836. //-----------------------------------------------------------------------------
  837. void CDmeLogLayer::SetKeyTime( int nKeyIndex, DmeTime_t keyTime )
  838. {
  839. m_times.Set( nKeyIndex, keyTime.GetTenthsOfMS() );
  840. }
  841. //-----------------------------------------------------------------------------
  842. // Returns a specific key's value
  843. //-----------------------------------------------------------------------------
  844. DmeTime_t CDmeLogLayer::GetKeyTime( int nKeyIndex ) const
  845. {
  846. return DmeTime_t( m_times[ nKeyIndex ] );
  847. }
  848. //-----------------------------------------------------------------------------
  849. // Scale + bias key times
  850. //-----------------------------------------------------------------------------
  851. void CDmeLogLayer::ScaleBiasKeyTimes( double flScale, DmeTime_t nBias )
  852. {
  853. // Don't waste time on the identity transform
  854. if ( ( nBias == DMETIME_ZERO ) && ( fabs( flScale - 1.0 ) < 1e-5 ) )
  855. return;
  856. int nCount = GetKeyCount();
  857. for ( int i = 0; i < nCount; ++i )
  858. {
  859. DmeTime_t t = GetKeyTime( i );
  860. t.SetSeconds( t.GetSeconds() * flScale );
  861. t += nBias;
  862. SetKeyTime( i, t );
  863. }
  864. }
  865. //-----------------------------------------------------------------------------
  866. // Returns the index of a particular key
  867. //-----------------------------------------------------------------------------
  868. int CDmeLogLayer::FindKeyWithinTolerance( DmeTime_t nTime, DmeTime_t nTolerance )
  869. {
  870. int nClosest = -1;
  871. DmeTime_t nClosestTolerance = DmeTime_t::MaxTime();
  872. DmeTime_t nCurrTolerance;
  873. int start = 0, end = GetKeyCount() - 1;
  874. while ( start <= end )
  875. {
  876. int mid = (start + end) >> 1;
  877. DmeTime_t nDelta = nTime - DmeTime_t( m_times[mid] );
  878. if ( nDelta > DmeTime_t( 0 ) )
  879. {
  880. nCurrTolerance = nDelta;
  881. start = mid + 1;
  882. }
  883. else if ( nDelta < DmeTime_t( 0 ) )
  884. {
  885. nCurrTolerance = -nDelta;
  886. end = mid - 1;
  887. }
  888. else
  889. {
  890. return mid;
  891. }
  892. if ( nCurrTolerance < nClosestTolerance )
  893. {
  894. nClosest = mid;
  895. nClosestTolerance = nCurrTolerance;
  896. }
  897. }
  898. if ( nClosestTolerance > nTolerance )
  899. return -1;
  900. return nClosest;
  901. }
  902. void CDmeLogLayer::OnUsingCurveTypesChanged()
  903. {
  904. if ( g_pDataModel->IsUnserializing() )
  905. return;
  906. if ( !IsUsingCurveTypes() )
  907. {
  908. m_CurveTypes.RemoveAll();
  909. }
  910. else
  911. {
  912. m_CurveTypes.RemoveAll();
  913. // Fill in an array with the default curve type for
  914. int c = m_times.Count();
  915. for ( int i = 0; i < c; ++i )
  916. {
  917. m_CurveTypes.AddToTail( GetDefaultCurveType() );
  918. }
  919. }
  920. }
  921. bool CDmeLogLayer::IsUsingCurveTypes() const
  922. {
  923. return GetOwnerLog() ? GetOwnerLog()->IsUsingCurveTypes() : false;
  924. }
  925. int CDmeLogLayer::GetDefaultCurveType() const
  926. {
  927. return GetOwnerLog()->GetDefaultCurveType();
  928. }
  929. void CDmeLogLayer::SetKeyCurveType( int nKeyIndex, int curveType )
  930. {
  931. Assert( GetOwnerLog() );
  932. if ( !GetOwnerLog() )
  933. return;
  934. Assert( GetOwnerLog()->IsUsingCurveTypes() );
  935. Assert( m_CurveTypes.IsValidIndex( nKeyIndex ) );
  936. if ( !m_CurveTypes.IsValidIndex( nKeyIndex ) )
  937. return;
  938. m_CurveTypes.Set( nKeyIndex, curveType );
  939. }
  940. int CDmeLogLayer::GetKeyCurveType( int nKeyIndex ) const
  941. {
  942. Assert( GetOwnerLog() );
  943. if ( !GetOwnerLog() )
  944. return CURVE_DEFAULT;
  945. Assert( GetOwnerLog()->IsUsingCurveTypes() );
  946. Assert( m_CurveTypes.IsValidIndex( nKeyIndex ) );
  947. if ( !m_CurveTypes.IsValidIndex( nKeyIndex ) )
  948. return GetOwnerLog()->GetDefaultCurveType();
  949. return m_CurveTypes[ nKeyIndex ];
  950. }
  951. //-----------------------------------------------------------------------------
  952. // Removes all keys outside the specified time range
  953. //-----------------------------------------------------------------------------
  954. void CDmeLogLayer::RemoveKeysOutsideRange( DmeTime_t tStart, DmeTime_t tEnd )
  955. {
  956. int i;
  957. int nKeysToRemove = 0;
  958. int nKeyCount = m_times.Count();
  959. for ( i = 0; i < nKeyCount; ++i, ++nKeysToRemove )
  960. {
  961. if ( m_times[i] >= tStart.GetTenthsOfMS() )
  962. break;
  963. }
  964. if ( nKeysToRemove )
  965. {
  966. RemoveKey( 0, nKeysToRemove );
  967. }
  968. nKeyCount = m_times.Count();
  969. for ( i = 0; i < nKeyCount; ++i )
  970. {
  971. if ( m_times[i] > tEnd.GetTenthsOfMS() )
  972. break;
  973. }
  974. nKeysToRemove = nKeyCount - i;
  975. if ( nKeysToRemove )
  976. {
  977. RemoveKey( i, nKeysToRemove );
  978. }
  979. }
  980. template < class T >
  981. class CUndoLayerAdded : public CUndoElement
  982. {
  983. typedef CUndoElement BaseClass;
  984. public:
  985. CUndoLayerAdded( const char *desc, CDmeLog *pLog ) :
  986. BaseClass( desc ),
  987. m_bNeedsCleanup( false ),
  988. m_hLog( pLog )
  989. {
  990. Assert( pLog && pLog->GetFileId() != DMFILEID_INVALID );
  991. }
  992. virtual ~CUndoLayerAdded()
  993. {
  994. if ( m_bNeedsCleanup )
  995. {
  996. g_pDataModel->DestroyElement( m_hLayer );
  997. }
  998. }
  999. virtual void Undo()
  1000. {
  1001. m_bNeedsCleanup = true;
  1002. m_hLayer = m_hLog->RemoveLayerFromTail()->GetHandle();
  1003. g_pDataModel->MarkHandleInvalid( m_hLayer );
  1004. }
  1005. virtual void Redo()
  1006. {
  1007. m_bNeedsCleanup = false;
  1008. g_pDataModel->MarkHandleValid( m_hLayer );
  1009. m_hLog->AddLayerToTail( GetElement< CDmeTypedLogLayer< T > >( m_hLayer ) );
  1010. }
  1011. virtual const char *GetDesc()
  1012. {
  1013. static char sz[ 512 ];
  1014. int iLayer = m_hLog->GetTopmostLayer();
  1015. if ( iLayer >= 0 )
  1016. {
  1017. CDmeLogLayer *layer = m_hLog->GetLayer( iLayer );
  1018. Q_snprintf( sz, sizeof( sz ), "addlayer: log %p lc[%d], layer %p",
  1019. m_hLog.Get(), m_hLog->GetNumLayers(), layer );
  1020. }
  1021. else
  1022. {
  1023. Q_snprintf( sz, sizeof( sz ), "addlayer: log %p lc[%d], layer NULL",
  1024. m_hLog.Get(), m_hLog->GetNumLayers() );
  1025. }
  1026. return sz;
  1027. }
  1028. private:
  1029. CDmeHandle< CDmeLog > m_hLog;
  1030. bool m_bNeedsCleanup;
  1031. CDmeCountedHandle m_hLayer;
  1032. };
  1033. template < class T >
  1034. class CUndoFlattenLayers : public CUndoElement
  1035. {
  1036. typedef CUndoElement BaseClass;
  1037. public:
  1038. CUndoFlattenLayers( const char *desc, CDmeTypedLog< T > *pLog, float threshold, int flags ) :
  1039. BaseClass( desc ),
  1040. m_bNeedsCleanup( true ),
  1041. m_hLog( pLog ),
  1042. m_nFlags( flags ),
  1043. m_flThreshold( threshold )
  1044. {
  1045. Assert( pLog && pLog->GetFileId() != DMFILEID_INVALID );
  1046. LatchCurrentLayers();
  1047. }
  1048. virtual ~CUndoFlattenLayers()
  1049. {
  1050. if ( m_bNeedsCleanup )
  1051. {
  1052. for ( int i = 0; i < m_hLayers.Count(); ++i )
  1053. {
  1054. m_hLayers[ i ] = DMELEMENT_HANDLE_INVALID;
  1055. #ifdef _DEBUG
  1056. CDmElement *pElement = g_pDataModel->GetElement( m_hLayers[ i ] );
  1057. Assert( !pElement || pElement->IsStronglyReferenced() );
  1058. #endif
  1059. }
  1060. }
  1061. }
  1062. virtual void Undo()
  1063. {
  1064. m_bNeedsCleanup = false;
  1065. for ( int i = 0; i < m_hLayers.Count(); ++i )
  1066. {
  1067. if ( i == 0 )
  1068. {
  1069. // Copy base layer in place so handles to the base layer remain valid
  1070. CDmeTypedLogLayer< T > *base = m_hLog->GetLayer( i );
  1071. base->CopyLayer( GetElement< CDmeTypedLogLayer< T > >( m_hLayers[ i ] ) );
  1072. // Release it since we didn't txfer it over
  1073. g_pDataModel->DestroyElement( m_hLayers[ i ] );
  1074. }
  1075. else
  1076. {
  1077. // This transfers ownership, so no Release needed
  1078. m_hLog->AddLayerToTail( GetElement< CDmeTypedLogLayer< T > >( m_hLayers[ i ] ) );
  1079. }
  1080. }
  1081. m_hLayers.RemoveAll();
  1082. }
  1083. virtual void Redo()
  1084. {
  1085. m_bNeedsCleanup = true;
  1086. Assert( m_hLayers.Count() == 0 );
  1087. LatchCurrentLayers();
  1088. // Flatten them again (won't create undo records since we're in undo already)
  1089. m_hLog->FlattenLayers( m_flThreshold, m_nFlags );
  1090. }
  1091. virtual const char *GetDesc()
  1092. {
  1093. static char sz[ 512 ];
  1094. Q_snprintf( sz, sizeof( sz ), "flatten log %p lc[%d]",
  1095. m_hLog.Get(), m_hLayers.Count() );
  1096. return sz;
  1097. }
  1098. private:
  1099. void LatchCurrentLayers()
  1100. {
  1101. CDisableUndoScopeGuard guard;
  1102. Assert( m_hLayers.Count() == 0 );
  1103. Assert( m_hLog->GetNumLayers() >= 1 );
  1104. // Entry 0 is the original "base" layer
  1105. for ( int i = 0; i < m_hLog->GetNumLayers(); ++i )
  1106. {
  1107. CDmeTypedLogLayer< T > *pLayer = CastElement< CDmeTypedLogLayer< T > >( CreateLayer< T >( m_hLog ) );
  1108. pLayer->CopyLayer( m_hLog->GetLayer( i ) );
  1109. m_hLayers.AddToTail( pLayer->GetHandle() );
  1110. }
  1111. }
  1112. CDmeHandle< CDmeTypedLog< T > > m_hLog;
  1113. bool m_bNeedsCleanup;
  1114. CUtlVector< CDmeCountedHandle > m_hLayers;
  1115. int m_nFlags;
  1116. float m_flThreshold;
  1117. };
  1118. //-----------------------------------------------------------------------------
  1119. // CDmeTypedLogLayer - a generic typed layer used by a log
  1120. //-----------------------------------------------------------------------------
  1121. template< class T >
  1122. void CDmeTypedLogLayer< T >::OnConstruction()
  1123. {
  1124. // m_times.Init( this, "times" );
  1125. // m_CurveTypes.Init( this, "curvetypes" );
  1126. m_values.Init( this, "values" );
  1127. }
  1128. template< class T >
  1129. void CDmeTypedLogLayer< T >::SetOwnerLog( CDmeLog *owner )
  1130. {
  1131. Assert( owner );
  1132. Assert( assert_cast< CDmeTypedLog< T > * >( owner ) );
  1133. m_pOwnerLog = owner;
  1134. }
  1135. template< class T >
  1136. CDmeTypedLog< T > *CDmeTypedLogLayer< T >::GetTypedOwnerLog()
  1137. {
  1138. return assert_cast< CDmeTypedLog< T > * >( m_pOwnerLog );
  1139. }
  1140. template< class T >
  1141. const CDmeTypedLog< T > *CDmeTypedLogLayer< T >::GetTypedOwnerLog() const
  1142. {
  1143. return assert_cast< CDmeTypedLog< T > * >( m_pOwnerLog );
  1144. }
  1145. template< class T >
  1146. void CDmeTypedLogLayer< T >::OnDestruction()
  1147. {
  1148. }
  1149. template< class T >
  1150. void CDmeTypedLogLayer< T >::RemoveKeys( DmeTime_t starttime )
  1151. {
  1152. int ti = FindKey( starttime );
  1153. if ( ti < 0 )
  1154. return;
  1155. if ( starttime > DmeTime_t( m_times[ ti ] ) )
  1156. ++ti;
  1157. int nKeys = m_times.Count() - ti;
  1158. if ( nKeys == 0 )
  1159. return;
  1160. m_times.RemoveMultiple( ti, nKeys );
  1161. m_values.RemoveMultiple( ti, nKeys );
  1162. if ( IsUsingCurveTypes() )
  1163. {
  1164. m_CurveTypes.RemoveMultiple( ti, nKeys );
  1165. }
  1166. if ( m_lastKey >= ti && m_lastKey < ti + nKeys )
  1167. {
  1168. m_lastKey = ( ti > 0 ) ? ti - 1 : 0;
  1169. }
  1170. }
  1171. template< class T >
  1172. void CDmeTypedLogLayer< T >::ClearKeys()
  1173. {
  1174. m_times.RemoveAll();
  1175. m_values.RemoveAll();
  1176. m_CurveTypes.RemoveAll();
  1177. m_lastKey = 0;
  1178. }
  1179. template< class T >
  1180. void CDmeTypedLogLayer< T >::RemoveKey( int nKeyIndex, int nNumKeysToRemove /*= 1*/ )
  1181. {
  1182. m_times.RemoveMultiple( nKeyIndex, nNumKeysToRemove );
  1183. m_values.RemoveMultiple( nKeyIndex, nNumKeysToRemove );
  1184. if ( IsUsingCurveTypes() )
  1185. {
  1186. m_CurveTypes.RemoveMultiple( nKeyIndex, nNumKeysToRemove );
  1187. }
  1188. }
  1189. //-----------------------------------------------------------------------------
  1190. // Sets a key, removes all keys after this time
  1191. // FIXME: This needs to account for interpolation!!!
  1192. //-----------------------------------------------------------------------------
  1193. template< class T >
  1194. void CDmeTypedLogLayer< T >::SetKey( DmeTime_t time, const T& value, int curveType /*=CURVE_DEFAULT*/)
  1195. {
  1196. Assert( m_values.Count() == m_times.Count() );
  1197. Assert( !IsUsingCurveTypes() || ( m_CurveTypes.Count() == m_times.Count() ) );
  1198. // Remove all keys after this time
  1199. RemoveKeys( time );
  1200. // Add the key and then check to see if the penultimate key is still necessary
  1201. m_times.AddToTail( time.GetTenthsOfMS() );
  1202. m_values.AddToTail( value );
  1203. if ( IsUsingCurveTypes() )
  1204. {
  1205. m_CurveTypes.AddToTail( curveType );
  1206. }
  1207. int nKeys = m_values.Count();
  1208. if ( ( nKeys < 3 ) ||
  1209. ( IsUsingCurveTypes() && ( curveType != m_CurveTypes[ nKeys -1 ] || ( curveType != m_CurveTypes[ nKeys - 2 ] ) ) )
  1210. )
  1211. {
  1212. return;
  1213. }
  1214. // If adding the new means that the penultimate key's value was unneeded, then we will remove the penultimate key value
  1215. T check = GetValueSkippingKey( nKeys - 2 );
  1216. T oldPenultimateValue = m_values[ nKeys - 2 ];
  1217. if ( GetTypedOwnerLog()->ValuesDiffer( oldPenultimateValue, check ) )
  1218. {
  1219. return;
  1220. }
  1221. // Remove penultimate, it's not needed
  1222. m_times.Remove( nKeys - 2 );
  1223. m_values.Remove( nKeys - 2 );
  1224. if ( IsUsingCurveTypes() )
  1225. {
  1226. m_CurveTypes.Remove( nKeys - 2 );
  1227. }
  1228. }
  1229. //-----------------------------------------------------------------------------
  1230. // Finds a key within tolerance, or adds one
  1231. //-----------------------------------------------------------------------------
  1232. template< class T >
  1233. int CDmeTypedLogLayer< T >::FindOrAddKey( DmeTime_t nTime, DmeTime_t nTolerance, const T& value, int curveType /*=CURVE_DEFAULT*/ )
  1234. {
  1235. Assert( m_values.Count() == m_times.Count() );
  1236. Assert( !IsUsingCurveTypes() || ( m_CurveTypes.Count() == m_times.Count() ) );
  1237. // NOTE: This math must occur in 64bits because the max delta nDelta
  1238. // can be 33 bits large. Bleah.
  1239. int nClosest = -1;
  1240. int64 nClosestTolerance = DmeTime_t::MinTime().GetTenthsOfMS();
  1241. int64 nCurrTolerance;
  1242. int start = 0, end = GetKeyCount() - 1;
  1243. while ( start <= end )
  1244. {
  1245. int mid = (start + end) >> 1;
  1246. int64 nDelta = (int64)nTime.GetTenthsOfMS() - (int64)m_times[mid];
  1247. if ( nDelta > 0 )
  1248. {
  1249. nCurrTolerance = nDelta;
  1250. start = mid + 1;
  1251. }
  1252. else if ( nDelta < 0 )
  1253. {
  1254. nCurrTolerance = -nDelta;
  1255. end = mid - 1;
  1256. }
  1257. else
  1258. {
  1259. nClosest = end = mid;
  1260. nClosestTolerance = 0;
  1261. break;
  1262. }
  1263. if ( nCurrTolerance < nClosestTolerance )
  1264. {
  1265. nClosest = mid;
  1266. nClosestTolerance = nCurrTolerance;
  1267. }
  1268. }
  1269. // At this point, end is the entry less than or equal to the entry
  1270. if ( nClosest == -1 || nTolerance.GetTenthsOfMS() < nClosestTolerance )
  1271. {
  1272. ++end;
  1273. nClosest = m_times.InsertBefore( end, nTime.GetTenthsOfMS() );
  1274. m_values.InsertBefore( end, value );
  1275. if ( IsUsingCurveTypes() )
  1276. {
  1277. m_CurveTypes.InsertBefore( end, curveType );
  1278. }
  1279. }
  1280. return nClosest;
  1281. }
  1282. //-----------------------------------------------------------------------------
  1283. // This inserts a key. Unlike SetKey, this will *not* delete keys after the specified time
  1284. //-----------------------------------------------------------------------------
  1285. template < class T >
  1286. int CDmeTypedLogLayer< T >::InsertKey( DmeTime_t nTime, const T& value, int curveType /*=CURVE_DEFAULT*/ )
  1287. {
  1288. int idx = FindOrAddKey( nTime, DmeTime_t( 0 ), value );
  1289. m_times .Set( idx, nTime.GetTenthsOfMS() );
  1290. m_values.Set( idx, value );
  1291. if ( IsUsingCurveTypes() )
  1292. {
  1293. m_CurveTypes.Set( idx, curveType );
  1294. }
  1295. return idx;
  1296. }
  1297. template< class T >
  1298. int CDmeTypedLogLayer< T >::InsertKeyAtTime( DmeTime_t nTime, int curveType /*=CURVE_DEFAULT*/ )
  1299. {
  1300. T curVal = GetValue( nTime );
  1301. return InsertKey( nTime, curVal, curveType );
  1302. }
  1303. static bool CanInterpolateType( DmAttributeType_t attType )
  1304. {
  1305. switch ( attType )
  1306. {
  1307. default:
  1308. return false;
  1309. case AT_FLOAT:
  1310. case AT_VECTOR3:
  1311. case AT_QUATERNION:
  1312. break;
  1313. }
  1314. return true;
  1315. }
  1316. template< class T >
  1317. const T& CDmeTypedLogLayer< T >::GetValue( DmeTime_t time ) const
  1318. {
  1319. // Curve Interpolation only for 1-D float data right now!!!
  1320. if ( IsUsingCurveTypes() &&
  1321. CanInterpolateType( GetDataType() ) )
  1322. {
  1323. static T out;
  1324. GetValueUsingCurveInfo( time, out );
  1325. return out;
  1326. }
  1327. int tc = m_times.Count();
  1328. Assert( m_values.Count() == tc );
  1329. Assert( !IsUsingCurveTypes() || ( m_CurveTypes.Count() == tc ) );
  1330. int ti = FindKey( time );
  1331. if ( ti < 0 )
  1332. {
  1333. if ( tc > 0 )
  1334. return m_values[ 0 ];
  1335. const CDmeTypedLog< T > *pOwner = GetTypedOwnerLog();
  1336. if ( pOwner->HasDefaultValue() )
  1337. return pOwner->GetDefaultValue();
  1338. static T s_value;
  1339. CDmAttributeInfo< T >::SetDefaultValue( s_value ); // TODO - create GetDefaultValue that returns a default T, to avoid rebuilding every time
  1340. return s_value;
  1341. }
  1342. // Early out if we're at the end
  1343. if ( ti >= tc - 1 )
  1344. return m_values[ ti ];
  1345. if ( !IsInterpolableType( GetDataType() ) )
  1346. return m_values[ ti ];
  1347. // Figure out the lerp factor
  1348. float t = GetFractionOfTimeBetween( time, DmeTime_t( m_times[ti] ), DmeTime_t( m_times[ti+1] ) );
  1349. static T s_value;
  1350. s_value = Interpolate( t, m_values[ti], m_values[ti+1] ); // Compute the lerp between ti and ti+1
  1351. return s_value;
  1352. }
  1353. template< class T >
  1354. void CDmeTypedLogLayer< T >::SetKey( DmeTime_t time, const CDmAttribute *pAttr, uint index, int curveType /*= CURVE_DEFAULT*/ )
  1355. {
  1356. DmAttributeType_t type = pAttr->GetType();
  1357. if ( IsValueType( type ) )
  1358. {
  1359. Assert( pAttr->GetType() == GetDataType() );
  1360. SetKey( time, pAttr->GetValue< T >(), curveType );
  1361. }
  1362. else if ( IsArrayType( type ) )
  1363. {
  1364. Assert( ArrayTypeToValueType( type ) == GetDataType() );
  1365. CDmrArrayConst<T> array( pAttr );
  1366. SetKey( time, array[ index ], curveType );
  1367. }
  1368. else
  1369. {
  1370. Assert( 0 );
  1371. }
  1372. }
  1373. template< class T >
  1374. bool CDmeTypedLogLayer< T >::SetDuplicateKeyAtTime( DmeTime_t time )
  1375. {
  1376. int nKeys = m_times.Count();
  1377. if ( nKeys == 0 || DmeTime_t( m_times[ nKeys - 1 ] ) == time )
  1378. return false;
  1379. T value = GetValue( time );
  1380. // these two calls need to be separated (and we need to make an extra copy here) because
  1381. // CUtlVector has an assert to try to safeguard against inserting an existing value
  1382. // therefore, m_values.AddToTail( m_values[ i ] ) is illegal (or at least, triggers the assert)
  1383. SetKey( time, value );
  1384. return true;
  1385. }
  1386. //-----------------------------------------------------------------------------
  1387. // Returns a specific key's value
  1388. //-----------------------------------------------------------------------------
  1389. template< class T >
  1390. const T& CDmeTypedLogLayer< T >::GetKeyValue( int nKeyIndex ) const
  1391. {
  1392. Assert( m_values.Count() == m_times.Count() );
  1393. Assert( !IsUsingCurveTypes() || ( m_CurveTypes.Count() == m_times.Count() ) );
  1394. return m_values[ nKeyIndex ];
  1395. }
  1396. template< class T >
  1397. void CDmeTypedLogLayer< T >::GetValue( DmeTime_t time, CDmAttribute *pAttr, uint index ) const
  1398. {
  1399. DmAttributeType_t attrtype = pAttr->GetType();
  1400. if ( IsValueType( attrtype ) )
  1401. {
  1402. Assert( attrtype == GetDataType() );
  1403. pAttr->SetValue( GetValue( time ) );
  1404. }
  1405. else if ( IsArrayType( attrtype ) )
  1406. {
  1407. Assert( ArrayTypeToValueType( attrtype ) == GetDataType() );
  1408. CDmrArray<T> array( pAttr );
  1409. array.Set( index, GetValue( time ) );
  1410. }
  1411. else
  1412. {
  1413. Assert( 0 );
  1414. }
  1415. }
  1416. template< class T >
  1417. float CDmeTypedLogLayer< T >::GetComponent( DmeTime_t time, int componentIndex ) const
  1418. {
  1419. return ::GetComponent( GetValue( time ), componentIndex );
  1420. }
  1421. template< class T >
  1422. void CDmeTypedLogLayer< T >::SetKeyValue( int nKey, const T& value )
  1423. {
  1424. Assert( nKey >= 0 );
  1425. Assert( nKey < m_values.Count() );
  1426. m_values.Set( nKey, value );
  1427. }
  1428. //-----------------------------------------------------------------------------
  1429. // resampling and filtering
  1430. //-----------------------------------------------------------------------------
  1431. template< class T >
  1432. void CDmeTypedLogLayer< T >::Resample( DmeFramerate_t samplerate )
  1433. {
  1434. // FIXME: Might have to revisit how to determine "curve types" for "resampled points...
  1435. Assert( !IsUsingCurveTypes() );
  1436. // make sure we resample to include _at_least_ the existing time range
  1437. DmeTime_t begin = GetBeginTime();
  1438. DmeTime_t end = GetEndTime();
  1439. int nSamples = 2 + FrameForTime( end - begin, samplerate );
  1440. CUtlVector< int > resampledTimes;
  1441. CUtlVector< T > resampledValues;
  1442. CUtlVector< int > resampledCurveTypes;
  1443. resampledValues.EnsureCapacity( nSamples );
  1444. resampledTimes.EnsureCapacity( nSamples );
  1445. DmeTime_t time( begin );
  1446. for ( int i = 0; i < nSamples; ++i )
  1447. {
  1448. resampledTimes.AddToTail( time.GetTenthsOfMS() );
  1449. resampledValues.AddToTail( GetValue( time ) );
  1450. if ( IsUsingCurveTypes() )
  1451. {
  1452. resampledCurveTypes.AddToTail( CURVE_DEFAULT );
  1453. }
  1454. time = time.TimeAtNextFrame( samplerate );
  1455. }
  1456. m_times.SwapArray( resampledTimes );
  1457. m_values.SwapArray( resampledValues );
  1458. if ( IsUsingCurveTypes() )
  1459. {
  1460. m_CurveTypes.SwapArray( resampledCurveTypes );
  1461. }
  1462. }
  1463. template< class T >
  1464. void CDmeTypedLogLayer< T >::Filter( int nSampleRadius )
  1465. {
  1466. // Doesn't mess with curvetypes!!!
  1467. const CUtlVector< T > &values = m_values.Get();
  1468. CUtlVector< T > filteredValues;
  1469. int nValues = values.Count();
  1470. filteredValues.EnsureCapacity( nValues );
  1471. for ( int i = 0; i < nValues; ++i )
  1472. {
  1473. int nSamples = min( nSampleRadius, min( i, nValues - i - 1 ) );
  1474. filteredValues.AddToTail( Average( values.Base() + i - nSamples, 2 * nSamples + 1 ) );
  1475. }
  1476. m_values.SwapArray( filteredValues );
  1477. }
  1478. template< class T >
  1479. void CDmeTypedLogLayer< T >::Filter2( DmeTime_t sampleRadius )
  1480. {
  1481. // Doesn't mess with curvetypes!!!
  1482. const CUtlVector< T > &values = m_values.Get();
  1483. CUtlVector< T > filteredValues;
  1484. int nValues = values.Count();
  1485. filteredValues.EnsureCapacity( nValues );
  1486. DmeTime_t earliest = DMETIME_ZERO;
  1487. if ( nValues > 0 )
  1488. {
  1489. earliest = DmeTime_t( m_times[ 0 ] );
  1490. }
  1491. for ( int i = 0; i < nValues; ++i )
  1492. {
  1493. T vals[ 3 ];
  1494. DmeTime_t t = GetKeyTime( i );
  1495. DmeTime_t t0 = t - sampleRadius;
  1496. DmeTime_t t1 = t + sampleRadius;
  1497. if ( t0 >= earliest )
  1498. {
  1499. vals[ 0 ] = GetValue( t0 );
  1500. }
  1501. else
  1502. {
  1503. vals[ 0 ] = m_values[ 0 ];
  1504. }
  1505. vals[ 1 ] = GetValue( t );
  1506. vals[ 2 ] = GetValue( t1 );
  1507. if ( i == 0 || i == nValues - 1 )
  1508. {
  1509. filteredValues.AddToTail( values[ i ] );
  1510. }
  1511. else
  1512. {
  1513. filteredValues.AddToTail( Average( vals, 3 ) );
  1514. }
  1515. }
  1516. m_values.SwapArray( filteredValues );
  1517. }
  1518. template< class T >
  1519. const T& CDmeTypedLogLayer< T >::GetValueSkippingKey( int nKeyToSkip ) const
  1520. {
  1521. // Curve Interpolation only for 1-D float data right now!!!
  1522. if ( IsUsingCurveTypes() && CanInterpolateType( GetDataType() ) )
  1523. {
  1524. static T out;
  1525. GetValueUsingCurveInfoSkippingKey( nKeyToSkip, out );
  1526. return out;
  1527. }
  1528. Assert( m_values.Count() == m_times.Count() );
  1529. Assert( !IsUsingCurveTypes() || ( m_CurveTypes.Count() == m_times.Count() ) );
  1530. DmeTime_t time = GetKeyTime( nKeyToSkip );
  1531. int prevKey = nKeyToSkip - 1;
  1532. int nextKey = nKeyToSkip + 1;
  1533. DmeTime_t prevTime;
  1534. T prevValue;
  1535. int prevCurveType;
  1536. DmeTime_t nextTime;
  1537. T nextValue;
  1538. int nextCurveType;
  1539. GetBoundedSample( prevKey, prevTime, prevValue, prevCurveType );
  1540. GetBoundedSample( nextKey, nextTime, nextValue, nextCurveType );
  1541. // Figure out the lerp factor
  1542. float t = GetFractionOfTimeBetween( time, prevTime, nextTime );
  1543. static T s_value;
  1544. s_value = Interpolate( t, prevValue, nextValue );
  1545. return s_value;
  1546. }
  1547. template< class T >
  1548. void CDmeTypedLog<T>::RemoveRedundantKeys( float threshold )
  1549. {
  1550. int bestLayer = GetTopmostLayer();
  1551. if ( bestLayer < 0 )
  1552. return;
  1553. GetLayer( bestLayer )->RemoveRedundantKeys( threshold );
  1554. }
  1555. template< class T >
  1556. void CDmeTypedLogLayer<T>::RemoveRedundantKeys( float threshold )
  1557. {
  1558. Assert( GetTypedOwnerLog() );
  1559. if ( !GetTypedOwnerLog() )
  1560. return;
  1561. float saveThreshold;
  1562. {
  1563. CDisableUndoScopeGuard sg;
  1564. saveThreshold = GetTypedOwnerLog()->GetValueThreshold();
  1565. GetTypedOwnerLog()->SetValueThreshold( threshold );
  1566. }
  1567. RemoveRedundantKeys();
  1568. {
  1569. CDisableUndoScopeGuard sg;
  1570. GetTypedOwnerLog()->SetValueThreshold( saveThreshold );
  1571. }
  1572. }
  1573. // Implementation of Douglas-Peucker curve simplification routine (hacked to only care about error against original curve (sort of 1D)
  1574. template< class T >
  1575. void CDmeTypedLogLayer< T >::CurveSimplify_R( float thresholdSqr, int startPoint, int endPoint, CDmeTypedLogLayer< T > *output )
  1576. {
  1577. if ( endPoint <= startPoint + 1 )
  1578. {
  1579. return;
  1580. }
  1581. int maxPoint = startPoint;
  1582. float maxDistanceSqr = 0.0f;
  1583. for ( int i = startPoint + 1 ; i < endPoint; ++i )
  1584. {
  1585. DmeTime_t keyTime = GetKeyTime( i );
  1586. T check = GetKeyValue( i );
  1587. T check2 = output->GetValue( keyTime );
  1588. T dist = Subtract( check, check2 );
  1589. float distSqr = LengthOf( dist ) * LengthOf( dist );
  1590. if ( distSqr < maxDistanceSqr )
  1591. continue;
  1592. maxPoint = i;
  1593. maxDistanceSqr = distSqr;
  1594. }
  1595. if ( maxDistanceSqr > thresholdSqr )
  1596. {
  1597. output->InsertKey( GetKeyTime( maxPoint ), GetKeyValue( maxPoint ) );
  1598. CurveSimplify_R( thresholdSqr, startPoint, maxPoint, output );
  1599. CurveSimplify_R( thresholdSqr, maxPoint, endPoint, output );
  1600. }
  1601. }
  1602. template<> void CDmeTypedLogLayer< bool >::CurveSimplify_R( float thresholdSqr, int startPoint, int endPoint, CDmeTypedLogLayer< bool > *output ) {};
  1603. template<> void CDmeTypedLogLayer< int >::CurveSimplify_R( float thresholdSqr, int startPoint, int endPoint, CDmeTypedLogLayer< int > *output ) {};
  1604. template<> void CDmeTypedLogLayer< Color >::CurveSimplify_R( float thresholdSqr, int startPoint, int endPoint, CDmeTypedLogLayer< Color > *output ) {};
  1605. template<> void CDmeTypedLogLayer< Quaternion >::CurveSimplify_R( float thresholdSqr, int startPoint, int endPoint, CDmeTypedLogLayer< Quaternion > *output ) {};
  1606. template<> void CDmeTypedLogLayer< VMatrix >::CurveSimplify_R( float thresholdSqr, int startPoint, int endPoint, CDmeTypedLogLayer< VMatrix > *output ) {};
  1607. // We can't just walk the keys linearly since it'll accumulate too much error and give us a bad curve after simplification. We do a recursive subdivide which has a worst case of O(n^2) but
  1608. // probably is better than that in most cases.
  1609. template< class T >
  1610. void CDmeTypedLogLayer<T>::RemoveRedundantKeys()
  1611. {
  1612. CDmeTypedLog< T > *pOwner = GetTypedOwnerLog();
  1613. if ( !pOwner )
  1614. return;
  1615. int nKeys = GetKeyCount();
  1616. if ( nKeys <= 2 )
  1617. return;
  1618. float thresh = pOwner->GetValueThreshold();
  1619. if ( thresh < 0.0f )
  1620. return;
  1621. CDmeTypedLogLayer< T > *save = 0;
  1622. {
  1623. CDisableUndoScopeGuard guard;
  1624. save = CastElement< CDmeTypedLogLayer< T > >( CreateLayer< T >( pOwner ) );
  1625. Assert( save );
  1626. save->m_times.EnsureCapacity( nKeys );
  1627. save->m_values.EnsureCapacity( nKeys );
  1628. // Insert start and end points as first "guess" at simplified curve
  1629. // Skip preceeding and ending keys that have the same value
  1630. int nFirstKey, nLastKey;
  1631. for ( nFirstKey = 1; nFirstKey < nKeys; ++nFirstKey )
  1632. {
  1633. // FIXME: Should we use a tolerance check here?
  1634. if ( GetKeyValue( nFirstKey ) != GetKeyValue( nFirstKey - 1 ) )
  1635. break;
  1636. }
  1637. --nFirstKey;
  1638. for ( nLastKey = nKeys; --nLastKey >= 1; )
  1639. {
  1640. // FIXME: Should we use a tolerance check here?
  1641. if ( GetKeyValue( nLastKey ) != GetKeyValue( nLastKey - 1 ) )
  1642. break;
  1643. }
  1644. if ( nLastKey <= nFirstKey )
  1645. {
  1646. save->InsertKey( GetKeyTime( 0 ), GetKeyValue( 0 ) );
  1647. }
  1648. else
  1649. {
  1650. if ( GetDataType() == AT_FLOAT )
  1651. {
  1652. save->InsertKey( GetKeyTime( nFirstKey ), GetKeyValue( nFirstKey ) );
  1653. save->InsertKey( GetKeyTime( nLastKey ), GetKeyValue( nLastKey ) );
  1654. // Recursively finds the point with the largest error from the "simplified curve" and subdivides the problem on both sides until the largest delta from the simplified
  1655. // curve is less than the tolerance (squared)
  1656. CurveSimplify_R( thresh * thresh, nFirstKey, nLastKey, save );
  1657. }
  1658. else
  1659. {
  1660. save->InsertKey( GetKeyTime( nFirstKey ), GetKeyValue( nFirstKey ) );
  1661. // copy over keys that differ from their prior or next keys - this keeps the first and last key of a run of same-valued keys
  1662. for ( int i = nFirstKey + 1; i < nLastKey; ++i )
  1663. {
  1664. // prev is from the saved log to allow deleting runs of same-valued keys
  1665. const T &prev = save->GetKeyValue( save->GetKeyCount() - 1 );
  1666. const T &curr = GetKeyValue( i );
  1667. const T &next = GetKeyValue( i + 1 );
  1668. if ( pOwner->ValuesDiffer( prev, curr ) || pOwner->ValuesDiffer( curr, next ) )
  1669. {
  1670. save->InsertKey( GetKeyTime( i ), curr );
  1671. }
  1672. }
  1673. save->InsertKey( GetKeyTime( nLastKey ), GetKeyValue( nLastKey ) );
  1674. }
  1675. }
  1676. }
  1677. // This operation is undoable
  1678. CopyLayer( save );
  1679. {
  1680. CDisableUndoScopeGuard guard;
  1681. g_pDataModel->DestroyElement( save->GetHandle() );
  1682. }
  1683. }
  1684. // curve info helpers
  1685. template< class T >
  1686. const CDmeTypedCurveInfo< T > *CDmeTypedLogLayer<T>::GetTypedCurveInfo() const
  1687. {
  1688. Assert( GetTypedOwnerLog() );
  1689. return GetTypedOwnerLog()->GetTypedCurveInfo();
  1690. }
  1691. template< class T >
  1692. CDmeTypedCurveInfo< T > *CDmeTypedLogLayer<T>::GetTypedCurveInfo()
  1693. {
  1694. Assert( GetTypedOwnerLog() );
  1695. return GetTypedOwnerLog()->GetTypedCurveInfo();
  1696. }
  1697. template< class T >
  1698. bool CDmeTypedLogLayer< T >::IsUsingEdgeInfo() const
  1699. {
  1700. return GetTypedOwnerLog()->IsUsingEdgeInfo();
  1701. }
  1702. template< class T >
  1703. const T& CDmeTypedLogLayer< T >::GetDefaultEdgeZeroValue() const
  1704. {
  1705. return GetTypedOwnerLog()->GetDefaultEdgeZeroValue();
  1706. }
  1707. template< class T >
  1708. DmeTime_t CDmeTypedLogLayer< T >::GetRightEdgeTime() const
  1709. {
  1710. return GetTypedOwnerLog()->GetRightEdgeTime();
  1711. }
  1712. template< class T >
  1713. void CDmeTypedLogLayer< T >::GetEdgeInfo( int edge, bool& active, T& val, int& curveType ) const
  1714. {
  1715. GetTypedOwnerLog()->GetEdgeInfo( edge, active, val, curveType );
  1716. }
  1717. template< class T >
  1718. int CDmeTypedLogLayer< T >::GetEdgeCurveType( int edge ) const
  1719. {
  1720. return GetTypedOwnerLog()->GetEdgeCurveType( edge );
  1721. }
  1722. template< class T >
  1723. void CDmeTypedLogLayer< T >::GetZeroValue( int side, T& val ) const
  1724. {
  1725. return GetTypedOwnerLog()->GetZeroValue( side, val );
  1726. }
  1727. template< class T >
  1728. void CDmeTypedLogLayer< T >::GetBoundedSample( int keyindex, DmeTime_t& time, T& val, int& curveType ) const
  1729. {
  1730. Assert( GetOwnerLog() );
  1731. if ( !GetOwnerLog() )
  1732. {
  1733. time = DmeTime_t( 0 );
  1734. CDmAttributeInfo< T >::SetDefaultValue( val );
  1735. curveType = CURVE_DEFAULT;
  1736. return;
  1737. }
  1738. if ( keyindex < 0 )
  1739. {
  1740. time = DmeTime_t( 0 );
  1741. GetZeroValue( 0, val );
  1742. curveType = GetEdgeCurveType( 0 );
  1743. return;
  1744. }
  1745. else if ( keyindex >= m_times.Count() )
  1746. {
  1747. time = GetTypedOwnerLog()->GetRightEdgeTime();
  1748. if ( time == DmeTime_t( 0 ) && m_times.Count() > 0 )
  1749. {
  1750. // Push it one msec past the final end time
  1751. time = DmeTime_t( m_times[ m_times.Count() - 1 ] ) + DmeTime_t( 1 );
  1752. }
  1753. GetTypedOwnerLog()->GetZeroValue( 1, val );
  1754. curveType = GetTypedOwnerLog()->GetEdgeCurveType( 1 );
  1755. return;
  1756. }
  1757. time = DmeTime_t( m_times[ keyindex ] );
  1758. val = m_values[ keyindex ];
  1759. if ( IsUsingCurveTypes() )
  1760. {
  1761. curveType = m_CurveTypes[ keyindex ];
  1762. if ( curveType == CURVE_DEFAULT )
  1763. {
  1764. curveType = GetTypedOwnerLog()->GetDefaultCurveType();
  1765. }
  1766. }
  1767. }
  1768. template<>
  1769. void CDmeTypedLogLayer< float >::GetValueUsingCurveInfoSkippingKey( int nKeyToSkip, float& out ) const
  1770. {
  1771. Assert( GetOwnerLog() );
  1772. if ( !GetOwnerLog() )
  1773. {
  1774. out = 0.0f;
  1775. return;
  1776. }
  1777. Assert( CanInterpolateType( GetDataType() ) );
  1778. Assert( m_values.Count() == m_times.Count() );
  1779. Assert( !IsUsingCurveTypes() || ( m_CurveTypes.Count() == m_times.Count() ) );
  1780. Assert( IsInterpolableType( GetDataType() ) );
  1781. float v[ 4 ];
  1782. DmeTime_t t[ 4 ];
  1783. int curvetypes[ 4 ];
  1784. int ti = nKeyToSkip;
  1785. DmeTime_t time = GetKeyTime( nKeyToSkip );
  1786. if ( !IsUsingCurveTypes() )
  1787. {
  1788. if ( ti < 0 )
  1789. {
  1790. CDmAttributeInfo< float >::SetDefaultValue( out ); // TODO - create GetDefaultValue that returns a default T, to avoid rebuilding every time
  1791. return;
  1792. }
  1793. else if ( ti >= m_times.Count() - 1 )
  1794. {
  1795. out = m_values[ ti + 1 ];
  1796. return;
  1797. }
  1798. }
  1799. DmeTime_t finalTime = GetTypedOwnerLog()->GetRightEdgeTime();
  1800. if ( finalTime != DmeTime_t( 0 ) )
  1801. {
  1802. if ( time > finalTime )
  1803. {
  1804. GetZeroValue( 1, out );
  1805. return;
  1806. }
  1807. }
  1808. else
  1809. {
  1810. if ( ti >= m_times.Count() - 1 )
  1811. {
  1812. out = m_values[ ti + 1 ];
  1813. return;
  1814. }
  1815. }
  1816. GetBoundedSample( ti - 2, t[ 0 ], v[ 0 ], curvetypes[ 0 ] );
  1817. GetBoundedSample( ti - 1, t[ 1 ], v[ 1 ], curvetypes[ 1 ] );
  1818. GetBoundedSample( ti + 1, t[ 2 ], v[ 2 ], curvetypes[ 2 ] );
  1819. GetBoundedSample( ti + 2, t[ 3 ], v[ 3 ], curvetypes[ 3 ] );
  1820. float frac = 0.0f;
  1821. if ( t[2] > t[ 1 ] )
  1822. {
  1823. frac = (time.GetSeconds() - t[1].GetSeconds()) / (float) ( t[2].GetSeconds() - t[ 1 ].GetSeconds() );
  1824. }
  1825. // Compute the lerp between ti and ti+1
  1826. out = Curve_Interpolate( frac, t, v, curvetypes, GetOwnerLog()->GetMinValue(), GetOwnerLog()->GetMaxValue() );
  1827. }
  1828. template<>
  1829. void CDmeTypedLogLayer< Vector >::GetValueUsingCurveInfoSkippingKey( int nKeyToSkip, Vector& out ) const
  1830. {
  1831. Assert( GetOwnerLog() );
  1832. if ( !GetOwnerLog() )
  1833. {
  1834. CDmAttributeInfo< Vector >::SetDefaultValue( out );
  1835. return;
  1836. }
  1837. Assert( CanInterpolateType( GetDataType() ) );
  1838. Assert( m_values.Count() == m_times.Count() );
  1839. Assert( !IsUsingCurveTypes() || ( m_CurveTypes.Count() == m_times.Count() ) );
  1840. Assert( IsInterpolableType( GetDataType() ) );
  1841. Vector v[ 4 ];
  1842. DmeTime_t t[ 4 ];
  1843. int curvetypes[ 4 ];
  1844. int ti = nKeyToSkip;
  1845. DmeTime_t time = GetKeyTime( nKeyToSkip );
  1846. if ( !IsUsingCurveTypes() )
  1847. {
  1848. if ( ti < 0 )
  1849. {
  1850. CDmAttributeInfo< Vector >::SetDefaultValue( out ); // TODO - create GetDefaultValue that returns a default T, to avoid rebuilding every time
  1851. return;
  1852. }
  1853. else if ( ti >= m_times.Count() - 1 )
  1854. {
  1855. out = m_values[ ti + 1 ];
  1856. return;
  1857. }
  1858. }
  1859. DmeTime_t finalTime = GetTypedOwnerLog()->GetRightEdgeTime();
  1860. if ( finalTime != DmeTime_t( 0 ) )
  1861. {
  1862. if ( time > finalTime )
  1863. {
  1864. CDmAttributeInfo< Vector >::SetDefaultValue( out );
  1865. return;
  1866. }
  1867. }
  1868. else
  1869. {
  1870. if ( ti >= m_times.Count() - 1 )
  1871. {
  1872. out = m_values[ ti + 1 ];
  1873. return;
  1874. }
  1875. }
  1876. GetBoundedSample( ti - 2, t[ 0 ], v[ 0 ], curvetypes[ 0 ] );
  1877. GetBoundedSample( ti - 1, t[ 1 ], v[ 1 ], curvetypes[ 1 ] );
  1878. GetBoundedSample( ti + 1, t[ 2 ], v[ 2 ], curvetypes[ 2 ] );
  1879. GetBoundedSample( ti + 2, t[ 3 ], v[ 3 ], curvetypes[ 3 ] );
  1880. float frac = 0.0f;
  1881. if ( t[2] > t[ 1 ] )
  1882. {
  1883. frac = (time.GetSeconds() - t[1].GetSeconds()) / (float) ( t[2].GetSeconds() - t[ 1 ].GetSeconds() );
  1884. }
  1885. // Compute the lerp between ti and ti+1
  1886. out = Curve_Interpolate( frac, t, v, curvetypes, GetOwnerLog()->GetMinValue(), GetOwnerLog()->GetMaxValue() );
  1887. }
  1888. template<>
  1889. void CDmeTypedLogLayer< Quaternion >::GetValueUsingCurveInfoSkippingKey( int nKeyToSkip, Quaternion& out ) const
  1890. {
  1891. Assert( GetOwnerLog() );
  1892. if ( !GetOwnerLog() )
  1893. {
  1894. CDmAttributeInfo< Quaternion >::SetDefaultValue( out );
  1895. return;
  1896. }
  1897. Assert( CanInterpolateType( GetDataType() ) );
  1898. Assert( m_values.Count() == m_times.Count() );
  1899. Assert( !IsUsingCurveTypes() || ( m_CurveTypes.Count() == m_times.Count() ) );
  1900. Assert( IsInterpolableType( GetDataType() ) );
  1901. Quaternion v[ 4 ];
  1902. DmeTime_t t[ 4 ];
  1903. int curvetypes[ 4 ];
  1904. int ti = nKeyToSkip;
  1905. DmeTime_t time = GetKeyTime( nKeyToSkip );
  1906. if ( !IsUsingCurveTypes() )
  1907. {
  1908. if ( ti < 0 )
  1909. {
  1910. CDmAttributeInfo< Quaternion >::SetDefaultValue( out ); // TODO - create GetDefaultValue that returns a default T, to avoid rebuilding every time
  1911. return;
  1912. }
  1913. else if ( ti >= m_times.Count() - 1 )
  1914. {
  1915. out = m_values[ ti + 1 ];
  1916. return;
  1917. }
  1918. }
  1919. DmeTime_t finalTime = GetTypedOwnerLog()->GetRightEdgeTime();
  1920. if ( finalTime != DmeTime_t( 0 ) )
  1921. {
  1922. if ( time > finalTime )
  1923. {
  1924. CDmAttributeInfo< Quaternion >::SetDefaultValue( out );
  1925. return;
  1926. }
  1927. }
  1928. else
  1929. {
  1930. if ( ti >= m_times.Count() - 1 )
  1931. {
  1932. out = m_values[ ti + 1 ];
  1933. return;
  1934. }
  1935. }
  1936. GetBoundedSample( ti - 2, t[ 0 ], v[ 0 ], curvetypes[ 0 ] );
  1937. GetBoundedSample( ti - 1, t[ 1 ], v[ 1 ], curvetypes[ 1 ] );
  1938. GetBoundedSample( ti + 1, t[ 2 ], v[ 2 ], curvetypes[ 2 ] );
  1939. GetBoundedSample( ti + 2, t[ 3 ], v[ 3 ], curvetypes[ 3 ] );
  1940. float frac = 0.0f;
  1941. if ( t[2] > t[ 1 ] )
  1942. {
  1943. frac = (time.GetSeconds() - t[1].GetSeconds()) / (float) ( t[2].GetSeconds() - t[ 1 ].GetSeconds() );
  1944. }
  1945. // Compute the lerp between ti and ti+1
  1946. out = Curve_Interpolate( frac, t, v, curvetypes, GetOwnerLog()->GetMinValue(), GetOwnerLog()->GetMaxValue() );
  1947. }
  1948. template<>
  1949. void CDmeTypedLogLayer< float >::GetValueUsingCurveInfo( DmeTime_t time, float& out ) const
  1950. {
  1951. Assert( GetOwnerLog() );
  1952. if ( !GetOwnerLog() )
  1953. {
  1954. out = 0.0f;
  1955. return;
  1956. }
  1957. Assert( CanInterpolateType( GetDataType() ) );
  1958. Assert( m_values.Count() == m_times.Count() );
  1959. Assert( !IsUsingCurveTypes() || ( m_CurveTypes.Count() == m_times.Count() ) );
  1960. Assert( IsInterpolableType( GetDataType() ) );
  1961. float v[ 4 ];
  1962. DmeTime_t t[ 4 ];
  1963. int curvetypes[ 4 ];
  1964. int ti = FindKey( time );
  1965. if ( !IsUsingCurveTypes() )
  1966. {
  1967. if ( ti < 0 )
  1968. {
  1969. CDmAttributeInfo< float >::SetDefaultValue( out ); // TODO - create GetDefaultValue that returns a default T, to avoid rebuilding every time
  1970. return;
  1971. }
  1972. else if ( ti >= m_times.Count() - 1 )
  1973. {
  1974. out = m_values[ ti ];
  1975. return;
  1976. }
  1977. }
  1978. DmeTime_t finalTime = GetTypedOwnerLog()->GetRightEdgeTime();
  1979. if ( finalTime != DmeTime_t( 0 ) )
  1980. {
  1981. if ( time > finalTime )
  1982. {
  1983. GetZeroValue( 1, out );
  1984. return;
  1985. }
  1986. }
  1987. else
  1988. {
  1989. if ( ti >= m_times.Count() - 1 )
  1990. {
  1991. out = m_values[ ti ];
  1992. return;
  1993. }
  1994. }
  1995. GetBoundedSample( ti - 1, t[ 0 ], v[ 0 ], curvetypes[ 0 ] );
  1996. GetBoundedSample( ti + 0, t[ 1 ], v[ 1 ], curvetypes[ 1 ] );
  1997. GetBoundedSample( ti + 1, t[ 2 ], v[ 2 ], curvetypes[ 2 ] );
  1998. GetBoundedSample( ti + 2, t[ 3 ], v[ 3 ], curvetypes[ 3 ] );
  1999. float frac = 0.0f;
  2000. if ( t[2] > t[ 1 ] )
  2001. {
  2002. frac = (time.GetSeconds() - t[1].GetSeconds()) / (float) ( t[2].GetSeconds() - t[ 1 ].GetSeconds() );
  2003. }
  2004. // Compute the lerp between ti and ti+1
  2005. out = Curve_Interpolate( frac, t, v, curvetypes, GetOwnerLog()->GetMinValue(), GetOwnerLog()->GetMaxValue() );
  2006. }
  2007. template<>
  2008. void CDmeTypedLogLayer< Vector >::GetValueUsingCurveInfo( DmeTime_t time, Vector& out ) const
  2009. {
  2010. Assert( GetOwnerLog() );
  2011. if ( !GetOwnerLog() )
  2012. {
  2013. CDmAttributeInfo< Vector >::SetDefaultValue( out );
  2014. return;
  2015. }
  2016. Assert( CanInterpolateType( GetDataType() ) );
  2017. Assert( m_values.Count() == m_times.Count() );
  2018. Assert( !IsUsingCurveTypes() || ( m_CurveTypes.Count() == m_times.Count() ) );
  2019. Assert( IsInterpolableType( GetDataType() ) );
  2020. Vector v[ 4 ];
  2021. DmeTime_t t[ 4 ];
  2022. int curvetypes[ 4 ];
  2023. int ti = FindKey( time );
  2024. if ( !IsUsingCurveTypes() )
  2025. {
  2026. if ( ti < 0 )
  2027. {
  2028. CDmAttributeInfo< Vector >::SetDefaultValue( out ); // TODO - create GetDefaultValue that returns a default T, to avoid rebuilding every time
  2029. return;
  2030. }
  2031. else if ( ti >= m_times.Count() - 1 )
  2032. {
  2033. out = m_values[ ti ];
  2034. return;
  2035. }
  2036. }
  2037. DmeTime_t finalTime = GetTypedOwnerLog()->GetRightEdgeTime();
  2038. if ( finalTime != DmeTime_t( 0 ) )
  2039. {
  2040. if ( time > finalTime )
  2041. {
  2042. CDmAttributeInfo< Vector >::SetDefaultValue( out );
  2043. return;
  2044. }
  2045. }
  2046. else
  2047. {
  2048. if ( ti >= m_times.Count() - 1 )
  2049. {
  2050. out = m_values[ ti ];
  2051. return;
  2052. }
  2053. }
  2054. GetBoundedSample( ti - 1, t[ 0 ], v[ 0 ], curvetypes[ 0 ] );
  2055. GetBoundedSample( ti + 0, t[ 1 ], v[ 1 ], curvetypes[ 1 ] );
  2056. GetBoundedSample( ti + 1, t[ 2 ], v[ 2 ], curvetypes[ 2 ] );
  2057. GetBoundedSample( ti + 2, t[ 3 ], v[ 3 ], curvetypes[ 3 ] );
  2058. float frac = 0.0f;
  2059. if ( t[2] > t[ 1 ] )
  2060. {
  2061. frac = (time.GetSeconds() - t[1].GetSeconds()) / (float) ( t[2].GetSeconds() - t[ 1 ].GetSeconds() );
  2062. }
  2063. // Compute the lerp between ti and ti+1
  2064. out = Curve_Interpolate( frac, t, v, curvetypes, GetOwnerLog()->GetMinValue(), GetOwnerLog()->GetMaxValue() );
  2065. }
  2066. template<>
  2067. void CDmeTypedLogLayer< Quaternion >::GetValueUsingCurveInfo( DmeTime_t time, Quaternion& out ) const
  2068. {
  2069. Assert( GetOwnerLog() );
  2070. if ( !GetOwnerLog() )
  2071. {
  2072. CDmAttributeInfo< Quaternion >::SetDefaultValue( out );
  2073. return;
  2074. }
  2075. Assert( CanInterpolateType( GetDataType() ) );
  2076. Assert( m_values.Count() == m_times.Count() );
  2077. Assert( !IsUsingCurveTypes() || ( m_CurveTypes.Count() == m_times.Count() ) );
  2078. Assert( IsInterpolableType( GetDataType() ) );
  2079. Quaternion v[ 4 ];
  2080. DmeTime_t t[ 4 ];
  2081. int curvetypes[ 4 ];
  2082. int ti = FindKey( time );
  2083. if ( !IsUsingCurveTypes() )
  2084. {
  2085. if ( ti < 0 )
  2086. {
  2087. CDmAttributeInfo< Quaternion >::SetDefaultValue( out ); // TODO - create GetDefaultValue that returns a default T, to avoid rebuilding every time
  2088. return;
  2089. }
  2090. else if ( ti >= m_times.Count() - 1 )
  2091. {
  2092. out = m_values[ ti ];
  2093. return;
  2094. }
  2095. }
  2096. DmeTime_t finalTime = GetTypedOwnerLog()->GetRightEdgeTime();
  2097. if ( finalTime != DmeTime_t( 0 ) )
  2098. {
  2099. if ( time > finalTime )
  2100. {
  2101. CDmAttributeInfo< Quaternion >::SetDefaultValue( out );
  2102. return;
  2103. }
  2104. }
  2105. else
  2106. {
  2107. if ( ti >= m_times.Count() - 1 )
  2108. {
  2109. out = m_values[ ti ];
  2110. return;
  2111. }
  2112. }
  2113. GetBoundedSample( ti - 1, t[ 0 ], v[ 0 ], curvetypes[ 0 ] );
  2114. GetBoundedSample( ti + 0, t[ 1 ], v[ 1 ], curvetypes[ 1 ] );
  2115. GetBoundedSample( ti + 1, t[ 2 ], v[ 2 ], curvetypes[ 2 ] );
  2116. GetBoundedSample( ti + 2, t[ 3 ], v[ 3 ], curvetypes[ 3 ] );
  2117. float frac = 0.0f;
  2118. if ( t[2] > t[ 1 ] )
  2119. {
  2120. frac = (time.GetSeconds() - t[1].GetSeconds()) / (float) ( t[2].GetSeconds() - t[ 1 ].GetSeconds() );
  2121. }
  2122. // Compute the lerp between ti and ti+1
  2123. out = Curve_Interpolate( frac, t, v, curvetypes, GetOwnerLog()->GetMinValue(), GetOwnerLog()->GetMaxValue() );
  2124. }
  2125. template< class T >
  2126. void CDmeTypedLogLayer< T >::CopyLayer( const CDmeLogLayer *src )
  2127. {
  2128. const CDmeTypedLogLayer< T > *pSrc = static_cast< const CDmeTypedLogLayer< T > * >( src );
  2129. m_times = pSrc->m_times;
  2130. m_lastKey = pSrc->m_lastKey;
  2131. m_values = pSrc->m_values;
  2132. m_CurveTypes = pSrc->m_CurveTypes;
  2133. }
  2134. template< class T >
  2135. void CDmeTypedLogLayer< T >::InsertKeyFromLayer( DmeTime_t keyTime, const CDmeLogLayer *src, DmeTime_t srcKeyTime )
  2136. {
  2137. const CDmeTypedLogLayer< T > *pSrc = static_cast< const CDmeTypedLogLayer< T > * >( src );
  2138. Assert( pSrc );
  2139. // NOTE: This copy is necessary if src == this
  2140. T value = pSrc->GetValue( srcKeyTime );
  2141. InsertKey( keyTime, value );
  2142. }
  2143. template< class T >
  2144. void CDmeTypedLogLayer< T >::ExplodeLayer( const CDmeLogLayer *src, DmeTime_t startTime, DmeTime_t endTime, bool bRebaseTimestamps, DmeTime_t tResampleInterval )
  2145. {
  2146. const CDmeTypedLogLayer< T > *pSrc = static_cast< const CDmeTypedLogLayer< T > * >( src );
  2147. Assert( pSrc );
  2148. DmeTime_t tTimeOffset = DMETIME_ZERO;
  2149. if ( bRebaseTimestamps )
  2150. {
  2151. tTimeOffset = -startTime;
  2152. }
  2153. m_times.RemoveAll();
  2154. m_values.RemoveAll();
  2155. m_CurveTypes.RemoveAll();
  2156. bool usecurvetypes = pSrc->IsUsingCurveTypes();
  2157. // Now copy the data for the later
  2158. for ( DmeTime_t t = startTime ; t + tResampleInterval < endTime; t += tResampleInterval )
  2159. {
  2160. DmeTime_t keyTime = DmeTime_t( t );
  2161. if ( keyTime > endTime )
  2162. {
  2163. keyTime = endTime;
  2164. }
  2165. T val = pSrc->GetValue( keyTime );
  2166. keyTime += tTimeOffset;
  2167. InsertKey( keyTime, val, usecurvetypes ? GetDefaultCurveType() : CURVE_DEFAULT );
  2168. }
  2169. m_lastKey = m_times.Count() - 1;
  2170. }
  2171. template< class T >
  2172. void CDmeTypedLogLayer< T >::CopyPartialLayer( const CDmeLogLayer *src, DmeTime_t startTime, DmeTime_t endTime, bool bRebaseTimestamps )
  2173. {
  2174. const CDmeTypedLogLayer< T > *pSrc = static_cast< const CDmeTypedLogLayer< T > * >( src );
  2175. Assert( pSrc );
  2176. int nTimeOffset = 0;
  2177. if ( bRebaseTimestamps )
  2178. {
  2179. nTimeOffset = -startTime.GetTenthsOfMS();
  2180. }
  2181. m_times.RemoveAll();
  2182. m_values.RemoveAll();
  2183. m_CurveTypes.RemoveAll();
  2184. bool usecurvetypes = pSrc->IsUsingCurveTypes();
  2185. // Now copy the data for the later
  2186. int c = pSrc->m_times.Count();
  2187. for ( int i = 0; i < c; ++i )
  2188. {
  2189. DmeTime_t keyTime = DmeTime_t( pSrc->m_times[ i ] );
  2190. if ( keyTime < startTime || keyTime > endTime )
  2191. continue;
  2192. m_times.AddToTail( pSrc->m_times[ i ] + nTimeOffset );
  2193. m_values.AddToTail( pSrc->m_values[ i ] );
  2194. if ( usecurvetypes )
  2195. {
  2196. m_CurveTypes.AddToTail( pSrc->m_CurveTypes[ i ] );
  2197. }
  2198. }
  2199. m_lastKey = m_times.Count() - 1;
  2200. }
  2201. //-----------------------------------------------------------------------------
  2202. // Creates a log of a specific type
  2203. //-----------------------------------------------------------------------------
  2204. template< class T >
  2205. CDmeLogLayer *CreateLayer< T >( CDmeTypedLog< T > *pOwnerLog )
  2206. {
  2207. DmFileId_t fileid = pOwnerLog ? pOwnerLog->GetFileId() : DMFILEID_INVALID;
  2208. CDmeLogLayer *layer = NULL;
  2209. switch ( CDmAttributeInfo<T>::AttributeType() )
  2210. {
  2211. case AT_INT:
  2212. case AT_INT_ARRAY:
  2213. layer = CreateElement< CDmeIntLogLayer >( "int log", fileid );
  2214. break;
  2215. case AT_FLOAT:
  2216. case AT_FLOAT_ARRAY:
  2217. layer = CreateElement< CDmeFloatLogLayer >( "float log", fileid );
  2218. break;
  2219. case AT_BOOL:
  2220. case AT_BOOL_ARRAY:
  2221. layer = CreateElement< CDmeBoolLogLayer >( "bool log", fileid );
  2222. break;
  2223. case AT_COLOR:
  2224. case AT_COLOR_ARRAY:
  2225. layer = CreateElement< CDmeColorLogLayer >( "color log", fileid );
  2226. break;
  2227. case AT_VECTOR2:
  2228. case AT_VECTOR2_ARRAY:
  2229. layer = CreateElement< CDmeVector2LogLayer >( "vector2 log", fileid );
  2230. break;
  2231. case AT_VECTOR3:
  2232. case AT_VECTOR3_ARRAY:
  2233. layer = CreateElement< CDmeVector3LogLayer >( "vector3 log", fileid );
  2234. break;
  2235. case AT_VECTOR4:
  2236. case AT_VECTOR4_ARRAY:
  2237. layer = CreateElement< CDmeVector4LogLayer >( "vector4 log", fileid );
  2238. break;
  2239. case AT_QANGLE:
  2240. case AT_QANGLE_ARRAY:
  2241. layer = CreateElement< CDmeQAngleLogLayer >( "qangle log", fileid );
  2242. break;
  2243. case AT_QUATERNION:
  2244. case AT_QUATERNION_ARRAY:
  2245. layer = CreateElement< CDmeQuaternionLogLayer >( "quaternion log", fileid );
  2246. break;
  2247. case AT_VMATRIX:
  2248. case AT_VMATRIX_ARRAY:
  2249. layer = CreateElement< CDmeVMatrixLogLayer >( "vmatrix log", fileid );
  2250. break;
  2251. case AT_STRING:
  2252. case AT_STRING_ARRAY:
  2253. layer = CreateElement< CDmeStringLogLayer >( "string log", fileid );
  2254. break;
  2255. }
  2256. if ( layer )
  2257. {
  2258. layer->SetOwnerLog( pOwnerLog );
  2259. }
  2260. return layer;
  2261. }
  2262. //-----------------------------------------------------------------------------
  2263. //
  2264. // CDmeCurveInfo - abstract base class
  2265. //
  2266. //-----------------------------------------------------------------------------
  2267. void CDmeCurveInfo::OnConstruction()
  2268. {
  2269. m_DefaultCurveType.Init( this, "defaultCurveType" );
  2270. m_MinValue.InitAndSet( this, "minvalue", 0.0f );
  2271. m_MaxValue.InitAndSet( this, "maxvalue", 1.0f );
  2272. }
  2273. void CDmeCurveInfo::OnDestruction()
  2274. {
  2275. }
  2276. // Global override for all keys unless overriden by specific key
  2277. void CDmeCurveInfo::SetDefaultCurveType( int curveType )
  2278. {
  2279. m_DefaultCurveType = curveType;
  2280. }
  2281. int CDmeCurveInfo::GetDefaultCurveType() const
  2282. {
  2283. return m_DefaultCurveType.Get();
  2284. }
  2285. void CDmeCurveInfo::SetMinValue( float val )
  2286. {
  2287. m_MinValue = val;
  2288. }
  2289. float CDmeCurveInfo::GetMinValue() const
  2290. {
  2291. return m_MinValue;
  2292. }
  2293. void CDmeCurveInfo::SetMaxValue( float val )
  2294. {
  2295. m_MaxValue = val;
  2296. }
  2297. float CDmeCurveInfo::GetMaxValue() const
  2298. {
  2299. return m_MaxValue;
  2300. }
  2301. //-----------------------------------------------------------------------------
  2302. //
  2303. // CDmeTypedCurveInfo - implementation class for all logs
  2304. //
  2305. //-----------------------------------------------------------------------------
  2306. template< class T >
  2307. void CDmeTypedCurveInfo< T >::OnConstruction()
  2308. {
  2309. m_bUseEdgeInfo.Init( this, "useEdgeInfo" );
  2310. m_DefaultEdgeValue.Init( this, "defaultEdgeZeroValue" );
  2311. m_RightEdgeTime.Init( this, "rightEdgeTime" );
  2312. for ( int i = 0; i < 2; ++i )
  2313. {
  2314. char edgename[ 32 ];
  2315. Q_snprintf( edgename, sizeof( edgename ), "%s", i == 0 ? "left" : "right" );
  2316. char name[ 32 ];
  2317. Q_snprintf( name, sizeof( name ), "%sEdgeActive", edgename );
  2318. m_bEdgeActive[ i ].Init( this, name );
  2319. Q_snprintf( name, sizeof( name ), "%sEdgeValue", edgename );
  2320. m_EdgeValue[ i ].Init( this, name );
  2321. Q_snprintf( name, sizeof( name ), "%sEdgeCurveType", edgename );
  2322. m_EdgeCurveType[ i ].Init( this, name );
  2323. }
  2324. }
  2325. template< class T >
  2326. void CDmeTypedCurveInfo< T >::OnDestruction()
  2327. {
  2328. }
  2329. template< class T >
  2330. void CDmeTypedCurveInfo< T >::SetUseEdgeInfo( bool state )
  2331. {
  2332. m_bUseEdgeInfo = state;
  2333. }
  2334. template< class T >
  2335. bool CDmeTypedCurveInfo< T >::IsUsingEdgeInfo() const
  2336. {
  2337. return m_bUseEdgeInfo;
  2338. }
  2339. template< class T >
  2340. void CDmeTypedCurveInfo< T >::SetEdgeInfo( int edge, bool active, const T& val, int curveType )
  2341. {
  2342. SetUseEdgeInfo( true );
  2343. Assert( edge == 0 || edge == 1 );
  2344. m_bEdgeActive[ edge ] = active;
  2345. m_EdgeValue[ edge ] = val;
  2346. m_EdgeCurveType[ edge ] = curveType;
  2347. }
  2348. template< class T >
  2349. void CDmeTypedCurveInfo< T >::SetDefaultEdgeZeroValue( const T& val )
  2350. {
  2351. m_DefaultEdgeValue = val;
  2352. }
  2353. template< class T >
  2354. const T& CDmeTypedCurveInfo< T >::GetDefaultEdgeZeroValue() const
  2355. {
  2356. return m_DefaultEdgeValue;
  2357. }
  2358. template< class T >
  2359. void CDmeTypedCurveInfo< T >::SetRightEdgeTime( DmeTime_t time )
  2360. {
  2361. m_RightEdgeTime = time.GetTenthsOfMS();
  2362. }
  2363. template< class T >
  2364. DmeTime_t CDmeTypedCurveInfo< T >::GetRightEdgeTime() const
  2365. {
  2366. return DmeTime_t( m_RightEdgeTime );
  2367. }
  2368. template< class T >
  2369. void CDmeTypedCurveInfo< T >::GetEdgeInfo( int edge, bool& active, T& val, int& curveType ) const
  2370. {
  2371. Assert( IsUsingEdgeInfo() );
  2372. Assert( edge == 0 || edge == 1 );
  2373. active = m_bEdgeActive[ edge ];
  2374. val = m_EdgeValue[ edge ];
  2375. curveType = m_EdgeCurveType[ edge ];
  2376. }
  2377. template< class T >
  2378. int CDmeTypedCurveInfo< T >::GetEdgeCurveType( int edge ) const
  2379. {
  2380. Assert( edge == 0 || edge == 1 );
  2381. if ( !m_bEdgeActive[ edge ] )
  2382. {
  2383. return m_DefaultCurveType;
  2384. }
  2385. if ( m_EdgeCurveType[ edge ] == CURVE_DEFAULT )
  2386. {
  2387. return m_DefaultCurveType;
  2388. }
  2389. return m_EdgeCurveType[ edge ];
  2390. }
  2391. template<>
  2392. void CDmeTypedCurveInfo<float>::GetZeroValue( int side, float& val ) const
  2393. {
  2394. if ( !m_bUseEdgeInfo )
  2395. {
  2396. val = 0.0f;
  2397. return;
  2398. }
  2399. if ( m_bEdgeActive[ side ] )
  2400. {
  2401. val = m_EdgeValue[ side ];
  2402. return;
  2403. }
  2404. val = m_DefaultEdgeValue;
  2405. }
  2406. template<>
  2407. bool CDmeTypedCurveInfo<float>::IsEdgeActive( int edge ) const
  2408. {
  2409. return m_bEdgeActive[ edge ];
  2410. }
  2411. template<>
  2412. void CDmeTypedCurveInfo<float>::GetEdgeValue( int edge, float& value ) const
  2413. {
  2414. value = m_EdgeValue[ edge ];
  2415. }
  2416. template<>
  2417. void CDmeTypedCurveInfo<Vector>::GetZeroValue( int side, Vector& val ) const
  2418. {
  2419. if ( !m_bUseEdgeInfo )
  2420. {
  2421. val = vec3_origin;
  2422. return;
  2423. }
  2424. if ( m_bEdgeActive[ side ] )
  2425. {
  2426. val = m_EdgeValue[ side ];
  2427. return;
  2428. }
  2429. val = m_DefaultEdgeValue;
  2430. }
  2431. template<>
  2432. void CDmeTypedCurveInfo<Quaternion>::GetZeroValue( int side, Quaternion& val ) const
  2433. {
  2434. if ( !m_bUseEdgeInfo )
  2435. {
  2436. val.Init();
  2437. return;
  2438. }
  2439. if ( m_bEdgeActive[ side ] )
  2440. {
  2441. val = m_EdgeValue[ side ];
  2442. return;
  2443. }
  2444. val = m_DefaultEdgeValue;
  2445. }
  2446. //-----------------------------------------------------------------------------
  2447. //
  2448. // CDmeLog - abstract base class
  2449. //
  2450. //-----------------------------------------------------------------------------
  2451. void CDmeLog::OnConstruction()
  2452. {
  2453. m_Layers.Init( this, "layers", FATTRIB_MUSTCOPY | FATTRIB_HAS_ARRAY_CALLBACK );
  2454. m_CurveInfo.Init( this, "curveinfo", FATTRIB_MUSTCOPY | FATTRIB_HAS_CALLBACK );
  2455. }
  2456. void CDmeLog::OnDestruction()
  2457. {
  2458. }
  2459. int CDmeLog::GetTopmostLayer() const
  2460. {
  2461. return m_Layers.Count() - 1;
  2462. }
  2463. int CDmeLog::GetNumLayers() const
  2464. {
  2465. return m_Layers.Count();
  2466. }
  2467. CDmeLogLayer *CDmeLog::GetLayer( int index )
  2468. {
  2469. return m_Layers[ index ];
  2470. }
  2471. const CDmeLogLayer *CDmeLog::GetLayer( int index ) const
  2472. {
  2473. return m_Layers[ index ];
  2474. }
  2475. bool CDmeLog::IsEmpty() const
  2476. {
  2477. int c = m_Layers.Count();
  2478. for ( int i = 0; i < c; ++i )
  2479. {
  2480. CDmeLogLayer* layer = m_Layers[ i ];
  2481. if ( layer->GetKeyCount() > 0 )
  2482. return false;
  2483. }
  2484. return true;
  2485. }
  2486. void CDmeLog::FindLayersForTime( DmeTime_t time, CUtlVector< int >& list ) const
  2487. {
  2488. list.RemoveAll();
  2489. int c = m_Layers.Count();
  2490. // The base layer is always available!!!
  2491. if ( c > 0 )
  2492. {
  2493. list.AddToTail( 0 );
  2494. }
  2495. for ( int i = 1; i < c; ++i )
  2496. {
  2497. CDmeLogLayer* layer = m_Layers[ i ];
  2498. DmeTime_t layerStart = layer->GetBeginTime();
  2499. if ( layerStart == DmeTime_t::MinTime() )
  2500. continue;
  2501. DmeTime_t layerEnd = layer->GetEndTime();
  2502. if ( layerEnd == DmeTime_t::MaxTime() )
  2503. continue;
  2504. if ( time >= layerStart && time <= layerEnd )
  2505. {
  2506. list.AddToTail( i );
  2507. }
  2508. }
  2509. }
  2510. int CDmeLog::FindLayerForTimeSkippingTopmost( DmeTime_t time ) const
  2511. {
  2512. int c = m_Layers.Count() - 1; // This makes it never consider the topmost layer!!!
  2513. for ( int i = c - 1; i >= 0; --i )
  2514. {
  2515. CDmeLogLayer* layer = m_Layers[ i ];
  2516. DmeTime_t layerStart = layer->GetBeginTime();
  2517. if ( layerStart == DmeTime_t::MinTime() )
  2518. continue;
  2519. DmeTime_t layerEnd = layer->GetEndTime();
  2520. if ( layerEnd == DmeTime_t::MaxTime() )
  2521. continue;
  2522. if ( time >= layerStart && time <= layerEnd )
  2523. return i;
  2524. }
  2525. return ( c > 0 ) ? 0 : -1;
  2526. }
  2527. int CDmeLog::FindLayerForTime( DmeTime_t time ) const
  2528. {
  2529. int c = m_Layers.Count();
  2530. for ( int i = c - 1; i >= 0; --i )
  2531. {
  2532. CDmeLogLayer* layer = m_Layers[ i ];
  2533. DmeTime_t layerStart = layer->GetBeginTime();
  2534. if ( layerStart == DmeTime_t::MinTime() )
  2535. continue;
  2536. DmeTime_t layerEnd = layer->GetEndTime();
  2537. if ( layerEnd == DmeTime_t::MaxTime() )
  2538. continue;
  2539. if ( time >= layerStart && time <= layerEnd )
  2540. return i;
  2541. }
  2542. return ( c > 0 ) ? 0 : -1;
  2543. }
  2544. DmeTime_t CDmeLog::GetBeginTime() const
  2545. {
  2546. int c = m_Layers.Count();
  2547. if ( c == 0 )
  2548. return DmeTime_t::MinTime();
  2549. DmeTime_t bestMin = DmeTime_t::MinTime();
  2550. for ( int i = 0; i < c; ++i )
  2551. {
  2552. CDmeLogLayer* layer = m_Layers[ i ];
  2553. DmeTime_t layerStart = layer->GetBeginTime();
  2554. if ( layerStart == DmeTime_t::MinTime() )
  2555. continue;
  2556. if ( bestMin == DmeTime_t::MinTime() )
  2557. {
  2558. bestMin = layerStart;
  2559. }
  2560. else if ( layerStart < bestMin )
  2561. {
  2562. bestMin = layerStart;
  2563. }
  2564. }
  2565. return bestMin;
  2566. }
  2567. DmeTime_t CDmeLog::GetEndTime() const
  2568. {
  2569. int c = m_Layers.Count();
  2570. if ( c == 0 )
  2571. return DmeTime_t::MaxTime();
  2572. DmeTime_t bestMax = DmeTime_t::MaxTime();
  2573. for ( int i = 0; i < c; ++i )
  2574. {
  2575. CDmeLogLayer *layer = m_Layers[ i ];
  2576. DmeTime_t layerEnd = layer->GetEndTime();
  2577. if ( layerEnd == DmeTime_t::MaxTime() )
  2578. continue;
  2579. if ( bestMax == DmeTime_t::MaxTime() )
  2580. {
  2581. bestMax = layerEnd;
  2582. }
  2583. else if ( layerEnd > bestMax )
  2584. {
  2585. bestMax = layerEnd;
  2586. }
  2587. }
  2588. return bestMax;
  2589. }
  2590. //-----------------------------------------------------------------------------
  2591. // Returns the number of keys
  2592. //-----------------------------------------------------------------------------
  2593. int CDmeLog::GetKeyCount() const
  2594. {
  2595. int count = 0;
  2596. int c = m_Layers.Count();
  2597. for ( int i = 0; i < c; ++i )
  2598. {
  2599. CDmeLogLayer* layer = m_Layers[ i ];
  2600. int timecount = layer->GetKeyCount();
  2601. count += timecount;
  2602. }
  2603. return count;
  2604. }
  2605. //-----------------------------------------------------------------------------
  2606. // Scale + bias key times
  2607. //-----------------------------------------------------------------------------
  2608. void CDmeLog::ScaleBiasKeyTimes( double flScale, DmeTime_t nBias )
  2609. {
  2610. // Don't waste time on the identity transform
  2611. if ( ( nBias == DMETIME_ZERO ) && ( fabs( flScale - 1.0 ) < 1e-5 ) )
  2612. return;
  2613. int nCount = GetNumLayers();
  2614. for ( int i = 0; i < nCount; ++i )
  2615. {
  2616. CDmeLogLayer *pLayer = GetLayer( i );
  2617. pLayer->ScaleBiasKeyTimes( flScale, nBias );
  2618. }
  2619. }
  2620. //-----------------------------------------------------------------------------
  2621. // Resolve - keeps non-attribute data in sync with attribute data
  2622. //-----------------------------------------------------------------------------
  2623. void CDmeLog::Resolve()
  2624. {
  2625. int c = m_Layers.Count();
  2626. for ( int i = 0; i < c; ++i )
  2627. {
  2628. CDmeLogLayer* layer = m_Layers[ i ];
  2629. layer->SetOwnerLog( this );
  2630. }
  2631. }
  2632. void CDmeLog::OnAttributeChanged( CDmAttribute *pAttribute )
  2633. {
  2634. if ( pAttribute == m_CurveInfo.GetAttribute() )
  2635. {
  2636. OnUsingCurveTypesChanged();
  2637. }
  2638. }
  2639. void CDmeLog::OnUsingCurveTypesChanged()
  2640. {
  2641. int c = m_Layers.Count();
  2642. for ( int i = 0; i < c; ++i )
  2643. {
  2644. GetLayer( i )->OnUsingCurveTypesChanged();
  2645. }
  2646. }
  2647. // curve info helpers
  2648. bool CDmeLog::IsUsingCurveTypes() const
  2649. {
  2650. return m_CurveInfo.GetElement() != NULL;
  2651. }
  2652. const CDmeCurveInfo *CDmeLog::GetCurveInfo() const
  2653. {
  2654. return m_CurveInfo.GetElement();
  2655. }
  2656. CDmeCurveInfo *CDmeLog::GetCurveInfo()
  2657. {
  2658. return m_CurveInfo.GetElement();
  2659. }
  2660. // accessors for CurveInfo data
  2661. int CDmeLog::GetDefaultCurveType() const
  2662. {
  2663. Assert( IsUsingCurveTypes() );
  2664. return m_CurveInfo->GetDefaultCurveType();
  2665. }
  2666. // min/max accessors
  2667. float CDmeLog::GetMinValue() const
  2668. {
  2669. Assert( IsUsingCurveTypes() );
  2670. return m_CurveInfo->GetMinValue();
  2671. }
  2672. void CDmeLog::SetMinValue( float val )
  2673. {
  2674. Assert( IsUsingCurveTypes() );
  2675. m_CurveInfo->SetMinValue( val );
  2676. }
  2677. float CDmeLog::GetMaxValue() const
  2678. {
  2679. Assert( IsUsingCurveTypes() );
  2680. return m_CurveInfo->GetMaxValue();
  2681. }
  2682. void CDmeLog::SetMaxValue( float val )
  2683. {
  2684. Assert( IsUsingCurveTypes() );
  2685. m_CurveInfo->SetMaxValue( val );
  2686. }
  2687. void CDmeLog::SetKeyCurveType( int nKeyIndex, int curveType )
  2688. {
  2689. int bestLayer = GetTopmostLayer();
  2690. if ( bestLayer < 0 )
  2691. return;
  2692. GetLayer( bestLayer )->SetKeyCurveType( nKeyIndex, curveType );
  2693. }
  2694. int CDmeLog::GetKeyCurveType( int nKeyIndex ) const
  2695. {
  2696. int bestLayer = GetTopmostLayer();
  2697. if ( bestLayer < 0 )
  2698. return CURVE_DEFAULT;
  2699. return GetLayer( bestLayer )->GetKeyCurveType( nKeyIndex );
  2700. }
  2701. //-----------------------------------------------------------------------------
  2702. // Removes all keys in a certain time interval
  2703. //-----------------------------------------------------------------------------
  2704. bool CDmeLog::RemoveKeys( DmeTime_t tStartTime, DmeTime_t tEndTime )
  2705. {
  2706. CDmeLogLayer *pLayer = GetLayer( GetTopmostLayer() );
  2707. int nKeyCount = pLayer->GetKeyCount();
  2708. int nFirstRemove = -1;
  2709. int nLastRemove = -1;
  2710. for ( int nKey = 0; nKey < nKeyCount; ++nKey )
  2711. {
  2712. DmeTime_t tKeyTime = pLayer->GetKeyTime( nKey );
  2713. if ( tKeyTime < tStartTime )
  2714. continue;
  2715. if ( tKeyTime > tEndTime )
  2716. break;
  2717. if ( nFirstRemove == -1 )
  2718. {
  2719. nFirstRemove = nKey;
  2720. }
  2721. nLastRemove = nKey;
  2722. }
  2723. if ( nFirstRemove != -1 )
  2724. {
  2725. int nRemoveCount = nLastRemove - nFirstRemove + 1;
  2726. pLayer->RemoveKey( nFirstRemove, nRemoveCount );
  2727. return true;
  2728. }
  2729. return false;
  2730. }
  2731. //-----------------------------------------------------------------------------
  2732. // CDmeTypedLog - implementation class for all logs
  2733. //-----------------------------------------------------------------------------
  2734. template< class T >
  2735. void CDmeTypedLog< T >::OnConstruction()
  2736. {
  2737. if ( !g_pDataModel->IsUnserializing() )
  2738. {
  2739. // Add the default layer!!!
  2740. AddNewLayer();
  2741. Assert( m_Layers.Count() == 1 );
  2742. }
  2743. m_threshold = s_defaultThreshold;
  2744. m_UseDefaultValue.InitAndSet( this, "usedefaultvalue", false );
  2745. m_DefaultValue.Init( this, "defaultvalue" );
  2746. }
  2747. template< class T >
  2748. void CDmeTypedLog< T >::OnDestruction()
  2749. {
  2750. }
  2751. template< class T >
  2752. void CDmeTypedLog< T >::SetDefaultValue( const T& value )
  2753. {
  2754. m_UseDefaultValue = true;
  2755. m_DefaultValue.Set( value );
  2756. }
  2757. template< class T >
  2758. const T& CDmeTypedLog< T >::GetDefaultValue() const
  2759. {
  2760. Assert( (bool)m_UseDefaultValue );
  2761. return m_DefaultValue;
  2762. }
  2763. template< class T >
  2764. bool CDmeTypedLog< T >::HasDefaultValue() const
  2765. {
  2766. return m_UseDefaultValue;
  2767. }
  2768. template< class T >
  2769. void CDmeTypedLog< T >::ClearDefaultValue()
  2770. {
  2771. m_UseDefaultValue = false;
  2772. T out;
  2773. CDmAttributeInfo< T >::SetDefaultValue( out );
  2774. m_DefaultValue.Set( out );
  2775. }
  2776. // Only used by undo system!!!
  2777. template< class T >
  2778. void CDmeTypedLog< T >::AddLayerToTail( CDmeLogLayer *layer )
  2779. {
  2780. Assert( layer );
  2781. Assert( (static_cast< CDmeTypedLogLayer< T > * >( layer ))->GetTypedOwnerLog() == this );
  2782. m_Layers.AddToTail( layer );
  2783. }
  2784. template< class T >
  2785. CDmeLogLayer *CDmeTypedLog< T >::RemoveLayerFromTail()
  2786. {
  2787. Assert( m_Layers.Count() >= 1 );
  2788. CDmeLogLayer *layer = m_Layers[ m_Layers.Count() -1 ];
  2789. m_Layers.Remove( m_Layers.Count() - 1 );
  2790. return layer;
  2791. }
  2792. template< class T >
  2793. CDmeLogLayer *CDmeTypedLog< T >::RemoveLayer( int iLayer )
  2794. {
  2795. Assert( m_Layers.IsValidIndex( iLayer ) );
  2796. CDmeLogLayer *layer = m_Layers[ iLayer ];
  2797. m_Layers.Remove( iLayer );
  2798. return layer;
  2799. }
  2800. template< class T >
  2801. CDmeLogLayer *CDmeTypedLog< T >::AddNewLayer()
  2802. {
  2803. if ( g_pDataModel->UndoEnabledForElement( this ) )
  2804. {
  2805. CUndoLayerAdded<T> *pUndo = new CUndoLayerAdded<T>( "AddNewLayer", this );
  2806. g_pDataModel->AddUndoElement( pUndo );
  2807. }
  2808. CDisableUndoScopeGuard guard;
  2809. // Now add the layer to the stack!!!
  2810. CDmeTypedLogLayer< T > *layer = static_cast< CDmeTypedLogLayer< T > * >( CreateLayer<T>( this ) );
  2811. if ( layer )
  2812. {
  2813. layer->SetOwnerLog( this );
  2814. m_Layers.AddToTail( layer );
  2815. }
  2816. return layer;
  2817. }
  2818. // curve info helpers
  2819. template< class T >
  2820. const CDmeTypedCurveInfo< T > *CDmeTypedLog<T>::GetTypedCurveInfo() const
  2821. {
  2822. Assert( !m_CurveInfo.GetElement() || dynamic_cast< const CDmeTypedCurveInfo< T > * >( m_CurveInfo.GetElement() ) );
  2823. return static_cast< const CDmeTypedCurveInfo< T > * >( m_CurveInfo.GetElement() );
  2824. }
  2825. template< class T >
  2826. CDmeTypedCurveInfo< T > *CDmeTypedLog<T>::GetTypedCurveInfo()
  2827. {
  2828. Assert( !m_CurveInfo.GetElement() || dynamic_cast< CDmeTypedCurveInfo< T > * >( m_CurveInfo.GetElement() ) );
  2829. return static_cast< CDmeTypedCurveInfo< T > * >( m_CurveInfo.GetElement() );
  2830. }
  2831. template< class T >
  2832. void CDmeTypedLog<T>::SetCurveInfo( CDmeCurveInfo *pCurveInfo )
  2833. {
  2834. Assert( !pCurveInfo || dynamic_cast< CDmeTypedCurveInfo< T > * >( pCurveInfo ) );
  2835. m_CurveInfo = pCurveInfo;
  2836. OnUsingCurveTypesChanged(); // FIXME: Is this really necessary? OnAttributeChanged should have already called this!
  2837. }
  2838. template< class T >
  2839. CDmeCurveInfo *CDmeTypedLog<T>::GetOrCreateCurveInfo()
  2840. {
  2841. CDmeCurveInfo *pCurveInfo = m_CurveInfo.GetElement();
  2842. if ( pCurveInfo )
  2843. return pCurveInfo;
  2844. SetCurveInfo( CreateElement< CDmeTypedCurveInfo< T > >( "curveinfo", GetFileId() ) );
  2845. return m_CurveInfo.GetElement();
  2846. }
  2847. template < class T >
  2848. struct ActiveLayer_t
  2849. {
  2850. ActiveLayer_t() :
  2851. bValid( false ),
  2852. priority( 0 ),
  2853. firstTime( 0 ),
  2854. lastTime( 0 ),
  2855. layer( NULL )
  2856. {
  2857. }
  2858. static bool PriorityLessFunc( ActiveLayer_t< T > * const & lhs, ActiveLayer_t< T > * const & rhs )
  2859. {
  2860. return lhs->priority < rhs->priority;
  2861. }
  2862. int priority; // higher wins
  2863. bool bValid;
  2864. DmeTime_t firstTime;
  2865. DmeTime_t lastTime;
  2866. CDmeTypedLogLayer< T > *layer;
  2867. };
  2868. template < class T >
  2869. struct LayerEvent_t
  2870. {
  2871. enum EventType_t
  2872. {
  2873. LE_START = 0,
  2874. LE_END
  2875. };
  2876. LayerEvent_t() : m_pList( NULL ), m_Type( LE_START ), m_nLayer( 0 ), m_Time( 0 )
  2877. {
  2878. }
  2879. static bool LessFunc( const LayerEvent_t& lhs, const LayerEvent_t& rhs )
  2880. {
  2881. return lhs.m_Time < rhs.m_Time;
  2882. }
  2883. CUtlVector< ActiveLayer_t< T > > *m_pList;
  2884. EventType_t m_Type;
  2885. int m_nLayer;
  2886. DmeTime_t m_Time;
  2887. T m_NeighborValue;
  2888. };
  2889. template< class T >
  2890. static const T& GetActiveLayerValue( CUtlVector< ActiveLayer_t< T > > &layerlist, DmeTime_t t, int nTopmostLayer )
  2891. {
  2892. int nCount = layerlist.Count();
  2893. #ifdef _DEBUG
  2894. Assert( nCount >= nTopmostLayer );
  2895. #endif
  2896. for ( int i = nTopmostLayer; i >= 0; --i )
  2897. {
  2898. ActiveLayer_t< T > &layer = layerlist[i];
  2899. if ( layer.firstTime > t || layer.lastTime < t )
  2900. continue;
  2901. return layer.layer->GetValue( t );
  2902. }
  2903. if ( nCount != 0 )
  2904. {
  2905. const CDmeTypedLog< T > *pOwner = layerlist[0].layer->GetTypedOwnerLog();
  2906. if ( pOwner->HasDefaultValue() )
  2907. return pOwner->GetDefaultValue();
  2908. }
  2909. static T defaultVal;
  2910. CDmAttributeInfo<T>::SetDefaultValue( defaultVal );
  2911. return defaultVal;
  2912. }
  2913. template< class T >
  2914. static void SpewEvents( CUtlRBTree< LayerEvent_t< T > > &events )
  2915. {
  2916. for ( unsigned short idx = events.FirstInorder(); idx != events.InvalidIndex(); idx = events.NextInorder( idx ) )
  2917. {
  2918. LayerEvent_t< T > *pEvent = &events[ idx ];
  2919. Msg( "Event %u layer %i at time %i type %s\n",
  2920. (unsigned)idx, pEvent->m_nLayer, pEvent->m_Time.GetTenthsOfMS(), pEvent->m_Type == LayerEvent_t< T >::LE_START ? "start" : "end" );
  2921. }
  2922. }
  2923. template< class T >
  2924. inline void SpewKey( const T& )
  2925. {
  2926. Msg( "GenericType" );
  2927. }
  2928. template<>
  2929. inline void SpewKey<float>( const float& val )
  2930. {
  2931. Msg( "%f", val );
  2932. }
  2933. template<>
  2934. inline void SpewKey<int>( const int& val )
  2935. {
  2936. Msg( "%d", val );
  2937. }
  2938. template<>
  2939. inline void SpewKey<Vector2D>( const Vector2D& val )
  2940. {
  2941. Msg( "%f,%f", val.x, val.y );
  2942. }
  2943. template<>
  2944. inline void SpewKey<Vector4D>( const Vector4D& val )
  2945. {
  2946. Msg( "%f,%f,%f,%f", val.x, val.y, val.z, val.w );
  2947. }
  2948. template<>
  2949. inline void SpewKey<DmeTime_t>( const DmeTime_t& val )
  2950. {
  2951. Msg( "%d", val.GetTenthsOfMS() );
  2952. }
  2953. template<>
  2954. inline void SpewKey<bool>( const bool& val )
  2955. {
  2956. Msg( "%s", val ? "true" : "false" );
  2957. }
  2958. template<>
  2959. inline void SpewKey<Color>( const Color& val )
  2960. {
  2961. Msg( "%08x", val.GetRawColor() );
  2962. }
  2963. template< >
  2964. inline void SpewKey( const Vector& val )
  2965. {
  2966. Msg( "[%f %f %f]", val.x, val.y, val.z );
  2967. }
  2968. template< >
  2969. inline void SpewKey( const Quaternion& val )
  2970. {
  2971. Msg( "[%f %f %f %f]", val.x, val.y, val.z, val.w );
  2972. }
  2973. template< class T >
  2974. static void SpewFlattenedKey( CDmeTypedLogLayer< T > *pLogLayer, ActiveLayer_t< T > *pActiveLayer, DmeTime_t t, const T& val )
  2975. {
  2976. Msg( "Layer %d: adding key at time %f [%d -> %d], value ",
  2977. pActiveLayer->priority, t.GetSeconds(), pActiveLayer->firstTime.GetTenthsOfMS(), pActiveLayer->lastTime.GetTenthsOfMS() );
  2978. SpewKey( val );
  2979. Msg( "\n" );
  2980. }
  2981. template< class T >
  2982. static void ComputeLayerEvents( CDmeTypedLog< T >* pLog,
  2983. CUtlVector< ActiveLayer_t< T > > &layerlist,
  2984. CUtlRBTree< LayerEvent_t< T > > &events )
  2985. {
  2986. // Build a list of all known layers and a sorted list of layer "transitions"
  2987. for ( int i = 0; i < pLog->GetNumLayers(); ++i )
  2988. {
  2989. ActiveLayer_t< T > layer;
  2990. layer.priority = i;
  2991. layer.layer = static_cast< CDmeTypedLogLayer< T > * >( pLog->GetLayer( i ) );
  2992. layer.firstTime = layer.layer->GetBeginTime();
  2993. layer.lastTime = layer.layer->GetEndTime();
  2994. layer.bValid = true;
  2995. if ( ( layer.firstTime == DMETIME_MINTIME || layer.lastTime == DMETIME_MAXTIME ) && ( i > 0 ) ) // Base layer is always valid
  2996. {
  2997. layer.bValid = false;
  2998. }
  2999. // Skip invalid layers
  3000. if ( !layer.bValid )
  3001. continue;
  3002. // Layer zero can capture everything from above...
  3003. if ( i == 0 )
  3004. {
  3005. layer.firstTime = DmeTime_t::MinTime();
  3006. layer.lastTime = DmeTime_t::MaxTime();
  3007. }
  3008. // Add layer to global list
  3009. int nIndex = layerlist.AddToTail( layer );
  3010. // Add layer start/end events
  3011. DmeTime_t tNeighbor = ( layer.firstTime != DMETIME_MINTIME ) ? ( layer.firstTime - DMETIME_MINDELTA ) : DMETIME_MINTIME;
  3012. LayerEvent_t< T > start;
  3013. start.m_pList = &layerlist;
  3014. start.m_nLayer = nIndex;
  3015. start.m_Type = LayerEvent_t< T >::LE_START;
  3016. start.m_Time = layer.firstTime;
  3017. start.m_NeighborValue = GetActiveLayerValue( layerlist, tNeighbor, nIndex - 1 );
  3018. events.Insert( start );
  3019. tNeighbor = ( layer.lastTime != DMETIME_MAXTIME ) ? ( layer.lastTime + DMETIME_MINDELTA ) : DMETIME_MAXTIME;
  3020. LayerEvent_t< T > end;
  3021. end.m_pList = &layerlist;
  3022. end.m_nLayer = nIndex;
  3023. end.m_Type = LayerEvent_t< T >::LE_END;
  3024. end.m_Time = layer.lastTime;
  3025. end.m_NeighborValue = GetActiveLayerValue( layerlist, tNeighbor, nIndex - 1 );
  3026. events.Insert( end );
  3027. }
  3028. }
  3029. template< class T >
  3030. static void AddDiscontinitySample( CDmeTypedLogLayer< T > *pTargetLayer, CDmeTypedLog< T > *pLog, DmeTime_t tKeyTime, const T& val, const char *pSpewLabel )
  3031. {
  3032. // Finally, add a helper key
  3033. if ( pLog->IsUsingCurveTypes() )
  3034. {
  3035. if ( pSpewLabel )
  3036. {
  3037. Msg( "Adding %s helper key at %d value ", pSpewLabel, tKeyTime.GetTenthsOfMS() );
  3038. SpewKey( val );
  3039. Msg( " [curvetype %s]\n", Interpolator_NameForCurveType( pLog->GetDefaultCurveType(), false ) );
  3040. }
  3041. pTargetLayer->SetKey( tKeyTime, val, pLog->GetDefaultCurveType() );
  3042. }
  3043. else
  3044. {
  3045. if ( pSpewLabel )
  3046. {
  3047. Msg( "Adding %s helper key at %d value ", pSpewLabel, tKeyTime.GetTenthsOfMS() );
  3048. SpewKey( val );
  3049. Msg( "\n" );
  3050. }
  3051. pTargetLayer->SetKey( tKeyTime, val );
  3052. }
  3053. }
  3054. template< class T >
  3055. static DmeTime_t ProcessStartLayerStartEvent(
  3056. bool bSpew,
  3057. bool bFixupDiscontinuities,
  3058. CDmeTypedLog< T > *pLog,
  3059. LayerEvent_t< T > *pEvent,
  3060. CUtlVector< ActiveLayer_t< T > > &layerlist,
  3061. CUtlRBTree< ActiveLayer_t< T > * > &active,
  3062. CDmeTypedLogLayer< T > *flattenedlayer )
  3063. {
  3064. Assert( pEvent->m_Type == LayerEvent_t< T >::LE_START );
  3065. // Push it onto the active stack if it's not already on the stack
  3066. if ( active.Find( &layerlist[ pEvent->m_nLayer ] ) != active.InvalidIndex() )
  3067. return pEvent->m_Time;
  3068. if ( bSpew )
  3069. {
  3070. Msg( "adding layer %d to stack\n", layerlist[ pEvent->m_nLayer ].priority );
  3071. }
  3072. active.Insert( &layerlist[ pEvent->m_nLayer ] );
  3073. if ( !bFixupDiscontinuities || ( pEvent->m_Time == DMETIME_MINTIME ) )
  3074. return pEvent->m_Time;
  3075. // We'll need to add 2 new "discontinuity" fixup samples.
  3076. // 1) A sample from the base layer @ start time - .1 msec
  3077. // 2) A sample from the new layer @ start time
  3078. int nActiveCount = active.Count();
  3079. if ( nActiveCount >= 2 )
  3080. {
  3081. DmeTime_t tKeyTime = pEvent->m_Time - DmeTime_t( 1 );
  3082. AddDiscontinitySample( flattenedlayer, pLog, tKeyTime, pEvent->m_NeighborValue, bSpew ? "start" : NULL );
  3083. }
  3084. AddDiscontinitySample( flattenedlayer, pLog, pEvent->m_Time, GetActiveLayerValue( layerlist, pEvent->m_Time, pEvent->m_nLayer ), bSpew ? "start" : NULL );
  3085. return pEvent->m_Time;
  3086. }
  3087. template< class T >
  3088. static DmeTime_t ProcessStartLayerEndEvent(
  3089. bool bSpew,
  3090. bool bFixupDiscontinuities,
  3091. CDmeTypedLog< T > *pLog,
  3092. LayerEvent_t< T > *pEvent,
  3093. CUtlVector< ActiveLayer_t< T > > &layerlist,
  3094. CUtlRBTree< ActiveLayer_t< T > * > &active,
  3095. CDmeTypedLogLayer< T > *pBaseLayer )
  3096. {
  3097. Assert( pEvent->m_Type == LayerEvent_t< T >::LE_END );
  3098. // Push it onto the active stack if it's not already on the stack
  3099. if ( bSpew )
  3100. {
  3101. Msg( "removing layer %d from stack\n", layerlist[ pEvent->m_nLayer ].priority );
  3102. }
  3103. // We'll need to add a "discontinuity" fixup sample from the
  3104. // 1) A sample from the ending layer @ start time
  3105. // 2) A sample from the new layer @ start time + .1 msec
  3106. // NOTE: This will cause problems if there are non-default value keys at max time
  3107. Assert( active.Count() >= 1 );
  3108. if ( bFixupDiscontinuities && ( pEvent->m_Time != DMETIME_MAXTIME ) )
  3109. {
  3110. AddDiscontinitySample( pBaseLayer, pLog, pEvent->m_Time, GetActiveLayerValue( layerlist, pEvent->m_Time, pEvent->m_nLayer ), bSpew ? "end" : NULL );
  3111. if ( active.Count() >= 2 )
  3112. {
  3113. DmeTime_t keyTime = pEvent->m_Time + DmeTime_t( 1 );
  3114. AddDiscontinitySample( pBaseLayer, pLog, keyTime, pEvent->m_NeighborValue, bSpew ? "end" : NULL );
  3115. }
  3116. }
  3117. active.Remove( &layerlist[ pEvent->m_nLayer ] );
  3118. return ( active.Count() >= 2 ) ? pEvent->m_Time + DmeTime_t( 1 ) : pEvent->m_Time;
  3119. }
  3120. template< class T >
  3121. void CDmeTypedLog< T >::FlattenLayers( float threshold, int flags )
  3122. {
  3123. // Already flattened
  3124. if ( m_Layers.Count() <= 1 )
  3125. return;
  3126. if ( g_pDataModel->UndoEnabledForElement( this ) )
  3127. {
  3128. CUndoFlattenLayers<T> *pUndo = new CUndoFlattenLayers<T>( "FlattenLayers", this, threshold, flags );
  3129. g_pDataModel->AddUndoElement( pUndo );
  3130. }
  3131. bool bSpew = ( flags & FLATTEN_SPEW ) != 0;
  3132. bool bFixupDiscontinuities = true; //( flags & FLATTEN_NODISCONTINUITY_FIXUP ) == 0;
  3133. // NOTE: UNDO IS DISABLED FOR THE REST OF THIS OPERATION (the above function does what we need to preserve the layers)
  3134. CDisableUndoScopeGuard guard;
  3135. CDmeTypedLogLayer< T > *flattenedlayer = static_cast< CDmeTypedLogLayer< T > * >( CreateLayer< T >( this ) );
  3136. flattenedlayer->SetOwnerLog( this );
  3137. // Global list of layers
  3138. CUtlVector< ActiveLayer_t< T > > layerlist;
  3139. // List of all start/end layer events, sorted by the time at which the event occurs ( we walk this list in order )
  3140. CUtlRBTree< LayerEvent_t< T > > events( 0, 0, LayerEvent_t< T >::LessFunc );
  3141. // Stack of active events, sorted by event "priority", which means last item is the one writing data into the new base layer
  3142. CUtlRBTree< ActiveLayer_t< T > * > active( 0, 0, ActiveLayer_t< T >::PriorityLessFunc );
  3143. // Build layer list and list of start/end events and times
  3144. ComputeLayerEvents( this, layerlist, events );
  3145. // Debuggins
  3146. if ( bSpew )
  3147. {
  3148. SpewEvents( events );
  3149. }
  3150. // Now walk from the earliest time in any layer until the latest time, going key by key and checking if the active layer should change as we go
  3151. DmeTime_t iCurrentKeyTime = DmeTime_t::MinTime();
  3152. unsigned short idx = events.FirstInorder();
  3153. while ( 1 )
  3154. {
  3155. if ( idx == events.InvalidIndex() )
  3156. break;
  3157. LayerEvent_t< T > *pEvent = &events[ idx ];
  3158. switch ( pEvent->m_Type )
  3159. {
  3160. default:
  3161. iCurrentKeyTime = pEvent->m_Time;
  3162. Assert( 0 );
  3163. break;
  3164. case LayerEvent_t< T >::LE_START:
  3165. iCurrentKeyTime = ProcessStartLayerStartEvent( bSpew, bFixupDiscontinuities, this, pEvent, layerlist, active, flattenedlayer );
  3166. break;
  3167. case LayerEvent_t< T >::LE_END:
  3168. iCurrentKeyTime = ProcessStartLayerEndEvent( bSpew, bFixupDiscontinuities, this, pEvent, layerlist, active, flattenedlayer );
  3169. break;
  3170. }
  3171. int nNextIndex = events.NextInorder( idx );
  3172. // We popped the last item off the stack
  3173. if ( nNextIndex == events.InvalidIndex() )
  3174. {
  3175. Assert( active.Count() == 0 );
  3176. break;
  3177. }
  3178. // Walk from current time up to the time of the next relevant event
  3179. LayerEvent_t< T > *nextevent = &events[ nNextIndex ];
  3180. DmeTime_t layerFinishTime = nextevent->m_Time;
  3181. // The topmost layer is the active layer
  3182. int layernum = active.LastInorder();
  3183. if ( layernum == active.InvalidIndex() )
  3184. break;
  3185. ActiveLayer_t< T > *activeLayer = active[ layernum ];
  3186. CDmeTypedLogLayer< T > *loglayer = activeLayer->layer;
  3187. // Splat all keys betweeen the current head position and the next event time (layerFinishTime) into the flattened layer
  3188. int keyCount = loglayer->GetKeyCount();
  3189. for ( int j = 0; j < keyCount; ++j )
  3190. {
  3191. DmeTime_t keyTime = loglayer->GetKeyTime( j );
  3192. // Key is too early, skip
  3193. if ( keyTime < iCurrentKeyTime )
  3194. continue;
  3195. // Done with this layer, set time exactly equal to end time so next layer can take over
  3196. // at the correct spot
  3197. if ( keyTime >= layerFinishTime )
  3198. {
  3199. iCurrentKeyTime = layerFinishTime;
  3200. break;
  3201. }
  3202. // Advance the head position
  3203. iCurrentKeyTime = keyTime;
  3204. // Because it's a key, the interpolated value should == the actual value (not true for certain 4 point curve types, but we shouldn't support them
  3205. // for this type of operation anyway)
  3206. const T& val = loglayer->GetKeyValue( j );
  3207. // Debugging spew
  3208. if ( bSpew )
  3209. {
  3210. SpewFlattenedKey( loglayer, activeLayer, iCurrentKeyTime, val );
  3211. }
  3212. // Now set the key into the flattened layer
  3213. flattenedlayer->SetKey( iCurrentKeyTime, val, loglayer->IsUsingCurveTypes() ? loglayer->GetKeyCurveType( j ) : CURVE_DEFAULT );
  3214. }
  3215. idx = nNextIndex;
  3216. }
  3217. // Blow away all of the existing layers except the original base layer
  3218. while ( GetNumLayers() > 1 )
  3219. {
  3220. CDmeTypedLogLayer< T > *layer = static_cast< CDmeTypedLogLayer< T > * >( RemoveLayerFromTail() );
  3221. g_pDataModel->DestroyElement( layer->GetHandle() );
  3222. }
  3223. // Compress the flattened layer
  3224. flattenedlayer->RemoveRedundantKeys( threshold );
  3225. // Copy the flattened layer over the existing base layer
  3226. GetLayer( 0 )->CopyLayer( flattenedlayer );
  3227. g_pDataModel->DestroyElement( flattenedlayer->GetHandle() );
  3228. }
  3229. template< class T >
  3230. void CDmeTypedLog< T >::StampKeyAtHead( DmeTime_t tHeadPosition, DmeTime_t tPreviousHeadPosition, const DmeLog_TimeSelection_t& params, const CDmAttribute *pAttr, uint index /*= 0*/ )
  3231. {
  3232. DmAttributeType_t type = pAttr->GetType();
  3233. if ( IsValueType( type ) )
  3234. {
  3235. Assert( pAttr->GetType() == GetDataType() );
  3236. StampKeyAtHead( tHeadPosition, tPreviousHeadPosition, params, pAttr->GetValue< T >() );
  3237. }
  3238. else if ( IsArrayType( type ) )
  3239. {
  3240. Assert( ArrayTypeToValueType( type ) == GetDataType() );
  3241. CDmrArrayConst<T> array( pAttr );
  3242. StampKeyAtHead( tHeadPosition, tPreviousHeadPosition, params, array[ index ] );
  3243. }
  3244. else
  3245. {
  3246. Assert( 0 );
  3247. }
  3248. }
  3249. template< class T >
  3250. void CDmeTypedLog< T >::FinishTimeSelection( DmeTime_t tHeadPosition, DmeLog_TimeSelection_t& params )
  3251. {
  3252. bool bWasAdvancing = params.IsTimeAdvancing();
  3253. params.ResetTimeAdvancing();
  3254. if ( !params.m_bAttachedMode )
  3255. return;
  3256. if ( !bWasAdvancing )
  3257. return;
  3258. // Should be in "layer recording" mode!!!
  3259. Assert( GetNumLayers() >= 2 );
  3260. int nBestLayer = GetTopmostLayer(); // Topmost should be at least layer # 1 (0 is the base layer)
  3261. if ( nBestLayer < 1 )
  3262. return;
  3263. CDmeTypedLogLayer< T > *pWriteLayer = GetLayer( nBestLayer );
  3264. Assert( pWriteLayer );
  3265. if ( !pWriteLayer )
  3266. return;
  3267. int nKeyCount = pWriteLayer->GetKeyCount();
  3268. if ( nKeyCount <= 0 )
  3269. return;
  3270. // The head is considered to be at the "last" value
  3271. T headValue = pWriteLayer->GetKeyValue( nKeyCount - 1 );
  3272. _StampKeyAtHeadResample( tHeadPosition, params, headValue, true, false );
  3273. }
  3274. template< >
  3275. float CDmeTypedLog< float >::ClampValue( const float& value )
  3276. {
  3277. float retval;
  3278. if ( !IsUsingCurveTypes() )
  3279. {
  3280. retval = clamp( value, 0.0f, 1.0f );
  3281. }
  3282. else
  3283. {
  3284. retval = clamp( value, GetMinValue(), GetMaxValue() );
  3285. }
  3286. return retval;
  3287. }
  3288. template< class T >
  3289. void CDmeTypedLog< T >::StampKeyAtHead( DmeTime_t tHeadPosition, DmeTime_t tPreviousHeadPosition, const DmeLog_TimeSelection_t& params, const T& value )
  3290. {
  3291. //T useValue = ClampValue( value );
  3292. // This gets set if time ever starts moving (even if the user pauses time while still holding a slider)
  3293. if ( params.IsTimeAdvancing() )
  3294. {
  3295. // This uses the time selection as a "filter" to decide whether to stamp a new key at the current position
  3296. _StampKeyAtHeadFilteredByTimeSelection( tHeadPosition, tPreviousHeadPosition, params, value );
  3297. }
  3298. else
  3299. {
  3300. Assert( params.m_bResampleMode );
  3301. _StampKeyAtHeadResample( tHeadPosition, params, value, false, true );
  3302. }
  3303. }
  3304. /*
  3305. template<>
  3306. void CDmeTypedLog< float >::_StampKeyAtHeadResample( const DmeLog_TimeSelection_t& params, const float& value );
  3307. template<>
  3308. void CDmeTypedLog< bool >::_StampKeyAtHeadResample( const DmeLog_TimeSelection_t& params, const bool& value );
  3309. template<>
  3310. void CDmeTypedLog< Color >::_StampKeyAtHeadResample( const DmeLog_TimeSelection_t& params, const Color& value );
  3311. template<>
  3312. void CDmeTypedLog< Vector4D >::_StampKeyAtHeadResample( const DmeLog_TimeSelection_t& params, const Vector4D& value );
  3313. template<>
  3314. void CDmeTypedLog< Vector2D >::_StampKeyAtHeadResample( const DmeLog_TimeSelection_t& params, const Vector2D& value );
  3315. template<>
  3316. void CDmeTypedLog< VMatrix >::_StampKeyAtHeadResample( const DmeLog_TimeSelection_t& params, const VMatrix& value );
  3317. template<>
  3318. void CDmeTypedLog< Quaternion >::_StampKeyAtHeadResample( const DmeLog_TimeSelection_t& params, const Quaternion& value );
  3319. template<>
  3320. void CDmeTypedLog< QAngle >::_StampKeyAtHeadResample( const DmeLog_TimeSelection_t& params, const QAngle& value );
  3321. */
  3322. //-----------------------------------------------------------------------------
  3323. // Helper class used to compute falloff blend factors
  3324. //-----------------------------------------------------------------------------
  3325. template< class T >
  3326. struct LogClampHelper_t
  3327. {
  3328. public:
  3329. LogClampHelper_t() : m_tLastTime( DMETIME_MINTIME ) {}
  3330. DmeTime_t m_tLastTime;
  3331. T m_LastUnclampedValue;
  3332. };
  3333. template< class T >
  3334. class CLogFalloffBlend
  3335. {
  3336. public:
  3337. void Init( CDmeTypedLog<T> *pLog, DmeTime_t tFalloff, DmeTime_t tHold, bool bLeftFalloff, int nInterpolatorType, const T& delta );
  3338. void Init( CDmeTypedLog<T> *pLog, const T& delta );
  3339. float ComputeBlendFactor( DmeTime_t tTime, const T& oldVal, bool bUsingInterpolation ) const;
  3340. const T& GetDelta() const;
  3341. void StampKey( CDmeTypedLogLayer<T>* pWriteLayer, DmeTime_t t, const CDmeTypedLogLayer<T>* pReadLayer, float flIntensity, LogClampHelper_t<T> &helper, bool bSpew, const T* pInterpTarget );
  3342. void UpdateClampHelper( DmeTime_t t, const CDmeTypedLogLayer<T>* pReadLayer, float flIntensity, LogClampHelper_t<T> &helper, const T* pInterpTarget );
  3343. private:
  3344. void ComputeDelta( CDmeTypedLog<T> *pLog, const T& delta, const T& holdValue );
  3345. void InsertClampTransitionPoints( CDmeTypedLogLayer<T>* pWriteLayer, DmeTime_t t, LogClampHelper_t<T> &clampHelper, const T& val, bool bSpew );
  3346. void ComputeBounds( CDmeTypedLog<T> *pLog );
  3347. T m_BaseValue;
  3348. T m_Delta;
  3349. DmeTime_t m_tBaseTime;
  3350. DmeTime_t m_tHoldTime;
  3351. float m_flOOTime;
  3352. int m_nTestSign;
  3353. int m_nInterpolatorType;
  3354. int m_nCurveType;
  3355. T m_MinValue;
  3356. T m_MaxValue;
  3357. bool m_bHold;
  3358. };
  3359. template< class T >
  3360. void CLogFalloffBlend< T >::Init( CDmeTypedLog<T> *pLog, DmeTime_t tFalloffTime, DmeTime_t tHoldTime, bool bLeftFalloff, int nInterpolatorType, const T& delta )
  3361. {
  3362. m_tBaseTime = tFalloffTime;
  3363. m_tHoldTime = tHoldTime;
  3364. m_BaseValue = pLog->GetValueSkippingTopmostLayer( tFalloffTime );
  3365. T holdValue = pLog->GetValueSkippingTopmostLayer( tHoldTime );
  3366. m_nTestSign = bLeftFalloff ? 1 : -1;
  3367. m_nInterpolatorType = nInterpolatorType;
  3368. m_bHold = false;
  3369. m_nCurveType = pLog->IsUsingCurveTypes() ? pLog->GetDefaultCurveType() : CURVE_DEFAULT;
  3370. float flDuration = tHoldTime.GetSeconds() - tFalloffTime.GetSeconds();
  3371. m_flOOTime = ( flDuration != 0.0f ) ? 1.0f / flDuration : 0.0f;
  3372. ComputeBounds( pLog );
  3373. ComputeDelta( pLog, delta, holdValue );
  3374. }
  3375. template< class T >
  3376. void CLogFalloffBlend< T >::Init( CDmeTypedLog<T> *pLog, const T& delta )
  3377. {
  3378. m_nTestSign = 0;
  3379. m_nInterpolatorType = INTERPOLATE_DEFAULT;
  3380. m_bHold = true;
  3381. m_nCurveType = pLog->IsUsingCurveTypes() ? pLog->GetDefaultCurveType() : CURVE_DEFAULT;
  3382. m_Delta = delta;
  3383. ComputeBounds( pLog );
  3384. }
  3385. template< class T >
  3386. void CLogFalloffBlend< T >::ComputeBounds( CDmeTypedLog<T> *pLog )
  3387. {
  3388. }
  3389. template<>
  3390. void CLogFalloffBlend< float >::ComputeBounds( CDmeTypedLog<float> *pLog )
  3391. {
  3392. m_MinValue = pLog->IsUsingCurveTypes() ? pLog->GetMinValue() : 0.0f;
  3393. m_MaxValue = pLog->IsUsingCurveTypes() ? pLog->GetMaxValue() : 1.0f;
  3394. }
  3395. template< class T >
  3396. void CLogFalloffBlend< T >::ComputeDelta( CDmeTypedLog<T> *pLog, const T& delta, const T& holdValue )
  3397. {
  3398. // By default, no clamping
  3399. m_Delta = delta;
  3400. }
  3401. template<>
  3402. void CLogFalloffBlend< float >::ComputeDelta( CDmeTypedLog<float> *pLog, const float& delta, const float& holdValue )
  3403. {
  3404. if ( LengthOf( delta ) > 0.0f )
  3405. {
  3406. m_Delta = min( delta, m_MaxValue - holdValue ); // Max amount we can move up...
  3407. }
  3408. else
  3409. {
  3410. m_Delta = max( delta, m_MinValue - holdValue ); // Amount we can move down...
  3411. }
  3412. }
  3413. template< class T >
  3414. float CLogFalloffBlend< T >::ComputeBlendFactor( DmeTime_t tTime, const T& oldVal, bool bUsingInterpolation ) const
  3415. {
  3416. if ( m_bHold )
  3417. return 1.0f;
  3418. // Clamp inside region; hold time beats base time (for zero width regions)
  3419. if ( ( tTime - m_tHoldTime ) * m_nTestSign >= DMETIME_ZERO )
  3420. return 1.0f;
  3421. if ( ( tTime - m_tBaseTime ) * m_nTestSign <= DMETIME_ZERO )
  3422. return 0.0f;
  3423. float flFactor = ( tTime.GetSeconds() - m_tBaseTime.GetSeconds() ) * m_flOOTime;
  3424. return ComputeInterpolationFactor( flFactor, m_nInterpolatorType );
  3425. }
  3426. template< class T >
  3427. const T& CLogFalloffBlend< T >::GetDelta( ) const
  3428. {
  3429. return m_Delta;
  3430. }
  3431. //-----------------------------------------------------------------------------
  3432. // Insert points where clamping begins or ends
  3433. //-----------------------------------------------------------------------------
  3434. template< class T >
  3435. void CLogFalloffBlend< T >::InsertClampTransitionPoints( CDmeTypedLogLayer<T>* pWriteLayer,
  3436. DmeTime_t t, LogClampHelper_t<T> &clampHelper, const T& val, bool bSpew )
  3437. {
  3438. // NOTE: By default, nothing clamps, so no transition points are needed
  3439. }
  3440. template<>
  3441. void CLogFalloffBlend< float >::InsertClampTransitionPoints( CDmeTypedLogLayer<float>* pWriteLayer,
  3442. DmeTime_t t, LogClampHelper_t<float> &clampHelper, const float& val, bool bSpew )
  3443. {
  3444. bool bLastLess, bLastGreater, bCurrLess, bCurrGreater;
  3445. DmeTime_t tCrossing, tDuration;
  3446. double flOODv;
  3447. // First time through? cache last values.
  3448. if ( clampHelper.m_tLastTime == DMETIME_MINTIME )
  3449. goto cacheLastValues;
  3450. bLastLess = clampHelper.m_LastUnclampedValue < m_MinValue;
  3451. bLastGreater = clampHelper.m_LastUnclampedValue > m_MaxValue;
  3452. bCurrLess = val < m_MinValue;
  3453. bCurrGreater = val > m_MaxValue;
  3454. if ( bLastLess == bCurrLess && bLastGreater == bCurrGreater )
  3455. goto cacheLastValues;
  3456. // NOTE: The check above means val != m_LastUnclampedValue
  3457. flOODv = 1.0 / ( val - clampHelper.m_LastUnclampedValue );
  3458. tDuration = t - clampHelper.m_tLastTime;
  3459. // NOTE: Clamp semantics here favor keeping the non-clamped value
  3460. // That's why when we start outside + end inside, we never overwrite the dest
  3461. // and why when we start inside + end outside, we never overwrite the start
  3462. // These two checks deal with starting outside + heading inside
  3463. if ( bLastLess && !bCurrLess )
  3464. {
  3465. // Insert at min crossing
  3466. double flFactor = ( m_MinValue - clampHelper.m_LastUnclampedValue ) * flOODv;
  3467. tCrossing = clampHelper.m_tLastTime + tDuration * flFactor;
  3468. tCrossing.Clamp( clampHelper.m_tLastTime, t - DMETIME_MINDELTA );
  3469. pWriteLayer->InsertKey( tCrossing, m_MinValue, m_nCurveType );
  3470. if ( bSpew )
  3471. {
  3472. Msg(" Clamp Crossing Key: %d %f\n", tCrossing.GetTenthsOfMS(), m_MinValue );
  3473. }
  3474. }
  3475. else if ( bLastGreater && !bCurrGreater )
  3476. {
  3477. // Insert at max crossing
  3478. double flFactor = ( m_MaxValue - clampHelper.m_LastUnclampedValue ) * flOODv;
  3479. tCrossing = clampHelper.m_tLastTime + tDuration * flFactor;
  3480. tCrossing.Clamp( clampHelper.m_tLastTime, t - DMETIME_MINDELTA );
  3481. pWriteLayer->InsertKey( tCrossing, m_MaxValue, m_nCurveType );
  3482. if ( bSpew )
  3483. {
  3484. Msg(" Clamp Crossing Key: %d %f\n", tCrossing.GetTenthsOfMS(), m_MaxValue );
  3485. }
  3486. }
  3487. // These two checks deal with starting inside + heading outside
  3488. if ( !bLastLess && bCurrLess )
  3489. {
  3490. // Insert at min crossing
  3491. // NOTE: Clamp semantics here favor keeping the non-clamped value
  3492. double flFactor = ( m_MinValue - clampHelper.m_LastUnclampedValue ) * flOODv;
  3493. tCrossing = clampHelper.m_tLastTime + tDuration * flFactor;
  3494. tCrossing.Clamp( clampHelper.m_tLastTime + DMETIME_MINDELTA, t );
  3495. pWriteLayer->InsertKey( tCrossing, m_MinValue, m_nCurveType );
  3496. if ( bSpew )
  3497. {
  3498. Msg(" Clamp Crossing Key: %d %f\n", tCrossing.GetTenthsOfMS(), m_MinValue );
  3499. }
  3500. }
  3501. else if ( !bLastGreater && bCurrGreater )
  3502. {
  3503. // Insert at max crossing
  3504. double flFactor = ( m_MaxValue - clampHelper.m_LastUnclampedValue ) * flOODv;
  3505. tCrossing = clampHelper.m_tLastTime + tDuration * flFactor;
  3506. tCrossing.Clamp( clampHelper.m_tLastTime + DMETIME_MINDELTA, t );
  3507. pWriteLayer->InsertKey( tCrossing, m_MaxValue, m_nCurveType );
  3508. if ( bSpew )
  3509. {
  3510. Msg(" Clamp Crossing Key: %d %f\n", tCrossing.GetTenthsOfMS(), m_MaxValue );
  3511. }
  3512. }
  3513. // Cache off the last values
  3514. cacheLastValues:
  3515. clampHelper.m_tLastTime = t;
  3516. clampHelper.m_LastUnclampedValue = val;
  3517. }
  3518. //-----------------------------------------------------------------------------
  3519. // Stamp the key at the specified time
  3520. //-----------------------------------------------------------------------------
  3521. template< class T >
  3522. void CLogFalloffBlend< T >::StampKey( CDmeTypedLogLayer<T>* pWriteLayer, DmeTime_t t,
  3523. const CDmeTypedLogLayer<T>* pReadLayer, float flIntensity, LogClampHelper_t<T> &clampHelper, bool bSpew, const T* pInterpTarget )
  3524. {
  3525. // Stamp the key at the current time
  3526. T oldVal = pReadLayer->GetValue( t );
  3527. // In the falloff area
  3528. float flFactor = ComputeBlendFactor( t, oldVal, ( pInterpTarget != NULL ) );
  3529. flFactor *= flIntensity;
  3530. T newVal;
  3531. if ( !pInterpTarget )
  3532. {
  3533. newVal = ScaleValue( m_Delta, flFactor );
  3534. newVal = Add( oldVal, newVal );
  3535. }
  3536. else
  3537. {
  3538. newVal = Interpolate( flFactor, oldVal, *pInterpTarget );
  3539. }
  3540. InsertClampTransitionPoints( pWriteLayer, t, clampHelper, newVal, bSpew );
  3541. T clampedVal = pWriteLayer->GetTypedOwnerLog()->ClampValue( newVal );
  3542. // Add a key to the new "layer" at this time with this value
  3543. pWriteLayer->InsertKey( t, clampedVal, m_nCurveType );
  3544. if ( bSpew )
  3545. {
  3546. Msg(" Key: %d ", t.GetTenthsOfMS() );
  3547. SpewKey( clampedVal );
  3548. Msg(" [" );
  3549. SpewKey( newVal );
  3550. Msg( "]\n" );
  3551. }
  3552. }
  3553. //-----------------------------------------------------------------------------
  3554. // Stamp the key at the specified time
  3555. //-----------------------------------------------------------------------------
  3556. template< class T >
  3557. void CLogFalloffBlend< T >::UpdateClampHelper( DmeTime_t t, const CDmeTypedLogLayer<T>* pReadLayer,
  3558. float flIntensity, LogClampHelper_t<T> &clampHelper, const T* pInterpTarget )
  3559. {
  3560. // Stamp the key at the current time
  3561. T oldVal = pReadLayer->GetValue( t );
  3562. // In the falloff area
  3563. float flFactor = ComputeBlendFactor( t, oldVal, ( pInterpTarget != NULL ) );
  3564. flFactor *= flIntensity;
  3565. T val;
  3566. if ( !pInterpTarget )
  3567. {
  3568. val = ScaleValue( m_Delta, flFactor );
  3569. val = Add( oldVal, val );
  3570. }
  3571. else
  3572. {
  3573. val = Interpolate( flFactor, oldVal, *pInterpTarget );
  3574. }
  3575. clampHelper.m_tLastTime = t;
  3576. clampHelper.m_LastUnclampedValue = val;
  3577. }
  3578. //-----------------------------------------------------------------------------
  3579. // This is used to modify the entire portion of the curve under the time selection
  3580. //-----------------------------------------------------------------------------
  3581. static inline DmeTime_t ComputeResampleStartTime( const DmeLog_TimeSelection_t &params, int nSide )
  3582. {
  3583. // NOTE: This logic will place the resampled points centered in the falloff regions
  3584. DmeTimeSelectionTimes_t start = ( nSide == 0 ) ? TS_LEFT_FALLOFF : TS_RIGHT_HOLD;
  3585. DmeTimeSelectionTimes_t end = ( nSide == 0 ) ? TS_LEFT_HOLD : TS_RIGHT_FALLOFF;
  3586. if ( params.m_nFalloffInterpolatorTypes[nSide] != INTERPOLATE_LINEAR_INTERP )
  3587. {
  3588. DmeTime_t tDuration = params.m_nTimes[end] - params.m_nTimes[start];
  3589. if ( tDuration > params.m_nResampleInterval )
  3590. {
  3591. int nFactor = tDuration.GetTenthsOfMS() / params.m_nResampleInterval.GetTenthsOfMS();
  3592. tDuration -= params.m_nResampleInterval * nFactor;
  3593. tDuration /= 2;
  3594. return params.m_nTimes[start] + tDuration;
  3595. }
  3596. }
  3597. return DMETIME_MAXTIME;
  3598. }
  3599. //-----------------------------------------------------------------------------
  3600. // This is used to modify the entire portion of the curve under the time selection
  3601. //-----------------------------------------------------------------------------
  3602. template< class T >
  3603. void CDmeTypedLog< T >::_StampKeyAtHeadResample( DmeTime_t tHeadPosition, const DmeLog_TimeSelection_t& params, const T& value, bool bSkipToHead, bool bClearPreviousKeys )
  3604. {
  3605. Assert( params.m_nResampleInterval > DmeTime_t( 0 ) );
  3606. if ( params.m_nResampleInterval < DmeTime_t( 0 ) )
  3607. return;
  3608. // Should be in "layer recording" mode!!!
  3609. Assert( GetNumLayers() >= 2 );
  3610. int nBestLayer = GetTopmostLayer(); // Topmost should be at least layer # 1 (0 is the base layer)
  3611. if ( nBestLayer < 1 )
  3612. return;
  3613. CDmeTypedLogLayer< T > *pWriteLayer = GetLayer( nBestLayer );
  3614. Assert( pWriteLayer );
  3615. if ( !pWriteLayer )
  3616. return;
  3617. if ( bClearPreviousKeys )
  3618. {
  3619. pWriteLayer->ClearKeys();
  3620. }
  3621. bool bSpew = false;
  3622. // NOTE: The headDelta is only used when not blending toward a preset
  3623. // When not blending toward a preset, just add the head delta onto everything.
  3624. // When blending toward a preset, lerp towards the preset.
  3625. T oldHeadValue = GetValueSkippingTopmostLayer( tHeadPosition );
  3626. T headDelta = Subtract( value, oldHeadValue );
  3627. // When dragging preset fader, eveything get's blended in by the amount of the preset being applied
  3628. bool bUsePresetRules = ( RECORD_PRESET == params.GetRecordingMode() );
  3629. bool bIsStampingQuaternions = ( CDmAttributeInfo<T>::ATTRIBUTE_TYPE == AT_QUATERNION );
  3630. bool bPerformInterpolation = bUsePresetRules || bIsStampingQuaternions;
  3631. // FIXME: Preset value should never be NULL. We need to grab it from the attribute
  3632. bool bUsePresetValue = bUsePresetRules && params.m_pPresetValue && params.m_pPresetValue->GetType() == CDmAttributeInfo<T>::ATTRIBUTE_TYPE;
  3633. const T& interpTarget = bUsePresetValue ? params.m_pPresetValue->GetValue<T>() : value;
  3634. // Compute falloff region blend factors
  3635. CLogFalloffBlend< T > blend[ 3 ];
  3636. blend[0].Init( this, params.m_nTimes[ TS_FALLOFF(0) ], params.m_nTimes[ TS_HOLD(0) ], true, params.m_nFalloffInterpolatorTypes[0], headDelta );
  3637. blend[1].Init( this, headDelta );
  3638. blend[2].Init( this, params.m_nTimes[ TS_FALLOFF(1) ], params.m_nTimes[ TS_HOLD(1) ], false, params.m_nFalloffInterpolatorTypes[1], headDelta );
  3639. // The algorithm we're going to use is to add samples in the following places:
  3640. // 1) At each time selection transition point (start, end of falloff regions)
  3641. // NOTE: If a falloff region has 0 size, we'll add points right outside the transition
  3642. // 2) At the resample point (we're going to base this so the resamples always occur at the same spots)
  3643. // 3) At any existing sample position
  3644. // 4) Any time we switch from clamped to not clamped
  3645. // By doing this, we will guarantee no bogus slope changes
  3646. // First, compute times for transition regions
  3647. DmeTime_t tTransitionTimes[TS_TIME_COUNT];
  3648. memcpy( &tTransitionTimes, &params.m_nTimes, sizeof(params.m_nTimes) );
  3649. if ( tTransitionTimes[TS_LEFT_FALLOFF] == tTransitionTimes[TS_LEFT_HOLD] )
  3650. {
  3651. tTransitionTimes[TS_LEFT_FALLOFF] -= DMETIME_MINDELTA;
  3652. }
  3653. if ( tTransitionTimes[TS_RIGHT_FALLOFF] == tTransitionTimes[TS_RIGHT_HOLD] )
  3654. {
  3655. tTransitionTimes[TS_RIGHT_FALLOFF] += DMETIME_MINDELTA;
  3656. }
  3657. DmeTime_t tStartTime = params.m_nTimes[ TS_LEFT_FALLOFF ];
  3658. // Next, compute the first resample time for each region
  3659. DmeTime_t tResampleStartTime[TS_TIME_COUNT];
  3660. tResampleStartTime[TS_LEFT_FALLOFF] = DMETIME_MAXTIME;
  3661. tResampleStartTime[TS_LEFT_HOLD] = ComputeResampleStartTime( params, 0 );
  3662. tResampleStartTime[TS_RIGHT_HOLD] = DMETIME_MAXTIME;
  3663. tResampleStartTime[TS_RIGHT_FALLOFF] = ComputeResampleStartTime( params, 1 );
  3664. // Finally, figure out which layer we're reading from,
  3665. // where the next key is, and when we must stop reading from it
  3666. int nReadLayer = FindLayerForTimeSkippingTopmost( tStartTime );
  3667. CDmeTypedLogLayer< T > *pReadLayer = GetLayer( nReadLayer );
  3668. int nLayerSampleIndex = pReadLayer->FindKey( tStartTime ) + 1;
  3669. DmeTime_t tLayerEndTime = pReadLayer->GetEndTime();
  3670. // NOTE: This can happen after reading off the end of layer 0
  3671. if ( tLayerEndTime <= tStartTime )
  3672. {
  3673. tLayerEndTime = DMETIME_MAXTIME;
  3674. }
  3675. DmeTime_t tNextSampleTime = nLayerSampleIndex >= pReadLayer->GetKeyCount() ? tLayerEndTime : pReadLayer->GetKeyTime( nLayerSampleIndex );
  3676. if ( tNextSampleTime > tLayerEndTime )
  3677. {
  3678. tNextSampleTime = tLayerEndTime;
  3679. }
  3680. // Now keep going until we've hit the end point
  3681. // NOTE: We use tTransitionTimes, *not* params.m_nTimes, so that we can get a single
  3682. // sample before zero-width left falloff regions
  3683. DmeTime_t tCurrent = tTransitionTimes[TS_LEFT_FALLOFF];
  3684. int nNextTransition = TS_LEFT_HOLD;
  3685. DmeTime_t tResampleTime = tResampleStartTime[nNextTransition];
  3686. const T* pInterpTarget = bPerformInterpolation ? &interpTarget : NULL;
  3687. if ( bSpew )
  3688. {
  3689. Msg( "Stamp key at head resample: %s\n", GetName() );
  3690. }
  3691. LogClampHelper_t<T> clampHelper;
  3692. while( nNextTransition < TS_TIME_COUNT )
  3693. {
  3694. // Stamp the key at the current time
  3695. if ( !bSkipToHead || ( tCurrent >= tHeadPosition ) )
  3696. {
  3697. blend[nNextTransition-1].StampKey( pWriteLayer, tCurrent, pReadLayer, params.m_flIntensity, clampHelper, bSpew, pInterpTarget );
  3698. }
  3699. // Update the read layer sample
  3700. if ( tCurrent == tNextSampleTime )
  3701. {
  3702. ++nLayerSampleIndex;
  3703. tNextSampleTime = nLayerSampleIndex >= pReadLayer->GetKeyCount() ? tLayerEndTime : pReadLayer->GetKeyTime( nLayerSampleIndex );
  3704. }
  3705. // Update the read layer
  3706. if ( tCurrent == tLayerEndTime )
  3707. {
  3708. nReadLayer = FindLayerForTimeSkippingTopmost( tCurrent + DMETIME_MINDELTA );
  3709. pReadLayer = GetLayer( nReadLayer );
  3710. nLayerSampleIndex = pReadLayer->FindKey( tCurrent ) + 1;
  3711. tLayerEndTime = pReadLayer->GetEndTime();
  3712. // NOTE: This can happen after reading off the end of layer 0
  3713. if ( tLayerEndTime <= tCurrent )
  3714. {
  3715. tLayerEndTime = DMETIME_MAXTIME;
  3716. }
  3717. tNextSampleTime = nLayerSampleIndex >= pReadLayer->GetKeyCount() ? tLayerEndTime : pReadLayer->GetKeyTime( nLayerSampleIndex );
  3718. if ( tNextSampleTime > tLayerEndTime )
  3719. {
  3720. tNextSampleTime = tLayerEndTime;
  3721. }
  3722. }
  3723. // Update the transition time
  3724. if ( tCurrent == tTransitionTimes[nNextTransition] )
  3725. {
  3726. // NOTE: This is necessary because each blend region has different 'deltas'
  3727. // to avoid overdriving in the falloff regions. Therefore, the 'previous value'
  3728. // used in the clamping operation will be different
  3729. if ( nNextTransition < ARRAYSIZE(blend) )
  3730. {
  3731. blend[nNextTransition].UpdateClampHelper( tCurrent, pReadLayer, params.m_flIntensity, clampHelper, pInterpTarget );
  3732. }
  3733. // Also need to update the 'previous' value stored in the
  3734. ++nNextTransition;
  3735. if ( nNextTransition >= ARRAYSIZE(tResampleStartTime) )
  3736. break;
  3737. // Update the first resample time
  3738. tResampleTime = tResampleStartTime[nNextTransition];
  3739. if ( bSpew )
  3740. {
  3741. Msg( " Entering region %d\n", nNextTransition-1 );
  3742. }
  3743. }
  3744. // Update the resample time
  3745. if ( tCurrent == tResampleTime )
  3746. {
  3747. tResampleTime += params.m_nResampleInterval;
  3748. }
  3749. // Now that the key is stamped, update current time.
  3750. tCurrent = tTransitionTimes[nNextTransition];
  3751. if ( tResampleTime < tCurrent )
  3752. {
  3753. tCurrent = tResampleTime;
  3754. }
  3755. if ( tNextSampleTime < tCurrent )
  3756. {
  3757. tCurrent = tNextSampleTime;
  3758. }
  3759. }
  3760. }
  3761. //-----------------------------------------------------------------------------
  3762. // In this case, we actually stamp a key right at the head position unlike the above method
  3763. //-----------------------------------------------------------------------------
  3764. template< class T >
  3765. void CDmeTypedLog< T >::_StampKeyFilteredByTimeSelection( CDmeTypedLogLayer< T > *pWriteLayer, DmeTime_t t, const DmeLog_TimeSelection_t &params, const T& value, bool bForce )
  3766. {
  3767. // Found a key which needs to be modulated upward
  3768. float flFraction = params.GetAmountForTime( t ) * params.m_flIntensity;
  3769. if ( flFraction <= 0.0f && !bForce )
  3770. return;
  3771. // When dragging preset fader, eveything get's blended in by the amount of the preset being applied
  3772. bool bUsePresetRules = ( RECORD_PRESET == params.GetRecordingMode() );
  3773. // FIXME: Preset value should never be NULL. We need to grab it from the attribute
  3774. const T& interpTarget = ( bUsePresetRules && params.m_pPresetValue ) ? params.m_pPresetValue->GetValue<T>() : value;
  3775. T oldVal = GetValueSkippingTopmostLayer( t );
  3776. T newVal = Interpolate( flFraction, oldVal, interpTarget );
  3777. T writeVal = ClampValue( newVal );
  3778. pWriteLayer->InsertKey( t, writeVal, IsUsingCurveTypes() ? GetDefaultCurveType() : CURVE_DEFAULT );
  3779. }
  3780. //-----------------------------------------------------------------------------
  3781. // In this case, we actually stamp a key right at the head position unlike the above method
  3782. //-----------------------------------------------------------------------------
  3783. template< class T >
  3784. void CDmeTypedLog< T >::_StampKeyAtHeadFilteredByTimeSelection( DmeTime_t tHeadPosition, DmeTime_t tPreviousHeadPosition, const DmeLog_TimeSelection_t &params, const T& value )
  3785. {
  3786. // Should be in "layer recording" mode!!!
  3787. Assert( GetNumLayers() >= 2 );
  3788. int nBestLayer = GetTopmostLayer(); // Topmost should be at least layer # 1 (0 is the base layer)
  3789. if ( nBestLayer < 1 )
  3790. return;
  3791. CDmeTypedLogLayer< T > *pWriteLayer = GetLayer( nBestLayer );
  3792. Assert( pWriteLayer );
  3793. if ( !pWriteLayer )
  3794. return;
  3795. // NOTE: This little trickery is necessary to generate samples right outside the
  3796. // transition region in the case of zero length falloff regions
  3797. DmeLog_TimeSelection_t tempParams = params;
  3798. if ( tempParams.m_nTimes[TS_LEFT_FALLOFF] == tempParams.m_nTimes[TS_LEFT_HOLD] )
  3799. {
  3800. tempParams.m_nTimes[TS_LEFT_FALLOFF] -= DMETIME_MINDELTA;
  3801. }
  3802. if ( tempParams.m_nTimes[TS_RIGHT_FALLOFF] == tempParams.m_nTimes[TS_RIGHT_HOLD] )
  3803. {
  3804. tempParams.m_nTimes[TS_RIGHT_FALLOFF] += DMETIME_MINDELTA;
  3805. }
  3806. int nPrevRegion = tempParams.ComputeRegionForTime( tPreviousHeadPosition );
  3807. int nCurrRegion = tempParams.ComputeRegionForTime( tHeadPosition );
  3808. // Test for backward performance!
  3809. if ( nCurrRegion < nPrevRegion )
  3810. {
  3811. V_swap( nCurrRegion, nPrevRegion );
  3812. }
  3813. // Insert samples at each transition point we skipped over
  3814. for ( int i = nPrevRegion; i < nCurrRegion; ++i )
  3815. {
  3816. _StampKeyFilteredByTimeSelection( pWriteLayer, tempParams.m_nTimes[i], params, value, true );
  3817. }
  3818. _StampKeyFilteredByTimeSelection( pWriteLayer, tHeadPosition, params, value );
  3819. }
  3820. template< class T >
  3821. void CDmeTypedLog< T >::RemoveKeys( DmeTime_t starttime )
  3822. {
  3823. int bestLayer = GetTopmostLayer();
  3824. if ( bestLayer < 0 )
  3825. return;
  3826. GetLayer( bestLayer )->RemoveKeys( starttime );
  3827. }
  3828. template< class T >
  3829. void CDmeTypedLog< T >::RemoveKey( int nKeyIndex, int nNumKeysToRemove /*= 1*/ )
  3830. {
  3831. int bestLayer = GetTopmostLayer();
  3832. if ( bestLayer < 0 )
  3833. return;
  3834. GetLayer( bestLayer )->RemoveKey( nKeyIndex, nNumKeysToRemove );
  3835. }
  3836. template< class T >
  3837. void CDmeTypedLog< T >::ClearKeys()
  3838. {
  3839. int bestLayer = GetTopmostLayer();
  3840. if ( bestLayer < 0 )
  3841. return;
  3842. GetLayer( bestLayer )->ClearKeys();
  3843. }
  3844. //-----------------------------------------------------------------------------
  3845. // Returns a specific key's value
  3846. //-----------------------------------------------------------------------------
  3847. template< class T >
  3848. DmeTime_t CDmeTypedLog< T >::GetKeyTime( int nKeyIndex ) const
  3849. {
  3850. int bestLayer = GetTopmostLayer();
  3851. if ( bestLayer < 0 )
  3852. return DmeTime_t::MinTime();
  3853. return GetLayer( bestLayer )->GetKeyTime( nKeyIndex );
  3854. }
  3855. template< class T >
  3856. void CDmeTypedLog< T >::SetKeyTime( int nKeyIndex, DmeTime_t keyTime )
  3857. {
  3858. int bestLayer = GetTopmostLayer();
  3859. if ( bestLayer < 0 )
  3860. return;
  3861. return GetLayer( bestLayer )->SetKeyTime( nKeyIndex, keyTime );
  3862. }
  3863. //-----------------------------------------------------------------------------
  3864. // Returns the index of a particular key
  3865. //-----------------------------------------------------------------------------
  3866. template< class T >
  3867. int CDmeTypedLog< T >::FindKeyWithinTolerance( DmeTime_t nTime, DmeTime_t nTolerance )
  3868. {
  3869. int bestLayer = GetTopmostLayer();
  3870. if ( bestLayer < 0 )
  3871. return -1;
  3872. return GetLayer( bestLayer )->FindKeyWithinTolerance( nTime, nTolerance );
  3873. }
  3874. //-----------------------------------------------------------------------------
  3875. // tests whether two values differ by more than the threshold
  3876. //-----------------------------------------------------------------------------
  3877. template<>
  3878. bool CDmeTypedLog< Vector >::ValuesDiffer( const Vector& a, const Vector& b ) const
  3879. {
  3880. return a.DistToSqr( b ) > m_threshold * m_threshold;
  3881. }
  3882. template<>
  3883. bool CDmeTypedLog< QAngle >::ValuesDiffer( const QAngle& a, const QAngle& b ) const
  3884. {
  3885. return ( a - b ).LengthSqr() > m_threshold * m_threshold;
  3886. }
  3887. template<>
  3888. bool CDmeTypedLog< Quaternion >::ValuesDiffer( const Quaternion& a, const Quaternion& b ) const
  3889. {
  3890. return QuaternionAngleDiff( a, b ) > m_threshold;
  3891. }
  3892. template<>
  3893. bool CDmeTypedLog< float >::ValuesDiffer( const float& a, const float& b ) const
  3894. {
  3895. return fabs( a - b ) > m_threshold;
  3896. }
  3897. template< class T >
  3898. bool CDmeTypedLog< T >::ValuesDiffer( const T& a, const T& b ) const
  3899. {
  3900. return a != b;
  3901. }
  3902. //-----------------------------------------------------------------------------
  3903. // Sets a key, removes all keys after this time
  3904. //-----------------------------------------------------------------------------
  3905. template< class T >
  3906. void CDmeTypedLog< T >::SetKey( DmeTime_t time, const T& value, int curveType /*=CURVE_DEFAULT*/)
  3907. {
  3908. int bestLayer = GetTopmostLayer();
  3909. if ( bestLayer < 0 )
  3910. return;
  3911. GetLayer( bestLayer )->SetKey( time, value, curveType );
  3912. }
  3913. template< class T >
  3914. CDmeTypedLogLayer< T > *CDmeTypedLog< T >::GetLayer( int index )
  3915. {
  3916. if ( index < 0 )
  3917. return NULL;
  3918. return static_cast< CDmeTypedLogLayer< T > * >( m_Layers[ index ] );
  3919. }
  3920. template< class T >
  3921. const CDmeTypedLogLayer< T > *CDmeTypedLog< T >::GetLayer( int index ) const
  3922. {
  3923. if ( index < 0 )
  3924. return NULL;
  3925. return static_cast< CDmeTypedLogLayer< T > * >( m_Layers[ index ] );
  3926. }
  3927. //-----------------------------------------------------------------------------
  3928. // Finds a key within tolerance, or adds one
  3929. //-----------------------------------------------------------------------------
  3930. template< class T >
  3931. int CDmeTypedLog< T >::FindOrAddKey( DmeTime_t nTime, DmeTime_t nTolerance, const T& value, int curveType /*=CURVE_DEFAULT*/ )
  3932. {
  3933. int bestLayer = GetTopmostLayer();
  3934. if ( bestLayer == -1 )
  3935. return -1;
  3936. return GetLayer( bestLayer )->FindOrAddKey( nTime, nTolerance, value, curveType );
  3937. }
  3938. //-----------------------------------------------------------------------------
  3939. // This inserts a key. Unlike SetKey, this will *not* delete keys after the specified time
  3940. //-----------------------------------------------------------------------------
  3941. template < class T >
  3942. int CDmeTypedLog< T >::InsertKey( DmeTime_t nTime, const T& value, int curveType /*=CURVE_DEFAULT*/ )
  3943. {
  3944. int bestLayer = GetTopmostLayer();
  3945. if ( bestLayer == -1 )
  3946. return -1;
  3947. return GetLayer( bestLayer )->InsertKey( nTime, value, curveType );
  3948. }
  3949. template < class T >
  3950. int CDmeTypedLog< T >::InsertKeyAtTime( DmeTime_t nTime, int curveType /*=CURVE_DEFAULT*/ )
  3951. {
  3952. int bestLayer = GetTopmostLayer();
  3953. if ( bestLayer == -1 )
  3954. return -1;
  3955. return GetLayer( bestLayer )->InsertKeyAtTime( nTime, curveType );
  3956. }
  3957. template< class T >
  3958. const T& CDmeTypedLog< T >::GetValue( DmeTime_t time ) const
  3959. {
  3960. int bestLayer = FindLayerForTime( time );
  3961. if ( bestLayer < 0 )
  3962. {
  3963. static T s_value;
  3964. CDmAttributeInfo< T >::SetDefaultValue( s_value ); // TODO - create GetDefaultValue that returns a default T, to avoid rebuilding every time
  3965. return s_value;
  3966. }
  3967. return GetLayer( bestLayer )->GetValue( time );
  3968. }
  3969. template< class T >
  3970. const T& CDmeTypedLog< T >::GetValueSkippingTopmostLayer( DmeTime_t time ) const
  3971. {
  3972. int nLayer = FindLayerForTimeSkippingTopmost( time );
  3973. if ( nLayer < 0 )
  3974. return GetValue( time );
  3975. return GetLayer( nLayer )->GetValue( time );
  3976. }
  3977. template< class T >
  3978. void CDmeTypedLog< T >::SetKey( DmeTime_t time, const CDmAttribute *pAttr, uint index, int curveType /*= CURVE_DEFAULT*/ )
  3979. {
  3980. int bestLayer = GetTopmostLayer();
  3981. if ( bestLayer == -1 )
  3982. return;
  3983. GetLayer( bestLayer )->SetKey( time, pAttr, index, curveType );
  3984. }
  3985. template< class T >
  3986. bool CDmeTypedLog< T >::SetDuplicateKeyAtTime( DmeTime_t time )
  3987. {
  3988. int bestLayer = GetTopmostLayer();
  3989. if ( bestLayer == -1 )
  3990. return false;
  3991. return GetLayer( bestLayer )->SetDuplicateKeyAtTime( time );
  3992. }
  3993. //-----------------------------------------------------------------------------
  3994. // Returns a specific key's value
  3995. //-----------------------------------------------------------------------------
  3996. template< class T >
  3997. const T& CDmeTypedLog< T >::GetKeyValue( int nKeyIndex ) const
  3998. {
  3999. int bestLayer = GetTopmostLayer();
  4000. if ( bestLayer == -1 )
  4001. {
  4002. static T s_value;
  4003. CDmAttributeInfo< T >::SetDefaultValue( s_value ); // TODO - create GetDefaultValue that returns a default T, to avoid rebuilding every time
  4004. return s_value;
  4005. }
  4006. return GetLayer( bestLayer )->GetKeyValue( nKeyIndex );
  4007. }
  4008. template< class T >
  4009. void CDmeTypedLog< T >::GetValue( DmeTime_t time, CDmAttribute *pAttr, uint index ) const
  4010. {
  4011. int bestLayer = FindLayerForTime( time );
  4012. if ( bestLayer < 0 )
  4013. {
  4014. T value;
  4015. CDmAttributeInfo< T >::SetDefaultValue( value ); // TODO - create GetDefaultValue that returns a default T, to avoid rebuilding every time
  4016. pAttr->SetValue( CDmAttributeInfo< T >::AttributeType(), &value );
  4017. }
  4018. return GetLayer( bestLayer )->GetValue( time, pAttr, index );
  4019. }
  4020. template< class T >
  4021. void CDmeTypedLog< T >::GetValueSkippingTopmostLayer( DmeTime_t time, CDmAttribute *pAttr, uint index = 0 ) const
  4022. {
  4023. CUtlVector< int > layers;
  4024. FindLayersForTime( time, layers );
  4025. int layerCount = layers.Count();
  4026. if ( layerCount <= 1 )
  4027. {
  4028. return GetValue( time, pAttr, index );
  4029. }
  4030. int topMostLayer = GetTopmostLayer();
  4031. int useLayer = layers[ layerCount - 1 ];
  4032. if ( topMostLayer == useLayer )
  4033. {
  4034. useLayer = layers[ layerCount - 2 ];
  4035. }
  4036. Assert( useLayer >= 0 );
  4037. return GetLayer( useLayer )->GetValue( time, pAttr, index );
  4038. }
  4039. template< class T >
  4040. float CDmeTypedLog< T >::GetComponent( DmeTime_t time, int componentIndex ) const
  4041. {
  4042. return ::GetComponent( GetValue( time ), componentIndex );
  4043. }
  4044. //-----------------------------------------------------------------------------
  4045. // resampling and filtering
  4046. //-----------------------------------------------------------------------------
  4047. template< class T >
  4048. void CDmeTypedLog< T >::Resample( DmeFramerate_t samplerate )
  4049. {
  4050. int c = m_Layers.Count();
  4051. for ( int i = 0; i < c; ++i )
  4052. {
  4053. GetLayer( i )->Resample( samplerate );
  4054. }
  4055. }
  4056. template< class T >
  4057. void CDmeTypedLog< T >::Filter( int nSampleRadius )
  4058. {
  4059. int c = m_Layers.Count();
  4060. for ( int i = 0; i < c; ++i )
  4061. {
  4062. GetLayer( i )->Filter( nSampleRadius );
  4063. }
  4064. }
  4065. template< class T >
  4066. void CDmeTypedLog< T >::Filter2( DmeTime_t sampleRadius )
  4067. {
  4068. int c = m_Layers.Count();
  4069. for ( int i = 0; i < c; ++i )
  4070. {
  4071. GetLayer( i )->Filter2( sampleRadius );
  4072. }
  4073. }
  4074. template< class T >
  4075. void CDmeTypedLog< T >::OnAttributeArrayElementAdded( CDmAttribute *pAttribute, int nFirstElem, int nLastElem )
  4076. {
  4077. BaseClass::OnAttributeArrayElementAdded( pAttribute, nFirstElem, nLastElem );
  4078. if ( pAttribute == m_Layers.GetAttribute() )
  4079. {
  4080. for ( int i = nFirstElem; i <= nLastElem; ++i )
  4081. {
  4082. m_Layers[i]->SetOwnerLog( this );
  4083. }
  4084. return;
  4085. }
  4086. }
  4087. template< class T >
  4088. void CDmeTypedLog< T >::SetUseEdgeInfo( bool state )
  4089. {
  4090. Assert( IsUsingCurveTypes() );
  4091. GetTypedCurveInfo()->SetUseEdgeInfo( state );
  4092. }
  4093. template< class T >
  4094. bool CDmeTypedLog< T >::IsUsingEdgeInfo() const
  4095. {
  4096. Assert( IsUsingCurveTypes() );
  4097. return GetTypedCurveInfo()->IsUsingEdgeInfo();
  4098. }
  4099. template< class T >
  4100. void CDmeTypedLog< T >::SetEdgeInfo( int edge, bool active, const T& val, int curveType )
  4101. {
  4102. Assert( IsUsingCurveTypes() );
  4103. GetTypedCurveInfo()->SetEdgeInfo( edge, active, val, curveType );
  4104. }
  4105. template< class T >
  4106. void CDmeTypedLog< T >::SetDefaultEdgeZeroValue( const T& val )
  4107. {
  4108. Assert( IsUsingCurveTypes() );
  4109. GetTypedCurveInfo()->SetDefaultEdgeZeroValue( val );
  4110. }
  4111. template< class T >
  4112. const T& CDmeTypedLog< T >::GetDefaultEdgeZeroValue() const
  4113. {
  4114. Assert( IsUsingCurveTypes() );
  4115. return GetTypedCurveInfo()->GetDefaultEdgeZeroValue();
  4116. }
  4117. template< class T >
  4118. void CDmeTypedLog< T >::SetRightEdgeTime( DmeTime_t time )
  4119. {
  4120. Assert( IsUsingCurveTypes() );
  4121. GetTypedCurveInfo()->SetRightEdgeTime( time );
  4122. }
  4123. template< class T >
  4124. DmeTime_t CDmeTypedLog< T >::GetRightEdgeTime() const
  4125. {
  4126. Assert( IsUsingCurveTypes() );
  4127. return GetTypedCurveInfo()->GetRightEdgeTime();
  4128. }
  4129. template< class T >
  4130. void CDmeTypedLog< T >::GetEdgeInfo( int edge, bool& active, T& val, int& curveType ) const
  4131. {
  4132. Assert( IsUsingCurveTypes() );
  4133. GetTypedCurveInfo()->GetEdgeInfo( edge, active, val, curveType );
  4134. }
  4135. template< class T >
  4136. int CDmeTypedLog< T >::GetEdgeCurveType( int edge ) const
  4137. {
  4138. Assert( IsUsingCurveTypes() );
  4139. return GetTypedCurveInfo()->GetEdgeCurveType( edge );
  4140. }
  4141. template< class T >
  4142. void CDmeTypedLog< T >::GetZeroValue( int side, T& val ) const
  4143. {
  4144. Assert( IsUsingCurveTypes() );
  4145. GetTypedCurveInfo()->GetZeroValue( side, val );
  4146. }
  4147. template< class T >
  4148. bool CDmeTypedLog< T >::IsEdgeActive( int edge ) const
  4149. {
  4150. Assert( IsUsingCurveTypes() );
  4151. return GetTypedCurveInfo()->IsEdgeActive( edge );
  4152. }
  4153. template< class T >
  4154. void CDmeTypedLog< T >::GetEdgeValue( int edge, T& val ) const
  4155. {
  4156. Assert( IsUsingCurveTypes() );
  4157. GetTypedCurveInfo()->GetEdgeValue( edge, val );
  4158. }
  4159. template< class T >
  4160. void CDmeTypedLog< T >::BlendTimesUsingTimeSelection( const CDmeLogLayer *firstLayer, const CDmeLogLayer *secondLayer, CDmeLogLayer *outputLayer, const DmeLog_TimeSelection_t &params, DmeTime_t tStartOffset )
  4161. {
  4162. const CDmeTypedLogLayer< T > *topLayer = static_cast< const CDmeTypedLogLayer< T > * >( secondLayer );
  4163. if ( !topLayer )
  4164. return;
  4165. const CDmeTypedLogLayer< T > *baseLayer = static_cast< const CDmeTypedLogLayer< T > * >( firstLayer );
  4166. if ( !baseLayer )
  4167. return;
  4168. CDmeTypedLogLayer< T > *newLayer = static_cast< CDmeTypedLogLayer< T > * >( outputLayer );
  4169. if ( !newLayer )
  4170. return;
  4171. Assert( topLayer->GetKeyCount() == baseLayer->GetKeyCount() );
  4172. int i;
  4173. // Resample everything in the base layer first
  4174. int kc = baseLayer->GetKeyCount();
  4175. newLayer->ClearKeys();
  4176. for ( i = 0; i < kc; ++i )
  4177. {
  4178. DmeTime_t baseKeyTime = baseLayer->GetKeyTime( i );
  4179. DmeTime_t checkTime = baseKeyTime + tStartOffset;
  4180. if ( checkTime < params.m_nTimes[ TS_LEFT_FALLOFF ] )
  4181. continue;
  4182. if ( checkTime > params.m_nTimes[ TS_RIGHT_FALLOFF ] )
  4183. break;
  4184. float frac = params.GetAmountForTime( checkTime );
  4185. float frac2 = params.m_flIntensity;
  4186. float flInterp = frac2 * frac;
  4187. DmeTime_t targetKeyTime = topLayer->GetKeyTime( i );
  4188. DmeTime_t blendedKeyTime = Lerp( flInterp, baseKeyTime, targetKeyTime ) + tStartOffset;
  4189. T baseVal = baseLayer->GetKeyValue( i );
  4190. newLayer->InsertKey( blendedKeyTime, baseVal );
  4191. }
  4192. }
  4193. template< class T >
  4194. void CDmeTypedLog< T >::BlendLayersUsingTimeSelection( const CDmeLogLayer *firstLayer, const CDmeLogLayer *secondLayer, CDmeLogLayer *outputLayer, const DmeLog_TimeSelection_t &params, bool bUseBaseLayerSamples, DmeTime_t tStartOffset )
  4195. {
  4196. const CDmeTypedLogLayer< T > *topLayer = static_cast< const CDmeTypedLogLayer< T > * >( secondLayer );
  4197. if ( !topLayer )
  4198. return;
  4199. const CDmeTypedLogLayer< T > *baseLayer = static_cast< const CDmeTypedLogLayer< T > * >( firstLayer );
  4200. if ( !baseLayer )
  4201. return;
  4202. CDmeTypedLogLayer< T > *newLayer = static_cast< CDmeTypedLogLayer< T > * >( outputLayer );
  4203. if ( !newLayer )
  4204. return;
  4205. int i;
  4206. // Resample everything in the base layer first
  4207. int kc = baseLayer->GetKeyCount();
  4208. if ( bUseBaseLayerSamples )
  4209. {
  4210. for ( i = 0; i < kc; ++i )
  4211. {
  4212. DmeTime_t keyTime = baseLayer->GetKeyTime( i );
  4213. if ( keyTime < params.m_nTimes[ TS_LEFT_FALLOFF ] )
  4214. continue;
  4215. if ( keyTime > params.m_nTimes[ TS_RIGHT_FALLOFF ] )
  4216. break;
  4217. float frac = params.GetAmountForTime( keyTime );
  4218. float frac2 = params.m_flIntensity;
  4219. T baseVal = baseLayer->GetKeyValue( i );
  4220. T newVal = topLayer->GetValue( keyTime );
  4221. T blended = Interpolate( frac2 * frac, baseVal, newVal );
  4222. newLayer->SetKey( keyTime + tStartOffset, blended );
  4223. }
  4224. }
  4225. kc = topLayer->GetKeyCount();
  4226. for ( i = 0; i < kc; ++i )
  4227. {
  4228. DmeTime_t keyTime = topLayer->GetKeyTime( i );
  4229. DmeTime_t finalKeyTime = keyTime + tStartOffset;
  4230. if ( finalKeyTime < params.m_nTimes[ TS_LEFT_FALLOFF ] )
  4231. continue;
  4232. if ( finalKeyTime > params.m_nTimes[ TS_RIGHT_FALLOFF ] )
  4233. break;
  4234. float frac = params.GetAmountForTime( finalKeyTime );
  4235. float frac2 = params.m_flIntensity;
  4236. T baseVal = baseLayer->GetValue( keyTime );
  4237. T newVal = topLayer->GetKeyValue( i );
  4238. T blended = Interpolate( frac2 *frac, baseVal, newVal );
  4239. newLayer->InsertKey( finalKeyTime, blended );
  4240. }
  4241. if ( g_pDmElementFramework->GetPhase() == PH_EDIT )
  4242. {
  4243. newLayer->RemoveRedundantKeys( params.m_flThreshold );
  4244. }
  4245. }
  4246. template< class T >
  4247. void CDmeTypedLog< T >::BlendLayersUsingTimeSelection( const DmeLog_TimeSelection_t &params )
  4248. {
  4249. Assert( GetNumLayers() >= 2 );
  4250. int bestLayer = GetTopmostLayer(); // Topmost should be at least layer # 1 (0 is the base layer)
  4251. if ( bestLayer <= 0 )
  4252. return;
  4253. Assert( params.m_nResampleInterval > DmeTime_t( 0 ) );
  4254. if ( params.m_nResampleInterval < DmeTime_t( 0 ) )
  4255. return;
  4256. CDmeTypedLogLayer< T > *topLayer = GetLayer( bestLayer );
  4257. Assert( topLayer );
  4258. if ( !topLayer )
  4259. return;
  4260. CDmeTypedLogLayer< T > *baseLayer = GetLayer( 0 );
  4261. if ( !baseLayer )
  4262. return;
  4263. CDmeTypedLogLayer< T > *newLayer = static_cast< CDmeTypedLogLayer< T > * >( CreateLayer< T >( this ) );
  4264. if ( !newLayer )
  4265. return;
  4266. BlendLayersUsingTimeSelection( baseLayer, topLayer, newLayer, params, true, DMETIME_ZERO );
  4267. // Store it back into the new topmost layer
  4268. topLayer->CopyLayer( newLayer );
  4269. g_pDataModel->DestroyElement( newLayer->GetHandle() );
  4270. }
  4271. template< class T >
  4272. void CDmeTypedLog< T >::RevealUsingTimeSelection( const DmeLog_TimeSelection_t &params, CDmeLogLayer *savedLayer )
  4273. {
  4274. CDmeTypedLogLayer< T > *saved = static_cast< CDmeTypedLogLayer< T > * >( savedLayer );
  4275. if ( !saved )
  4276. return;
  4277. Assert( GetNumLayers() >= 2 );
  4278. int bestLayer = GetTopmostLayer(); // Topmost should be at least layer # 1 (0 is the base layer)
  4279. if ( bestLayer <= 0 )
  4280. return;
  4281. Assert( params.m_nResampleInterval > DmeTime_t( 0 ) );
  4282. if ( params.m_nResampleInterval < DmeTime_t( 0 ) )
  4283. return;
  4284. CDmeTypedLogLayer< T > *writeLayer = static_cast< CDmeTypedLogLayer< T > * >( GetLayer( bestLayer ) );
  4285. Assert( writeLayer );
  4286. if ( !writeLayer )
  4287. return;
  4288. CDmeLogLayer *baseLayer = GetLayer( 0 );
  4289. if ( !baseLayer )
  4290. return;
  4291. DmeTime_t resample = 0.5f * params.m_nResampleInterval;
  4292. // Do a second pass where we bis the keys in the falloff area back toward the original value
  4293. for ( int t = params.m_nTimes[ TS_LEFT_FALLOFF ].GetTenthsOfMS(); t < params.m_nTimes[ TS_RIGHT_FALLOFF ].GetTenthsOfMS() + resample.GetTenthsOfMS(); t += resample.GetTenthsOfMS() )
  4294. {
  4295. DmeTime_t curtime = DmeTime_t( t );
  4296. if ( curtime > params.m_nTimes[ TS_RIGHT_FALLOFF ] )
  4297. curtime = params.m_nTimes[ TS_RIGHT_FALLOFF ];
  4298. float frac = params.GetAmountForTime( curtime );
  4299. frac *= params.m_flIntensity;
  4300. if ( frac <= 0.0f )
  4301. continue;
  4302. // Get current value in layer
  4303. T curValue = GetValueSkippingTopmostLayer( curtime );
  4304. T revealValue = saved->GetValue( curtime );
  4305. T newValue = Interpolate( frac, curValue, revealValue );
  4306. // Overwrite key
  4307. writeLayer->InsertKey( curtime, newValue, IsUsingCurveTypes() ? GetDefaultCurveType() : CURVE_DEFAULT );
  4308. }
  4309. if ( g_pDmElementFramework->GetPhase() == PH_EDIT )
  4310. {
  4311. writeLayer->RemoveRedundantKeys( params.m_flThreshold );
  4312. }
  4313. }
  4314. template< class T >
  4315. void RandomValue( const T& average, const T& oldValue, T& newValue )
  4316. {
  4317. newValue = oldValue;
  4318. }
  4319. template<> void RandomValue( const Vector& average, const Vector& oldValue, Vector& newValue )
  4320. {
  4321. newValue = oldValue;
  4322. for ( int i = 0; i < 3; ++i )
  4323. {
  4324. newValue[ i ] += RandomFloat( -fabs( average[ i ] ), fabs( average[ i ] ) );
  4325. }
  4326. }
  4327. template<> void RandomValue( const Quaternion& average, const Quaternion& oldValue, Quaternion& newValue )
  4328. {
  4329. newValue = oldValue;
  4330. for ( int i = 0; i < 4; ++i )
  4331. {
  4332. newValue[ i ] += RandomFloat( -fabs( average[ i ] ), fabs( average[ i ] ) );
  4333. }
  4334. }
  4335. template<> void RandomValue( const Vector4D& average, const Vector4D& oldValue, Vector4D& newValue )
  4336. {
  4337. newValue = oldValue;
  4338. for ( int i = 0; i < 4; ++i )
  4339. {
  4340. newValue[ i ] += RandomFloat( -fabs( average[ i ] ), fabs( average[ i ] ) );
  4341. }
  4342. }
  4343. template<> void RandomValue( const Vector2D& average, const Vector2D& oldValue, Vector2D& newValue )
  4344. {
  4345. newValue = oldValue;
  4346. for ( int i = 0; i < 2; ++i )
  4347. {
  4348. newValue[ i ] += RandomFloat( -fabs( average[ i ] ), fabs( average[ i ] ) );
  4349. }
  4350. }
  4351. template<> void RandomValue( const float& average, const float& oldValue, float& newValue )
  4352. {
  4353. newValue = oldValue + RandomFloat( -average, average );
  4354. }
  4355. template<> void RandomValue( const int& average, const int& oldValue, int& newValue )
  4356. {
  4357. newValue = oldValue + RandomInt( -average, average );
  4358. }
  4359. // Builds a layer with samples matching the times in reference layer, from the data in pDataLayer, putting the resulting keys into pOutputLayer
  4360. template< class T >
  4361. void CDmeTypedLog< T >::BuildCorrespondingLayer( const CDmeLogLayer *pReferenceLayer, const CDmeLogLayer *pDataLayer, CDmeLogLayer *pOutputLayer )
  4362. {
  4363. const CDmeTypedLogLayer< T > *ref = static_cast< const CDmeTypedLogLayer< T > * >( pReferenceLayer );
  4364. const CDmeTypedLogLayer< T > *data = static_cast< const CDmeTypedLogLayer< T > * >( pDataLayer );
  4365. CDmeTypedLogLayer< T > *out = static_cast< CDmeTypedLogLayer< T > * >( pOutputLayer );
  4366. if ( !ref || !data || !out )
  4367. {
  4368. Assert( 0 );
  4369. return;
  4370. }
  4371. bool usecurvetypes = ref->IsUsingCurveTypes();
  4372. out->ClearKeys();
  4373. int kc = ref->GetKeyCount();
  4374. for ( int i = 0; i < kc; ++i )
  4375. {
  4376. DmeTime_t keyTime = ref->GetKeyTime( i );
  4377. T value = data->GetValue( keyTime );
  4378. out->InsertKey( keyTime, value, usecurvetypes ? GetDefaultCurveType() : CURVE_DEFAULT );
  4379. }
  4380. }
  4381. template< class T >
  4382. void CDmeTypedLog< T >::StaggerUsingTimeSelection( const DmeLog_TimeSelection_t& params, DmeTime_t tStaggerAmount, const CDmeLogLayer *pBaseLayer, CDmeLogLayer *pWriteLayer )
  4383. {
  4384. CDmeTypedLogLayer< T > *writeLayer = static_cast< CDmeTypedLogLayer< T > * >( pWriteLayer );
  4385. Assert( writeLayer );
  4386. if ( !writeLayer )
  4387. return;
  4388. const CDmeTypedLogLayer< T > *baseLayer = static_cast< const CDmeTypedLogLayer< T > * >( pBaseLayer );
  4389. if ( !baseLayer )
  4390. return;
  4391. writeLayer->ClearKeys();
  4392. DmeLog_TimeSelection_t newParams;
  4393. newParams = params;
  4394. // Move the hold area by the stagger amount
  4395. float flScaleFactor[ 2 ] = { 1.0f, 1.0f };
  4396. newParams.m_nTimes[ TS_LEFT_HOLD ] += tStaggerAmount;
  4397. newParams.m_nTimes[ TS_RIGHT_HOLD ] += tStaggerAmount;
  4398. for ( int i = 0; i < 2 ; ++i )
  4399. {
  4400. DmeTime_t dt = params.m_nTimes[ 2 * i + 1 ] - params.m_nTimes[ 2 * i ];
  4401. if ( dt > DMETIME_ZERO )
  4402. {
  4403. DmeTime_t newDt = newParams.m_nTimes[ 2 * i + 1 ] - newParams.m_nTimes[ 2 * i ];
  4404. flScaleFactor[ i ] = newDt / dt;
  4405. }
  4406. }
  4407. int kc = baseLayer->GetKeyCount();
  4408. for ( int i = 0; i < kc; ++i )
  4409. {
  4410. DmeTime_t curtime = baseLayer->GetKeyTime( i );
  4411. T oldValue = baseLayer->GetKeyValue( i );
  4412. // Classify time
  4413. if ( curtime <= params.m_nTimes[ TS_LEFT_HOLD ] )
  4414. {
  4415. curtime = curtime * flScaleFactor[ 0 ];
  4416. }
  4417. else if ( curtime >= params.m_nTimes[ TS_RIGHT_HOLD ] )
  4418. {
  4419. curtime = params.m_nTimes[ TS_RIGHT_FALLOFF ] - ( params.m_nTimes[ TS_RIGHT_FALLOFF ] - curtime ) * flScaleFactor[ 1 ];
  4420. }
  4421. else
  4422. {
  4423. curtime += tStaggerAmount;
  4424. }
  4425. writeLayer->InsertKey( curtime, oldValue, IsUsingCurveTypes() ? GetDefaultCurveType() : CURVE_DEFAULT );
  4426. }
  4427. }
  4428. template< class T >
  4429. void CDmeTypedLog< T >::FilterUsingTimeSelection( IUniformRandomStream *random, const DmeLog_TimeSelection_t& params, int filterType, bool bResample, bool bApplyFalloff )
  4430. {
  4431. Assert( GetNumLayers() >= 2 );
  4432. int bestLayer = GetTopmostLayer(); // Topmost should be at least layer # 1 (0 is the base layer)
  4433. if ( bestLayer <= 0 )
  4434. return;
  4435. CDmeTypedLogLayer< T > *writeLayer = GetLayer( bestLayer );
  4436. Assert( writeLayer );
  4437. if ( !writeLayer )
  4438. return;
  4439. CDmeTypedLogLayer< T > *baseLayer = GetLayer( 0 );
  4440. if ( !baseLayer )
  4441. return;
  4442. FilterUsingTimeSelection( random, 1.0f, params, filterType, bResample, bApplyFalloff, baseLayer, writeLayer );
  4443. }
  4444. template< class T >
  4445. void CDmeTypedLog< T >::FilterUsingTimeSelection( IUniformRandomStream *random, float flScale, const DmeLog_TimeSelection_t& params, int filterType, bool bResample, bool bApplyFalloff, const CDmeLogLayer *pBaseLayer, CDmeLogLayer *pWriteLayer )
  4446. {
  4447. Assert( params.m_nResampleInterval > DmeTime_t( 0 ) );
  4448. if ( params.m_nResampleInterval < DmeTime_t( 0 ) )
  4449. return;
  4450. CDmeTypedLogLayer< T > *writeLayer = static_cast< CDmeTypedLogLayer< T > * >( pWriteLayer );
  4451. Assert( writeLayer );
  4452. if ( !writeLayer )
  4453. return;
  4454. const CDmeTypedLogLayer< T > *baseLayer = static_cast< const CDmeTypedLogLayer< T > * >( pBaseLayer );
  4455. if ( !baseLayer )
  4456. return;
  4457. writeLayer->ClearKeys();
  4458. DmeTime_t resample = 0.5f * params.m_nResampleInterval;
  4459. switch ( filterType )
  4460. {
  4461. default:
  4462. case FILTER_SMOOTH:
  4463. {
  4464. int t;
  4465. if ( bResample )
  4466. {
  4467. for ( t = params.m_nTimes[ TS_LEFT_FALLOFF ].GetTenthsOfMS(); t < params.m_nTimes[ TS_RIGHT_FALLOFF ].GetTenthsOfMS() + resample.GetTenthsOfMS(); t += resample.GetTenthsOfMS() )
  4468. {
  4469. DmeTime_t curtime = DmeTime_t( t );
  4470. if ( curtime > params.m_nTimes[ TS_RIGHT_FALLOFF ] )
  4471. curtime = params.m_nTimes[ TS_RIGHT_FALLOFF ];
  4472. T curValue = baseLayer->GetValue( curtime );
  4473. writeLayer->SetKey( curtime, curValue, IsUsingCurveTypes() ? GetDefaultCurveType() : CURVE_DEFAULT );
  4474. }
  4475. }
  4476. else
  4477. {
  4478. // Do a second pass where we bias the keys in the falloff area back toward the original value
  4479. int kc = baseLayer->GetKeyCount();
  4480. for ( int i = 0; i < kc; ++i )
  4481. {
  4482. DmeTime_t curtime = baseLayer->GetKeyTime( i );
  4483. if ( curtime < params.m_nTimes[ TS_LEFT_FALLOFF ] )
  4484. continue;
  4485. if ( curtime > params.m_nTimes[ TS_RIGHT_FALLOFF ] )
  4486. continue;
  4487. T oldValue = baseLayer->GetKeyValue( i );
  4488. writeLayer->InsertKey( curtime, oldValue, IsUsingCurveTypes() ? GetDefaultCurveType() : CURVE_DEFAULT );
  4489. }
  4490. }
  4491. writeLayer->Filter2( params.m_nResampleInterval * 0.95f * flScale );
  4492. if ( bApplyFalloff )
  4493. {
  4494. if ( bResample )
  4495. {
  4496. // Do a second pass where we bias the keys in the falloff area back toward the original value
  4497. for ( t = params.m_nTimes[ TS_LEFT_FALLOFF ].GetTenthsOfMS(); t < params.m_nTimes[ TS_RIGHT_FALLOFF ].GetTenthsOfMS() + resample.GetTenthsOfMS(); t += resample.GetTenthsOfMS() )
  4498. {
  4499. DmeTime_t curtime = DmeTime_t( t );
  4500. if ( curtime > params.m_nTimes[ TS_RIGHT_FALLOFF ] )
  4501. curtime = params.m_nTimes[ TS_RIGHT_FALLOFF ];
  4502. T oldValue = baseLayer->GetValue( curtime );
  4503. if ( curtime >= params.m_nTimes[ TS_LEFT_HOLD ] && curtime <= params.m_nTimes[ TS_RIGHT_HOLD ] )
  4504. continue;
  4505. // Modulate these keys back down toward the original value
  4506. T newValue = writeLayer->GetValue( curtime );
  4507. float frac = bApplyFalloff ? params.GetAmountForTime( curtime ) : 1.0f;
  4508. newValue = Interpolate( frac, oldValue, newValue );
  4509. // Overwrite key
  4510. writeLayer->InsertKey( curtime, newValue, IsUsingCurveTypes() ? GetDefaultCurveType() : CURVE_DEFAULT );
  4511. }
  4512. }
  4513. else
  4514. {
  4515. // Do a second pass where we bias the keys in the falloff area back toward the original value
  4516. int kc = writeLayer->GetKeyCount();
  4517. for ( int i = 0; i < kc; ++i )
  4518. {
  4519. DmeTime_t curtime = writeLayer->GetKeyTime( i );
  4520. if ( curtime < params.m_nTimes[ TS_LEFT_FALLOFF ] )
  4521. continue;
  4522. if ( curtime > params.m_nTimes[ TS_RIGHT_FALLOFF ] )
  4523. continue;
  4524. if ( curtime >= params.m_nTimes[ TS_LEFT_HOLD ] && curtime <= params.m_nTimes[ TS_RIGHT_HOLD ] )
  4525. continue;
  4526. T oldValue = baseLayer->GetValue( curtime );
  4527. // Modulate these keys back down toward the original value
  4528. T newValue = writeLayer->GetValue( curtime );
  4529. float frac = bApplyFalloff ? params.GetAmountForTime( curtime ) : 1.0f;
  4530. newValue = Interpolate( frac, oldValue, newValue );
  4531. // Overwrite key
  4532. writeLayer->InsertKey( curtime, newValue, IsUsingCurveTypes() ? GetDefaultCurveType() : CURVE_DEFAULT );
  4533. }
  4534. }
  4535. }
  4536. if ( bResample )
  4537. {
  4538. writeLayer->RemoveRedundantKeys( params.m_flThreshold );
  4539. }
  4540. }
  4541. break;
  4542. case FILTER_JITTER:
  4543. {
  4544. // Compute average value in entire log
  4545. T average = Average( baseLayer->m_values.Base(), baseLayer->m_values.Count() );
  4546. average = ScaleValue( average, 0.05f * flScale );
  4547. if ( bResample )
  4548. {
  4549. int t;
  4550. for ( t = params.m_nTimes[ TS_LEFT_FALLOFF ].GetTenthsOfMS(); t < params.m_nTimes[ TS_RIGHT_FALLOFF ].GetTenthsOfMS() + resample.GetTenthsOfMS(); t += resample.GetTenthsOfMS() )
  4551. {
  4552. DmeTime_t curtime = DmeTime_t( t );
  4553. if ( curtime > params.m_nTimes[ TS_RIGHT_FALLOFF ] )
  4554. curtime = params.m_nTimes[ TS_RIGHT_FALLOFF ];
  4555. float frac = bApplyFalloff ? params.GetAmountForTime( curtime ) : 1.0f;
  4556. T oldValue = baseLayer->GetValue( curtime );
  4557. T newValue;
  4558. RandomValue( average, oldValue, newValue );
  4559. newValue = Interpolate( frac, oldValue, newValue );
  4560. writeLayer->SetKey( curtime, newValue, IsUsingCurveTypes() ? GetDefaultCurveType() : CURVE_DEFAULT );
  4561. }
  4562. }
  4563. else
  4564. {
  4565. int kc = baseLayer->GetKeyCount();
  4566. for ( int i = 0; i < kc; ++i )
  4567. {
  4568. DmeTime_t curtime = baseLayer->GetKeyTime( i );
  4569. if ( curtime < params.m_nTimes[ TS_LEFT_FALLOFF ] )
  4570. continue;
  4571. if ( curtime > params.m_nTimes[ TS_RIGHT_FALLOFF ] )
  4572. continue;
  4573. float frac = bApplyFalloff ? params.GetAmountForTime( curtime ) : 1.0f;
  4574. T oldValue = baseLayer->GetValue( curtime );
  4575. T newValue;
  4576. RandomValue( average, oldValue, newValue );
  4577. newValue = Interpolate( frac, oldValue, newValue );
  4578. writeLayer->InsertKey( curtime, newValue, IsUsingCurveTypes() ? GetDefaultCurveType() : CURVE_DEFAULT );
  4579. }
  4580. }
  4581. }
  4582. break;
  4583. case FILTER_SHARPEN:
  4584. case FILTER_SOFTEN:
  4585. {
  4586. writeLayer->ClearKeys();
  4587. bool bSharpen = filterType == FILTER_SHARPEN;
  4588. int kc = baseLayer->GetKeyCount();
  4589. for ( int i = 0; i < kc; ++i )
  4590. {
  4591. DmeTime_t curtime = baseLayer->GetKeyTime( i );
  4592. if ( curtime < params.m_nTimes[ TS_LEFT_FALLOFF ] )
  4593. continue;
  4594. if ( curtime > params.m_nTimes[ TS_RIGHT_FALLOFF ] )
  4595. continue;
  4596. float frac = bApplyFalloff ? params.GetAmountForTime( curtime ) : 1.0f;
  4597. T oldValue = baseLayer->GetValue( curtime );
  4598. T newValue = oldValue;
  4599. if ( frac != 1.0f )
  4600. {
  4601. T crossingValue[ 2 ] = { oldValue, oldValue };
  4602. if ( curtime <= params.m_nTimes[ TS_LEFT_HOLD ] )
  4603. {
  4604. // Get the value at the crossing point (either green edge for sharpen, or left edge for soften...)
  4605. crossingValue[ 0 ] = baseLayer->GetValue( params.m_nTimes[ TS_LEFT_FALLOFF ] );
  4606. crossingValue[ 1 ] = baseLayer->GetValue( params.m_nTimes[ TS_LEFT_HOLD ] );
  4607. }
  4608. else if ( curtime >= params.m_nTimes[ TS_RIGHT_HOLD ] )
  4609. {
  4610. crossingValue[ 0 ] = baseLayer->GetValue( params.m_nTimes[ TS_RIGHT_FALLOFF ] );
  4611. crossingValue[ 1 ] = baseLayer->GetValue( params.m_nTimes[ TS_RIGHT_HOLD ] );
  4612. }
  4613. else
  4614. {
  4615. Assert( 0 );
  4616. }
  4617. T dynamicRange = Subtract( crossingValue[ 1 ], crossingValue[ 0 ] );
  4618. int iType = bSharpen ? INTERPOLATE_EASE_IN : INTERPOLATE_EASE_OUT;
  4619. Vector points[ 4 ];
  4620. points[ 0 ].Init();
  4621. points[ 1 ].Init( 0.0, 0.0, 0.0f );
  4622. points[ 2 ].Init( 1.0f, 1.0f, 0.0f );
  4623. points[ 3 ].Init();
  4624. Vector out;
  4625. Interpolator_CurveInterpolate
  4626. (
  4627. iType,
  4628. points[ 0 ], // unused
  4629. points[ 1 ],
  4630. points[ 2 ],
  4631. points[ 3 ], // unused
  4632. frac,
  4633. out
  4634. );
  4635. float flBias = clamp( out.y, 0.0f, 1.0f );
  4636. float dFrac = flScale * ( frac - flBias );
  4637. newValue = Add( oldValue, ScaleValue( dynamicRange, dFrac ) );
  4638. }
  4639. writeLayer->InsertKey( curtime, newValue, IsUsingCurveTypes() ? GetDefaultCurveType() : CURVE_DEFAULT );
  4640. }
  4641. }
  4642. break;
  4643. }
  4644. }
  4645. enum PasteState_t
  4646. {
  4647. PASTE_STATE_BEFORE = -1,
  4648. PASTE_STATE_RAMP_IN = 0,
  4649. PASTE_STATE_HOLD,
  4650. PASTE_STATE_RAMP_OUT,
  4651. PASTE_STATE_COUNT,
  4652. PASTE_STATE_AFTER = PASTE_STATE_COUNT,
  4653. };
  4654. template<class T >
  4655. static void CountClipboardSamples( int *pCount, CDmeTypedLogLayer< T > *pClipboard, const DmeLog_TimeSelection_t &params )
  4656. {
  4657. pCount[0] = pCount[1] = pCount[2] = 0;
  4658. int nKeyCount = pClipboard->GetKeyCount();
  4659. for ( int i = 0; i < nKeyCount; ++i )
  4660. {
  4661. DmeTime_t tKeyTime = pClipboard->GetKeyTime( i );
  4662. int nIndex = params.ComputeRegionForTime( tKeyTime ) - 1;
  4663. if ( nIndex < 0 || nIndex > 2 )
  4664. continue;
  4665. // Only count interstitial samples.. don't count ones that land exactly on boundaries
  4666. if ( tKeyTime != params.m_nTimes[nIndex] && tKeyTime != params.m_nTimes[nIndex+1] )
  4667. {
  4668. pCount[nIndex]++;
  4669. }
  4670. }
  4671. }
  4672. //-----------------------------------------------------------------------------
  4673. // Used by PasteAndRescaleSamples to determine if it should skip a transition or not
  4674. //-----------------------------------------------------------------------------
  4675. static inline bool ShouldSkipTransition( int nTransition, int nZeroField )
  4676. {
  4677. // NOTE: This is pretty tricky. The bits of the 'zero field' are set to true
  4678. // for each region whose source + dest region size is exactly 0 seconds.
  4679. // Here's the table this logic is reproducing:
  4680. // 0,1,2,3 are the time selection m_nTimes, and A,B,C are the regions
  4681. // 0 1 2 3
  4682. // | A | B | C |
  4683. //
  4684. // nZeroField bits
  4685. // C B A Skip transitions
  4686. // 0 0 0 none
  4687. // 0 0 1 2
  4688. // 0 1 0 2
  4689. // 0 1 1 1, 2
  4690. // 1 0 0 1
  4691. // 1 0 1 1, 2
  4692. // 1 1 0 1, 2
  4693. // 1 1 1 1, 2, 3
  4694. switch( nTransition )
  4695. {
  4696. default: case 0: return false;
  4697. case 1: return ( (( nZeroField & 0x1 ) != 0 ) || nZeroField >= 5 );
  4698. case 2: return ( nZeroField >= 2 );
  4699. case 3: return ( nZeroField == 7 );
  4700. }
  4701. }
  4702. template< class T >
  4703. void CDmeTypedLog< T >::PasteAndRescaleSamples(
  4704. const CDmeLogLayer *pBase,
  4705. const CDmeLogLayer *pDataLayer,
  4706. CDmeLogLayer *pOutputLayer,
  4707. const DmeLog_TimeSelection_t& srcParams,
  4708. const DmeLog_TimeSelection_t& destParams,
  4709. bool bBlendAreaInFalloffRegion )
  4710. {
  4711. Assert( GetNumLayers() >= 2 );
  4712. if ( GetNumLayers() < 2 )
  4713. return;
  4714. CDmeTypedLogLayer< T > *pClipboard = CastElement< CDmeTypedLogLayer< T > >( const_cast< CDmeLogLayer * >( pDataLayer ) );
  4715. // Could have passed in layer with wrong attribute type?!
  4716. Assert( pClipboard );
  4717. if ( !pClipboard )
  4718. return;
  4719. CDmeTypedLogLayer< T > *pBaseLayer = CastElement< CDmeTypedLogLayer< T > >( const_cast< CDmeLogLayer * >( pBase ) );
  4720. CDmeTypedLogLayer< T > *pWriteLayer = CastElement< CDmeTypedLogLayer< T > >( pOutputLayer );
  4721. Assert( pBaseLayer );
  4722. Assert( pWriteLayer );
  4723. // NOTE: Array index 0 is src (pClipboard), index 1 is dest (pWriteLayer)
  4724. DmeTime_t tStartTime[ PASTE_STATE_COUNT+1 ][ 2 ] =
  4725. {
  4726. { DmeTime_t( srcParams.m_nTimes[ 0 ] ), DmeTime_t( destParams.m_nTimes[ 0 ] ) },
  4727. { DmeTime_t( srcParams.m_nTimes[ 1 ] ), DmeTime_t( destParams.m_nTimes[ 1 ] ) },
  4728. { DmeTime_t( srcParams.m_nTimes[ 2 ] ), DmeTime_t( destParams.m_nTimes[ 2 ] ) },
  4729. { DmeTime_t( srcParams.m_nTimes[ 3 ] ), DmeTime_t( destParams.m_nTimes[ 3 ] ) },
  4730. };
  4731. // compute rescaling factors
  4732. int pDuration[ PASTE_STATE_COUNT ][ 2 ];
  4733. double pScaleFactor[ PASTE_STATE_COUNT ];
  4734. int nZeroField = 0;
  4735. for ( int i = 0; i < PASTE_STATE_COUNT; ++i )
  4736. {
  4737. for ( int s = 0; s < 2; ++s )
  4738. {
  4739. pDuration[ i ][ s ] = tStartTime[ i+1 ][ s ].GetTenthsOfMS() - tStartTime[ i ][ s ].GetTenthsOfMS();
  4740. }
  4741. // We're building up a bitfield to find which regions have src + dest durations of 0
  4742. // for use in determining which regions to completely skip processing
  4743. if ( pDuration[i][0] == 0 && pDuration[i][1] == 0 )
  4744. {
  4745. nZeroField |= ( 1 << i );
  4746. }
  4747. pScaleFactor[i] = 1.0;
  4748. if ( pDuration[ i ][ 0 ] > 0 )
  4749. {
  4750. pScaleFactor[i] = 1.0 / ( double )pDuration[ i ][ 0 ];
  4751. }
  4752. }
  4753. // Compute values used to paste into selection state transitions
  4754. T pStartValue[ PASTE_STATE_COUNT + 1 ] =
  4755. {
  4756. bBlendAreaInFalloffRegion ? pBaseLayer->GetValue( tStartTime[ PASTE_STATE_RAMP_IN ][ 1 ] ) : pClipboard->GetValue( tStartTime[ PASTE_STATE_RAMP_IN ][ 0 ] ),
  4757. pClipboard->GetValue( tStartTime[ PASTE_STATE_HOLD ][ 0 ] ),
  4758. pClipboard->GetValue( tStartTime[ PASTE_STATE_RAMP_OUT ][ 0 ] ),
  4759. bBlendAreaInFalloffRegion ? pBaseLayer->GetValue( tStartTime[ PASTE_STATE_AFTER ][ 1 ] ) : pClipboard->GetValue( tStartTime[ PASTE_STATE_AFTER ][ 0 ] )
  4760. };
  4761. // Compute state necessary to blend in the ramp in + ramp out regions
  4762. // NOTE: These computations are only used if bBlendAreaInFalloffRegion is true
  4763. T pBlendBase[ 2 ];
  4764. float pOOBlendLength[ 2 ];
  4765. DmeTime_t pBlendTime[ 2 ];
  4766. for ( int s = 0; s < 2; ++s )
  4767. {
  4768. pBlendTime[ s ] = destParams.m_nTimes[ TS_FALLOFF(s) ];
  4769. pBlendBase[ s ] = pBaseLayer->GetValue( pBlendTime[ s ] );
  4770. T holdValue = pBaseLayer->GetValue( destParams.m_nTimes[ TS_HOLD(s) ] );
  4771. Vector2D vec;
  4772. vec.x = destParams.m_nTimes[ TS_HOLD(s) ].GetSeconds() - pBlendTime[ s ].GetSeconds();
  4773. vec.y = LengthOf( Subtract( holdValue, pBlendBase[ s ] ) );
  4774. pOOBlendLength[ s ] = vec.Length();
  4775. if ( pOOBlendLength[ s ] != 0.0f )
  4776. {
  4777. pOOBlendLength[ s ] = 1.0f / pOOBlendLength[ s ];
  4778. }
  4779. }
  4780. // Count the number of samples on the clipboard in the various regions
  4781. int pKeyCount[PASTE_STATE_COUNT];
  4782. CountClipboardSamples( pKeyCount, pClipboard, srcParams );
  4783. // Walk the samples in the clipboard
  4784. int nKeyCount = pClipboard->GetKeyCount();
  4785. int nPrevState = PASTE_STATE_BEFORE;
  4786. DmeTime_t tLastWrittenTime = DMETIME_MINTIME;
  4787. DmeTime_t tMaxKeyTime = DMETIME_MAXTIME;
  4788. bool bCollapseSamples = false;
  4789. for ( int j = 0 ; j < nKeyCount; ++j )
  4790. {
  4791. DmeTime_t tKeyTime = pClipboard->GetKeyTime( j );
  4792. T val = pClipboard->GetKeyValue( j );
  4793. // Determine which state we're in
  4794. // NOTE: Don't use ComputeRegionForTime here because it includes
  4795. // the endpoint of the hold region into the hold region.
  4796. int nState;
  4797. for ( nState = nPrevState; nState < PASTE_STATE_COUNT; ++nState )
  4798. {
  4799. if ( tKeyTime < tStartTime[ nState + 1 ][ 0 ] )
  4800. break;
  4801. }
  4802. // This logic inserts a key if there is no sample in the clipboard at the transition time
  4803. bool bForceKey = false;
  4804. if ( nPrevState < nState )
  4805. {
  4806. nState = ++nPrevState;
  4807. // This logic will prevent samples at the hold start + end if
  4808. // the source + dest regions are 0 width and will only do the first and last
  4809. // if we're squeezing the entire time selection down to a single point.
  4810. bForceKey = true;
  4811. if ( nState != PASTE_STATE_AFTER )
  4812. {
  4813. bCollapseSamples = ( pKeyCount[nState] >= pDuration[nState][1] );
  4814. tMaxKeyTime = bCollapseSamples ? tStartTime[ nState ][ 1 ] : ( tStartTime[ nState+1 ][ 1 ] - DmeTime_t( pKeyCount[nState] + 1 ) );
  4815. }
  4816. else
  4817. {
  4818. bCollapseSamples = false;
  4819. tMaxKeyTime = DMETIME_MAXTIME;
  4820. }
  4821. // NOTE: This has to occur after collapse samples + max key time has been set
  4822. if ( ShouldSkipTransition( nState, nZeroField ) )
  4823. {
  4824. --j;
  4825. continue;
  4826. }
  4827. // Don't insert an extra key if the current one we're looking at is right at that point
  4828. if ( tKeyTime != tStartTime[ nPrevState ][ 0 ] )
  4829. {
  4830. tKeyTime = tStartTime[ nPrevState ][ 0 ];
  4831. val = pStartValue[nPrevState];
  4832. // We want to re-do this key, since we inserted a key beforehand
  4833. --j;
  4834. }
  4835. }
  4836. if ( nState == PASTE_STATE_BEFORE )
  4837. continue;
  4838. if ( nState == PASTE_STATE_AFTER && !bForceKey )
  4839. return;
  4840. // Compute destination time based on scale + offset
  4841. double flFactor = ( tKeyTime - tStartTime[ nState ][ 0 ] ).GetTenthsOfMS() * pScaleFactor[ nState ];
  4842. // FIXME: Fix the algorithm, then uncomment to get time-scaled falloff regions
  4843. // if ( nState == PASTE_STATE_RAMP_IN || nState == PASTE_STATE_RAMP_OUT )
  4844. // {
  4845. // int s = ( nState == PASTE_STATE_RAMP_IN ) ? 0 : 1;
  4846. // flFactor = ComputeInterpolationFactor( flFactor, destParams.m_nFalloffInterpolatorTypes[s] );
  4847. // }
  4848. double flTempTime = flFactor * pDuration[ nState ][ 1 ];
  4849. DmeTime_t tDestTime( (int)( flTempTime + 0.5 ) );
  4850. tDestTime += tStartTime[ nState ][ 1 ];
  4851. // Clamp necessary to not lose samples
  4852. // NOTE: The !bForceKey check here makes it so we don't clamp points
  4853. // in time corresponding to transitions of the time selection
  4854. if ( !bForceKey && ( tDestTime > tMaxKeyTime ) )
  4855. {
  4856. tDestTime = tMaxKeyTime;
  4857. }
  4858. if ( tMaxKeyTime != DMETIME_MAXTIME )
  4859. {
  4860. tMaxKeyTime += DMETIME_MINDELTA;
  4861. }
  4862. // This logic will cause *all* samples to appear if we have enough room for them
  4863. if ( !bCollapseSamples )
  4864. {
  4865. bForceKey = true;
  4866. }
  4867. // If we'd go outside our region and we're not forcing the key, then skip
  4868. if ( !bForceKey && tDestTime >= tStartTime[ nState+1 ][ 1 ] )
  4869. continue;
  4870. // Perform blending on ramp in + ramp out regions
  4871. if ( bBlendAreaInFalloffRegion && ( nState != PASTE_STATE_HOLD ) )
  4872. {
  4873. int nBlendIndex = ( nState < PASTE_STATE_HOLD ) ? 0 : 1;
  4874. T baseValue = pBaseLayer->GetValue( tDestTime );
  4875. Vector2D oldDist;
  4876. oldDist.x = tDestTime.GetSeconds() - pBlendTime[ nBlendIndex ].GetSeconds();
  4877. oldDist.y = LengthOf( Subtract( baseValue, pBlendBase[ nBlendIndex ] ) );
  4878. float flDistance = oldDist.Length();
  4879. float flFactorBlend = flDistance * pOOBlendLength[ nBlendIndex ];
  4880. flFactorBlend = destParams.AdjustFactorForInterpolatorType( flFactorBlend, nBlendIndex );
  4881. val = Interpolate( flFactorBlend, baseValue, val );
  4882. }
  4883. // Force key insertion when we transition between states
  4884. if ( bForceKey && ( tLastWrittenTime >= tDestTime ) )
  4885. {
  4886. tDestTime = tLastWrittenTime + DMETIME_MINDELTA;
  4887. }
  4888. // Insert the key into the log
  4889. if ( tLastWrittenTime < tDestTime )
  4890. {
  4891. pWriteLayer->InsertKey( tDestTime, val );
  4892. tLastWrittenTime = tDestTime;
  4893. }
  4894. }
  4895. }
  4896. template< class T >
  4897. void CDmeTypedLog< T >::PasteAndRescaleSamples(
  4898. const CDmeLogLayer *src, // clipboard data
  4899. const DmeLog_TimeSelection_t& srcParams, // clipboard time selection
  4900. const DmeLog_TimeSelection_t& destParams, // current time selection
  4901. bool bBlendAreaInFalloffRegion ) // blending behavior in falloff area of current time selection
  4902. {
  4903. CDmeLogLayer *pBaseLayer = GetLayer( 0 );
  4904. CDmeLogLayer *pWriteLayer = GetLayer( GetTopmostLayer() );
  4905. PasteAndRescaleSamples( pBaseLayer, src, pWriteLayer, srcParams, destParams, bBlendAreaInFalloffRegion );
  4906. }
  4907. template<>
  4908. void CDmeTypedLog< Vector >::BuildNormalizedLayer( CDmeTypedLogLayer< float > *target )
  4909. {
  4910. Assert( target );
  4911. Assert( GetDataType() != AT_FLOAT );
  4912. CDmeTypedLogLayer< Vector > *baseLayer = static_cast< CDmeTypedLogLayer< Vector > * >( GetLayer( 0 ) );
  4913. if ( !baseLayer )
  4914. return;
  4915. float flMin = FLT_MAX;
  4916. float flMax = FLT_MIN;
  4917. int kc = baseLayer->GetKeyCount();
  4918. for ( int i = 0; i < kc; ++i )
  4919. {
  4920. DmeTime_t keyTime = baseLayer->GetKeyTime( i );
  4921. Vector keyValue = baseLayer->GetKeyValue( i );
  4922. float len = keyValue.Length();
  4923. if ( len < flMin )
  4924. {
  4925. flMin = len;
  4926. }
  4927. if ( len > flMax )
  4928. {
  4929. flMax = len;
  4930. }
  4931. target->InsertKey( keyTime, len );
  4932. }
  4933. for ( int i = 0; i < kc; ++i )
  4934. {
  4935. float keyValue = target->GetKeyValue( i );
  4936. float normalized = RemapVal( keyValue, flMin, flMax, 0.0f, 1.0f );
  4937. target->SetKeyValue( i, normalized );
  4938. }
  4939. if ( HasDefaultValue() )
  4940. {
  4941. target->GetTypedOwnerLog()->SetDefaultValue( RemapVal( GetDefaultValue().Length(), flMin, flMax, 0.0f, 1.0f ) );
  4942. }
  4943. }
  4944. template<>
  4945. void CDmeTypedLog< Vector2D >::BuildNormalizedLayer( CDmeTypedLogLayer< float > *target )
  4946. {
  4947. Assert( target );
  4948. Assert( GetDataType() != AT_FLOAT );
  4949. CDmeTypedLogLayer< Vector2D > *baseLayer = static_cast< CDmeTypedLogLayer< Vector2D > * >( GetLayer( 0 ) );
  4950. if ( !baseLayer )
  4951. return;
  4952. float flMin = FLT_MAX;
  4953. float flMax = FLT_MIN;
  4954. int kc = baseLayer->GetKeyCount();
  4955. for ( int i = 0; i < kc; ++i )
  4956. {
  4957. DmeTime_t keyTime = baseLayer->GetKeyTime( i );
  4958. Vector2D keyValue = baseLayer->GetKeyValue( i );
  4959. float len = keyValue.Length();
  4960. if ( len < flMin )
  4961. {
  4962. flMin = len;
  4963. }
  4964. if ( len > flMax )
  4965. {
  4966. flMax = len;
  4967. }
  4968. target->InsertKey( keyTime, len );
  4969. }
  4970. for ( int i = 0; i < kc; ++i )
  4971. {
  4972. float keyValue = target->GetKeyValue( i );
  4973. float normalized = RemapVal( keyValue, flMin, flMax, 0.0f, 1.0f );
  4974. target->SetKeyValue( i, normalized );
  4975. }
  4976. if ( HasDefaultValue() )
  4977. {
  4978. target->GetTypedOwnerLog()->SetDefaultValue( RemapVal( GetDefaultValue().Length(), flMin, flMax, 0.0f, 1.0f ) );
  4979. }
  4980. }
  4981. template<>
  4982. void CDmeTypedLog< Vector4D >::BuildNormalizedLayer( CDmeTypedLogLayer< float > *target )
  4983. {
  4984. Assert( target );
  4985. Assert( GetDataType() != AT_FLOAT );
  4986. CDmeTypedLogLayer< Vector4D > *baseLayer = static_cast< CDmeTypedLogLayer< Vector4D > * >( GetLayer( 0 ) );
  4987. if ( !baseLayer )
  4988. return;
  4989. float flMin = FLT_MAX;
  4990. float flMax = FLT_MIN;
  4991. int kc = baseLayer->GetKeyCount();
  4992. for ( int i = 0; i < kc; ++i )
  4993. {
  4994. DmeTime_t keyTime = baseLayer->GetKeyTime( i );
  4995. Vector4D keyValue = baseLayer->GetKeyValue( i );
  4996. float len = keyValue.Length();
  4997. if ( len < flMin )
  4998. {
  4999. flMin = len;
  5000. }
  5001. if ( len > flMax )
  5002. {
  5003. flMax = len;
  5004. }
  5005. target->InsertKey( keyTime, len );
  5006. }
  5007. for ( int i = 0; i < kc; ++i )
  5008. {
  5009. float keyValue = target->GetKeyValue( i );
  5010. float normalized = RemapVal( keyValue, flMin, flMax, 0.0f, 1.0f );
  5011. target->SetKeyValue( i, normalized );
  5012. }
  5013. if ( HasDefaultValue() )
  5014. {
  5015. target->GetTypedOwnerLog()->SetDefaultValue( RemapVal( GetDefaultValue().Length(), flMin, flMax, 0.0f, 1.0f ) );
  5016. }
  5017. }
  5018. template<>
  5019. void CDmeTypedLog< int >::BuildNormalizedLayer( CDmeTypedLogLayer< float > *target )
  5020. {
  5021. Assert( target );
  5022. Assert( GetDataType() != AT_FLOAT );
  5023. CDmeTypedLogLayer< int > *baseLayer = static_cast< CDmeTypedLogLayer< int > * >( GetLayer( 0 ) );
  5024. if ( !baseLayer )
  5025. return;
  5026. float flMin = FLT_MAX;
  5027. float flMax = FLT_MIN;
  5028. int kc = baseLayer->GetKeyCount();
  5029. for ( int i = 0; i < kc; ++i )
  5030. {
  5031. DmeTime_t keyTime = baseLayer->GetKeyTime( i );
  5032. int keyValue = baseLayer->GetKeyValue( i );
  5033. float len = (float)keyValue;
  5034. if ( len < flMin )
  5035. {
  5036. flMin = len;
  5037. }
  5038. if ( len > flMax )
  5039. {
  5040. flMax = len;
  5041. }
  5042. target->InsertKey( keyTime, len );
  5043. }
  5044. for ( int i = 0; i < kc; ++i )
  5045. {
  5046. float keyValue = target->GetKeyValue( i );
  5047. float normalized = RemapVal( keyValue, flMin, flMax, 0.0f, 1.0f );
  5048. target->SetKeyValue( i, normalized );
  5049. }
  5050. if ( HasDefaultValue() )
  5051. {
  5052. target->GetTypedOwnerLog()->SetDefaultValue( RemapVal( GetDefaultValue(), flMin, flMax, 0.0f, 1.0f ) );
  5053. }
  5054. }
  5055. template<>
  5056. void CDmeTypedLog< float >::BuildNormalizedLayer( CDmeTypedLogLayer< float > *target )
  5057. {
  5058. Assert( target );
  5059. Assert( GetDataType() != AT_FLOAT );
  5060. CDmeTypedLogLayer< float > *baseLayer = static_cast< CDmeTypedLogLayer< float > * >( GetLayer( 0 ) );
  5061. if ( !baseLayer )
  5062. return;
  5063. float flMin = FLT_MAX;
  5064. float flMax = FLT_MIN;
  5065. int kc = baseLayer->GetKeyCount();
  5066. for ( int i = 0; i < kc; ++i )
  5067. {
  5068. DmeTime_t keyTime = baseLayer->GetKeyTime( i );
  5069. int keyValue = baseLayer->GetKeyValue( i );
  5070. float len = (float)keyValue;
  5071. if ( len < flMin )
  5072. {
  5073. flMin = len;
  5074. }
  5075. if ( len > flMax )
  5076. {
  5077. flMax = len;
  5078. }
  5079. target->InsertKey( keyTime, len );
  5080. }
  5081. for ( int i = 0; i < kc; ++i )
  5082. {
  5083. float keyValue = target->GetKeyValue( i );
  5084. float normalized = RemapVal( keyValue, flMin, flMax, 0.0f, 1.0f );
  5085. target->SetKeyValue( i, normalized );
  5086. }
  5087. if ( HasDefaultValue() )
  5088. {
  5089. target->GetTypedOwnerLog()->SetDefaultValue( RemapVal( GetDefaultValue(), flMin, flMax, 0.0f, 1.0f ) );
  5090. }
  5091. }
  5092. //-----------------------------------------------------------------------------
  5093. // Creates a log of a specific type
  5094. //-----------------------------------------------------------------------------
  5095. CDmeLog *CDmeLog::CreateLog( DmAttributeType_t type, DmFileId_t fileid )
  5096. {
  5097. switch ( type )
  5098. {
  5099. case AT_INT:
  5100. case AT_INT_ARRAY:
  5101. return CreateElement< CDmeIntLog >( "int log", fileid );
  5102. case AT_FLOAT:
  5103. case AT_FLOAT_ARRAY:
  5104. return CreateElement< CDmeFloatLog >( "float log", fileid );
  5105. case AT_BOOL:
  5106. case AT_BOOL_ARRAY:
  5107. return CreateElement< CDmeBoolLog >( "bool log", fileid );
  5108. case AT_COLOR:
  5109. case AT_COLOR_ARRAY:
  5110. return CreateElement< CDmeColorLog >( "color log", fileid );
  5111. case AT_VECTOR2:
  5112. case AT_VECTOR2_ARRAY:
  5113. return CreateElement< CDmeVector2Log >( "vector2 log", fileid );
  5114. case AT_VECTOR3:
  5115. case AT_VECTOR3_ARRAY:
  5116. return CreateElement< CDmeVector3Log >( "vector3 log", fileid );
  5117. case AT_VECTOR4:
  5118. case AT_VECTOR4_ARRAY:
  5119. return CreateElement< CDmeVector4Log >( "vector4 log", fileid );
  5120. case AT_QANGLE:
  5121. case AT_QANGLE_ARRAY:
  5122. return CreateElement< CDmeQAngleLog >( "qangle log", fileid );
  5123. case AT_QUATERNION:
  5124. case AT_QUATERNION_ARRAY:
  5125. return CreateElement< CDmeQuaternionLog >( "quaternion log", fileid );
  5126. case AT_VMATRIX:
  5127. case AT_VMATRIX_ARRAY:
  5128. return CreateElement< CDmeVMatrixLog >( "vmatrix log", fileid );
  5129. case AT_STRING:
  5130. case AT_STRING_ARRAY:
  5131. return CreateElement< CDmeStringLog >( "string log", fileid );
  5132. }
  5133. return NULL;
  5134. }
  5135. // Disallowed methods for types
  5136. //template<> void CDmeTypedLog< bool >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const bool& value ) { Assert( 0 ); }
  5137. //template<> void CDmeTypedLog< bool >::_StampKeyAtHeadResample( const DmeLog_TimeSelection_t& params, const bool& value ) { Assert( 0 ); }
  5138. //template<> void CDmeTypedLog< bool >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const CDmAttribute *pAttr, uint index /*= 0*/ ) { Assert( 0 ); }
  5139. //template<> void CDmeTypedLog< bool >::FinishTimeSelection( DmeLog_TimeSelection_t& params ) { Assert( 0 ); }
  5140. //
  5141. //template<> void CDmeTypedLog< Color >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const Color& value ) { Assert( 0 ); }
  5142. //template<> void CDmeTypedLog< Color >::_StampKeyAtHeadResample( const DmeLog_TimeSelection_t& params, const Color& value ) { Assert( 0 ); }
  5143. //template<> void CDmeTypedLog< Color >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const CDmAttribute *pAttr, uint index /*= 0*/ ) { Assert( 0 ); }
  5144. //template<> void CDmeTypedLog< Color >::FinishTimeSelection( DmeLog_TimeSelection_t& params ) { Assert( 0 ); }
  5145. //
  5146. //template<> void CDmeTypedLog< Vector4D >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const Vector4D& value ) { Assert( 0 ); }
  5147. //template<> void CDmeTypedLog< Vector4D >::_StampKeyAtHeadResample( const DmeLog_TimeSelection_t& params, const Vector4D& value ) { Assert( 0 ); }
  5148. //template<> void CDmeTypedLog< Vector4D >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const CDmAttribute *pAttr, uint index /*= 0*/ ) { Assert( 0 ); }
  5149. //template<> void CDmeTypedLog< Vector4D >::FinishTimeSelection( DmeLog_TimeSelection_t& params ) { Assert( 0 ); }
  5150. //
  5151. //template<> void CDmeTypedLog< Vector2D >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const Vector2D& value ) { Assert( 0 ); }
  5152. //template<> void CDmeTypedLog< Vector2D >::_StampKeyAtHeadResample( const DmeLog_TimeSelection_t& params, const Vector2D& value ) { Assert( 0 ); }
  5153. //template<> void CDmeTypedLog< Vector2D >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const CDmAttribute *pAttr, uint index /*= 0*/ ) { Assert( 0 ); }
  5154. //template<> void CDmeTypedLog< Vector2D >::FinishTimeSelection( DmeLog_TimeSelection_t& params ) { Assert( 0 ); }
  5155. //template<> void CDmeTypedLog< Vector >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const Vector& value ) { Assert( 0 ); }
  5156. //template<> void CDmeTypedLog< Vector >::_StampKeyAtHeadResample( const DmeLog_TimeSelection_t& params, const Vector& value ) { Assert( 0 ); }
  5157. //template<> void CDmeTypedLog< Vector >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const CDmAttribute *pAttr, uint index /*= 0*/ ) { Assert( 0 ); }
  5158. //template<> void CDmeTypedLog< Vector >::FinishTimeSelection( DmeLog_TimeSelection_t& params ) { Assert( 0 ); }
  5159. //template<> void CDmeTypedLog< VMatrix >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const VMatrix& value ) { Assert( 0 ); }
  5160. //template<> void CDmeTypedLog< VMatrix >::_StampKeyAtHeadResample( const DmeLog_TimeSelection_t& params, const VMatrix& value ) { Assert( 0 ); }
  5161. //template<> void CDmeTypedLog< VMatrix >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const CDmAttribute *pAttr, uint index /*= 0*/ ) { Assert( 0 ); }
  5162. //template<> void CDmeTypedLog< VMatrix >::FinishTimeSelection( DmeLog_TimeSelection_t& params ) { Assert( 0 ); }
  5163. //
  5164. //template<> void CDmeTypedLog< Quaternion >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const Quaternion& value ) { Assert( 0 ); }
  5165. //template<> void CDmeTypedLog< Quaternion >::_StampKeyAtHeadResample( const DmeLog_TimeSelection_t& params, const Quaternion& value ) { Assert( 0 ); }
  5166. //template<> void CDmeTypedLog< Quaternion >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const CDmAttribute *pAttr, uint index /*= 0*/ ) { Assert( 0 ); }
  5167. //template<> void CDmeTypedLog< Quaternion >::FinishTimeSelection( DmeLog_TimeSelection_t& params ) { Assert( 0 ); }
  5168. //
  5169. //template<> void CDmeTypedLog< QAngle >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const QAngle& value ) { Assert( 0 ); }
  5170. //template<> void CDmeTypedLog< QAngle >::_StampKeyAtHeadResample( const DmeLog_TimeSelection_t& params, const QAngle& value ) { Assert( 0 ); }
  5171. //template<> void CDmeTypedLog< QAngle >::StampKeyAtHead( const DmeLog_TimeSelection_t& params, const CDmAttribute *pAttr, uint index /*= 0*/ ) { Assert( 0 ); }
  5172. //template<> void CDmeTypedLog< QAngle >::FinishTimeSelection( DmeLog_TimeSelection_t& params ) { Assert( 0 ); }
  5173. //-----------------------------------------------------------------------------
  5174. // Helpers for particular types of log layers
  5175. //-----------------------------------------------------------------------------
  5176. void GenerateRotationLog( CDmeQuaternionLogLayer *pLayer, const Vector &vecAxis, DmeTime_t pTime[4], float pRevolutionsPerSec[4] )
  5177. {
  5178. for ( int i = 1; i < 4; ++i )
  5179. {
  5180. if ( pTime[i] < pTime[i-1] )
  5181. {
  5182. Warning( "Bogus times passed into GenerateRotationLog\n" );
  5183. return;
  5184. }
  5185. }
  5186. // Gets the initial value
  5187. matrix3x4_t initial;
  5188. Quaternion q = pLayer->GetValue( pTime[0] );
  5189. QuaternionMatrix( q, initial );
  5190. // Find the max rps, and compute the total rotation in degrees
  5191. // by the time we reach the transition points. The total rotation =
  5192. // integral from 0 to t of 360 * ( rate[i] - rate[i-1] ) t / tl + rate[i-1] )
  5193. // == 360 * ( ( rate[i] - rate[i-1] ) t^2 / 2 + rate[i-1] t )
  5194. float pTotalRotation[4];
  5195. float flMaxRPS = pRevolutionsPerSec[0];
  5196. pTotalRotation[0] = 0.0f;
  5197. for ( int i = 1; i < 4; ++i )
  5198. {
  5199. if ( pRevolutionsPerSec[i] > flMaxRPS )
  5200. {
  5201. flMaxRPS = pRevolutionsPerSec[i];
  5202. }
  5203. float dt = pTime[i].GetSeconds() - pTime[i-1].GetSeconds();
  5204. float dRot = pRevolutionsPerSec[i] - pRevolutionsPerSec[i-1];
  5205. pTotalRotation[i] = 360.0f * ( dRot * dt * 0.5 + pRevolutionsPerSec[i-1] * dt ) + pTotalRotation[i-1];
  5206. }
  5207. // We need to compute how long a single rotation takes, then create samples
  5208. // at 1/4 the frequency of that amount of time
  5209. VMatrix rot;
  5210. matrix3x4_t total;
  5211. QAngle angles;
  5212. float flMaxRotationTime = (flMaxRPS != 0.0f) ? ( 0.125f / flMaxRPS ) : ( pTime[3].GetSeconds() - pTime[0].GetSeconds() );
  5213. DmeTime_t dt( flMaxRotationTime );
  5214. for ( DmeTime_t t = pTime[0]; t <= pTime[3]; t += dt )
  5215. {
  5216. int i = ( t < pTime[1] ) ? 1 : ( ( t < pTime[2] ) ? 2 : 3 );
  5217. float flInterval = t.GetSeconds() - pTime[i-1].GetSeconds();
  5218. float flOOSegmentDur = pTime[i].GetSeconds() - pTime[i-1].GetSeconds();
  5219. if ( flOOSegmentDur == 0.0f )
  5220. {
  5221. Assert( flInterval == 0.0f );
  5222. flOOSegmentDur = 1.0f;
  5223. }
  5224. else
  5225. {
  5226. flOOSegmentDur = 1.0f / flOOSegmentDur;
  5227. }
  5228. float dRot = pRevolutionsPerSec[i] - pRevolutionsPerSec[i-1];
  5229. float flRotation = 360.0f * ( dRot * flInterval * flInterval * 0.5f * flOOSegmentDur + pRevolutionsPerSec[i-1] * flInterval ) + pTotalRotation[i-1];
  5230. MatrixBuildRotationAboutAxis( rot, vecAxis, flRotation );
  5231. ConcatTransforms( initial, rot.As3x4(), total );
  5232. MatrixToAngles( total, angles );
  5233. AngleQuaternion( angles, q );
  5234. pLayer->SetKey( t, q );
  5235. }
  5236. }
  5237. //-----------------------------------------------------------------------------
  5238. // Transforms a position log
  5239. //-----------------------------------------------------------------------------
  5240. void RotatePositionLog( CDmeVector3LogLayer *pPositionLog, const matrix3x4_t& matrix )
  5241. {
  5242. Assert( fabs( matrix[0][3] ) < 1e-3 && fabs( matrix[1][3] ) < 1e-3 && fabs( matrix[2][3] ) < 1e-3 );
  5243. Vector position;
  5244. int nCount = pPositionLog->GetKeyCount();
  5245. for ( int i = 0; i < nCount; ++i )
  5246. {
  5247. const Vector &srcPosition = pPositionLog->GetKeyValue( i );
  5248. VectorTransform( srcPosition, matrix, position );
  5249. pPositionLog->SetKeyValue( i, position );
  5250. }
  5251. }
  5252. //-----------------------------------------------------------------------------
  5253. // Transforms a orientation log
  5254. //-----------------------------------------------------------------------------
  5255. void RotateOrientationLog( CDmeQuaternionLogLayer *pOrientationLog, const matrix3x4_t& matrix, bool bPreMultiply = false )
  5256. {
  5257. Assert( fabs( matrix[0][3] ) < 1e-3 && fabs( matrix[1][3] ) < 1e-3 && fabs( matrix[2][3] ) < 1e-3 );
  5258. matrix3x4_t orientation, newOrientation;
  5259. Quaternion q;
  5260. int nCount = pOrientationLog->GetKeyCount();
  5261. for ( int i = 0; i < nCount; ++i )
  5262. {
  5263. const Quaternion &srcQuat = pOrientationLog->GetKeyValue( i );
  5264. QuaternionMatrix( srcQuat, orientation );
  5265. if ( bPreMultiply )
  5266. {
  5267. ConcatTransforms( matrix, orientation, newOrientation );
  5268. }
  5269. else
  5270. {
  5271. ConcatTransforms( orientation, matrix, newOrientation );
  5272. }
  5273. MatrixQuaternion( newOrientation, q );
  5274. pOrientationLog->SetKeyValue( i, q );
  5275. }
  5276. }