2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/event/animation/animation-impl.h>
22 #include <cstring> // for strcmp
25 #include <dali/public-api/actors/actor.h>
26 #include <dali/public-api/animation/alpha-functions.h>
27 #include <dali/public-api/animation/time-period.h>
28 #include <dali/public-api/common/dali-common.h>
29 #include <dali/public-api/object/type-registry.h>
30 #include <dali/public-api/math/vector2.h>
31 #include <dali/public-api/math/radian.h>
32 #include <dali/internal/event/actors/actor-impl.h>
33 #include <dali/internal/event/animation/animation-playlist.h>
34 #include <dali/internal/event/animation/animator-connector.h>
35 #include <dali/internal/event/common/notification-manager.h>
36 #include <dali/internal/event/common/property-helper.h>
37 #include <dali/internal/event/common/stage-impl.h>
38 #include <dali/internal/event/common/thread-local-storage.h>
39 #include <dali/internal/event/effects/shader-effect-impl.h>
40 #include <dali/internal/update/manager/update-manager.h>
42 using Dali::Internal::SceneGraph::UpdateManager;
43 using Dali::Internal::SceneGraph::AnimatorBase;
44 using Dali::Internal::SceneGraph::Shader;
52 static bool SHOW_VALUE = true;
53 static bool HIDE_VALUE = false;
60 const char* const SIGNAL_FINISHED = "finished";
64 const char* const ACTION_PLAY = "play";
65 const char* const ACTION_STOP = "stop";
66 const char* const ACTION_PAUSE = "pause";
70 return Dali::Animation::New(0.f);
73 TypeRegistration mType( typeid( Dali::Animation ), typeid( Dali::BaseHandle ), Create );
75 SignalConnectorType signalConnector1( mType, SIGNAL_FINISHED, &Animation::DoConnectSignal );
77 TypeAction action1( mType, ACTION_PLAY, &Animation::DoAction );
78 TypeAction action2( mType, ACTION_STOP, &Animation::DoAction );
79 TypeAction action3( mType, ACTION_PAUSE, &Animation::DoAction );
81 const Dali::Animation::EndAction DEFAULT_END_ACTION( Dali::Animation::Bake );
82 const Dali::Animation::EndAction DEFAULT_DISCONNECT_ACTION( Dali::Animation::BakeFinal );
83 const Dali::Animation::Interpolation DEFAULT_INTERPOLATION( Dali::Animation::Linear );
88 AnimationPtr Animation::New(float durationSeconds)
90 Stage* stage = Stage::GetCurrent();
92 AnimationPlaylist& playlist = stage->GetAnimationPlaylist();
94 AnimationPtr animation = new Animation( *stage, playlist, durationSeconds, DEFAULT_END_ACTION, DEFAULT_DISCONNECT_ACTION, Dali::AlphaFunctions::Linear );
96 // Second-phase construction
97 animation->Initialize();
102 Animation::Animation( EventThreadServices& eventThreadServices, AnimationPlaylist& playlist, float durationSeconds, EndAction endAction, EndAction disconnectAction, AlphaFunction defaultAlpha )
103 : mEventThreadServices( eventThreadServices ),
104 mPlaylist( playlist ),
106 mNotificationCount( 0 ),
107 mFinishedCallback( NULL ),
108 mFinishedCallbackObject( NULL ),
109 mDurationSeconds( durationSeconds ),
112 mPlayRange( Vector2(0.0f,1.0f)),
113 mEndAction( endAction ),
114 mDisconnectAction( disconnectAction ),
115 mDefaultAlpha( defaultAlpha )
119 void Animation::Initialize()
121 // Connect to the animation playlist
122 mPlaylist.AnimationCreated( *this );
129 Animation::~Animation()
131 // Guard to allow handle destruction after Core has been destroyed
132 if ( Stage::IsInstalled() )
134 // Disconnect from the animation playlist
135 mPlaylist.AnimationDestroyed( *this );
137 DestroySceneObject();
143 void Animation::CreateSceneObject()
145 DALI_ASSERT_DEBUG( mAnimation == NULL );
147 // Create a new animation, temporarily owned
148 SceneGraph::Animation* animation = SceneGraph::Animation::New( mDurationSeconds, mSpeedFactor, mPlayRange, mIsLooping, mEndAction, mDisconnectAction );
150 // Keep a const pointer to the animation.
151 mAnimation = animation;
153 // Transfer animation ownership to the update manager through a message
154 AddAnimationMessage( mEventThreadServices.GetUpdateManager(), animation );
157 void Animation::DestroySceneObject()
159 if ( mAnimation != NULL )
161 // Remove animation using a message to the update manager
162 RemoveAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
167 void Animation::SetDuration(float seconds)
169 // Cache for public getters
170 mDurationSeconds = seconds;
172 // mAnimation is being used in a separate thread; queue a message to set the value
173 SetDurationMessage( mEventThreadServices, *mAnimation, seconds );
176 float Animation::GetDuration() const
178 // This is not animatable; the cached value is up-to-date.
179 return mDurationSeconds;
182 void Animation::SetLooping(bool looping)
184 // Cache for public getters
185 mIsLooping = looping;
187 // mAnimation is being used in a separate thread; queue a message to set the value
188 SetLoopingMessage( mEventThreadServices, *mAnimation, looping );
191 bool Animation::IsLooping() const
193 // This is not animatable; the cached value is up-to-date.
197 void Animation::SetEndAction(EndAction action)
199 // Cache for public getters
202 // mAnimation is being used in a separate thread; queue a message to set the value
203 SetEndActionMessage( mEventThreadServices, *mAnimation, action );
206 Dali::Animation::EndAction Animation::GetEndAction() const
208 // This is not animatable; the cached value is up-to-date.
212 void Animation::SetDisconnectAction(EndAction action)
214 // Cache for public getters
215 mDisconnectAction = action;
217 // mAnimation is being used in a separate thread; queue a message to set the value
218 SetDisconnectActionMessage( mEventThreadServices, *mAnimation, action );
221 Dali::Animation::EndAction Animation::GetDisconnectAction() const
223 // This is not animatable; the cached value is up-to-date.
224 return mDisconnectAction;
227 void Animation::Play()
229 // Update the current playlist
230 mPlaylist.OnPlay( *this );
232 // mAnimation is being used in a separate thread; queue a Play message
233 PlayAnimationMessage( mEventThreadServices, *mAnimation );
236 void Animation::PlayFrom( float progress )
238 if( progress >= mPlayRange.x && progress <= mPlayRange.y )
240 // Update the current playlist
241 mPlaylist.OnPlay( *this );
243 // mAnimation is being used in a separate thread; queue a Play message
244 PlayAnimationFromMessage( mEventThreadServices, *mAnimation, progress );
248 void Animation::Pause()
250 // mAnimation is being used in a separate thread; queue a Pause message
251 PauseAnimationMessage( mEventThreadServices, *mAnimation );
254 void Animation::Stop()
256 // mAnimation is being used in a separate thread; queue a Stop message
257 StopAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
260 void Animation::Clear()
262 DALI_ASSERT_DEBUG(mAnimation);
264 // Remove all the connectors
267 // Replace the old scene-object with a new one
268 DestroySceneObject();
271 // Reset the notification count, since the new scene-object has never been played
272 mNotificationCount = 0;
274 // Update the current playlist
275 mPlaylist.OnClear( *this );
278 void Animation::AnimateBy(Property& target, Property::Value& relativeValue)
280 AnimateBy(target, relativeValue, AlphaFunctions::Default, mDurationSeconds);
283 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha)
285 AnimateBy(target, relativeValue, alpha, mDurationSeconds);
288 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, TimePeriod period)
290 AnimateBy(target, relativeValue, AlphaFunctions::Default, period);
293 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha, TimePeriod period)
295 Object& object = dynamic_cast<Object&>( GetImplementation(target.object) );
297 ExtendDuration( period );
299 switch ( relativeValue.GetType() )
301 case Property::BOOLEAN:
303 AddAnimatorConnector( AnimatorConnector<bool>::New( object,
304 target.propertyIndex,
305 target.componentIndex,
306 new AnimateByBoolean(relativeValue.Get<bool>()),
312 case Property::FLOAT:
314 AddAnimatorConnector( AnimatorConnector<float>::New( object,
315 target.propertyIndex,
316 target.componentIndex,
317 new AnimateByFloat(relativeValue.Get<float>()),
323 case Property::INTEGER:
325 AddAnimatorConnector( AnimatorConnector<int>::New( object,
326 target.propertyIndex,
327 target.componentIndex,
328 new AnimateByInteger(relativeValue.Get<int>()),
334 case Property::VECTOR2:
336 AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
337 target.propertyIndex,
338 target.componentIndex,
339 new AnimateByVector2(relativeValue.Get<Vector2>()),
345 case Property::VECTOR3:
347 AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
348 target.propertyIndex,
349 target.componentIndex,
350 new AnimateByVector3(relativeValue.Get<Vector3>()),
356 case Property::VECTOR4:
358 AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
359 target.propertyIndex,
360 target.componentIndex,
361 new AnimateByVector4(relativeValue.Get<Vector4>()),
367 case Property::ROTATION:
369 AngleAxis angleAxis = relativeValue.Get<AngleAxis>();
371 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
372 target.propertyIndex,
373 target.componentIndex,
374 new RotateByAngleAxis(angleAxis.angle, angleAxis.axis),
381 DALI_ASSERT_ALWAYS( false && "Property type enumeration out of bounds" ); // should never come here
386 void Animation::AnimateTo(Property& target, Property::Value& destinationValue)
388 AnimateTo(target, destinationValue, AlphaFunctions::Default, mDurationSeconds);
391 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha)
393 AnimateTo(target, destinationValue, alpha, mDurationSeconds);
396 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, TimePeriod period)
398 AnimateTo(target, destinationValue, AlphaFunctions::Default, period);
401 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
403 Object& object = dynamic_cast<Object&>( GetImplementation(target.object) );
405 AnimateTo( object, target.propertyIndex, target.componentIndex, destinationValue, alpha, period );
408 void Animation::AnimateTo(Object& targetObject, Property::Index targetPropertyIndex, int componentIndex, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
410 Property::Type type = targetObject.GetPropertyType(targetPropertyIndex);
411 if(componentIndex != Property::INVALID_COMPONENT_INDEX)
413 if( type == Property::VECTOR2
414 || type == Property::VECTOR3
415 || type == Property::VECTOR4 )
417 type = Property::FLOAT;
420 DALI_ASSERT_ALWAYS( type == destinationValue.GetType() && "DestinationValue does not match Target Property type" );
422 ExtendDuration( period );
424 switch (destinationValue.GetType())
426 case Property::BOOLEAN:
428 AddAnimatorConnector( AnimatorConnector<bool>::New( targetObject,
431 new AnimateToBoolean( destinationValue.Get<bool>() ),
437 case Property::FLOAT:
439 AddAnimatorConnector( AnimatorConnector<float>::New( targetObject,
442 new AnimateToFloat( destinationValue.Get<float>() ),
448 case Property::INTEGER:
450 AddAnimatorConnector( AnimatorConnector<int>::New( targetObject,
453 new AnimateToInteger( destinationValue.Get<int>() ),
459 case Property::VECTOR2:
461 AddAnimatorConnector( AnimatorConnector<Vector2>::New( targetObject,
464 new AnimateToVector2( destinationValue.Get<Vector2>() ),
470 case Property::VECTOR3:
472 if ( Dali::Actor::Property::SIZE == targetPropertyIndex )
474 // Test whether this is actually an Actor
475 Actor* maybeActor = dynamic_cast<Actor*>( &targetObject );
478 // Notify the actor that its size is being animated
479 maybeActor->NotifySizeAnimation( *this, destinationValue.Get<Vector3>() );
483 AddAnimatorConnector( AnimatorConnector<Vector3>::New( targetObject,
486 new AnimateToVector3( destinationValue.Get<Vector3>() ),
492 case Property::VECTOR4:
494 AddAnimatorConnector( AnimatorConnector<Vector4>::New( targetObject,
497 new AnimateToVector4( destinationValue.Get<Vector4>() ),
503 case Property::ROTATION:
505 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( targetObject,
508 new RotateToQuaternion( destinationValue.Get<Quaternion>() ),
515 DALI_ASSERT_ALWAYS( false && "Property type enumeration out of bounds" ); // should never come here
520 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames)
522 AnimateBetween(target, keyFrames, mDefaultAlpha, mDurationSeconds, DEFAULT_INTERPOLATION );
525 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, Interpolation interpolation )
527 AnimateBetween(target, keyFrames, mDefaultAlpha, mDurationSeconds, interpolation );
530 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period)
532 AnimateBetween(target, keyFrames, mDefaultAlpha, period, DEFAULT_INTERPOLATION);
535 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period, Interpolation interpolation)
537 AnimateBetween(target, keyFrames, mDefaultAlpha, period, interpolation);
540 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha)
542 AnimateBetween(target, keyFrames, alpha, mDurationSeconds, DEFAULT_INTERPOLATION);
545 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, Interpolation interpolation)
547 AnimateBetween(target, keyFrames, alpha, mDurationSeconds, interpolation);
550 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period)
552 AnimateBetween(target, keyFrames, alpha, period, DEFAULT_INTERPOLATION);
555 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period, Interpolation interpolation)
557 Object& object = dynamic_cast<Object&>( GetImplementation(target.object) );
559 ExtendDuration( period );
561 switch(keyFrames.GetType())
563 case Dali::Property::BOOLEAN:
565 const KeyFrameBoolean* kf;
566 GetSpecialization(keyFrames, kf);
567 KeyFrameBooleanPtr kfCopy = KeyFrameBoolean::Clone(*kf);
568 AddAnimatorConnector( AnimatorConnector<bool>::New( object,
569 target.propertyIndex,
570 target.componentIndex,
571 new KeyFrameBooleanFunctor(kfCopy),
577 case Dali::Property::FLOAT:
579 const KeyFrameNumber* kf;
580 GetSpecialization(keyFrames, kf);
581 KeyFrameNumberPtr kfCopy = KeyFrameNumber::Clone(*kf);
582 AddAnimatorConnector( AnimatorConnector<float>::New( object,
583 target.propertyIndex,
584 target.componentIndex,
585 new KeyFrameNumberFunctor(kfCopy,interpolation),
591 case Dali::Property::INTEGER:
593 const KeyFrameInteger* kf;
594 GetSpecialization(keyFrames, kf);
595 KeyFrameIntegerPtr kfCopy = KeyFrameInteger::Clone(*kf);
596 AddAnimatorConnector( AnimatorConnector<int>::New( object,
597 target.propertyIndex,
598 target.componentIndex,
599 new KeyFrameIntegerFunctor(kfCopy,interpolation),
605 case Dali::Property::VECTOR2:
607 const KeyFrameVector2* kf;
608 GetSpecialization(keyFrames, kf);
609 KeyFrameVector2Ptr kfCopy = KeyFrameVector2::Clone(*kf);
610 AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
611 target.propertyIndex,
612 target.componentIndex,
613 new KeyFrameVector2Functor(kfCopy,interpolation),
619 case Dali::Property::VECTOR3:
621 const KeyFrameVector3* kf;
622 GetSpecialization(keyFrames, kf);
623 KeyFrameVector3Ptr kfCopy = KeyFrameVector3::Clone(*kf);
624 AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
625 target.propertyIndex,
626 target.componentIndex,
627 new KeyFrameVector3Functor(kfCopy,interpolation),
633 case Dali::Property::VECTOR4:
635 const KeyFrameVector4* kf;
636 GetSpecialization(keyFrames, kf);
637 KeyFrameVector4Ptr kfCopy = KeyFrameVector4::Clone(*kf);
638 AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
639 target.propertyIndex,
640 target.componentIndex,
641 new KeyFrameVector4Functor(kfCopy,interpolation),
647 case Dali::Property::ROTATION:
649 const KeyFrameQuaternion* kf;
650 GetSpecialization(keyFrames, kf);
651 KeyFrameQuaternionPtr kfCopy = KeyFrameQuaternion::Clone(*kf);
652 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
653 target.propertyIndex,
654 target.componentIndex,
655 new KeyFrameQuaternionFunctor(kfCopy),
661 default: // not all property types are animateable
666 bool Animation::HasFinished()
668 bool hasFinished(false);
669 const int playCount(mAnimation->GetPlayCount());
671 // If the play count has been incremented, then another notification is required
672 if (playCount > mNotificationCount)
674 // Note that only one signal is emitted, if the animation has been played repeatedly
675 mNotificationCount = playCount;
683 Dali::Animation::AnimationSignalType& Animation::FinishedSignal()
685 return mFinishedSignal;
688 void Animation::EmitSignalFinish()
690 if ( !mFinishedSignal.Empty() )
692 Dali::Animation handle( this );
693 mFinishedSignal.Emit( handle );
696 // This callback is used internally, to avoid the overhead of using a signal.
697 if ( mFinishedCallback )
699 mFinishedCallback( mFinishedCallbackObject );
703 bool Animation::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
705 bool connected( true );
706 Animation* animation = dynamic_cast<Animation*>(object);
708 if ( 0 == strcmp( signalName.c_str(), SIGNAL_FINISHED ) )
710 animation->FinishedSignal().Connect( tracker, functor );
714 // signalName does not match any signal
721 void Animation::SetFinishedCallback( FinishedCallback callback, Object* object )
723 mFinishedCallback = callback;
724 mFinishedCallbackObject = object;
727 void Animation::AddAnimatorConnector( AnimatorConnectorBase* connector )
729 DALI_ASSERT_DEBUG( NULL != connector );
731 connector->SetParent(*this);
733 mConnectors.PushBack( connector );
736 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward )
738 Animate( actor, path, forward, mDefaultAlpha, TimePeriod(0.0f,GetDuration()) );
741 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha )
743 Animate( actor, path, forward, alpha, TimePeriod(0.0f,GetDuration()) );
746 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, TimePeriod period )
748 Animate( actor, path, forward, mDefaultAlpha, period );
751 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha, TimePeriod period)
753 ExtendDuration( period );
755 PathPtr pathCopy = Path::Clone(path);
758 AddAnimatorConnector( AnimatorConnector<Vector3>::New( actor,
759 Dali::Actor::Property::POSITION,
760 Property::INVALID_COMPONENT_INDEX,
761 new PathPositionFunctor( pathCopy ),
765 //If forward is zero, PathRotationFunctor will always return the unit quaternion
766 if( forward != Vector3::ZERO )
769 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( actor,
770 Dali::Actor::Property::ORIENTATION,
771 Property::INVALID_COMPONENT_INDEX,
772 new PathRotationFunctor( pathCopy, forward ),
778 void Animation::Show(Actor& actor, float delaySeconds)
780 ExtendDuration( TimePeriod(delaySeconds, 0) );
782 AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
783 Dali::Actor::Property::VISIBLE,
784 Property::INVALID_COMPONENT_INDEX,
785 new AnimateToBoolean(SHOW_VALUE),
786 AlphaFunctions::Default,
787 TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
790 void Animation::Hide(Actor& actor, float delaySeconds)
792 ExtendDuration( TimePeriod(delaySeconds, 0) );
794 AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
795 Dali::Actor::Property::VISIBLE,
796 Property::INVALID_COMPONENT_INDEX,
797 new AnimateToBoolean(HIDE_VALUE),
798 AlphaFunctions::Default,
799 TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
802 bool Animation::DoAction( BaseObject* object, const std::string& actionName, const std::vector<Property::Value>& attributes )
805 Animation* animation = dynamic_cast<Animation*>( object );
809 if( 0 == strcmp( actionName.c_str(), ACTION_PLAY ) )
811 if( attributes.size() > 0 )
813 animation->SetDuration( attributes[0].Get<float>() );
819 else if( 0 == strcmp( actionName.c_str(), ACTION_STOP ) )
824 else if( 0 == strcmp( actionName.c_str(), ACTION_PAUSE ) )
834 void Animation::SetCurrentProgress(float progress)
836 if( mAnimation && progress >= mPlayRange.x && progress <= mPlayRange.y )
838 // mAnimation is being used in a separate thread; queue a message to set the current progress
839 SetCurrentProgressMessage( mEventThreadServices, *mAnimation, progress );
843 float Animation::GetCurrentProgress()
847 return mAnimation->GetCurrentProgress();
853 void Animation::ExtendDuration( const TimePeriod& timePeriod )
855 float duration = timePeriod.delaySeconds + timePeriod.durationSeconds;
857 if( duration > mDurationSeconds )
859 SetDuration( duration );
863 void Animation::SetSpeedFactor( float factor )
867 mSpeedFactor = factor;
868 SetSpeedFactorMessage( mEventThreadServices, *mAnimation, factor );
872 float Animation::GetSpeedFactor() const
877 void Animation::SetPlayRange( const Vector2& range)
879 //Make sure the range specified is between 0.0 and 1.0
880 if( range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f )
882 Vector2 orderedRange( range );
883 //If the range is not in order swap values
884 if( range.x > range.y )
886 orderedRange = Vector2(range.y, range.x);
889 // Cache for public getters
890 mPlayRange = orderedRange;
892 // mAnimation is being used in a separate thread; queue a message to set play range
893 SetPlayRangeMessage( mEventThreadServices, *mAnimation, orderedRange );
897 Vector2 Animation::GetPlayRange() const
903 } // namespace Internal