END_TEST;
}
+int UtcDaliAnimationSetSpeedFactor(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ Stage::GetCurrent().Add(actor);
+
+ // Build the animation
+ float durationSeconds(1.0f);
+ Animation animation = Animation::New(durationSeconds);
+
+ const Vector3 initialPosition(0.0f, 0.0f, 0.0f);
+ const Vector3 targetPosition(100.0f, 100.0f, 100.0f);
+
+ KeyFrames keyframes = KeyFrames::New();
+ keyframes.Add( 0.0f, initialPosition);
+ keyframes.Add( 1.0f, targetPosition );
+ animation.AnimateBetween( Property(actor, Actor::POSITION), keyframes, AlphaFunctions::Linear);
+
+ //Set speed to be x2
+ animation.SetSpeedFactor(2.0f);
+
+ // Start the animation
+ animation.Play();
+
+ bool signalReceived(false);
+ AnimationFinishCheck finishCheck(signalReceived);
+ animation.FinishedSignal().Connect(&application, finishCheck);
+
+ application.SendNotification();
+ application.Render(static_cast<unsigned int>(durationSeconds*200.0f)/* 40% progress */);
+
+ // We didn't expect the animation to finish yet
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+ DALI_TEST_EQUALS( actor.GetCurrentPosition(), (targetPosition * 0.4f), TEST_LOCATION );
+
+ application.Render(static_cast<unsigned int>(durationSeconds*200.0f)/* 80% progress */);
+
+ // We didn't expect the animation to finish yet
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+ DALI_TEST_EQUALS( actor.GetCurrentPosition(), (targetPosition * 0.8f), TEST_LOCATION );
+
+ application.Render(static_cast<unsigned int>(durationSeconds*100.0f) + 1u/*just beyond half the duration*/);
+
+ // We did expect the animation to finish
+ application.SendNotification();
+ finishCheck.CheckSignalReceived();
+ DALI_TEST_EQUALS( actor.GetCurrentPosition(), targetPosition, TEST_LOCATION );
+
+ // Check that nothing has changed after a couple of buffer swaps
+ application.Render(0);
+ DALI_TEST_EQUALS( targetPosition, actor.GetCurrentPosition(), TEST_LOCATION );
+ application.Render(0);
+ DALI_TEST_EQUALS( targetPosition, actor.GetCurrentPosition(), TEST_LOCATION );
+
+ finishCheck.Reset();
+
+ //Test -1 speed factor. Animation will play in reverse at normal speed
+ animation.SetSpeedFactor( -1.0f );
+
+ // Start the animation
+ animation.Play();
+
+ application.SendNotification();
+ application.Render(static_cast<unsigned int>(durationSeconds*200.0f)/* 80% progress */);
+
+ // We didn't expect the animation to finish yet
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+ DALI_TEST_EQUALS( actor.GetCurrentPosition(), (targetPosition * 0.8f), TEST_LOCATION );
+
+ application.Render(static_cast<unsigned int>(durationSeconds*200.0f)/* 60% progress */);
+
+ // We didn't expect the animation to finish yet
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+ DALI_TEST_EQUALS( actor.GetCurrentPosition(), (targetPosition * 0.6f), TEST_LOCATION );
+
+ application.Render(static_cast<unsigned int>(durationSeconds*200.0f)/* 40% progress */);
+
+ // We didn't expect the animation to finish yet
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+ DALI_TEST_EQUALS( actor.GetCurrentPosition(), (targetPosition * 0.4f), TEST_LOCATION );
+
+ application.Render(static_cast<unsigned int>(durationSeconds*200.0f)/* 20% progress */);
+
+ // We didn't expect the animation to finish yet
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+ DALI_TEST_EQUALS( actor.GetCurrentPosition(), (targetPosition * 0.2f), TEST_LOCATION );
+
+ application.Render(static_cast<unsigned int>(durationSeconds*200.0f) + 1u/*just beyond the animation duration*/);
+
+ // We did expect the animation to finish
+ application.SendNotification();
+ finishCheck.CheckSignalReceived();
+ DALI_TEST_EQUALS( actor.GetCurrentPosition(), initialPosition, TEST_LOCATION );
+
+ // Check that nothing has changed after a couple of buffer swaps
+ application.Render(0);
+ DALI_TEST_EQUALS( initialPosition, actor.GetCurrentPosition(), TEST_LOCATION );
+ application.Render(0);
+ DALI_TEST_EQUALS( initialPosition, actor.GetCurrentPosition(), TEST_LOCATION );
+
+
+ //Test change speed factor on the fly
+ finishCheck.Reset();
+
+ //Set speed to be half of normal speed
+ animation.SetSpeedFactor( 0.5f );
+
+ // Start the animation
+ animation.Play();
+
+ application.SendNotification();
+ application.Render(static_cast<unsigned int>(durationSeconds*200.0f)/* 10% progress */);
+
+ // We didn't expect the animation to finish yet
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+ DALI_TEST_EQUALS( actor.GetCurrentPosition(), (targetPosition * 0.1f), TEST_LOCATION );
+
+ application.Render(static_cast<unsigned int>(durationSeconds*200.0f)/* 20% progress */);
+
+ // We didn't expect the animation to finish yet
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+ DALI_TEST_EQUALS( actor.GetCurrentPosition(), (targetPosition * 0.2f), TEST_LOCATION );
+
+ application.Render(static_cast<unsigned int>(durationSeconds*200.0f)/* 30% progress */);
+
+ // We didn't expect the animation to finish yet
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+ DALI_TEST_EQUALS( actor.GetCurrentPosition(), (targetPosition * 0.3f), TEST_LOCATION );
+
+ //Change speed factor while animation still playing.
+ animation.SetSpeedFactor(-1.0f);
+ application.SendNotification();
+ application.Render(static_cast<unsigned int>(durationSeconds*200.0f)/* 10% progress */);
+
+ // We didn't expect the animation to finish yet
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+ DALI_TEST_EQUALS( actor.GetCurrentPosition(), (targetPosition * 0.1f), TEST_LOCATION );
+
+ application.Render(static_cast<unsigned int>(durationSeconds*100.0f) + 1u/*just beyond the animation duration*/);
+
+ // We did expect the animation to finish
+ application.SendNotification();
+ finishCheck.CheckSignalReceived();
+ DALI_TEST_EQUALS( actor.GetCurrentPosition(), initialPosition, TEST_LOCATION );
+
+ // Check that nothing has changed after a couple of buffer swaps
+ application.Render(0);
+ DALI_TEST_EQUALS( initialPosition, actor.GetCurrentPosition(), TEST_LOCATION );
+ application.Render(0);
+ DALI_TEST_EQUALS( initialPosition, actor.GetCurrentPosition(), TEST_LOCATION );
+ END_TEST;
+}
+
+int UtcDaliAnimationGetSpeedFactor(void)
+{
+ TestApplication application;
+
+ Animation animation = Animation::New(1.0f);
+ animation.SetSpeedFactor(0.5f);
+ DALI_TEST_EQUALS(animation.GetSpeedFactor(), 0.5f, TEST_LOCATION);
+
+ animation.SetSpeedFactor(-2.5f);
+ DALI_TEST_EQUALS(animation.GetSpeedFactor(), -2.5f, TEST_LOCATION);
+ END_TEST;
+}
+
int UtcDaliAnimationPlayOffStage(void)
{
// Test that an animation can be played, when the actor is off-stage.
return progress; // linear
}
-Animation::Animation(float durationSeconds, bool isLooping, Dali::Animation::EndAction endAction, Dali::Animation::EndAction destroyAction)
+Animation::Animation(float durationSeconds, float speedFactor, bool isLooping, Dali::Animation::EndAction endAction, Dali::Animation::EndAction destroyAction)
: mDurationSeconds(durationSeconds),
+ mSpeedFactor( speedFactor ),
mLooping(isLooping),
mEndAction(endAction),
mDestroyAction(destroyAction),
void Animation::Play()
{
mState = Playing;
+
+ if ( mSpeedFactor < 0.0f && mElapsedSeconds <= 0.0f )
+ {
+ mElapsedSeconds = mDurationSeconds;
+ }
}
void Animation::PlayFrom( float progress )
{
if( mEndAction == Dali::Animation::BakeFinal )
{
- mElapsedSeconds = mDurationSeconds + Math::MACHINE_EPSILON_1; // Force animation to reach it's end
+ if( mSpeedFactor > 0.0f )
+ {
+ mElapsedSeconds = mDurationSeconds + Math::MACHINE_EPSILON_1; // Force animation to reach it's end
+ }
+ else
+ {
+ mElapsedSeconds = 0.0f - Math::MACHINE_EPSILON_1; //Force animation to reach it's beginning
+ }
+
}
UpdateAnimators(bufferIndex, true/*bake the final result*/);
}
// The animation must still be applied when Paused/Stopping
if (mState == Playing)
{
- mElapsedSeconds += elapsedSeconds;
+ mElapsedSeconds += elapsedSeconds * mSpeedFactor;
}
if (mLooping)
{
- if (mElapsedSeconds > mDurationSeconds)
+ if (mElapsedSeconds > mDurationSeconds )
{
mElapsedSeconds = fmod(mElapsedSeconds, mDurationSeconds);
}
+ else if( mElapsedSeconds < 0.0f )
+ {
+ mElapsedSeconds = mDurationSeconds - fmod(mElapsedSeconds, mDurationSeconds);
+ }
}
- const bool animationFinished(mState == Playing && mElapsedSeconds > mDurationSeconds);
+
+ const bool animationFinished(mState == Playing &&
+ (( mSpeedFactor > 0.0f && mElapsedSeconds > mDurationSeconds ) ||
+ ( mSpeedFactor < 0.0f && mElapsedSeconds < 0.0f ))
+ );
UpdateAnimators(bufferIndex, animationFinished && (mEndAction != Dali::Animation::Discard));
AnimatorBase *animator = *iter;
const float initialDelay(animator->GetInitialDelay());
- if (mElapsedSeconds >= initialDelay)
+ if (mElapsedSeconds >= initialDelay || mSpeedFactor < 0.0f )
{
// Calculate a progress specific to each individual animator
float progress(1.0f);
const float animatorDuration = animator->GetDuration();
if (animatorDuration > 0.0f) // animators can be "immediate"
{
- progress = min(1.0f, (mElapsedSeconds - initialDelay) / animatorDuration);
+ progress = Clamp((mElapsedSeconds - initialDelay) / animatorDuration, 0.0f , 1.0f );
}
applied = animator->Update(bufferIndex, progress, bake);
/**
* Construct a new Animation.
* @param[in] durationSeconds The duration of the animation in seconds.
+ * @param[in] speedFactor Multiplier to the animation velocity.
* @param[in] isLooping Whether the animation will loop.
* @param[in] endAction The action to perform when the animation ends.
* @param[in] destroyAction The action to perform when the animation is destroyed.
* @return A new Animation
*/
- static Animation* New( float durationSeconds, bool isLooping, EndAction endAction, EndAction destroyAction )
+ static Animation* New( float durationSeconds, float speedFactor, bool isLooping, EndAction endAction, EndAction destroyAction )
{
- return new Animation( durationSeconds, isLooping, endAction, destroyAction );
+ return new Animation( durationSeconds, speedFactor, isLooping, endAction, destroyAction );
}
/**
mElapsedSeconds = mDurationSeconds * progress;
}
+ void SetSpeedFactor( float factor )
+ {
+ mSpeedFactor = factor;
+ }
+
/**
* Set whether the animation will loop.
* @param[in] looping True if the animation will loop.
/**
* Protected constructor. See New()
*/
- Animation( float durationSeconds, bool isLooping, EndAction endAction, EndAction destroyAction );
+ Animation( float durationSeconds, float speedFactor, bool isLooping, EndAction endAction, EndAction destroyAction );
private:
protected:
float mDurationSeconds;
+ float mSpeedFactor;
bool mLooping;
EndAction mEndAction;
EndAction mDestroyAction;
new (slot) LocalType( &animation, &Animation::SetCurrentProgress, progress );
}
+inline void SetSpeedFactorMessage( EventToUpdate& eventToUpdate, const Animation& animation, float factor )
+{
+ typedef MessageValue1< Animation, float > LocalType;
+
+ // Reserve some memory inside the message queue
+ unsigned int* slot = eventToUpdate.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::SetSpeedFactor, factor );
+}
+
inline void PlayAnimationMessage( EventToUpdate& eventToUpdate, const Animation& animation )
{
typedef Message< Animation > LocalType;