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 : mAnimation( NULL ),
116 mEventThreadServices( eventThreadServices ),
117 mPlaylist( playlist ),
120 mConnectorTargetValues(),
121 mPlayRange( Vector2(0.0f,1.0f)),
122 mDurationSeconds( durationSeconds ),
124 mNotificationCount( 0 ),
127 mEndAction( endAction ),
128 mDisconnectAction( disconnectAction ),
129 mDefaultAlpha( defaultAlpha ),
130 mState(Dali::Animation::STOPPED)
134 void Animation::Initialize()
136 // Connect to the animation playlist
137 mPlaylist.AnimationCreated( *this );
144 Animation::~Animation()
146 // Guard to allow handle destruction after Core has been destroyed
147 if ( Stage::IsInstalled() )
149 // Disconnect from the animation playlist
150 mPlaylist.AnimationDestroyed( *this );
152 DestroySceneObject();
158 void Animation::CreateSceneObject()
160 DALI_ASSERT_DEBUG( mAnimation == NULL );
162 // Create a new animation, temporarily owned
163 SceneGraph::Animation* animation = SceneGraph::Animation::New( mDurationSeconds, mSpeedFactor, mPlayRange, mLoopCount, mEndAction, mDisconnectAction );
165 // Keep a const pointer to the animation.
166 mAnimation = animation;
168 // Transfer animation ownership to the update manager through a message
169 AddAnimationMessage( mEventThreadServices.GetUpdateManager(), animation );
172 void Animation::DestroySceneObject()
174 if ( mAnimation != NULL )
176 // Remove animation using a message to the update manager
177 RemoveAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
182 void Animation::SetDuration(float seconds)
186 DALI_LOG_WARNING("duration should be greater than 0.0f.\n");
190 // Cache for public getters
191 mDurationSeconds = seconds;
193 // mAnimation is being used in a separate thread; queue a message to set the value
194 SetDurationMessage( mEventThreadServices, *mAnimation, seconds );
197 float Animation::GetDuration() const
199 // This is not animatable; the cached value is up-to-date.
200 return mDurationSeconds;
203 void Animation::SetLooping(bool on)
205 SetLoopCount( on ? 0 : 1 );
208 void Animation::SetLoopCount(int count)
210 // Cache for public getters
213 // mAnimation is being used in a separate thread; queue a message to set the value
214 SetLoopingMessage( mEventThreadServices, *mAnimation, mLoopCount );
217 int Animation::GetLoopCount()
222 int Animation::GetCurrentLoop()
227 bool Animation::IsLooping() const
229 return mLoopCount != 1;
232 void Animation::SetEndAction(EndAction action)
234 // Cache for public getters
237 // mAnimation is being used in a separate thread; queue a message to set the value
238 SetEndActionMessage( mEventThreadServices, *mAnimation, action );
241 Dali::Animation::EndAction Animation::GetEndAction() const
243 // This is not animatable; the cached value is up-to-date.
247 void Animation::SetDisconnectAction(EndAction action)
249 // Cache for public getters
250 mDisconnectAction = action;
252 // mAnimation is being used in a separate thread; queue a message to set the value
253 SetDisconnectActionMessage( mEventThreadServices, *mAnimation, action );
256 Dali::Animation::EndAction Animation::GetDisconnectAction() const
258 // This is not animatable; the cached value is up-to-date.
259 return mDisconnectAction;
262 void Animation::Play()
264 // Update the current playlist
265 mPlaylist.OnPlay( *this );
267 mState = Dali::Animation::PLAYING;
269 if( mEndAction != EndAction::Discard ) // If the animation is discarded, then we do not want to change the target values
271 // Sort according to end time with earlier end times coming first, if the end time is the same, then the connectors are not moved
272 std::stable_sort( mConnectorTargetValues.begin(), mConnectorTargetValues.end(), CompareConnectorEndTimes );
274 // Loop through all connector target values sorted by increasing end time
275 ConnectorTargetValuesContainer::const_iterator iter = mConnectorTargetValues.begin();
276 const ConnectorTargetValuesContainer::const_iterator endIter = mConnectorTargetValues.end();
277 for( ; iter != endIter; ++iter )
279 AnimatorConnectorBase* connector = mConnectors[ iter->connectorIndex ];
281 Object* object = connector->GetObject();
284 object->NotifyPropertyAnimation( *this, connector->GetPropertyIndex(), iter->targetValue, iter->propertyChangeType );
289 // mAnimation is being used in a separate thread; queue a Play message
290 PlayAnimationMessage( mEventThreadServices, *mAnimation );
293 void Animation::PlayFrom( float progress )
295 if( progress >= mPlayRange.x && progress <= mPlayRange.y )
297 // Update the current playlist
298 mPlaylist.OnPlay( *this );
300 mState = Dali::Animation::PLAYING;
302 // mAnimation is being used in a separate thread; queue a Play message
303 PlayAnimationFromMessage( mEventThreadServices, *mAnimation, progress );
307 void Animation::Pause()
309 mState = Dali::Animation::PAUSED;
311 // mAnimation is being used in a separate thread; queue a Pause message
312 PauseAnimationMessage( mEventThreadServices, *mAnimation );
315 Dali::Animation::State Animation::GetState() const
320 void Animation::Stop()
322 mState = Dali::Animation::STOPPED;
324 // mAnimation is being used in a separate thread; queue a Stop message
325 StopAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
328 void Animation::Clear()
330 DALI_ASSERT_DEBUG(mAnimation);
332 // Remove all the connectors
335 // Reset the connector target values
336 mConnectorTargetValues.clear();
338 // Replace the old scene-object with a new one
339 DestroySceneObject();
342 // Reset the notification count, since the new scene-object has never been played
343 mNotificationCount = 0;
345 // Update the current playlist
346 mPlaylist.OnClear( *this );
349 void Animation::AnimateBy(Property& target, Property::Value& relativeValue)
351 AnimateBy(target, relativeValue, mDefaultAlpha, TimePeriod(mDurationSeconds));
354 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha)
356 AnimateBy(target, relativeValue, alpha, TimePeriod(mDurationSeconds));
359 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, TimePeriod period)
361 AnimateBy(target, relativeValue, mDefaultAlpha, period);
364 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha, TimePeriod period)
366 Object& object = GetImplementation( target.object );
367 const Property::Type targetType = object.GetPropertyType( target.propertyIndex );
368 const Property::Type destinationType = relativeValue.GetType();
369 DALI_ASSERT_ALWAYS( targetType == destinationType && "Animated value and Property type don't match" );
371 ExtendDuration( period );
373 // Store data to later notify the object that its property is being animated
374 ConnectorTargetValues connectorPair;
375 connectorPair.targetValue = relativeValue;
376 connectorPair.connectorIndex = mConnectors.Count();
377 connectorPair.timePeriod = period;
378 connectorPair.propertyChangeType = Object::PropertyChange::ADJUST_VALUE_BY;
379 mConnectorTargetValues.push_back( connectorPair );
381 switch ( targetType )
383 case Property::BOOLEAN:
385 AddAnimatorConnector( AnimatorConnector<bool>::New( object,
386 target.propertyIndex,
387 target.componentIndex,
388 new AnimateByBoolean(relativeValue.Get<bool>()),
394 case Property::INTEGER:
396 AddAnimatorConnector( AnimatorConnector<int>::New( object,
397 target.propertyIndex,
398 target.componentIndex,
399 new AnimateByInteger(relativeValue.Get<int>()),
405 case Property::FLOAT:
407 AddAnimatorConnector( AnimatorConnector<float>::New( object,
408 target.propertyIndex,
409 target.componentIndex,
410 new AnimateByFloat(relativeValue.Get<float>()),
416 case Property::VECTOR2:
418 AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
419 target.propertyIndex,
420 target.componentIndex,
421 new AnimateByVector2(relativeValue.Get<Vector2>()),
427 case Property::VECTOR3:
429 AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
430 target.propertyIndex,
431 target.componentIndex,
432 new AnimateByVector3(relativeValue.Get<Vector3>()),
438 case Property::VECTOR4:
440 AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
441 target.propertyIndex,
442 target.componentIndex,
443 new AnimateByVector4(relativeValue.Get<Vector4>()),
449 case Property::ROTATION:
451 AngleAxis angleAxis = relativeValue.Get<AngleAxis>();
453 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
454 target.propertyIndex,
455 target.componentIndex,
456 new RotateByAngleAxis(angleAxis.angle, angleAxis.axis),
464 // non animatable types handled already
469 void Animation::AnimateTo(Property& target, Property::Value& destinationValue)
471 AnimateTo(target, destinationValue, mDefaultAlpha, TimePeriod(mDurationSeconds));
474 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha)
476 AnimateTo(target, destinationValue, alpha, TimePeriod(mDurationSeconds));
479 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, TimePeriod period)
481 AnimateTo(target, destinationValue, mDefaultAlpha, period);
484 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
486 Object& object = GetImplementation(target.object);
488 AnimateTo( object, target.propertyIndex, target.componentIndex, destinationValue, alpha, period );
491 void Animation::AnimateTo(Object& targetObject, Property::Index targetPropertyIndex, int componentIndex, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
493 Property::Type targetType = targetObject.GetPropertyType(targetPropertyIndex);
494 if( componentIndex != Property::INVALID_COMPONENT_INDEX )
496 if( ( targetType == Property::VECTOR2 ) ||
497 ( targetType == Property::VECTOR3 ) ||
498 ( targetType == Property::VECTOR4 ) )
500 targetType = Property::FLOAT;
503 const Property::Type destinationType = destinationValue.GetType();
504 DALI_ASSERT_ALWAYS( targetType == destinationType && "Animated value and Property type don't match" );
506 ExtendDuration( period );
508 // Store data to later notify the object that its property is being animated
509 ConnectorTargetValues connectorPair;
510 connectorPair.targetValue = destinationValue;
511 connectorPair.connectorIndex = mConnectors.Count();
512 connectorPair.timePeriod = period;
513 connectorPair.propertyChangeType = Object::PropertyChange::SET;
514 mConnectorTargetValues.push_back( connectorPair );
516 switch ( destinationType )
518 case Property::BOOLEAN:
520 AddAnimatorConnector( AnimatorConnector<bool>::New( targetObject,
523 new AnimateToBoolean( destinationValue.Get<bool>() ),
529 case Property::INTEGER:
531 AddAnimatorConnector( AnimatorConnector<int>::New( targetObject,
534 new AnimateToInteger( destinationValue.Get<int>() ),
540 case Property::FLOAT:
542 AddAnimatorConnector( AnimatorConnector<float>::New( targetObject,
545 new AnimateToFloat( destinationValue.Get<float>() ),
551 case Property::VECTOR2:
553 AddAnimatorConnector( AnimatorConnector<Vector2>::New( targetObject,
556 new AnimateToVector2( destinationValue.Get<Vector2>() ),
562 case Property::VECTOR3:
564 AddAnimatorConnector( AnimatorConnector<Vector3>::New( targetObject,
567 new AnimateToVector3( destinationValue.Get<Vector3>() ),
573 case Property::VECTOR4:
575 AddAnimatorConnector( AnimatorConnector<Vector4>::New( targetObject,
578 new AnimateToVector4( destinationValue.Get<Vector4>() ),
584 case Property::ROTATION:
586 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( targetObject,
589 new RotateToQuaternion( destinationValue.Get<Quaternion>() ),
597 // non animatable types handled already
602 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames)
604 AnimateBetween(target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION );
607 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, Interpolation interpolation )
609 AnimateBetween(target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), interpolation );
612 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period)
614 AnimateBetween(target, keyFrames, mDefaultAlpha, period, DEFAULT_INTERPOLATION);
617 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period, Interpolation interpolation)
619 AnimateBetween(target, keyFrames, mDefaultAlpha, period, interpolation);
622 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha)
624 AnimateBetween(target, keyFrames, alpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION);
627 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, Interpolation interpolation)
629 AnimateBetween(target, keyFrames, alpha, TimePeriod(mDurationSeconds), interpolation);
632 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period)
634 AnimateBetween(target, keyFrames, alpha, period, DEFAULT_INTERPOLATION);
637 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period, Interpolation interpolation)
639 Object& object = GetImplementation( target.object );
641 ExtendDuration( period );
643 switch(keyFrames.GetType())
645 case Dali::Property::BOOLEAN:
647 const KeyFrameBoolean* kf;
648 GetSpecialization(keyFrames, kf);
649 KeyFrameBooleanPtr kfCopy = KeyFrameBoolean::Clone(*kf);
650 AddAnimatorConnector( AnimatorConnector<bool>::New( object,
651 target.propertyIndex,
652 target.componentIndex,
653 new KeyFrameBooleanFunctor(kfCopy),
659 case Dali::Property::INTEGER:
661 const KeyFrameInteger* kf;
662 GetSpecialization(keyFrames, kf);
663 KeyFrameIntegerPtr kfCopy = KeyFrameInteger::Clone(*kf);
664 AddAnimatorConnector( AnimatorConnector<int>::New( object,
665 target.propertyIndex,
666 target.componentIndex,
667 new KeyFrameIntegerFunctor(kfCopy,interpolation),
673 case Dali::Property::FLOAT:
675 const KeyFrameNumber* kf;
676 GetSpecialization(keyFrames, kf);
677 KeyFrameNumberPtr kfCopy = KeyFrameNumber::Clone(*kf);
678 AddAnimatorConnector( AnimatorConnector<float>::New( object,
679 target.propertyIndex,
680 target.componentIndex,
681 new KeyFrameNumberFunctor(kfCopy,interpolation),
687 case Dali::Property::VECTOR2:
689 const KeyFrameVector2* kf;
690 GetSpecialization(keyFrames, kf);
691 KeyFrameVector2Ptr kfCopy = KeyFrameVector2::Clone(*kf);
692 AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
693 target.propertyIndex,
694 target.componentIndex,
695 new KeyFrameVector2Functor(kfCopy,interpolation),
701 case Dali::Property::VECTOR3:
703 const KeyFrameVector3* kf;
704 GetSpecialization(keyFrames, kf);
705 KeyFrameVector3Ptr kfCopy = KeyFrameVector3::Clone(*kf);
706 AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
707 target.propertyIndex,
708 target.componentIndex,
709 new KeyFrameVector3Functor(kfCopy,interpolation),
715 case Dali::Property::VECTOR4:
717 const KeyFrameVector4* kf;
718 GetSpecialization(keyFrames, kf);
719 KeyFrameVector4Ptr kfCopy = KeyFrameVector4::Clone(*kf);
720 AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
721 target.propertyIndex,
722 target.componentIndex,
723 new KeyFrameVector4Functor(kfCopy,interpolation),
729 case Dali::Property::ROTATION:
731 const KeyFrameQuaternion* kf;
732 GetSpecialization(keyFrames, kf);
733 KeyFrameQuaternionPtr kfCopy = KeyFrameQuaternion::Clone(*kf);
734 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
735 target.propertyIndex,
736 target.componentIndex,
737 new KeyFrameQuaternionFunctor(kfCopy),
745 // non animatable types handled by keyframes
750 bool Animation::HasFinished()
752 bool hasFinished(false);
753 const int playedCount(mAnimation->GetPlayedCount());
755 // If the play count has been incremented, then another notification is required
756 mCurrentLoop = mAnimation->GetCurrentLoop();
758 if (playedCount > mNotificationCount)
760 // Note that only one signal is emitted, if the animation has been played repeatedly
761 mNotificationCount = playedCount;
765 mState = Dali::Animation::STOPPED;
771 Dali::Animation::AnimationSignalType& Animation::FinishedSignal()
773 return mFinishedSignal;
776 void Animation::EmitSignalFinish()
778 if ( !mFinishedSignal.Empty() )
780 Dali::Animation handle( this );
781 mFinishedSignal.Emit( handle );
785 bool Animation::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
787 bool connected( true );
788 Animation* animation = static_cast< Animation* >(object); // TypeRegistry guarantees that this is the correct type.
790 if( 0 == signalName.compare( SIGNAL_FINISHED ) )
792 animation->FinishedSignal().Connect( tracker, functor );
796 // signalName does not match any signal
803 void Animation::AddAnimatorConnector( AnimatorConnectorBase* connector )
805 DALI_ASSERT_DEBUG( NULL != connector );
807 connector->SetParent(*this);
809 mConnectors.PushBack( connector );
812 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward )
814 Animate( actor, path, forward, mDefaultAlpha, TimePeriod(mDurationSeconds) );
817 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha )
819 Animate( actor, path, forward, alpha, TimePeriod(mDurationSeconds) );
822 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, TimePeriod period )
824 Animate( actor, path, forward, mDefaultAlpha, period );
827 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha, TimePeriod period)
829 ExtendDuration( period );
831 PathPtr pathCopy = Path::Clone(path);
834 AddAnimatorConnector( AnimatorConnector<Vector3>::New( actor,
835 Dali::Actor::Property::POSITION,
836 Property::INVALID_COMPONENT_INDEX,
837 new PathPositionFunctor( pathCopy ),
841 //If forward is zero, PathRotationFunctor will always return the unit quaternion
842 if( forward != Vector3::ZERO )
845 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( actor,
846 Dali::Actor::Property::ORIENTATION,
847 Property::INVALID_COMPONENT_INDEX,
848 new PathRotationFunctor( pathCopy, forward ),
854 void Animation::Show(Actor& actor, float delaySeconds)
856 ExtendDuration( TimePeriod(delaySeconds, 0) );
858 AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
859 Dali::Actor::Property::VISIBLE,
860 Property::INVALID_COMPONENT_INDEX,
861 new AnimateToBoolean(SHOW_VALUE),
863 TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
866 void Animation::Hide(Actor& actor, float delaySeconds)
868 ExtendDuration( TimePeriod(delaySeconds, 0) );
870 AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
871 Dali::Actor::Property::VISIBLE,
872 Property::INVALID_COMPONENT_INDEX,
873 new AnimateToBoolean(HIDE_VALUE),
875 TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
878 bool Animation::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
881 Animation* animation = dynamic_cast<Animation*>( object );
885 if( 0 == actionName.compare( ACTION_PLAY ) )
887 if( Property::Value* value = attributes.Find("duration", Property::FLOAT) )
889 animation->SetDuration( value->Get<float>() );
895 else if( 0 == actionName.compare( ACTION_STOP ) )
900 else if( 0 == actionName.compare( ACTION_PAUSE ) )
910 void Animation::SetCurrentProgress(float progress)
912 if( mAnimation && progress >= mPlayRange.x && progress <= mPlayRange.y )
914 // mAnimation is being used in a separate thread; queue a message to set the current progress
915 SetCurrentProgressMessage( mEventThreadServices, *mAnimation, progress );
919 float Animation::GetCurrentProgress()
923 return mAnimation->GetCurrentProgress();
929 void Animation::ExtendDuration( const TimePeriod& timePeriod )
931 float duration = timePeriod.delaySeconds + timePeriod.durationSeconds;
933 if( duration > mDurationSeconds )
935 SetDuration( duration );
939 void Animation::SetSpeedFactor( float factor )
943 mSpeedFactor = factor;
944 SetSpeedFactorMessage( mEventThreadServices, *mAnimation, factor );
948 float Animation::GetSpeedFactor() const
953 void Animation::SetPlayRange( const Vector2& range)
955 //Make sure the range specified is between 0.0 and 1.0
956 if( range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f )
958 Vector2 orderedRange( range );
959 //If the range is not in order swap values
960 if( range.x > range.y )
962 orderedRange = Vector2(range.y, range.x);
965 // Cache for public getters
966 mPlayRange = orderedRange;
968 // mAnimation is being used in a separate thread; queue a message to set play range
969 SetPlayRangeMessage( mEventThreadServices, *mAnimation, orderedRange );
973 Vector2 Animation::GetPlayRange() const
978 bool Animation::CompareConnectorEndTimes( const Animation::ConnectorTargetValues& lhs, const Animation::ConnectorTargetValues& rhs )
980 return ( ( lhs.timePeriod.delaySeconds + lhs.timePeriod.durationSeconds ) < ( rhs.timePeriod.delaySeconds + rhs.timePeriod.durationSeconds ) );
983 } // namespace Internal