License conversion from Flora to Apache 2.0
[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::Pause()
86 {
87   if (mState == Playing)
88   {
89     mState = Paused;
90   }
91 }
92
93 bool Animation::Stop(BufferIndex bufferIndex)
94 {
95   bool animationFinished(false);
96
97   if (mState == Playing || mState == Paused)
98   {
99     animationFinished = true; // The actor-thread should be notified of this
100
101     if( mEndAction != Dali::Animation::Discard )
102     {
103       if( mEndAction == Dali::Animation::BakeFinal )
104       {
105         mElapsedSeconds = mDurationSeconds + Math::MACHINE_EPSILON_1; // Force animation to reach it's end
106       }
107       UpdateAnimators(bufferIndex, true/*bake the final result*/);
108     }
109
110     // The animation has now been played to completion
111     ++mPlayCount;
112   }
113
114   mElapsedSeconds = 0.0f;
115   mState = Stopped;
116
117   return animationFinished;
118 }
119
120 void Animation::OnDestroy(BufferIndex bufferIndex)
121 {
122   if (mState == Playing || mState == Paused)
123   {
124     if (mDestroyAction != Dali::Animation::Discard)
125     {
126       UpdateAnimators(bufferIndex, true/*bake the final result*/);
127     }
128   }
129
130   mState = Destroyed;
131 }
132
133 void Animation::AddAnimator( AnimatorBase* animator, PropertyOwner* propertyOwner )
134 {
135   animator->Attach( propertyOwner );
136
137   mAnimators.PushBack( animator );
138 }
139
140 bool Animation::Update(BufferIndex bufferIndex, float elapsedSeconds)
141 {
142   if (mState == Stopped || mState == Destroyed)
143   {
144     // Short circuit when animation isn't running
145     return false;
146   }
147
148   // The animation must still be applied when Paused/Stopping
149   if (mState == Playing)
150   {
151     mElapsedSeconds += elapsedSeconds;
152   }
153
154   if (mLooping)
155   {
156     if (mElapsedSeconds > mDurationSeconds)
157     {
158       mElapsedSeconds = fmod(mElapsedSeconds, mDurationSeconds);
159     }
160   }
161
162   const bool animationFinished(mState == Playing && mElapsedSeconds > mDurationSeconds);
163
164   UpdateAnimators(bufferIndex, animationFinished && (mEndAction != Dali::Animation::Discard));
165
166   if (animationFinished)
167   {
168     // The animation has now been played to completion
169     ++mPlayCount;
170
171     mElapsedSeconds = 0.0f;
172     mState = Stopped;
173   }
174
175   return animationFinished;
176 }
177
178 void Animation::UpdateAnimators(BufferIndex bufferIndex, bool bake)
179 {
180   for ( AnimatorIter iter = mAnimators.Begin(); iter != mAnimators.End(); )
181   {
182     // If an animator is not successfully applied, then it has been orphaned
183     bool applied(true);
184
185     AnimatorBase *animator = *iter;
186     const float initialDelay(animator->GetInitialDelay());
187
188     if (mElapsedSeconds >= initialDelay)
189     {
190       // Calculate a progress specific to each individual animator
191       float progress(1.0f);
192       const float animatorDuration = animator->GetDuration();
193       if (animatorDuration > 0.0f) // animators can be "immediate"
194       {
195         progress = min(1.0f, (mElapsedSeconds - initialDelay) / animatorDuration);
196       }
197
198       applied = animator->Update(bufferIndex, progress, bake);
199     }
200
201     // Animators are automatically removed, when orphaned from animatable scene objects.
202     if (!applied)
203     {
204       iter = mAnimators.Erase(iter);
205     }
206     else
207     {
208       ++iter;
209
210       INCREASE_COUNTER(PerformanceMonitor::ANIMATORS_APPLIED);
211     }
212   }
213 }
214
215 } // namespace SceneGraph
216
217 } // namespace Internal
218
219 } // namespace Dali