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/render/common/performance-monitor.h>
38 float DefaultAlphaFunc(float progress)
40 return progress; // linear
43 Animation::Animation(float durationSeconds, float speedFactor, const Vector2& playRange, bool isLooping, Dali::Animation::EndAction endAction, Dali::Animation::EndAction destroyAction)
44 : mDurationSeconds(durationSeconds),
45 mSpeedFactor( speedFactor ),
47 mEndAction(endAction),
48 mDestroyAction(destroyAction),
50 mElapsedSeconds(playRange.x*mDurationSeconds),
52 mPlayRange( playRange )
56 Animation::~Animation()
60 void Animation::SetDuration(float durationSeconds)
62 DALI_ASSERT_DEBUG(durationSeconds > 0.0f);
64 mDurationSeconds = durationSeconds;
67 void Animation::SetLooping(bool looping)
72 void Animation::SetEndAction(Dali::Animation::EndAction action)
77 void Animation::SetDestroyAction(Dali::Animation::EndAction action)
79 mDestroyAction = action;
82 void Animation::SetPlayRange( const Vector2& range )
86 //Make sure mElapsedSeconds is within the new range
87 mElapsedSeconds = Dali::Clamp(mElapsedSeconds, mPlayRange.x*mDurationSeconds , mPlayRange.y*mDurationSeconds );
90 void Animation::Play()
94 if ( mSpeedFactor < 0.0f && mElapsedSeconds <= mPlayRange.x*mDurationSeconds )
96 mElapsedSeconds = mPlayRange.y * mDurationSeconds;
100 void Animation::PlayFrom( float progress )
102 //If the animation is already playing this has no effect
103 if( mState != Playing )
105 mElapsedSeconds = progress * mDurationSeconds;
110 void Animation::Pause()
112 if (mState == Playing)
118 void Animation::Bake(BufferIndex bufferIndex, EndAction action)
120 if( action == Dali::Animation::BakeFinal )
122 if( mSpeedFactor > 0.0f )
124 mElapsedSeconds = mPlayRange.y*mDurationSeconds + Math::MACHINE_EPSILON_1; // Force animation to reach it's end
128 mElapsedSeconds = mPlayRange.x*mDurationSeconds - Math::MACHINE_EPSILON_1; //Force animation to reach it's beginning
132 UpdateAnimators(bufferIndex, true/*bake the final result*/);
135 bool Animation::Stop(BufferIndex bufferIndex)
137 bool animationFinished(false);
139 if (mState == Playing || mState == Paused)
141 animationFinished = true; // The actor-thread should be notified of this
143 if( mEndAction != Dali::Animation::Discard )
145 Bake( bufferIndex, mEndAction );
148 // The animation has now been played to completion
152 mElapsedSeconds = mPlayRange.x*mDurationSeconds;
155 return animationFinished;
158 void Animation::OnDestroy(BufferIndex bufferIndex)
160 if (mState == Playing || mState == Paused)
162 if (mDestroyAction != Dali::Animation::Discard)
164 Bake( bufferIndex, mDestroyAction );
171 void Animation::AddAnimator( AnimatorBase* animator, PropertyOwner* propertyOwner )
173 animator->Attach( propertyOwner );
175 mAnimators.PushBack( animator );
178 bool Animation::Update(BufferIndex bufferIndex, float elapsedSeconds)
180 if (mState == Stopped || mState == Destroyed)
182 // Short circuit when animation isn't running
186 // The animation must still be applied when Paused/Stopping
187 if (mState == Playing)
189 mElapsedSeconds += elapsedSeconds * mSpeedFactor;
192 Vector2 playRangeSeconds = mPlayRange * mDurationSeconds;
195 if (mElapsedSeconds > playRangeSeconds.y )
197 mElapsedSeconds = playRangeSeconds.x + fmod(mElapsedSeconds, playRangeSeconds.y);
199 else if( mElapsedSeconds < playRangeSeconds.x )
201 mElapsedSeconds = playRangeSeconds.y - fmod(mElapsedSeconds, playRangeSeconds.y);
205 const bool animationFinished(mState == Playing &&
206 (( mSpeedFactor > 0.0f && mElapsedSeconds > playRangeSeconds.y ) ||
207 ( mSpeedFactor < 0.0f && mElapsedSeconds < playRangeSeconds.x ))
210 UpdateAnimators(bufferIndex, animationFinished && (mEndAction != Dali::Animation::Discard));
212 if (animationFinished)
214 // The animation has now been played to completion
217 mElapsedSeconds = playRangeSeconds.x;
221 return animationFinished;
224 void Animation::UpdateAnimators(BufferIndex bufferIndex, bool bake)
226 float elapsedSecondsClamped = Clamp( mElapsedSeconds, mPlayRange.x * mDurationSeconds,mPlayRange.y * mDurationSeconds );
227 for ( AnimatorIter iter = mAnimators.Begin(); iter != mAnimators.End(); )
229 // If an animator is not successfully applied, then it has been orphaned
232 AnimatorBase *animator = *iter;
233 const float initialDelay(animator->GetInitialDelay());
235 if (elapsedSecondsClamped >= initialDelay || mSpeedFactor < 0.0f )
237 // Calculate a progress specific to each individual animator
238 float progress(1.0f);
239 const float animatorDuration = animator->GetDuration();
240 if (animatorDuration > 0.0f) // animators can be "immediate"
242 progress = Clamp((elapsedSecondsClamped - initialDelay) / animatorDuration, 0.0f , 1.0f );
245 applied = animator->Update(bufferIndex, progress, bake);
248 // Animators are automatically removed, when orphaned from animatable scene objects.
251 iter = mAnimators.Erase(iter);
257 INCREASE_COUNTER(PerformanceMonitor::ANIMATORS_APPLIED);
262 } // namespace SceneGraph
264 } // namespace Internal