Renderer renderer = actor.GetRendererAt( 0u );
DALI_TEST_CHECK( renderer );
+ Property::Map map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+ Property::Value* value = map.Find( DevelImageVisual::Property::PLAY_RANGE );
+ DALI_TEST_EQUALS( value->Get< Vector2 >(), playRange, TEST_LOCATION );
+
END_TEST;
}
END_TEST;
}
+
+int UtcDaliAnimatedVectorImageVisualJumpToCurrentProgress(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "UtcDaliAnimatedVectorImageVisualJumpToCurrentProgress" );
+
+ Property::Map propertyMap;
+ propertyMap.Add( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE )
+ .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME );
+
+ Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
+ DALI_TEST_CHECK( visual );
+
+ DummyControl actor = DummyControl::New( true );
+ DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
+ dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+ Vector2 controlSize( 20.f, 30.f );
+ actor.SetSize( controlSize );
+
+ Stage::GetCurrent().Add( actor );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::JUMP_TO, 0.6f );
+
+ application.SendNotification();
+ application.Render();
+
+ Property::Map map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+ Property::Value* value = map.Find( DevelImageVisual::Property::CURRENT_PROGRESS );
+ DALI_TEST_EQUALS( value->Get< float >(), 0.6f, TEST_LOCATION );
+
+ Vector2 playRange( 0.0f, 0.4f );
+
+ Property::Map attributes;
+ attributes.Add( DevelImageVisual::Property::PLAY_RANGE, playRange );
+ DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+
+ DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::JUMP_TO, 0.8f );
+
+ application.SendNotification();
+ application.Render();
+
+ map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+ value = map.Find( DevelImageVisual::Property::CURRENT_PROGRESS );
+ DALI_TEST_EQUALS( value->Get< float >(), 0.4f, TEST_LOCATION );
+
+ END_TEST;
+}
+
+int UtcDaliAnimatedVectorImageVisualUpdateProperty(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline( "UtcDaliAnimatedVectorImageVisualJumpToCurrentProgress" );
+
+ Vector2 playRange( 0.2f, 0.8f );
+
+ Property::Map propertyMap;
+ propertyMap.Add( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE )
+ .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME )
+ .Add( DevelImageVisual::Property::LOOP_COUNT, 3 )
+ .Add( DevelImageVisual::Property::PLAY_RANGE, playRange );
+
+ Visual::Base visual = VisualFactory::Get().CreateVisual( propertyMap );
+ DALI_TEST_CHECK( visual );
+
+ DummyControl actor = DummyControl::New( true );
+ DummyControlImpl& dummyImpl = static_cast< DummyControlImpl& >( actor.GetImplementation() );
+ dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
+
+ Vector2 controlSize( 20.f, 30.f );
+ actor.SetSize( controlSize );
+
+ Stage::GetCurrent().Add( actor );
+
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 1 ), true, TEST_LOCATION );
+
+ Property::Map map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+ Property::Value* value = map.Find( DevelImageVisual::Property::LOOP_COUNT );
+ DALI_TEST_EQUALS( value->Get< int >(), 3, TEST_LOCATION );
+
+ value = map.Find( DevelImageVisual::Property::PLAY_RANGE );
+ DALI_TEST_EQUALS( value->Get< Vector2 >(), playRange, TEST_LOCATION );
+
+ Vector2 newPlayRange( 0.4f, 1.0f );
+
+ Property::Map attributes;
+ attributes.Add( DevelImageVisual::Property::PLAY_RANGE, newPlayRange );
+ attributes.Add( DevelImageVisual::Property::LOOP_COUNT, 5 );
+
+ DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
+
+ application.SendNotification();
+ application.Render();
+
+ map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+ value = map.Find( DevelImageVisual::Property::LOOP_COUNT );
+ DALI_TEST_EQUALS( value->Get< int >(), 5, TEST_LOCATION );
+
+ value = map.Find( DevelImageVisual::Property::PLAY_RANGE );
+ DALI_TEST_EQUALS( value->Get< Vector2 >(), newPlayRange, TEST_LOCATION );
+
+ END_TEST;
+}
*/
enum Type
{
- PLAY, ///< Play the animated vector image.
- PAUSE, ///< Pause the animated vector image.
- STOP ///< Stop the animated vector image. This is also Default playback mode.
+ PLAY, ///< Play the animated vector image.
+ PAUSE, ///< Pause the animated vector image.
+ STOP, ///< Stop the animated vector image. This is also Default playback mode.
+ JUMP_TO, ///< Jump to the specified frame. Property::FLOAT value should be passed.
+ UPDATE_PROPERTY ///< Update the properties of the animated vector image.
};
} // namespace Action
* @details Name "playState", type PlayState (Property::INTEGER)
* @note This property is read-only.
*/
- PLAY_STATE = ORIENTATION_CORRECTION + 5
+ PLAY_STATE = ORIENTATION_CORRECTION + 5,
+ /**
+ * @brief The animation progress the AnimatedVectorImageVisual will use.
+ * @details Name "currentProgress", Type Property::FLOAT, between [0, 1] or between the play range if specified
+ * @note This property is read-only.
+ */
+ CURRENT_PROGRESS = ORIENTATION_CORRECTION + 6
};
} //namespace Property
namespace
{
+constexpr auto LOOP_FOREVER = -1;
+
const Dali::Vector4 FULL_TEXTURE_RECT( 0.f, 0.f, 1.f, 1.f );
+// Flags for re-sending data to the rasterize thread
+enum Flags
+{
+ RESEND_PLAY_RANGE = 1 << 0,
+ RESEND_LOOP_COUNT = 1 << 1
+};
+
} // unnamed namespace
AnimatedVectorImageVisualPtr AnimatedVectorImageVisual::New( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl, const Property::Map& properties )
mUrl( imageUrl ),
mVectorRasterizeThread( imageUrl.GetUrl() ),
mVisualSize(),
+ mPlayRange( 0.0f, 1.0f ),
mPlacementActor(),
+ mLoopCount( LOOP_FOREVER ),
+ mResendFlag( 0 ),
mActionStatus( DevelAnimatedVectorImageVisual::Action::STOP )
{
// the rasterized image is with pre-multiplied alpha format
{
map.Insert( Toolkit::ImageVisual::Property::URL, mUrl.GetUrl() );
}
- map.Insert( Toolkit::DevelImageVisual::Property::LOOP_COUNT, static_cast< int >( mVectorRasterizeThread.GetLoopCount() ) );
- map.Insert( Toolkit::DevelImageVisual::Property::PLAY_RANGE, static_cast< Vector2 >( mVectorRasterizeThread.GetPlayRange() ) );
+ map.Insert( Toolkit::DevelImageVisual::Property::LOOP_COUNT, mLoopCount );
+ map.Insert( Toolkit::DevelImageVisual::Property::PLAY_RANGE, mPlayRange );
map.Insert( Toolkit::DevelImageVisual::Property::PLAY_STATE, static_cast< int >( mVectorRasterizeThread.GetPlayState() ) );
+ map.Insert( Toolkit::DevelImageVisual::Property::CURRENT_PROGRESS, mVectorRasterizeThread.GetCurrentProgress() );
}
void AnimatedVectorImageVisual::DoCreateInstancePropertyMap( Property::Map& map ) const
int32_t loopCount;
if( value.Get( loopCount ) )
{
- mVectorRasterizeThread.SetLoopCount( loopCount );
+ mLoopCount = loopCount;
+ mResendFlag |= RESEND_LOOP_COUNT;
}
break;
}
Vector2 range;
if( value.Get( range ) )
{
- mVectorRasterizeThread.SetPlayRange( range );
+ mPlayRange = range;
+ mResendFlag |= RESEND_PLAY_RANGE;
}
break;
}
mVectorRasterizeThread.SetSize( width, height );
}
+ SendAnimationData();
+
if( mActionStatus == DevelAnimatedVectorImageVisual::Action::PLAY )
{
mVectorRasterizeThread.PlayAnimation();
mActionStatus = DevelAnimatedVectorImageVisual::Action::STOP;
break;
}
+ case DevelAnimatedVectorImageVisual::Action::JUMP_TO:
+ {
+ float progress;
+ if( attributes.Get( progress ) )
+ {
+ mVectorRasterizeThread.SetCurrentProgress( progress );
+ }
+ break;
+ }
+ case DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY:
+ {
+ Property::Map* map = attributes.GetMap();
+ if( map )
+ {
+ DoSetProperties( *map );
+
+ SendAnimationData();
+ }
+ break;
+ }
}
}
actor.AddRenderer( mImpl->mRenderer );
// reset the weak handle so that the renderer only get added to actor once
mPlacementActor.Reset();
- }
- ResourceReady( Toolkit::Visual::ResourceStatus::READY );
+ ResourceReady( Toolkit::Visual::ResourceStatus::READY );
+ }
}
void AnimatedVectorImageVisual::OnAnimationFinished()
}
}
+void AnimatedVectorImageVisual::SendAnimationData()
+{
+ if( mResendFlag )
+ {
+ bool isPlaying = false;
+ if( mVectorRasterizeThread.GetPlayState() == DevelImageVisual::PlayState::PLAYING )
+ {
+ mVectorRasterizeThread.PauseAnimation();
+ isPlaying = true;
+ }
+
+ if( mResendFlag & RESEND_LOOP_COUNT )
+ {
+ mVectorRasterizeThread.SetLoopCount( mLoopCount );
+ }
+
+ if( mResendFlag & RESEND_PLAY_RANGE )
+ {
+ mVectorRasterizeThread.SetPlayRange( mPlayRange );
+ }
+
+ if( isPlaying )
+ {
+ mVectorRasterizeThread.PlayAnimation();
+ }
+ else
+ {
+ mVectorRasterizeThread.RenderFrame();
+ Stage::GetCurrent().KeepRendering( 0.0f );
+ }
+
+ mResendFlag = 0;
+ }
+}
+
} // namespace Internal
} // namespace Toolkit
*/
void OnAnimationFinished();
+ /**
+ * @brief Send animation data to the rasterize thread.
+ */
+ void SendAnimationData();
+
// Undefined
AnimatedVectorImageVisual( const AnimatedVectorImageVisual& visual ) = delete;
VisualUrl mUrl;
VectorRasterizeThread mVectorRasterizeThread;
Vector2 mVisualSize;
+ Vector2 mPlayRange;
WeakHandle< Actor > mPlacementActor;
+ int32_t mLoopCount;
+ uint32_t mResendFlag;
DevelAnimatedVectorImageVisual::Action::Type mActionStatus;
};
ConditionalWait::ScopedLock lock( mConditionalWait );
if( mPlayState != DevelImageVisual::PlayState::PLAYING )
{
- if( mPlayState == DevelImageVisual::PlayState::STOPPED )
- {
- // Reset the current frame and the current loop
- mCurrentFrame = mStartFrame;
- mCurrentLoop = 0;
- }
-
mPlayState = DevelImageVisual::PlayState::PLAYING;
mConditionalWait.Notify( lock );
{
mPlayState = DevelImageVisual::PlayState::STOPPED;
+ // Reset the current frame and the current loop
+ mCurrentFrame = mStartFrame;
+ mCurrentLoop = 0;
+
DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::StopAnimation: Stop\n" );
}
}
void VectorRasterizeThread::RenderFrame()
{
ConditionalWait::ScopedLock lock( mConditionalWait );
- mNeedRender = true;
- mConditionalWait.Notify( lock );
- DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::RenderFrame: Render\n" );
+ if( !mResourceReady )
+ {
+ mNeedRender = true;
+ mConditionalWait.Notify( lock );
+
+ DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::RenderFrame: Render\n" );
+ }
}
void VectorRasterizeThread::SetResourceReadyCallback( EventThreadCallback* callback )
void VectorRasterizeThread::SetLoopCount( int32_t count )
{
- ConditionalWait::ScopedLock lock( mConditionalWait );
+ if( mLoopCount != count )
+ {
+ ConditionalWait::ScopedLock lock( mConditionalWait );
- mLoopCount = count;
+ mLoopCount = count;
- // Reset progress
- mCurrentLoop = 0;
- mCurrentFrame = mStartFrame;
+ // Reset progress
+ mCurrentLoop = 0;
+ }
}
int32_t VectorRasterizeThread::GetLoopCount() const
void VectorRasterizeThread::SetPlayRange( Vector2 range )
{
- ConditionalWait::ScopedLock lock( mConditionalWait );
-
// Make sure the range specified is between 0.0 and 1.0
if( range.x >= 0.0f && range.x <= 1.0f && range.y >= 0.0f && range.y <= 1.0f )
{
orderedRange = Vector2( range.y, range.x );
}
- mPlayRange = orderedRange;
-
- if( mTotalFrame != 0 )
+ if( mPlayRange != orderedRange )
{
- mStartFrame = static_cast< uint32_t >( mPlayRange.x * mTotalFrame + 0.5f );
- mEndFrame = static_cast< uint32_t >( mPlayRange.y * mTotalFrame + 0.5f );
+ ConditionalWait::ScopedLock lock( mConditionalWait );
+
+ mPlayRange = orderedRange;
+
+ if( mTotalFrame != 0 )
+ {
+ mStartFrame = static_cast< uint32_t >( mPlayRange.x * mTotalFrame + 0.5f );
+ mEndFrame = static_cast< uint32_t >( mPlayRange.y * mTotalFrame + 0.5f );
+
+ // If the current frame is out of the range, change the current frame also.
+ if( mStartFrame > mCurrentFrame )
+ {
+ mCurrentFrame = mStartFrame;
+
+ mResourceReady = false;
+ }
+ else if( mEndFrame < mCurrentFrame )
+ {
+ mCurrentFrame = mEndFrame;
+
+ mResourceReady = false;
+ }
+ }
}
}
}
return mPlayRange;
}
+void VectorRasterizeThread::SetCurrentProgress( float progress )
+{
+ ConditionalWait::ScopedLock lock( mConditionalWait );
+
+ if( progress >= mPlayRange.x && progress <= mPlayRange.y )
+ {
+ mProgress = progress;
+
+ if( mTotalFrame != 0 )
+ {
+ mCurrentFrame = static_cast< uint32_t >( mTotalFrame * progress + 0.5f );
+ }
+
+ mResourceReady = false;
+
+ DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetCurrentProgress: progress = %f (%d)\n", progress, mCurrentFrame );
+ }
+}
+
+float VectorRasterizeThread::GetCurrentProgress() const
+{
+ return ( static_cast< float >( mCurrentFrame ) / static_cast< float >( mTotalFrame ) );
+}
+
DevelImageVisual::PlayState VectorRasterizeThread::GetPlayState() const
{
return mPlayState;
mStartFrame = static_cast< uint32_t >( mPlayRange.x * mTotalFrame + 0.5f );
mEndFrame = static_cast< uint32_t >( mPlayRange.y * mTotalFrame + 0.5f );
- mCurrentFrame = mStartFrame;
+ mCurrentFrame = std::max( static_cast< uint32_t >( mTotalFrame * mProgress + 0.5f ), mStartFrame );
DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::StartRender: Renderer is started [%d (%d, %d)]\n", mTotalFrame, mStartFrame, mEndFrame );
{
DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: [%d]\n", mCurrentFrame );
+ bool needRender, resourceReady;
+
+ {
+ ConditionalWait::ScopedLock lock( mConditionalWait );
+ needRender = mNeedRender;
+ resourceReady = mResourceReady;
+ }
+
// Rasterize
mVectorRenderer.Render( mCurrentFrame );
// Animation is finished
mPlayState = DevelImageVisual::PlayState::STOPPED;
+ // Reset the current frame and the current loop
+ mCurrentFrame = mStartFrame;
+ mCurrentLoop = 0;
+
mAnimationFinishedTrigger->Trigger();
DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Animation is finished\n" );
}
}
- mNeedRender = false;
+ if( needRender )
+ {
+ mNeedRender = false;
+ }
- if( !mResourceReady )
+ if( !resourceReady )
{
DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Resource ready trigger\n" );
*/
bool IsResourceReady() const;
+ /**
+ * @brief Sets the progress of the animation.
+ * @param[in] progress The new progress as a normalized value between [0,1] or between the play range if specified.
+ */
+ void SetCurrentProgress( float progress );
+
+ /**
+ * @brief Retrieves the current progress of the animation.
+ * @return The current progress as a normalized value between [0,1]
+ */
+ float GetCurrentProgress() const;
+
protected:
/**
const char * const ORIENTATION_CORRECTION_NAME("orientationCorrection");
const char * const AUXILIARY_IMAGE_NAME("auxiliaryImage");
const char * const AUXILIARY_IMAGE_ALPHA_NAME("auxiliaryImageAlpha");
-const char * const PLAY_RANGE_NAME("playRange");
+const char * const PLAY_RANGE_NAME( "playRange" );
+const char * const PLAY_STATE_NAME( "playState" );
+const char * const CURRENT_PROGRESS_NAME( "currentProgress" );
// Text visual
const char * const TEXT_PROPERTY( "text" );
extern const char * const AUXILLARY_IMAGE_NAME;
extern const char * const AUXILLARY_IMAGE_ALPHA_NAME;
extern const char * const PLAY_RANGE_NAME;
+extern const char * const PLAY_STATE_NAME;
+extern const char * const CURRENT_PROGRESS_NAME;
// Text visual
extern const char * const TEXT_PROPERTY;