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-function.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 );
84 const Dali::AlphaFunction DEFAULT_ALPHA_FUNCTION( Dali::AlphaFunction::DEFAULT );
89 AnimationPtr Animation::New(float durationSeconds)
91 Stage* stage = Stage::GetCurrent();
93 AnimationPlaylist& playlist = stage->GetAnimationPlaylist();
95 if( durationSeconds < 0.0f )
97 DALI_LOG_WARNING("duration should be greater than 0.0f.\n");
98 durationSeconds = 0.0f;
101 AnimationPtr animation = new Animation( *stage, playlist, durationSeconds, DEFAULT_END_ACTION, DEFAULT_DISCONNECT_ACTION, DEFAULT_ALPHA_FUNCTION );
103 // Second-phase construction
104 animation->Initialize();
109 Animation::Animation( EventThreadServices& eventThreadServices, AnimationPlaylist& playlist, float durationSeconds, EndAction endAction, EndAction disconnectAction, AlphaFunction defaultAlpha )
110 : mEventThreadServices( eventThreadServices ),
111 mPlaylist( playlist ),
113 mNotificationCount( 0 ),
114 mFinishedCallback( NULL ),
115 mFinishedCallbackObject( NULL ),
116 mDurationSeconds( durationSeconds ),
119 mPlayRange( Vector2(0.0f,1.0f)),
120 mEndAction( endAction ),
121 mDisconnectAction( disconnectAction ),
122 mDefaultAlpha( defaultAlpha )
126 void Animation::Initialize()
128 // Connect to the animation playlist
129 mPlaylist.AnimationCreated( *this );
136 Animation::~Animation()
138 // Guard to allow handle destruction after Core has been destroyed
139 if ( Stage::IsInstalled() )
141 // Disconnect from the animation playlist
142 mPlaylist.AnimationDestroyed( *this );
144 DestroySceneObject();
150 void Animation::CreateSceneObject()
152 DALI_ASSERT_DEBUG( mAnimation == NULL );
154 // Create a new animation, temporarily owned
155 SceneGraph::Animation* animation = SceneGraph::Animation::New( mDurationSeconds, mSpeedFactor, mPlayRange, mIsLooping, mEndAction, mDisconnectAction );
157 // Keep a const pointer to the animation.
158 mAnimation = animation;
160 // Transfer animation ownership to the update manager through a message
161 AddAnimationMessage( mEventThreadServices.GetUpdateManager(), animation );
164 void Animation::DestroySceneObject()
166 if ( mAnimation != NULL )
168 // Remove animation using a message to the update manager
169 RemoveAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
174 void Animation::SetDuration(float seconds)
178 DALI_LOG_WARNING("duration should be greater than 0.0f.\n");
182 // Cache for public getters
183 mDurationSeconds = seconds;
185 // mAnimation is being used in a separate thread; queue a message to set the value
186 SetDurationMessage( mEventThreadServices, *mAnimation, seconds );
189 float Animation::GetDuration() const
191 // This is not animatable; the cached value is up-to-date.
192 return mDurationSeconds;
195 void Animation::SetLooping(bool looping)
197 // Cache for public getters
198 mIsLooping = looping;
200 // mAnimation is being used in a separate thread; queue a message to set the value
201 SetLoopingMessage( mEventThreadServices, *mAnimation, looping );
204 bool Animation::IsLooping() const
206 // This is not animatable; the cached value is up-to-date.
210 void Animation::SetEndAction(EndAction action)
212 // Cache for public getters
215 // mAnimation is being used in a separate thread; queue a message to set the value
216 SetEndActionMessage( mEventThreadServices, *mAnimation, action );
219 Dali::Animation::EndAction Animation::GetEndAction() const
221 // This is not animatable; the cached value is up-to-date.
225 void Animation::SetDisconnectAction(EndAction action)
227 // Cache for public getters
228 mDisconnectAction = action;
230 // mAnimation is being used in a separate thread; queue a message to set the value
231 SetDisconnectActionMessage( mEventThreadServices, *mAnimation, action );
234 Dali::Animation::EndAction Animation::GetDisconnectAction() const
236 // This is not animatable; the cached value is up-to-date.
237 return mDisconnectAction;
240 void Animation::Play()
242 // Update the current playlist
243 mPlaylist.OnPlay( *this );
245 // mAnimation is being used in a separate thread; queue a Play message
246 PlayAnimationMessage( mEventThreadServices, *mAnimation );
249 void Animation::PlayFrom( float progress )
251 if( progress >= mPlayRange.x && progress <= mPlayRange.y )
253 // Update the current playlist
254 mPlaylist.OnPlay( *this );
256 // mAnimation is being used in a separate thread; queue a Play message
257 PlayAnimationFromMessage( mEventThreadServices, *mAnimation, progress );
261 void Animation::Pause()
263 // mAnimation is being used in a separate thread; queue a Pause message
264 PauseAnimationMessage( mEventThreadServices, *mAnimation );
267 void Animation::Stop()
269 // mAnimation is being used in a separate thread; queue a Stop message
270 StopAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
273 void Animation::Clear()
275 DALI_ASSERT_DEBUG(mAnimation);
277 // Remove all the connectors
280 // Replace the old scene-object with a new one
281 DestroySceneObject();
284 // Reset the notification count, since the new scene-object has never been played
285 mNotificationCount = 0;
287 // Update the current playlist
288 mPlaylist.OnClear( *this );
291 void Animation::AnimateBy(Property& target, Property::Value& relativeValue)
293 AnimateBy(target, relativeValue, mDefaultAlpha, TimePeriod(mDurationSeconds));
296 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha)
298 AnimateBy(target, relativeValue, alpha, TimePeriod(mDurationSeconds));
301 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, TimePeriod period)
303 AnimateBy(target, relativeValue, mDefaultAlpha, period);
306 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha, TimePeriod period)
308 Object& object = dynamic_cast<Object&>( GetImplementation(target.object) );
310 ExtendDuration( period );
312 switch ( relativeValue.GetType() )
314 case Property::BOOLEAN:
316 AddAnimatorConnector( AnimatorConnector<bool>::New( object,
317 target.propertyIndex,
318 target.componentIndex,
319 new AnimateByBoolean(relativeValue.Get<bool>()),
325 case Property::INTEGER:
327 AddAnimatorConnector( AnimatorConnector<int>::New( object,
328 target.propertyIndex,
329 target.componentIndex,
330 new AnimateByInteger(relativeValue.Get<int>()),
336 case Property::UNSIGNED_INTEGER:
338 AddAnimatorConnector( AnimatorConnector<unsigned int>::New( object,
339 target.propertyIndex,
340 target.componentIndex,
341 new AnimateByUnsignedInteger(relativeValue.Get<unsigned int>()),
347 case Property::FLOAT:
349 AddAnimatorConnector( AnimatorConnector<float>::New( object,
350 target.propertyIndex,
351 target.componentIndex,
352 new AnimateByFloat(relativeValue.Get<float>()),
358 case Property::VECTOR2:
360 AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
361 target.propertyIndex,
362 target.componentIndex,
363 new AnimateByVector2(relativeValue.Get<Vector2>()),
369 case Property::VECTOR3:
371 AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
372 target.propertyIndex,
373 target.componentIndex,
374 new AnimateByVector3(relativeValue.Get<Vector3>()),
380 case Property::VECTOR4:
382 AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
383 target.propertyIndex,
384 target.componentIndex,
385 new AnimateByVector4(relativeValue.Get<Vector4>()),
391 case Property::ROTATION:
393 AngleAxis angleAxis = relativeValue.Get<AngleAxis>();
395 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
396 target.propertyIndex,
397 target.componentIndex,
398 new RotateByAngleAxis(angleAxis.angle, angleAxis.axis),
405 DALI_ASSERT_ALWAYS( false && "Property type enumeration out of bounds" ); // should never come here
410 void Animation::AnimateTo(Property& target, Property::Value& destinationValue)
412 AnimateTo(target, destinationValue, mDefaultAlpha, TimePeriod(mDurationSeconds));
415 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha)
417 AnimateTo(target, destinationValue, alpha, TimePeriod(mDurationSeconds));
420 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, TimePeriod period)
422 AnimateTo(target, destinationValue, mDefaultAlpha, period);
425 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
427 Object& object = dynamic_cast<Object&>( GetImplementation(target.object) );
429 AnimateTo( object, target.propertyIndex, target.componentIndex, destinationValue, alpha, period );
432 void Animation::AnimateTo(Object& targetObject, Property::Index targetPropertyIndex, int componentIndex, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
434 Property::Type type = targetObject.GetPropertyType(targetPropertyIndex);
435 if(componentIndex != Property::INVALID_COMPONENT_INDEX)
437 if( type == Property::VECTOR2
438 || type == Property::VECTOR3
439 || type == Property::VECTOR4 )
441 type = Property::FLOAT;
444 DALI_ASSERT_ALWAYS( type == destinationValue.GetType() && "DestinationValue does not match Target Property type" );
446 ExtendDuration( period );
448 switch (destinationValue.GetType())
450 case Property::BOOLEAN:
452 AddAnimatorConnector( AnimatorConnector<bool>::New( targetObject,
455 new AnimateToBoolean( destinationValue.Get<bool>() ),
461 case Property::INTEGER:
463 AddAnimatorConnector( AnimatorConnector<int>::New( targetObject,
466 new AnimateToInteger( destinationValue.Get<int>() ),
472 case Property::UNSIGNED_INTEGER:
474 AddAnimatorConnector( AnimatorConnector<unsigned int>::New( targetObject,
477 new AnimateToUnsignedInteger( destinationValue.Get<unsigned int>() ),
483 case Property::FLOAT:
485 if ( ( Dali::Actor::Property::SIZE_WIDTH == targetPropertyIndex )||
486 ( Dali::Actor::Property::SIZE_HEIGHT == targetPropertyIndex ) )
488 // Test whether this is actually an Actor
489 Actor* maybeActor = dynamic_cast<Actor*>( &targetObject );
492 // Notify the actor that its size is being animated
493 maybeActor->NotifySizeAnimation( *this, destinationValue.Get<float>(), targetPropertyIndex );
496 AddAnimatorConnector( AnimatorConnector<float>::New( targetObject,
499 new AnimateToFloat( destinationValue.Get<float>() ),
505 case Property::VECTOR2:
507 AddAnimatorConnector( AnimatorConnector<Vector2>::New( targetObject,
510 new AnimateToVector2( destinationValue.Get<Vector2>() ),
516 case Property::VECTOR3:
518 if ( Dali::Actor::Property::SIZE == targetPropertyIndex )
520 // Test whether this is actually an Actor
521 Actor* maybeActor = dynamic_cast<Actor*>( &targetObject );
524 // Notify the actor that its size is being animated
525 maybeActor->NotifySizeAnimation( *this, destinationValue.Get<Vector3>() );
529 AddAnimatorConnector( AnimatorConnector<Vector3>::New( targetObject,
532 new AnimateToVector3( destinationValue.Get<Vector3>() ),
538 case Property::VECTOR4:
540 AddAnimatorConnector( AnimatorConnector<Vector4>::New( targetObject,
543 new AnimateToVector4( destinationValue.Get<Vector4>() ),
549 case Property::ROTATION:
551 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( targetObject,
554 new RotateToQuaternion( destinationValue.Get<Quaternion>() ),
561 DALI_ASSERT_ALWAYS( false && "Property type enumeration out of bounds" ); // should never come here
566 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames)
568 AnimateBetween(target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION );
571 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, Interpolation interpolation )
573 AnimateBetween(target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), interpolation );
576 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period)
578 AnimateBetween(target, keyFrames, mDefaultAlpha, period, DEFAULT_INTERPOLATION);
581 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period, Interpolation interpolation)
583 AnimateBetween(target, keyFrames, mDefaultAlpha, period, interpolation);
586 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha)
588 AnimateBetween(target, keyFrames, alpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION);
591 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, Interpolation interpolation)
593 AnimateBetween(target, keyFrames, alpha, TimePeriod(mDurationSeconds), interpolation);
596 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period)
598 AnimateBetween(target, keyFrames, alpha, period, DEFAULT_INTERPOLATION);
601 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period, Interpolation interpolation)
603 Object& object = dynamic_cast<Object&>( GetImplementation(target.object) );
605 ExtendDuration( period );
607 switch(keyFrames.GetType())
609 case Dali::Property::BOOLEAN:
611 const KeyFrameBoolean* kf;
612 GetSpecialization(keyFrames, kf);
613 KeyFrameBooleanPtr kfCopy = KeyFrameBoolean::Clone(*kf);
614 AddAnimatorConnector( AnimatorConnector<bool>::New( object,
615 target.propertyIndex,
616 target.componentIndex,
617 new KeyFrameBooleanFunctor(kfCopy),
623 case Dali::Property::INTEGER:
625 const KeyFrameInteger* kf;
626 GetSpecialization(keyFrames, kf);
627 KeyFrameIntegerPtr kfCopy = KeyFrameInteger::Clone(*kf);
628 AddAnimatorConnector( AnimatorConnector<int>::New( object,
629 target.propertyIndex,
630 target.componentIndex,
631 new KeyFrameIntegerFunctor(kfCopy,interpolation),
637 case Dali::Property::UNSIGNED_INTEGER:
639 const KeyFrameUnsignedInteger* kf;
640 GetSpecialization(keyFrames, kf);
641 KeyFrameUnsignedIntegerPtr kfCopy = KeyFrameUnsignedInteger::Clone(*kf);
642 AddAnimatorConnector( AnimatorConnector<int>::New( object,
643 target.propertyIndex,
644 target.componentIndex,
645 new KeyFrameUnsignedIntegerFunctor(kfCopy,interpolation),
651 case Dali::Property::FLOAT:
653 const KeyFrameNumber* kf;
654 GetSpecialization(keyFrames, kf);
655 KeyFrameNumberPtr kfCopy = KeyFrameNumber::Clone(*kf);
656 AddAnimatorConnector( AnimatorConnector<float>::New( object,
657 target.propertyIndex,
658 target.componentIndex,
659 new KeyFrameNumberFunctor(kfCopy,interpolation),
665 case Dali::Property::VECTOR2:
667 const KeyFrameVector2* kf;
668 GetSpecialization(keyFrames, kf);
669 KeyFrameVector2Ptr kfCopy = KeyFrameVector2::Clone(*kf);
670 AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
671 target.propertyIndex,
672 target.componentIndex,
673 new KeyFrameVector2Functor(kfCopy,interpolation),
679 case Dali::Property::VECTOR3:
681 const KeyFrameVector3* kf;
682 GetSpecialization(keyFrames, kf);
683 KeyFrameVector3Ptr kfCopy = KeyFrameVector3::Clone(*kf);
684 AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
685 target.propertyIndex,
686 target.componentIndex,
687 new KeyFrameVector3Functor(kfCopy,interpolation),
693 case Dali::Property::VECTOR4:
695 const KeyFrameVector4* kf;
696 GetSpecialization(keyFrames, kf);
697 KeyFrameVector4Ptr kfCopy = KeyFrameVector4::Clone(*kf);
698 AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
699 target.propertyIndex,
700 target.componentIndex,
701 new KeyFrameVector4Functor(kfCopy,interpolation),
707 case Dali::Property::ROTATION:
709 const KeyFrameQuaternion* kf;
710 GetSpecialization(keyFrames, kf);
711 KeyFrameQuaternionPtr kfCopy = KeyFrameQuaternion::Clone(*kf);
712 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
713 target.propertyIndex,
714 target.componentIndex,
715 new KeyFrameQuaternionFunctor(kfCopy),
721 default: // not all property types are animateable
726 bool Animation::HasFinished()
728 bool hasFinished(false);
729 const int playCount(mAnimation->GetPlayCount());
731 // If the play count has been incremented, then another notification is required
732 if (playCount > mNotificationCount)
734 // Note that only one signal is emitted, if the animation has been played repeatedly
735 mNotificationCount = playCount;
743 Dali::Animation::AnimationSignalType& Animation::FinishedSignal()
745 return mFinishedSignal;
748 void Animation::EmitSignalFinish()
750 if ( !mFinishedSignal.Empty() )
752 Dali::Animation handle( this );
753 mFinishedSignal.Emit( handle );
756 // This callback is used internally, to avoid the overhead of using a signal.
757 if ( mFinishedCallback )
759 mFinishedCallback( mFinishedCallbackObject );
763 bool Animation::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
765 bool connected( true );
766 Animation* animation = dynamic_cast<Animation*>(object);
768 if ( 0 == strcmp( signalName.c_str(), SIGNAL_FINISHED ) )
770 animation->FinishedSignal().Connect( tracker, functor );
774 // signalName does not match any signal
781 void Animation::SetFinishedCallback( FinishedCallback callback, Object* object )
783 mFinishedCallback = callback;
784 mFinishedCallbackObject = object;
787 void Animation::AddAnimatorConnector( AnimatorConnectorBase* connector )
789 DALI_ASSERT_DEBUG( NULL != connector );
791 connector->SetParent(*this);
793 mConnectors.PushBack( connector );
796 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward )
798 Animate( actor, path, forward, mDefaultAlpha, TimePeriod(mDurationSeconds) );
801 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha )
803 Animate( actor, path, forward, alpha, TimePeriod(mDurationSeconds) );
806 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, TimePeriod period )
808 Animate( actor, path, forward, mDefaultAlpha, period );
811 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha, TimePeriod period)
813 ExtendDuration( period );
815 PathPtr pathCopy = Path::Clone(path);
818 AddAnimatorConnector( AnimatorConnector<Vector3>::New( actor,
819 Dali::Actor::Property::POSITION,
820 Property::INVALID_COMPONENT_INDEX,
821 new PathPositionFunctor( pathCopy ),
825 //If forward is zero, PathRotationFunctor will always return the unit quaternion
826 if( forward != Vector3::ZERO )
829 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( actor,
830 Dali::Actor::Property::ORIENTATION,
831 Property::INVALID_COMPONENT_INDEX,
832 new PathRotationFunctor( pathCopy, forward ),
838 void Animation::Show(Actor& actor, float delaySeconds)
840 ExtendDuration( TimePeriod(delaySeconds, 0) );
842 AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
843 Dali::Actor::Property::VISIBLE,
844 Property::INVALID_COMPONENT_INDEX,
845 new AnimateToBoolean(SHOW_VALUE),
847 TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
850 void Animation::Hide(Actor& actor, float delaySeconds)
852 ExtendDuration( TimePeriod(delaySeconds, 0) );
854 AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
855 Dali::Actor::Property::VISIBLE,
856 Property::INVALID_COMPONENT_INDEX,
857 new AnimateToBoolean(HIDE_VALUE),
859 TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
862 bool Animation::DoAction( BaseObject* object, const std::string& actionName, const std::vector<Property::Value>& attributes )
865 Animation* animation = dynamic_cast<Animation*>( object );
869 if( 0 == strcmp( actionName.c_str(), ACTION_PLAY ) )
871 if( attributes.size() > 0 )
873 animation->SetDuration( attributes[0].Get<float>() );
879 else if( 0 == strcmp( actionName.c_str(), ACTION_STOP ) )
884 else if( 0 == strcmp( actionName.c_str(), ACTION_PAUSE ) )
894 void Animation::SetCurrentProgress(float progress)
896 if( mAnimation && progress >= mPlayRange.x && progress <= mPlayRange.y )
898 // mAnimation is being used in a separate thread; queue a message to set the current progress
899 SetCurrentProgressMessage( mEventThreadServices, *mAnimation, progress );
903 float Animation::GetCurrentProgress()
907 return mAnimation->GetCurrentProgress();
913 void Animation::ExtendDuration( const TimePeriod& timePeriod )
915 float duration = timePeriod.delaySeconds + timePeriod.durationSeconds;
917 if( duration > mDurationSeconds )
919 SetDuration( duration );
923 void Animation::SetSpeedFactor( float factor )
927 mSpeedFactor = factor;
928 SetSpeedFactorMessage( mEventThreadServices, *mAnimation, factor );
932 float Animation::GetSpeedFactor() const
937 void Animation::SetPlayRange( const Vector2& range)
939 //Make sure the range specified is between 0.0 and 1.0
940 if( range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f )
942 Vector2 orderedRange( range );
943 //If the range is not in order swap values
944 if( range.x > range.y )
946 orderedRange = Vector2(range.y, range.x);
949 // Cache for public getters
950 mPlayRange = orderedRange;
952 // mAnimation is being used in a separate thread; queue a message to set play range
953 SetPlayRangeMessage( mEventThreadServices, *mAnimation, orderedRange );
957 Vector2 Animation::GetPlayRange() const
963 } // namespace Internal