- PlayAfter() API is to play Animation after the given time.
Change-Id: I177fed58bb2bdfd9df1f7acec7a9acbd83f8453e
Signed-off-by: Seoyeon Kim <seoyeon2.kim@samsung.com>
END_TEST;
}
+int UtcDaliAnimationPlayAfterP(void)
+{
+ TestApplication application;
+
+ tet_printf("Testing that playing after 2 seconds\n");
+
+ Actor actor = Actor::New();
+ Stage::GetCurrent().Add(actor);
+
+ // Build the animation
+ float durationSeconds(1.0f);
+ Animation animation = Animation::New(durationSeconds);
+
+ 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, AlphaFunction::LINEAR, TimePeriod( 0.5f, 0.5f ) );
+
+ // Play animation after the initial delay time
+ DevelAnimation::PlayAfter( animation, 0.2f );
+ application.SendNotification();
+ application.Render(0); // start animation
+
+ application.Render( durationSeconds * 200.f ); // The intial delay time of PlayAfter
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+ DALI_TEST_EQUALS( actor.GetCurrentPosition(), ( targetPosition * 0.0f ), TEST_LOCATION ); // Not move
+
+ application.Render( static_cast< unsigned int >( durationSeconds * 500.0f )/* 50% animation progress, 0% animator progress */ );
+
+ // We didn't expect the animation to finish yet
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+ DALI_TEST_EQUALS( actor.GetCurrentPosition(), ( targetPosition * 0.0f ), TEST_LOCATION ); // Not move - A delay time of TimePeriod in seconds
+
+ application.SendNotification();
+ application.Render( static_cast< unsigned int >( durationSeconds * 250.0f )/* 75% animation progress, 50% animator progress */ );
+
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+ DALI_TEST_EQUALS( actor.GetCurrentPosition(), ( targetPosition * 0.5f ), TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render( static_cast< unsigned int >( durationSeconds * 250.0f ) + 1u/*just beyond the animation 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( actor.GetCurrentPosition(), targetPosition, TEST_LOCATION );
+ END_TEST;
+}
+
+int UtcDaliAnimationPlayAfterP2(void)
+{
+ TestApplication application;
+
+ tet_printf("Testing that playing after 2 seconds before looping\n");
+
+ Actor actor = Actor::New();
+ Stage::GetCurrent().Add(actor);
+
+ // Build the animation
+ 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, AlphaFunction::LINEAR, TimePeriod( 0.5f, 0.5f ) );
+
+ // Play animation after the initial delay time
+ DevelAnimation::PlayAfter( animation, 0.2f );
+ application.SendNotification();
+ application.Render(0); // start animation
+
+ for( int iterations = 0; iterations < 3; ++iterations )
+ {
+ // The initial delay time of PlayAfter() applies only once in looping mode.
+ if( iterations == 0 )
+ {
+ application.Render( durationSeconds * 200.f ); // The intial delay time of PlayAfter
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+ DALI_TEST_EQUALS( actor.GetCurrentPosition(), ( targetPosition * 0.0f ), TEST_LOCATION ); // Not move
+ }
+
+ application.Render( static_cast< unsigned int >( durationSeconds * 500.0f )/* 50% animation progress, 0% animator progress */ );
+
+ // We didn't expect the animation to finish yet
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+ DALI_TEST_EQUALS( actor.GetCurrentPosition(), ( targetPosition * 0.0f ), TEST_LOCATION ); // Not move - A delay time of TimePeriod in seconds
+
+ application.SendNotification();
+ application.Render( static_cast< unsigned int >( durationSeconds * 250.0f )/* 75% animation progress, 50% animator progress */ );
+
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+ DALI_TEST_EQUALS( actor.GetCurrentPosition(), ( targetPosition * 0.5f ), TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render( static_cast< unsigned int >( durationSeconds * 250.0f ) /* 100% 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 UtcDaliAnimationPlayAfterP3(void)
+{
+ TestApplication application;
+
+ tet_printf("Testing that PlayAfter with the negative delay seconds\n");
+
+ Actor actor = Actor::New();
+ Stage::GetCurrent().Add(actor);
+
+ // Build the animation
+ float durationSeconds(1.0f);
+ Animation animation = Animation::New(durationSeconds);
+
+ 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, AlphaFunction::LINEAR, TimePeriod( 0.5f, 0.5f ) );
+
+ // When the delay time is negative value, it would treat as play immediately.
+ DevelAnimation::PlayAfter( animation, -2.0f );
+ application.SendNotification();
+ application.Render(0); // start animation
+
+ application.Render( static_cast< unsigned int >( durationSeconds * 500.0f )/* 50% animation progress, 0% animator progress */ );
+
+ // We didn't expect the animation to finish yet
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+ DALI_TEST_EQUALS( actor.GetCurrentPosition(), ( targetPosition * 0.0f ), TEST_LOCATION ); // Not move - A delay time of TimePeriod in seconds
+
+ application.SendNotification();
+ application.Render( static_cast< unsigned int >( durationSeconds * 250.0f )/* 75% animation progress, 50% animator progress */ );
+
+ application.SendNotification();
+ finishCheck.CheckSignalNotReceived();
+ DALI_TEST_EQUALS( actor.GetCurrentPosition(), ( targetPosition * 0.5f ), TEST_LOCATION );
+
+ application.SendNotification();
+ application.Render( static_cast< unsigned int >( durationSeconds * 250.0f ) + 1u/*just beyond the animation 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( actor.GetCurrentPosition(), targetPosition, TEST_LOCATION );
+ END_TEST;
+}
+
int UtcDaliAnimationProgressSignalConnectionWithoutProgressMarkerP(void)
{
TestApplication application;
return GetImplementation( animation ).ProgressReachedSignal();
}
+void PlayAfter( Animation animation, float delaySeconds )
+{
+ GetImplementation( animation ).PlayAfter( delaySeconds );
+}
+
} // namespace DevelAnimation
} // namespace Dali
*/
DALI_IMPORT_API Animation::AnimationSignalType& ProgressReachedSignal( Animation animation );
+/**
+ * @brief Play the animation after a given delay time.
+ *
+ * The delay time is not included in the looping time.
+ * When the delay time is negative value, it would treat as play immediately.
+ * @param[in] animation The animation object to perform this operation on
+ * @param[in] delaySeconds The delay time
+ */
+DALI_IMPORT_API void PlayAfter( Animation animation, float delaySeconds );
+
} // namespace DevelAnimation
} // namespace Dali
mDisconnectAction( disconnectAction ),
mDefaultAlpha( defaultAlpha ),
mState(Dali::Animation::STOPPED),
- mProgressReachedMarker( 0.0f )
+ mProgressReachedMarker( 0.0f ),
+ mDelaySeconds( 0.0f )
{
}
}
}
+void Animation::PlayAfter( float delaySeconds )
+{
+ // The negative delay means play immediately.
+ delaySeconds = std::max( 0.f, delaySeconds );
+
+ mDelaySeconds = delaySeconds;
+
+ // Update the current playlist
+ mPlaylist.OnPlay( *this );
+
+ mState = Dali::Animation::PLAYING;
+
+ NotifyObjects();
+
+ SendFinalProgressNotificationMessage();
+
+ // mAnimation is being used in a separate thread; queue a message to set the value
+ PlayAfterMessage( mEventThreadServices, *mAnimation, delaySeconds );
+}
+
void Animation::Pause()
{
mState = Dali::Animation::PAUSED;
*/
void PlayFrom( float progress );
+ /**
+ * @copydoc Dali::Animation::PlayAfter()
+ */
+ void PlayAfter( float delaySeconds );
+
/**
* @copydoc Dali::Animation::Pause()
*/
AlphaFunction mDefaultAlpha;
Dali::Animation::State mState;
float mProgressReachedMarker;
+ float mDelaySeconds;
};
} // namespace Internal
// INTERNAL INCLUDES
#include <dali/internal/common/memory-pool-object-allocator.h>
#include <dali/internal/render/common/performance-monitor.h>
-
+#include <dali/public-api/math/math-utils.h>
namespace //Unnamed namespace
{
//Memory pool used to allocate new animations. Memory used by this pool will be released when shutting down DALi
/// 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() ) );
+ return ( ( lhs->GetIntervalDelay() + lhs->GetDuration() ) < ( rhs->GetIntervalDelay() + rhs->GetDuration() ) );
}
} // unnamed namespace
}
Animation::Animation( float durationSeconds, float speedFactor, const Vector2& playRange, int loopCount, Dali::Animation::EndAction endAction, Dali::Animation::EndAction disconnectAction )
-: mDurationSeconds(durationSeconds),
+: mPlayRange( playRange ),
+ mDurationSeconds( durationSeconds ),
+ mDelaySeconds( 0.0f ),
+ mElapsedSeconds( playRange.x*mDurationSeconds ),
mSpeedFactor( speedFactor ),
+ mProgressMarker( 0.0f ),
+ mPlayedCount( 0 ),
+ mLoopCount(loopCount),
+ mCurrentLoop(0),
mEndAction(endAction),
mDisconnectAction(disconnectAction),
mState(Stopped),
- mElapsedSeconds(playRange.x*mDurationSeconds),
- mPlayedCount(0),
- mLoopCount(loopCount),
- mCurrentLoop(0),
- mPlayRange( playRange ),
- mProgressMarker(0.0f),
mProgressReachedSignalRequired( false )
{
}
}
}
+void Animation::PlayAfter( float delaySeconds )
+{
+ if( mState != Playing )
+ {
+ mDelaySeconds = delaySeconds;
+ mState = Playing;
+
+ if ( mSpeedFactor < 0.0f && mElapsedSeconds <= mPlayRange.x*mDurationSeconds )
+ {
+ mElapsedSeconds = mPlayRange.y * mDurationSeconds;
+ }
+
+ SetAnimatorsActive( true );
+
+ mCurrentLoop = 0;
+ }
+}
+
void Animation::Pause()
{
if (mState == Playing)
// The animation must still be applied when Paused/Stopping
if (mState == Playing)
{
- mElapsedSeconds += elapsedSeconds * mSpeedFactor;
-
- if ( mProgressReachedSignalRequired && ( mElapsedSeconds >= mProgressMarker ) )
+ // If there is delay time before Animation starts, wait the Animation until mDelaySeconds.
+ if( mDelaySeconds > 0)
{
- // The application should be notified by NotificationManager, in another thread
- progressReached = true;
- mProgressReachedSignalRequired = false;
+ mDelaySeconds = mDelaySeconds - ( elapsedSeconds * mSpeedFactor );
+ }
+ else
+ {
+ mElapsedSeconds += elapsedSeconds * mSpeedFactor;
+
+ if ( mProgressReachedSignalRequired && ( mElapsedSeconds >= mProgressMarker ) )
+ {
+ // The application should be notified by NotificationManager, in another thread
+ progressReached = true;
+ mProgressReachedSignalRequired = false;
+ }
}
}
{
if( animator->IsEnabled() )
{
- const float initialDelay( animator->GetInitialDelay() );
- if( elapsedSecondsClamped >= initialDelay )
+ const float intervalDelay( animator->GetIntervalDelay() );
+
+ if( elapsedSecondsClamped >= intervalDelay )
{
// 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 = Clamp((elapsedSecondsClamped - initialDelay) / animatorDuration, 0.0f , 1.0f );
+ progress = Clamp((elapsedSecondsClamped - intervalDelay) / animatorDuration, 0.0f , 1.0f );
}
animator->Update(bufferIndex, progress, bake);
}
*/
void Play();
- /*
+ /**
* Play the animation from a given point
* @param[in] progress A value between [0,1] form where the animation should start playing
*/
void PlayFrom( float progress );
+ /**
+ * @brief Play the animation after a given delay time.
+ * @param[in] delaySeconds The delay time
+ */
+ void PlayAfter( float delaySeconds );
+
/**
* Pause the animation.
*/
protected:
+ AnimatorContainer mAnimators;
+
+ Vector2 mPlayRange;
+
float mDurationSeconds;
+ float mDelaySeconds;
+ float mElapsedSeconds;
float mSpeedFactor;
- EndAction mEndAction;
- EndAction mDisconnectAction;
+ float mProgressMarker; // Progress marker to trigger a notification
- State mState;
- float mElapsedSeconds;
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;
+ EndAction mEndAction;
+ EndAction mDisconnectAction;
- float mProgressMarker; // Progress marker to trigger a notification
- bool mProgressReachedSignalRequired; // Flag to indicate the progress marker was hit
+ State mState;
- AnimatorContainer mAnimators;
+ bool mProgressReachedSignalRequired; // Flag to indicate the progress marker was hit
};
}; //namespace SceneGraph
new (slot) LocalType( &animation, &Animation::AddAnimator, parameter );
}
+inline void PlayAfterMessage( EventThreadServices& eventThreadServices, const Animation& animation, float delaySeconds )
+{
+ typedef MessageValue1< Animation, float > 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::PlayAfter, delaySeconds );
+}
} // namespace SceneGraph
*/
AnimatorBase()
: mDurationSeconds(1.0f),
- mInitialDelaySeconds(0.0f),
+ mIntervalDelaySeconds(0.0f),
mAlphaFunction(AlphaFunction::DEFAULT),
mDisconnectAction(Dali::Animation::BakeFinal),
mActive(false),
* The default is zero i.e. no delay.
* @param [in] seconds The delay in seconds.
*/
- void SetInitialDelay(float seconds)
+ void SetIntervalDelay(float seconds)
{
- mInitialDelaySeconds = seconds;
+ mIntervalDelaySeconds = seconds;
}
/**
- * Retrieve the initial delay of the animator.
+ * Retrieve the delay before the animator should take effect.
* @return The delay in seconds.
*/
- float GetInitialDelay() const
+ float GetIntervalDelay() const
{
- return mInitialDelaySeconds;
+ return mIntervalDelaySeconds;
}
/**
}
float mDurationSeconds;
- float mInitialDelaySeconds;
+ float mIntervalDelaySeconds;
AlphaFunction mAlphaFunction;
animatorFunction );
animator->SetAlphaFunction( alphaFunction );
- animator->SetInitialDelay( timePeriod.delaySeconds );
+ animator->SetIntervalDelay( timePeriod.delaySeconds );
animator->SetDuration( timePeriod.durationSeconds );
return animator;
animatorFunction );
animator->SetAlphaFunction( alphaFunction );
- animator->SetInitialDelay( timePeriod.delaySeconds );
+ animator->SetIntervalDelay( timePeriod.delaySeconds );
animator->SetDuration( timePeriod.durationSeconds );
return animator;