2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/internal/update/animation/scene-graph-animation.h>
22 #include <cmath> // fmod
25 #include <dali/internal/common/memory-pool-object-allocator.h>
26 #include <dali/internal/render/common/performance-monitor.h>
28 namespace //Unnamed namespace
30 //Memory pool used to allocate new animations. Memory used by this pool will be released when shutting down DALi
31 Dali::Internal::MemoryPoolObjectAllocator<Dali::Internal::SceneGraph::Animation> gAnimationMemoryPool;
43 Animation* Animation::New( float durationSeconds, float speedFactor, const Vector2& playRange, bool isLooping, EndAction endAction, EndAction disconnectAction )
45 return new ( gAnimationMemoryPool.AllocateRawThreadSafe() ) Animation( durationSeconds, speedFactor, playRange, isLooping, endAction, disconnectAction );
48 Animation::Animation( float durationSeconds, float speedFactor, const Vector2& playRange, bool isLooping, Dali::Animation::EndAction endAction, Dali::Animation::EndAction disconnectAction )
49 : mDurationSeconds(durationSeconds),
50 mSpeedFactor( speedFactor ),
52 mEndAction(endAction),
53 mDisconnectAction(disconnectAction),
55 mElapsedSeconds(playRange.x*mDurationSeconds),
57 mPlayRange( playRange )
61 Animation::~Animation()
65 void Animation::operator delete( void* ptr )
67 gAnimationMemoryPool.FreeThreadSafe( static_cast<Animation*>( ptr ) );
70 void Animation::SetDuration(float durationSeconds)
72 mDurationSeconds = durationSeconds;
75 void Animation::SetLooping(bool looping)
80 void Animation::SetEndAction(Dali::Animation::EndAction action)
85 void Animation::SetDisconnectAction(Dali::Animation::EndAction action)
87 if ( mDisconnectAction != action )
89 mDisconnectAction = action;
91 for ( AnimatorIter iter = mAnimators.Begin(), endIter = mAnimators.End(); iter != endIter; ++iter )
93 (*iter)->SetDisconnectAction( action );
98 void Animation::SetPlayRange( const Vector2& range )
102 //Make sure mElapsedSeconds is within the new range
103 mElapsedSeconds = Dali::Clamp(mElapsedSeconds, mPlayRange.x*mDurationSeconds , mPlayRange.y*mDurationSeconds );
106 void Animation::Play()
110 if ( mSpeedFactor < 0.0f && mElapsedSeconds <= mPlayRange.x*mDurationSeconds )
112 mElapsedSeconds = mPlayRange.y * mDurationSeconds;
115 SetAnimatorsActive( true );
118 void Animation::PlayFrom( float progress )
120 //If the animation is already playing this has no effect
121 if( mState != Playing )
123 mElapsedSeconds = progress * mDurationSeconds;
126 SetAnimatorsActive( true );
130 void Animation::Pause()
132 if (mState == Playing)
138 void Animation::Bake(BufferIndex bufferIndex, EndAction action)
140 if( action == Dali::Animation::BakeFinal )
142 if( mSpeedFactor > 0.0f )
144 mElapsedSeconds = mPlayRange.y*mDurationSeconds + Math::MACHINE_EPSILON_1; // Force animation to reach it's end
148 mElapsedSeconds = mPlayRange.x*mDurationSeconds - Math::MACHINE_EPSILON_1; //Force animation to reach it's beginning
152 UpdateAnimators( bufferIndex, true/*bake the final result*/, true /*animation finished*/ );
155 void Animation::SetAnimatorsActive( bool active )
157 for ( AnimatorIter iter = mAnimators.Begin(), endIter = mAnimators.End(); iter != endIter; ++iter )
159 (*iter)->SetActive( active );
163 bool Animation::Stop(BufferIndex bufferIndex)
165 bool animationFinished(false);
167 if (mState == Playing || mState == Paused)
169 animationFinished = true; // The actor-thread should be notified of this
171 if( mEndAction != Dali::Animation::Discard )
173 Bake( bufferIndex, mEndAction );
175 // Animators are automatically set to inactive in Bake
179 SetAnimatorsActive( false );
182 // The animation has now been played to completion
186 mElapsedSeconds = mPlayRange.x*mDurationSeconds;
189 return animationFinished;
192 void Animation::OnDestroy(BufferIndex bufferIndex)
194 if (mState == Playing || mState == Paused)
196 if (mEndAction != Dali::Animation::Discard)
198 Bake( bufferIndex, mEndAction );
200 // Animators are automatically set to inactive in Bake
204 SetAnimatorsActive( false );
211 void Animation::AddAnimator( AnimatorBase* animator )
213 animator->ConnectToSceneGraph();
214 animator->SetDisconnectAction( mDisconnectAction );
216 mAnimators.PushBack( animator );
219 bool Animation::Update(BufferIndex bufferIndex, float elapsedSeconds)
221 if (mState == Stopped || mState == Destroyed)
223 // Short circuit when animation isn't running
227 // The animation must still be applied when Paused/Stopping
228 if (mState == Playing)
230 mElapsedSeconds += elapsedSeconds * mSpeedFactor;
233 Vector2 playRangeSeconds = mPlayRange * mDurationSeconds;
236 if (mElapsedSeconds > playRangeSeconds.y )
238 mElapsedSeconds = playRangeSeconds.x + fmod(mElapsedSeconds, playRangeSeconds.y);
240 else if( mElapsedSeconds < playRangeSeconds.x )
242 mElapsedSeconds = playRangeSeconds.y - fmod(mElapsedSeconds, playRangeSeconds.y);
246 const bool animationFinished(mState == Playing &&
247 (( mSpeedFactor > 0.0f && mElapsedSeconds > playRangeSeconds.y ) ||
248 ( mSpeedFactor < 0.0f && mElapsedSeconds < playRangeSeconds.x ))
251 UpdateAnimators(bufferIndex, animationFinished && (mEndAction != Dali::Animation::Discard), animationFinished);
253 if (animationFinished)
255 // The animation has now been played to completion
258 mElapsedSeconds = playRangeSeconds.x;
262 return animationFinished;
265 void Animation::UpdateAnimators( BufferIndex bufferIndex, bool bake, bool animationFinished )
267 float elapsedSecondsClamped = Clamp( mElapsedSeconds, mPlayRange.x * mDurationSeconds,mPlayRange.y * mDurationSeconds );
269 //Loop through all animators
271 for ( AnimatorIter iter = mAnimators.Begin(); iter != mAnimators.End(); )
273 AnimatorBase *animator = *iter;
275 if( animator->Orphan() )
277 //Remove animators whose PropertyOwner has been destroyed
278 iter = mAnimators.Erase(iter);
282 if( animator->IsEnabled() )
284 const float initialDelay(animator->GetInitialDelay());
285 if (elapsedSecondsClamped >= initialDelay || mSpeedFactor < 0.0f )
287 // Calculate a progress specific to each individual animator
288 float progress(1.0f);
289 const float animatorDuration = animator->GetDuration();
290 if (animatorDuration > 0.0f) // animators can be "immediate"
292 progress = Clamp((elapsedSecondsClamped - initialDelay) / animatorDuration, 0.0f , 1.0f );
294 animator->Update(bufferIndex, progress, bake);
303 if ( animationFinished )
305 animator->SetActive( false );
310 INCREASE_COUNTER(PerformanceMonitor::ANIMATORS_APPLIED);
319 } // namespace SceneGraph
321 } // namespace Internal