summaryrefslogtreecommitdiff
path: root/unittests/dmxtest/dmxtest_dmeloglayers.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /unittests/dmxtest/dmxtest_dmeloglayers.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'unittests/dmxtest/dmxtest_dmeloglayers.cpp')
-rw-r--r--unittests/dmxtest/dmxtest_dmeloglayers.cpp908
1 files changed, 908 insertions, 0 deletions
diff --git a/unittests/dmxtest/dmxtest_dmeloglayers.cpp b/unittests/dmxtest/dmxtest_dmeloglayers.cpp
new file mode 100644
index 0000000..77626b1
--- /dev/null
+++ b/unittests/dmxtest/dmxtest_dmeloglayers.cpp
@@ -0,0 +1,908 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#include "unitlib/unitlib.h"
+#include "datamodel/dmelement.h"
+#include "movieobjects/movieobjects.h"
+#include "datamodel/idatamodel.h"
+
+#include "movieobjects/dmechannel.h"
+#include "movieobjects/dmelog.h"
+
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#define NUM_CHANNELS 1
+#define NUM_LOG_ENTRIES 10
+
+enum
+{
+ SPEW_DIFFS = (1<<0),
+ SPEW_VALUES= (1<<1),
+ SPEW_KEYS= (1<<2),
+};
+
+static void ValidateDataSets( int spew, char const *testname, CUtlVector< CUtlVector< float > >& values, CUtlVector< CUtlVector< float > >& valuesbaked )
+{
+ int i, j;
+ // Compare baked, unbaked values
+ Assert( values.Count() == valuesbaked.Count() );
+ int c = values.Count();
+ bool differs = false;
+ bool spewvalues = ( spew & SPEW_VALUES ) ? true : false;
+
+ float tol = 0.0001f;
+
+ for ( i = 0; i < c; ++i )
+ {
+ CUtlVector< float >& v = values[ i ];
+ CUtlVector< float >& vb = valuesbaked[ i ];
+
+ Assert( v.Count() == vb.Count() );
+
+ // Now get the values of the samples in the log
+ for ( j = 0; j < v.Count(); ++j )
+ {
+ Assert( vb.IsValidIndex( j ) );
+ if ( !vb.IsValidIndex( j ) )
+ continue;
+
+ float v1 = v[ j ];
+ float v2 = vb[ j ];
+ if ( fabs( v1 - v2 ) > tol )
+ {
+ differs = true;
+ }
+
+ if ( spewvalues )
+ {
+ Msg( "%d %f %f\n", j, v[ j ], vb[ j ] );
+ }
+ }
+ }
+
+ Msg( " %s\n", differs ? "FAILED" : "OK" );
+
+ if ( !(spew & SPEW_DIFFS ) )
+ return;
+
+ for ( i = 0; i < c; ++i )
+ {
+ CUtlVector< float >& v = values[ i ];
+ CUtlVector< float >& vb = valuesbaked[ i ];
+
+ Assert( v.Count() == vb.Count() );
+
+ // Now get the values of the samples in the log
+ for ( j = 0; j < v.Count(); ++j )
+ {
+ Assert( vb.IsValidIndex( j ) );
+ if ( !vb.IsValidIndex( j ) )
+ continue;
+
+ if ( v[ j ] == vb[ j ] )
+ {
+ if ( differs )
+ {
+ Msg( "%d found %f to equal %f\n", j, v[ j ], vb[ j ] );
+ }
+ continue;
+ }
+
+ Msg( "%d expected %f to equal %f\n", j, v[ j ], vb[ j ] );
+ }
+ }
+
+ if ( differs )
+ {
+ Msg( "End Test '%s'\n---------------\n", testname );
+ }
+}
+
+static void CreateChannels( int num, CUtlVector< CDmeChannel * >& channels, DmFileId_t fileid )
+{
+ CDisableUndoScopeGuard guard;
+
+ for ( int i = 0; i < num; ++i )
+ {
+ CDmeChannel *channel = NULL;
+
+ channel = CreateElement< CDmeChannel >( "channel1", fileid );
+ channels.AddToTail( channel );
+ channel->CreateLog( AT_FLOAT ); // only care about float logs for now
+ channel->SetMode( CM_PLAY );// Make sure it's in playback mode
+ }
+}
+
+struct TestLayer_t
+{
+ enum
+ {
+ TYPE_SIMPLESLOPE = 0, // value == time
+ TYPE_SINE, // sinusoidal
+ TYPE_CONSTANT,
+ };
+
+ TestLayer_t() :
+ startTime( 0 ),
+ endTime( 0 ),
+ timeStep( 0 ),
+ usecurvetype( false ),
+ curvetype( CURVE_DEFAULT ),
+ type( TYPE_SIMPLESLOPE ),
+ constantvalue( 0.0f )
+ {
+ }
+
+ float ValueForTime( DmeTime_t time ) const
+ {
+ float t = (float)time.GetSeconds();
+ switch ( type )
+ {
+ default:
+ case TYPE_SIMPLESLOPE:
+ return t;
+ case TYPE_SINE:
+ return constantvalue * ( 1.0f + sin( ( t * 0.002f ) * 2 * M_PI ) ) * 0.5f;
+ case TYPE_CONSTANT:
+ return constantvalue;
+ }
+
+ return t;
+ }
+
+ int type;
+ DmeTime_t startTime;
+ DmeTime_t endTime;
+ DmeTime_t timeStep;
+
+ bool usecurvetype;
+ int curvetype;
+
+ float constantvalue;
+};
+
+struct TestParams_t
+{
+ TestParams_t() :
+ testundo( false ),
+ usecurves( false ),
+ purgevalues( true ),
+ testabort( false ),
+ spew( 0 ),
+ spewnontopmostlayers( false ),
+ defaultcurve( CURVE_DEFAULT ),
+ mintime( DmeTime_t( 0 ) ),
+ maxtime( DmeTime_t( 100 ) )
+ {
+ }
+ int spew;
+ bool usecurves;
+ bool purgevalues;
+ bool testundo;
+ bool testabort;
+ bool spewnontopmostlayers;
+ int defaultcurve;
+ DmeTime_t mintime;
+ DmeTime_t maxtime;
+ CUtlVector< TestLayer_t > layers;
+
+ void Reset()
+ {
+ purgevalues = true;
+ usecurves = false;
+ testundo = false;
+ testabort = false;
+ spewnontopmostlayers = false;
+ spew = 0;
+ mintime = DmeTime_t( 0 );
+ maxtime = DmeTime_t( 100 );
+ defaultcurve = CURVE_DEFAULT;
+ layers.RemoveAll();
+ }
+
+ void AddLayer( DmeTime_t start, DmeTime_t end, DmeTime_t step, int curvetype, int valuetype, float constantvalue = 0.0f )
+ {
+ TestLayer_t tl;
+ tl.startTime = start;
+ tl.endTime = end;
+ tl.timeStep = step;
+ tl.curvetype = curvetype;
+ tl.type = valuetype;
+ tl.constantvalue = constantvalue;
+
+ layers.AddToTail( tl );
+ }
+};
+
+static void RunLayerTest( char const *testname, CUtlVector< CDmeChannel * >& channels, const TestParams_t& params )
+{
+ if ( params.layers.Count() == 0 )
+ {
+ Assert( 0 );
+ return;
+ }
+
+ Msg( "Test '%s'...\n", testname );
+
+ g_pDataModel->StartUndo( testname, testname );
+
+ int i;
+ int c = channels.Count();
+
+ {
+ CDisableUndoScopeGuard guard;
+
+ for ( i = 0; i < NUM_CHANNELS; ++i )
+ {
+ CDmeChannel *channel = channels[ i ];
+ CDmeTypedLog< float > *pLog = CastElement< CDmeTypedLog< float > >( channel->GetLog() );
+ Assert( pLog );
+ pLog->ClearKeys(); // reset it
+
+ CDmeCurveInfo *pCurveInfo = NULL;
+ if ( params.usecurves )
+ {
+ pCurveInfo = pLog->GetOrCreateCurveInfo();
+ pCurveInfo->SetDefaultCurveType( params.defaultcurve );
+ pCurveInfo->SetMinValue( 0.0f );
+ pCurveInfo->SetMaxValue( 1000.0f );
+ }
+ else
+ {
+ if ( pLog->GetCurveInfo() )
+ {
+ g_pDataModel->DestroyElement( pLog->GetCurveInfo()->GetHandle() );
+ }
+ pLog->SetCurveInfo( NULL );
+ }
+
+ const TestLayer_t& tl = params.layers[ 0 ];
+ // Now add entries
+ DmeTime_t logStep = tl.timeStep;
+ DmeTime_t logStart = tl.startTime;
+
+ for ( DmeTime_t t = logStart; t <= tl.endTime + logStep - DmeTime_t( 1 ); t += logStep )
+ {
+ DmeTime_t useTime = t;
+ if ( useTime > tl.endTime )
+ {
+ useTime = tl.endTime;
+ }
+ float value = tl.ValueForTime( useTime );
+ if ( tl.usecurvetype )
+ {
+ pLog->SetKey( useTime, value, tl.curvetype );
+ }
+ else
+ {
+ pLog->SetKey( useTime, value );
+ }
+ }
+ }
+ }
+
+ for ( int layer = 1; layer < params.layers.Count(); ++layer )
+ {
+ const TestLayer_t& tl = params.layers[ layer ];
+
+ // Test creating a layer and collapsing it back down
+ g_pChannelRecordingMgr->StartLayerRecording( "layer operations" );
+ for ( i = 0; i < c; ++i )
+ {
+ g_pChannelRecordingMgr->AddChannelToRecordingLayer( channels[ i ] ); // calls log->CreateNewLayer()
+ }
+
+ // Now add values to channel logs
+ for ( i = 0; i < c; ++i )
+ {
+ CDmeChannel *channel = channels[ i ];
+ CDmeTypedLog< float > *pLog = CastElement< CDmeTypedLog< float > >( channel->GetLog() );
+ Assert( pLog );
+
+ // Now add entries
+ DmeTime_t logStep = tl.timeStep;
+ DmeTime_t logStart = tl.startTime;
+
+ for ( DmeTime_t t = logStart; t <= tl.endTime + logStep - DmeTime_t( 1 ); t += logStep )
+ {
+ DmeTime_t useTime = t;
+ if ( useTime > tl.endTime )
+ {
+ useTime = tl.endTime;
+ }
+ float value = tl.ValueForTime( useTime );
+ if ( tl.usecurvetype )
+ {
+ pLog->SetKey( useTime, value, tl.curvetype );
+ }
+ else
+ {
+ pLog->SetKey( useTime, value );
+ }
+ }
+ }
+
+ g_pChannelRecordingMgr->FinishLayerRecording( 0.0f, false ); // don't flatten layers here, we'll do it manually
+ }
+
+ // Now sample values
+ CUtlVector< CUtlVector< float > > values;
+ CUtlVector< CUtlVector< float > > valuesbaked;
+
+ for ( i = 0; i < c; ++i )
+ {
+ CDmeChannel *channel = channels[ i ];
+ CDmeTypedLog< float > *pLog = CastElement< CDmeTypedLog< float > >( channel->GetLog() );
+ Assert( pLog );
+
+ int idx = values.AddToTail();
+
+ CUtlVector< float >& v = values[ idx ];
+
+ // Now get the values of the samples in the log
+ for ( DmeTime_t j = params.mintime; j <= params.maxtime; j += DmeTime_t( 1 ) )
+ {
+ float fval = pLog->GetValue( j );
+ v.AddToTail( fval );
+ }
+ }
+
+ if ( params.spewnontopmostlayers )
+ {
+ for ( i = 0; i < c; ++i )
+ {
+ CDmeChannel *channel = channels[ i ];
+ CDmeTypedLog< float > *pLog = CastElement< CDmeTypedLog< float > >( channel->GetLog() );
+ Assert( pLog );
+
+ // Now get the values of the samples in the log
+ for ( DmeTime_t j = params.mintime; j <= params.maxtime; j += DmeTime_t( 1 ) )
+ {
+ float topValue = pLog->GetValue( j );
+ float underlyingValue = pLog->GetValueSkippingTopmostLayer( j );
+
+ Msg( "t(%d) top [%f] rest [%f]\n",
+ j.GetTenthsOfMS(), topValue, underlyingValue );
+ }
+ }
+ }
+
+ // Now test creating a layer and "undo/redo" of the layer
+ if ( params.testundo )
+ {
+ g_pDataModel->FinishUndo();
+ g_pDataModel->Undo();
+ g_pDataModel->Redo();
+ g_pDataModel->StartUndo( testname, testname );
+ }
+
+ {
+ CUndoScopeGuard guard( "Bake Layers" );
+ // Now bake down and resample values
+ for ( i = 0; i < c; ++i )
+ {
+ CDmeChannel *channel = channels[ i ];
+ CDmeTypedLog< float > *pLog = CastElement< CDmeTypedLog< float > >( channel->GetLog() );
+ Assert( pLog );
+
+ pLog->FlattenLayers( 0.0f, params.spew & SPEW_DIFFS );
+
+ int idx = valuesbaked.AddToTail();
+
+ CUtlVector< float >& v = valuesbaked[ idx ];
+
+ // Now get the values of the samples in the log
+ for ( DmeTime_t j = params.mintime; j <= params.maxtime; j += DmeTime_t( 1 ) )
+ {
+ float fval = pLog->GetValue( j );
+ v.AddToTail( fval );
+ }
+ }
+ }
+
+ ValidateDataSets( params.spew, testname, values, valuesbaked );
+
+ // Now test creating a layer and "undo/redo" of the layer
+ if ( params.testundo )
+ {
+ g_pDataModel->FinishUndo();
+ g_pDataModel->Undo();
+ g_pDataModel->Redo();
+ g_pDataModel->StartUndo( testname, testname );
+ }
+
+ if ( params.testabort )
+ {
+ g_pDataModel->AbortUndoableOperation();
+ }
+ else
+ {
+ g_pDataModel->FinishUndo();
+ }
+}
+
+static void RunTimeSelectionTest( char const *testname, CUtlVector< CDmeChannel * >& channels,
+ const TestParams_t& params, DmeTime_t tHeadPosition, DmeLog_TimeSelection_t& ts, float value )
+{
+ if ( params.layers.Count() == 0 )
+ {
+ Assert( 0 );
+ return;
+ }
+
+ Msg( "Test '%s'...\n", testname );
+
+ int i, j;
+ int c = channels.Count();
+
+ if ( params.purgevalues )
+ {
+ CDisableUndoScopeGuard guard;
+
+ for ( i = 0; i < NUM_CHANNELS; ++i )
+ {
+ CDmeChannel *channel = channels[ i ];
+ CDmeTypedLog< float > *pLog = CastElement< CDmeTypedLog< float > >( channel->GetLog() );
+ Assert( pLog );
+ pLog->ClearKeys(); // reset it
+
+ CDmeCurveInfo *pCurveInfo = params.usecurves ? pLog->GetOrCreateCurveInfo() : pLog->GetCurveInfo();
+ if ( params.usecurves )
+ {
+ pCurveInfo->SetDefaultCurveType( params.defaultcurve );
+ pCurveInfo->SetMinValue( 0.0f );
+ pCurveInfo->SetMaxValue( 1000.0f );
+ }
+ else if ( !params.usecurves && pCurveInfo )
+ {
+ g_pDataModel->DestroyElement( pCurveInfo->GetHandle() );
+ pLog->SetCurveInfo( NULL );
+ }
+
+ const TestLayer_t& tl = params.layers[ 0 ];
+ // Now add entries
+ DmeTime_t logStep = tl.timeStep;
+ DmeTime_t logStart = tl.startTime;
+
+ for ( DmeTime_t t = logStart; t <= tl.endTime + logStep - DmeTime_t( 1 ); t += logStep )
+ {
+ DmeTime_t useTime = t;
+ if ( useTime > tl.endTime )
+ useTime = tl.endTime;
+
+ float value = tl.ValueForTime( useTime );
+ if ( tl.usecurvetype )
+ {
+ pLog->SetKey( useTime, value, tl.curvetype );
+ }
+ else
+ {
+ pLog->SetKey( useTime, value );
+ }
+ }
+ }
+ }
+
+ // Test creating a layer and collapsing it back down
+ g_pChannelRecordingMgr->StartLayerRecording( "layer operations", &ts );
+ for ( i = 0; i < c; ++i )
+ {
+ g_pChannelRecordingMgr->AddChannelToRecordingLayer( channels[ i ] ); // calls log->CreateNewLayer()
+ }
+
+ // Now add values to channel logs
+ for ( i = 0; i < c; ++i )
+ {
+ CDmeChannel *channel = channels[ i ];
+ CDmeTypedLog< float > *pLog = CastElement< CDmeTypedLog< float > >( channel->GetLog() );
+ Assert( pLog );
+
+ pLog->StampKeyAtHead( tHeadPosition, tHeadPosition, ts, value );
+ }
+
+ // Flattens the layers
+ g_pChannelRecordingMgr->FinishLayerRecording( 0.0f, true );
+
+ if ( params.spew & SPEW_VALUES )
+ {
+ for ( i = 0; i < c; ++i )
+ {
+ CDmeChannel *channel = channels[ i ];
+ CDmeTypedLog< float > *pLog = CastElement< CDmeTypedLog< float > >( channel->GetLog() );
+ Assert( pLog );
+ Assert( pLog->GetNumLayers() == 1 );
+
+ for ( DmeTime_t j = params.mintime; j <= params.maxtime; j += DmeTime_t( 1 ) )
+ {
+ float fval = pLog->GetValue( j );
+ Msg( "%d %f\n", j.GetTenthsOfMS(), fval );
+ }
+ }
+ }
+
+ if ( params.spew & SPEW_KEYS )
+ {
+ for ( i = 0; i < c; ++i )
+ {
+ CDmeChannel *channel = channels[ i ];
+ CDmeTypedLog< float > *pLog = CastElement< CDmeTypedLog< float > >( channel->GetLog() );
+ Assert( pLog );
+ Assert( pLog->GetNumLayers() == 1 );
+
+ int kc = pLog->GetKeyCount();
+ for ( j = 0; j < kc; ++j )
+ {
+ DmeTime_t time = pLog->GetKeyTime( j );
+
+ float fval = pLog->GetValue( time );
+ Msg( "%d %f %f\n", j, time.GetSeconds(), fval );
+ }
+ }
+ }
+
+ // Now test creating a layer and "undo/redo" of the layer
+ if ( params.testundo )
+ {
+ g_pDataModel->Undo();
+ g_pDataModel->Redo();
+ }
+}
+
+DEFINE_TESTCASE_NOSUITE( DmxTestDmeLogLayers )
+{
+ Msg( "Running CDmeTypedLog<float> layering tests...\n" );
+
+#ifdef _DEBUG
+ int nStartingCount = g_pDataModel->GetAllocatedElementCount();
+#endif
+
+ CUtlVector< CDmeChannel * > channels;
+
+ DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( "<DmxTestDmeLogLayers>" );
+
+ CreateChannels( NUM_CHANNELS, channels, fileid );
+
+ TestParams_t params;
+ {
+ params.testundo = false;
+ params.usecurves = false;
+ params.defaultcurve = CURVE_DEFAULT;
+ params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 100 ), DmeTime_t( 10 ), CURVE_DEFAULT, TestLayer_t::TYPE_SIMPLESLOPE );
+ params.AddLayer( DmeTime_t( 5 ), DmeTime_t( 95 ), DmeTime_t( 10 ), CURVE_DEFAULT, TestLayer_t::TYPE_SIMPLESLOPE );
+ RunLayerTest( "One-Layer", channels, params );
+ params.Reset();
+ }
+
+ // Single layer using lerp everywhere
+ // -----------------------
+ {
+ params.testundo = false;
+ params.usecurves = true;
+ params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP;
+ params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 100 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE );
+ RunLayerTest( "One-Layer Lerp", channels, params );
+ params.Reset();
+ }
+
+ // Two layers using lerp
+ // ----------------------------
+ // ------------------------
+ {
+ params.testundo = false;
+ params.usecurves = true;
+ params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP;
+ params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 100 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE );
+ params.AddLayer( DmeTime_t( 5 ), DmeTime_t( 95 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE );
+ RunLayerTest( "Two-Layer Lerp (contained)", channels, params );
+ params.Reset();
+ }
+
+ // Two layers using CURVE_EASE_IN_TO_EASE_OUT, there should be some disparity
+ // ----------------------------
+ // ------------------------
+ {
+ params.testundo = false;
+ params.usecurves = true;
+ params.defaultcurve = CURVE_EASE_IN_TO_EASE_OUT;
+ params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 100 ), DmeTime_t( 10 ), CURVE_EASE_IN_TO_EASE_OUT, TestLayer_t::TYPE_SIMPLESLOPE );
+ params.AddLayer( DmeTime_t( 5 ), DmeTime_t( 95 ), DmeTime_t( 10 ), CURVE_EASE_IN_TO_EASE_OUT, TestLayer_t::TYPE_SIMPLESLOPE );
+ RunLayerTest( "Two-Layer Ease In/Out (contained)", channels, params );
+ params.Reset();
+ }
+
+ // Two layers using lerp
+ // ----------------------------
+ // ---------
+ {
+ params.testundo = false;
+ params.usecurves = true;
+ params.mintime = DmeTime_t( -20 );
+ params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP;
+ params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 100 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE );
+ params.AddLayer( DmeTime_t( -20 ), DmeTime_t( 20 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE );
+ RunLayerTest( "Two-Layer Lerp (overhang start)", channels, params );
+ params.Reset();
+ }
+
+ // Two layers using lerp
+ // ----------------------------
+ // ------------
+ {
+ params.testundo = false;
+ params.usecurves = true;
+ params.maxtime = DmeTime_t( 120 );
+ params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP;
+ params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 100 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE );
+ params.AddLayer( DmeTime_t( 80 ), DmeTime_t( 120 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE );
+ RunLayerTest( "Two-Layer Lerp (overhang end)", channels, params );
+ params.Reset();
+ }
+ // Three layers using lerp
+ // -------------
+ // ----- -----
+ {
+ params.testundo = false;
+ params.usecurves = true;
+ params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP;
+ params.mintime = DmeTime_t( -12 );
+ params.maxtime = DmeTime_t( 115 );
+ params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 100 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE );
+ params.AddLayer( DmeTime_t( -12 ), DmeTime_t( 12 ), DmeTime_t( 4 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE );
+ params.AddLayer( DmeTime_t( 85 ), DmeTime_t( 115 ), DmeTime_t( 5 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE );
+ RunLayerTest( "Three-Layer Lerp (overhang start + end)", channels, params );
+ params.Reset();
+ }
+
+ // Three layers using lerp
+ // -------------
+ // -----
+ // --
+ {
+ params.testundo = false;
+ params.usecurves = true;
+ params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP;
+ params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 100 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE );
+ params.AddLayer( DmeTime_t( 25 ), DmeTime_t( 75 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE );
+ params.AddLayer( DmeTime_t( 40 ), DmeTime_t( 60 ), DmeTime_t( 5 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE );
+ RunLayerTest( "Three-Layer Lerp (layer inside layer)", channels, params );
+ params.Reset();
+ }
+
+ // Three layers using lerp
+ // -------------
+ // -----
+ // --
+ {
+ params.testundo = false;
+ params.usecurves = true;
+ params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP;
+ params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 100 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE );
+ params.AddLayer( DmeTime_t( 25 ), DmeTime_t( 75 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE );
+ params.AddLayer( DmeTime_t( 70 ), DmeTime_t( 80 ), DmeTime_t( 2 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE );
+ RunLayerTest( "Three-Layer Lerp (first layer contained, second layer overlapping first at end)", channels, params );
+ params.Reset();
+ }
+
+ // Three layers using lerp
+ // -------------
+ // -----
+ // --
+ {
+ params.testundo = false;
+ params.usecurves = true;
+ params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP;
+ params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 100 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE );
+ params.AddLayer( DmeTime_t( 25 ), DmeTime_t( 75 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE );
+ params.AddLayer( DmeTime_t( 15 ), DmeTime_t( 35 ), DmeTime_t( 5 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE );
+ RunLayerTest( "Three-Layer Lerp (first layer contained, second layer overlapping first at start)", channels, params );
+ params.Reset();
+ }
+
+ // Four layers using lerp
+ // ---------------
+ // -----
+ // ----
+ // -------
+ {
+ params.testundo = false;
+ params.usecurves = true;
+ // params.spewnontopmostlayers = true;
+ params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP;
+ params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 100 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_CONSTANT, 20.0f );
+ params.AddLayer( DmeTime_t( 15 ), DmeTime_t( 40 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE );
+ params.AddLayer( DmeTime_t( 60 ), DmeTime_t( 85 ), DmeTime_t( 5 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE );
+ params.AddLayer( DmeTime_t( 35 ), DmeTime_t( 79 ), DmeTime_t( 5 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE );
+ RunLayerTest( "Four-Layer Lerp (top overlapping end of 1st and start of 2nd layer)", channels, params );
+ params.Reset();
+ }
+
+ // Single layer using lerp everywhere
+ // -----------------------
+ {
+ params.testundo = false;
+ params.usecurves = true;
+ params.spew = 0; //SPEW_VALUES | SPEW_KEYS;
+ params.mintime = DmeTime_t( 0 );
+ params.maxtime = DmeTime_t( 10000 );
+ params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP;
+ params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 10000 ), DmeTime_t( 20 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SINE, 100.0f );
+
+ DmeTime_t tHeadPosition = DmeTime_t( 5000 );
+
+ DmeLog_TimeSelection_t ts;
+ ts.m_nTimes[ TS_LEFT_FALLOFF ] = tHeadPosition + DmeTime_t( -987 );
+ ts.m_nTimes[ TS_LEFT_HOLD ] = ts.m_nTimes[ TS_RIGHT_HOLD ] = tHeadPosition;
+ ts.m_nTimes[ TS_RIGHT_FALLOFF ] = tHeadPosition + DmeTime_t( 1052 );
+ ts.m_nFalloffInterpolatorTypes[ 0 ] = ts.m_nFalloffInterpolatorTypes[ 1 ] = INTERPOLATE_EASE_INOUT;
+
+ // Resample at 50 msec intervals
+ ts.m_bResampleMode = true;
+ ts.m_nResampleInterval = DmeTime_t( 50 );
+
+ ///params.spew |= SPEW_KEYS | SPEW_VALUES;
+
+ RunTimeSelectionTest( "One-Layer Time Selection at 50, falloff 25, EASE_INOUT interp", channels, params, tHeadPosition, ts, 250 );
+
+ params.purgevalues = false;
+ // params.spew |= SPEW_VALUES;
+
+ // Shift the head and do it all again
+ tHeadPosition = DmeTime_t( 2000 );
+ ts.m_nTimes[ TS_LEFT_FALLOFF ] = DmeTime_t( 1487 );
+ ts.m_nTimes[ TS_LEFT_HOLD ] = ts.m_nTimes[ TS_RIGHT_HOLD ] = tHeadPosition;
+ ts.m_nTimes[ TS_RIGHT_FALLOFF ] = tHeadPosition + DmeTime_t( 631 );
+
+ RunTimeSelectionTest( "2nd layer", channels, params, tHeadPosition, ts, 500 );
+ params.Reset();
+ }
+ // Single layer using lerp everywhere
+ // -----------------------
+ {
+ params.testundo = true;
+ params.usecurves = true;
+ params.spew = 0; //SPEW_VALUES | SPEW_KEYS;
+ params.mintime = DmeTime_t( 0 );
+ params.maxtime = DmeTime_t( 1000 );
+ params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP;
+ params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 1000 ), DmeTime_t( 20 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_CONSTANT, 100.0f );
+
+ DmeTime_t tHeadPosition = DmeTime_t( 500 );
+ DmeLog_TimeSelection_t ts;
+ ts.m_nTimes[ TS_LEFT_FALLOFF ] = tHeadPosition + DmeTime_t( -100 );
+ ts.m_nTimes[ TS_LEFT_HOLD ] = ts.m_nTimes[ TS_RIGHT_HOLD ] = tHeadPosition;
+ ts.m_nTimes[ TS_RIGHT_FALLOFF ] = tHeadPosition + DmeTime_t( 100 );
+ ts.m_nFalloffInterpolatorTypes[ 0 ] = ts.m_nFalloffInterpolatorTypes[ 1 ] = INTERPOLATE_LINEAR_INTERP;
+
+ // Resample at 50 msec intervals
+ ts.m_bResampleMode = true;
+ ts.m_nResampleInterval = DmeTime_t( 10 );
+
+// params.spew |= SPEW_VALUES;
+
+ RunTimeSelectionTest( "Resetting layer", channels, params, tHeadPosition, ts, 200 );
+
+ params.purgevalues = false;
+ //params.spew |= SPEW_VALUES;
+
+ // Shift the head and do it all again
+ //ts.m_nRelativeFalloffTimes[ 0 ] = 1487 - 2000;
+ //ts.m_nRelativeHoldTimes[ 0 ] = ts.m_nRelativeHoldTimes[ 1 ] = 0;
+ //ts.m_nRelativeFalloffTimes[ 1 ] = 631;
+ //ts.SetHeadPosition( 2000 );
+
+ RunTimeSelectionTest( "2nd layer", channels, params, tHeadPosition, ts, 110 );
+ params.Reset();
+ }
+// g_pDataModel->TraceUndo( true );
+
+ // Test abort undo stuff
+ for ( int i = 0; i < 2; ++i )
+ // Four layers using lerp
+ // ---------------
+ // -----
+ // ----
+ // -------
+ {
+ params.testundo = false;
+ params.testabort = i != 1 ? true : false;
+ params.usecurves = false;
+ // params.spewnontopmostlayers = true;
+ params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP;
+ params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 10 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_CONSTANT, 20.0f );
+ params.AddLayer( DmeTime_t( 5 ), DmeTime_t( 6 ), DmeTime_t( 1 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE );
+ RunLayerTest( "Four-Layer Lerp (top overlapping end of 1st and start of 2nd layer)", channels, params );
+ params.Reset();
+ }
+
+ // g_pDataModel->TraceUndo( false );
+
+
+ //DestroyChannels( channels );
+
+ g_pDataModel->ClearUndo();
+
+ g_pDataModel->RemoveFileId( fileid );
+
+#ifdef _DEBUG
+ int nEndingCount = g_pDataModel->GetAllocatedElementCount();
+ AssertEquals( nEndingCount, nStartingCount );
+ if ( nEndingCount != nStartingCount )
+ {
+ for ( DmElementHandle_t hElement = g_pDataModel->FirstAllocatedElement() ;
+ hElement != DMELEMENT_HANDLE_INVALID;
+ hElement = g_pDataModel->NextAllocatedElement( hElement ) )
+ {
+ CDmElement *pElement = g_pDataModel->GetElement( hElement );
+ Assert( pElement );
+ if ( !pElement )
+ return;
+
+ Msg( "[%s : %s] in memory\n", pElement->GetName(), pElement->GetTypeString() );
+ }
+ }
+#endif
+}
+
+DEFINE_TESTCASE_NOSUITE( DmxTestDmeLogLayersUndo )
+{
+ Msg( "Running CDmeTypedLog<float> layering UNDO tests...\n" );
+
+#ifdef _DEBUG
+ int nStartingCount = g_pDataModel->GetAllocatedElementCount();
+#endif
+
+ CUtlVector< CDmeChannel * > channels;
+
+ DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( "<DmxTestDmeLogLayersUndo>" );
+
+ CreateChannels( NUM_CHANNELS, channels, fileid );
+
+ TestParams_t params;
+
+// g_pDataModel->TraceUndo( true );
+
+ // Test abort undo stuff
+ for ( int i = 0; i < 2; ++i )
+ {
+ params.testundo = false;
+ params.testabort = true;
+ params.usecurves = false;
+ // params.spewnontopmostlayers = true;
+ params.defaultcurve = CURVE_LINEAR_INTERP_TO_LINEAR_INTERP;
+ params.AddLayer( DmeTime_t( 0 ), DmeTime_t( 1000 ), DmeTime_t( 10 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_CONSTANT, 20.0f );
+ params.AddLayer( DmeTime_t( 100 ), DmeTime_t( 900 ), DmeTime_t( 5 ), CURVE_LINEAR_INTERP_TO_LINEAR_INTERP, TestLayer_t::TYPE_SIMPLESLOPE );
+ RunLayerTest( "Abort undo", channels, params );
+ params.Reset();
+ }
+
+// g_pDataModel->TraceUndo( false );
+
+ g_pDataModel->ClearUndo();
+ g_pDataModel->RemoveFileId( fileid );
+
+#ifdef _DEBUG
+ int nEndingCount = g_pDataModel->GetAllocatedElementCount();
+ AssertEquals( nEndingCount, nStartingCount );
+ if ( nEndingCount != nStartingCount )
+ {
+ for ( DmElementHandle_t hElement = g_pDataModel->FirstAllocatedElement() ;
+ hElement != DMELEMENT_HANDLE_INVALID;
+ hElement = g_pDataModel->NextAllocatedElement( hElement ) )
+ {
+ CDmElement *pElement = g_pDataModel->GetElement( hElement );
+ Assert( pElement );
+ if ( !pElement )
+ return;
+
+ Msg( "[%s : %s] in memory\n", pElement->GetName(), pElement->GetTypeString() );
+ }
+ }
+#endif
+}