2 * Copyright (c) 2017 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>
20 #include <dali/public-api/object/property-map.h>
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/common/notification-manager.h>
34 #include <dali/internal/event/common/property-helper.h>
35 #include <dali/internal/event/common/stage-impl.h>
36 #include <dali/internal/event/common/thread-local-storage.h>
37 #include <dali/internal/update/animation/scene-graph-animator.h>
38 #include <dali/internal/update/manager/update-manager.h>
40 using Dali::Internal::SceneGraph::UpdateManager;
41 using Dali::Internal::SceneGraph::AnimatorBase;
42 using Dali::Internal::SceneGraph::Shader;
50 static bool SHOW_VALUE = true;
51 static bool HIDE_VALUE = false;
58 const char* const SIGNAL_FINISHED = "finished";
62 const char* const ACTION_PLAY = "play";
63 const char* const ACTION_STOP = "stop";
64 const char* const ACTION_PAUSE = "pause";
68 return Dali::Animation::New(0.f);
71 TypeRegistration mType( typeid( Dali::Animation ), typeid( Dali::BaseHandle ), Create );
73 SignalConnectorType signalConnector1( mType, SIGNAL_FINISHED, &Animation::DoConnectSignal );
75 TypeAction action1( mType, ACTION_PLAY, &Animation::DoAction );
76 TypeAction action2( mType, ACTION_STOP, &Animation::DoAction );
77 TypeAction action3( mType, ACTION_PAUSE, &Animation::DoAction );
79 const Dali::Animation::EndAction DEFAULT_END_ACTION( Dali::Animation::Bake );
80 const Dali::Animation::EndAction DEFAULT_DISCONNECT_ACTION( Dali::Animation::BakeFinal );
81 const Dali::Animation::Interpolation DEFAULT_INTERPOLATION( Dali::Animation::Linear );
82 const Dali::AlphaFunction DEFAULT_ALPHA_FUNCTION( Dali::AlphaFunction::DEFAULT );
87 AnimationPtr Animation::New(float durationSeconds)
89 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();
114 Animation::Animation( EventThreadServices& eventThreadServices, AnimationPlaylist& playlist, float durationSeconds, EndAction endAction, EndAction disconnectAction, AlphaFunction defaultAlpha )
115 : mEventThreadServices( eventThreadServices ),
116 mPlaylist( playlist ),
118 mNotificationCount( 0 ),
119 mFinishedCallback( NULL ),
120 mFinishedCallbackObject( NULL ),
121 mDurationSeconds( durationSeconds ),
125 mPlayRange( Vector2(0.0f,1.0f)),
126 mEndAction( endAction ),
127 mDisconnectAction( disconnectAction ),
128 mDefaultAlpha( defaultAlpha ),
129 mState(Dali::Animation::STOPPED)
133 void Animation::Initialize()
135 // Connect to the animation playlist
136 mPlaylist.AnimationCreated( *this );
143 Animation::~Animation()
145 // Guard to allow handle destruction after Core has been destroyed
146 if ( Stage::IsInstalled() )
148 // Disconnect from the animation playlist
149 mPlaylist.AnimationDestroyed( *this );
151 DestroySceneObject();
157 void Animation::CreateSceneObject()
159 DALI_ASSERT_DEBUG( mAnimation == NULL );
161 // Create a new animation, temporarily owned
162 SceneGraph::Animation* animation = SceneGraph::Animation::New( mDurationSeconds, mSpeedFactor, mPlayRange, mLoopCount, mEndAction, mDisconnectAction );
164 // Keep a const pointer to the animation.
165 mAnimation = animation;
167 // Transfer animation ownership to the update manager through a message
168 AddAnimationMessage( mEventThreadServices.GetUpdateManager(), animation );
171 void Animation::DestroySceneObject()
173 if ( mAnimation != NULL )
175 // Remove animation using a message to the update manager
176 RemoveAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
181 void Animation::SetDuration(float seconds)
185 DALI_LOG_WARNING("duration should be greater than 0.0f.\n");
189 // Cache for public getters
190 mDurationSeconds = seconds;
192 // mAnimation is being used in a separate thread; queue a message to set the value
193 SetDurationMessage( mEventThreadServices, *mAnimation, seconds );
196 float Animation::GetDuration() const
198 // This is not animatable; the cached value is up-to-date.
199 return mDurationSeconds;
202 void Animation::SetLooping(bool on)
204 SetLoopCount( on ? 0 : 1 );
207 void Animation::SetLoopCount(int count)
209 // Cache for public getters
212 // mAnimation is being used in a separate thread; queue a message to set the value
213 SetLoopingMessage( mEventThreadServices, *mAnimation, mLoopCount );
216 int Animation::GetLoopCount()
221 int Animation::GetCurrentLoop()
226 bool Animation::IsLooping() const
228 return mLoopCount != 1;
231 void Animation::SetEndAction(EndAction action)
233 // Cache for public getters
236 // mAnimation is being used in a separate thread; queue a message to set the value
237 SetEndActionMessage( mEventThreadServices, *mAnimation, action );
240 Dali::Animation::EndAction Animation::GetEndAction() const
242 // This is not animatable; the cached value is up-to-date.
246 void Animation::SetDisconnectAction(EndAction action)
248 // Cache for public getters
249 mDisconnectAction = action;
251 // mAnimation is being used in a separate thread; queue a message to set the value
252 SetDisconnectActionMessage( mEventThreadServices, *mAnimation, action );
255 Dali::Animation::EndAction Animation::GetDisconnectAction() const
257 // This is not animatable; the cached value is up-to-date.
258 return mDisconnectAction;
261 void Animation::Play()
263 // Update the current playlist
264 mPlaylist.OnPlay( *this );
266 mState = Dali::Animation::PLAYING;
268 if( mEndAction != EndAction::Discard ) // If the animation is discarded, then we do not want to change the target values
270 unsigned int connectorTargetValuesIndex( 0 );
271 unsigned int numberOfConnectorTargetValues = mConnectorTargetValues.size();
274 * Loop through all Animator connectors, if connector index matches the current index stored in mConnectorTargetValues container then
275 * should apply target values for this index to the object.
277 for ( unsigned int connectorIndex = 0; connectorIndex < mConnectors.Count(); connectorIndex ++)
279 // Use index to check if the current connector is next in the mConnectorTargetValues container, meaning targetValues have been pushed in AnimateXXFunction
280 if ( connectorTargetValuesIndex < numberOfConnectorTargetValues )
282 ConnectorTargetValues& connectorPair = mConnectorTargetValues[ connectorTargetValuesIndex ];
284 if ( connectorPair.connectorIndex == connectorIndex )
286 // Current connector index matches next in the stored connectors with target values so apply target value.
287 connectorTargetValuesIndex++; // Found a match for connector so increment index to next one
289 AnimatorConnectorBase* connector = mConnectors[ connectorIndex ];
291 Object* object = connector->GetObject();
294 object->NotifyPropertyAnimation( *this, connector->GetPropertyIndex(), connectorPair.targetValue );
301 // mAnimation is being used in a separate thread; queue a Play message
302 PlayAnimationMessage( mEventThreadServices, *mAnimation );
305 void Animation::PlayFrom( float progress )
307 if( progress >= mPlayRange.x && progress <= mPlayRange.y )
309 // Update the current playlist
310 mPlaylist.OnPlay( *this );
312 mState = Dali::Animation::PLAYING;
314 // mAnimation is being used in a separate thread; queue a Play message
315 PlayAnimationFromMessage( mEventThreadServices, *mAnimation, progress );
319 void Animation::Pause()
321 mState = Dali::Animation::PAUSED;
323 // mAnimation is being used in a separate thread; queue a Pause message
324 PauseAnimationMessage( mEventThreadServices, *mAnimation );
327 Dali::Animation::State Animation::GetState() const
332 void Animation::Stop()
334 mState = Dali::Animation::STOPPED;
336 // mAnimation is being used in a separate thread; queue a Stop message
337 StopAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
340 void Animation::Clear()
342 DALI_ASSERT_DEBUG(mAnimation);
344 // Remove all the connectors
347 // Reset the connector target values
348 mConnectorTargetValues.clear();
350 // Replace the old scene-object with a new one
351 DestroySceneObject();
354 // Reset the notification count, since the new scene-object has never been played
355 mNotificationCount = 0;
357 // Update the current playlist
358 mPlaylist.OnClear( *this );
361 void Animation::AnimateBy(Property& target, Property::Value& relativeValue)
363 AnimateBy(target, relativeValue, mDefaultAlpha, TimePeriod(mDurationSeconds));
366 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha)
368 AnimateBy(target, relativeValue, alpha, TimePeriod(mDurationSeconds));
371 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, TimePeriod period)
373 AnimateBy(target, relativeValue, mDefaultAlpha, period);
376 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha, TimePeriod period)
378 Object& object = GetImplementation( target.object );
379 const Property::Type targetType = object.GetPropertyType( target.propertyIndex );
380 const Property::Type destinationType = relativeValue.GetType();
381 DALI_ASSERT_ALWAYS( targetType == destinationType && "Animated value and Property type don't match" );
383 ExtendDuration( period );
385 switch ( targetType )
387 case Property::BOOLEAN:
389 AddAnimatorConnector( AnimatorConnector<bool>::New( object,
390 target.propertyIndex,
391 target.componentIndex,
392 new AnimateByBoolean(relativeValue.Get<bool>()),
398 case Property::INTEGER:
400 AddAnimatorConnector( AnimatorConnector<int>::New( object,
401 target.propertyIndex,
402 target.componentIndex,
403 new AnimateByInteger(relativeValue.Get<int>()),
409 case Property::FLOAT:
411 AddAnimatorConnector( AnimatorConnector<float>::New( object,
412 target.propertyIndex,
413 target.componentIndex,
414 new AnimateByFloat(relativeValue.Get<float>()),
420 case Property::VECTOR2:
422 AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
423 target.propertyIndex,
424 target.componentIndex,
425 new AnimateByVector2(relativeValue.Get<Vector2>()),
431 case Property::VECTOR3:
433 AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
434 target.propertyIndex,
435 target.componentIndex,
436 new AnimateByVector3(relativeValue.Get<Vector3>()),
442 case Property::VECTOR4:
444 AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
445 target.propertyIndex,
446 target.componentIndex,
447 new AnimateByVector4(relativeValue.Get<Vector4>()),
453 case Property::ROTATION:
455 AngleAxis angleAxis = relativeValue.Get<AngleAxis>();
457 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
458 target.propertyIndex,
459 target.componentIndex,
460 new RotateByAngleAxis(angleAxis.angle, angleAxis.axis),
468 // non animatable types handled already
473 void Animation::AnimateTo(Property& target, Property::Value& destinationValue)
475 AnimateTo(target, destinationValue, mDefaultAlpha, TimePeriod(mDurationSeconds));
478 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha)
480 AnimateTo(target, destinationValue, alpha, TimePeriod(mDurationSeconds));
483 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, TimePeriod period)
485 AnimateTo(target, destinationValue, mDefaultAlpha, period);
488 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
490 Object& object = GetImplementation(target.object);
492 AnimateTo( object, target.propertyIndex, target.componentIndex, destinationValue, alpha, period );
495 void Animation::AnimateTo(Object& targetObject, Property::Index targetPropertyIndex, int componentIndex, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
497 Property::Type targetType = targetObject.GetPropertyType(targetPropertyIndex);
498 if( componentIndex != Property::INVALID_COMPONENT_INDEX )
500 if( ( targetType == Property::VECTOR2 ) ||
501 ( targetType == Property::VECTOR3 ) ||
502 ( targetType == Property::VECTOR4 ) )
504 targetType = Property::FLOAT;
507 const Property::Type destinationType = destinationValue.GetType();
508 DALI_ASSERT_ALWAYS( targetType == destinationType && "Animated value and Property type don't match" );
510 ExtendDuration( period );
512 // Store data to later notify the object that its property is being animated
513 ConnectorTargetValues connectorPair;
514 connectorPair.targetValue = destinationValue;
515 connectorPair.connectorIndex = mConnectors.Count();
516 mConnectorTargetValues.push_back( connectorPair );
518 switch ( destinationType )
520 case Property::BOOLEAN:
522 AddAnimatorConnector( AnimatorConnector<bool>::New( targetObject,
525 new AnimateToBoolean( destinationValue.Get<bool>() ),
531 case Property::INTEGER:
533 AddAnimatorConnector( AnimatorConnector<int>::New( targetObject,
536 new AnimateToInteger( destinationValue.Get<int>() ),
542 case Property::FLOAT:
544 AddAnimatorConnector( AnimatorConnector<float>::New( targetObject,
547 new AnimateToFloat( destinationValue.Get<float>() ),
553 case Property::VECTOR2:
555 AddAnimatorConnector( AnimatorConnector<Vector2>::New( targetObject,
558 new AnimateToVector2( destinationValue.Get<Vector2>() ),
564 case Property::VECTOR3:
566 AddAnimatorConnector( AnimatorConnector<Vector3>::New( targetObject,
569 new AnimateToVector3( destinationValue.Get<Vector3>() ),
575 case Property::VECTOR4:
577 AddAnimatorConnector( AnimatorConnector<Vector4>::New( targetObject,
580 new AnimateToVector4( destinationValue.Get<Vector4>() ),
586 case Property::ROTATION:
588 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( targetObject,
591 new RotateToQuaternion( destinationValue.Get<Quaternion>() ),
599 // non animatable types handled already
604 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames)
606 AnimateBetween(target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION );
609 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, Interpolation interpolation )
611 AnimateBetween(target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), interpolation );
614 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period)
616 AnimateBetween(target, keyFrames, mDefaultAlpha, period, DEFAULT_INTERPOLATION);
619 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period, Interpolation interpolation)
621 AnimateBetween(target, keyFrames, mDefaultAlpha, period, interpolation);
624 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha)
626 AnimateBetween(target, keyFrames, alpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION);
629 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, Interpolation interpolation)
631 AnimateBetween(target, keyFrames, alpha, TimePeriod(mDurationSeconds), interpolation);
634 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period)
636 AnimateBetween(target, keyFrames, alpha, period, DEFAULT_INTERPOLATION);
639 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period, Interpolation interpolation)
641 Object& object = GetImplementation( target.object );
643 ExtendDuration( period );
645 switch(keyFrames.GetType())
647 case Dali::Property::BOOLEAN:
649 const KeyFrameBoolean* kf;
650 GetSpecialization(keyFrames, kf);
651 KeyFrameBooleanPtr kfCopy = KeyFrameBoolean::Clone(*kf);
652 AddAnimatorConnector( AnimatorConnector<bool>::New( object,
653 target.propertyIndex,
654 target.componentIndex,
655 new KeyFrameBooleanFunctor(kfCopy),
661 case Dali::Property::INTEGER:
663 const KeyFrameInteger* kf;
664 GetSpecialization(keyFrames, kf);
665 KeyFrameIntegerPtr kfCopy = KeyFrameInteger::Clone(*kf);
666 AddAnimatorConnector( AnimatorConnector<int>::New( object,
667 target.propertyIndex,
668 target.componentIndex,
669 new KeyFrameIntegerFunctor(kfCopy,interpolation),
675 case Dali::Property::FLOAT:
677 const KeyFrameNumber* kf;
678 GetSpecialization(keyFrames, kf);
679 KeyFrameNumberPtr kfCopy = KeyFrameNumber::Clone(*kf);
680 AddAnimatorConnector( AnimatorConnector<float>::New( object,
681 target.propertyIndex,
682 target.componentIndex,
683 new KeyFrameNumberFunctor(kfCopy,interpolation),
689 case Dali::Property::VECTOR2:
691 const KeyFrameVector2* kf;
692 GetSpecialization(keyFrames, kf);
693 KeyFrameVector2Ptr kfCopy = KeyFrameVector2::Clone(*kf);
694 AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
695 target.propertyIndex,
696 target.componentIndex,
697 new KeyFrameVector2Functor(kfCopy,interpolation),
703 case Dali::Property::VECTOR3:
705 const KeyFrameVector3* kf;
706 GetSpecialization(keyFrames, kf);
707 KeyFrameVector3Ptr kfCopy = KeyFrameVector3::Clone(*kf);
708 AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
709 target.propertyIndex,
710 target.componentIndex,
711 new KeyFrameVector3Functor(kfCopy,interpolation),
717 case Dali::Property::VECTOR4:
719 const KeyFrameVector4* kf;
720 GetSpecialization(keyFrames, kf);
721 KeyFrameVector4Ptr kfCopy = KeyFrameVector4::Clone(*kf);
722 AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
723 target.propertyIndex,
724 target.componentIndex,
725 new KeyFrameVector4Functor(kfCopy,interpolation),
731 case Dali::Property::ROTATION:
733 const KeyFrameQuaternion* kf;
734 GetSpecialization(keyFrames, kf);
735 KeyFrameQuaternionPtr kfCopy = KeyFrameQuaternion::Clone(*kf);
736 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
737 target.propertyIndex,
738 target.componentIndex,
739 new KeyFrameQuaternionFunctor(kfCopy),
747 // non animatable types handled by keyframes
752 bool Animation::HasFinished()
754 bool hasFinished(false);
755 const int playedCount(mAnimation->GetPlayedCount());
757 // If the play count has been incremented, then another notification is required
758 mCurrentLoop = mAnimation->GetCurrentLoop();
760 if (playedCount > mNotificationCount)
762 // Note that only one signal is emitted, if the animation has been played repeatedly
763 mNotificationCount = playedCount;
767 mState = Dali::Animation::STOPPED;
773 Dali::Animation::AnimationSignalType& Animation::FinishedSignal()
775 return mFinishedSignal;
778 void Animation::EmitSignalFinish()
780 if ( !mFinishedSignal.Empty() )
782 Dali::Animation handle( this );
783 mFinishedSignal.Emit( handle );
786 // This callback is used internally, to avoid the overhead of using a signal.
787 if ( mFinishedCallback )
789 mFinishedCallback( mFinishedCallbackObject );
793 bool Animation::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
795 bool connected( true );
796 Animation* animation = static_cast< Animation* >(object); // TypeRegistry guarantees that this is the correct type.
798 if( 0 == signalName.compare( SIGNAL_FINISHED ) )
800 animation->FinishedSignal().Connect( tracker, functor );
804 // signalName does not match any signal
811 void Animation::SetFinishedCallback( FinishedCallback callback, Object* object )
813 mFinishedCallback = callback;
814 mFinishedCallbackObject = object;
817 void Animation::AddAnimatorConnector( AnimatorConnectorBase* connector )
819 DALI_ASSERT_DEBUG( NULL != connector );
821 connector->SetParent(*this);
823 mConnectors.PushBack( connector );
826 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward )
828 Animate( actor, path, forward, mDefaultAlpha, TimePeriod(mDurationSeconds) );
831 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha )
833 Animate( actor, path, forward, alpha, TimePeriod(mDurationSeconds) );
836 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, TimePeriod period )
838 Animate( actor, path, forward, mDefaultAlpha, period );
841 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha, TimePeriod period)
843 ExtendDuration( period );
845 PathPtr pathCopy = Path::Clone(path);
848 AddAnimatorConnector( AnimatorConnector<Vector3>::New( actor,
849 Dali::Actor::Property::POSITION,
850 Property::INVALID_COMPONENT_INDEX,
851 new PathPositionFunctor( pathCopy ),
855 //If forward is zero, PathRotationFunctor will always return the unit quaternion
856 if( forward != Vector3::ZERO )
859 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( actor,
860 Dali::Actor::Property::ORIENTATION,
861 Property::INVALID_COMPONENT_INDEX,
862 new PathRotationFunctor( pathCopy, forward ),
868 void Animation::Show(Actor& actor, float delaySeconds)
870 ExtendDuration( TimePeriod(delaySeconds, 0) );
872 AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
873 Dali::Actor::Property::VISIBLE,
874 Property::INVALID_COMPONENT_INDEX,
875 new AnimateToBoolean(SHOW_VALUE),
877 TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
880 void Animation::Hide(Actor& actor, float delaySeconds)
882 ExtendDuration( TimePeriod(delaySeconds, 0) );
884 AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
885 Dali::Actor::Property::VISIBLE,
886 Property::INVALID_COMPONENT_INDEX,
887 new AnimateToBoolean(HIDE_VALUE),
889 TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
892 bool Animation::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
895 Animation* animation = dynamic_cast<Animation*>( object );
899 if( 0 == actionName.compare( ACTION_PLAY ) )
901 if( Property::Value* value = attributes.Find("duration", Property::FLOAT) )
903 animation->SetDuration( value->Get<float>() );
909 else if( 0 == actionName.compare( ACTION_STOP ) )
914 else if( 0 == actionName.compare( ACTION_PAUSE ) )
924 void Animation::SetCurrentProgress(float progress)
926 if( mAnimation && progress >= mPlayRange.x && progress <= mPlayRange.y )
928 // mAnimation is being used in a separate thread; queue a message to set the current progress
929 SetCurrentProgressMessage( mEventThreadServices, *mAnimation, progress );
933 float Animation::GetCurrentProgress()
937 return mAnimation->GetCurrentProgress();
943 void Animation::ExtendDuration( const TimePeriod& timePeriod )
945 float duration = timePeriod.delaySeconds + timePeriod.durationSeconds;
947 if( duration > mDurationSeconds )
949 SetDuration( duration );
953 void Animation::SetSpeedFactor( float factor )
957 mSpeedFactor = factor;
958 SetSpeedFactorMessage( mEventThreadServices, *mAnimation, factor );
962 float Animation::GetSpeedFactor() const
967 void Animation::SetPlayRange( const Vector2& range)
969 //Make sure the range specified is between 0.0 and 1.0
970 if( range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f )
972 Vector2 orderedRange( range );
973 //If the range is not in order swap values
974 if( range.x > range.y )
976 orderedRange = Vector2(range.y, range.x);
979 // Cache for public getters
980 mPlayRange = orderedRange;
982 // mAnimation is being used in a separate thread; queue a message to set play range
983 SetPlayRangeMessage( mEventThreadServices, *mAnimation, orderedRange );
987 Vector2 Animation::GetPlayRange() const
993 } // namespace Internal