/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
static const float ROTATION_EPSILON = 0.0001f;
static const float VECTOR4_EPSILON = 0.0001f;
+static const float VECTOR3_EPSILON = 0.0001f;
// Functor to test whether a Finish signal is emitted
struct AnimationFinishCheck
END_TEST;
}
-int UtcDaliAnimationSetEndActioN(void)
+int UtcDaliAnimationSetEndActionN(void)
{
TestApplication application;
END_TEST;
}
+
+namespace // Purposefully left this in the middle as the values in this namespace are only used for the subsequent two test cases
+{
+enum TestFunction
+{
+ STOP,
+ CLEAR
+};
+
+void CheckPropertyValuesWhenCallingAnimationMethod( TestFunction functionToTest, const char * testName )
+{
+ tet_printf( "Testing %s\n", testName );
+
+ // When an Animation::Stop() or Animation::Clear() is called, the event-side property needs to be updated appropriately
+ // This test checks that that is being done
+
+ const float durationSeconds( 1.0f );
+ unsigned int halfAnimationDuration( static_cast< unsigned int >( durationSeconds * 1000.0f * 0.5f ) );
+ const Vector3 originalPosition( Vector3::ZERO );
+ const Vector3 targetPosition( 10.0f, 10.0f, 10.0f );
+ const Vector3 halfWayToTarget( targetPosition * 0.5f );
+
+ struct ExpectedValue
+ {
+ Animation::EndAction endAction;
+ Vector3 expectedGetPropertyValue;
+ };
+
+ ExpectedValue expectedValueTable[] =
+ {
+ { Animation::Bake, halfWayToTarget }, // When baking, the current value is the final value.
+ { Animation::BakeFinal, targetPosition }, // When BakeFinal, we should jump to the final value when clearing or stopping.
+ { Animation::Discard, originalPosition }, // When discarding, we should jump back to the original value when clearing or stopping.
+ };
+ const auto expectedValueTableCount = sizeof( expectedValueTable ) / sizeof( ExpectedValue );
+
+ for( auto i = 0u; i < expectedValueTableCount; ++i )
+ {
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ Stage::GetCurrent().Add(actor);
+
+ // Build the animation
+ Animation animation = Animation::New( durationSeconds );
+ animation.SetEndAction( expectedValueTable[ i ].endAction );
+ animation.AnimateTo( Property( actor, Actor::Property::POSITION ), targetPosition, AlphaFunction::LINEAR );
+
+ // Start the animation
+ animation.Play();
+
+ application.SendNotification();
+ application.Render( halfAnimationDuration );
+
+ // Stop or Clear the animation early, both have the same effect
+ if( functionToTest == TestFunction::STOP )
+ {
+ animation.Stop();
+ }
+ else
+ {
+ animation.Clear();
+ }
+
+ // The event side property should be set the expected value immediately, the update side property will still only be halfway as we haven't run an update yet
+ DALI_TEST_EQUALS( actor.GetProperty( Actor::Property::POSITION ).Get< Vector3 >(), expectedValueTable[ i ].expectedGetPropertyValue, VECTOR3_EPSILON, TEST_LOCATION );
+ DALI_TEST_EQUALS( actor.GetCurrentProperty( Actor::Property::POSITION ).Get< Vector3 >(), halfWayToTarget, VECTOR3_EPSILON, TEST_LOCATION );
+
+ // After one frame, both values should match regardless of the End Action
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( actor.GetProperty( Actor::Property::POSITION ).Get< Vector3 >(), expectedValueTable[ i ].expectedGetPropertyValue, VECTOR3_EPSILON, TEST_LOCATION );
+ DALI_TEST_EQUALS( actor.GetCurrentProperty( Actor::Property::POSITION ).Get< Vector3 >(), expectedValueTable[ i ].expectedGetPropertyValue, VECTOR3_EPSILON, TEST_LOCATION );
+ }
+}
+} // unnamed namespace
+
+int UtcDaliAnimationStopPropertyValue(void)
+{
+ CheckPropertyValuesWhenCallingAnimationMethod( TestFunction::STOP, "UtcDaliAnimationStopPropertyValue" );
+ END_TEST;
+}
+
+int UtcDaliAnimationClearPropertyValue(void)
+{
+ CheckPropertyValuesWhenCallingAnimationMethod( TestFunction::CLEAR, "UtcDaliAnimationStopPropertyValue" );
+ END_TEST;
+}
+
+int UtcDaliAnimationPausePropertyValue(void)
+{
+ const float durationSeconds( 1.0f );
+ unsigned int halfAnimationDuration( static_cast< unsigned int >( durationSeconds * 1000.0f * 0.5f ) );
+ const Vector3 originalPosition( Vector3::ZERO );
+ const Vector3 targetPosition( 10.0f, 10.0f, 10.0f );
+ const Vector3 halfWayToTarget( targetPosition * 0.5f );
+
+ Animation::EndAction endActions[] =
+ {
+ Animation::Bake,
+ Animation::BakeFinal,
+ Animation::Discard,
+ };
+ const auto endActionCount = sizeof( endActions ) / sizeof( endActions[0] );
+
+ // For all end actions, when pausing, we stay at the current value
+ for( auto i = 0u; i < endActionCount; ++i )
+ {
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ Stage::GetCurrent().Add(actor);
+
+ // Build the animation
+ Animation animation = Animation::New( durationSeconds );
+ animation.SetEndAction( endActions[ i ] );
+ animation.AnimateTo( Property( actor, Actor::Property::POSITION ), targetPosition, AlphaFunction::LINEAR );
+
+ // Start the animation
+ animation.Play();
+
+ application.SendNotification();
+ application.Render( halfAnimationDuration );
+
+ // Puase the animation early
+ animation.Pause();
+
+ // The event side property should be set the current value immediately, the update side property will still only be halfway
+ DALI_TEST_EQUALS( actor.GetProperty( Actor::Property::POSITION ).Get< Vector3 >(), halfWayToTarget, VECTOR3_EPSILON, TEST_LOCATION );
+ DALI_TEST_EQUALS( actor.GetCurrentProperty( Actor::Property::POSITION ).Get< Vector3 >(), halfWayToTarget, VECTOR3_EPSILON, TEST_LOCATION );
+
+ // After one frame, both values should match regardless of the End Action
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( actor.GetProperty( Actor::Property::POSITION ).Get< Vector3 >(), halfWayToTarget, VECTOR3_EPSILON, TEST_LOCATION );
+ DALI_TEST_EQUALS( actor.GetCurrentProperty( Actor::Property::POSITION ).Get< Vector3 >(), halfWayToTarget, VECTOR3_EPSILON, TEST_LOCATION );
+ }
+
+ END_TEST;
+}
/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
mState = Dali::Animation::PLAYING;
- NotifyObjects();
+ NotifyObjects( Notify::USE_TARGET_VALUE );
SendFinalProgressNotificationMessage();
mState = Dali::Animation::PLAYING;
- NotifyObjects();
+ NotifyObjects( Notify::USE_TARGET_VALUE );
SendFinalProgressNotificationMessage();
mState = Dali::Animation::PLAYING;
- NotifyObjects();
+ NotifyObjects( Notify::USE_TARGET_VALUE );
SendFinalProgressNotificationMessage();
// mAnimation is being used in a separate thread; queue a Pause message
PauseAnimationMessage( mEventThreadServices, *mAnimation );
+
+ // Notify the objects with the _paused_, i.e. current values
+ NotifyObjects( Notify::FORCE_CURRENT_VALUE );
}
Dali::Animation::State Animation::GetState() const
// mAnimation is being used in a separate thread; queue a Stop message
StopAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
+
+ // Only notify the objects with the _stopped_, i.e. current values if the end action is set to BAKE
+ if( mEndAction == EndAction::Bake )
+ {
+ NotifyObjects( Notify::USE_CURRENT_VALUE );
+ }
}
void Animation::Clear()
{
DALI_ASSERT_DEBUG(mAnimation);
+ // Only notify the objects with the current values if the end action is set to BAKE
+ if( mEndAction == EndAction::Bake )
+ {
+ NotifyObjects( Notify::USE_CURRENT_VALUE );
+ }
+
// Remove all the connectors
mConnectors.Clear();
return ( ( lhs.timePeriod.delaySeconds + lhs.timePeriod.durationSeconds ) < ( rhs.timePeriod.delaySeconds + rhs.timePeriod.durationSeconds ) );
}
-void Animation::NotifyObjects()
+void Animation::NotifyObjects( Animation::Notify notifyValueType )
{
- if( mEndAction != EndAction::Discard ) // If the animation is discarded, then we do not want to change the target values
+ // If the animation is discarded, then we do not want to change the target values unless we want to force the current values
+ if( mEndAction != EndAction::Discard || notifyValueType == Notify::FORCE_CURRENT_VALUE )
{
// Sort according to end time with earlier end times coming first, if the end time is the same, then the connectors are not moved
- std::stable_sort( mConnectorTargetValues.begin(), mConnectorTargetValues.end(), CompareConnectorEndTimes );
+ // Only do this if we're using the target value
+ if( notifyValueType == Notify::USE_TARGET_VALUE )
+ {
+ std::stable_sort( mConnectorTargetValues.begin(), mConnectorTargetValues.end(), CompareConnectorEndTimes );
+ }
// Loop through all connector target values sorted by increasing end time
ConnectorTargetValuesContainer::const_iterator iter = mConnectorTargetValues.begin();
Object* object = connector->GetObject();
if( object )
{
- object->NotifyPropertyAnimation( *this, connector->GetPropertyIndex(), iter->targetValue, iter->animatorType );
+ const auto propertyIndex = connector->GetPropertyIndex();
+ object->NotifyPropertyAnimation(
+ *this,
+ propertyIndex,
+ ( notifyValueType == Notify::USE_TARGET_VALUE ) ? iter->targetValue : object->GetCurrentProperty( propertyIndex ),
+ iter->animatorType );
}
}
}