Implement Animation SetLoopMode and GetLoopMode API 33/140933/6
authorSeoyeon Kim <seoyeon2.kim@samsung.com>
Thu, 27 Jul 2017 07:17:20 +0000 (16:17 +0900)
committerSeoyeon Kim <seoyeon2.kim@samsung.com>
Wed, 9 Aug 2017 04:06:50 +0000 (13:06 +0900)
- Animation can play forwards and then runs backwards again using SetLoopMode().
- Enumeration 'LoopingMode' is one of RESTART and AUTO_REVERSE.

Change-Id: Ideecab8060d242874cb8997918b0a6e9c7734dd9
Signed-off-by: Seoyeon Kim <seoyeon2.kim@samsung.com>
automated-tests/src/dali/utc-Dali-Animation.cpp
dali/devel-api/animation/animation-devel.cpp
dali/devel-api/animation/animation-devel.h
dali/internal/event/animation/animation-impl.cpp
dali/internal/event/animation/animation-impl.h
dali/internal/update/animation/scene-graph-animation.cpp
dali/internal/update/animation/scene-graph-animation.h
dali/internal/update/animation/scene-graph-animator.h
dali/public-api/animation/animation.h

index d753f98..9c2f9be 100644 (file)
@@ -11537,6 +11537,303 @@ int UtcDaliAnimationPlayAfterP3(void)
   END_TEST;
 }
 
+int UtcDaliAnimationSetLoopingModeP(void)
+{
+  // Test Loop forever and Loop mode being set
+  TestApplication application;
+  Stage stage( Stage::GetCurrent() );
+
+  // Default: LoopingMode::RESTART
+  {
+    Actor actor = Actor::New();
+    stage.Add( actor );
+
+    float durationSeconds( 1.0f );
+    Animation animation = Animation::New( durationSeconds );
+    DALI_TEST_CHECK( DevelAnimation::GetLoopingMode( animation ) == DevelAnimation::RESTART );
+
+    Vector3 targetPosition(10.0f, 10.0f, 10.0f);
+    animation.AnimateTo( Property( actor, Actor::Property::POSITION ), targetPosition );
+
+    // Start the animation
+    animation.Play();
+    application.SendNotification();
+    application.Render(static_cast<unsigned int>(durationSeconds*0.5f*1000.0f)/*Only half the animation*/);
+
+    actor.Unparent();
+
+    application.SendNotification();
+    application.Render();
+    DALI_TEST_EQUALS( actor.GetCurrentPosition(), targetPosition, TEST_LOCATION );
+  }
+
+  // LoopingMode::AUTO_REVERSE
+  {
+    Actor actor = Actor::New();
+    stage.Add( actor );
+
+    float durationSeconds( 1.0f );
+    Animation animation = Animation::New( durationSeconds );
+    animation.SetLooping( true );
+
+    bool signalReceived( false );
+    AnimationFinishCheck finishCheck( signalReceived );
+    animation.FinishedSignal().Connect( &application, finishCheck );
+    application.SendNotification();
+
+    Vector3 targetPosition(100.0f, 100.0f, 100.0f);
+    animation.AnimateTo( Property( actor, Actor::Property::POSITION ), targetPosition );
+
+    DevelAnimation::SetLoopingMode( animation, DevelAnimation::LoopingMode::AUTO_REVERSE );
+    DALI_TEST_CHECK( DevelAnimation::GetLoopingMode( animation ) == DevelAnimation::AUTO_REVERSE );
+
+    // Start the animation
+    animation.Play();
+    application.SendNotification();
+    application.Render(0);
+
+    for( int iterations = 0; iterations < 3; ++iterations )
+    {
+      application.Render( static_cast< unsigned int >( durationSeconds * 500.0f )/* 50% time progress */ );
+      application.SendNotification();
+      finishCheck.CheckSignalNotReceived();
+
+      // AUTO_REVERSE mode means, for Animation duration time, the actor starts from the beginning, passes the targetPosition,
+      // and arrives at the beginning.
+      DALI_TEST_EQUALS( actor.GetCurrentPosition(), targetPosition, TEST_LOCATION );
+
+      application.SendNotification();
+      application.Render( static_cast< unsigned int >( durationSeconds * 500.0f )/* 100% time progress */ );
+
+      // We did expect the animation to finish
+      application.SendNotification();
+      finishCheck.CheckSignalNotReceived();
+      DALI_TEST_EQUALS( actor.GetCurrentPosition(), Vector3( 0.0f, 0.0f, 0.0f ), TEST_LOCATION );
+    }
+
+    animation.SetLooping( false );
+    application.SendNotification();
+    application.Render(static_cast< unsigned int >( durationSeconds * 1000.0f ) + 1u /*just beyond the animation duration*/);
+
+    application.SendNotification();
+    finishCheck.CheckSignalReceived();
+
+    DALI_TEST_EQUALS( actor.GetCurrentPosition(), Vector3( 0.0f, 0.0f, 0.0f ), TEST_LOCATION );
+  }
+
+  // LoopingMode::AUTO_REVERSE in Reverse mode, which begin from the end
+  {
+    Actor actor = Actor::New();
+    stage.Add( actor );
+
+    float durationSeconds( 1.0f );
+    Animation animation = Animation::New( durationSeconds );
+    animation.SetLooping( true );
+
+    bool signalReceived( false );
+    AnimationFinishCheck finishCheck( signalReceived );
+    animation.FinishedSignal().Connect( &application, finishCheck );
+    application.SendNotification();
+
+    // Specify a negative multiplier to play the animation in reverse
+    animation.SetSpeedFactor( -1.0f );
+
+    Vector3 targetPosition(100.0f, 100.0f, 100.0f);
+    animation.AnimateTo( Property( actor, Actor::Property::POSITION ), targetPosition );
+
+    DevelAnimation::SetLoopingMode( animation, DevelAnimation::LoopingMode::AUTO_REVERSE );
+    DALI_TEST_CHECK( DevelAnimation::GetLoopingMode( animation ) == DevelAnimation::AUTO_REVERSE );
+
+    // Start the animation
+    animation.Play();
+    application.SendNotification();
+    application.Render(0);
+
+    for( int iterations = 0; iterations < 3; ++iterations )
+    {
+      application.Render( static_cast< unsigned int >( durationSeconds * 500.0f )/* 50% time progress */ );
+      application.SendNotification();
+      finishCheck.CheckSignalNotReceived();
+
+      // Setting a negative speed factor is to play the animation in reverse.
+      // So, when LoopingMode::AUTO_REVERSE and SetSpeedFactor( -1.0f ) is, for Animation duration time,
+      // the actor starts from the targetPosition, passes the beginning, and arrives at the targetPosition.
+      DALI_TEST_EQUALS( actor.GetCurrentPosition(), Vector3( 0.0f, 0.0f, 0.0f ), TEST_LOCATION );
+
+      application.SendNotification();
+      application.Render( static_cast< unsigned int >( durationSeconds * 500.0f )/* 100% time progress */ );
+
+      // We did expect the animation to finish
+      application.SendNotification();
+      finishCheck.CheckSignalNotReceived();
+      DALI_TEST_EQUALS( actor.GetCurrentPosition(), targetPosition, TEST_LOCATION );
+    }
+
+    animation.SetLooping( false );
+    application.SendNotification();
+    application.Render(static_cast< unsigned int >( durationSeconds * 1000.0f ) + 1u /*just beyond the animation duration*/);
+
+    application.SendNotification();
+    finishCheck.CheckSignalReceived();
+
+    DALI_TEST_EQUALS( actor.GetCurrentPosition(), targetPosition, TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliAnimationSetLoopingModeP2(void)
+{
+  // Test Loop Count and Loop mode being set
+  TestApplication application;
+  Stage stage( Stage::GetCurrent() );
+
+  // LoopingMode::AUTO_REVERSE
+  {
+    Actor actor = Actor::New();
+    stage.Add( actor );
+
+    float durationSeconds( 1.0f );
+    Animation animation = Animation::New( durationSeconds );
+    animation.SetLoopCount(3);
+    DALI_TEST_CHECK(animation.IsLooping());
+
+    bool signalReceived( false );
+    AnimationFinishCheck finishCheck( signalReceived );
+    animation.FinishedSignal().Connect( &application, finishCheck );
+    application.SendNotification();
+
+    Vector3 targetPosition(100.0f, 100.0f, 100.0f);
+    animation.AnimateTo( Property( actor, Actor::Property::POSITION ), targetPosition );
+
+    DevelAnimation::SetLoopingMode( animation, DevelAnimation::LoopingMode::AUTO_REVERSE );
+    DALI_TEST_CHECK( DevelAnimation::GetLoopingMode( animation ) == DevelAnimation::AUTO_REVERSE );
+
+    // Start the animation
+    animation.Play();
+
+    application.Render(0);
+    application.SendNotification();
+    application.Render(0);
+    application.SendNotification();
+    application.Render(0);
+    application.SendNotification();
+    application.Render(0);
+    application.SendNotification();
+
+    // Loop
+    float intervalSeconds = 3.0f;
+
+    application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+    // AUTO_REVERSE mode means, for Animation duration time, the actor starts from the beginning, passes the targetPosition,
+    // and arrives at the beginning.
+    DALI_TEST_EQUALS( actor.GetCurrentPosition(), Vector3( 0.0f, 0.0f, 0.0f ), TEST_LOCATION );
+
+    application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+
+    application.Render(0);
+    application.SendNotification();
+    application.Render(0);
+    application.SendNotification();
+    application.Render(0);
+    application.SendNotification();
+    application.Render(0);
+    application.SendNotification();
+    finishCheck.CheckSignalNotReceived();
+
+    application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+
+    application.SendNotification();
+    finishCheck.CheckSignalReceived();
+    DALI_TEST_EQUALS( actor.GetCurrentPosition(), Vector3( 0.0f, 0.0f, 0.0f ), TEST_LOCATION );
+
+    finishCheck.Reset();
+  }
+
+  // LoopingMode::AUTO_REVERSE in Reverse mode, which begin from the end
+  {
+    Actor actor = Actor::New();
+    stage.Add( actor );
+
+    float durationSeconds( 1.0f );
+    Animation animation = Animation::New( durationSeconds );
+    animation.SetLoopCount(3);
+    DALI_TEST_CHECK(animation.IsLooping());
+
+    bool signalReceived( false );
+    AnimationFinishCheck finishCheck( signalReceived );
+    animation.FinishedSignal().Connect( &application, finishCheck );
+    application.SendNotification();
+
+    // Specify a negative multiplier to play the animation in reverse
+    animation.SetSpeedFactor( -1.0f );
+
+    Vector3 targetPosition(100.0f, 100.0f, 100.0f);
+    animation.AnimateTo( Property( actor, Actor::Property::POSITION ), targetPosition );
+
+    DevelAnimation::SetLoopingMode( animation, DevelAnimation::LoopingMode::AUTO_REVERSE );
+    DALI_TEST_CHECK( DevelAnimation::GetLoopingMode( animation ) == DevelAnimation::AUTO_REVERSE );
+
+    // Start the animation
+    animation.Play();
+
+    application.Render(0);
+    application.SendNotification();
+    application.Render(0);
+    application.SendNotification();
+    application.Render(0);
+    application.SendNotification();
+    application.Render(0);
+    application.SendNotification();
+
+    // Loop
+    float intervalSeconds = 3.0f;
+
+    application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+    // Setting a negative speed factor is to play the animation in reverse.
+    // So, when LoopingMode::AUTO_REVERSE and SetSpeedFactor( -1.0f ) is, for Animation duration time,
+    // the actor starts from the targetPosition, passes the beginning, and arrives at the targetPosition.
+    DALI_TEST_EQUALS( actor.GetCurrentPosition(), targetPosition, TEST_LOCATION );
+
+    application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+
+    application.Render(0);
+    application.SendNotification();
+    application.Render(0);
+    application.SendNotification();
+    application.Render(0);
+    application.SendNotification();
+    application.Render(0);
+    application.SendNotification();
+    finishCheck.CheckSignalNotReceived();
+
+    application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+
+    application.SendNotification();
+    finishCheck.CheckSignalReceived();
+    DALI_TEST_EQUALS( actor.GetCurrentPosition(), targetPosition, TEST_LOCATION );
+
+    finishCheck.Reset();
+  }
+
+  END_TEST;
+}
+
+int UtcDaliAnimationGetLoopingModeP(void)
+{
+  TestApplication application;
+
+  Animation animation = Animation::New(1.0f);
+
+  // default mode
+  DALI_TEST_CHECK( DevelAnimation::GetLoopingMode( animation ) == DevelAnimation::RESTART );
+
+  DevelAnimation::SetLoopingMode( animation, DevelAnimation::LoopingMode::AUTO_REVERSE );
+  DALI_TEST_CHECK( DevelAnimation::GetLoopingMode( animation ) == DevelAnimation::AUTO_REVERSE );
+
+  END_TEST;
+}
+
 int UtcDaliAnimationProgressSignalConnectionWithoutProgressMarkerP(void)
 {
   TestApplication application;
index 5484256..79ebbb3 100644 (file)
@@ -45,6 +45,16 @@ void PlayAfter( Animation animation, float delaySeconds )
   GetImplementation( animation ).PlayAfter( delaySeconds );
 }
 
+void SetLoopingMode( Animation animation, LoopingMode loopingMode )
+{
+  GetImplementation( animation ).SetLoopingMode( loopingMode );
+}
+
+LoopingMode GetLoopingMode( Animation animation )
+{
+  return GetImplementation(animation).GetLoopingMode();
+}
+
 } // namespace DevelAnimation
 
 } // namespace Dali
index 4efa70a..209b4b0 100644 (file)
@@ -28,6 +28,15 @@ namespace DevelAnimation
 {
 
 /**
+ * @brief Enumeration for what looping mode is in.
+ */
+enum LoopingMode
+{
+  RESTART,      ///< When the animation arrives at the end in looping mode, the animation restarts from the beginning.
+  AUTO_REVERSE  ///< When the animation arrives at the end in looping mode, the animation reverses direction and runs backwards again.
+};
+
+/**
  * @brief Set progress percentage marker to trigger ProgressHasBeenReachedSignal
  *
  * @param[in] animation the animation object to perform this operation on
@@ -61,6 +70,23 @@ DALI_IMPORT_API Animation::AnimationSignalType& ProgressReachedSignal( Animation
  */
 DALI_IMPORT_API void PlayAfter( Animation animation, float delaySeconds );
 
+/**
+ * @brief Sets the looping mode.
+ *
+ * Animation plays forwards and then restarts from the beginning or runs backwards again.
+ * @param[in] animation The animation object to perform this operation on
+ * @param[in] loopingMode The looping mode is one of RESTART and AUTO_REVERSE
+ */
+DALI_IMPORT_API void SetLoopingMode( Animation animation, LoopingMode loopingMode );
+
+/**
+ * @brief Gets one of the current looping mode.
+ *
+ * @param[in] animation The animation object to perform this operation on
+ * @return The current looping mode
+ */
+DALI_IMPORT_API LoopingMode GetLoopingMode( Animation animation );
+
 } // namespace DevelAnimation
 
 } // namespace Dali
index b7cc899..7290bb3 100644 (file)
@@ -130,7 +130,8 @@ Animation::Animation( EventThreadServices& eventThreadServices, AnimationPlaylis
   mDefaultAlpha( defaultAlpha ),
   mState(Dali::Animation::STOPPED),
   mProgressReachedMarker( 0.0f ),
-  mDelaySeconds( 0.0f )
+  mDelaySeconds( 0.0f ),
+  mAutoReverseEnabled( false )
 {
 }
 
@@ -1023,6 +1024,19 @@ Vector2 Animation::GetPlayRange() const
   return mPlayRange;
 }
 
+void Animation::SetLoopingMode( DevelAnimation::LoopingMode loopingMode )
+{
+  mAutoReverseEnabled = ( loopingMode == DevelAnimation::LoopingMode::AUTO_REVERSE );
+
+  // mAnimation is being used in a separate thread; queue a message to set play range
+  SetLoopingModeMessage( mEventThreadServices, *mAnimation, mAutoReverseEnabled );
+}
+
+DevelAnimation::LoopingMode Animation::GetLoopingMode()
+{
+  return mAutoReverseEnabled ? DevelAnimation::LoopingMode::AUTO_REVERSE : DevelAnimation::LoopingMode::RESTART;
+}
+
 bool Animation::CompareConnectorEndTimes( const Animation::ConnectorTargetValues& lhs, const Animation::ConnectorTargetValues& rhs )
 {
   return ( ( lhs.timePeriod.delaySeconds + lhs.timePeriod.durationSeconds ) < ( rhs.timePeriod.delaySeconds + rhs.timePeriod.durationSeconds ) );
index bf1e628..760ef02 100644 (file)
@@ -23,6 +23,7 @@
 #include <dali/public-api/object/ref-object.h>
 #include <dali/public-api/animation/animation.h>
 #include <dali/public-api/object/base-object.h>
+#include <dali/devel-api/animation/animation-devel.h>
 #include <dali/devel-api/common/owner-container.h>
 #include <dali/internal/event/animation/key-frames-impl.h>
 #include <dali/internal/event/common/event-thread-services.h>
@@ -364,36 +365,46 @@ public:
    */
   void Hide(Actor& actor, float delaySeconds);
 
-  /*
+  /**
    * @copydoc Dali::Animation::SetCurrentProgress()
    */
   void SetCurrentProgress(float progress);
 
-  /*
+  /**
    * @copydoc Dali::Animation::GetCurrentProgress()
    */
   float GetCurrentProgress();
 
-  /*
+  /**
    * @copydoc Dali::Animation::SetSpeedFactor()
    */
   void SetSpeedFactor( float factor );
 
-  /*
+  /**
    * @copydoc Dali::Animation::GetSpeedFactor()
    */
   float GetSpeedFactor() const;
 
-  /*
+  /**
    * @copydoc Dali::Animation::SetPlayRange()
    */
   void SetPlayRange( const Vector2& range );
 
-  /*
-   * @copydoc Dali::Animation::GetPlayRange
+  /**
+   * @copydoc Dali::Animation::GetPlayRange()
    */
   Vector2 GetPlayRange() const;
 
+  /**
+   * @copydoc Dali::Animation::SetLoopingMode()
+   */
+  void SetLoopingMode( Dali::DevelAnimation::LoopingMode loopingMode );
+
+  /**
+   * @copydoc Dali::Animation::GetLoopingMode()
+   */
+  Dali::DevelAnimation::LoopingMode GetLoopingMode();
+
 public: // For connecting animators to animations
 
   /**
@@ -540,6 +551,7 @@ private:
   Dali::Animation::State mState;
   float mProgressReachedMarker;
   float mDelaySeconds;
+  bool mAutoReverseEnabled;  ///< Flag to identify that the looping mode is auto reverse.
 };
 
 } // namespace Internal
index 9ce8ef0..709d7e7 100644 (file)
@@ -77,7 +77,8 @@ Animation::Animation( float durationSeconds, float speedFactor, const Vector2& p
   mEndAction(endAction),
   mDisconnectAction(disconnectAction),
   mState(Stopped),
-  mProgressReachedSignalRequired( false )
+  mProgressReachedSignalRequired( false ),
+  mAutoReverseEnabled( false )
 {
 }
 
@@ -278,6 +279,20 @@ void Animation::OnDestroy(BufferIndex bufferIndex)
   mState = Destroyed;
 }
 
+void Animation::SetLoopingMode( bool loopingMode )
+{
+  mAutoReverseEnabled = loopingMode;
+
+  for ( AnimatorIter iter = mAnimators.Begin(), endIter = mAnimators.End(); iter != endIter; ++iter )
+  {
+    // Send some variables together to figure out the Animation status
+    (*iter)->SetSpeedFactor( mSpeedFactor );
+    (*iter)->SetLoopCount( mLoopCount );
+
+    (*iter)->SetLoopingMode( loopingMode );
+  }
+}
+
 void Animation::AddAnimator( OwnerPointer<AnimatorBase>& animator )
 {
   animator->ConnectToSceneGraph();
index 3e27055..a30a347 100644 (file)
@@ -106,7 +106,7 @@ public:
     return mDurationSeconds;
   }
 
-  /*
+  /**
    * Retrieve the current progress of the animation.
    * @return The current progress as a normalized value between [0,1].
    */
@@ -120,7 +120,7 @@ public:
     return 0.0f;
   }
 
-  /*
+  /**
    * Sets the progress of the animation.
    * @param[in] The new progress as a normalized value between [0,1]
    */
@@ -129,6 +129,10 @@ public:
     mElapsedSeconds = mDurationSeconds * progress;
   }
 
+  /**
+   * Specifies a speed factor for the animation.
+   * @param[in] factor A value which will multiply the velocity
+   */
   void SetSpeedFactor( float factor )
   {
     mSpeedFactor = factor;
@@ -150,7 +154,7 @@ public:
     return mLoopCount != 1;
   }
 
-  /*
+  /**
    * Get the loop count
    * @return the loop count
    */
@@ -262,6 +266,14 @@ public:
   }
 
   /**
+   * @brief Sets the looping mode.
+   *
+   * Animation plays forwards and then restarts from the beginning or runs backwards again.
+   * @param[in] loopingMode True when the looping mode is AUTO_REVERSE
+   */
+  void SetLoopingMode( bool loopingMode );
+
+  /**
    * Add a newly created animator.
    * Animators are automatically removed, when orphaned from an animatable scene object.
    * @param[in] animator The animator to add.
@@ -352,6 +364,7 @@ protected:
   State mState;
 
   bool mProgressReachedSignalRequired;  // Flag to indicate the progress marker was hit
+  bool mAutoReverseEnabled;             // Flag to identify that the looping mode is auto reverse.
 };
 
 }; //namespace SceneGraph
@@ -509,6 +522,17 @@ inline void PlayAfterMessage( EventThreadServices& eventThreadServices, const An
   new (slot) LocalType( &animation, &Animation::PlayAfter, delaySeconds );
 }
 
+inline void SetLoopingModeMessage( EventThreadServices& eventThreadServices, const Animation& animation, bool loopingMode )
+{
+  typedef MessageValue1< Animation, bool > LocalType;
+
+  // Reserve some memory inside the message queue
+  unsigned int* slot = eventThreadServices.ReserveMessageSlot( sizeof( LocalType ) );
+
+  // Construct message in the message queue memory; note that delete should not be called on the return value
+  new (slot) LocalType( &animation, &Animation::SetLoopingMode, loopingMode );
+}
+
 } // namespace SceneGraph
 
 } // namespace Internal
index d1cac15..19d4ecc 100644 (file)
@@ -32,7 +32,7 @@
 #include <dali/public-api/math/quaternion.h>
 #include <dali/public-api/math/radian.h>
 #include <dali/internal/update/animation/property-accessor.h>
-
+#include <dali/integration-api/debug.h>
 
 namespace Dali
 {
@@ -70,11 +70,14 @@ public:
   AnimatorBase()
   : mDurationSeconds(1.0f),
     mIntervalDelaySeconds(0.0f),
+    mSpeedFactor(1.0f),
+    mLoopCount(1),
     mAlphaFunction(AlphaFunction::DEFAULT),
     mDisconnectAction(Dali::Animation::BakeFinal),
     mActive(false),
     mEnabled(true),
-    mConnectedToSceneGraph(false)
+    mConnectedToSceneGraph(false),
+    mAutoReverseEnabled( false )
   {
   }
 
@@ -111,6 +114,36 @@ public:
     return mDurationSeconds;
   }
 
+  void SetSpeedFactor( float factor )
+  {
+    mSpeedFactor = factor;
+  }
+
+  void SetLoopCount(int loopCount)
+  {
+    mLoopCount = loopCount;
+  }
+
+  float SetProgress( float progress )
+  {
+    float value = 0.0f;
+
+    if( mAutoReverseEnabled )
+    {
+      if( mSpeedFactor > 0.0f )
+      {
+        value = 1.0f - 2.0f * std::abs( progress - 0.5f );
+      }
+      // Reverse mode
+      else if( mSpeedFactor < 0.0f )
+      {
+        value = 2.0f * std::abs( progress - 0.5f );
+      }
+    }
+
+    return value;
+  }
+
   /**
    * Set the delay before the animator should take effect.
    * The default is zero i.e. no delay.
@@ -148,7 +181,7 @@ public:
     return mAlphaFunction;
   }
 
-  /*
+  /**
    * Applies the alpha function to the specified progress
    * @param[in] Current progress
    * @return The progress after the alpha function has been aplied
@@ -317,7 +350,7 @@ public:
     return mActive;
   }
 
-  /*
+  /**
    * Retrive wheter the animator's target object is valid and on the stage.
    * @return The enabled state.
    */
@@ -325,6 +358,16 @@ public:
   {
     return mEnabled;
   }
+
+  /**
+   * @brief Sets the looping mode.
+   * @param[in] loopingMode True when the looping mode is AUTO_REVERSE
+   */
+  void SetLoopingMode( bool loopingMode )
+  {
+    mAutoReverseEnabled = loopingMode;
+  }
+
   /**
    * Returns wheter the target object of the animator is still valid
    * or has been destroyed.
@@ -358,6 +401,9 @@ protected:
 
   float mDurationSeconds;
   float mIntervalDelaySeconds;
+  float mSpeedFactor;
+
+  int mLoopCount;
 
   AlphaFunction mAlphaFunction;
 
@@ -365,6 +411,7 @@ protected:
   bool mActive:1;                                   ///< Animator is "active" while it's running.
   bool mEnabled:1;                                  ///< Animator is "enabled" while its target object is valid and on the stage.
   bool mConnectedToSceneGraph:1;                    ///< True if ConnectToSceneGraph() has been called in update-thread.
+  bool mAutoReverseEnabled:1;
 };
 
 /**
@@ -462,7 +509,13 @@ public:
    */
   virtual void Update( BufferIndex bufferIndex, float progress, bool bake )
   {
-    float alpha = ApplyAlphaFunction(progress);
+    if( mLoopCount != 1 ) // Looping mode
+    {
+      // Update the progress value
+      progress = SetProgress( progress );
+    }
+
+    float alpha = ApplyAlphaFunction( progress );
 
     const PropertyType& current = mPropertyAccessor.Get( bufferIndex );
 
@@ -615,7 +668,13 @@ public:
    */
   virtual void Update( BufferIndex bufferIndex, float progress, bool bake )
   {
-    float alpha = ApplyAlphaFunction(progress);
+    if( mLoopCount != 1 ) // Looping mode
+    {
+      // Update the progress value
+      progress = SetProgress( progress );
+    }
+
+    float alpha = ApplyAlphaFunction( progress );
 
     const T& current = mPropertyAccessor.Get( bufferIndex );
 
index 29160c3..c73e2b0 100644 (file)
@@ -340,7 +340,7 @@ public:
    */
   AlphaFunction GetDefaultAlphaFunction() const;
 
-  /*
+  /**
    * @brief Sets the progress of the animation.
    *
    * The animation will play (or continue playing) from this point. The progress