Ensure animations take TimePeriod into account when running animators 02/128802/3
authorAdeel Kazmi <adeel.kazmi@samsung.com>
Thu, 11 May 2017 11:07:19 +0000 (12:07 +0100)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Fri, 12 May 2017 14:23:33 +0000 (15:23 +0100)
Issue is that when animating the same property using animators, the final value would be whatever animator came last
rather than the taking the end time of the animator into account.

Now, we order the animators according to the end time.

Change-Id: Ic51513dda942caaf9a9c7b339b5bd41431f5116c

automated-tests/src/dali/utc-Dali-Animation.cpp
dali/internal/update/animation/scene-graph-animation.cpp
dali/internal/update/animation/scene-graph-animator.h
dali/public-api/animation/animation.h

index 1565169..36fb592 100644 (file)
@@ -10506,3 +10506,88 @@ int UtcDaliAnimationSetAndGetTargetBeforePlayMulitpleAnimatorsSizeAndPositionCol
 
   END_TEST;
 }
+
+int UtcDaliAnimationTimePeriodOrder(void)
+{
+  tet_infoline("Animate the same property with different time periods and ensure it runs correctly and ends up in the right place" );
+
+  TestApplication application;
+
+  Actor actor = Actor::New();
+  Stage::GetCurrent().Add( actor );
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS( actor.GetCurrentPosition(), Vector3::ZERO, TEST_LOCATION );
+
+  tet_infoline( "With two AnimateTo calls" );
+
+  Animation animation = Animation::New( 0.0f );
+  animation.AnimateTo( Property( actor, Actor::Property::POSITION_X ), 100.0f, TimePeriod( 3.0f, 1.0f ) );
+  animation.AnimateTo( Property( actor, Actor::Property::POSITION_X ), 10.0f, TimePeriod( 1.0f, 1.0f ) );
+  animation.Play();
+
+  application.SendNotification();
+  application.Render(5000); // After the animation is complete
+
+  DALI_TEST_EQUALS( actor.GetCurrentPosition(), Vector3( 100.0f, 0.0f, 0.0f ), TEST_LOCATION );
+
+  tet_infoline( "Same animation again but in a different order - should yield the same result" );
+
+  actor.SetX( 0.0f );
+  application.SendNotification();
+  application.Render();
+
+  animation = Animation::New( 0.0f );
+  animation.AnimateTo( Property( actor, Actor::Property::POSITION_X ), 10.0f, TimePeriod( 1.0f, 1.0f ) );
+  animation.AnimateTo( Property( actor, Actor::Property::POSITION_X ), 100.0f, TimePeriod( 3.0f, 1.0f ) );
+  animation.Play();
+
+  application.SendNotification();
+  application.Render(5000); // After the animation is complete
+
+  DALI_TEST_EQUALS( actor.GetCurrentPosition(), Vector3( 100.0f, 0.0f, 0.0f ), TEST_LOCATION );
+
+  tet_infoline( "Now with several AnimateTo calls" );
+
+  actor.SetX( 0.0f );
+  application.SendNotification();
+  application.Render();
+
+  animation = Animation::New( 0.0f );
+  animation.AnimateTo( Property( actor, Actor::Property::POSITION_X ), 1000.0f, TimePeriod( 4.0f, 2.0f ) );
+  animation.AnimateTo( Property( actor, Actor::Property::POSITION_X ), 145.0f, TimePeriod( 3.0f, 10.0f ) );
+  animation.AnimateTo( Property( actor, Actor::Property::POSITION_X ), 109.0f, TimePeriod( 1.0f, 1.0f ) );
+  animation.AnimateTo( Property( actor, Actor::Property::POSITION_X ), 1.0f, TimePeriod( 3.0f, 4.0f ) );
+  animation.AnimateTo( Property( actor, Actor::Property::POSITION_X ), 200.0f, TimePeriod( 2.0f, 5.0f ) );
+  animation.AnimateTo( Property( actor, Actor::Property::POSITION_X ), 10.0f, TimePeriod( 10.0f, 2.0f ) );
+  animation.Play();
+
+  application.SendNotification();
+  application.Render(14000); // After the animation is complete
+
+  DALI_TEST_EQUALS( actor.GetCurrentPosition(), Vector3( 145.0f, 0.0f, 0.0f ), TEST_LOCATION );
+
+  tet_infoline( "Same animation again but in a different order - should end up at the same point" );
+
+  actor.SetX( 0.0f );
+  application.SendNotification();
+  application.Render();
+
+  animation = Animation::New( 0.0f );
+  animation.AnimateTo( Property( actor, Actor::Property::POSITION_X ), 200.0f, TimePeriod( 2.0f, 5.0f ) );
+  animation.AnimateTo( Property( actor, Actor::Property::POSITION_X ), 10.0f, TimePeriod( 10.0f, 2.0f ) );
+  animation.AnimateTo( Property( actor, Actor::Property::POSITION_X ), 145.0f, TimePeriod( 3.0f, 10.0f ) );
+  animation.AnimateTo( Property( actor, Actor::Property::POSITION_X ), 1000.0f, TimePeriod( 4.0f, 2.0f ) );
+  animation.AnimateTo( Property( actor, Actor::Property::POSITION_X ), 1.0f, TimePeriod( 3.0f, 4.0f ) );
+  animation.AnimateTo( Property( actor, Actor::Property::POSITION_X ), 109.0f, TimePeriod( 1.0f, 1.0f ) );
+  animation.Play();
+
+  application.SendNotification();
+  application.Render(14000); // After the animation is complete
+
+  DALI_TEST_EQUALS( actor.GetCurrentPosition(), Vector3( 145.0f, 0.0f, 0.0f ), TEST_LOCATION );
+
+  END_TEST;
+}
index 1cf77e5..3f33f3c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
@@ -42,8 +42,14 @@ inline void WrapInPlayRange( float& elapsed, const Dali::Vector2& playRangeSecon
   }
 }
 
+/// Compares the end times of the animators and if the end time is less, then it is moved earlier in the list. If end times are the same, then no change.
+bool CompareAnimatorEndTimes( const Dali::Internal::SceneGraph::AnimatorBase* lhs, const Dali::Internal::SceneGraph::AnimatorBase* rhs )
+{
+  return ( ( lhs->GetInitialDelay() + lhs->GetDuration() ) < ( rhs->GetInitialDelay() + rhs->GetDuration() ) );
 }
 
+} // unnamed namespace
+
 namespace Dali
 {
 
@@ -132,6 +138,9 @@ void Animation::SetPlayRange( const Vector2& range )
 
 void Animation::Play()
 {
+  // Sort according to end time with earlier end times coming first, if the end time is the same, then the animators are not moved
+  std::stable_sort( mAnimators.Begin(), mAnimators.End(), CompareAnimatorEndTimes );
+
   mState = Playing;
 
   if ( mSpeedFactor < 0.0f && mElapsedSeconds <= mPlayRange.x*mDurationSeconds )
index b3694b7..4c7088a 100644 (file)
@@ -2,7 +2,7 @@
 #define __DALI_INTERNAL_SCENE_GRAPH_ANIMATOR_H__
 
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
@@ -106,7 +106,7 @@ public:
    * Retrieve the duration of the animator.
    * @return The duration in seconds.
    */
-  float GetDuration()
+  float GetDuration() const
   {
     return mDurationSeconds;
   }
@@ -125,7 +125,7 @@ public:
    * Retrieve the initial delay of the animator.
    * @return The delay in seconds.
    */
-  float GetInitialDelay()
+  float GetInitialDelay() const
   {
     return mInitialDelaySeconds;
   }
index 34ced29..7480ff1 100644 (file)
@@ -2,7 +2,7 @@
 #define __DALI_ANIMATION_H__
 
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 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.
@@ -100,6 +100,8 @@ class Animation;
  * The overall animation time is superseded by the values given in the TimePeriod structure used when calling the AnimateTo(), AnimateBy(), AnimateBetween() and Animate() methods.
  * If any of the individual calls to those functions exceeds the overall animation time, then the overall animation time is automatically extended.
  *
+ * Using AnimateTo and AnimateBy for the same property of the same Actor will yield undefined behaviour especially if the TimePeriod overlaps.
+ *
  * Signals
  * | %Signal Name | Method                   |
  * |--------------|--------------------------|