#include <dali/public-api/dali-core.h>
#include <dali/devel-api/actors/actor-devel.h>
#include <dali-test-suite-utils.h>
+#include <dali/devel-api/animation/animation-devel.h>
using std::max;
using namespace Dali;
bool& mSignalReceived; // owned by individual tests
};
+// Functor to test whether a Progress signal is emitted
+struct AnimationProgressCheck
+{
+ AnimationProgressCheck(bool& signalReceived, std::string name = " ")
+ : mSignalReceived(signalReceived),
+ mName( name )
+ {
+ }
+
+ void operator()(Animation& animation)
+ {
+ mSignalReceived = true;
+ }
+
+ void Reset()
+ {
+ mSignalReceived = false;
+ }
+
+ void CheckSignalReceived()
+ {
+ if (!mSignalReceived)
+ {
+ tet_printf("Expected Progress reached signal was not received %s \n", mName.c_str() );
+ tet_result(TET_FAIL);
+ }
+ else
+ {
+ tet_result(TET_PASS);
+ }
+ }
+
+ void CheckSignalNotReceived()
+ {
+ if (mSignalReceived)
+ {
+ tet_printf("Unexpected Progress reached signal was received %s \n", mName.c_str());
+ tet_result(TET_FAIL);
+ }
+ else
+ {
+ tet_result(TET_PASS);
+ }
+ }
+
+ bool& mSignalReceived; // owned by individual tests
+ std::string mName;
+};
+
} // anon namespace
int UtcDaliAnimationConstructorP(void)
END_TEST;
}
+
+int UtcDaliAnimationProgressCallbackP(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ Stage::GetCurrent().Add(actor);
+
+ // Build the animation
+ Animation animation = Animation::New(0.0f);
+
+ //Set duration
+ float durationSeconds(1.0f);
+ animation.SetDuration(durationSeconds);
+
+ bool finishedSignalReceived(false);
+ bool progressSignalReceived(false);
+
+ AnimationFinishCheck finishCheck(finishedSignalReceived);
+ animation.FinishedSignal().Connect(&application, finishCheck);
+
+ AnimationProgressCheck progressCheck(progressSignalReceived);
+ DevelAnimation::ProgressReachedSignal( animation ).Connect( &application, progressCheck);
+ application.SendNotification();
+
+ Vector3 targetPosition(100.0f, 100.0f, 100.0f);
+ animation.AnimateTo(Property(actor, Actor::Property::POSITION), targetPosition, AlphaFunction::LINEAR);
+
+ tet_infoline( "Animation Progress notification set to 30%" );
+ DevelAnimation::SetProgressNotification( animation, 0.3f );
+
+ application.SendNotification();
+ application.Render( );
+
+ DALI_TEST_EQUALS( 0.3f, DevelAnimation::GetProgressNotification( animation ), TEST_LOCATION );
+
+ progressCheck.CheckSignalNotReceived();
+
+ // Start the animation from 10% progress
+ animation.SetCurrentProgress( 0.1f );
+ animation.Play();
+
+ tet_infoline( "Animation Playing from 10%" );
+
+ application.SendNotification();
+ application.Render(0); // start animation
+ application.Render(durationSeconds*100.0f ); // 20% progress
+
+ tet_infoline( "Animation at 20%" );
+
+ progressCheck.CheckSignalNotReceived();
+
+ application.SendNotification();
+ application.Render(durationSeconds*200.0f ); // 40% progress
+ application.SendNotification();
+ tet_infoline( "Animation at 40%" );
+ DALI_TEST_EQUALS( 0.4f, animation.GetCurrentProgress(), TEST_LOCATION );
+
+ progressCheck.CheckSignalReceived();
+
+ tet_infoline( "Progress check reset" );
+ progressCheck.Reset();
+
+ application.Render(durationSeconds*100.0f ); // 50% progress
+ tet_infoline( "Animation at 50%" );
+ application.SendNotification();
+
+ DALI_TEST_EQUALS( 0.5f, animation.GetCurrentProgress(), TEST_LOCATION );
+
+ progressCheck.CheckSignalNotReceived();
+
+ application.Render(static_cast<unsigned int>(durationSeconds*100.0f)/* 60% progress */);
+ application.SendNotification();
+
+ tet_infoline( "Animation at 60%" );
+
+ finishCheck.CheckSignalNotReceived();
+
+ application.Render(static_cast<unsigned int>(durationSeconds*200.0f)/* 80% progress */);
+ application.SendNotification();
+ DALI_TEST_EQUALS( 0.8f, animation.GetCurrentProgress(), TEST_LOCATION );
+ tet_infoline( "Animation at 80%" );
+
+ application.Render(static_cast<unsigned int>(durationSeconds*200.0f) + 1u/*just beyond the animation duration*/);
+ // We did expect the animation to finish
+ application.SendNotification();
+ finishCheck.CheckSignalReceived();
+ tet_infoline( "Animation finished" );
+ DALI_TEST_EQUALS( actor.GetCurrentPosition(), targetPosition, TEST_LOCATION );
+
+ END_TEST;
+}
+
+int UtcDaliAnimationProgressSignalConnectionWithoutProgressMarkerP(void)
+{
+ TestApplication application;
+
+ tet_infoline( "Connect to ProgressReachedSignal but do not set a required Progress marker" );
+
+ Actor actor = Actor::New();
+ Stage::GetCurrent().Add(actor);
+
+ // Build the animation
+ Animation animation = Animation::New(0.0f);
+
+ //Set duration
+ float durationSeconds(1.0f);
+ animation.SetDuration(durationSeconds);
+
+ bool finishedSignalReceived(false);
+ bool progressSignalReceived(false);
+
+ AnimationFinishCheck finishCheck(finishedSignalReceived);
+ animation.FinishedSignal().Connect(&application, finishCheck);
+
+ AnimationProgressCheck progressCheck( progressSignalReceived );
+ DevelAnimation::ProgressReachedSignal( animation ).Connect( &application, progressCheck);
+ application.SendNotification();
+
+ Vector3 targetPosition(100.0f, 100.0f, 100.0f);
+ animation.AnimateTo(Property(actor, Actor::Property::POSITION), targetPosition, AlphaFunction::LINEAR);
+
+ progressCheck.CheckSignalNotReceived();
+
+ animation.Play();
+
+ application.SendNotification();
+ application.Render(0); // start animation
+ application.Render(durationSeconds*100.0f ); // 10% progress
+ application.SendNotification();
+
+ tet_infoline( "Ensure after animation has started playing that ProgressReachedSignal not emitted" );
+ progressCheck.CheckSignalNotReceived();
+
+ application.Render(static_cast<unsigned int>(durationSeconds*900.0f) + 1u/*just beyond the animation duration*/);
+
+ application.SendNotification();
+ finishCheck.CheckSignalReceived();
+ tet_infoline( "Animation finished" );
+ DALI_TEST_EQUALS( actor.GetCurrentPosition(), targetPosition, TEST_LOCATION );
+
+ END_TEST;
+}
+
+int UtcDaliAnimationMultipleProgressSignalsP(void)
+{
+ tet_infoline( "Multiple animations with different progress markers" );
+
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ Stage::GetCurrent().Add(actor);
+
+ // Build the animation
+ Animation animationAlpha = Animation::New(0.0f);
+ Animation animationBeta = Animation::New(0.0f);
+
+ //Set duration
+ float durationSeconds(1.0f);
+ animationAlpha.SetDuration(durationSeconds);
+ animationBeta.SetDuration(durationSeconds);
+
+ bool progressSignalReceivedAlpha(false);
+ bool progressSignalReceivedBeta(false);
+
+ AnimationProgressCheck progressCheckAlpha(progressSignalReceivedAlpha, "animation:Alpha");
+ AnimationProgressCheck progressCheckBeta(progressSignalReceivedBeta, "animation:Beta" );
+
+ DevelAnimation::ProgressReachedSignal( animationAlpha ).Connect( &application, progressCheckAlpha );
+ DevelAnimation::ProgressReachedSignal( animationBeta ).Connect( &application, progressCheckBeta);
+ application.SendNotification();
+
+ Vector3 targetPosition(100.0f, 100.0f, 100.0f);
+ animationAlpha.AnimateTo(Property(actor, Actor::Property::POSITION), targetPosition, AlphaFunction::LINEAR);
+ animationBeta.AnimateTo(Property(actor, Actor::Property::POSITION), targetPosition, AlphaFunction::LINEAR);
+
+ tet_infoline( "AnimationAlpha Progress notification set to 30%" );
+ DevelAnimation::SetProgressNotification( animationAlpha, 0.3f );
+
+ tet_infoline( "AnimationBeta Progress notification set to 50%" );
+ DevelAnimation::SetProgressNotification( animationBeta, 0.5f );
+
+ application.SendNotification();
+ application.Render( );
+
+ progressCheckAlpha.CheckSignalNotReceived();
+ progressCheckBeta.CheckSignalNotReceived();
+
+ // Start the animations from 10% progress
+ animationAlpha.SetCurrentProgress( 0.1f );
+ animationBeta.SetCurrentProgress( 0.1f );
+ animationAlpha.Play();
+ animationBeta.Play();
+
+ tet_infoline( "Animation Playing from 10%" );
+
+ application.SendNotification();
+ application.Render(0); // start animation
+ application.Render(durationSeconds*100.0f ); // 20% progress
+
+ tet_infoline( "Animation at 20% - No signals to be received" );
+
+ progressCheckAlpha.CheckSignalNotReceived();
+ progressCheckBeta.CheckSignalNotReceived();
+
+ application.SendNotification();
+ application.Render(durationSeconds*200.0f ); // 40% progress
+ application.SendNotification();
+ tet_infoline( "Animation at 40% - Alpha signal should be received" );
+ DALI_TEST_EQUALS( 0.4f, animationAlpha.GetCurrentProgress(), TEST_LOCATION );
+
+ progressCheckAlpha.CheckSignalReceived();
+ progressCheckBeta.CheckSignalNotReceived();
+
+ tet_infoline( "Progress check reset" );
+ progressCheckAlpha.Reset();
+ progressCheckBeta.Reset();
+
+ application.Render(durationSeconds*100.0f ); // 50% progress
+ tet_infoline( "Animation at 50% - Beta should receive signal, Alpha should not" );
+ application.SendNotification();
+
+ DALI_TEST_EQUALS( 0.5f, animationBeta.GetCurrentProgress(), TEST_LOCATION );
+
+ progressCheckAlpha.CheckSignalNotReceived();
+ progressCheckBeta.CheckSignalReceived();
+ tet_infoline( "Progress check reset" );
+ progressCheckAlpha.Reset();
+ progressCheckBeta.Reset();
+
+ application.Render(static_cast<unsigned int>(durationSeconds*100.0f)/* 60% progress */);
+ application.SendNotification();
+
+ tet_infoline( "Animation at 60%" );
+
+ progressCheckAlpha.CheckSignalNotReceived();
+ progressCheckBeta.CheckSignalNotReceived();
+
+ application.Render(static_cast<unsigned int>(durationSeconds*200.0f)/* 80% progress */);
+ application.SendNotification();
+ tet_infoline( "Animation at 80%" );
+
+ progressCheckAlpha.CheckSignalNotReceived();
+ progressCheckBeta.CheckSignalNotReceived();
+
+ application.Render(static_cast<unsigned int>(durationSeconds*200.0f) + 1u/*just beyond the animation duration*/);
+ // We did expect the animation to finish
+ tet_infoline( "Animation finished" );
+
+ END_TEST;
+}
+
+
+int UtcDaliAnimationProgressCallbackLongDurationP(void)
+{
+ TestApplication application;
+
+ Actor actor = Actor::New();
+ Stage::GetCurrent().Add(actor);
+
+ // Build the animation
+ Animation animation = Animation::New(0.0f);
+
+ //Set duration
+ float durationSeconds(5.0f);
+ animation.SetDuration(durationSeconds);
+
+ bool finishedSignalReceived(false);
+ bool progressSignalReceived(false);
+
+ AnimationFinishCheck finishCheck(finishedSignalReceived);
+ animation.FinishedSignal().Connect(&application, finishCheck);
+
+ AnimationProgressCheck progressCheck(progressSignalReceived);
+ DevelAnimation::ProgressReachedSignal( animation ).Connect( &application, progressCheck);
+ application.SendNotification();
+
+ Vector3 targetPosition(100.0f, 100.0f, 100.0f);
+ animation.AnimateTo(Property(actor, Actor::Property::POSITION), targetPosition, AlphaFunction::LINEAR);
+
+ tet_infoline( "Animation Progress notification set to 50%" );
+ DevelAnimation::SetProgressNotification( animation, 0.5f );
+
+ application.SendNotification();
+ application.Render( );
+
+ progressCheck.CheckSignalNotReceived();
+
+ animation.Play();
+
+ application.SendNotification();
+ application.Render(0); // start animation
+ application.Render(durationSeconds*0.25*1000.0f ); // 25% progress
+ DALI_TEST_EQUALS( 0.25f, animation.GetCurrentProgress(), TEST_LOCATION );
+
+ tet_infoline( "Animation at 25%" );
+
+ progressCheck.CheckSignalNotReceived();
+
+ application.SendNotification();
+ application.Render(durationSeconds*0.25*1000.0f ); // 50% progress
+ application.SendNotification();
+ tet_infoline( "Animation at 50%" );
+ DALI_TEST_EQUALS( 0.5f, animation.GetCurrentProgress(), TEST_LOCATION );
+
+ progressCheck.CheckSignalReceived();
+
+ tet_infoline( "Progress check reset" );
+ progressCheck.Reset();
+
+ application.Render(durationSeconds*0.25*1000.0f ); // 75% progress
+ tet_infoline( "Animation at 75%" );
+ application.SendNotification();
+
+ DALI_TEST_EQUALS( 0.75f, animation.GetCurrentProgress(), TEST_LOCATION );
+
+ progressCheck.CheckSignalNotReceived();
+
+ END_TEST;
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/animation/animation-devel.h>
+#include <dali/internal/event/animation/animation-impl.h>
+
+namespace Dali
+{
+
+namespace DevelAnimation
+{
+
+void SetProgressNotification( Animation animation, float progress )
+{
+ GetImplementation(animation).SetProgressNotification( progress );
+}
+
+float GetProgressNotification( Animation animation )
+{
+ return GetImplementation(animation).GetProgressNotification();
+}
+
+Animation::AnimationSignalType& ProgressReachedSignal( Animation animation )
+{
+ return GetImplementation( animation ).ProgressReachedSignal();
+}
+
+} // namespace DevelAnimation
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_ANIMATION_DEVEL_H
+#define DALI_ANIMATION_DEVEL_H
+
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/animation/animation.h>
+
+namespace Dali
+{
+
+namespace DevelAnimation
+{
+
+/**
+ * @brief Set progress percentage marker to trigger ProgressHasBeenReachedSignal
+ *
+ * @param[in] animation the animation object to perform this operation on
+ * @param[in] progress the progress percentage to trigger the signal at, e.g .3 for 30%.
+ */
+DALI_IMPORT_API void SetProgressNotification( Animation animation, float progress );
+
+/**
+ * @brief Get progress percentage marker that has been set to trigger ProgressHasBeenReachedSignal
+ *
+ * @param[in] animation the animation object to perform this operation on
+ * @return the percentage to trigger at eg 0.3 for 30%
+ */
+DALI_IMPORT_API float GetProgressNotification( Animation animation );
+
+/**
+ * @brief Connects to this signal to be notified when an Animation's animations have reached set progress.
+ *
+ * @return A signal object to connect with
+ *
+ */
+DALI_IMPORT_API Animation::AnimationSignalType& ProgressReachedSignal( Animation animation );
+
+} // namespace DevelAnimation
+
+} // namespace Dali
+
+#endif // DALI_ANIMATION_DEVEL_H
devel_api_src_files = \
$(devel_api_src_dir)/actors/actor-devel.cpp \
$(devel_api_src_dir)/animation/animation-data.cpp \
+ $(devel_api_src_dir)/animation/animation-devel.cpp \
$(devel_api_src_dir)/animation/path-constrainer.cpp \
$(devel_api_src_dir)/common/hash.cpp \
$(devel_api_src_dir)/common/stage-devel.cpp \
devel_api_core_animation_header_files = \
$(devel_api_src_dir)/animation/animation-data.h \
- $(devel_api_src_dir)/animation/path-constrainer.h
+ $(devel_api_src_dir)/animation/path-constrainer.h \
+ $(devel_api_src_dir)/animation/animation-devel.h
devel_api_core_common_header_files = \
$(devel_api_src_dir)/common/hash.h \
mEndAction( endAction ),
mDisconnectAction( disconnectAction ),
mDefaultAlpha( defaultAlpha ),
- mState(Dali::Animation::STOPPED)
+ mState(Dali::Animation::STOPPED),
+ mProgressReachedMarker( 0.0f )
{
}
SetDurationMessage( mEventThreadServices, *mAnimation, seconds );
}
+void Animation::SetProgressNotification( float progress )
+{
+ // mAnimation is being used in a separate thread; queue a message to set the value
+ mProgressReachedMarker = progress;
+}
+
+float Animation::GetProgressNotification()
+{
+ return mProgressReachedMarker;
+}
+
float Animation::GetDuration() const
{
// This is not animatable; the cached value is up-to-date.
NotifyObjects();
+ SendFinalProgressNotificationMessage();
+
// mAnimation is being used in a separate thread; queue a Play message
PlayAnimationMessage( mEventThreadServices, *mAnimation );
}
NotifyObjects();
+ SendFinalProgressNotificationMessage();
+
// mAnimation is being used in a separate thread; queue a Play message
PlayAnimationFromMessage( mEventThreadServices, *mAnimation, progress );
}
return mFinishedSignal;
}
+Dali::Animation::AnimationSignalType& Animation::ProgressReachedSignal()
+{
+ return mProgressReachedSignal;
+}
+
void Animation::EmitSignalFinish()
{
if ( !mFinishedSignal.Empty() )
}
}
+void Animation::EmitSignalProgressReached()
+{
+ if ( !mProgressReachedSignal.Empty() )
+ {
+ Dali::Animation handle( this );
+ mProgressReachedSignal.Emit( handle );
+ }
+}
+
bool Animation::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
{
bool connected( true );
}
}
+
+void Animation::SendFinalProgressNotificationMessage()
+{
+ if ( mProgressReachedMarker > 0.0f )
+ {
+ float progressMarkerSeconds = mDurationSeconds * mProgressReachedMarker;
+ SetProgressNotificationMessage( mEventThreadServices, *mAnimation, progressMarkerSeconds );
+ }
+}
+
} // namespace Internal
} // namespace Dali
*/
void SetDuration(float seconds);
+ /**
+ * @copydoc Dali::DevelAnimation::SetProgressNotification()
+ */
+ void SetProgressNotification( float progress );
+
+ /**
+ * @copydoc Dali::DevelAnimation::GetProgressNotification()
+ */
+ float GetProgressNotification();
+
/**
* @copydoc Dali::Animation::GetDuration()
*/
*/
Dali::Animation::AnimationSignalType& FinishedSignal();
+ /**
+ * @copydoc Dali::DevelAnimation::ProgressHasBeenReachedSignal()
+ */
+ Dali::Animation::AnimationSignalType& ProgressReachedSignal();
+
/**
* Emit the Finished signal
*/
void EmitSignalFinish();
+ /**
+ * Emit the ProgressReached signal
+ */
+ void EmitSignalProgressReached();
+
/**
* Connects a callback function with the object's signals.
* @param[in] object The object providing the signal.
*/
void NotifyObjects();
+ /**
+ * Sends message to SceneGraph with final progress value
+ */
+ void SendFinalProgressNotificationMessage();
+
private:
const SceneGraph::Animation* mAnimation;
Dali::Animation::AnimationSignalType mFinishedSignal;
+ Dali::Animation::AnimationSignalType mProgressReachedSignal;
+
typedef OwnerContainer< AnimatorConnectorBase* > AnimatorConnectorContainer;
AnimatorConnectorContainer mConnectors; ///< Owned by the Animation
EndAction mDisconnectAction;
AlphaFunction mDefaultAlpha;
Dali::Animation::State mState;
+ float mProgressReachedMarker;
};
} // namespace Internal
}
}
+void AnimationPlaylist::NotifyProgressReached( const SceneGraph::Animation* sceneGraphAnimation )
+{
+ std::vector< Dali::Animation > notifyProgressAnimations; // Will own animations until all emits have been done
+
+ for ( Dali::Vector< Animation* >::Iterator iter = mAnimations.Begin(); iter != mAnimations.End(); ++iter )
+ {
+ Animation* animation = *iter;
+
+ if ( ( animation->GetSceneObject() ) == sceneGraphAnimation )
+ {
+ // Store handles to animations that need signals emitted in the case of an animation being cleared in-between emits
+ notifyProgressAnimations.push_back( Dali::Animation( animation ) );
+ }
+ }
+
+ for ( std::vector< Dali::Animation >::iterator iter = notifyProgressAnimations.begin(); iter != notifyProgressAnimations.end(); ++iter )
+ {
+ Dali::Animation& handle = *iter;
+
+ GetImplementation(handle).EmitSignalProgressReached();
+ }
+}
+
} // namespace Internal
} // namespace Dali
#include <dali/public-api/animation/animation.h>
#include <dali/public-api/common/dali-vector.h>
#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/internal/common/message.h>
#include <dali/internal/event/common/complete-notification-interface.h>
+#include <dali/internal/update/animation/scene-graph-animation.h>
namespace Dali
{
*/
void OnClear( Animation& animation );
+ /**
+ * @brief Notify that an animation has reached a progress marker
+ * @param[in] sceneGraphAnimation scene graph animation that has reached progress
+ */
+ void NotifyProgressReached( const SceneGraph::Animation* sceneGraphAnimation );
+
private:
/**
};
+/**
+ * Called when an animation reaches a progress marker
+ *
+ * Note animationPlaylist is of type CompleteNotificationInterface because of updateManager only knowing about the interface not actual playlist
+ */
+inline MessageBase* NotifyProgressReachedMessage( CompleteNotificationInterface& animationPlaylist, const SceneGraph::Animation* animation )
+{
+ return new MessageValue1< AnimationPlaylist, const SceneGraph::Animation* >( static_cast<AnimationPlaylist*>(&animationPlaylist), &AnimationPlaylist::NotifyProgressReached, animation );
+}
+
} // namespace Internal
} // namespace Dali
/**
* Provides notifications to the event-thread regarding the changes in previous update(s).
- * For example after an animation finished, or after resources were loaded.
+ * For example after an animation finished
*/
class CompleteNotificationInterface
{
mPlayedCount(0),
mLoopCount(loopCount),
mCurrentLoop(0),
- mPlayRange( playRange )
+ mPlayRange( playRange ),
+ mProgressMarker(0.0f),
+ mProgressReachedSignalRequired( false )
{
}
mDurationSeconds = durationSeconds;
}
+void Animation::SetProgressNotification( float progress )
+{
+ mProgressMarker = progress;
+ if ( mProgressMarker > 0.0f )
+ {
+ mProgressReachedSignalRequired = true;
+ }
+}
+
void Animation::SetLoopCount(int loopCount)
{
mLoopCount = loopCount;
mAnimators.PushBack( animator.Release() );
}
-void Animation::Update(BufferIndex bufferIndex, float elapsedSeconds, bool& looped, bool& finished )
+void Animation::Update(BufferIndex bufferIndex, float elapsedSeconds, bool& looped, bool& finished, bool& progressReached )
{
looped = false;
finished = false;
if (mState == Playing)
{
mElapsedSeconds += elapsedSeconds * mSpeedFactor;
+
+ if ( mProgressReachedSignalRequired && ( mElapsedSeconds >= mProgressMarker ) )
+ {
+ // The application should be notified by NotificationManager, in another thread
+ progressReached = true;
+ mProgressReachedSignalRequired = false;
+ }
}
Vector2 playRangeSeconds = mPlayRange * mDurationSeconds;
// loop forever
WrapInPlayRange(mElapsedSeconds, playRangeSeconds);
- UpdateAnimators(bufferIndex, false, false);
+ UpdateAnimators(bufferIndex, false, false );
// don't increment mPlayedCount as event loop tracks this to indicate animation finished (end of all loops)
}
WrapInPlayRange( mElapsedSeconds, playRangeSeconds );
- UpdateAnimators(bufferIndex, false, false);
+ UpdateAnimators(bufferIndex, false, false );
if(looped)
{
++mCurrentLoop;
+ mProgressReachedSignalRequired = mProgressMarker > 0.0f;
// don't increment mPlayedCount until the finished final loop
}
}
( mSpeedFactor < 0.0f && mElapsedSeconds < playRangeSeconds.x )) );
// update with bake if finished
- UpdateAnimators(bufferIndex, finished && (mEndAction != Dali::Animation::Discard), finished);
+ UpdateAnimators(bufferIndex, finished && (mEndAction != Dali::Animation::Discard), finished );
if(finished)
{
DALI_ASSERT_DEBUG(mCurrentLoop == mLoopCount);
}
+ mProgressReachedSignalRequired = mProgressMarker > 0.0f;
mElapsedSeconds = playRangeSeconds.x;
mState = Stopped;
}
*/
void SetDuration(float durationSeconds);
+ /**
+ * Set the progress marker to trigger notification
+ * @param[in] progress percent of progress to trigger notification, 0.0f < progress <= 1.0f
+ */
+ void SetProgressNotification( float progress );
+
/**
* Retrieve the duration of the animation.
* @return The duration in seconds.
* @param[in] elapsedSeconds The time elapsed since the previous frame.
* @param[out] looped True if the animation looped
* @param[out] finished True if the animation has finished.
+ * @param[out] progressReached True if progress marker reached
*/
- void Update(BufferIndex bufferIndex, float elapsedSeconds, bool& looped, bool& finished );
+ void Update(BufferIndex bufferIndex, float elapsedSeconds, bool& looped, bool& finished, bool& progressReached );
protected:
int mCurrentLoop; // Current loop number
Vector2 mPlayRange;
+
+ float mProgressMarker; // Progress marker to trigger a notification
+ bool mProgressReachedSignalRequired; // Flag to indicate the progress marker was hit
+
AnimatorContainer mAnimators;
};
new (slot) LocalType( &animation, &Animation::SetDuration, durationSeconds );
}
+inline void SetProgressNotificationMessage( EventThreadServices& eventThreadServices, const Animation& animation, float progress )
+{
+ typedef MessageValue1< Animation, float > LocalType;
+
+ // Reserve some memory inside the message queue
+ unsigned int* slot = eventThreadServices.ReserveMessageSlot( sizeof( LocalType ) );
+
+ // Construct message in the message queue memory; note that delete should not be called on the return value
+ new (slot) LocalType( &animation, &Animation::SetProgressNotification, progress );
+}
+
+
inline void SetLoopingMessage( EventThreadServices& eventThreadServices, const Animation& animation, int loopCount )
{
typedef MessageValue1< Animation, int > LocalType;
#include <dali/internal/event/common/property-notification-impl.h>
#include <dali/internal/event/common/property-notifier.h>
#include <dali/internal/event/effects/shader-factory.h>
+#include <dali/internal/event/animation/animation-playlist.h>
#include <dali/internal/update/animation/scene-graph-animator.h>
#include <dali/internal/update/animation/scene-graph-animation.h>
struct UpdateManager::Impl
{
Impl( NotificationManager& notificationManager,
- CompleteNotificationInterface& animationFinishedNotifier,
+ CompleteNotificationInterface& animationPlaylist,
PropertyNotifier& propertyNotifier,
DiscardQueue& discardQueue,
RenderController& renderController,
: renderMessageDispatcher( renderManager, renderQueue, sceneGraphBuffers ),
notificationManager( notificationManager ),
transformManager(),
- animationFinishedNotifier( animationFinishedNotifier ),
+ animationPlaylist( animationPlaylist ),
propertyNotifier( propertyNotifier ),
shaderSaver( NULL ),
discardQueue( discardQueue ),
RenderMessageDispatcher renderMessageDispatcher; ///< Used for passing messages to the render-thread
NotificationManager& notificationManager; ///< Queues notification messages for the event-thread.
TransformManager transformManager; ///< Used to update the transformation matrices of the nodes
- CompleteNotificationInterface& animationFinishedNotifier; ///< Provides notification to applications when animations are finished.
+ CompleteNotificationInterface& animationPlaylist; ///< Holds handles to all the animations
PropertyNotifier& propertyNotifier; ///< Provides notification to applications when properties are modified.
ShaderSaver* shaderSaver; ///< Saves shader binaries.
DiscardQueue& discardQueue; ///< Nodes are added here when disconnected from the scene-graph.
AnimationContainer &animations = mImpl->animations;
AnimationIter iter = animations.Begin();
bool animationLooped = false;
+
while ( iter != animations.End() )
{
Animation* animation = *iter;
bool finished = false;
bool looped = false;
- animation->Update( bufferIndex, elapsedSeconds, looped, finished );
+ bool progressMarkerReached = false;
+ animation->Update( bufferIndex, elapsedSeconds, looped, finished, progressMarkerReached );
+
+ if ( progressMarkerReached )
+ {
+ mImpl->notificationManager.QueueMessage( Internal::NotifyProgressReachedMessage( mImpl->animationPlaylist, animation ) );
+ }
mImpl->animationFinishedDuringUpdate = mImpl->animationFinishedDuringUpdate || finished;
animationLooped = animationLooped || looped;
if ( mImpl->animationFinishedDuringUpdate || animationLooped )
{
// The application should be notified by NotificationManager, in another thread
- mImpl->notificationManager.QueueCompleteNotification( &mImpl->animationFinishedNotifier );
+ mImpl->notificationManager.QueueCompleteNotification( &mImpl->animationPlaylist );
}
}
/**
* Construct a new UpdateManager.
* @param[in] notificationManager This should be notified when animations have finished.
- * @param[in] animationFinishedNotifier The CompleteNotificationInterface that handles animation completions
+ * @param[in] animationPlaylist The CompleteNotificationInterface that handles the animations
* @param[in] propertyNotifier The PropertyNotifier
* @param[in] discardQueue Nodes are added here when disconnected from the scene-graph.
* @param[in] controller After messages are flushed, we request a render from the RenderController.
* @param[in] renderTaskProcessor Handles RenderTasks and RenderInstrucitons.
*/
UpdateManager( NotificationManager& notificationManager,
- CompleteNotificationInterface& animationFinishedNotifier,
+ CompleteNotificationInterface& animationPlaylist,
PropertyNotifier& propertyNotifier,
DiscardQueue& discardQueue,
Integration::RenderController& controller,