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.

392 lines
12 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "unitlib/unitlib.h"
  9. #include "datamodel/dmelement.h"
  10. #include "movieobjects/movieobjects.h"
  11. #include "datamodel/idatamodel.h"
  12. #include "tier1/utlbuffer.h"
  13. #include "filesystem.h"
  14. #include "movieobjects/dmelog.h"
  15. #include "choreoscene.h"
  16. #include "choreoevent.h"
  17. struct data_t
  18. {
  19. int tms; // tenths of a millisecond
  20. float value;
  21. int curvetype;
  22. };
  23. struct tvpair_t
  24. {
  25. int tms;
  26. float expectedvalue;
  27. };
  28. data_t data[] =
  29. {
  30. { 0, 0.0f, MAKE_CURVE_TYPE( INTERPOLATE_CATMULL_ROM_NORMALIZEX, INTERPOLATE_CATMULL_ROM_NORMALIZEX ) },
  31. { 10000, 0.5f, MAKE_CURVE_TYPE( INTERPOLATE_CATMULL_ROM_NORMALIZEX, INTERPOLATE_CATMULL_ROM_NORMALIZEX ) },
  32. { 20000, 0.5f, MAKE_CURVE_TYPE( INTERPOLATE_EASE_IN, INTERPOLATE_EASE_OUT ) },
  33. { 30000, 0.5f, MAKE_CURVE_TYPE( INTERPOLATE_EASE_OUT, INTERPOLATE_EASE_INOUT ) },
  34. { 40000, 0.5f, MAKE_CURVE_TYPE( INTERPOLATE_EASE_INOUT, INTERPOLATE_BSPLINE ) },
  35. { 50000, 0.5f, MAKE_CURVE_TYPE( INTERPOLATE_BSPLINE, INTERPOLATE_LINEAR_INTERP ) },
  36. { 60000, 1.0f, MAKE_CURVE_TYPE( INTERPOLATE_LINEAR_INTERP, INTERPOLATE_KOCHANEK_BARTELS ) },
  37. { 70000, 0.0f, MAKE_CURVE_TYPE( INTERPOLATE_KOCHANEK_BARTELS, INTERPOLATE_KOCHANEK_BARTELS_EARLY ) },
  38. { 80000, 0.5f, MAKE_CURVE_TYPE( INTERPOLATE_KOCHANEK_BARTELS_EARLY, INTERPOLATE_KOCHANEK_BARTELS_LATE ) },
  39. { 90000, 0.0f, MAKE_CURVE_TYPE( INTERPOLATE_KOCHANEK_BARTELS_LATE, INTERPOLATE_SIMPLE_CUBIC ) },
  40. { 100000, 0.25f, MAKE_CURVE_TYPE( INTERPOLATE_SIMPLE_CUBIC, INTERPOLATE_CATMULL_ROM ) },
  41. { 110000, 0.0f, MAKE_CURVE_TYPE( INTERPOLATE_CATMULL_ROM, INTERPOLATE_CATMULL_ROM_NORMALIZE ) },
  42. { 120000, 0.125f, MAKE_CURVE_TYPE( INTERPOLATE_CATMULL_ROM_NORMALIZE, INTERPOLATE_EXPONENTIAL_DECAY ) },
  43. { 130000, 0.0f, MAKE_CURVE_TYPE( INTERPOLATE_EXPONENTIAL_DECAY, INTERPOLATE_HOLD ) },
  44. { 140000, 0.0625f, MAKE_CURVE_TYPE( INTERPOLATE_CATMULL_ROM_NORMALIZEX, INTERPOLATE_EXPONENTIAL_DECAY ) },
  45. { 150000, 0.0f, MAKE_CURVE_TYPE( INTERPOLATE_CATMULL_ROM_NORMALIZEX, INTERPOLATE_CATMULL_ROM_NORMALIZEX ) },
  46. };
  47. #define NUM_DEF_TESTS 3
  48. static data_t values1[] =
  49. {
  50. { -1, 0.0f, 0 },
  51. };
  52. static data_t values2[] =
  53. {
  54. { 5000, 0.5f, CURVE_DEFAULT },
  55. { -1, 0.0f, 0 },
  56. };
  57. static data_t values3[] =
  58. {
  59. { 2500, 0.25f, CURVE_DEFAULT },
  60. { 7500, 0.75f, CURVE_DEFAULT },
  61. { -1, 0.0f, 0 },
  62. };
  63. static data_t *defaultvaluetest[ NUM_DEF_TESTS ] =
  64. {
  65. values1,
  66. values2,
  67. values3
  68. };
  69. #define NUM_TEST_VALUES 3
  70. static tvpair_t expectedvalues1[NUM_TEST_VALUES] =
  71. {
  72. { 0, 0.5f },
  73. { 5000, 0.5f },
  74. { 10000, 0.5f },
  75. };
  76. static tvpair_t expectedvalues2[NUM_TEST_VALUES] =
  77. {
  78. { 0, 0.5f },
  79. { 5000, 0.5f },
  80. { 10000, 0.5f },
  81. };
  82. static tvpair_t expectedvalues3[NUM_TEST_VALUES] =
  83. {
  84. { 0, 0.25f },
  85. { 5000, 0.5f },
  86. { 10000, 0.75f },
  87. };
  88. static tvpair_t *expectedvalues[ NUM_DEF_TESTS ] =
  89. {
  90. expectedvalues1,
  91. expectedvalues2,
  92. expectedvalues3
  93. };
  94. void ResetLog( CDmeFloatLog *log, bool useCurveTypes, int startIndex = 0, int endIndex = -1 )
  95. {
  96. log->ClearKeys();
  97. CDmeCurveInfo *pCurveInfo = useCurveTypes ? log->GetOrCreateCurveInfo() : log->GetCurveInfo();
  98. if ( useCurveTypes )
  99. {
  100. pCurveInfo->SetDefaultCurveType( MAKE_CURVE_TYPE( INTERPOLATE_CATMULL_ROM_NORMALIZEX, INTERPOLATE_CATMULL_ROM_NORMALIZEX ) );
  101. }
  102. else if ( !useCurveTypes && pCurveInfo )
  103. {
  104. g_pDataModel->DestroyElement( pCurveInfo->GetHandle() );
  105. log->SetCurveInfo( NULL );
  106. }
  107. int i;
  108. int c;
  109. c = ARRAYSIZE( data );
  110. for ( i = startIndex; i < c; ++i )
  111. {
  112. log->SetKey( DmeTime_t( data[ i ].tms ), data[ i ].value, useCurveTypes ? data[ i ].curvetype : CURVE_DEFAULT );
  113. if ( endIndex != -1 && i >= endIndex )
  114. break;
  115. }
  116. }
  117. void CompareFloats( float f1, float f2, float tol, char const *fmt, ... )
  118. {
  119. float diff = fabs( f1 - f2 );
  120. if ( diff < tol )
  121. return;
  122. char buf[ 256 ];
  123. va_list argptr;
  124. va_start( argptr, fmt );
  125. _vsnprintf( buf, sizeof( buf ) - 1, fmt, argptr );
  126. va_end( argptr );
  127. Msg( buf );
  128. }
  129. DEFINE_TESTCASE_NOSUITE( DmxRunDefaultValueLogTest )
  130. {
  131. Msg( "Running CDmeTypedLog<float> default value (stereo channel w/ value 0.5) tests...\n" );
  132. CDisableUndoScopeGuard sg;
  133. DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( "<DmxTestDmeLog>" );
  134. for ( int i = 0; i < NUM_DEF_TESTS; ++i )
  135. {
  136. data_t *pdata = defaultvaluetest[ i ];
  137. tvpair_t *pexpected = expectedvalues[ i ];
  138. // Run each test
  139. CDmeFloatLog *log = CreateElement<CDmeFloatLog>( "curve", fileid );
  140. if ( !log )
  141. {
  142. Msg( "Unable to create CDmeFloatLog object!!!" );
  143. continue;
  144. }
  145. log->SetDefaultValue( 0.5f );
  146. if ( pdata )
  147. {
  148. // Run the test
  149. for ( int j = 0; ; ++j )
  150. {
  151. if ( pdata[ j ].tms == -1 )
  152. break;
  153. log->SetKey( DmeTime_t( pdata[ j ].tms ), pdata[ j ].value );
  154. }
  155. }
  156. // Now compare against expected values
  157. for ( int j = 0; j < NUM_TEST_VALUES; ++j )
  158. {
  159. DmeTime_t t = DmeTime_t( pexpected[ j ].tms );
  160. float v = pexpected[ j ].expectedvalue;
  161. float logv = log->GetValue( t );
  162. Shipping_Assert( v == logv );
  163. }
  164. DestroyElement( log );
  165. }
  166. g_pDataModel->RemoveFileId( fileid );
  167. }
  168. void RunDmeFloatLogTests( CDmeFloatLog *log )
  169. {
  170. Msg( " Testing general log data...\n" );
  171. ResetLog( log, false );
  172. CompareFloats( 0.5f, log->GetValue( DmeTime_t( 2.0f ) ), 0.000001f, "log->GetValue( 2.0 ) expected to be 0.5f\n" );
  173. CompareFloats( 0.5f, log->GetValue( DmeTime_t( 2.5f ) ), 0.000001f, "log->GetValue( 2.5 ) expected to be 0.5f\n" );
  174. CompareFloats( 0.5f, log->GetValue( DmeTime_t( 2.5f ) ), 0.000001f, "log->GetValue( 2.5 ) expected to be 0.5f\n" );
  175. CompareFloats( 0.5f, log->GetValue( DmeTime_t( 6.5f ) ), 0.000001f, "log->GetValue( 6.5 ) expected to be 0.5f\n" );
  176. CDmeCurveInfo *pCurveInfo = log->GetOrCreateCurveInfo();
  177. int idx = log->FindKeyWithinTolerance( DmeTime_t( 6.0f ), DmeTime_t( 0 ) );
  178. Shipping_Assert( log->GetKeyTime( idx ) == DmeTime_t( 6.0f ) );
  179. log->SetKeyCurveType( idx, MAKE_CURVE_TYPE( INTERPOLATE_LINEAR_INTERP, INTERPOLATE_LINEAR_INTERP ) );
  180. log->SetKeyCurveType( idx + 1, MAKE_CURVE_TYPE( INTERPOLATE_LINEAR_INTERP, INTERPOLATE_LINEAR_INTERP ) );
  181. float val = log->GetValue( DmeTime_t( 6.5f ) );
  182. float qval = log->GetValue( DmeTime_t( 6.25f ) );
  183. CompareFloats( 0.5f, val, 0.000001f, "INTERPOLATE_LINEAR_INTERPlog->GetValue( 6500 ) expcted to be 0.5f\n" );
  184. CompareFloats( 0.75f, qval, 0.000001f, "INTERPOLATE_LINEAR_INTERPlog->GetValue( 6250 ) expcted to be 0.75f\n" );
  185. log->SetKeyCurveType( idx, MAKE_CURVE_TYPE( INTERPOLATE_CATMULL_ROM_NORMALIZEX, INTERPOLATE_CATMULL_ROM_NORMALIZEX ) );
  186. log->SetKeyCurveType( idx + 1, MAKE_CURVE_TYPE( INTERPOLATE_CATMULL_ROM_NORMALIZEX, INTERPOLATE_CATMULL_ROM_NORMALIZEX ) );
  187. float val2 = log->GetValue( DmeTime_t( 6.5f ) );
  188. float qval2 = log->GetValue( DmeTime_t( 6.25f ) );
  189. Shipping_Assert( val2 == val );
  190. Shipping_Assert( qval2 != val );
  191. log->SetKeyCurveType( idx, MAKE_CURVE_TYPE( INTERPOLATE_EASE_INOUT, INTERPOLATE_EASE_INOUT ) );
  192. log->SetKeyCurveType( idx + 1, MAKE_CURVE_TYPE( INTERPOLATE_EASE_INOUT, INTERPOLATE_EASE_INOUT ) );
  193. float val3 = log->GetValue( DmeTime_t( 6.5f ) );
  194. float qval3 = log->GetValue( DmeTime_t( 6.25f ) );
  195. Shipping_Assert( val3 == val );
  196. Shipping_Assert( qval3 != val );
  197. log->SetKeyCurveType( idx, MAKE_CURVE_TYPE( INTERPOLATE_EXPONENTIAL_DECAY, INTERPOLATE_EXPONENTIAL_DECAY ) );
  198. log->SetKeyCurveType( idx + 1, MAKE_CURVE_TYPE( INTERPOLATE_EXPONENTIAL_DECAY, INTERPOLATE_EXPONENTIAL_DECAY ) );
  199. float val4 = log->GetValue( DmeTime_t( 6.5f ) );
  200. float qval4 = log->GetValue( DmeTime_t( 6.25f ) );
  201. Shipping_Assert( val4 != val );
  202. Shipping_Assert( qval4 != val );
  203. log->SetKeyCurveType( idx, MAKE_CURVE_TYPE( INTERPOLATE_KOCHANEK_BARTELS, INTERPOLATE_KOCHANEK_BARTELS ) );
  204. log->SetKeyCurveType( idx + 1, MAKE_CURVE_TYPE( INTERPOLATE_KOCHANEK_BARTELS, INTERPOLATE_KOCHANEK_BARTELS ) );
  205. float val5 = log->GetValue( DmeTime_t( 6.5f ) );
  206. float qval5 = log->GetValue( DmeTime_t( 6.25f ) );
  207. Shipping_Assert( val5 == val );
  208. Shipping_Assert( qval5 != val );
  209. pCurveInfo->SetDefaultCurveType( MAKE_CURVE_TYPE( INTERPOLATE_KOCHANEK_BARTELS, INTERPOLATE_KOCHANEK_BARTELS ) );
  210. log->SetKeyCurveType( idx, MAKE_CURVE_TYPE( INTERPOLATE_DEFAULT, INTERPOLATE_DEFAULT ) );
  211. log->SetKeyCurveType( idx + 1, MAKE_CURVE_TYPE( INTERPOLATE_DEFAULT, INTERPOLATE_DEFAULT ) );
  212. float val6 = log->GetValue( DmeTime_t( 6.5f ) );
  213. float qval6 = log->GetValue( DmeTime_t( 6.25f ) );
  214. Shipping_Assert( val5 == val6 );
  215. Shipping_Assert( qval6 == qval5 );
  216. }
  217. void CompareLogToChoreo( CFlexAnimationTrack *track, CDmeFloatLog *log )
  218. {
  219. // Now run tests
  220. for ( DmeTime_t t( 0 ); t < DmeTime_t( 20.0f ); t += DmeTime_t( 0.1f ) )
  221. {
  222. // Compare values
  223. float dmevalue = log->GetValue( t );
  224. float choreovalue = track->GetIntensity( t.GetSeconds() );
  225. CompareFloats( dmevalue, choreovalue, 0.001f, "Time(%f sec) , dme [%f] choreo[%f], diff[%f]\n",
  226. t.GetSeconds(),
  227. dmevalue,
  228. choreovalue,
  229. fabs( dmevalue - choreovalue ) );
  230. }
  231. }
  232. void ResetChoreo( CFlexAnimationTrack *track, bool useCurveTypes, int startIndex = 0, int endIndex = -1 )
  233. {
  234. track->Clear();
  235. int i;
  236. int c;
  237. c = ARRAYSIZE( data );
  238. for ( i = startIndex; i < c; ++i )
  239. {
  240. data_t *e = &data[ i ];
  241. float t = (float)e->tms / 10000.0f;
  242. CExpressionSample *sample = track->AddSample( t, e->value );
  243. Shipping_Assert( sample );
  244. if ( useCurveTypes )
  245. {
  246. sample->SetCurveType( e->curvetype );
  247. }
  248. if ( endIndex != -1 && i >= endIndex )
  249. break;
  250. }
  251. }
  252. void RunDmeChoreoComparisons( CDmeFloatLog *log )
  253. {
  254. Msg( " Testing choreo-style log data...\n" );
  255. ResetLog( log, true );
  256. log->SetRightEdgeTime( DmeTime_t( 15.0f ) );
  257. CChoreoScene *scene = new CChoreoScene( NULL );
  258. CChoreoEvent *event = new CChoreoEvent( scene, CChoreoEvent::FLEXANIMATION, "test" );
  259. event->SetStartTime( 0.0f );
  260. event->SetEndTime( 15.0f );
  261. CFlexAnimationTrack *track = new CFlexAnimationTrack( event );
  262. track->SetFlexControllerName( "flextest" );
  263. track->SetComboType( false );
  264. ResetChoreo( track, true );
  265. Msg( " Comparing default data...\n" );
  266. CompareLogToChoreo( track, log );
  267. ResetLog( log, true, 3, 14 );
  268. ResetChoreo( track, true, 3, 14 );
  269. Msg( " Comparing subset of data...\n" );
  270. CompareLogToChoreo( track, log );
  271. Msg( " Comparing left/right edge settings...\n" );
  272. // Now test right and left edge stuff
  273. // Enable left edge stuff
  274. track->SetEdgeActive( true, true );
  275. track->SetEdgeInfo( true, MAKE_CURVE_TYPE( INTERPOLATE_LINEAR_INTERP, INTERPOLATE_LINEAR_INTERP ), 0.75f );
  276. track->SetEdgeActive( false, true );
  277. track->SetEdgeInfo( false, MAKE_CURVE_TYPE( INTERPOLATE_EASE_OUT, INTERPOLATE_EASE_OUT ), 0.25f );
  278. // Same settings for log
  279. log->SetUseEdgeInfo( true );
  280. log->SetDefaultEdgeZeroValue( 0.0f );
  281. log->SetEdgeInfo( 0, true, 0.75f, MAKE_CURVE_TYPE( INTERPOLATE_LINEAR_INTERP, INTERPOLATE_LINEAR_INTERP ) );
  282. log->SetEdgeInfo( 1, true, 0.25f, MAKE_CURVE_TYPE( INTERPOLATE_EASE_OUT, INTERPOLATE_EASE_OUT ) );
  283. CompareLogToChoreo( track, log );
  284. int i;
  285. for ( i = 1; i < NUM_INTERPOLATE_TYPES; ++i )
  286. {
  287. Msg( " Comparing left/right edge settings[ %s ]...\n", Interpolator_NameForInterpolator( i, true ) );
  288. float val = (float)i / (float)( NUM_INTERPOLATE_TYPES - 1 ) ;
  289. // Now test right and left edge stuff with different data
  290. track->SetEdgeInfo( true, MAKE_CURVE_TYPE( i, i ), val );
  291. track->SetEdgeInfo( false, MAKE_CURVE_TYPE( i, i ), val );
  292. log->SetEdgeInfo( 0, true, val, MAKE_CURVE_TYPE( i, i ) );
  293. log->SetEdgeInfo( 1, true, val, MAKE_CURVE_TYPE( i, i ) );
  294. CompareLogToChoreo( track, log );
  295. }
  296. delete event;
  297. delete scene;
  298. }
  299. DEFINE_TESTCASE_NOSUITE( DmxTestDmeLog )
  300. {
  301. Msg( "Running CDmeTypedLog<float> tests...\n" );
  302. CDisableUndoScopeGuard sg;
  303. DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( "<DmxTestDmeLog>" );
  304. CDmeFloatLog *pElement = CreateElement<CDmeFloatLog>( "curve", fileid );
  305. if ( !pElement )
  306. {
  307. Msg( "Unable to create CDmeFloatLog object!!!" );
  308. return;
  309. }
  310. // Run tests
  311. RunDmeFloatLogTests( pElement );
  312. RunDmeChoreoComparisons( pElement );
  313. g_pDataModel->RemoveFileId( fileid );
  314. }