8b1b925ea5ff9c65a7efdf67defff1bdf1eb95bf
[platform/core/uifw/dali-core.git] / dali / internal / update / animation / scene-graph-animation.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/update/animation/scene-graph-animation.h>
20
21 // EXTERNAL INCLUDES
22 #include <cmath> // fmod
23
24 // INTERNAL INCLUDES
25 #include <dali/internal/render/common/performance-monitor.h>
26
27 using namespace std;
28
29 namespace Dali
30 {
31
32 namespace Internal
33 {
34
35 namespace SceneGraph
36 {
37
38 float DefaultAlphaFunc(float progress)
39 {
40   return progress; // linear
41 }
42
43 Animation::Animation(float durationSeconds, bool isLooping, Dali::Animation::EndAction endAction, Dali::Animation::EndAction destroyAction)
44 : mDurationSeconds(durationSeconds),
45   mLooping(isLooping),
46   mEndAction(endAction),
47   mDestroyAction(destroyAction),
48   mState(Stopped),
49   mElapsedSeconds(0.0f),
50   mPlayCount(0)
51 {
52 }
53
54 Animation::~Animation()
55 {
56 }
57
58 void Animation::SetDuration(float durationSeconds)
59 {
60   DALI_ASSERT_DEBUG(durationSeconds > 0.0f);
61
62   mDurationSeconds = durationSeconds;
63 }
64
65 void Animation::SetLooping(bool looping)
66 {
67   mLooping = looping;
68 }
69
70 void Animation::SetEndAction(Dali::Animation::EndAction action)
71 {
72   mEndAction = action;
73 }
74
75 void Animation::SetDestroyAction(Dali::Animation::EndAction action)
76 {
77   mDestroyAction = action;
78 }
79
80 void Animation::Play()
81 {
82   mState = Playing;
83 }
84
85 void Animation::PlayFrom( float progress )
86 {
87   //If the animation is already playing this has no effect
88   if( mState != Playing )
89   {
90     mElapsedSeconds = progress * mDurationSeconds;
91     mState = Playing;
92   }
93 }
94
95 void Animation::Pause()
96 {
97   if (mState == Playing)
98   {
99     mState = Paused;
100   }
101 }
102
103 bool Animation::Stop(BufferIndex bufferIndex)
104 {
105   bool animationFinished(false);
106
107   if (mState == Playing || mState == Paused)
108   {
109     animationFinished = true; // The actor-thread should be notified of this
110
111     if( mEndAction != Dali::Animation::Discard )
112     {
113       if( mEndAction == Dali::Animation::BakeFinal )
114       {
115         mElapsedSeconds = mDurationSeconds + Math::MACHINE_EPSILON_1; // Force animation to reach it's end
116       }
117       UpdateAnimators(bufferIndex, true/*bake the final result*/);
118     }
119
120     // The animation has now been played to completion
121     ++mPlayCount;
122   }
123
124   mElapsedSeconds = 0.0f;
125   mState = Stopped;
126
127   return animationFinished;
128 }
129
130 void Animation::OnDestroy(BufferIndex bufferIndex)
131 {
132   if (mState == Playing || mState == Paused)
133   {
134     if (mDestroyAction != Dali::Animation::Discard)
135     {
136       UpdateAnimators(bufferIndex, true/*bake the final result*/);
137     }
138   }
139
140   mState = Destroyed;
141 }
142
143 void Animation::AddAnimator( AnimatorBase* animator, PropertyOwner* propertyOwner )
144 {
145   animator->Attach( propertyOwner );
146
147   mAnimators.PushBack( animator );
148 }
149
150 bool Animation::Update(BufferIndex bufferIndex, float elapsedSeconds)
151 {
152   if (mState == Stopped || mState == Destroyed)
153   {
154     // Short circuit when animation isn't running
155     return false;
156   }
157
158   // The animation must still be applied when Paused/Stopping
159   if (mState == Playing)
160   {
161     mElapsedSeconds += elapsedSeconds;
162   }
163
164   if (mLooping)
165   {
166     if (mElapsedSeconds > mDurationSeconds)
167     {
168       mElapsedSeconds = fmod(mElapsedSeconds, mDurationSeconds);
169     }
170   }
171
172   const bool animationFinished(mState == Playing && mElapsedSeconds > mDurationSeconds);
173
174   UpdateAnimators(bufferIndex, animationFinished && (mEndAction != Dali::Animation::Discard));
175
176   if (animationFinished)
177   {
178     // The animation has now been played to completion
179     ++mPlayCount;
180
181     mElapsedSeconds = 0.0f;
182     mState = Stopped;
183   }
184
185   return animationFinished;
186 }
187
188 void Animation::UpdateAnimators(BufferIndex bufferIndex, bool bake)
189 {
190   for ( AnimatorIter iter = mAnimators.Begin(); iter != mAnimators.End(); )
191   {
192     // If an animator is not successfully applied, then it has been orphaned
193     bool applied(true);
194
195     AnimatorBase *animator = *iter;
196     const float initialDelay(animator->GetInitialDelay());
197
198     if (mElapsedSeconds >= initialDelay)
199     {
200       // Calculate a progress specific to each individual animator
201       float progress(1.0f);
202       const float animatorDuration = animator->GetDuration();
203       if (animatorDuration > 0.0f) // animators can be "immediate"
204       {
205         progress = min(1.0f, (mElapsedSeconds - initialDelay) / animatorDuration);
206       }
207
208       applied = animator->Update(bufferIndex, progress, bake);
209     }
210
211     // Animators are automatically removed, when orphaned from animatable scene objects.
212     if (!applied)
213     {
214       iter = mAnimators.Erase(iter);
215     }
216     else
217     {
218       ++iter;
219
220       INCREASE_COUNTER(PerformanceMonitor::ANIMATORS_APPLIED);
221     }
222   }
223 }
224
225 } // namespace SceneGraph
226
227 } // namespace Internal
228
229 } // namespace Dali