X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Fupdate%2Fanimation%2Fscene-graph-animation.cpp;h=1ac2e43e86779aaad6800bd8ad3355dff2054a68;hb=2d970aead71b5ec203887d14f5cb36ae1f31aec1;hp=260be922b9d643c0e8edaf8cf0b140a9e1d10516;hpb=ec18bfc8801217432e672fe40f8d50b98d1c70cb;p=platform%2Fcore%2Fuifw%2Fdali-core.git diff --git a/dali/internal/update/animation/scene-graph-animation.cpp b/dali/internal/update/animation/scene-graph-animation.cpp index 260be92..1ac2e43 100644 --- a/dali/internal/update/animation/scene-graph-animation.cpp +++ b/dali/internal/update/animation/scene-graph-animation.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,15 +30,15 @@ namespace //Unnamed namespace //Memory pool used to allocate new animations. Memory used by this pool will be released when shutting down DALi Dali::Internal::MemoryPoolObjectAllocator gAnimationMemoryPool; -inline void WrapInPlayRange( float& elapsed, const Dali::Vector2& playRangeSeconds) +inline void WrapInPlayRange( float& elapsed, const float& playRangeStartSeconds, const float& playRangeEndSeconds) { - if( elapsed > playRangeSeconds.y ) + if( elapsed > playRangeEndSeconds ) { - elapsed = playRangeSeconds.x + fmodf((elapsed-playRangeSeconds.x), (playRangeSeconds.y-playRangeSeconds.x)); + elapsed = playRangeStartSeconds + fmodf( ( elapsed - playRangeStartSeconds ), ( playRangeEndSeconds - playRangeStartSeconds ) ); } - else if( elapsed < playRangeSeconds.x ) + else if( elapsed < playRangeStartSeconds ) { - elapsed = playRangeSeconds.y - fmodf( (playRangeSeconds.x - elapsed), (playRangeSeconds.y-playRangeSeconds.x) ); + elapsed = playRangeEndSeconds - fmodf( ( playRangeStartSeconds - elapsed ), ( playRangeEndSeconds - playRangeStartSeconds ) ); } } @@ -59,12 +59,12 @@ namespace Internal namespace SceneGraph { -Animation* Animation::New( float durationSeconds, float speedFactor, const Vector2& playRange, int loopCount, EndAction endAction, EndAction disconnectAction ) +Animation* Animation::New( float durationSeconds, float speedFactor, const Vector2& playRange, int32_t loopCount, EndAction endAction, EndAction disconnectAction ) { return new ( gAnimationMemoryPool.AllocateRawThreadSafe() ) Animation( durationSeconds, speedFactor, playRange, loopCount, endAction, disconnectAction ); } -Animation::Animation( float durationSeconds, float speedFactor, const Vector2& playRange, int loopCount, Dali::Animation::EndAction endAction, Dali::Animation::EndAction disconnectAction ) +Animation::Animation( float durationSeconds, float speedFactor, const Vector2& playRange, int32_t loopCount, Dali::Animation::EndAction endAction, Dali::Animation::EndAction disconnectAction ) : mPlayRange( playRange ), mDurationSeconds( durationSeconds ), mDelaySeconds( 0.0f ), @@ -78,13 +78,12 @@ Animation::Animation( float durationSeconds, float speedFactor, const Vector2& p mDisconnectAction(disconnectAction), mState(Stopped), mProgressReachedSignalRequired( false ), - mAutoReverseEnabled( false ) + mAutoReverseEnabled( false ), + mIsActive{ false } { } -Animation::~Animation() -{ -} +Animation::~Animation() = default; void Animation::operator delete( void* ptr ) { @@ -105,7 +104,7 @@ void Animation::SetProgressNotification( float progress ) } } -void Animation::SetLoopCount(int loopCount) +void Animation::SetLoopCount(int32_t loopCount) { mLoopCount = loopCount; mCurrentLoop = 0; @@ -122,9 +121,9 @@ void Animation::SetDisconnectAction(Dali::Animation::EndAction action) { mDisconnectAction = action; - for ( AnimatorIter iter = mAnimators.Begin(), endIter = mAnimators.End(); iter != endIter; ++iter ) + for ( auto&& item : mAnimators ) { - (*iter)->SetDisconnectAction( action ); + item->SetDisconnectAction( action ); } } } @@ -176,6 +175,8 @@ void Animation::PlayFrom( float progress ) mState = Playing; SetAnimatorsActive( true ); + + mCurrentLoop = 0; } } @@ -207,7 +208,7 @@ void Animation::Pause() void Animation::Bake(BufferIndex bufferIndex, EndAction action) { - if( action == Dali::Animation::BakeFinal ) + if( action == Dali::Animation::BAKE_FINAL ) { if( mSpeedFactor > 0.0f ) { @@ -224,9 +225,9 @@ void Animation::Bake(BufferIndex bufferIndex, EndAction action) void Animation::SetAnimatorsActive( bool active ) { - for ( AnimatorIter iter = mAnimators.Begin(), endIter = mAnimators.End(); iter != endIter; ++iter ) + for ( auto&& item : mAnimators ) { - (*iter)->SetActive( active ); + item->SetActive( active ); } } @@ -238,7 +239,7 @@ bool Animation::Stop(BufferIndex bufferIndex) { animationFinished = true; // The actor-thread should be notified of this - if( mEndAction != Dali::Animation::Discard ) + if( mEndAction != Dali::Animation::DISCARD ) { Bake( bufferIndex, mEndAction ); @@ -264,7 +265,7 @@ void Animation::OnDestroy(BufferIndex bufferIndex) { if (mState == Playing || mState == Paused) { - if (mEndAction != Dali::Animation::Discard) + if (mEndAction != Dali::Animation::DISCARD) { Bake( bufferIndex, mEndAction ); @@ -283,13 +284,12 @@ void Animation::SetLoopingMode( bool loopingMode ) { mAutoReverseEnabled = loopingMode; - for ( AnimatorIter iter = mAnimators.Begin(), endIter = mAnimators.End(); iter != endIter; ++iter ) + for ( auto&& item : mAnimators ) { // Send some variables together to figure out the Animation status - (*iter)->SetSpeedFactor( mSpeedFactor ); - (*iter)->SetLoopCount( mLoopCount ); - - (*iter)->SetLoopingMode( loopingMode ); + item->SetSpeedFactor( mSpeedFactor ); + item->SetLoopCount( mLoopCount ); + item->SetLoopingMode( loopingMode ); } } @@ -301,7 +301,7 @@ void Animation::AddAnimator( OwnerPointer& animator ) mAnimators.PushBack( animator.Release() ); } -void Animation::Update(BufferIndex bufferIndex, float elapsedSeconds, bool& looped, bool& finished, bool& progressReached ) +void Animation::Update( BufferIndex bufferIndex, float elapsedSeconds, bool& looped, bool& finished, bool& progressReached ) { looped = false; finished = false; @@ -315,20 +315,19 @@ void Animation::Update(BufferIndex bufferIndex, float elapsedSeconds, bool& loop // The animation must still be applied when Paused/Stopping if (mState == Playing) { + // Sign value of speed factor. It can optimize many arithmetic comparision + float signSpeedFactor = ( mSpeedFactor < 0.0f ) ? -1.f : 1.f; + // If there is delay time before Animation starts, wait the Animation until mDelaySeconds. if( mDelaySeconds > 0.0f ) { float reduceSeconds = fabsf( elapsedSeconds * mSpeedFactor ); if( reduceSeconds > mDelaySeconds ) { - if( mSpeedFactor < 0.0f ) - { - mElapsedSeconds -= reduceSeconds - mDelaySeconds; - } - else - { - mElapsedSeconds += reduceSeconds - mDelaySeconds; - } + // add overflowed time to mElapsedSecond. + // If speed factor > 0, add it. if speed factor < 0, subtract it. + float overflowSeconds = reduceSeconds - mDelaySeconds; + mElapsedSeconds += signSpeedFactor * overflowSeconds; mDelaySeconds = 0.0f; } else @@ -341,120 +340,154 @@ void Animation::Update(BufferIndex bufferIndex, float elapsedSeconds, bool& loop mElapsedSeconds += ( elapsedSeconds * mSpeedFactor ); } - if ( mProgressReachedSignalRequired && ( mElapsedSeconds >= mProgressMarker ) ) - { - // The application should be notified by NotificationManager, in another thread - progressReached = true; - mProgressReachedSignalRequired = false; - } - } + const float playRangeStartSeconds = mPlayRange.x * mDurationSeconds; + const float playRangeEndSeconds = mPlayRange.y * mDurationSeconds; + // Final reached seconds. It can optimize many arithmetic comparision + float edgeRangeSeconds = ( mSpeedFactor < 0.0f ) ? playRangeStartSeconds : playRangeEndSeconds; - Vector2 playRangeSeconds = mPlayRange * mDurationSeconds; + // Optimized Factors. + // elapsed > edge --> check if looped + // elapsed >= marker --> check if elapsed reached to marker in normal case + // edge >= marker --> check if elapsed reached to marker in looped case + float elapsedFactor = signSpeedFactor * mElapsedSeconds; + float edgeFactor = signSpeedFactor * edgeRangeSeconds; + float markerFactor = signSpeedFactor * mProgressMarker; - if( 0 == mLoopCount || 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 )) ); + // check it is looped + looped = ( elapsedFactor > edgeFactor ); - WrapInPlayRange( mElapsedSeconds, playRangeSeconds ); + if( looped ) + { + WrapInPlayRange( mElapsedSeconds, playRangeStartSeconds, playRangeEndSeconds ); - UpdateAnimators(bufferIndex, false, false ); + // Recalculate elapsedFactor here + elapsedFactor = signSpeedFactor * mElapsedSeconds; - if(looped) - { if( mLoopCount != 0 ) { + // Check If this animation is finished ++mCurrentLoop; - } - mProgressReachedSignalRequired = mProgressMarker > 0.0f; - // 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 )) ); + if( mCurrentLoop >= mLoopCount ) + { + DALI_ASSERT_DEBUG( mCurrentLoop == mLoopCount ); + finished = true; - // update with bake if finished - UpdateAnimators(bufferIndex, finished && (mEndAction != Dali::Animation::Discard), finished ); + // The animation has now been played to completion + ++mPlayedCount; - if(finished) - { - // The animation has now been played to completion - ++mPlayedCount; + // Make elapsed second as edge of range forcely. + mElapsedSeconds = edgeRangeSeconds + signSpeedFactor * Math::MACHINE_EPSILON_10; + UpdateAnimators(bufferIndex, finished && (mEndAction != Dali::Animation::DISCARD), finished ); - // loop iterations come to this else branch for their final iterations - if( mCurrentLoop < mLoopCount) - { - ++mCurrentLoop; - DALI_ASSERT_DEBUG(mCurrentLoop == mLoopCount); + // After update animation, mElapsedSeconds must be begin of value + mElapsedSeconds = playRangeStartSeconds + playRangeEndSeconds - edgeRangeSeconds; + mState = Stopped; + } } - mProgressReachedSignalRequired = mProgressMarker > 0.0f; - mElapsedSeconds = playRangeSeconds.x; - mState = Stopped; + // when it is on looped state, 2 case to send progress signal. + // (require && range_value >= marker) || << Signal at previous loop + // (marker > 0 && !finished && elaped >= marker) << Signal at current loop + if( ( mProgressMarker > 0.0f ) && !finished && ( elapsedFactor >= markerFactor ) ) + { + // The application should be notified by NotificationManager, in another thread + progressReached = true; + mProgressReachedSignalRequired = false; + } + else + { + if( mProgressReachedSignalRequired && ( edgeFactor >= markerFactor ) ) + { + progressReached = true; + } + mProgressReachedSignalRequired = mProgressMarker > 0.0f; + } } + else + { + // when it is not on looped state, only 1 case to send progress signal. + // (require && elaped >= marker) + if( mProgressReachedSignalRequired && ( elapsedFactor >= markerFactor ) ) + { + // The application should be notified by NotificationManager, in another thread + progressReached = true; + mProgressReachedSignalRequired = false; + } + } + } + + // Already updated when finished. So skip. + if( !finished ) + { + UpdateAnimators(bufferIndex, false, false ); } } void Animation::UpdateAnimators( BufferIndex bufferIndex, bool bake, bool animationFinished ) { + mIsActive[bufferIndex] = false; + const Vector2 playRange( mPlayRange * mDurationSeconds ); float elapsedSecondsClamped = Clamp( mElapsedSeconds, playRange.x, playRange.y ); + bool cleanup = false; + //Loop through all animators - bool applied(true); - for ( AnimatorIter iter = mAnimators.Begin(); iter != mAnimators.End(); ) + for(auto& animator : mAnimators) { - AnimatorBase *animator = *iter; - - if( animator->Orphan() ) + if(animator->Orphan()) { - //Remove animators whose PropertyOwner has been destroyed - iter = mAnimators.Erase(iter); + cleanup = true; + continue; } - else + + bool applied(true); + if(animator->IsEnabled()) { - if( animator->IsEnabled() ) - { - const float intervalDelay( animator->GetIntervalDelay() ); + const float intervalDelay(animator->GetIntervalDelay()); - if( elapsedSecondsClamped >= intervalDelay ) + 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" { - // 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 - intervalDelay) / animatorDuration, 0.0f , 1.0f ); - } - animator->Update(bufferIndex, progress, bake); + progress = Clamp((elapsedSecondsClamped - intervalDelay) / animatorDuration, 0.0f, 1.0f); } - applied = true; - } - else - { - applied = false; - } + animator->Update(bufferIndex, progress, bake); - if ( animationFinished ) - { - animator->SetActive( false ); + if (animatorDuration > 0.0f && (elapsedSecondsClamped - intervalDelay) <= animatorDuration) + { + mIsActive[bufferIndex] = true; + } } + applied = true; + } + else + { + applied = false; + } - if (applied) - { - INCREASE_COUNTER(PerformanceMonitor::ANIMATORS_APPLIED); - } + if(animationFinished) + { + animator->SetActive(false); + } - ++iter; + if(applied) + { + INCREASE_COUNTER(PerformanceMonitor::ANIMATORS_APPLIED); } } + if(cleanup) + { + //Remove animators whose PropertyOwner has been destroyed + mAnimators.Erase(std::remove_if(mAnimators.begin(), + mAnimators.end(), + [](auto& animator) { return animator->Orphan(); }), + mAnimators.end()); + } } } // namespace SceneGraph