END_TEST;
}
+int UtcDaliAnimationSetLoopCountP(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ Stage::GetCurrent().Add(actor);
+
+ // Build the animation
+ float durationSeconds(1.0f);
+ Animation animation = Animation::New(durationSeconds);
+ Vector3 targetPosition(10.0f, 10.0f, 10.0f);
+ animation.AnimateTo(Property(actor, Actor::Property::POSITION), targetPosition, AlphaFunction::LINEAR);
+
+ // Start the animation
+ animation.SetLoopCount(3);
+ DALI_TEST_CHECK(animation.IsLooping());
+ animation.Play();
+
+ bool signalReceived(false);
+ AnimationFinishCheck finishCheck(signalReceived);
+ animation.FinishedSignal().Connect(&application, finishCheck);
+
+ 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));
+ 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( targetPosition, actor.GetCurrentPosition(), TEST_LOCATION );
+
+ finishCheck.Reset();
+
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+
+ END_TEST;
+}
+
+int UtcDaliAnimationSetLoopCountP2(void)
+{
+ TestApplication application;
+
+ //
+ // switching between forever and loop count
+ //
+
+ Actor actor = Actor::New();
+ Stage::GetCurrent().Add(actor);
+
+ // Build the animation
+ float durationSeconds(1.0f);
+ Animation animation = Animation::New(durationSeconds);
+ Vector3 targetPosition(10.0f, 10.0f, 10.0f);
+ animation.AnimateTo(Property(actor, Actor::Property::POSITION), targetPosition, AlphaFunction::LINEAR);
+ animation.SetEndAction(Animation::Discard);
+
+ // Start the animation
+ animation.SetLoopCount(3);
+ DALI_TEST_CHECK(animation.IsLooping());
+ animation.Play();
+
+ bool signalReceived(false);
+ AnimationFinishCheck finishCheck(signalReceived);
+ animation.FinishedSignal().Connect(&application, finishCheck);
+
+ float intervalSeconds = 3.0f;
+
+ application.SendNotification();
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+
+ application.SendNotification();
+ finishCheck.CheckSignalReceived();
+
+ finishCheck.Reset();
+
+ // Loop forever
+ animation.SetLooping(true);
+ DALI_TEST_CHECK(animation.IsLooping());
+
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+
+ finishCheck.Reset();
+
+ // Loop N again
+ animation.SetLoopCount(3);
+ DALI_TEST_CHECK(animation.IsLooping());
+ animation.Play();
+
+ application.SendNotification();
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ finishCheck.CheckSignalReceived();
+
+ finishCheck.Reset();
+
+ // loop forever
+ animation.SetLooping(true);
+ DALI_TEST_CHECK(animation.IsLooping());
+
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+
+ finishCheck.Reset();
+
+ // Loop N again
+ animation.SetLoopCount(3);
+ DALI_TEST_CHECK(animation.IsLooping());
+
+ application.SendNotification();
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived(); // we never hit play
+
+ finishCheck.Reset();
+
+
+ END_TEST;
+}
+
+int UtcDaliAnimationSetLoopCountP3(void)
+{
+ TestApplication application;
+
+ //
+ // switching between forever and loop count
+ //
+ Actor actor = Actor::New();
+ Stage::GetCurrent().Add(actor);
+
+ // Build the animation
+ float durationSeconds(1.0f);
+ Animation animation = Animation::New(durationSeconds);
+ Vector3 targetPosition(10.0f, 10.0f, 10.0f);
+ animation.AnimateTo(Property(actor, Actor::Property::POSITION), targetPosition, AlphaFunction::LINEAR);
+ animation.SetEndAction(Animation::Discard);
+
+ float intervalSeconds = 3.0f;
+
+ bool signalReceived(false);
+ AnimationFinishCheck finishCheck(signalReceived);
+ animation.FinishedSignal().Connect(&application, finishCheck);
+
+ // loop forever
+ animation.SetLooping(true);
+ DALI_TEST_CHECK(animation.IsLooping());
+
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+
+ finishCheck.Reset();
+
+ // Loop N again
+ animation.SetLoopCount(3);
+ DALI_TEST_CHECK(animation.IsLooping());
+
+ application.SendNotification();
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived(); // we never hit play
+
+ finishCheck.Reset();
+
+
+ END_TEST;
+}
+
+int UtcDaliAnimationSetLoopCountP4(void)
+{
+ TestApplication application;
+
+ //
+ // ..and play again
+ //
+ Actor actor = Actor::New();
+ Stage::GetCurrent().Add(actor);
+
+ // Build the animation
+ float durationSeconds(1.0f);
+ Animation animation = Animation::New(durationSeconds);
+ Vector3 targetPosition(10.0f, 10.0f, 10.0f);
+ animation.AnimateTo(Property(actor, Actor::Property::POSITION), targetPosition, AlphaFunction::LINEAR);
+ animation.SetEndAction(Animation::Bake);
+
+ float intervalSeconds = 3.0f;
+
+ bool signalReceived(false);
+ AnimationFinishCheck finishCheck(signalReceived);
+ animation.FinishedSignal().Connect(&application, finishCheck);
+
+ animation.SetLoopCount(1);
+ animation.Play();
+ DALI_TEST_CHECK(!animation.IsLooping());
+
+ 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 );
+ actor.SetProperty( Actor::Property::POSITION, Vector3(0.0f, 0.0f, 0.0f) );
+
+ finishCheck.Reset();
+
+ animation.Play(); // again
+ DALI_TEST_CHECK(!animation.IsLooping());
+
+ 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 );
+
+ END_TEST;
+}
+
+int UtcDaliAnimationGetLoopCountP(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ Stage::GetCurrent().Add(actor);
+
+ // Build the animation
+ float durationSeconds(1.0f);
+ Animation animation = Animation::New(durationSeconds);
+ Vector3 targetPosition(10.0f, 10.0f, 10.0f);
+ animation.AnimateTo(Property(actor, Actor::Property::POSITION), targetPosition, AlphaFunction::LINEAR);
+
+ DALI_TEST_CHECK(1 == animation.GetLoopCount());
+
+ // Start the animation
+ animation.SetLoopCount(3);
+ DALI_TEST_CHECK(animation.IsLooping());
+ DALI_TEST_CHECK(3 == animation.GetLoopCount());
+
+ animation.Play();
+
+ application.Render(0);
+ application.SendNotification();
+
+ // Loop
+ float intervalSeconds = 3.0f;
+
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+
+ application.Render(0);
+ application.SendNotification();
+
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+
+ animation.SetLoopCount(0);
+ DALI_TEST_CHECK(animation.IsLooping());
+ DALI_TEST_CHECK(0 == animation.GetLoopCount());
+
+ animation.SetLoopCount(1);
+ DALI_TEST_CHECK(!animation.IsLooping());
+ DALI_TEST_CHECK(1 == animation.GetLoopCount());
+
+ END_TEST;
+}
+
+
+int UtcDaliAnimationGetCurrentLoopP(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ Stage::GetCurrent().Add(actor);
+
+ // Build the animation
+ float durationSeconds(1.0f);
+ Animation animation = Animation::New(durationSeconds);
+ Vector3 targetPosition(10.0f, 10.0f, 10.0f);
+ animation.AnimateTo(Property(actor, Actor::Property::POSITION), targetPosition, AlphaFunction::LINEAR);
+
+ // Start the animation
+ animation.SetLoopCount(3);
+ DALI_TEST_CHECK(animation.IsLooping());
+ DALI_TEST_CHECK(0 == animation.GetCurrentLoop());
+ animation.Play();
+
+ bool signalReceived(false);
+ AnimationFinishCheck finishCheck(signalReceived);
+ animation.FinishedSignal().Connect(&application, finishCheck);
+
+ application.SendNotification();
+
+ // Loop
+ float intervalSeconds = 3.0f;
+
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+ DALI_TEST_CHECK(2 == animation.GetCurrentLoop());
+
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+
+ application.SendNotification();
+ finishCheck.CheckSignalReceived();
+ DALI_TEST_CHECK(3 == animation.GetCurrentLoop());
+ DALI_TEST_CHECK(animation.GetLoopCount() == animation.GetCurrentLoop());
+
+ finishCheck.Reset();
+
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+ DALI_TEST_CHECK(3 == animation.GetCurrentLoop());
+
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.Render(static_cast<unsigned int>(durationSeconds*intervalSeconds*1000.0f));
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+ DALI_TEST_CHECK(3 == animation.GetCurrentLoop());
+
+ END_TEST;
+}
+
int UtcDaliAnimationIsLoopingP(void)
{
TestApplication application;
mFinishedCallbackObject( NULL ),
mDurationSeconds( durationSeconds ),
mSpeedFactor(1.0f),
- mIsLooping( false ),
+ mLoopCount(1),
+ mCurrentLoop(0),
mPlayRange( Vector2(0.0f,1.0f)),
mEndAction( endAction ),
mDisconnectAction( disconnectAction ),
DALI_ASSERT_DEBUG( mAnimation == NULL );
// Create a new animation, temporarily owned
- SceneGraph::Animation* animation = SceneGraph::Animation::New( mDurationSeconds, mSpeedFactor, mPlayRange, mIsLooping, mEndAction, mDisconnectAction );
+ SceneGraph::Animation* animation = SceneGraph::Animation::New( mDurationSeconds, mSpeedFactor, mPlayRange, mLoopCount, mEndAction, mDisconnectAction );
// Keep a const pointer to the animation.
mAnimation = animation;
return mDurationSeconds;
}
-void Animation::SetLooping(bool looping)
+void Animation::SetLooping(bool on)
+{
+ SetLoopCount( on ? 0 : 1 );
+}
+
+void Animation::SetLoopCount(int count)
{
// Cache for public getters
- mIsLooping = looping;
+ mLoopCount = count;
// mAnimation is being used in a separate thread; queue a message to set the value
- SetLoopingMessage( mEventThreadServices, *mAnimation, looping );
+ SetLoopingMessage( mEventThreadServices, *mAnimation, mLoopCount );
+}
+
+int Animation::GetLoopCount()
+{
+ return mLoopCount;
+}
+
+int Animation::GetCurrentLoop()
+{
+ return mCurrentLoop;
}
bool Animation::IsLooping() const
{
- // This is not animatable; the cached value is up-to-date.
- return mIsLooping;
+ return mLoopCount != 1;
}
void Animation::SetEndAction(EndAction action)
bool Animation::HasFinished()
{
bool hasFinished(false);
- const int playCount(mAnimation->GetPlayCount());
+ const int playedCount(mAnimation->GetPlayedCount());
// If the play count has been incremented, then another notification is required
- if (playCount > mNotificationCount)
+ mCurrentLoop = mAnimation->GetCurrentLoop();
+
+ if (playedCount > mNotificationCount)
{
// Note that only one signal is emitted, if the animation has been played repeatedly
- mNotificationCount = playCount;
+ mNotificationCount = playedCount;
hasFinished = true;
}
/**
* @copydoc Dali::Animation::SetLooping()
*/
- void SetLooping(bool looping);
+ void SetLooping(bool on);
+
+ /**
+ * @copydoc Dali::Animation::SetLoopCount()
+ */
+ void SetLoopCount(int count);
+
+ /**
+ * @copydoc Dali::Animation::GetLoopCount()
+ */
+ int GetLoopCount();
+
+ /**
+ * @copydoc Dali::Animation::GetCurrentLoop()
+ */
+ int GetCurrentLoop();
/**
* @copydoc Dali::Animation::IsLooping()
// Cached for public getters
float mDurationSeconds;
float mSpeedFactor;
- bool mIsLooping;
+ int mLoopCount;
+ int mCurrentLoop;
Vector2 mPlayRange;
EndAction mEndAction;
EndAction mDisconnectAction;
// The animation may be present in mPlaylist - remove if necessary
// Note that the animation "Finish" signal is emitted after Stop() has been called
std::vector< Dali::Animation >::iterator iter = std::find( mPlaylist.begin(), mPlaylist.end(), Dali::Animation(animation) );
+ DALI_ASSERT_DEBUG(iter != mPlaylist.end());
mPlaylist.erase( iter );
}
}
{
//Memory pool used to allocate new animations. Memory used by this pool will be released when shutting down DALi
Dali::Internal::MemoryPoolObjectAllocator<Dali::Internal::SceneGraph::Animation> gAnimationMemoryPool;
+
+inline void WrapInPlayRange( float& elapsed, const Dali::Vector2& playRangeSeconds)
+{
+ if (elapsed > playRangeSeconds.y )
+ {
+ elapsed = playRangeSeconds.x + fmod(elapsed, playRangeSeconds.y);
+ }
+ else if( elapsed < playRangeSeconds.x )
+ {
+ elapsed = playRangeSeconds.y - fmod(elapsed, playRangeSeconds.y);
+ }
+}
+
}
namespace Dali
namespace SceneGraph
{
-Animation* Animation::New( float durationSeconds, float speedFactor, const Vector2& playRange, bool isLooping, EndAction endAction, EndAction disconnectAction )
+Animation* Animation::New( float durationSeconds, float speedFactor, const Vector2& playRange, int loopCount, EndAction endAction, EndAction disconnectAction )
{
- return new ( gAnimationMemoryPool.AllocateRawThreadSafe() ) Animation( durationSeconds, speedFactor, playRange, isLooping, endAction, disconnectAction );
+ return new ( gAnimationMemoryPool.AllocateRawThreadSafe() ) Animation( durationSeconds, speedFactor, playRange, loopCount, endAction, disconnectAction );
}
-Animation::Animation( float durationSeconds, float speedFactor, const Vector2& playRange, bool isLooping, Dali::Animation::EndAction endAction, Dali::Animation::EndAction disconnectAction )
+Animation::Animation( float durationSeconds, float speedFactor, const Vector2& playRange, int loopCount, Dali::Animation::EndAction endAction, Dali::Animation::EndAction disconnectAction )
: mDurationSeconds(durationSeconds),
mSpeedFactor( speedFactor ),
- mLooping(isLooping),
mEndAction(endAction),
mDisconnectAction(disconnectAction),
mState(Stopped),
mElapsedSeconds(playRange.x*mDurationSeconds),
- mPlayCount(0),
+ mPlayedCount(0),
+ mLoopCount(loopCount),
+ mCurrentLoop(0),
mPlayRange( playRange )
{
}
mDurationSeconds = durationSeconds;
}
-void Animation::SetLooping(bool looping)
+void Animation::SetLoopCount(int loopCount)
{
- mLooping = looping;
+ mLoopCount = loopCount;
+ mCurrentLoop = 0;
}
void Animation::SetEndAction(Dali::Animation::EndAction action)
}
SetAnimatorsActive( true );
+
+ mCurrentLoop = 0;
}
void Animation::PlayFrom( float progress )
}
// The animation has now been played to completion
- ++mPlayCount;
+ ++mPlayedCount;
+ mCurrentLoop = 0;
}
mElapsedSeconds = mPlayRange.x*mDurationSeconds;
mAnimators.PushBack( animator );
}
-bool Animation::Update(BufferIndex bufferIndex, float elapsedSeconds)
+void Animation::Update(BufferIndex bufferIndex, float elapsedSeconds, bool& looped, bool& finished )
{
+ looped = false;
+ finished = false;
+
if (mState == Stopped || mState == Destroyed)
{
// Short circuit when animation isn't running
- return false;
+ return;
}
// The animation must still be applied when Paused/Stopping
}
Vector2 playRangeSeconds = mPlayRange * mDurationSeconds;
- if (mLooping)
+
+ if( 0 == mLoopCount )
{
- if (mElapsedSeconds > playRangeSeconds.y )
- {
- mElapsedSeconds = playRangeSeconds.x + fmod(mElapsedSeconds, playRangeSeconds.y);
- }
- else if( mElapsedSeconds < playRangeSeconds.x )
+ // loop forever
+ WrapInPlayRange(mElapsedSeconds, playRangeSeconds);
+
+ UpdateAnimators(bufferIndex, false, false);
+
+ // don't increment mPlayedCount as event loop tracks this to indicate animation finished (end of all loops)
+ }
+ else if( mCurrentLoop < mLoopCount - 1) // '-1' here so last loop iteration uses play once below
+ {
+ // looping
+ looped = (mState == Playing &&
+ (( mSpeedFactor > 0.0f && mElapsedSeconds > playRangeSeconds.y ) ||
+ ( mSpeedFactor < 0.0f && mElapsedSeconds < playRangeSeconds.x )) );
+
+ WrapInPlayRange(mElapsedSeconds, playRangeSeconds);
+
+ UpdateAnimators(bufferIndex, false, false);
+
+ if(looped)
{
- mElapsedSeconds = playRangeSeconds.y - fmod(mElapsedSeconds, playRangeSeconds.y);
+ ++mCurrentLoop;
+ // don't increment mPlayedCount until the finished final loop
}
}
+ else
+ {
+ // playing once (and last mCurrentLoop)
+ finished = (mState == Playing &&
+ (( mSpeedFactor > 0.0f && mElapsedSeconds > playRangeSeconds.y ) ||
+ ( mSpeedFactor < 0.0f && mElapsedSeconds < playRangeSeconds.x )) );
- const bool animationFinished(mState == Playing &&
- (( mSpeedFactor > 0.0f && mElapsedSeconds > playRangeSeconds.y ) ||
- ( mSpeedFactor < 0.0f && mElapsedSeconds < playRangeSeconds.x ))
- );
+ // update with bake if finished
+ UpdateAnimators(bufferIndex, finished && (mEndAction != Dali::Animation::Discard), finished);
- UpdateAnimators(bufferIndex, animationFinished && (mEndAction != Dali::Animation::Discard), animationFinished);
+ if(finished)
+ {
+ // The animation has now been played to completion
+ ++mPlayedCount;
- if (animationFinished)
- {
- // The animation has now been played to completion
- ++mPlayCount;
+ // loop iterations come to this else branch for their final iterations
+ if( mCurrentLoop < mLoopCount)
+ {
+ ++mCurrentLoop;
+ DALI_ASSERT_DEBUG(mCurrentLoop == mLoopCount);
+ }
- mElapsedSeconds = playRangeSeconds.x;
- mState = Stopped;
+ mElapsedSeconds = playRangeSeconds.x;
+ mState = Stopped;
+ }
}
- return animationFinished;
}
void Animation::UpdateAnimators( BufferIndex bufferIndex, bool bake, bool animationFinished )
* @param[in] durationSeconds The duration of the animation in seconds.
* @param[in] speedFactor Multiplier to the animation velocity.
* @param[in] playRange Minimum and maximum progress between which the animation will play.
- * @param[in] isLooping Whether the animation will loop.
+ * @param[in] loopCount The number of times the animation will loop. ( See SetLoopCount() )
* @param[in] endAction The action to perform when the animation ends.
* @param[in] disconnectAction The action to perform when the property owner of an animator is disconnected.
* @return A new Animation
*/
- static Animation* New( float durationSeconds, float speedFactor, const Vector2& playRange, bool isLooping, EndAction endAction, EndAction disconnectAction );
+ static Animation* New( float durationSeconds, float speedFactor, const Vector2& playRange, int loopCount, EndAction endAction, EndAction disconnectAction );
/**
* Virtual destructor
}
/**
- * Set whether the animation will loop.
- * @param[in] looping True if the animation will loop.
+ * Set the animation loop count.
+ * 0 is loop forever, N loop play N times
+ * @param[in] loopCount The loop count
*/
- void SetLooping(bool looping);
+ void SetLoopCount(int loopCount);
/**
* Query whether the animation will loop.
*/
bool IsLooping() const
{
- return mLooping;
+ return mLoopCount != 1;
+ }
+
+ /*
+ * Get the loop count
+ * @return the loop count
+ */
+ int GetLoopCount() const
+ {
+ return mLoopCount;
}
/**
* Retrive a count of the number of times the animation has been played to completion.
* This can be used to emit "Finised" signals from the public-api
*/
- int GetPlayCount() const
+ int GetPlayedCount() const
+ {
+ return mPlayedCount;
+ }
+
+ /**
+ * Get the current loop count from zero to GetLoopCount().
+ */
+ int GetCurrentLoop() const
{
- return mPlayCount;
+ return mCurrentLoop;
}
/**
* @pre The animation is playing or paused.
* @param[in] bufferIndex The buffer to update.
* @param[in] elapsedSeconds The time elapsed since the previous frame.
- * @return True if the animation has finished.
+ * @param[out] looped True if the animation looped
+ * @param[out] finished True if the animation has finished.
*/
- bool Update(BufferIndex bufferIndex, float elapsedSeconds);
+ void Update(BufferIndex bufferIndex, float elapsedSeconds, bool& looped, bool& finished );
protected:
/**
* Protected constructor. See New()
*/
- Animation( float durationSeconds, float speedFactor, const Vector2& playRange, bool isLooping, EndAction endAction, EndAction disconnectAction );
+ Animation( float durationSeconds, float speedFactor, const Vector2& playRange, int loopCount, EndAction endAction, EndAction disconnectAction );
private:
float mDurationSeconds;
float mSpeedFactor;
- bool mLooping;
EndAction mEndAction;
EndAction mDisconnectAction;
State mState;
float mElapsedSeconds;
- int mPlayCount;
+ int mPlayedCount; // Incremented at end of animation or completion of all loops
+ // Never incremented when looping forever. Event thread tracks to signal end.
+ int mLoopCount; // N loop setting
+ int mCurrentLoop; // Current loop number
Vector2 mPlayRange;
AnimatorContainer mAnimators;
new (slot) LocalType( &animation, &Animation::SetDuration, durationSeconds );
}
-inline void SetLoopingMessage( EventThreadServices& eventThreadServices, const Animation& animation, bool looping )
+inline void SetLoopingMessage( EventThreadServices& eventThreadServices, const Animation& animation, int loopCount )
{
- typedef MessageValue1< Animation, bool > LocalType;
+ typedef MessageValue1< Animation, int > 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::SetLooping, looping );
+ new (slot) LocalType( &animation, &Animation::SetLoopCount, loopCount );
}
inline void SetEndActionMessage( EventThreadServices& eventThreadServices, const Animation& animation, Dali::Animation::EndAction action )
/**
* Rebuild the Layer::colorRenderables, stencilRenderables and overlayRenderables members,
* including only renderers which are included in the current render-task.
- * Returns true if all renderers have finshed acquiring resources.
+ * Returns true if all renderers have finished acquiring resources.
*/
bool AddRenderablesForTask( BufferIndex updateBufferIndex,
Node& node,
{
AnimationContainer &animations = mImpl->animations;
AnimationIter iter = animations.Begin();
+ bool animationLooped = false;
while ( iter != animations.End() )
{
Animation* animation = *iter;
- bool finished = animation->Update( bufferIndex, elapsedSeconds );
+ bool finished = false;
+ bool looped = false;
+ animation->Update( bufferIndex, elapsedSeconds, looped, finished );
mImpl->animationFinishedDuringUpdate = mImpl->animationFinishedDuringUpdate || finished;
+ animationLooped = animationLooped || looped;
// Remove animations that had been destroyed but were still waiting for an update
if (animation->GetState() == Animation::Destroyed)
}
}
- if ( mImpl->animationFinishedDuringUpdate )
+ // queue the notification on finished or looped (to update loop count)
+ if ( mImpl->animationFinishedDuringUpdate || animationLooped )
{
// The application should be notified by NotificationManager, in another thread
mImpl->notificationManager.QueueCompleteNotification( &mImpl->animationFinishedNotifier );
GetImplementation(*this).SetLooping(looping);
}
+void Animation::SetLoopCount(int count)
+{
+ GetImplementation(*this).SetLoopCount(count);
+}
+
+int Animation::GetLoopCount()
+{
+ return GetImplementation(*this).GetLoopCount();
+}
+
+int Animation::GetCurrentLoop()
+{
+ return GetImplementation(*this).GetCurrentLoop();
+}
+
bool Animation::IsLooping() const
{
return GetImplementation(*this).IsLooping();
float GetDuration() const;
/**
- * @brief Set whether the animation will loop.
+ * @brief Set whether the animation will loop forever.
+ *
+ * This function resets the loop count and should not be used with SetLoopCount(int).
+ * Setting this parameter does not cause the animation to Play()
*
* @SINCE_1_0.0
- * @param[in] looping True if the animation will loop.
+ * @param[in] looping If true then the animation will loop forever, if false it will never loop.
*/
void SetLooping(bool looping);
+ /**
+ * @brief Enable looping for 'count' repeats.
+ *
+ * A zero is the same as SetLooping(true) ie repeat forever.
+ * If Play() Stop() or 'count' loops is reached, the loop counter will reset.
+ * Setting this parameter does not cause the animation to Play()
+ *
+ * @SINCE_1_1.20
+ * @param[in] count The number of times to loop.
+ */
+ void SetLoopCount(int count);
+
+ /**
+ * @brief Get the loop count.
+ *
+ * A zero is the same as SetLooping(true) ie repeat forever.
+ * The loop count is initially 1 for play once.
+ *
+ * @SINCE_1_1.20
+ * @return The number of times to loop.
+ */
+ int GetLoopCount();
+
+ /**
+ * @brief Get the current loop count.
+ *
+ * A value 0 to GetLoopCount() indicating the current loop count when looping.
+ *
+ * @SINCE_1_1.20
+ * @return The current number of loops that have occured.
+ */
+ int GetCurrentLoop();
+
/**
* @brief Query whether the animation will loop.
*