// INTERNAL INCLUDES
#include <dali/internal/render/common/performance-monitor.h>
-using namespace std;
-
namespace Dali
{
return progress; // linear
}
-Animation::Animation(float durationSeconds, bool isLooping, Dali::Animation::EndAction endAction, Dali::Animation::EndAction destroyAction)
+Animation::Animation( float durationSeconds, float speedFactor, const Vector2& playRange, bool isLooping, Dali::Animation::EndAction endAction, Dali::Animation::EndAction disconnectAction )
: mDurationSeconds(durationSeconds),
+ mSpeedFactor( speedFactor ),
mLooping(isLooping),
mEndAction(endAction),
- mDestroyAction(destroyAction),
+ mDisconnectAction(disconnectAction),
mState(Stopped),
- mElapsedSeconds(0.0f),
- mPlayCount(0)
+ mElapsedSeconds(playRange.x*mDurationSeconds),
+ mPlayCount(0),
+ mPlayRange( playRange )
{
}
mEndAction = action;
}
-void Animation::SetDestroyAction(Dali::Animation::EndAction action)
+void Animation::SetDisconnectAction(Dali::Animation::EndAction action)
{
- mDestroyAction = action;
+ if ( mDisconnectAction != action )
+ {
+ mDisconnectAction = action;
+
+ for ( AnimatorIter iter = mAnimators.Begin(), endIter = mAnimators.End(); iter != endIter; ++iter )
+ {
+ (*iter)->SetDisconnectAction( action );
+ }
+ }
+}
+
+void Animation::SetPlayRange( const Vector2& range )
+{
+ mPlayRange = range;
+
+ //Make sure mElapsedSeconds is within the new range
+ mElapsedSeconds = Dali::Clamp(mElapsedSeconds, mPlayRange.x*mDurationSeconds , mPlayRange.y*mDurationSeconds );
}
void Animation::Play()
{
mState = Playing;
+
+ if ( mSpeedFactor < 0.0f && mElapsedSeconds <= mPlayRange.x*mDurationSeconds )
+ {
+ mElapsedSeconds = mPlayRange.y * mDurationSeconds;
+ }
+
+ SetAnimatorsActive( true );
}
void Animation::PlayFrom( float progress )
{
mElapsedSeconds = progress * mDurationSeconds;
mState = Playing;
+
+ SetAnimatorsActive( true );
}
}
}
}
+void Animation::Bake(BufferIndex bufferIndex, EndAction action)
+{
+ if( action == Dali::Animation::BakeFinal )
+ {
+ if( mSpeedFactor > 0.0f )
+ {
+ mElapsedSeconds = mPlayRange.y*mDurationSeconds + Math::MACHINE_EPSILON_1; // Force animation to reach it's end
+ }
+ else
+ {
+ mElapsedSeconds = mPlayRange.x*mDurationSeconds - Math::MACHINE_EPSILON_1; //Force animation to reach it's beginning
+ }
+ }
+
+ UpdateAnimators( bufferIndex, true/*bake the final result*/, true /*animation finished*/ );
+}
+
+void Animation::SetAnimatorsActive( bool active )
+{
+ for ( AnimatorIter iter = mAnimators.Begin(), endIter = mAnimators.End(); iter != endIter; ++iter )
+ {
+ (*iter)->SetActive( active );
+ }
+}
+
bool Animation::Stop(BufferIndex bufferIndex)
{
bool animationFinished(false);
if( mEndAction != Dali::Animation::Discard )
{
- if( mEndAction == Dali::Animation::BakeFinal )
- {
- mElapsedSeconds = mDurationSeconds + Math::MACHINE_EPSILON_1; // Force animation to reach it's end
- }
- UpdateAnimators(bufferIndex, true/*bake the final result*/);
+ Bake( bufferIndex, mEndAction );
+
+ // Animators are automatically set to inactive in Bake
+ }
+ else
+ {
+ SetAnimatorsActive( false );
}
// The animation has now been played to completion
++mPlayCount;
}
- mElapsedSeconds = 0.0f;
+ mElapsedSeconds = mPlayRange.x*mDurationSeconds;
mState = Stopped;
return animationFinished;
{
if (mState == Playing || mState == Paused)
{
- if (mDestroyAction != Dali::Animation::Discard)
+ if (mEndAction != Dali::Animation::Discard)
+ {
+ Bake( bufferIndex, mEndAction );
+
+ // Animators are automatically set to inactive in Bake
+ }
+ else
{
- UpdateAnimators(bufferIndex, true/*bake the final result*/);
+ SetAnimatorsActive( false );
}
}
mState = Destroyed;
}
-void Animation::AddAnimator( AnimatorBase* animator, PropertyOwner* propertyOwner )
+void Animation::AddAnimator( AnimatorBase* animator )
{
- animator->Attach( propertyOwner );
-
+ animator->SetDisconnectAction( mDisconnectAction );
mAnimators.PushBack( animator );
}
// The animation must still be applied when Paused/Stopping
if (mState == Playing)
{
- mElapsedSeconds += elapsedSeconds;
+ mElapsedSeconds += elapsedSeconds * mSpeedFactor;
}
+ Vector2 playRangeSeconds = mPlayRange * mDurationSeconds;
if (mLooping)
{
- if (mElapsedSeconds > mDurationSeconds)
+ if (mElapsedSeconds > playRangeSeconds.y )
+ {
+ mElapsedSeconds = playRangeSeconds.x + fmod(mElapsedSeconds, playRangeSeconds.y);
+ }
+ else if( mElapsedSeconds < playRangeSeconds.x )
{
- mElapsedSeconds = fmod(mElapsedSeconds, mDurationSeconds);
+ mElapsedSeconds = playRangeSeconds.y - fmod(mElapsedSeconds, playRangeSeconds.y);
}
}
- const bool animationFinished(mState == Playing && mElapsedSeconds > mDurationSeconds);
+ const bool animationFinished(mState == Playing &&
+ (( mSpeedFactor > 0.0f && mElapsedSeconds > playRangeSeconds.y ) ||
+ ( mSpeedFactor < 0.0f && mElapsedSeconds < playRangeSeconds.x ))
+ );
- UpdateAnimators(bufferIndex, animationFinished && (mEndAction != Dali::Animation::Discard));
+ UpdateAnimators(bufferIndex, animationFinished && (mEndAction != Dali::Animation::Discard), animationFinished);
if (animationFinished)
{
// The animation has now been played to completion
++mPlayCount;
- mElapsedSeconds = 0.0f;
+ mElapsedSeconds = playRangeSeconds.x;
mState = Stopped;
}
return animationFinished;
}
-void Animation::UpdateAnimators(BufferIndex bufferIndex, bool bake)
+void Animation::UpdateAnimators( BufferIndex bufferIndex, bool bake, bool animationFinished )
{
+ float elapsedSecondsClamped = Clamp( mElapsedSeconds, mPlayRange.x * mDurationSeconds,mPlayRange.y * mDurationSeconds );
+
+ //Loop through all animators
+ bool applied(true);
for ( AnimatorIter iter = mAnimators.Begin(); iter != mAnimators.End(); )
{
- // If an animator is not successfully applied, then it has been orphaned
- bool applied(true);
-
AnimatorBase *animator = *iter;
- const float initialDelay(animator->GetInitialDelay());
-
- if (mElapsedSeconds >= initialDelay)
- {
- // 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);
- }
-
- applied = animator->Update(bufferIndex, progress, bake);
- }
- // Animators are automatically removed, when orphaned from animatable scene objects.
- if (!applied)
+ if( animator->Orphan() )
{
+ //Remove animators whose PropertyOwner has been destroyed
iter = mAnimators.Erase(iter);
}
else
{
- ++iter;
+ if( animator->IsEnabled() )
+ {
+ const float initialDelay(animator->GetInitialDelay());
+ if (elapsedSecondsClamped >= 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 = Clamp((elapsedSecondsClamped - initialDelay) / animatorDuration, 0.0f , 1.0f );
+ }
+ animator->Update(bufferIndex, progress, bake);
+ }
+ applied = true;
+ }
+ else
+ {
+ applied = false;
+ }
- INCREASE_COUNTER(PerformanceMonitor::ANIMATORS_APPLIED);
+ if ( animationFinished )
+ {
+ animator->SetActive( false );
+ }
+
+ if (applied)
+ {
+ INCREASE_COUNTER(PerformanceMonitor::ANIMATORS_APPLIED);
+ }
+
+ ++iter;
}
}
+
}
} // namespace SceneGraph