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