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