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>
36 float DefaultAlphaFunc(float progress)
38 return progress; // linear
41 Animation::Animation( float durationSeconds, float speedFactor, const Vector2& playRange, bool isLooping, Dali::Animation::EndAction endAction, Dali::Animation::EndAction disconnectAction )
42 : mDurationSeconds(durationSeconds),
43 mSpeedFactor( speedFactor ),
45 mEndAction(endAction),
46 mDisconnectAction(disconnectAction),
48 mElapsedSeconds(playRange.x*mDurationSeconds),
50 mPlayRange( playRange )
54 Animation::~Animation()
58 void Animation::SetDuration(float durationSeconds)
60 DALI_ASSERT_DEBUG(durationSeconds > 0.0f);
62 mDurationSeconds = durationSeconds;
65 void Animation::SetLooping(bool looping)
70 void Animation::SetEndAction(Dali::Animation::EndAction action)
75 void Animation::SetDisconnectAction(Dali::Animation::EndAction action)
77 if ( mDisconnectAction != action )
79 mDisconnectAction = action;
81 for ( AnimatorIter iter = mAnimators.Begin(), endIter = mAnimators.End(); iter != endIter; ++iter )
83 (*iter)->SetDisconnectAction( action );
88 void Animation::SetPlayRange( const Vector2& range )
92 //Make sure mElapsedSeconds is within the new range
93 mElapsedSeconds = Dali::Clamp(mElapsedSeconds, mPlayRange.x*mDurationSeconds , mPlayRange.y*mDurationSeconds );
96 void Animation::Play()
100 if ( mSpeedFactor < 0.0f && mElapsedSeconds <= mPlayRange.x*mDurationSeconds )
102 mElapsedSeconds = mPlayRange.y * mDurationSeconds;
105 SetAnimatorsActive( true );
108 void Animation::PlayFrom( float progress )
110 //If the animation is already playing this has no effect
111 if( mState != Playing )
113 mElapsedSeconds = progress * mDurationSeconds;
116 SetAnimatorsActive( true );
120 void Animation::Pause()
122 if (mState == Playing)
128 void Animation::Bake(BufferIndex bufferIndex, EndAction action)
130 if( action == Dali::Animation::BakeFinal )
132 if( mSpeedFactor > 0.0f )
134 mElapsedSeconds = mPlayRange.y*mDurationSeconds + Math::MACHINE_EPSILON_1; // Force animation to reach it's end
138 mElapsedSeconds = mPlayRange.x*mDurationSeconds - Math::MACHINE_EPSILON_1; //Force animation to reach it's beginning
142 UpdateAnimators( bufferIndex, true/*bake the final result*/, true /*animation finished*/ );
145 void Animation::SetAnimatorsActive( bool active )
147 for ( AnimatorIter iter = mAnimators.Begin(), endIter = mAnimators.End(); iter != endIter; ++iter )
149 (*iter)->SetActive( active );
153 bool Animation::Stop(BufferIndex bufferIndex)
155 bool animationFinished(false);
157 if (mState == Playing || mState == Paused)
159 animationFinished = true; // The actor-thread should be notified of this
161 if( mEndAction != Dali::Animation::Discard )
163 Bake( bufferIndex, mEndAction );
165 // Animators are automatically set to inactive in Bake
169 SetAnimatorsActive( false );
172 // The animation has now been played to completion
176 mElapsedSeconds = mPlayRange.x*mDurationSeconds;
179 return animationFinished;
182 void Animation::OnDestroy(BufferIndex bufferIndex)
184 if (mState == Playing || mState == Paused)
186 if (mEndAction != Dali::Animation::Discard)
188 Bake( bufferIndex, mEndAction );
190 // Animators are automatically set to inactive in Bake
194 SetAnimatorsActive( false );
201 void Animation::AddAnimator( AnimatorBase* animator )
203 animator->SetDisconnectAction( mDisconnectAction );
204 mAnimators.PushBack( animator );
207 bool Animation::Update(BufferIndex bufferIndex, float elapsedSeconds)
209 if (mState == Stopped || mState == Destroyed)
211 // Short circuit when animation isn't running
215 // The animation must still be applied when Paused/Stopping
216 if (mState == Playing)
218 mElapsedSeconds += elapsedSeconds * mSpeedFactor;
221 Vector2 playRangeSeconds = mPlayRange * mDurationSeconds;
224 if (mElapsedSeconds > playRangeSeconds.y )
226 mElapsedSeconds = playRangeSeconds.x + fmod(mElapsedSeconds, playRangeSeconds.y);
228 else if( mElapsedSeconds < playRangeSeconds.x )
230 mElapsedSeconds = playRangeSeconds.y - fmod(mElapsedSeconds, playRangeSeconds.y);
234 const bool animationFinished(mState == Playing &&
235 (( mSpeedFactor > 0.0f && mElapsedSeconds > playRangeSeconds.y ) ||
236 ( mSpeedFactor < 0.0f && mElapsedSeconds < playRangeSeconds.x ))
239 UpdateAnimators(bufferIndex, animationFinished && (mEndAction != Dali::Animation::Discard), animationFinished);
241 if (animationFinished)
243 // The animation has now been played to completion
246 mElapsedSeconds = playRangeSeconds.x;
250 return animationFinished;
253 void Animation::UpdateAnimators( BufferIndex bufferIndex, bool bake, bool animationFinished )
255 float elapsedSecondsClamped = Clamp( mElapsedSeconds, mPlayRange.x * mDurationSeconds,mPlayRange.y * mDurationSeconds );
257 //Loop through all animators
259 for ( AnimatorIter iter = mAnimators.Begin(); iter != mAnimators.End(); )
261 AnimatorBase *animator = *iter;
263 if( animator->Orphan() )
265 //Remove animators whose PropertyOwner has been destroyed
266 iter = mAnimators.Erase(iter);
270 if( animator->IsEnabled() )
272 const float initialDelay(animator->GetInitialDelay());
273 if (elapsedSecondsClamped >= initialDelay || mSpeedFactor < 0.0f )
275 // Calculate a progress specific to each individual animator
276 float progress(1.0f);
277 const float animatorDuration = animator->GetDuration();
278 if (animatorDuration > 0.0f) // animators can be "immediate"
280 progress = Clamp((elapsedSecondsClamped - initialDelay) / animatorDuration, 0.0f , 1.0f );
282 animator->Update(bufferIndex, progress, bake);
291 if ( animationFinished )
293 animator->SetActive( false );
298 INCREASE_COUNTER(PerformanceMonitor::ANIMATORS_APPLIED);
307 } // namespace SceneGraph
309 } // namespace Internal