Merge "Event-side size storage in Actor." into tizen
[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, float speedFactor, bool isLooping, Dali::Animation::EndAction endAction, Dali::Animation::EndAction destroyAction)
44 : mDurationSeconds(durationSeconds),
45   mSpeedFactor( speedFactor ),
46   mLooping(isLooping),
47   mEndAction(endAction),
48   mDestroyAction(destroyAction),
49   mState(Stopped),
50   mElapsedSeconds(0.0f),
51   mPlayCount(0)
52 {
53 }
54
55 Animation::~Animation()
56 {
57 }
58
59 void Animation::SetDuration(float durationSeconds)
60 {
61   DALI_ASSERT_DEBUG(durationSeconds > 0.0f);
62
63   mDurationSeconds = durationSeconds;
64 }
65
66 void Animation::SetLooping(bool looping)
67 {
68   mLooping = looping;
69 }
70
71 void Animation::SetEndAction(Dali::Animation::EndAction action)
72 {
73   mEndAction = action;
74 }
75
76 void Animation::SetDestroyAction(Dali::Animation::EndAction action)
77 {
78   mDestroyAction = action;
79 }
80
81 void Animation::Play()
82 {
83   mState = Playing;
84
85   if ( mSpeedFactor < 0.0f && mElapsedSeconds <= 0.0f )
86   {
87     mElapsedSeconds = mDurationSeconds;
88   }
89 }
90
91 void Animation::PlayFrom( float progress )
92 {
93   //If the animation is already playing this has no effect
94   if( mState != Playing )
95   {
96     mElapsedSeconds = progress * mDurationSeconds;
97     mState = Playing;
98   }
99 }
100
101 void Animation::Pause()
102 {
103   if (mState == Playing)
104   {
105     mState = Paused;
106   }
107 }
108
109 void Animation::Bake(BufferIndex bufferIndex, EndAction action)
110 {
111   if( action == Dali::Animation::BakeFinal )
112   {
113     if( mSpeedFactor > 0.0f )
114     {
115       mElapsedSeconds = mDurationSeconds + Math::MACHINE_EPSILON_1; // Force animation to reach it's end
116     }
117     else
118     {
119       mElapsedSeconds = 0.0f - Math::MACHINE_EPSILON_1; //Force animation to reach it's beginning
120     }
121   }
122
123   UpdateAnimators(bufferIndex, true/*bake the final result*/);
124 }
125
126 bool Animation::Stop(BufferIndex bufferIndex)
127 {
128   bool animationFinished(false);
129
130   if (mState == Playing || mState == Paused)
131   {
132     animationFinished = true; // The actor-thread should be notified of this
133
134     if( mEndAction != Dali::Animation::Discard )
135     {
136       Bake( bufferIndex, mEndAction );
137     }
138
139     // The animation has now been played to completion
140     ++mPlayCount;
141   }
142
143   mElapsedSeconds = 0.0f;
144   mState = Stopped;
145
146   return animationFinished;
147 }
148
149 void Animation::OnDestroy(BufferIndex bufferIndex)
150 {
151   if (mState == Playing || mState == Paused)
152   {
153     if (mDestroyAction != Dali::Animation::Discard)
154     {
155       Bake( bufferIndex, mDestroyAction );
156     }
157   }
158
159   mState = Destroyed;
160 }
161
162 void Animation::AddAnimator( AnimatorBase* animator, PropertyOwner* propertyOwner )
163 {
164   animator->Attach( propertyOwner );
165
166   mAnimators.PushBack( animator );
167 }
168
169 bool Animation::Update(BufferIndex bufferIndex, float elapsedSeconds)
170 {
171   if (mState == Stopped || mState == Destroyed)
172   {
173     // Short circuit when animation isn't running
174     return false;
175   }
176
177   // The animation must still be applied when Paused/Stopping
178   if (mState == Playing)
179   {
180     mElapsedSeconds += elapsedSeconds * mSpeedFactor;
181   }
182
183   if (mLooping)
184   {
185     if (mElapsedSeconds > mDurationSeconds )
186     {
187       mElapsedSeconds = fmod(mElapsedSeconds, mDurationSeconds);
188     }
189     else if( mElapsedSeconds < 0.0f )
190     {
191       mElapsedSeconds = mDurationSeconds - fmod(mElapsedSeconds, mDurationSeconds);
192     }
193   }
194
195
196   const bool animationFinished(mState == Playing                                              &&
197                               (( mSpeedFactor > 0.0f && mElapsedSeconds > mDurationSeconds )  ||
198                                ( mSpeedFactor < 0.0f && mElapsedSeconds < 0.0f ))
199                               );
200
201   UpdateAnimators(bufferIndex, animationFinished && (mEndAction != Dali::Animation::Discard));
202
203   if (animationFinished)
204   {
205     // The animation has now been played to completion
206     ++mPlayCount;
207
208     mElapsedSeconds = 0.0f;
209     mState = Stopped;
210   }
211
212   return animationFinished;
213 }
214
215 void Animation::UpdateAnimators(BufferIndex bufferIndex, bool bake)
216 {
217   for ( AnimatorIter iter = mAnimators.Begin(); iter != mAnimators.End(); )
218   {
219     // If an animator is not successfully applied, then it has been orphaned
220     bool applied(true);
221
222     AnimatorBase *animator = *iter;
223     const float initialDelay(animator->GetInitialDelay());
224
225     if (mElapsedSeconds >= initialDelay || mSpeedFactor < 0.0f )
226     {
227       // Calculate a progress specific to each individual animator
228       float progress(1.0f);
229       const float animatorDuration = animator->GetDuration();
230       if (animatorDuration > 0.0f) // animators can be "immediate"
231       {
232         progress = Clamp((mElapsedSeconds - initialDelay) / animatorDuration, 0.0f , 1.0f );
233       }
234
235       applied = animator->Update(bufferIndex, progress, bake);
236     }
237
238     // Animators are automatically removed, when orphaned from animatable scene objects.
239     if (!applied)
240     {
241       iter = mAnimators.Erase(iter);
242     }
243     else
244     {
245       ++iter;
246
247       INCREASE_COUNTER(PerformanceMonitor::ANIMATORS_APPLIED);
248     }
249   }
250 }
251
252 } // namespace SceneGraph
253
254 } // namespace Internal
255
256 } // namespace Dali