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/animation/path-impl.h>
34 #include <dali/internal/event/common/notification-manager.h>
35 #include <dali/internal/event/common/property-helper.h>
36 #include <dali/internal/event/common/stage-impl.h>
37 #include <dali/internal/event/common/thread-local-storage.h>
38 #include <dali/internal/update/animation/scene-graph-animator.h>
39 #include <dali/internal/update/manager/update-manager.h>
41 using Dali::Internal::SceneGraph::UpdateManager;
42 using Dali::Internal::SceneGraph::AnimatorBase;
43 using Dali::Internal::SceneGraph::Shader;
51 static bool SHOW_VALUE = true;
52 static bool HIDE_VALUE = false;
59 const char* const SIGNAL_FINISHED = "finished";
63 const char* const ACTION_PLAY = "play";
64 const char* const ACTION_STOP = "stop";
65 const char* const ACTION_PAUSE = "pause";
69 return Dali::Animation::New(0.f);
72 TypeRegistration mType( typeid( Dali::Animation ), typeid( Dali::BaseHandle ), Create );
74 SignalConnectorType signalConnector1( mType, SIGNAL_FINISHED, &Animation::DoConnectSignal );
76 TypeAction action1( mType, ACTION_PLAY, &Animation::DoAction );
77 TypeAction action2( mType, ACTION_STOP, &Animation::DoAction );
78 TypeAction action3( mType, ACTION_PAUSE, &Animation::DoAction );
80 const Dali::Animation::EndAction DEFAULT_END_ACTION( Dali::Animation::Bake );
81 const Dali::Animation::EndAction DEFAULT_DISCONNECT_ACTION( Dali::Animation::BakeFinal );
82 const Dali::Animation::Interpolation DEFAULT_INTERPOLATION( Dali::Animation::Linear );
83 const Dali::AlphaFunction DEFAULT_ALPHA_FUNCTION( Dali::AlphaFunction::DEFAULT );
88 AnimationPtr Animation::New(float durationSeconds)
90 Stage* stage = Stage::GetCurrent();
94 AnimationPlaylist& playlist = stage->GetAnimationPlaylist();
96 if( durationSeconds < 0.0f )
98 DALI_LOG_WARNING("duration should be greater than 0.0f.\n");
99 durationSeconds = 0.0f;
102 AnimationPtr animation = new Animation( *stage, playlist, durationSeconds, DEFAULT_END_ACTION, DEFAULT_DISCONNECT_ACTION, DEFAULT_ALPHA_FUNCTION );
104 // Second-phase construction
105 animation->Initialize();
115 Animation::Animation( EventThreadServices& eventThreadServices, AnimationPlaylist& playlist, float durationSeconds, EndAction endAction, EndAction disconnectAction, AlphaFunction defaultAlpha )
116 : mAnimation( NULL ),
117 mEventThreadServices( eventThreadServices ),
118 mPlaylist( playlist ),
121 mConnectorTargetValues(),
122 mPlayRange( Vector2(0.0f,1.0f)),
123 mDurationSeconds( durationSeconds ),
125 mNotificationCount( 0 ),
128 mEndAction( endAction ),
129 mDisconnectAction( disconnectAction ),
130 mDefaultAlpha( defaultAlpha ),
131 mState(Dali::Animation::STOPPED)
135 void Animation::Initialize()
137 // Connect to the animation playlist
138 mPlaylist.AnimationCreated( *this );
145 Animation::~Animation()
147 // Guard to allow handle destruction after Core has been destroyed
148 if ( Stage::IsInstalled() )
150 // Disconnect from the animation playlist
151 mPlaylist.AnimationDestroyed( *this );
153 DestroySceneObject();
159 void Animation::CreateSceneObject()
161 DALI_ASSERT_DEBUG( mAnimation == NULL );
163 // Create a new animation, Keep a const pointer to the animation.
164 mAnimation = SceneGraph::Animation::New( mDurationSeconds, mSpeedFactor, mPlayRange, mLoopCount, mEndAction, mDisconnectAction );
165 OwnerPointer< SceneGraph::Animation > transferOwnership( const_cast< SceneGraph::Animation* >( mAnimation ) );
166 AddAnimationMessage( mEventThreadServices.GetUpdateManager(), transferOwnership );
169 void Animation::DestroySceneObject()
171 if ( mAnimation != NULL )
173 // Remove animation using a message to the update manager
174 RemoveAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
179 void Animation::SetDuration(float seconds)
183 DALI_LOG_WARNING("duration should be greater than 0.0f.\n");
187 // Cache for public getters
188 mDurationSeconds = seconds;
190 // mAnimation is being used in a separate thread; queue a message to set the value
191 SetDurationMessage( mEventThreadServices, *mAnimation, seconds );
194 float Animation::GetDuration() const
196 // This is not animatable; the cached value is up-to-date.
197 return mDurationSeconds;
200 void Animation::SetLooping(bool on)
202 SetLoopCount( on ? 0 : 1 );
205 void Animation::SetLoopCount(int count)
207 // Cache for public getters
210 // mAnimation is being used in a separate thread; queue a message to set the value
211 SetLoopingMessage( mEventThreadServices, *mAnimation, mLoopCount );
214 int Animation::GetLoopCount()
219 int Animation::GetCurrentLoop()
224 bool Animation::IsLooping() const
226 return mLoopCount != 1;
229 void Animation::SetEndAction(EndAction action)
231 // Cache for public getters
234 // mAnimation is being used in a separate thread; queue a message to set the value
235 SetEndActionMessage( mEventThreadServices, *mAnimation, action );
238 Dali::Animation::EndAction Animation::GetEndAction() const
240 // This is not animatable; the cached value is up-to-date.
244 void Animation::SetDisconnectAction(EndAction action)
246 // Cache for public getters
247 mDisconnectAction = action;
249 // mAnimation is being used in a separate thread; queue a message to set the value
250 SetDisconnectActionMessage( mEventThreadServices, *mAnimation, action );
253 Dali::Animation::EndAction Animation::GetDisconnectAction() const
255 // This is not animatable; the cached value is up-to-date.
256 return mDisconnectAction;
259 void Animation::Play()
261 // Update the current playlist
262 mPlaylist.OnPlay( *this );
264 mState = Dali::Animation::PLAYING;
268 // mAnimation is being used in a separate thread; queue a Play message
269 PlayAnimationMessage( mEventThreadServices, *mAnimation );
272 void Animation::PlayFrom( float progress )
274 if( progress >= mPlayRange.x && progress <= mPlayRange.y )
276 // Update the current playlist
277 mPlaylist.OnPlay( *this );
279 mState = Dali::Animation::PLAYING;
283 // mAnimation is being used in a separate thread; queue a Play message
284 PlayAnimationFromMessage( mEventThreadServices, *mAnimation, progress );
288 void Animation::Pause()
290 mState = Dali::Animation::PAUSED;
292 // mAnimation is being used in a separate thread; queue a Pause message
293 PauseAnimationMessage( mEventThreadServices, *mAnimation );
296 Dali::Animation::State Animation::GetState() const
301 void Animation::Stop()
303 mState = Dali::Animation::STOPPED;
305 // mAnimation is being used in a separate thread; queue a Stop message
306 StopAnimationMessage( mEventThreadServices.GetUpdateManager(), *mAnimation );
309 void Animation::Clear()
311 DALI_ASSERT_DEBUG(mAnimation);
313 // Remove all the connectors
316 // Reset the connector target values
317 mConnectorTargetValues.clear();
319 // Replace the old scene-object with a new one
320 DestroySceneObject();
323 // Reset the notification count, since the new scene-object has never been played
324 mNotificationCount = 0;
326 // Update the current playlist
327 mPlaylist.OnClear( *this );
330 void Animation::AnimateBy(Property& target, Property::Value& relativeValue)
332 AnimateBy(target, relativeValue, mDefaultAlpha, TimePeriod(mDurationSeconds));
335 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha)
337 AnimateBy(target, relativeValue, alpha, TimePeriod(mDurationSeconds));
340 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, TimePeriod period)
342 AnimateBy(target, relativeValue, mDefaultAlpha, period);
345 void Animation::AnimateBy(Property& target, Property::Value& relativeValue, AlphaFunction alpha, TimePeriod period)
347 Object& object = GetImplementation(target.object);
348 const Property::Type targetType = object.GetPropertyType(target.propertyIndex);
349 const Property::Type destinationType = relativeValue.GetType();
351 if ( object.GetPropertyComponentIndex( target.propertyIndex ) != Property::INVALID_COMPONENT_INDEX )
353 DALI_ASSERT_ALWAYS(Property::FLOAT == destinationType && "Animated value and Property type don't match");
357 DALI_ASSERT_ALWAYS(targetType == destinationType && "Animated value and Property type don't match");
360 ExtendDuration(period);
362 // Store data to later notify the object that its property is being animated
363 ConnectorTargetValues connectorPair;
364 connectorPair.targetValue = relativeValue;
365 connectorPair.connectorIndex = mConnectors.Count();
366 connectorPair.timePeriod = period;
367 connectorPair.animatorType = Animation::BY;
368 mConnectorTargetValues.push_back( connectorPair );
370 switch ( targetType )
372 case Property::BOOLEAN:
374 AddAnimatorConnector( AnimatorConnector<bool>::New( object,
375 target.propertyIndex,
376 target.componentIndex,
377 new AnimateByBoolean(relativeValue.Get<bool>()),
383 case Property::INTEGER:
385 AddAnimatorConnector( AnimatorConnector<int>::New( object,
386 target.propertyIndex,
387 target.componentIndex,
388 new AnimateByInteger(relativeValue.Get<int>()),
394 case Property::FLOAT:
396 AddAnimatorConnector( AnimatorConnector<float>::New( object,
397 target.propertyIndex,
398 target.componentIndex,
399 new AnimateByFloat(relativeValue.Get<float>()),
405 case Property::VECTOR2:
407 AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
408 target.propertyIndex,
409 target.componentIndex,
410 new AnimateByVector2(relativeValue.Get<Vector2>()),
416 case Property::VECTOR3:
418 AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
419 target.propertyIndex,
420 target.componentIndex,
421 new AnimateByVector3(relativeValue.Get<Vector3>()),
427 case Property::VECTOR4:
429 AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
430 target.propertyIndex,
431 target.componentIndex,
432 new AnimateByVector4(relativeValue.Get<Vector4>()),
438 case Property::ROTATION:
440 AngleAxis angleAxis = relativeValue.Get<AngleAxis>();
442 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
443 target.propertyIndex,
444 target.componentIndex,
445 new RotateByAngleAxis(angleAxis.angle, angleAxis.axis),
453 // non animatable types handled already
458 void Animation::AnimateTo(Property& target, Property::Value& destinationValue)
460 AnimateTo(target, destinationValue, mDefaultAlpha, TimePeriod(mDurationSeconds));
463 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha)
465 AnimateTo(target, destinationValue, alpha, TimePeriod(mDurationSeconds));
468 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, TimePeriod period)
470 AnimateTo(target, destinationValue, mDefaultAlpha, period);
473 void Animation::AnimateTo(Property& target, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
475 Object& object = GetImplementation(target.object);
477 AnimateTo( object, target.propertyIndex, target.componentIndex, destinationValue, alpha, period );
480 void Animation::AnimateTo(Object& targetObject, Property::Index targetPropertyIndex, int componentIndex, Property::Value& destinationValue, AlphaFunction alpha, TimePeriod period)
482 Property::Type targetType = targetObject.GetPropertyType(targetPropertyIndex);
483 if( componentIndex != Property::INVALID_COMPONENT_INDEX )
485 if( ( targetType == Property::VECTOR2 ) ||
486 ( targetType == Property::VECTOR3 ) ||
487 ( targetType == Property::VECTOR4 ) )
489 targetType = Property::FLOAT;
492 const Property::Type destinationType = destinationValue.GetType();
493 DALI_ASSERT_ALWAYS( targetType == destinationType && "Animated value and Property type don't match" );
495 ExtendDuration( period );
497 // Store data to later notify the object that its property is being animated
498 ConnectorTargetValues connectorPair;
499 connectorPair.targetValue = destinationValue;
500 connectorPair.connectorIndex = mConnectors.Count();
501 connectorPair.timePeriod = period;
502 connectorPair.animatorType = Animation::TO;
503 mConnectorTargetValues.push_back( connectorPair );
505 switch ( destinationType )
507 case Property::BOOLEAN:
509 AddAnimatorConnector( AnimatorConnector<bool>::New( targetObject,
512 new AnimateToBoolean( destinationValue.Get<bool>() ),
518 case Property::INTEGER:
520 AddAnimatorConnector( AnimatorConnector<int>::New( targetObject,
523 new AnimateToInteger( destinationValue.Get<int>() ),
529 case Property::FLOAT:
531 AddAnimatorConnector( AnimatorConnector<float>::New( targetObject,
534 new AnimateToFloat( destinationValue.Get<float>() ),
540 case Property::VECTOR2:
542 AddAnimatorConnector( AnimatorConnector<Vector2>::New( targetObject,
545 new AnimateToVector2( destinationValue.Get<Vector2>() ),
551 case Property::VECTOR3:
553 AddAnimatorConnector( AnimatorConnector<Vector3>::New( targetObject,
556 new AnimateToVector3( destinationValue.Get<Vector3>() ),
562 case Property::VECTOR4:
564 AddAnimatorConnector( AnimatorConnector<Vector4>::New( targetObject,
567 new AnimateToVector4( destinationValue.Get<Vector4>() ),
573 case Property::ROTATION:
575 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( targetObject,
578 new RotateToQuaternion( destinationValue.Get<Quaternion>() ),
586 // non animatable types handled already
591 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames)
593 AnimateBetween(target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION );
596 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, Interpolation interpolation )
598 AnimateBetween(target, keyFrames, mDefaultAlpha, TimePeriod(mDurationSeconds), interpolation );
601 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period)
603 AnimateBetween(target, keyFrames, mDefaultAlpha, period, DEFAULT_INTERPOLATION);
606 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, TimePeriod period, Interpolation interpolation)
608 AnimateBetween(target, keyFrames, mDefaultAlpha, period, interpolation);
611 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha)
613 AnimateBetween(target, keyFrames, alpha, TimePeriod(mDurationSeconds), DEFAULT_INTERPOLATION);
616 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, Interpolation interpolation)
618 AnimateBetween(target, keyFrames, alpha, TimePeriod(mDurationSeconds), interpolation);
621 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period)
623 AnimateBetween(target, keyFrames, alpha, period, DEFAULT_INTERPOLATION);
626 void Animation::AnimateBetween(Property target, const KeyFrames& keyFrames, AlphaFunction alpha, TimePeriod period, Interpolation interpolation)
628 Object& object = GetImplementation( target.object );
630 ExtendDuration( period );
632 // Store data to later notify the object that its property is being animated
633 ConnectorTargetValues connectorPair;
634 connectorPair.targetValue = keyFrames.GetLastKeyFrameValue();
635 connectorPair.connectorIndex = mConnectors.Count();
636 connectorPair.timePeriod = period;
637 connectorPair.animatorType = BETWEEN;
638 mConnectorTargetValues.push_back( connectorPair );
640 switch(keyFrames.GetType())
642 case Dali::Property::BOOLEAN:
644 const KeyFrameBoolean* kf;
645 GetSpecialization(keyFrames, kf);
646 KeyFrameBooleanPtr kfCopy = KeyFrameBoolean::Clone(*kf);
647 AddAnimatorConnector( AnimatorConnector<bool>::New( object,
648 target.propertyIndex,
649 target.componentIndex,
650 new KeyFrameBooleanFunctor(kfCopy),
656 case Dali::Property::INTEGER:
658 const KeyFrameInteger* kf;
659 GetSpecialization(keyFrames, kf);
660 KeyFrameIntegerPtr kfCopy = KeyFrameInteger::Clone(*kf);
661 AddAnimatorConnector( AnimatorConnector<int>::New( object,
662 target.propertyIndex,
663 target.componentIndex,
664 new KeyFrameIntegerFunctor(kfCopy,interpolation),
670 case Dali::Property::FLOAT:
672 const KeyFrameNumber* kf;
673 GetSpecialization(keyFrames, kf);
674 KeyFrameNumberPtr kfCopy = KeyFrameNumber::Clone(*kf);
675 AddAnimatorConnector( AnimatorConnector<float>::New( object,
676 target.propertyIndex,
677 target.componentIndex,
678 new KeyFrameNumberFunctor(kfCopy,interpolation),
684 case Dali::Property::VECTOR2:
686 const KeyFrameVector2* kf;
687 GetSpecialization(keyFrames, kf);
688 KeyFrameVector2Ptr kfCopy = KeyFrameVector2::Clone(*kf);
689 AddAnimatorConnector( AnimatorConnector<Vector2>::New( object,
690 target.propertyIndex,
691 target.componentIndex,
692 new KeyFrameVector2Functor(kfCopy,interpolation),
698 case Dali::Property::VECTOR3:
700 const KeyFrameVector3* kf;
701 GetSpecialization(keyFrames, kf);
702 KeyFrameVector3Ptr kfCopy = KeyFrameVector3::Clone(*kf);
703 AddAnimatorConnector( AnimatorConnector<Vector3>::New( object,
704 target.propertyIndex,
705 target.componentIndex,
706 new KeyFrameVector3Functor(kfCopy,interpolation),
712 case Dali::Property::VECTOR4:
714 const KeyFrameVector4* kf;
715 GetSpecialization(keyFrames, kf);
716 KeyFrameVector4Ptr kfCopy = KeyFrameVector4::Clone(*kf);
717 AddAnimatorConnector( AnimatorConnector<Vector4>::New( object,
718 target.propertyIndex,
719 target.componentIndex,
720 new KeyFrameVector4Functor(kfCopy,interpolation),
726 case Dali::Property::ROTATION:
728 const KeyFrameQuaternion* kf;
729 GetSpecialization(keyFrames, kf);
730 KeyFrameQuaternionPtr kfCopy = KeyFrameQuaternion::Clone(*kf);
731 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( object,
732 target.propertyIndex,
733 target.componentIndex,
734 new KeyFrameQuaternionFunctor(kfCopy),
742 // non animatable types handled by keyframes
747 bool Animation::HasFinished()
749 bool hasFinished(false);
750 const int playedCount(mAnimation->GetPlayedCount());
752 // If the play count has been incremented, then another notification is required
753 mCurrentLoop = mAnimation->GetCurrentLoop();
755 if (playedCount > mNotificationCount)
757 // Note that only one signal is emitted, if the animation has been played repeatedly
758 mNotificationCount = playedCount;
762 mState = Dali::Animation::STOPPED;
768 Dali::Animation::AnimationSignalType& Animation::FinishedSignal()
770 return mFinishedSignal;
773 void Animation::EmitSignalFinish()
775 if ( !mFinishedSignal.Empty() )
777 Dali::Animation handle( this );
778 mFinishedSignal.Emit( handle );
782 bool Animation::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
784 bool connected( true );
785 Animation* animation = static_cast< Animation* >(object); // TypeRegistry guarantees that this is the correct type.
787 if( 0 == signalName.compare( SIGNAL_FINISHED ) )
789 animation->FinishedSignal().Connect( tracker, functor );
793 // signalName does not match any signal
800 void Animation::AddAnimatorConnector( AnimatorConnectorBase* connector )
802 DALI_ASSERT_DEBUG( NULL != connector );
804 connector->SetParent(*this);
806 mConnectors.PushBack( connector );
809 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward )
811 Animate( actor, path, forward, mDefaultAlpha, TimePeriod(mDurationSeconds) );
814 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha )
816 Animate( actor, path, forward, alpha, TimePeriod(mDurationSeconds) );
819 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, TimePeriod period )
821 Animate( actor, path, forward, mDefaultAlpha, period );
824 void Animation::Animate( Actor& actor, const Path& path, const Vector3& forward, AlphaFunction alpha, TimePeriod period)
826 ExtendDuration( period );
828 PathPtr pathCopy = Path::Clone(path);
831 AddAnimatorConnector( AnimatorConnector<Vector3>::New( actor,
832 Dali::Actor::Property::POSITION,
833 Property::INVALID_COMPONENT_INDEX,
834 new PathPositionFunctor( pathCopy ),
838 //If forward is zero, PathRotationFunctor will always return the unit quaternion
839 if( forward != Vector3::ZERO )
842 AddAnimatorConnector( AnimatorConnector<Quaternion>::New( actor,
843 Dali::Actor::Property::ORIENTATION,
844 Property::INVALID_COMPONENT_INDEX,
845 new PathRotationFunctor( pathCopy, forward ),
851 void Animation::Show(Actor& actor, float delaySeconds)
853 ExtendDuration( TimePeriod(delaySeconds, 0) );
855 AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
856 Dali::Actor::Property::VISIBLE,
857 Property::INVALID_COMPONENT_INDEX,
858 new AnimateToBoolean(SHOW_VALUE),
860 TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
863 void Animation::Hide(Actor& actor, float delaySeconds)
865 ExtendDuration( TimePeriod(delaySeconds, 0) );
867 AddAnimatorConnector( AnimatorConnector<bool>::New( actor,
868 Dali::Actor::Property::VISIBLE,
869 Property::INVALID_COMPONENT_INDEX,
870 new AnimateToBoolean(HIDE_VALUE),
872 TimePeriod(delaySeconds, 0.0f/*immediate*/) ) );
875 bool Animation::DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes )
878 Animation* animation = dynamic_cast<Animation*>( object );
882 if( 0 == actionName.compare( ACTION_PLAY ) )
884 if( Property::Value* value = attributes.Find("duration", Property::FLOAT) )
886 animation->SetDuration( value->Get<float>() );
892 else if( 0 == actionName.compare( ACTION_STOP ) )
897 else if( 0 == actionName.compare( ACTION_PAUSE ) )
907 void Animation::SetCurrentProgress(float progress)
909 if( mAnimation && progress >= mPlayRange.x && progress <= mPlayRange.y )
911 // mAnimation is being used in a separate thread; queue a message to set the current progress
912 SetCurrentProgressMessage( mEventThreadServices, *mAnimation, progress );
916 float Animation::GetCurrentProgress()
920 return mAnimation->GetCurrentProgress();
926 void Animation::ExtendDuration( const TimePeriod& timePeriod )
928 float duration = timePeriod.delaySeconds + timePeriod.durationSeconds;
930 if( duration > mDurationSeconds )
932 SetDuration( duration );
936 void Animation::SetSpeedFactor( float factor )
940 mSpeedFactor = factor;
941 SetSpeedFactorMessage( mEventThreadServices, *mAnimation, factor );
945 float Animation::GetSpeedFactor() const
950 void Animation::SetPlayRange( const Vector2& range)
952 //Make sure the range specified is between 0.0 and 1.0
953 if( range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f )
955 Vector2 orderedRange( range );
956 //If the range is not in order swap values
957 if( range.x > range.y )
959 orderedRange = Vector2(range.y, range.x);
962 // Cache for public getters
963 mPlayRange = orderedRange;
965 // mAnimation is being used in a separate thread; queue a message to set play range
966 SetPlayRangeMessage( mEventThreadServices, *mAnimation, orderedRange );
970 Vector2 Animation::GetPlayRange() const
975 bool Animation::CompareConnectorEndTimes( const Animation::ConnectorTargetValues& lhs, const Animation::ConnectorTargetValues& rhs )
977 return ( ( lhs.timePeriod.delaySeconds + lhs.timePeriod.durationSeconds ) < ( rhs.timePeriod.delaySeconds + rhs.timePeriod.durationSeconds ) );
980 void Animation::NotifyObjects()
982 if( mEndAction != EndAction::Discard ) // If the animation is discarded, then we do not want to change the target values
984 // Sort according to end time with earlier end times coming first, if the end time is the same, then the connectors are not moved
985 std::stable_sort( mConnectorTargetValues.begin(), mConnectorTargetValues.end(), CompareConnectorEndTimes );
987 // Loop through all connector target values sorted by increasing end time
988 ConnectorTargetValuesContainer::const_iterator iter = mConnectorTargetValues.begin();
989 const ConnectorTargetValuesContainer::const_iterator endIter = mConnectorTargetValues.end();
990 for( ; iter != endIter; ++iter )
992 AnimatorConnectorBase* connector = mConnectors[ iter->connectorIndex ];
994 Object* object = connector->GetObject();
997 object->NotifyPropertyAnimation( *this, connector->GetPropertyIndex(), iter->targetValue, iter->animatorType );
1003 } // namespace Internal