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 if( durationSeconds < 0.0f )
96 DALI_LOG_WARNING("duration should be greater than 0.0f.\n");
97 durationSeconds = 0.0f;
100 AnimationPtr animation = new Animation( *stage, playlist, durationSeconds, DEFAULT_END_ACTION, DEFAULT_DISCONNECT_ACTION, Dali::AlphaFunctions::Linear );
102 // Second-phase construction
103 animation->Initialize();
108 Animation::Animation( EventThreadServices& eventThreadServices, AnimationPlaylist& playlist, float durationSeconds, EndAction endAction, EndAction disconnectAction, AlphaFunction defaultAlpha )
109 : mEventThreadServices( eventThreadServices ),
110 mPlaylist( playlist ),
112 mNotificationCount( 0 ),
113 mFinishedCallback( NULL ),
114 mFinishedCallbackObject( NULL ),
115 mDurationSeconds( durationSeconds ),
118 mPlayRange( Vector2(0.0f,1.0f)),
119 mEndAction( endAction ),
120 mDisconnectAction( disconnectAction ),
121 mDefaultAlpha( defaultAlpha )
125 void Animation::Initialize()
127 // Connect to the animation playlist
128 mPlaylist.AnimationCreated( *this );
135 Animation::~Animation()
137 // Guard to allow handle destruction after Core has been destroyed
138 if ( Stage::IsInstalled() )
140 // Disconnect from the animation playlist
141 mPlaylist.AnimationDestroyed( *this );
143 DestroySceneObject();
149 void Animation::CreateSceneObject()
151 DALI_ASSERT_DEBUG( mAnimation == NULL );
153 // Create a new animation, temporarily owned
154 SceneGraph::Animation* animation = SceneGraph::Animation::New( mDurationSeconds, mSpeedFactor, mPlayRange, mIsLooping, mEndAction, mDisconnectAction );
156 // Keep a const pointer to the animation.
157 mAnimation = animation;
159 // Transfer animation ownership to the update manager through a message
160 AddAnimationMessage( mEventThreadServices.GetUpdateManager(), animation );
163 void Animation::DestroySceneObject()
165 if ( mAnimation != NULL )
167 // Remove animation using a message to the update manager
168 RemoveAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
173 void Animation::SetDuration(float seconds)
177 DALI_LOG_WARNING("duration should be greater than 0.0f.\n");
181 // Cache for public getters
182 mDurationSeconds = seconds;
184 // mAnimation is being used in a separate thread; queue a message to set the value
185 SetDurationMessage( mEventThreadServices, *mAnimation, seconds );
188 float Animation::GetDuration() const
190 // This is not animatable; the cached value is up-to-date.
191 return mDurationSeconds;
194 void Animation::SetLooping(bool looping)
196 // Cache for public getters
197 mIsLooping = looping;
199 // mAnimation is being used in a separate thread; queue a message to set the value
200 SetLoopingMessage( mEventThreadServices, *mAnimation, looping );
203 bool Animation::IsLooping() const
205 // This is not animatable; the cached value is up-to-date.
209 void Animation::SetEndAction(EndAction action)
211 // Cache for public getters
214 // mAnimation is being used in a separate thread; queue a message to set the value
215 SetEndActionMessage( mEventThreadServices, *mAnimation, action );
218 Dali::Animation::EndAction Animation::GetEndAction() const
220 // This is not animatable; the cached value is up-to-date.
224 void Animation::SetDisconnectAction(EndAction action)
226 // Cache for public getters
227 mDisconnectAction = action;
229 // mAnimation is being used in a separate thread; queue a message to set the value
230 SetDisconnectActionMessage( mEventThreadServices, *mAnimation, action );
233 Dali::Animation::EndAction Animation::GetDisconnectAction() const
235 // This is not animatable; the cached value is up-to-date.
236 return mDisconnectAction;
239 void Animation::Play()
241 // Update the current playlist
242 mPlaylist.OnPlay( *this );
244 // mAnimation is being used in a separate thread; queue a Play message
245 PlayAnimationMessage( mEventThreadServices, *mAnimation );
248 void Animation::PlayFrom( float progress )
250 if( progress >= mPlayRange.x && progress <= mPlayRange.y )
252 // Update the current playlist
253 mPlaylist.OnPlay( *this );
255 // mAnimation is being used in a separate thread; queue a Play message
256 PlayAnimationFromMessage( mEventThreadServices, *mAnimation, progress );
260 void Animation::Pause()
262 // mAnimation is being used in a separate thread; queue a Pause message
263 PauseAnimationMessage( mEventThreadServices, *mAnimation );
266 void Animation::Stop()
268 // mAnimation is being used in a separate thread; queue a Stop message
269 StopAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
272 void Animation::Clear()
274 DALI_ASSERT_DEBUG(mAnimation);
276 // Remove all the connectors
279 // Replace the old scene-object with a new one
280 DestroySceneObject();
283 // Reset the notification count, since the new scene-object has never been played
284 mNotificationCount = 0;
286 // Update the current playlist
287 mPlaylist.OnClear( *this );
290 void Animation::AnimateBy(Property& target, Property::Value& relativeValue)
292 AnimateBy(target, relativeValue, AlphaFunctions::Default, mDurationSeconds);
295 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha)
297 AnimateBy(target, relativeValue, alpha, mDurationSeconds);
300 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, TimePeriod period)
302 AnimateBy(target, relativeValue, AlphaFunctions::Default, period);
305 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha, TimePeriod period)
307 Object& object = dynamic_cast<Object&>( GetImplementation(target.object) );
309 ExtendDuration( period );
311 switch ( relativeValue.GetType() )
313 case Property::BOOLEAN:
315 AddAnimatorConnector( AnimatorConnector<bool>::New( object,
316 target.propertyIndex,
317 target.componentIndex,
318 new AnimateByBoolean(relativeValue.Get<bool>()),
324 case Property::INTEGER:
326 AddAnimatorConnector( AnimatorConnector<int>::New( object,
327 target.propertyIndex,
328 target.componentIndex,
329 new AnimateByInteger(relativeValue.Get<int>()),
335 case Property::UNSIGNED_INTEGER:
337 AddAnimatorConnector( AnimatorConnector<unsigned int>::New( object,
338 target.propertyIndex,
339 target.componentIndex,
340 new AnimateByUnsignedInteger(relativeValue.Get<unsigned int>()),
346 case Property::FLOAT:
348 AddAnimatorConnector( AnimatorConnector<float>::New( object,
349 target.propertyIndex,
350 target.componentIndex,
351 new AnimateByFloat(relativeValue.Get<float>()),
357 case Property::VECTOR2:
359 AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
360 target.propertyIndex,
361 target.componentIndex,
362 new AnimateByVector2(relativeValue.Get<Vector2>()),
368 case Property::VECTOR3:
370 AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
371 target.propertyIndex,
372 target.componentIndex,
373 new AnimateByVector3(relativeValue.Get<Vector3>()),
379 case Property::VECTOR4:
381 AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
382 target.propertyIndex,
383 target.componentIndex,
384 new AnimateByVector4(relativeValue.Get<Vector4>()),
390 case Property::ROTATION:
392 AngleAxis angleAxis = relativeValue.Get<AngleAxis>();
394 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
395 target.propertyIndex,
396 target.componentIndex,
397 new RotateByAngleAxis(angleAxis.angle, angleAxis.axis),
404 DALI_ASSERT_ALWAYS( false && "Property type enumeration out of bounds" ); // should never come here
409 void Animation::AnimateTo(Property& target, Property::Value& destinationValue)
411 AnimateTo(target, destinationValue, AlphaFunctions::Default, mDurationSeconds);
414 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha)
416 AnimateTo(target, destinationValue, alpha, mDurationSeconds);
419 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, TimePeriod period)
421 AnimateTo(target, destinationValue, AlphaFunctions::Default, period);
424 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
426 Object& object = dynamic_cast<Object&>( GetImplementation(target.object) );
428 AnimateTo( object, target.propertyIndex, target.componentIndex, destinationValue, alpha, period );
431 void Animation::AnimateTo(Object& targetObject, Property::Index targetPropertyIndex, int componentIndex, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
433 Property::Type type = targetObject.GetPropertyType(targetPropertyIndex);
434 if(componentIndex != Property::INVALID_COMPONENT_INDEX)
436 if( type == Property::VECTOR2
437 || type == Property::VECTOR3
438 || type == Property::VECTOR4 )
440 type = Property::FLOAT;
443 DALI_ASSERT_ALWAYS( type == destinationValue.GetType() && "DestinationValue does not match Target Property type" );
445 ExtendDuration( period );
447 switch (destinationValue.GetType())
449 case Property::BOOLEAN:
451 AddAnimatorConnector( AnimatorConnector<bool>::New( targetObject,
454 new AnimateToBoolean( destinationValue.Get<bool>() ),
460 case Property::INTEGER:
462 AddAnimatorConnector( AnimatorConnector<int>::New( targetObject,
465 new AnimateToInteger( destinationValue.Get<int>() ),
471 case Property::UNSIGNED_INTEGER:
473 AddAnimatorConnector( AnimatorConnector<unsigned int>::New( targetObject,
476 new AnimateToUnsignedInteger( destinationValue.Get<unsigned int>() ),
482 case Property::FLOAT:
484 AddAnimatorConnector( AnimatorConnector<float>::New( targetObject,
487 new AnimateToFloat( destinationValue.Get<float>() ),
493 case Property::VECTOR2:
495 AddAnimatorConnector( AnimatorConnector<Vector2>::New( targetObject,
498 new AnimateToVector2( destinationValue.Get<Vector2>() ),
504 case Property::VECTOR3:
506 if ( Dali::Actor::Property::SIZE == targetPropertyIndex )
508 // Test whether this is actually an Actor
509 Actor* maybeActor = dynamic_cast<Actor*>( &targetObject );
512 // Notify the actor that its size is being animated
513 maybeActor->NotifySizeAnimation( *this, destinationValue.Get<Vector3>() );
517 AddAnimatorConnector( AnimatorConnector<Vector3>::New( targetObject,
520 new AnimateToVector3( destinationValue.Get<Vector3>() ),
526 case Property::VECTOR4:
528 AddAnimatorConnector( AnimatorConnector<Vector4>::New( targetObject,
531 new AnimateToVector4( destinationValue.Get<Vector4>() ),
537 case Property::ROTATION:
539 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( targetObject,
542 new RotateToQuaternion( destinationValue.Get<Quaternion>() ),
549 DALI_ASSERT_ALWAYS( false && "Property type enumeration out of bounds" ); // should never come here
554 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames)
556 AnimateBetween(target, keyFrames, mDefaultAlpha, mDurationSeconds, DEFAULT_INTERPOLATION );
559 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, Interpolation interpolation )
561 AnimateBetween(target, keyFrames, mDefaultAlpha, mDurationSeconds, interpolation );
564 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period)
566 AnimateBetween(target, keyFrames, mDefaultAlpha, period, DEFAULT_INTERPOLATION);
569 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period, Interpolation interpolation)
571 AnimateBetween(target, keyFrames, mDefaultAlpha, period, interpolation);
574 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha)
576 AnimateBetween(target, keyFrames, alpha, mDurationSeconds, DEFAULT_INTERPOLATION);
579 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, Interpolation interpolation)
581 AnimateBetween(target, keyFrames, alpha, mDurationSeconds, interpolation);
584 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period)
586 AnimateBetween(target, keyFrames, alpha, period, DEFAULT_INTERPOLATION);
589 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period, Interpolation interpolation)
591 Object& object = dynamic_cast<Object&>( GetImplementation(target.object) );
593 ExtendDuration( period );
595 switch(keyFrames.GetType())
597 case Dali::Property::BOOLEAN:
599 const KeyFrameBoolean* kf;
600 GetSpecialization(keyFrames, kf);
601 KeyFrameBooleanPtr kfCopy = KeyFrameBoolean::Clone(*kf);
602 AddAnimatorConnector( AnimatorConnector<bool>::New( object,
603 target.propertyIndex,
604 target.componentIndex,
605 new KeyFrameBooleanFunctor(kfCopy),
611 case Dali::Property::INTEGER:
613 const KeyFrameInteger* kf;
614 GetSpecialization(keyFrames, kf);
615 KeyFrameIntegerPtr kfCopy = KeyFrameInteger::Clone(*kf);
616 AddAnimatorConnector( AnimatorConnector<int>::New( object,
617 target.propertyIndex,
618 target.componentIndex,
619 new KeyFrameIntegerFunctor(kfCopy,interpolation),
625 case Dali::Property::UNSIGNED_INTEGER:
627 const KeyFrameUnsignedInteger* kf;
628 GetSpecialization(keyFrames, kf);
629 KeyFrameUnsignedIntegerPtr kfCopy = KeyFrameUnsignedInteger::Clone(*kf);
630 AddAnimatorConnector( AnimatorConnector<int>::New( object,
631 target.propertyIndex,
632 target.componentIndex,
633 new KeyFrameUnsignedIntegerFunctor(kfCopy,interpolation),
639 case Dali::Property::FLOAT:
641 const KeyFrameNumber* kf;
642 GetSpecialization(keyFrames, kf);
643 KeyFrameNumberPtr kfCopy = KeyFrameNumber::Clone(*kf);
644 AddAnimatorConnector( AnimatorConnector<float>::New( object,
645 target.propertyIndex,
646 target.componentIndex,
647 new KeyFrameNumberFunctor(kfCopy,interpolation),
653 case Dali::Property::VECTOR2:
655 const KeyFrameVector2* kf;
656 GetSpecialization(keyFrames, kf);
657 KeyFrameVector2Ptr kfCopy = KeyFrameVector2::Clone(*kf);
658 AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
659 target.propertyIndex,
660 target.componentIndex,
661 new KeyFrameVector2Functor(kfCopy,interpolation),
667 case Dali::Property::VECTOR3:
669 const KeyFrameVector3* kf;
670 GetSpecialization(keyFrames, kf);
671 KeyFrameVector3Ptr kfCopy = KeyFrameVector3::Clone(*kf);
672 AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
673 target.propertyIndex,
674 target.componentIndex,
675 new KeyFrameVector3Functor(kfCopy,interpolation),
681 case Dali::Property::VECTOR4:
683 const KeyFrameVector4* kf;
684 GetSpecialization(keyFrames, kf);
685 KeyFrameVector4Ptr kfCopy = KeyFrameVector4::Clone(*kf);
686 AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
687 target.propertyIndex,
688 target.componentIndex,
689 new KeyFrameVector4Functor(kfCopy,interpolation),
695 case Dali::Property::ROTATION:
697 const KeyFrameQuaternion* kf;
698 GetSpecialization(keyFrames, kf);
699 KeyFrameQuaternionPtr kfCopy = KeyFrameQuaternion::Clone(*kf);
700 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
701 target.propertyIndex,
702 target.componentIndex,
703 new KeyFrameQuaternionFunctor(kfCopy),
709 default: // not all property types are animateable
714 bool Animation::HasFinished()
716 bool hasFinished(false);
717 const int playCount(mAnimation->GetPlayCount());
719 // If the play count has been incremented, then another notification is required
720 if (playCount > mNotificationCount)
722 // Note that only one signal is emitted, if the animation has been played repeatedly
723 mNotificationCount = playCount;
731 Dali::Animation::AnimationSignalType& Animation::FinishedSignal()
733 return mFinishedSignal;
736 void Animation::EmitSignalFinish()
738 if ( !mFinishedSignal.Empty() )
740 Dali::Animation handle( this );
741 mFinishedSignal.Emit( handle );
744 // This callback is used internally, to avoid the overhead of using a signal.
745 if ( mFinishedCallback )
747 mFinishedCallback( mFinishedCallbackObject );
751 bool Animation::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
753 bool connected( true );
754 Animation* animation = dynamic_cast<Animation*>(object);
756 if ( 0 == strcmp( signalName.c_str(), SIGNAL_FINISHED ) )
758 animation->FinishedSignal().Connect( tracker, functor );
762 // signalName does not match any signal
769 void Animation::SetFinishedCallback( FinishedCallback callback, Object* object )
771 mFinishedCallback = callback;
772 mFinishedCallbackObject = object;
775 void Animation::AddAnimatorConnector( AnimatorConnectorBase* connector )
777 DALI_ASSERT_DEBUG( NULL != connector );
779 connector->SetParent(*this);
781 mConnectors.PushBack( connector );
784 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward )
786 Animate( actor, path, forward, mDefaultAlpha, TimePeriod(0.0f,GetDuration()) );
789 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha )
791 Animate( actor, path, forward, alpha, TimePeriod(0.0f,GetDuration()) );
794 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, TimePeriod period )
796 Animate( actor, path, forward, mDefaultAlpha, period );
799 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha, TimePeriod period)
801 ExtendDuration( period );
803 PathPtr pathCopy = Path::Clone(path);
806 AddAnimatorConnector( AnimatorConnector<Vector3>::New( actor,
807 Dali::Actor::Property::POSITION,
808 Property::INVALID_COMPONENT_INDEX,
809 new PathPositionFunctor( pathCopy ),
813 //If forward is zero, PathRotationFunctor will always return the unit quaternion
814 if( forward != Vector3::ZERO )
817 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( actor,
818 Dali::Actor::Property::ORIENTATION,
819 Property::INVALID_COMPONENT_INDEX,
820 new PathRotationFunctor( pathCopy, forward ),
826 void Animation::Show(Actor& actor, float delaySeconds)
828 ExtendDuration( TimePeriod(delaySeconds, 0) );
830 AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
831 Dali::Actor::Property::VISIBLE,
832 Property::INVALID_COMPONENT_INDEX,
833 new AnimateToBoolean(SHOW_VALUE),
834 AlphaFunctions::Default,
835 TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
838 void Animation::Hide(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(HIDE_VALUE),
846 AlphaFunctions::Default,
847 TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
850 bool Animation::DoAction( BaseObject* object, const std::string& actionName, const std::vector<Property::Value>& attributes )
853 Animation* animation = dynamic_cast<Animation*>( object );
857 if( 0 == strcmp( actionName.c_str(), ACTION_PLAY ) )
859 if( attributes.size() > 0 )
861 animation->SetDuration( attributes[0].Get<float>() );
867 else if( 0 == strcmp( actionName.c_str(), ACTION_STOP ) )
872 else if( 0 == strcmp( actionName.c_str(), ACTION_PAUSE ) )
882 void Animation::SetCurrentProgress(float progress)
884 if( mAnimation && progress >= mPlayRange.x && progress <= mPlayRange.y )
886 // mAnimation is being used in a separate thread; queue a message to set the current progress
887 SetCurrentProgressMessage( mEventThreadServices, *mAnimation, progress );
891 float Animation::GetCurrentProgress()
895 return mAnimation->GetCurrentProgress();
901 void Animation::ExtendDuration( const TimePeriod& timePeriod )
903 float duration = timePeriod.delaySeconds + timePeriod.durationSeconds;
905 if( duration > mDurationSeconds )
907 SetDuration( duration );
911 void Animation::SetSpeedFactor( float factor )
915 mSpeedFactor = factor;
916 SetSpeedFactorMessage( mEventThreadServices, *mAnimation, factor );
920 float Animation::GetSpeedFactor() const
925 void Animation::SetPlayRange( const Vector2& range)
927 //Make sure the range specified is between 0.0 and 1.0
928 if( range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f )
930 Vector2 orderedRange( range );
931 //If the range is not in order swap values
932 if( range.x > range.y )
934 orderedRange = Vector2(range.y, range.x);
937 // Cache for public getters
938 mPlayRange = orderedRange;
940 // mAnimation is being used in a separate thread; queue a message to set play range
941 SetPlayRangeMessage( mEventThreadServices, *mAnimation, orderedRange );
945 Vector2 Animation::GetPlayRange() const
951 } // namespace Internal