Make sure that global variables are initialized lazily.
[platform/core/uifw/dali-core.git] / dali / internal / update / animation / scene-graph-animation.cpp
index 167dcaa..659547f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
 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<Dali::Internal::SceneGraph::Animation> gAnimationMemoryPool;
+Dali::Internal::MemoryPoolObjectAllocator<Dali::Internal::SceneGraph::Animation>& GetAnimationMemoryPool()
+{
+  static Dali::Internal::MemoryPoolObjectAllocator<Dali::Internal::SceneGraph::Animation> gAnimationMemoryPool;
+  return gAnimationMemoryPool;
+}
 
-inline void WrapInPlayRange( float& elapsed, const float& playRangeStartSeconds, const float& playRangeEndSeconds)
+inline void WrapInPlayRange(float& elapsed, const float& playRangeStartSeconds, const float& playRangeEndSeconds)
 {
-  if( elapsed > playRangeEndSeconds )
+  if(elapsed > playRangeEndSeconds)
   {
-    elapsed = playRangeStartSeconds + fmodf( ( elapsed - playRangeStartSeconds ), ( playRangeEndSeconds - playRangeStartSeconds ) );
+    elapsed = playRangeStartSeconds + fmodf((elapsed - playRangeStartSeconds), (playRangeEndSeconds - playRangeStartSeconds));
   }
-  else if( elapsed < playRangeStartSeconds )
+  else if(elapsed < playRangeStartSeconds)
   {
-    elapsed = playRangeEndSeconds - fmodf( ( playRangeStartSeconds - elapsed ), ( playRangeEndSeconds - playRangeStartSeconds ) );
+    elapsed = playRangeEndSeconds - fmodf((playRangeStartSeconds - elapsed), (playRangeEndSeconds - playRangeStartSeconds));
   }
 }
 
 /// 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 )
+bool CompareAnimatorEndTimes(const Dali::Internal::SceneGraph::AnimatorBase* lhs, const Dali::Internal::SceneGraph::AnimatorBase* rhs)
 {
-  return ( ( lhs->GetIntervalDelay() + lhs->GetDuration() ) < ( rhs->GetIntervalDelay() + rhs->GetDuration() ) );
+  return ((lhs->GetIntervalDelay() + lhs->GetDuration()) < (rhs->GetIntervalDelay() + rhs->GetDuration()));
 }
 
 } // unnamed namespace
 
 namespace Dali
 {
-
 namespace Internal
 {
-
 namespace SceneGraph
 {
-
-Animation* Animation::New( float durationSeconds, float speedFactor, const Vector2& playRange, int32_t 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 );
+  return new(GetAnimationMemoryPool().AllocateRawThreadSafe()) Animation(durationSeconds, speedFactor, playRange, loopCount, 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 ),
-  mElapsedSeconds( playRange.x*mDurationSeconds ),
-  mSpeedFactor( speedFactor ),
-  mProgressMarker( 0.0f ),
-  mPlayedCount( 0 ),
+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),
+  mElapsedSeconds(playRange.x * mDurationSeconds),
+  mSpeedFactor(speedFactor),
+  mProgressMarker(0.0f),
+  mPlayedCount(0),
   mLoopCount(loopCount),
   mCurrentLoop(0),
   mEndAction(endAction),
   mDisconnectAction(disconnectAction),
   mState(Stopped),
-  mProgressReachedSignalRequired( false ),
-  mAutoReverseEnabled( false )
+  mProgressReachedSignalRequired(false),
+  mAutoReverseEnabled(false),
+  mIsActive{false}
 {
 }
 
-Animation::~Animation()
-{
-}
+Animation::~Animation() = default;
 
-void Animation::operator delete( void* ptr )
+void Animation::operator delete(void* ptr)
 {
-  gAnimationMemoryPool.FreeThreadSafe( static_cast<Animation*>( ptr ) );
+  GetAnimationMemoryPool().FreeThreadSafe(static_cast<Animation*>(ptr));
 }
 
 void Animation::SetDuration(float durationSeconds)
@@ -96,10 +96,10 @@ void Animation::SetDuration(float durationSeconds)
   mDurationSeconds = durationSeconds;
 }
 
-void Animation::SetProgressNotification( float progress )
+void Animation::SetProgressNotification(float progress)
 {
   mProgressMarker = progress;
-  if ( mProgressMarker > 0.0f )
+  if(mProgressMarker > 0.0f)
   {
     mProgressReachedSignalRequired = true;
   }
@@ -107,7 +107,7 @@ void Animation::SetProgressNotification( float progress )
 
 void Animation::SetLoopCount(int32_t loopCount)
 {
-  mLoopCount = loopCount;
+  mLoopCount   = loopCount;
   mCurrentLoop = 0;
 }
 
@@ -118,24 +118,24 @@ void Animation::SetEndAction(Dali::Animation::EndAction action)
 
 void Animation::SetDisconnectAction(Dali::Animation::EndAction action)
 {
-  if ( mDisconnectAction != action )
+  if(mDisconnectAction != action)
   {
     mDisconnectAction = action;
 
-    for ( auto&& item : mAnimators )
+    for(auto&& item : mAnimators)
     {
-      item->SetDisconnectAction( action );
+      item->SetDisconnectAction(action);
     }
   }
 }
 
-void Animation::SetPlayRange( const Vector2& range )
+void Animation::SetPlayRange(const Vector2& range)
 {
   mPlayRange = range;
 
   // Make sure mElapsedSeconds is within the new range
 
-  if( mState == Stopped )
+  if(mState == Stopped)
   {
     // Ensure that the animation starts at the right place
     mElapsedSeconds = mPlayRange.x * mDurationSeconds;
@@ -145,55 +145,55 @@ void Animation::SetPlayRange( const Vector2& range )
     // If already past the end of the range, but before end of duration, then clamp will
     // ensure that the animation stops on the next update.
     // If not yet at the start of the range, clamping will jump to the start
-    mElapsedSeconds = Dali::Clamp(mElapsedSeconds, mPlayRange.x*mDurationSeconds , mPlayRange.y*mDurationSeconds );
+    mElapsedSeconds = Dali::Clamp(mElapsedSeconds, mPlayRange.x * mDurationSeconds, mPlayRange.y * mDurationSeconds);
   }
 }
 
 void Animation::Play()
 {
   // Sort according to end time with earlier end times coming first, if the end time is the same, then the animators are not moved
-  std::stable_sort( mAnimators.Begin(), mAnimators.End(), CompareAnimatorEndTimes );
+  std::stable_sort(mAnimators.Begin(), mAnimators.End(), CompareAnimatorEndTimes);
 
   mState = Playing;
 
-  if ( mSpeedFactor < 0.0f && mElapsedSeconds <= mPlayRange.x*mDurationSeconds )
+  if(mSpeedFactor < 0.0f && mElapsedSeconds <= mPlayRange.x * mDurationSeconds)
   {
     mElapsedSeconds = mPlayRange.y * mDurationSeconds;
   }
 
-  SetAnimatorsActive( true );
+  SetAnimatorsActive(true);
 
   mCurrentLoop = 0;
 }
 
-void Animation::PlayFrom( float progress )
+void Animation::PlayFrom(float progress)
 {
   // If the animation is already playing this has no effect
   // Progress is guaranteed to be in range.
-  if( mState != Playing )
+  if(mState != Playing)
   {
     mElapsedSeconds = progress * mDurationSeconds;
-    mState = Playing;
+    mState          = Playing;
 
-    SetAnimatorsActive( true );
+    SetAnimatorsActive(true);
 
     mCurrentLoop = 0;
   }
 }
 
-void Animation::PlayAfter( float delaySeconds )
+void Animation::PlayAfter(float delaySeconds)
 {
-  if( mState != Playing )
+  if(mState != Playing)
   {
     mDelaySeconds = delaySeconds;
-    mState = Playing;
+    mState        = Playing;
 
-    if ( mSpeedFactor < 0.0f && mElapsedSeconds <= mPlayRange.x*mDurationSeconds )
+    if(mSpeedFactor < 0.0f && mElapsedSeconds <= mPlayRange.x * mDurationSeconds)
     {
       mElapsedSeconds = mPlayRange.y * mDurationSeconds;
     }
 
-    SetAnimatorsActive( true );
+    SetAnimatorsActive(true);
 
     mCurrentLoop = 0;
   }
@@ -201,7 +201,7 @@ void Animation::PlayAfter( float delaySeconds )
 
 void Animation::Pause()
 {
-  if (mState == Playing)
+  if(mState == Playing)
   {
     mState = Paused;
   }
@@ -209,26 +209,26 @@ 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 )
+    if(mSpeedFactor > 0.0f)
     {
-      mElapsedSeconds = mPlayRange.y*mDurationSeconds + Math::MACHINE_EPSILON_1; // Force animation to reach it's end
+      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
+      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*/ );
+  UpdateAnimators(bufferIndex, true /*bake the final result*/, true /*animation finished*/);
 }
 
-void Animation::SetAnimatorsActive( bool active )
+void Animation::SetAnimatorsActive(bool active)
 {
-  for ( auto&& item : mAnimators )
+  for(auto&& item : mAnimators)
   {
-    item->SetActive( active );
+    item->SetActive(active);
   }
 }
 
@@ -236,19 +236,19 @@ bool Animation::Stop(BufferIndex bufferIndex)
 {
   bool animationFinished(false);
 
-  if (mState == Playing || mState == Paused)
+  if(mState == Playing || mState == Paused)
   {
     animationFinished = true; // The actor-thread should be notified of this
 
-    if( mEndAction != Dali::Animation::Discard )
+    if(mEndAction != Dali::Animation::DISCARD)
     {
-      Bake( bufferIndex, mEndAction );
+      Bake(bufferIndex, mEndAction);
 
       // Animators are automatically set to inactive in Bake
     }
     else
     {
-      SetAnimatorsActive( false );
+      SetAnimatorsActive(false);
     }
 
     // The animation has now been played to completion
@@ -256,74 +256,74 @@ bool Animation::Stop(BufferIndex bufferIndex)
     mCurrentLoop = 0;
   }
 
-  mElapsedSeconds = mPlayRange.x*mDurationSeconds;
-  mState = Stopped;
+  mElapsedSeconds = mPlayRange.x * mDurationSeconds;
+  mState          = Stopped;
 
   return animationFinished;
 }
 
 void Animation::OnDestroy(BufferIndex bufferIndex)
 {
-  if (mState == Playing || mState == Paused)
+  if(mState == Playing || mState == Paused)
   {
-    if (mEndAction != Dali::Animation::Discard)
+    if(mEndAction != Dali::Animation::DISCARD)
     {
-      Bake( bufferIndex, mEndAction );
+      Bake(bufferIndex, mEndAction);
 
       // Animators are automatically set to inactive in Bake
     }
     else
     {
-      SetAnimatorsActive( false );
+      SetAnimatorsActive(false);
     }
   }
 
   mState = Destroyed;
 }
 
-void Animation::SetLoopingMode( bool loopingMode )
+void Animation::SetLoopingMode(bool loopingMode)
 {
   mAutoReverseEnabled = loopingMode;
 
-  for ( auto&& item : mAnimators )
+  for(auto&& item : mAnimators)
   {
     // Send some variables together to figure out the Animation status
-    item->SetSpeedFactor( mSpeedFactor );
-    item->SetLoopCount( mLoopCount );
-    item->SetLoopingMode( loopingMode );
+    item->SetSpeedFactor(mSpeedFactor);
+    item->SetLoopCount(mLoopCount);
+    item->SetLoopingMode(loopingMode);
   }
 }
 
-void Animation::AddAnimator( OwnerPointer<AnimatorBase>& animator )
+void Animation::AddAnimator(OwnerPointer<AnimatorBase>& animator)
 {
   animator->ConnectToSceneGraph();
-  animator->SetDisconnectAction( mDisconnectAction );
+  animator->SetDisconnectAction(mDisconnectAction);
 
-  mAnimators.PushBack( animator.Release() );
+  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;
+  looped   = false;
   finished = false;
 
-  if (mState == Stopped || mState == Destroyed)
+  if(mState == Stopped || mState == Destroyed)
   {
     // Short circuit when animation isn't running
     return;
   }
 
   // The animation must still be applied when Paused/Stopping
-  if (mState == Playing)
+  if(mState == Playing)
   {
     // Sign value of speed factor. It can optimize many arithmetic comparision
-    float signSpeedFactor = ( mSpeedFactor < 0.0f ) ? -1.f : 1.f;
+    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 )
+    if(mDelaySeconds > 0.0f)
     {
-      float reduceSeconds = fabsf( elapsedSeconds * mSpeedFactor );
-      if( reduceSeconds > mDelaySeconds )
+      float reduceSeconds = fabsf(elapsedSeconds * mSpeedFactor);
+      if(reduceSeconds > mDelaySeconds)
       {
         // add overflowed time to mElapsedSecond.
         // If speed factor > 0, add it. if speed factor < 0, subtract it.
@@ -338,39 +338,39 @@ void Animation::Update( BufferIndex bufferIndex, float elapsedSeconds, bool& loo
     }
     else
     {
-      mElapsedSeconds += ( elapsedSeconds * mSpeedFactor );
+      mElapsedSeconds += (elapsedSeconds * mSpeedFactor);
     }
 
     const float playRangeStartSeconds = mPlayRange.x * mDurationSeconds;
-    const float playRangeEndSeconds = mPlayRange.y * mDurationSeconds;
+    const float playRangeEndSeconds   = mPlayRange.y * mDurationSeconds;
     // Final reached seconds. It can optimize many arithmetic comparision
-    float edgeRangeSeconds = ( mSpeedFactor < 0.0f ) ? playRangeStartSeconds : playRangeEndSeconds;
+    float edgeRangeSeconds = (mSpeedFactor < 0.0f) ? playRangeStartSeconds : playRangeEndSeconds;
 
     // 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;
+    float edgeFactor    = signSpeedFactor * edgeRangeSeconds;
+    float markerFactor  = signSpeedFactor * mProgressMarker;
 
     // check it is looped
-    looped = ( elapsedFactor > edgeFactor );
+    looped = (elapsedFactor > edgeFactor);
 
-    if( looped )
+    if(looped)
     {
-      WrapInPlayRange( mElapsedSeconds, playRangeStartSeconds, playRangeEndSeconds );
+      WrapInPlayRange(mElapsedSeconds, playRangeStartSeconds, playRangeEndSeconds);
 
       // Recalculate elapsedFactor here
       elapsedFactor = signSpeedFactor * mElapsedSeconds;
 
-      if( mLoopCount != 0 )
+      if(mLoopCount != 0)
       {
         // Check If this animation is finished
         ++mCurrentLoop;
-        if( mCurrentLoop >= mLoopCount )
+        if(mCurrentLoop >= mLoopCount)
         {
-          DALI_ASSERT_DEBUG( mCurrentLoop == mLoopCount );
+          DALI_ASSERT_DEBUG(mCurrentLoop == mLoopCount);
           finished = true;
 
           // The animation has now been played to completion
@@ -378,26 +378,26 @@ void Animation::Update( BufferIndex bufferIndex, float elapsedSeconds, bool& loo
 
           // Make elapsed second as edge of range forcely.
           mElapsedSeconds = edgeRangeSeconds + signSpeedFactor * Math::MACHINE_EPSILON_10;
-          UpdateAnimators(bufferIndex, finished && (mEndAction != Dali::Animation::Discard), finished );
+          UpdateAnimators(bufferIndex, finished && (mEndAction != Dali::Animation::DISCARD), finished);
 
           // After update animation, mElapsedSeconds must be begin of value
           mElapsedSeconds = playRangeStartSeconds + playRangeEndSeconds - edgeRangeSeconds;
-          mState = Stopped;
+          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 ) )
+      if((mProgressMarker > 0.0f) && !finished && (elapsedFactor >= markerFactor))
       {
         // The application should be notified by NotificationManager, in another thread
-        progressReached = true;
+        progressReached                = true;
         mProgressReachedSignalRequired = false;
       }
       else
       {
-        if( mProgressReachedSignalRequired && ( edgeFactor >= markerFactor ) )
+        if(mProgressReachedSignalRequired && (edgeFactor >= markerFactor))
         {
           progressReached = true;
         }
@@ -408,76 +408,89 @@ void Animation::Update( BufferIndex bufferIndex, float elapsedSeconds, bool& loo
     {
       // when it is not on looped state, only 1 case to send progress signal.
       // (require && elaped >= marker)
-      if( mProgressReachedSignalRequired && ( elapsedFactor >= markerFactor ) )
+      if(mProgressReachedSignalRequired && (elapsedFactor >= markerFactor))
       {
         // The application should be notified by NotificationManager, in another thread
-        progressReached = true;
+        progressReached                = true;
         mProgressReachedSignalRequired = false;
       }
     }
   }
 
   // Already updated when finished. So skip.
-  if( !finished )
+  if(!finished)
   {
-    UpdateAnimators(bufferIndex, false, false );
+    UpdateAnimators(bufferIndex, false, false);
   }
 }
 
-void Animation::UpdateAnimators( BufferIndex bufferIndex, bool bake, bool animationFinished )
+void Animation::UpdateAnimators(BufferIndex bufferIndex, bool bake, bool animationFinished)
 {
-  const Vector2 playRange( mPlayRange * mDurationSeconds );
-  float elapsedSecondsClamped = Clamp( mElapsedSeconds, playRange.x, playRange.y );
+  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 ( auto&& 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.EraseIf([](auto& animator) { return animator->Orphan(); });
+  }
+}
+
+uint32_t Animation::GetMemoryPoolCapacity()
+{
+  return GetAnimationMemoryPool().GetCapacity();
 }
 
 } // namespace SceneGraph