6a914c309872db703c88f1209a1436986508f09d
[platform/core/uifw/dali-core.git] / dali / internal / event / animation / animation-impl.cpp
1 /*
2  * Copyright (c) 2018 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/event/animation/animation-impl.h>
20 #include <dali/public-api/object/property-map.h>
21
22 // EXTERNAL INCLUDES
23
24 // INTERNAL INCLUDES
25 #include <dali/public-api/animation/alpha-function.h>
26 #include <dali/public-api/animation/time-period.h>
27 #include <dali/public-api/common/dali-common.h>
28 #include <dali/public-api/object/type-registry.h>
29 #include <dali/public-api/math/vector2.h>
30 #include <dali/public-api/math/radian.h>
31 #include <dali/internal/event/animation/animation-playlist.h>
32 #include <dali/internal/event/animation/animator-connector.h>
33 #include <dali/internal/event/animation/path-impl.h>
34 #include <dali/internal/event/common/notification-manager.h>
35 #include <dali/internal/event/common/property-helper.h>
36 #include <dali/internal/event/common/stage-impl.h>
37 #include <dali/internal/event/common/thread-local-storage.h>
38 #include <dali/internal/update/animation/scene-graph-animator.h>
39 #include <dali/internal/update/manager/update-manager.h>
40
41 using Dali::Internal::SceneGraph::UpdateManager;
42 using Dali::Internal::SceneGraph::AnimatorBase;
43 using Dali::Internal::SceneGraph::Shader;
44
45 namespace Dali
46 {
47
48 namespace Internal
49 {
50
51 static bool SHOW_VALUE = true;
52 static bool HIDE_VALUE = false;
53
54 namespace
55 {
56
57 // Signals
58
59 const char* const SIGNAL_FINISHED = "finished";
60
61 // Actions
62
63 const char* const ACTION_PLAY =     "play";
64 const char* const ACTION_STOP =     "stop";
65 const char* const ACTION_PAUSE =    "pause";
66
67 BaseHandle Create()
68 {
69   return Dali::Animation::New(0.f);
70 }
71
72 TypeRegistration mType( typeid( Dali::Animation ), typeid( Dali::BaseHandle ), Create );
73
74 SignalConnectorType signalConnector1( mType, SIGNAL_FINISHED, &Animation::DoConnectSignal );
75
76 TypeAction action1( mType, ACTION_PLAY,  &Animation::DoAction );
77 TypeAction action2( mType, ACTION_STOP,  &Animation::DoAction );
78 TypeAction action3( mType, ACTION_PAUSE, &Animation::DoAction );
79
80 const Dali::Animation::EndAction DEFAULT_END_ACTION( Dali::Animation::Bake );
81 const Dali::Animation::EndAction DEFAULT_DISCONNECT_ACTION( Dali::Animation::BakeFinal );
82 const Dali::Animation::Interpolation DEFAULT_INTERPOLATION( Dali::Animation::Linear );
83 const Dali::AlphaFunction DEFAULT_ALPHA_FUNCTION( Dali::AlphaFunction::DEFAULT );
84
85 } // anon namespace
86
87
88 AnimationPtr Animation::New(float durationSeconds)
89 {
90   Stage* stage = Stage::GetCurrent();
91
92   if( stage )
93   {
94     AnimationPlaylist& playlist = stage->GetAnimationPlaylist();
95
96     if( durationSeconds < 0.0f )
97     {
98       DALI_LOG_WARNING("duration should be greater than 0.0f.\n");
99       durationSeconds = 0.0f;
100     }
101
102     AnimationPtr animation = new Animation( *stage, playlist, durationSeconds, DEFAULT_END_ACTION, DEFAULT_DISCONNECT_ACTION, DEFAULT_ALPHA_FUNCTION );
103
104     // Second-phase construction
105     animation->Initialize();
106
107     return animation;
108   }
109   else
110   {
111     return NULL;
112   }
113 }
114
115 Animation::Animation( EventThreadServices& eventThreadServices, AnimationPlaylist& playlist, float durationSeconds, EndAction endAction, EndAction disconnectAction, AlphaFunction defaultAlpha )
116 : mAnimation( NULL ),
117   mEventThreadServices( eventThreadServices ),
118   mPlaylist( playlist ),
119   mFinishedSignal(),
120   mConnectors(),
121   mConnectorTargetValues(),
122   mPlayRange( Vector2(0.0f,1.0f)),
123   mDurationSeconds( durationSeconds ),
124   mSpeedFactor(1.0f),
125   mNotificationCount( 0 ),
126   mLoopCount(1),
127   mCurrentLoop(0),
128   mEndAction( endAction ),
129   mDisconnectAction( disconnectAction ),
130   mDefaultAlpha( defaultAlpha ),
131   mState(Dali::Animation::STOPPED),
132   mProgressReachedMarker( 0.0f ),
133   mDelaySeconds( 0.0f ),
134   mAutoReverseEnabled( false )
135 {
136 }
137
138 void Animation::Initialize()
139 {
140   // Connect to the animation playlist
141   mPlaylist.AnimationCreated( *this );
142
143   CreateSceneObject();
144
145   RegisterObject();
146 }
147
148 Animation::~Animation()
149 {
150   // Guard to allow handle destruction after Core has been destroyed
151   if ( Stage::IsInstalled() )
152   {
153     // Disconnect from the animation playlist
154     mPlaylist.AnimationDestroyed( *this );
155
156     DestroySceneObject();
157
158     UnregisterObject();
159   }
160 }
161
162 void Animation::CreateSceneObject()
163 {
164   DALI_ASSERT_DEBUG( mAnimation == NULL );
165
166   // Create a new animation, Keep a const pointer to the animation.
167   mAnimation = SceneGraph::Animation::New( mDurationSeconds, mSpeedFactor, mPlayRange, mLoopCount, mEndAction, mDisconnectAction );
168   OwnerPointer< SceneGraph::Animation > transferOwnership( const_cast< SceneGraph::Animation* >( mAnimation ) );
169   AddAnimationMessage( mEventThreadServices.GetUpdateManager(), transferOwnership );
170 }
171
172 void Animation::DestroySceneObject()
173 {
174   if ( mAnimation != NULL )
175   {
176     // Remove animation using a message to the update manager
177     RemoveAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
178     mAnimation = NULL;
179   }
180 }
181
182 void Animation::SetDuration(float seconds)
183 {
184   if( seconds < 0.0f )
185   {
186     DALI_LOG_WARNING("duration should be greater than 0.0f.\n");
187     seconds = 0.0f;
188   }
189
190   mDurationSeconds = seconds;
191
192   // mAnimation is being used in a separate thread; queue a message to set the value
193   SetDurationMessage( mEventThreadServices, *mAnimation, seconds );
194 }
195
196 void Animation::SetProgressNotification( float progress )
197 {
198   // mAnimation is being used in a separate thread; queue a message to set the value
199   mProgressReachedMarker = progress;
200 }
201
202 float Animation::GetProgressNotification()
203 {
204   return mProgressReachedMarker;
205 }
206
207 float Animation::GetDuration() const
208 {
209   // This is not animatable; the cached value is up-to-date.
210   return mDurationSeconds;
211 }
212
213 void Animation::SetLooping(bool on)
214 {
215   SetLoopCount( on ? 0 : 1 );
216 }
217
218 void Animation::SetLoopCount(int count)
219 {
220   // Cache for public getters
221   mLoopCount = count;
222
223   // mAnimation is being used in a separate thread; queue a message to set the value
224   SetLoopingMessage( mEventThreadServices, *mAnimation, mLoopCount );
225 }
226
227 int Animation::GetLoopCount()
228 {
229   return mLoopCount;
230 }
231
232 int Animation::GetCurrentLoop()
233 {
234   return mCurrentLoop;
235 }
236
237 bool Animation::IsLooping() const
238 {
239   return mLoopCount != 1;
240 }
241
242 void Animation::SetEndAction(EndAction action)
243 {
244   // Cache for public getters
245   mEndAction = action;
246
247   // mAnimation is being used in a separate thread; queue a message to set the value
248   SetEndActionMessage( mEventThreadServices, *mAnimation, action );
249 }
250
251 Dali::Animation::EndAction Animation::GetEndAction() const
252 {
253   // This is not animatable; the cached value is up-to-date.
254   return mEndAction;
255 }
256
257 void Animation::SetDisconnectAction(EndAction action)
258 {
259   // Cache for public getters
260   mDisconnectAction = action;
261
262   // mAnimation is being used in a separate thread; queue a message to set the value
263   SetDisconnectActionMessage( mEventThreadServices, *mAnimation, action );
264 }
265
266 Dali::Animation::EndAction Animation::GetDisconnectAction() const
267 {
268   // This is not animatable; the cached value is up-to-date.
269   return mDisconnectAction;
270 }
271
272 void Animation::Play()
273 {
274   // Update the current playlist
275   mPlaylist.OnPlay( *this );
276
277   mState = Dali::Animation::PLAYING;
278
279   NotifyObjects();
280
281   SendFinalProgressNotificationMessage();
282
283   // mAnimation is being used in a separate thread; queue a Play message
284   PlayAnimationMessage( mEventThreadServices, *mAnimation );
285 }
286
287 void Animation::PlayFrom( float progress )
288 {
289   if( progress >= mPlayRange.x && progress <= mPlayRange.y )
290   {
291     // Update the current playlist
292     mPlaylist.OnPlay( *this );
293
294     mState = Dali::Animation::PLAYING;
295
296     NotifyObjects();
297
298     SendFinalProgressNotificationMessage();
299
300     // mAnimation is being used in a separate thread; queue a Play message
301     PlayAnimationFromMessage( mEventThreadServices, *mAnimation, progress );
302   }
303 }
304
305 void Animation::PlayAfter( float delaySeconds )
306 {
307   // The negative delay means play immediately.
308   delaySeconds = std::max( 0.f, delaySeconds );
309
310   mDelaySeconds = delaySeconds;
311
312   // Update the current playlist
313   mPlaylist.OnPlay( *this );
314
315   mState = Dali::Animation::PLAYING;
316
317   NotifyObjects();
318
319   SendFinalProgressNotificationMessage();
320
321   // mAnimation is being used in a separate thread; queue a message to set the value
322   PlayAfterMessage( mEventThreadServices, *mAnimation, delaySeconds );
323 }
324
325 void Animation::Pause()
326 {
327   mState = Dali::Animation::PAUSED;
328
329   // mAnimation is being used in a separate thread; queue a Pause message
330   PauseAnimationMessage( mEventThreadServices, *mAnimation );
331 }
332
333 Dali::Animation::State Animation::GetState() const
334 {
335   return mState;
336 }
337
338 void Animation::Stop()
339 {
340   mState = Dali::Animation::STOPPED;
341
342   // mAnimation is being used in a separate thread; queue a Stop message
343   StopAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
344 }
345
346 void Animation::Clear()
347 {
348   DALI_ASSERT_DEBUG(mAnimation);
349
350   // Remove all the connectors
351   mConnectors.Clear();
352
353   // Reset the connector target values
354   mConnectorTargetValues.clear();
355
356   // Replace the old scene-object with a new one
357   DestroySceneObject();
358   CreateSceneObject();
359
360   // Reset the notification count, since the new scene-object has never been played
361   mNotificationCount = 0;
362
363   // Update the current playlist
364   mPlaylist.OnClear( *this );
365 }
366
367 void Animation::AnimateBy(Property& target, Property::Value& relativeValue)
368 {
369   AnimateBy(target, relativeValue, mDefaultAlpha, TimePeriod(mDurationSeconds));
370 }
371
372 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha)
373 {
374   AnimateBy(target, relativeValue, alpha, TimePeriod(mDurationSeconds));
375 }
376
377 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, TimePeriod period)
378 {
379   AnimateBy(target, relativeValue, mDefaultAlpha, period);
380 }
381
382 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha, TimePeriod period)
383 {
384   Object& object = GetImplementation(target.object);
385   const Property::Type targetType = object.GetPropertyType(target.propertyIndex);
386   const Property::Type destinationType = relativeValue.GetType();
387
388   if ( object.GetPropertyComponentIndex( target.propertyIndex ) != Property::INVALID_COMPONENT_INDEX )
389   {
390     DALI_ASSERT_ALWAYS(Property::FLOAT == destinationType && "Animated value and Property type don't match");
391   }
392   else
393   {
394     DALI_ASSERT_ALWAYS(targetType == destinationType && "Animated value and Property type don't match");
395   }
396
397   ExtendDuration(period);
398
399   // Store data to later notify the object that its property is being animated
400   ConnectorTargetValues connectorPair;
401   connectorPair.targetValue = relativeValue;
402   connectorPair.connectorIndex = mConnectors.Count();
403   connectorPair.timePeriod = period;
404   connectorPair.animatorType = Animation::BY;
405   mConnectorTargetValues.push_back( connectorPair );
406
407   switch ( targetType )
408   {
409     case Property::BOOLEAN:
410     {
411       AddAnimatorConnector( AnimatorConnector<bool>::New( object,
412                                                           target.propertyIndex,
413                                                           target.componentIndex,
414                                                           new AnimateByBoolean(relativeValue.Get<bool>()),
415                                                           alpha,
416                                                           period ) );
417       break;
418     }
419
420     case Property::INTEGER:
421     {
422       AddAnimatorConnector( AnimatorConnector<int>::New( object,
423                                                          target.propertyIndex,
424                                                          target.componentIndex,
425                                                          new AnimateByInteger(relativeValue.Get<int>()),
426                                                          alpha,
427                                                          period ) );
428       break;
429     }
430
431     case Property::FLOAT:
432     {
433       AddAnimatorConnector( AnimatorConnector<float>::New( object,
434                                                            target.propertyIndex,
435                                                            target.componentIndex,
436                                                            new AnimateByFloat(relativeValue.Get<float>()),
437                                                            alpha,
438                                                            period ) );
439       break;
440     }
441
442     case Property::VECTOR2:
443     {
444       AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
445                                                              target.propertyIndex,
446                                                              target.componentIndex,
447                                                              new AnimateByVector2(relativeValue.Get<Vector2>()),
448                                                              alpha,
449                                                              period ) );
450       break;
451     }
452
453     case Property::VECTOR3:
454     {
455       AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
456                                                              target.propertyIndex,
457                                                              target.componentIndex,
458                                                              new AnimateByVector3(relativeValue.Get<Vector3>()),
459                                                              alpha,
460                                                              period ) );
461       break;
462     }
463
464     case Property::VECTOR4:
465     {
466       AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
467                                                              target.propertyIndex,
468                                                              target.componentIndex,
469                                                              new AnimateByVector4(relativeValue.Get<Vector4>()),
470                                                              alpha,
471                                                              period ) );
472       break;
473     }
474
475     case Property::ROTATION:
476     {
477       AngleAxis angleAxis = relativeValue.Get<AngleAxis>();
478
479       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
480                                                                 target.propertyIndex,
481                                                                 target.componentIndex,
482                                                                 new RotateByAngleAxis(angleAxis.angle, angleAxis.axis),
483                                                                 alpha,
484                                                                 period ) );
485       break;
486     }
487
488     default:
489     {
490       // non animatable types handled already
491     }
492   }
493 }
494
495 void Animation::AnimateTo(Property& target, Property::Value& destinationValue)
496 {
497   AnimateTo(target, destinationValue, mDefaultAlpha, TimePeriod(mDurationSeconds));
498 }
499
500 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha)
501 {
502   AnimateTo(target, destinationValue, alpha, TimePeriod(mDurationSeconds));
503 }
504
505 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, TimePeriod period)
506 {
507   AnimateTo(target, destinationValue, mDefaultAlpha, period);
508 }
509
510 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
511 {
512   Object& object = GetImplementation(target.object);
513
514   AnimateTo( object, target.propertyIndex, target.componentIndex, destinationValue, alpha, period );
515 }
516
517 void Animation::AnimateTo(Object& targetObject, Property::Index targetPropertyIndex, int componentIndex, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
518 {
519   Property::Type targetType = targetObject.GetPropertyType(targetPropertyIndex);
520   if( componentIndex != Property::INVALID_COMPONENT_INDEX )
521   {
522     if( ( targetType == Property::VECTOR2 ) ||
523         ( targetType == Property::VECTOR3 ) ||
524         ( targetType == Property::VECTOR4 ) )
525     {
526       targetType = Property::FLOAT;
527     }
528   }
529   const Property::Type destinationType = destinationValue.GetType();
530   DALI_ASSERT_ALWAYS( targetType == destinationType && "Animated value and Property type don't match" );
531
532   ExtendDuration( period );
533
534   // Store data to later notify the object that its property is being animated
535   ConnectorTargetValues connectorPair;
536   connectorPair.targetValue = destinationValue;
537   connectorPair.connectorIndex = mConnectors.Count();
538   connectorPair.timePeriod = period;
539   connectorPair.animatorType = Animation::TO;
540   mConnectorTargetValues.push_back( connectorPair );
541
542   switch ( destinationType )
543   {
544     case Property::BOOLEAN:
545     {
546       AddAnimatorConnector( AnimatorConnector<bool>::New( targetObject,
547                                                           targetPropertyIndex,
548                                                           componentIndex,
549                                                           new AnimateToBoolean( destinationValue.Get<bool>() ),
550                                                           alpha,
551                                                           period ) );
552       break;
553     }
554
555     case Property::INTEGER:
556     {
557       AddAnimatorConnector( AnimatorConnector<int>::New( targetObject,
558                                                          targetPropertyIndex,
559                                                          componentIndex,
560                                                          new AnimateToInteger( destinationValue.Get<int>() ),
561                                                          alpha,
562                                                          period ) );
563       break;
564     }
565
566     case Property::FLOAT:
567     {
568       AddAnimatorConnector( AnimatorConnector<float>::New( targetObject,
569                                                            targetPropertyIndex,
570                                                            componentIndex,
571                                                            new AnimateToFloat( destinationValue.Get<float>() ),
572                                                            alpha,
573                                                            period ) );
574       break;
575     }
576
577     case Property::VECTOR2:
578     {
579       AddAnimatorConnector( AnimatorConnector<Vector2>::New( targetObject,
580                                                              targetPropertyIndex,
581                                                              componentIndex,
582                                                              new AnimateToVector2( destinationValue.Get<Vector2>() ),
583                                                              alpha,
584                                                              period ) );
585       break;
586     }
587
588     case Property::VECTOR3:
589     {
590       AddAnimatorConnector( AnimatorConnector<Vector3>::New( targetObject,
591                                                              targetPropertyIndex,
592                                                              componentIndex,
593                                                              new AnimateToVector3( destinationValue.Get<Vector3>() ),
594                                                              alpha,
595                                                              period ) );
596       break;
597     }
598
599     case Property::VECTOR4:
600     {
601       AddAnimatorConnector( AnimatorConnector<Vector4>::New( targetObject,
602                                                              targetPropertyIndex,
603                                                              componentIndex,
604                                                              new AnimateToVector4( destinationValue.Get<Vector4>() ),
605                                                              alpha,
606                                                              period ) );
607       break;
608     }
609
610     case Property::ROTATION:
611     {
612       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( targetObject,
613                                                                 targetPropertyIndex,
614                                                                 componentIndex,
615                                                                 new RotateToQuaternion( destinationValue.Get<Quaternion>() ),
616                                                                 alpha,
617                                                                 period ) );
618       break;
619     }
620
621     default:
622     {
623       // non animatable types handled already
624     }
625   }
626 }
627
628 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames)
629 {
630   AnimateBetween(target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION );
631 }
632
633 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, Interpolation interpolation )
634 {
635   AnimateBetween(target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), interpolation );
636 }
637
638 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period)
639 {
640   AnimateBetween(target, keyFrames, mDefaultAlpha, period, DEFAULT_INTERPOLATION);
641 }
642
643 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period, Interpolation interpolation)
644 {
645   AnimateBetween(target, keyFrames, mDefaultAlpha, period, interpolation);
646 }
647
648 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha)
649 {
650   AnimateBetween(target, keyFrames, alpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION);
651 }
652
653 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, Interpolation interpolation)
654 {
655   AnimateBetween(target, keyFrames, alpha, TimePeriod(mDurationSeconds), interpolation);
656 }
657
658 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period)
659 {
660   AnimateBetween(target, keyFrames, alpha, period, DEFAULT_INTERPOLATION);
661 }
662
663 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period, Interpolation interpolation)
664 {
665   Object& object = GetImplementation( target.object );
666
667   ExtendDuration( period );
668
669   // Store data to later notify the object that its property is being animated
670   ConnectorTargetValues connectorPair;
671   connectorPair.targetValue = keyFrames.GetLastKeyFrameValue();
672   connectorPair.connectorIndex = mConnectors.Count();
673   connectorPair.timePeriod = period;
674   connectorPair.animatorType = BETWEEN;
675   mConnectorTargetValues.push_back( connectorPair );
676
677   switch(keyFrames.GetType())
678   {
679     case Dali::Property::BOOLEAN:
680     {
681       const KeyFrameBoolean* kf;
682       GetSpecialization(keyFrames, kf);
683       KeyFrameBooleanPtr kfCopy = KeyFrameBoolean::Clone(*kf);
684       AddAnimatorConnector( AnimatorConnector<bool>::New( object,
685                                                           target.propertyIndex,
686                                                           target.componentIndex,
687                                                           new KeyFrameBooleanFunctor(kfCopy),
688                                                           alpha,
689                                                           period ) );
690       break;
691     }
692
693     case Dali::Property::INTEGER:
694     {
695       const KeyFrameInteger* kf;
696       GetSpecialization(keyFrames, kf);
697       KeyFrameIntegerPtr kfCopy = KeyFrameInteger::Clone(*kf);
698       AddAnimatorConnector( AnimatorConnector<int>::New( object,
699                                                          target.propertyIndex,
700                                                          target.componentIndex,
701                                                          new KeyFrameIntegerFunctor(kfCopy,interpolation),
702                                                          alpha,
703                                                          period ) );
704       break;
705     }
706
707     case Dali::Property::FLOAT:
708     {
709       const KeyFrameNumber* kf;
710       GetSpecialization(keyFrames, kf);
711       KeyFrameNumberPtr kfCopy = KeyFrameNumber::Clone(*kf);
712       AddAnimatorConnector( AnimatorConnector<float>::New( object,
713                                                            target.propertyIndex,
714                                                            target.componentIndex,
715                                                            new KeyFrameNumberFunctor(kfCopy,interpolation),
716                                                            alpha,
717                                                            period ) );
718       break;
719     }
720
721     case Dali::Property::VECTOR2:
722     {
723       const KeyFrameVector2* kf;
724       GetSpecialization(keyFrames, kf);
725       KeyFrameVector2Ptr kfCopy = KeyFrameVector2::Clone(*kf);
726       AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
727                                                              target.propertyIndex,
728                                                              target.componentIndex,
729                                                              new KeyFrameVector2Functor(kfCopy,interpolation),
730                                                              alpha,
731                                                              period ) );
732       break;
733     }
734
735     case Dali::Property::VECTOR3:
736     {
737       const KeyFrameVector3* kf;
738       GetSpecialization(keyFrames, kf);
739       KeyFrameVector3Ptr kfCopy = KeyFrameVector3::Clone(*kf);
740       AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
741                                                              target.propertyIndex,
742                                                              target.componentIndex,
743                                                              new KeyFrameVector3Functor(kfCopy,interpolation),
744                                                              alpha,
745                                                              period ) );
746       break;
747     }
748
749     case Dali::Property::VECTOR4:
750     {
751       const KeyFrameVector4* kf;
752       GetSpecialization(keyFrames, kf);
753       KeyFrameVector4Ptr kfCopy = KeyFrameVector4::Clone(*kf);
754       AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
755                                                              target.propertyIndex,
756                                                              target.componentIndex,
757                                                              new KeyFrameVector4Functor(kfCopy,interpolation),
758                                                              alpha,
759                                                              period ) );
760       break;
761     }
762
763     case Dali::Property::ROTATION:
764     {
765       const KeyFrameQuaternion* kf;
766       GetSpecialization(keyFrames, kf);
767       KeyFrameQuaternionPtr kfCopy = KeyFrameQuaternion::Clone(*kf);
768       AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
769                                                                 target.propertyIndex,
770                                                                 target.componentIndex,
771                                                                 new KeyFrameQuaternionFunctor(kfCopy),
772                                                                 alpha,
773                                                                 period ) );
774       break;
775     }
776
777     default:
778     {
779       // non animatable types handled by keyframes
780     }
781   }
782 }
783
784 bool Animation::HasFinished()
785 {
786   bool hasFinished(false);
787   const int playedCount(mAnimation->GetPlayedCount());
788
789   // If the play count has been incremented, then another notification is required
790   mCurrentLoop = mAnimation->GetCurrentLoop();
791
792   if (playedCount > mNotificationCount)
793   {
794     // Note that only one signal is emitted, if the animation has been played repeatedly
795     mNotificationCount = playedCount;
796
797     hasFinished = true;
798
799     mState = Dali::Animation::STOPPED;
800   }
801
802   return hasFinished;
803 }
804
805 Dali::Animation::AnimationSignalType& Animation::FinishedSignal()
806 {
807   return mFinishedSignal;
808 }
809
810 Dali::Animation::AnimationSignalType& Animation::ProgressReachedSignal()
811 {
812   return mProgressReachedSignal;
813 }
814
815 void Animation::EmitSignalFinish()
816 {
817   if ( !mFinishedSignal.Empty() )
818   {
819     Dali::Animation handle( this );
820     mFinishedSignal.Emit( handle );
821   }
822 }
823
824 void Animation::EmitSignalProgressReached()
825 {
826   if ( !mProgressReachedSignal.Empty() )
827   {
828     Dali::Animation handle( this );
829     mProgressReachedSignal.Emit( handle );
830   }
831 }
832
833 bool Animation::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
834 {
835   bool connected( true );
836   Animation* animation = static_cast< Animation* >(object); // TypeRegistry guarantees that this is the correct type.
837
838   if( 0 == signalName.compare( SIGNAL_FINISHED ) )
839   {
840     animation->FinishedSignal().Connect( tracker, functor );
841   }
842   else
843   {
844     // signalName does not match any signal
845     connected = false;
846   }
847
848   return connected;
849 }
850
851 void Animation::AddAnimatorConnector( AnimatorConnectorBase* connector )
852 {
853   DALI_ASSERT_DEBUG( NULL != connector );
854
855   connector->SetParent(*this);
856
857   mConnectors.PushBack( connector );
858 }
859
860 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward )
861 {
862   Animate( actor, path, forward, mDefaultAlpha, TimePeriod(mDurationSeconds) );
863 }
864
865 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha )
866 {
867   Animate( actor, path, forward, alpha, TimePeriod(mDurationSeconds) );
868 }
869
870 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, TimePeriod period )
871 {
872   Animate( actor, path, forward, mDefaultAlpha, period );
873 }
874
875 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha, TimePeriod period)
876 {
877   ExtendDuration( period );
878
879   PathPtr pathCopy = Path::Clone(path);
880
881   //Position animation
882   AddAnimatorConnector( AnimatorConnector<Vector3>::New( actor,
883                                                          Dali::Actor::Property::POSITION,
884                                                          Property::INVALID_COMPONENT_INDEX,
885                                                          new PathPositionFunctor( pathCopy ),
886                                                          alpha,
887                                                          period ) );
888
889   //If forward is zero, PathRotationFunctor will always return the unit quaternion
890   if( forward != Vector3::ZERO )
891   {
892     //Rotation animation
893     AddAnimatorConnector( AnimatorConnector<Quaternion>::New( actor,
894                                                               Dali::Actor::Property::ORIENTATION,
895                                                               Property::INVALID_COMPONENT_INDEX,
896                                                               new PathRotationFunctor( pathCopy, forward ),
897                                                               alpha,
898                                                               period ) );
899   }
900 }
901
902 void Animation::Show(Actor& actor, float delaySeconds)
903 {
904   ExtendDuration( TimePeriod(delaySeconds, 0) );
905
906   AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
907                                                       Dali::Actor::Property::VISIBLE,
908                                                       Property::INVALID_COMPONENT_INDEX,
909                                                       new AnimateToBoolean(SHOW_VALUE),
910                                                       mDefaultAlpha,
911                                                       TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
912 }
913
914 void Animation::Hide(Actor& actor, float delaySeconds)
915 {
916   ExtendDuration( TimePeriod(delaySeconds, 0) );
917
918   AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
919                                                       Dali::Actor::Property::VISIBLE,
920                                                       Property::INVALID_COMPONENT_INDEX,
921                                                       new AnimateToBoolean(HIDE_VALUE),
922                                                       mDefaultAlpha,
923                                                       TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
924 }
925
926 bool Animation::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
927 {
928   bool done = false;
929   Animation* animation = dynamic_cast<Animation*>( object );
930
931   if( animation )
932   {
933     if( 0 == actionName.compare( ACTION_PLAY ) )
934     {
935       if( Property::Value* value = attributes.Find("duration", Property::FLOAT) )
936       {
937         animation->SetDuration( value->Get<float>() );
938       }
939
940       animation->Play();
941       done = true;
942     }
943     else if( 0 == actionName.compare( ACTION_STOP ) )
944     {
945       animation->Stop();
946       done = true;
947     }
948     else if( 0 == actionName.compare( ACTION_PAUSE ) )
949     {
950       animation->Pause();
951       done = true;
952     }
953   }
954
955   return done;
956 }
957
958 void Animation::SetCurrentProgress(float progress)
959 {
960   if( mAnimation && progress >= mPlayRange.x && progress <= mPlayRange.y )
961   {
962     // mAnimation is being used in a separate thread; queue a message to set the current progress
963     SetCurrentProgressMessage( mEventThreadServices, *mAnimation, progress );
964   }
965 }
966
967 float Animation::GetCurrentProgress()
968 {
969   if( mAnimation )
970   {
971     return mAnimation->GetCurrentProgress();
972   }
973
974   return 0.0f;
975 }
976
977 void Animation::ExtendDuration( const TimePeriod& timePeriod )
978 {
979   float duration = timePeriod.delaySeconds + timePeriod.durationSeconds;
980
981   if( duration > mDurationSeconds )
982   {
983     SetDuration( duration );
984   }
985 }
986
987 void Animation::SetSpeedFactor( float factor )
988 {
989   if( mAnimation )
990   {
991     mSpeedFactor = factor;
992     SetSpeedFactorMessage( mEventThreadServices, *mAnimation, factor );
993   }
994 }
995
996 float Animation::GetSpeedFactor() const
997 {
998   return mSpeedFactor;
999 }
1000
1001 void Animation::SetPlayRange( const Vector2& range)
1002 {
1003   //Make sure the range specified is between 0.0 and 1.0
1004   if( range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f )
1005   {
1006     Vector2 orderedRange( range );
1007     //If the range is not in order swap values
1008     if( range.x > range.y )
1009     {
1010       orderedRange = Vector2(range.y, range.x);
1011     }
1012
1013     // Cache for public getters
1014     mPlayRange = orderedRange;
1015
1016     // mAnimation is being used in a separate thread; queue a message to set play range
1017     SetPlayRangeMessage( mEventThreadServices, *mAnimation, orderedRange );
1018   }
1019 }
1020
1021 Vector2 Animation::GetPlayRange() const
1022 {
1023   return mPlayRange;
1024 }
1025
1026 void Animation::SetLoopingMode( Dali::Animation::LoopingMode loopingMode )
1027 {
1028   mAutoReverseEnabled = ( loopingMode == Dali::Animation::LoopingMode::AUTO_REVERSE );
1029
1030   // mAnimation is being used in a separate thread; queue a message to set play range
1031   SetLoopingModeMessage( mEventThreadServices, *mAnimation, mAutoReverseEnabled );
1032 }
1033
1034 Dali::Animation::LoopingMode Animation::GetLoopingMode() const
1035 {
1036   return mAutoReverseEnabled ? Dali::Animation::AUTO_REVERSE : Dali::Animation::RESTART;
1037 }
1038
1039 bool Animation::CompareConnectorEndTimes( const Animation::ConnectorTargetValues& lhs, const Animation::ConnectorTargetValues& rhs )
1040 {
1041   return ( ( lhs.timePeriod.delaySeconds + lhs.timePeriod.durationSeconds ) < ( rhs.timePeriod.delaySeconds + rhs.timePeriod.durationSeconds ) );
1042 }
1043
1044 void Animation::NotifyObjects()
1045 {
1046   if( mEndAction != EndAction::Discard ) // If the animation is discarded, then we do not want to change the target values
1047   {
1048     // Sort according to end time with earlier end times coming first, if the end time is the same, then the connectors are not moved
1049     std::stable_sort( mConnectorTargetValues.begin(), mConnectorTargetValues.end(), CompareConnectorEndTimes );
1050
1051     // Loop through all connector target values sorted by increasing end time
1052     ConnectorTargetValuesContainer::const_iterator iter = mConnectorTargetValues.begin();
1053     const ConnectorTargetValuesContainer::const_iterator endIter = mConnectorTargetValues.end();
1054     for( ; iter != endIter; ++iter )
1055     {
1056       AnimatorConnectorBase* connector = mConnectors[ iter->connectorIndex ];
1057
1058       Object* object = connector->GetObject();
1059       if( object )
1060       {
1061         object->NotifyPropertyAnimation( *this, connector->GetPropertyIndex(), iter->targetValue, iter->animatorType );
1062       }
1063     }
1064   }
1065 }
1066
1067
1068 void Animation::SendFinalProgressNotificationMessage()
1069 {
1070   if ( mProgressReachedMarker > 0.0f )
1071   {
1072     float progressMarkerSeconds = mDurationSeconds * mProgressReachedMarker;
1073     SetProgressNotificationMessage( mEventThreadServices, *mAnimation, progressMarkerSeconds );
1074   }
1075 }
1076
1077 } // namespace Internal
1078
1079 } // namespace Dali