mRenderer(),
mWidth( 0 ),
mHeight( 0 ),
- mPreviousFrame( 0 ),
- mFrameRate( 60.0f )
+ mPreviousFrame( 0 )
{
- mCount++;
-
- if( mCount == 2 )
- {
- mFrameRate = 0.1f;
- }
- }
-
- ~VectorAnimationRenderer()
- {
- mCount--;
}
void SetRenderer( Dali::Renderer renderer )
float GetFrameRate() const
{
- return mFrameRate;
+ return 60.0f;
}
void GetDefaultSize( uint32_t& width, uint32_t& height ) const
public:
- static uint32_t mCount;
-
std::string mUrl;
Dali::Renderer mRenderer;
uint32_t mWidth;
uint32_t mHeight;
uint32_t mPreviousFrame;
- float mFrameRate;
Dali::VectorAnimationRenderer::UploadCompletedSignalType mUploadCompletedSignal;
};
-uint32_t VectorAnimationRenderer::mCount = 0;
-
inline VectorAnimationRenderer& GetImplementation( Dali::VectorAnimationRenderer& renderer )
{
DALI_ASSERT_ALWAYS( renderer && "VectorAnimationRenderer handle is empty." );
VisualFactory factory = VisualFactory::Get();
Visual::Base visual = factory.CreateVisual( propertyMap );
- 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();
-
Property::Map resultMap;
- resultMap = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
+ visual.CreatePropertyMap( resultMap );
// check the property values from the returned map from a visual
Property::Value* value = resultMap.Find( Toolkit::Visual::Property::TYPE, Property::INTEGER );
ToolkitTestApplication application;
tet_infoline( "UtcDaliAnimatedVectorImageVisualPlayRange" );
- int startFrame = 1, endFrame = 3;
+ int startFrame = 3, endFrame = 1;
Property::Array array;
- array.PushBack( endFrame );
array.PushBack( startFrame );
+ array.PushBack( endFrame );
Property::Map propertyMap;
propertyMap.Add( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE )
// Set invalid play range
array.Clear();
- array.PushBack( 1 );
+ array.PushBack( -1 );
array.PushBack( 100 );
attributes.Clear();
DALI_TEST_EQUALS( startFrame, resultStartFrame, TEST_LOCATION ); // Should not be changed
DALI_TEST_EQUALS( endFrame, resultEndFrame, TEST_LOCATION );
- DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PAUSE, Property::Map() );
-
- application.SendNotification();
- application.Render();
-
- DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::JUMP_TO, 3 );
-
- application.SendNotification();
- application.Render();
-
- map = actor.GetProperty< Property::Map >( DummyControl::Property::TEST_VISUAL );
- value = map.Find( DevelImageVisual::Property::CURRENT_FRAME_NUMBER );
- DALI_TEST_EQUALS( value->Get< int >(), 3, TEST_LOCATION );
-
- array.Clear();
- array.PushBack( 0 );
- array.PushBack( 2 );
-
- attributes.Clear();
- attributes.Add( DevelImageVisual::Property::PLAY_RANGE, array );
- 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::PLAY_RANGE );
-
- result = value->GetArray();
- result->GetElementAt( 0 ).Get( resultStartFrame );
- result->GetElementAt( 1 ).Get( resultEndFrame );
-
- DALI_TEST_EQUALS( 0, resultStartFrame, TEST_LOCATION );
- DALI_TEST_EQUALS( 2, resultEndFrame, TEST_LOCATION );
-
- value = map.Find( DevelImageVisual::Property::CURRENT_FRAME_NUMBER );
- DALI_TEST_EQUALS( value->Get< int >(), 2, TEST_LOCATION ); // CURRENT_FRAME_NUMBER should be changed also.
-
END_TEST;
}
DALI_TEST_CHECK( result->GetElementAt( 0 ).Get< int >() == startFrame );
DALI_TEST_CHECK( result->GetElementAt( 1 ).Get< int >() == endFrame );
- // Play and update property
- attributes.Clear();
- DevelControl::DoAction( actor, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, attributes );
-
- application.SendNotification();
- application.Render();
-
- attributes.Add( DevelImageVisual::Property::LOOP_COUNT, 10 );
-
- 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 >(), 10, TEST_LOCATION );
-
END_TEST;
}
END_TEST;
}
-
-int UtcDaliAnimatedVectorImageVisualMultipleInstances(void)
-{
- ToolkitTestApplication application;
- tet_infoline( "UtcDaliAnimatedVectorImageVisualMultipleInstances" );
-
- Property::Map propertyMap;
- propertyMap.Add( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE )
- .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME );
-
- Visual::Base visual1 = VisualFactory::Get().CreateVisual( propertyMap );
- DALI_TEST_CHECK( visual1 );
-
- DummyControl actor1 = DummyControl::New( true );
- DummyControlImpl& dummyImpl1 = static_cast< DummyControlImpl& >( actor1.GetImplementation() );
- dummyImpl1.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual1 );
-
- Vector2 controlSize( 20.f, 30.f );
- actor1.SetSize( controlSize );
-
- Stage::GetCurrent().Add( actor1 );
-
- propertyMap.Clear();
- propertyMap.Add( Toolkit::Visual::Property::TYPE, DevelVisual::ANIMATED_VECTOR_IMAGE )
- .Add( ImageVisual::Property::URL, TEST_VECTOR_IMAGE_FILE_NAME );
-
- Visual::Base visual2 = VisualFactory::Get().CreateVisual( propertyMap );
- DALI_TEST_CHECK( visual2 );
-
- DummyControl actor2 = DummyControl::New( true );
- DummyControlImpl& dummyImpl2 = static_cast< DummyControlImpl& >( actor2.GetImplementation() );
- dummyImpl2.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual2 );
-
- actor2.SetSize( controlSize );
-
- Stage::GetCurrent().Add( actor2 );
-
- DevelControl::DoAction( actor2, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, Property::Map() );
-
- application.SendNotification();
- application.Render();
-
- std::this_thread::sleep_for( std::chrono::milliseconds( 200 ) );
-
- Property::Map attributes;
- attributes.Add( DevelImageVisual::Property::STOP_BEHAVIOR, DevelImageVisual::StopBehavior::LAST_FRAME );
-
- DevelControl::DoAction( actor1, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
- DevelControl::DoAction( actor2, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::UPDATE_PROPERTY, attributes );
-
- DevelControl::DoAction( actor1, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedVectorImageVisual::Action::PLAY, Property::Map() );
-
- // renderer is added to actor
- DALI_TEST_CHECK( actor1.GetRendererCount() == 1u );
- Renderer renderer1 = actor1.GetRendererAt( 0u );
- DALI_TEST_CHECK( renderer1 );
-
- // renderer is added to actor
- DALI_TEST_CHECK( actor2.GetRendererCount() == 1u );
- Renderer renderer2 = actor2.GetRendererAt( 0u );
- DALI_TEST_CHECK( renderer2 );
-
- END_TEST;
-}
${toolkit_src_dir}/visuals/animated-image/rolling-image-cache.cpp
${toolkit_src_dir}/visuals/animated-image/rolling-gif-image-cache.cpp
${toolkit_src_dir}/visuals/animated-vector-image/animated-vector-image-visual.cpp
- ${toolkit_src_dir}/visuals/animated-vector-image/vector-animation-task.cpp
- ${toolkit_src_dir}/visuals/animated-vector-image/vector-animation-thread.cpp
${toolkit_src_dir}/visuals/animated-vector-image/vector-rasterize-thread.cpp
${toolkit_src_dir}/visuals/border/border-visual.cpp
${toolkit_src_dir}/visuals/color/color-visual.cpp
AnimatedVectorImageVisual::AnimatedVectorImageVisual( VisualFactoryCache& factoryCache, ImageVisualShaderFactory& shaderFactory, const VisualUrl& imageUrl )
: Visual::Base( factoryCache, Visual::FittingMode::FILL ),
- mUrl( imageUrl ),
- mVectorAnimationTask( new VectorAnimationTask( factoryCache, imageUrl.GetUrl() ) ),
mImageVisualShaderFactory( shaderFactory ),
+ mUrl( imageUrl ),
+ mVectorRasterizeThread( imageUrl.GetUrl() ),
mVisualSize(),
mVisualScale( Vector2::ONE ),
mPlacementActor(),
// the rasterized image is with pre-multiplied alpha format
mImpl->mFlags |= Impl::IS_PREMULTIPLIED_ALPHA;
- mVectorAnimationTask->UploadCompletedSignal().Connect( this, &AnimatedVectorImageVisual::OnUploadCompleted );
- mVectorAnimationTask->SetAnimationFinishedCallback( new EventThreadCallback( MakeCallback( this, &AnimatedVectorImageVisual::OnAnimationFinished ) ) );
+ mVectorRasterizeThread.UploadCompletedSignal().Connect( this, &AnimatedVectorImageVisual::OnUploadCompleted );
+ mVectorRasterizeThread.SetAnimationFinishedCallback( new EventThreadCallback( MakeCallback( this, &AnimatedVectorImageVisual::OnAnimationFinished ) ) );
+
+ mVectorRasterizeThread.Start();
}
AnimatedVectorImageVisual::~AnimatedVectorImageVisual()
else
{
uint32_t width, height;
- mVectorAnimationTask->GetDefaultSize( width, height );
+ mVectorRasterizeThread.GetDefaultSize( width, height );
naturalSize.x = width;
naturalSize.y = height;
}
}
map.Insert( Toolkit::DevelImageVisual::Property::LOOP_COUNT, mLoopCount );
- uint32_t startFrame, endFrame;
- mVectorAnimationTask->GetPlayRange( startFrame, endFrame );
-
Property::Array playRange;
- playRange.PushBack( static_cast< int32_t >( startFrame ) );
- playRange.PushBack( static_cast< int32_t >( endFrame ) );
+ playRange.PushBack( mStartFrame );
+ playRange.PushBack( mEndFrame );
map.Insert( Toolkit::DevelImageVisual::Property::PLAY_RANGE, playRange );
- map.Insert( Toolkit::DevelImageVisual::Property::PLAY_STATE, static_cast< int32_t >( mVectorAnimationTask->GetPlayState() ) );
- map.Insert( Toolkit::DevelImageVisual::Property::CURRENT_FRAME_NUMBER, static_cast< int32_t >( mVectorAnimationTask->GetCurrentFrameNumber() ) );
- map.Insert( Toolkit::DevelImageVisual::Property::TOTAL_FRAME_NUMBER, static_cast< int32_t >( mVectorAnimationTask->GetTotalFrameNumber() ) );
+ map.Insert( Toolkit::DevelImageVisual::Property::PLAY_STATE, static_cast< int >( mVectorRasterizeThread.GetPlayState() ) );
+ map.Insert( Toolkit::DevelImageVisual::Property::CURRENT_FRAME_NUMBER, static_cast< int32_t >( mVectorRasterizeThread.GetCurrentFrameNumber() ) );
+ map.Insert( Toolkit::DevelImageVisual::Property::TOTAL_FRAME_NUMBER, static_cast< int32_t >( mVectorRasterizeThread.GetTotalFrameNumber() ) );
map.Insert( Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, mStopBehavior );
map.Insert( Toolkit::DevelImageVisual::Property::LOOPING_MODE, mLoopingMode );
if( count >= 2 )
{
int startFrame, endFrame;
- int totalFrame = mVectorAnimationTask->GetTotalFrameNumber();
+ int totalFrame = mVectorRasterizeThread.GetTotalFrameNumber();
array->GetElementAt( 0 ).Get( startFrame );
array->GetElementAt( 1 ).Get( endFrame );
// Hold the weak handle of the placement actor and delay the adding of renderer until the rasterization is finished.
mPlacementActor = actor;
- mVectorAnimationTask->SetRenderer( mImpl->mRenderer );
+ mVectorRasterizeThread.SetRenderer( mImpl->mRenderer );
// Add property notification for scaling & size
mScaleNotification = actor.AddPropertyNotification( Actor::Property::WORLD_SCALE, StepCondition( 0.1f, 1.0f ) );
void AnimatedVectorImageVisual::DoSetOffStage( Actor& actor )
{
- mVectorAnimationTask->PauseAnimation();
+ mVectorRasterizeThread.PauseAnimation();
mActionStatus = DevelAnimatedVectorImageVisual::Action::PAUSE;
if( mActionStatus == DevelAnimatedVectorImageVisual::Action::PLAY )
{
- mVectorAnimationTask->PlayAnimation();
+ mVectorRasterizeThread.PlayAnimation();
mImpl->mRenderer.SetProperty( DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::CONTINUOUSLY );
}
else
{
// Render one frame
- mVectorAnimationTask->RenderFrame();
+ mVectorRasterizeThread.RenderFrame();
}
}
}
{
if( IsOnStage() && mVisualSize != Vector2::ZERO )
{
- mVectorAnimationTask->PlayAnimation();
+ mVectorRasterizeThread.PlayAnimation();
mImpl->mRenderer.SetProperty( DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::CONTINUOUSLY );
}
}
case DevelAnimatedVectorImageVisual::Action::PAUSE:
{
- mVectorAnimationTask->PauseAnimation();
+ mVectorRasterizeThread.PauseAnimation();
if( mImpl->mRenderer )
{
}
case DevelAnimatedVectorImageVisual::Action::STOP:
{
- if( mVectorAnimationTask->GetPlayState() != DevelImageVisual::PlayState::STOPPED )
+ if( mVectorRasterizeThread.GetPlayState() != DevelImageVisual::PlayState::STOPPED )
{
- mVectorAnimationTask->StopAnimation();
+ mVectorRasterizeThread.StopAnimation();
}
if( mImpl->mRenderer )
int32_t frameNumber;
if( attributes.Get( frameNumber ) )
{
- mVectorAnimationTask->SetCurrentFrameNumber( frameNumber );
+ mVectorRasterizeThread.SetCurrentFrameNumber( frameNumber );
- if( IsOnStage() && mVectorAnimationTask->GetPlayState() != DevelImageVisual::PlayState::PLAYING )
+ if( IsOnStage() && mVectorRasterizeThread.GetPlayState() != DevelImageVisual::PlayState::PLAYING )
{
- mVectorAnimationTask->RenderFrame();
+ mVectorRasterizeThread.RenderFrame();
Stage::GetCurrent().KeepRendering( 0.0f ); // Trigger rendering
}
}
if( mResendFlag )
{
bool isPlaying = false;
- if( mVectorAnimationTask->GetPlayState() == DevelImageVisual::PlayState::PLAYING )
+ if( mVectorRasterizeThread.GetPlayState() == DevelImageVisual::PlayState::PLAYING )
{
- mVectorAnimationTask->PauseAnimation();
+ mVectorRasterizeThread.PauseAnimation();
isPlaying = true;
}
if( mResendFlag & RESEND_LOOP_COUNT )
{
- mVectorAnimationTask->SetLoopCount( mLoopCount );
+ mVectorRasterizeThread.SetLoopCount( mLoopCount );
}
if( mResendFlag & RESEND_PLAY_RANGE )
{
- mVectorAnimationTask->SetPlayRange( mStartFrame, mEndFrame );
+ mVectorRasterizeThread.SetPlayRange( mStartFrame, mEndFrame );
}
if( mResendFlag & RESEND_STOP_BEHAVIOR )
{
- mVectorAnimationTask->SetStopBehavior( mStopBehavior );
+ mVectorRasterizeThread.SetStopBehavior( mStopBehavior );
}
if( mResendFlag & RESEND_LOOPING_MODE )
{
- mVectorAnimationTask->SetLoopingMode( mLoopingMode );
+ mVectorRasterizeThread.SetLoopingMode( mLoopingMode );
}
if( IsOnStage() )
{
if( isPlaying )
{
- mVectorAnimationTask->PlayAnimation();
+ mVectorRasterizeThread.PlayAnimation();
}
else
{
- mVectorAnimationTask->RenderFrame();
+ mVectorRasterizeThread.RenderFrame();
Stage::GetCurrent().KeepRendering( 0.0f );
}
}
uint32_t width = static_cast< uint32_t >( mVisualSize.width * mVisualScale.width );
uint32_t height = static_cast< uint32_t >( mVisualSize.height * mVisualScale.height );
- mVectorAnimationTask->SetSize( width, height );
+ mVectorRasterizeThread.SetSize( width, height );
- if( IsOnStage() && mVectorAnimationTask->GetPlayState() != DevelImageVisual::PlayState::PLAYING )
+ if( IsOnStage() && mVectorRasterizeThread.GetPlayState() != DevelImageVisual::PlayState::PLAYING )
{
- mVectorAnimationTask->RenderFrame();
+ mVectorRasterizeThread.RenderFrame();
Stage::GetCurrent().KeepRendering( 0.0f ); // Trigger rendering
}
}
#include <dali-toolkit/internal/visuals/visual-base-impl.h>
#include <dali-toolkit/internal/visuals/visual-url.h>
#include <dali-toolkit/devel-api/visuals/animated-vector-image-visual-actions-devel.h>
-#include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h>
+#include <dali-toolkit/internal/visuals/animated-vector-image/vector-rasterize-thread.h>
namespace Dali
{
{
class ImageVisualShaderFactory;
+class VectorRasterizeThread;
class AnimatedVectorImageVisual;
using AnimatedVectorImageVisualPtr = IntrusivePtr< AnimatedVectorImageVisual >;
AnimatedVectorImageVisual& operator=( const AnimatedVectorImageVisual& visual ) = delete;
private:
- VisualUrl mUrl;
- VectorAnimationTaskPtr mVectorAnimationTask;
ImageVisualShaderFactory& mImageVisualShaderFactory;
+ VisualUrl mUrl;
+ VectorRasterizeThread mVectorRasterizeThread;
PropertyNotification mScaleNotification;
PropertyNotification mSizeNotification;
Vector2 mVisualSize;
Vector2 mVisualScale;
WeakHandle< Actor > mPlacementActor;
int32_t mLoopCount;
- uint32_t mStartFrame;
- uint32_t mEndFrame;
+ int32_t mStartFrame;
+ int32_t mEndFrame;
uint32_t mResendFlag;
DevelAnimatedVectorImageVisual::Action::Type mActionStatus;
DevelImageVisual::StopBehavior::Type mStopBehavior;
+++ /dev/null
-/*
- * Copyright (c) 2019 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.
- *
- */
-
-// CLASS HEADER
-#include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h>
-
-// EXTERNAL INCLUDES
-#include <dali/integration-api/debug.h>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
-#include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.h>
-
-namespace Dali
-{
-
-namespace Toolkit
-{
-
-namespace Internal
-{
-
-namespace
-{
-
-constexpr auto LOOP_FOREVER = -1;
-constexpr auto NANOSECONDS_PER_SECOND( 1e+9 );
-
-#if defined(DEBUG_ENABLED)
-Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_VECTOR_ANIMATION" );
-#endif
-
-template< typename T >
-inline void ResetValue( bool& updated, T& value, T newValue, ConditionalWait& conditionalWait )
-{
- ConditionalWait::ScopedLock lock( conditionalWait );
- if( !updated )
- {
- value = newValue;
- updated = true;
- }
-}
-
-} // unnamed namespace
-
-VectorAnimationTask::VectorAnimationTask( VisualFactoryCache& factoryCache, const std::string& url )
-: mUrl( url ),
- mVectorRenderer(),
- mVectorAnimationThread( factoryCache.GetVectorAnimationThread() ),
- mConditionalWait(),
- mAnimationFinishedTrigger(),
- mPlayState( PlayState::STOPPED ),
- mStopBehavior( DevelImageVisual::StopBehavior::CURRENT_FRAME ),
- mLoopingMode( DevelImageVisual::LoopingMode::RESTART ),
- mNextFrameStartTime(),
- mFrameDurationNanoSeconds( 0 ),
- mFrameRate( 60.0f ),
- mCurrentFrame( 0 ),
- mTotalFrame( 0 ),
- mStartFrame( 0 ),
- mEndFrame( 0 ),
- mWidth( 0 ),
- mHeight( 0 ),
- mLoopCount( LOOP_FOREVER ),
- mCurrentLoop( 0 ),
- mResourceReady( false ),
- mCurrentFrameUpdated( false ),
- mCurrentLoopUpdated( false ),
- mForward( true ),
- mUpdateFrameNumber( false ),
- mNeedAnimationFinishedTrigger( true )
-{
- Initialize();
-}
-
-VectorAnimationTask::~VectorAnimationTask()
-{
- DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::~VectorAnimationTask: destructor [%p]\n", this );
-}
-
-void VectorAnimationTask::SetRenderer( Renderer renderer )
-{
- ConditionalWait::ScopedLock lock( mConditionalWait );
-
- mVectorRenderer.SetRenderer( renderer );
-
- DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetRenderer [%p]\n", this );
-}
-
-void VectorAnimationTask::SetSize( uint32_t width, uint32_t height )
-{
- if( mWidth != width || mHeight != height )
- {
- ConditionalWait::ScopedLock lock( mConditionalWait );
- mVectorRenderer.SetSize( width, height );
-
- mWidth = width;
- mHeight = height;
-
- mResourceReady = false;
-
- DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetSize: width = %d, height = %d [%p]\n", width, height, this );
- }
-}
-
-void VectorAnimationTask::PlayAnimation()
-{
- ConditionalWait::ScopedLock lock( mConditionalWait );
-
- if( mPlayState != PlayState::PLAYING )
- {
- mUpdateFrameNumber = false;
- mPlayState = PlayState::PLAYING;
-
- mVectorAnimationThread.AddTask( this );
-
- DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PlayAnimation: Play [%p]\n", this );
- }
-}
-
-void VectorAnimationTask::StopAnimation()
-{
- ConditionalWait::ScopedLock lock( mConditionalWait );
- if( mPlayState != PlayState::STOPPED && mPlayState != PlayState::STOPPING )
- {
- mNeedAnimationFinishedTrigger = false;
- mPlayState = PlayState::STOPPING;
-
- DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::StopAnimation: Stop [%p]\n", this );
- }
-}
-
-void VectorAnimationTask::PauseAnimation()
-{
- ConditionalWait::ScopedLock lock( mConditionalWait );
- if( mPlayState == PlayState::PLAYING )
- {
- mPlayState = PlayState::PAUSED;
-
- DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PauseAnimation: Pause [%p]\n", this );
- }
-}
-
-void VectorAnimationTask::RenderFrame()
-{
- ConditionalWait::ScopedLock lock( mConditionalWait );
-
- if( !mResourceReady )
- {
- mVectorAnimationThread.AddTask( this );
-
- DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::RenderFrame: Render [%p]\n", this );
- }
-}
-
-void VectorAnimationTask::SetAnimationFinishedCallback( EventThreadCallback* callback )
-{
- ConditionalWait::ScopedLock lock( mConditionalWait );
- mAnimationFinishedTrigger = std::unique_ptr< EventThreadCallback >( callback );
-}
-
-void VectorAnimationTask::SetLoopCount( int32_t count )
-{
- if( mLoopCount != count )
- {
- ConditionalWait::ScopedLock lock( mConditionalWait );
-
- mLoopCount = count;
- mCurrentLoop = 0;
- mCurrentLoopUpdated = true;
-
- DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetLoopCount: [%d] [%p]\n", count, this );
- }
-}
-
-void VectorAnimationTask::SetPlayRange( uint32_t startFrame, uint32_t endFrame )
-{
- // Make sure the range specified is between 0 and the total frame number
- if( ( startFrame < mTotalFrame ) && ( endFrame < mTotalFrame ) )
- {
- // If the range is not in order swap values
- if( startFrame > endFrame )
- {
- uint32_t temp = startFrame;
- startFrame = endFrame;
- endFrame = temp;
- }
-
- if( startFrame != mStartFrame || endFrame != mEndFrame )
- {
- ConditionalWait::ScopedLock lock( mConditionalWait );
-
- mStartFrame = startFrame;
- mEndFrame = endFrame;
-
- // If the current frame is out of the range, change the current frame also.
- if( mStartFrame > mCurrentFrame )
- {
- mCurrentFrame = mStartFrame;
-
- mCurrentFrameUpdated = true;
- mResourceReady = false;
- }
- else if( mEndFrame < mCurrentFrame )
- {
- mCurrentFrame = mEndFrame;
-
- mCurrentFrameUpdated = true;
- mResourceReady = false;
- }
-
- DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetPlayRange: [%d, %d] [%p]\n", mStartFrame, mEndFrame, this );
- }
- }
-}
-
-void VectorAnimationTask::GetPlayRange( uint32_t& startFrame, uint32_t& endFrame )
-{
- startFrame = mStartFrame;
- endFrame = mEndFrame;
-}
-
-DevelImageVisual::PlayState::Type VectorAnimationTask::GetPlayState() const
-{
- DevelImageVisual::PlayState::Type state = DevelImageVisual::PlayState::STOPPED;
-
- switch( mPlayState )
- {
- case PlayState::PLAYING:
- {
- state = DevelImageVisual::PlayState::PLAYING;
- break;
- }
- case PlayState::PAUSED:
- {
- state = DevelImageVisual::PlayState::PAUSED;
- break;
- }
- case PlayState::STOPPING:
- case PlayState::STOPPED:
- {
- state = DevelImageVisual::PlayState::STOPPED;
- break;
- }
- }
-
- return state;
-}
-
-void VectorAnimationTask::SetCurrentFrameNumber( uint32_t frameNumber )
-{
- ConditionalWait::ScopedLock lock( mConditionalWait );
-
- if( mCurrentFrame == frameNumber )
- {
- DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: Set same frame [%d] [%p]\n", frameNumber, this );
- return;
- }
-
- if( frameNumber >= mStartFrame && frameNumber <= mEndFrame )
- {
- mCurrentFrame = frameNumber;
- mCurrentFrameUpdated = true;
-
- mResourceReady = false;
-
- DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: frame number = %d [%p]\n", mCurrentFrame, this );
- }
- else
- {
- DALI_LOG_ERROR( "Invalid frame number [%d (%d, %d)]\n", frameNumber, mStartFrame, mEndFrame );
- }
-}
-
-uint32_t VectorAnimationTask::GetCurrentFrameNumber() const
-{
- return mCurrentFrame;
-}
-
-uint32_t VectorAnimationTask::GetTotalFrameNumber() const
-{
- return mTotalFrame;
-}
-
-void VectorAnimationTask::GetDefaultSize( uint32_t& width, uint32_t& height ) const
-{
- mVectorRenderer.GetDefaultSize( width, height );
-}
-
-void VectorAnimationTask::SetStopBehavior( DevelImageVisual::StopBehavior::Type stopBehavior )
-{
- ConditionalWait::ScopedLock lock( mConditionalWait );
- mStopBehavior = stopBehavior;
-
- DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetStopBehavior: stop behavor = %d [%p]\n", mStopBehavior, this );
-}
-
-void VectorAnimationTask::SetLoopingMode( DevelImageVisual::LoopingMode::Type loopingMode )
-{
- ConditionalWait::ScopedLock lock( mConditionalWait );
- mLoopingMode = loopingMode;
-
- DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetLoopingMode: looping mode = %d [%p]\n", mLoopingMode, this );
-}
-
-VectorAnimationTask::UploadCompletedSignalType& VectorAnimationTask::UploadCompletedSignal()
-{
- return mVectorRenderer.UploadCompletedSignal();
-}
-
-void VectorAnimationTask::Initialize()
-{
- mVectorRenderer = VectorAnimationRenderer::New( mUrl );
-
- mTotalFrame = mVectorRenderer.GetTotalFrameNumber();
-
- mEndFrame = mTotalFrame - 1;
-
- mFrameRate = mVectorRenderer.GetFrameRate();
- mFrameDurationNanoSeconds = NANOSECONDS_PER_SECOND / mFrameRate;
-
- uint32_t width, height;
- mVectorRenderer.GetDefaultSize( width, height );
-
- SetSize( width, height );
-
- DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Initialize: file = %s [%d frames, %f fps] [%p]\n", mUrl.c_str(), mTotalFrame, mFrameRate, this );
-}
-
-bool VectorAnimationTask::Rasterize()
-{
- bool stopped = false, needAnimationFinishedTrigger;
- uint32_t currentFrame, startFrame, endFrame;
- int32_t loopCount, currentLoopCount;
- PlayState playState;
-
- {
- ConditionalWait::ScopedLock lock( mConditionalWait );
-
- if( mPlayState == PlayState::PLAYING && mUpdateFrameNumber )
- {
- mCurrentFrame = mForward ? mCurrentFrame + 1 : mCurrentFrame - 1;
- }
-
- currentFrame = mCurrentFrame;
- startFrame = mStartFrame;
- endFrame = mEndFrame;
- loopCount = mLoopCount;
- currentLoopCount = mCurrentLoop;
- needAnimationFinishedTrigger = mNeedAnimationFinishedTrigger;
- playState = mPlayState;
-
- mResourceReady = true;
- mCurrentFrameUpdated = false;
- mCurrentLoopUpdated = false;
- mUpdateFrameNumber = true;
- mNeedAnimationFinishedTrigger = true;
- }
-
- if( playState == PlayState::STOPPING )
- {
- currentFrame = GetStoppedFrame( startFrame, endFrame, currentFrame );
- ResetValue( mCurrentFrameUpdated, mCurrentFrame, currentFrame, mConditionalWait );
-
- stopped = true;
- }
- else if( playState == PlayState::PLAYING )
- {
- bool animationFinished = false;
-
- if( currentFrame >= endFrame ) // last frame
- {
- if( mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE )
- {
- mForward = false;
- }
- else
- {
- if( loopCount < 0 || ++currentLoopCount < loopCount ) // repeat forever or before the last loop
- {
- ResetValue( mCurrentFrameUpdated, mCurrentFrame, startFrame, mConditionalWait ); // If the current frame is changed in the event thread, don't overwrite it.
- mUpdateFrameNumber = false;
- }
- else
- {
- animationFinished = true; // end of animation
- }
- ResetValue( mCurrentLoopUpdated, mCurrentLoop, currentLoopCount, mConditionalWait );
- }
- }
- else if( currentFrame == startFrame && !mForward ) // first frame
- {
- if( loopCount < 0 || ++currentLoopCount < loopCount ) // repeat forever or before the last loop
- {
- mForward = true;
- }
- else
- {
- animationFinished = true; // end of animation
- }
- ResetValue( mCurrentLoopUpdated, mCurrentLoop, currentLoopCount, mConditionalWait );
- }
-
- if( animationFinished )
- {
- if( mStopBehavior == DevelImageVisual::StopBehavior::CURRENT_FRAME )
- {
- stopped = true;
- }
- else
- {
- mPlayState = PlayState::STOPPING;
- }
- }
- }
-
- // Rasterize
- bool renderSuccess = mVectorRenderer.Render( currentFrame );
- if( !renderSuccess )
- {
- DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Rendering failed. Try again later.[%d] [%p]\n", currentFrame, this );
- mUpdateFrameNumber = false;
- }
-
- if( stopped && renderSuccess )
- {
- mPlayState = PlayState::STOPPED;
- mForward = true;
- mCurrentLoop = 0;
-
- // Animation is finished
- if( needAnimationFinishedTrigger && mAnimationFinishedTrigger )
- {
- mAnimationFinishedTrigger->Trigger();
- }
-
- DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Animation is finished [current = %d] [%p]\n", currentFrame, this );
- }
-
- bool keepAnimation = true;
- if( playState == PlayState::PAUSED || playState == PlayState::STOPPED )
- {
- keepAnimation = false;
- }
-
- return keepAnimation;
-}
-
-uint32_t VectorAnimationTask::GetStoppedFrame( uint32_t startFrame, uint32_t endFrame, uint32_t currentFrame )
-{
- uint32_t frame = currentFrame;
-
- switch( mStopBehavior )
- {
- case DevelImageVisual::StopBehavior::FIRST_FRAME:
- {
- frame = startFrame;
- break;
- }
- case DevelImageVisual::StopBehavior::LAST_FRAME:
- {
- if( mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE )
- {
- frame = startFrame;
- }
- else
- {
- frame = endFrame;
- }
- break;
- }
- case DevelImageVisual::StopBehavior::CURRENT_FRAME:
- {
- frame = currentFrame;
- break;
- }
- }
-
- return frame;
-}
-
-std::chrono::time_point< std::chrono::system_clock > VectorAnimationTask::CalculateNextFrameTime( bool renderNow )
-{
- mNextFrameStartTime = mNextFrameStartTime + std::chrono::nanoseconds( mFrameDurationNanoSeconds );
- auto current = std::chrono::system_clock::now();
- if( renderNow || mNextFrameStartTime < current )
- {
- mNextFrameStartTime = current;
- }
- return mNextFrameStartTime;
-}
-
-std::chrono::time_point< std::chrono::system_clock > VectorAnimationTask::GetNextFrameTime()
-{
- return mNextFrameStartTime;
-}
-
-} // namespace Internal
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_VECTOR_ANIMATION_TASK_H
-#define DALI_TOOLKIT_VECTOR_ANIMATION_TASK_H
-
-/*
- * Copyright (c) 2019 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.
- */
-
-// EXTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/event-thread-callback.h>
-#include <dali/devel-api/adaptor-framework/vector-animation-renderer.h>
-#include <dali/devel-api/threading/conditional-wait.h>
-#include <memory>
-#include <chrono>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
-
-namespace Dali
-{
-
-namespace Toolkit
-{
-
-namespace Internal
-{
-
-class VisualFactoryCache;
-class VectorAnimationThread;
-class VectorAnimationTask;
-typedef IntrusivePtr< VectorAnimationTask > VectorAnimationTaskPtr;
-
-/**
- * The task of the vector animation.
- */
-class VectorAnimationTask : public RefObject
-{
-public:
-
- using UploadCompletedSignalType = Dali::VectorAnimationRenderer::UploadCompletedSignalType;
-
- /**
- * @brief Constructor.
- *
- * @param[in] factoryCache A pointer pointing to the VisualFactoryCache object
- * @param[in] url The url of the vector animation file
- */
- VectorAnimationTask( VisualFactoryCache& factoryCache, const std::string& url );
-
- /**
- * @brief Destructor.
- */
- virtual ~VectorAnimationTask();
-
- /**
- * @brief Sets the renderer used to display the result image.
- *
- * @param[in] renderer The renderer used to display the result image
- */
- void SetRenderer( Renderer renderer );
-
- /**
- * @brief Sets the target image size.
- *
- * @param[in] width The target image width
- * @param[in] height The target image height
- */
- void SetSize( uint32_t width, uint32_t height );
-
- /**
- * @brief Play the vector animation.
- */
- void PlayAnimation();
-
- /**
- * @brief Stop the vector animation.
- */
- void StopAnimation();
-
- /**
- * @brief Pause the vector animation.
- */
- void PauseAnimation();
-
- /**
- * @brief Render one frame. The current frame number will be increased.
- */
- void RenderFrame();
-
- /**
- * @brief This callback is called after the animation is finished.
- * @param[in] callback The animation finished callback
- */
- void SetAnimationFinishedCallback( EventThreadCallback* callback );
-
- /**
- * @brief Enable looping for 'count' repeats. -1 means to repeat forever.
- * @param[in] count The number of times to loop
- */
- void SetLoopCount( int32_t count );
-
- /**
- * @brief Set the playing range in frame number.
- * @param[in] startFrame The frame number to specify minimum progress.
- * @param[in] endFrame The frame number to specify maximum progress.
- * The animation will play between those values.
- */
- void SetPlayRange( uint32_t startFrame, uint32_t endFrame );
-
- /**
- * @brief Gets the playing range in frame number.
- * @param[out] startFrame The frame number to specify minimum progress.
- * @param[out] endFrame The frame number to specify maximum progress.
- */
- void GetPlayRange( uint32_t& startFrame, uint32_t& endFrame );
-
- /**
- * @brief Get the play state
- * @return The play state
- */
- DevelImageVisual::PlayState::Type GetPlayState() const;
-
- /**
- * @brief Sets the current frame number of the animation.
- * @param[in] frameNumber The new frame number between [0, the maximum frame number] or between the play range if specified.
- */
- void SetCurrentFrameNumber( uint32_t frameNumber );
-
- /**
- * @brief Retrieves the current frame number of the animation.
- * @return The current frame number
- */
- uint32_t GetCurrentFrameNumber() const;
-
- /**
- * @brief Retrieves the total frame number of the animation.
- * @return The total frame number
- */
- uint32_t GetTotalFrameNumber() const;
-
- /**
- * @brief Gets the default size of the file,.
- * @return The default size of the file
- */
- void GetDefaultSize( uint32_t& width, uint32_t& height ) const;
-
- /**
- * @brief Sets the stop behavior of the animation. This is performed when the animation is stopped.
- * @param[in] stopBehavior The stop behavior
- */
- void SetStopBehavior( DevelImageVisual::StopBehavior::Type stopBehavior );
-
- /**
- * @brief Sets the looping mode.
- * Animation plays forwards and then restarts from the beginning or runs backwards again.
- * @param[in] loopingMode The looping mode
- */
- void SetLoopingMode( DevelImageVisual::LoopingMode::Type loopingMode );
-
- /**
- * @brief Connect to this signal to be notified when the texture upload is completed.
- * @return The signal to connect to.
- */
- UploadCompletedSignalType& UploadCompletedSignal();
-
- /**
- * @brief Rasterizes the current frame.
- * @return true if the animation is running, false otherwise.
- */
- bool Rasterize();
-
- /**
- * @brief Calculates the time for the next frame rasterization.
- * @return The time for the next frame rasterization.
- */
- std::chrono::time_point< std::chrono::system_clock > CalculateNextFrameTime( bool renderNow );
-
- /**
- * @brief Gets the time for the next frame rasterization.
- * @return The time for the next frame rasterization.
- */
- std::chrono::time_point< std::chrono::system_clock > GetNextFrameTime();
-
-private:
-
- /**
- * @brief Initializes the vector renderer.
- */
- void Initialize();
-
- /**
- * @brief Gets the frame number when the animation is stopped according to the stop behavior.
- */
- uint32_t GetStoppedFrame( uint32_t startFrame, uint32_t endFrame, uint32_t currentFrame );
-
- // Undefined
- VectorAnimationTask( const VectorAnimationTask& task ) = delete;
-
- // Undefined
- VectorAnimationTask& operator=( const VectorAnimationTask& task ) = delete;
-
-private:
-
- enum class PlayState
- {
- STOPPING, ///< The animation is stopping
- STOPPED, ///< The animation has stopped
- PLAYING, ///< The animation is playing
- PAUSED ///< The animation is paused
- };
-
- std::string mUrl;
- VectorAnimationRenderer mVectorRenderer;
- VectorAnimationThread& mVectorAnimationThread;
- ConditionalWait mConditionalWait;
- std::unique_ptr< EventThreadCallback > mAnimationFinishedTrigger;
- Vector2 mPlayRange;
- PlayState mPlayState;
- DevelImageVisual::StopBehavior::Type mStopBehavior;
- DevelImageVisual::LoopingMode::Type mLoopingMode;
- std::chrono::time_point< std::chrono::system_clock > mNextFrameStartTime;
- int64_t mFrameDurationNanoSeconds;
- float mFrameRate;
- uint32_t mCurrentFrame;
- uint32_t mTotalFrame;
- uint32_t mStartFrame;
- uint32_t mEndFrame;
- uint32_t mWidth;
- uint32_t mHeight;
- int32_t mLoopCount;
- int32_t mCurrentLoop;
- bool mResourceReady;
- bool mCurrentFrameUpdated;
- bool mCurrentLoopUpdated;
- bool mForward;
- bool mUpdateFrameNumber;
- bool mNeedAnimationFinishedTrigger;
-
-};
-
-} // namespace Internal
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // DALI_TOOLKIT_VECTOR_ANIMATION_TASK_H
+++ /dev/null
-/*
- * Copyright (c) 2019 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.
- *
- */
-
-// CLASS HEADER
-#include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.h>
-
-// EXTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/thread-settings.h>
-#include <dali/devel-api/adaptor-framework/environment-variable.h>
-#include <dali/integration-api/adaptors/adaptor.h>
-#include <dali/integration-api/debug.h>
-#include <thread>
-
-namespace Dali
-{
-
-namespace Toolkit
-{
-
-namespace Internal
-{
-
-namespace
-{
-
-constexpr auto DEFAULT_NUMBER_OF_RASTERIZE_THREADS = size_t{ 4u };
-constexpr auto NUMBER_OF_RASTERIZE_THREADS_ENV = "DALI_VECTOR_RASTERIZE_THREADS";
-
-size_t GetNumberOfThreads( const char* environmentVariable, size_t defaultValue )
-{
- using Dali::EnvironmentVariable::GetEnvironmentVariable;
- auto numberString = GetEnvironmentVariable( environmentVariable );
- auto numberOfThreads = numberString ? std::strtoul( numberString, nullptr, 10 ) : 0;
- constexpr auto MAX_NUMBER_OF_THREADS = 100u;
- DALI_ASSERT_DEBUG( numberOfThreads < MAX_NUMBER_OF_THREADS );
- return ( numberOfThreads > 0 && numberOfThreads < MAX_NUMBER_OF_THREADS ) ? numberOfThreads : defaultValue;
-}
-
-#if defined(DEBUG_ENABLED)
-Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_VECTOR_ANIMATION" );
-#endif
-
-} // unnamed namespace
-
-VectorAnimationThread::VectorAnimationThread()
-: mAnimationTasks(),
- mCompletedTasks(),
- mRasterizers( GetNumberOfThreads( NUMBER_OF_RASTERIZE_THREADS_ENV, DEFAULT_NUMBER_OF_RASTERIZE_THREADS ), [&]() { return RasterizeHelper( *this ); } ),
- mSleepThread( MakeCallback( this, &VectorAnimationThread::OnAwakeFromSleep ) ),
- mConditionalWait(),
- mNeedToSleep( false ),
- mDestroyThread( false ),
- mLogFactory( Dali::Adaptor::Get().GetLogFactory() )
-{
- mSleepThread.Start();
-}
-
-VectorAnimationThread::~VectorAnimationThread()
-{
- // Stop the thread
- {
- ConditionalWait::ScopedLock lock( mConditionalWait );
- mDestroyThread = true;
- mConditionalWait.Notify( lock );
- }
-
- DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationThread::~VectorAnimationThread: Join [%p]\n", this );
-
- Join();
-}
-
-void VectorAnimationThread::AddTask( VectorAnimationTaskPtr task )
-{
- ConditionalWait::ScopedLock lock( mConditionalWait );
-
- if( mAnimationTasks.end() == std::find( mAnimationTasks.begin(), mAnimationTasks.end(), task ) )
- {
- auto currentTime = task->CalculateNextFrameTime( true ); // Rasterize as soon as possible
-
- bool inserted = false;
- for( auto iter = mAnimationTasks.begin(); iter != mAnimationTasks.end(); ++iter )
- {
- auto nextTime = (*iter)->GetNextFrameTime();
- if( nextTime > currentTime )
- {
- mAnimationTasks.insert( iter, task );
- inserted = true;
- break;
- }
- }
-
- if( !inserted )
- {
- mAnimationTasks.push_back( task );
- }
-
- // wake up the animation thread
- mConditionalWait.Notify( lock );
- }
-}
-
-void VectorAnimationThread::OnTaskCompleted( VectorAnimationTaskPtr task, bool keepAnimation )
-{
- if( keepAnimation && !mDestroyThread )
- {
- ConditionalWait::ScopedLock lock( mConditionalWait );
-
- if( mAnimationTasks.end() == std::find( mAnimationTasks.begin(), mAnimationTasks.end(), task ) )
- {
- mCompletedTasks.push_back( task );
-
- // wake up the animation thread
- mConditionalWait.Notify( lock );
- }
- }
-}
-
-void VectorAnimationThread::OnAwakeFromSleep()
-{
- if( !mDestroyThread )
- {
- mNeedToSleep = false;
- // wake up the animation thread
- mConditionalWait.Notify();
- }
-}
-
-void VectorAnimationThread::Run()
-{
- SetThreadName( "VectorAnimationThread" );
- mLogFactory.InstallLogFunction();
-
- while( !mDestroyThread )
- {
- Rasterize();
- }
-}
-
-void VectorAnimationThread::Rasterize()
-{
- // Lock while popping task out from the queue
- ConditionalWait::ScopedLock lock( mConditionalWait );
-
- // conditional wait
- if( (mAnimationTasks.empty() && mCompletedTasks.empty() ) || mNeedToSleep )
- {
- mConditionalWait.Wait( lock );
- }
-
- mNeedToSleep = false;
-
- // Process completed tasks
- for( auto&& task : mCompletedTasks )
- {
- if( mAnimationTasks.end() == std::find( mAnimationTasks.begin(), mAnimationTasks.end(), task ) )
- {
- // Should use the frame rate of the animation file
- auto nextFrameTime = task->CalculateNextFrameTime( false );
-
- bool inserted = false;
- for( auto iter = mAnimationTasks.begin(); iter != mAnimationTasks.end(); ++iter )
- {
- auto time = (*iter)->GetNextFrameTime();
- if( time > nextFrameTime )
- {
- mAnimationTasks.insert( iter, task );
- inserted = true;
- break;
- }
- }
-
- if( !inserted )
- {
- mAnimationTasks.push_back( task );
- }
- }
- }
- mCompletedTasks.clear();
-
- // pop out the next task from the queue
- if( !mAnimationTasks.empty() && !mNeedToSleep )
- {
- std::vector< VectorAnimationTaskPtr >::iterator next = mAnimationTasks.begin();
- VectorAnimationTaskPtr nextTask = *next;
-
- auto currentTime = std::chrono::system_clock::now();
- auto nextFrameTime = nextTask->GetNextFrameTime();
-
-#if defined(DEBUG_ENABLED)
- auto duration = std::chrono::duration_cast< std::chrono::milliseconds >( nextFrameTime - currentTime );
-
- DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationThread::Rasterize: [next time = %lld]\n", duration.count() );
-#endif
-
- if( nextFrameTime <= currentTime )
- {
- mAnimationTasks.erase( next );
-
- auto rasterizerHelperIt = mRasterizers.GetNext();
- DALI_ASSERT_ALWAYS( rasterizerHelperIt != mRasterizers.End() );
-
- rasterizerHelperIt->Rasterize( nextTask );
- }
- else
- {
- mNeedToSleep = true;
- mSleepThread.SleepUntil( nextFrameTime );
- }
- }
-}
-
-VectorAnimationThread::RasterizeHelper::RasterizeHelper( VectorAnimationThread& animationThread )
-: RasterizeHelper( std::unique_ptr< VectorRasterizeThread >( new VectorRasterizeThread() ), animationThread )
-{
-}
-
-VectorAnimationThread::RasterizeHelper::RasterizeHelper( RasterizeHelper&& rhs )
-: RasterizeHelper( std::move( rhs.mRasterizer ), rhs.mAnimationThread )
-{
-}
-
-VectorAnimationThread::RasterizeHelper::RasterizeHelper( std::unique_ptr< VectorRasterizeThread > rasterizer, VectorAnimationThread& animationThread )
-: mRasterizer( std::move( rasterizer ) ),
- mAnimationThread( animationThread )
-{
- mRasterizer->SetCompletedCallback( MakeCallback( &mAnimationThread, &VectorAnimationThread::OnTaskCompleted ) );
-}
-
-void VectorAnimationThread::RasterizeHelper::Rasterize( VectorAnimationTaskPtr task )
-{
- if( task )
- {
- mRasterizer->AddTask( task );
- }
-}
-
-VectorAnimationThread::SleepThread::SleepThread( CallbackBase* callback )
-: mConditionalWait(),
- mAwakeCallback( std::unique_ptr< CallbackBase >( callback ) ),
- mSleepTimePoint(),
- mLogFactory( Dali::Adaptor::Get().GetLogFactory() ),
- mNeedToSleep( false ),
- mDestroyThread( false )
-{
-}
-
-VectorAnimationThread::SleepThread::~SleepThread()
-{
- // Stop the thread
- {
- ConditionalWait::ScopedLock lock( mConditionalWait );
- mDestroyThread = true;
- mConditionalWait.Notify( lock );
- }
-
- Join();
-}
-
-void VectorAnimationThread::SleepThread::SleepUntil( std::chrono::time_point< std::chrono::system_clock > timeToSleepUntil )
-{
- ConditionalWait::ScopedLock lock( mConditionalWait );
- mSleepTimePoint = timeToSleepUntil;
- mNeedToSleep = true;
- mConditionalWait.Notify( lock );
-}
-
-void VectorAnimationThread::SleepThread::Run()
-{
- SetThreadName( "VectorSleepThread" );
- mLogFactory.InstallLogFunction();
-
- while( !mDestroyThread )
- {
- bool needToSleep;
- std::chrono::time_point< std::chrono::system_clock > sleepTimePoint;
-
- {
- ConditionalWait::ScopedLock lock( mConditionalWait );
-
- needToSleep = mNeedToSleep;
- sleepTimePoint = mSleepTimePoint;
-
- mNeedToSleep = false;
- }
-
- if( needToSleep )
- {
-#if defined(DEBUG_ENABLED)
- auto sleepDuration = std::chrono::duration_cast< std::chrono::milliseconds >( mSleepTimePoint - std::chrono::system_clock::now() );
-
- DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationThread::SleepThread::Run: [sleep duration = %lld]\n", sleepDuration.count() );
-#endif
-
- std::this_thread::sleep_until( sleepTimePoint );
-
- if( mAwakeCallback )
- {
- CallbackBase::Execute( *mAwakeCallback );
- }
- }
-
- {
- ConditionalWait::ScopedLock lock( mConditionalWait );
- if( !mDestroyThread && !mNeedToSleep )
- {
- mConditionalWait.Wait( lock );
- }
- }
- }
-}
-
-} // namespace Internal
-
-} // namespace Toolkit
-
-} // namespace Dali
+++ /dev/null
-#ifndef DALI_TOOLKIT_VECTOR_ANIMATION_THREAD_H
-#define DALI_TOOLKIT_VECTOR_ANIMATION_THREAD_H
-
-/*
- * Copyright (c) 2019 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.
- */
-
-// EXTERNAL INCLUDES
-#include <dali/public-api/signals/connection-tracker.h>
-#include <dali/devel-api/threading/conditional-wait.h>
-#include <dali/devel-api/threading/thread.h>
-#include <dali/integration-api/adaptors/log-factory-interface.h>
-#include <memory>
-
-// INTERNAL INCLUDES
-#include <dali-toolkit/internal/helpers/round-robin-container-view.h>
-#include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h>
-#include <dali-toolkit/internal/visuals/animated-vector-image/vector-rasterize-thread.h>
-
-namespace Dali
-{
-
-namespace Toolkit
-{
-
-namespace Internal
-{
-
-/**
- * The main animation thread for vector animations
- */
-class VectorAnimationThread : public Thread
-{
-public:
-
- /**
- * @brief Constructor.
- */
- VectorAnimationThread();
-
- /**
- * @brief Destructor.
- */
- virtual ~VectorAnimationThread();
-
- /**
- * Add a animation task into the vector animation thread, called by main thread.
- *
- * @param[in] task The task added to the thread.
- */
- void AddTask( VectorAnimationTaskPtr task );
-
- /**
- * @brief Called when the rasterization is completed from the rasterize thread.
- * @param task The completed task
- */
- void OnTaskCompleted( VectorAnimationTaskPtr task, bool stopped );
-
- /**
- * @brief Called when the sleep thread is awaken.
- */
- void OnAwakeFromSleep();
-
-protected:
-
- /**
- * @brief The entry function of the animation thread.
- */
- void Run() override;
-
-private:
-
- /**
- * Rasterizes the tasks.
- */
- void Rasterize();
-
-private:
-
- /**
- * @brief Helper class to keep the relation between VectorRasterizeThread and corresponding container
- */
- class RasterizeHelper : public ConnectionTracker
- {
- public:
- /**
- * @brief Create an RasterizeHelper.
- *
- * @param[in] animationThread Reference to the VectorAnimationThread
- */
- RasterizeHelper( VectorAnimationThread& animationThread );
-
- /**
- * @brief Rasterizes the task.
- *
- * @param[in] task The task to rasterize.
- */
- void Rasterize( VectorAnimationTaskPtr task );
-
- public:
- RasterizeHelper( const RasterizeHelper& ) = delete;
- RasterizeHelper& operator=( const RasterizeHelper& ) = delete;
-
- RasterizeHelper( RasterizeHelper&& rhs );
- RasterizeHelper& operator=( RasterizeHelper&& rhs ) = delete;
-
- private:
-
- /**
- * @brief Main constructor that used by all other constructors
- */
- RasterizeHelper( std::unique_ptr< VectorRasterizeThread > rasterizer, VectorAnimationThread& animationThread );
-
- private:
- std::unique_ptr< VectorRasterizeThread > mRasterizer;
- VectorAnimationThread& mAnimationThread;
- };
-
- /**
- * @brief The thread to sleep until the next frame time.
- */
- class SleepThread : public Thread
- {
- public:
-
- /**
- * @brief Constructor.
- */
- SleepThread( CallbackBase* callback );
-
- /**
- * @brief Destructor.
- */
- virtual ~SleepThread();
-
- /**
- * @brief Sleeps untile the specified time point.
- */
- void SleepUntil( std::chrono::time_point< std::chrono::system_clock > timeToSleepUntil );
-
- protected:
-
- /**
- * @brief The entry function of the animation thread.
- */
- void Run() override;
-
- private:
-
- SleepThread( const SleepThread& thread ) = delete;
- SleepThread& operator=( const SleepThread& thread ) = delete;
-
- private:
- ConditionalWait mConditionalWait;
- std::unique_ptr< CallbackBase > mAwakeCallback;
- std::chrono::time_point< std::chrono::system_clock > mSleepTimePoint;
- const Dali::LogFactoryInterface& mLogFactory;
- bool mNeedToSleep;
- bool mDestroyThread;
- };
-
-private:
-
- // Undefined
- VectorAnimationThread( const VectorAnimationThread& thread ) = delete;
-
- // Undefined
- VectorAnimationThread& operator=( const VectorAnimationThread& thread ) = delete;
-
-private:
-
- std::vector< VectorAnimationTaskPtr > mAnimationTasks;
- std::vector< VectorAnimationTaskPtr > mCompletedTasks;
- RoundRobinContainerView< RasterizeHelper > mRasterizers;
- SleepThread mSleepThread;
- ConditionalWait mConditionalWait;
- bool mNeedToSleep;
- bool mDestroyThread;
- const Dali::LogFactoryInterface& mLogFactory;
-
-};
-
-} // namespace Internal
-
-} // namespace Toolkit
-
-} // namespace Dali
-
-#endif // #endif // DALI_TOOLKIT_VECTOR_ANIMATION_THREAD_H
namespace
{
+constexpr auto LOOP_FOREVER = -1;
+constexpr auto NANOSECONDS_PER_SECOND( 1e+9 );
+
#if defined(DEBUG_ENABLED)
Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_VECTOR_ANIMATION" );
#endif
+template< typename T >
+inline void ResetValue( bool& updated, T& value, T newValue, ConditionalWait& conditionalWait )
+{
+ ConditionalWait::ScopedLock lock( conditionalWait );
+ if( !updated )
+ {
+ value = newValue;
+ updated = true;
+ }
+}
+
} // unnamed namespace
-VectorRasterizeThread::VectorRasterizeThread()
-: mRasterizeTasks(),
+VectorRasterizeThread::VectorRasterizeThread( const std::string& url )
+: mUrl( url ),
+ mVectorRenderer(),
mConditionalWait(),
- mCompletedCallback(),
+ mAnimationFinishedTrigger(),
+ mPlayState( PlayState::STOPPED ),
+ mStopBehavior( DevelImageVisual::StopBehavior::CURRENT_FRAME ),
+ mLoopingMode( DevelImageVisual::LoopingMode::RESTART ),
+ mFrameDurationNanoSeconds( 0 ),
+ mFrameRate( 60.0f ),
+ mCurrentFrame( 0 ),
+ mTotalFrame( 0 ),
+ mStartFrame( 0 ),
+ mEndFrame( 0 ),
+ mWidth( 0 ),
+ mHeight( 0 ),
+ mLoopCount( LOOP_FOREVER ),
+ mCurrentLoop( 0 ),
+ mNeedRender( false ),
mDestroyThread( false ),
- mIsThreadStarted( false ),
+ mResourceReady( false ),
+ mCurrentFrameUpdated( false ),
+ mCurrentLoopUpdated( false ),
+ mForward( true ),
+ mUpdateFrameNumber( false ),
+ mNeedAnimationFinishedTrigger( true ),
mLogFactory( Dali::Adaptor::Get().GetLogFactory() )
{
+ Initialize();
}
VectorRasterizeThread::~VectorRasterizeThread()
Join();
}
-void VectorRasterizeThread::SetCompletedCallback( CallbackBase* callback )
+void VectorRasterizeThread::Run()
+{
+ SetThreadName( "VectorImageThread" );
+ mLogFactory.InstallLogFunction();
+
+ while( !mDestroyThread )
+ {
+ Rasterize();
+ }
+
+ DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Run: End of thread [%p]\n", this );
+}
+
+void VectorRasterizeThread::SetRenderer( Renderer renderer )
{
ConditionalWait::ScopedLock lock( mConditionalWait );
- mCompletedCallback = std::unique_ptr< CallbackBase >( callback );
+ mVectorRenderer.SetRenderer( renderer );
+
+ DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetRenderer [%p]\n", this );
}
-void VectorRasterizeThread::AddTask( VectorAnimationTaskPtr task )
+void VectorRasterizeThread::SetSize( uint32_t width, uint32_t height )
{
- if( !mIsThreadStarted )
+ if( mWidth != width || mHeight != height )
{
- Start();
- mIsThreadStarted = true;
+ ConditionalWait::ScopedLock lock( mConditionalWait );
+ mVectorRenderer.SetSize( width, height );
+
+ mWidth = width;
+ mHeight = height;
+
+ mResourceReady = false;
+
+ DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetSize: width = %d, height = %d [%p]\n", width, height, this );
}
+}
- // Lock while adding task to the queue
+void VectorRasterizeThread::PlayAnimation()
+{
ConditionalWait::ScopedLock lock( mConditionalWait );
- if( mRasterizeTasks.end() == std::find( mRasterizeTasks.begin(), mRasterizeTasks.end(), task ) )
+ if( mPlayState != PlayState::PLAYING )
{
- mRasterizeTasks.push_back( task );
+ mNeedRender = true;
+ mUpdateFrameNumber = false;
+ mPlayState = PlayState::PLAYING;
+ mConditionalWait.Notify( lock );
+
+ DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::PlayAnimation: Play [%p]\n", this );
+ }
+}
- // wake up the animation thread
+void VectorRasterizeThread::StopAnimation()
+{
+ ConditionalWait::ScopedLock lock( mConditionalWait );
+ if( mPlayState != PlayState::STOPPED && mPlayState != PlayState::STOPPING )
+ {
+ mNeedRender = true;
+ mNeedAnimationFinishedTrigger = false;
+ mPlayState = PlayState::STOPPING;
mConditionalWait.Notify( lock );
+
+ DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::StopAnimation: Stop [%p]\n", this );
}
}
-void VectorRasterizeThread::Run()
+void VectorRasterizeThread::PauseAnimation()
{
- SetThreadName( "VectorRasterizeThread" );
- mLogFactory.InstallLogFunction();
+ ConditionalWait::ScopedLock lock( mConditionalWait );
+ if( mPlayState == PlayState::PLAYING )
+ {
+ mPlayState = PlayState::PAUSED;
- while( !mDestroyThread )
+ DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::PauseAnimation: Pause [%p]\n", this );
+ }
+}
+
+void VectorRasterizeThread::RenderFrame()
+{
+ ConditionalWait::ScopedLock lock( mConditionalWait );
+
+ if( !mResourceReady )
{
- Rasterize();
+ mNeedRender = true;
+ mConditionalWait.Notify( lock );
+
+ DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::RenderFrame: Render [%p]\n", this );
+ }
+}
+
+void VectorRasterizeThread::SetAnimationFinishedCallback( EventThreadCallback* callback )
+{
+ ConditionalWait::ScopedLock lock( mConditionalWait );
+ mAnimationFinishedTrigger = std::unique_ptr< EventThreadCallback >( callback );
+}
+
+void VectorRasterizeThread::SetLoopCount( int32_t count )
+{
+ if( mLoopCount != count )
+ {
+ ConditionalWait::ScopedLock lock( mConditionalWait );
+
+ mLoopCount = count;
+ mCurrentLoop = 0;
+ mCurrentLoopUpdated = true;
+
+ DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetLoopCount: [%d] [%p]\n", count, this );
+ }
+}
+
+void VectorRasterizeThread::SetPlayRange( uint32_t startFrame, uint32_t endFrame )
+{
+ // Make sure the range specified is between 0 and the total frame number
+ if( ( startFrame < mTotalFrame ) && ( endFrame < mTotalFrame ) )
+ {
+ // If the range is not in order swap values
+ if( startFrame > endFrame )
+ {
+ uint32_t temp = startFrame;
+ startFrame = endFrame;
+ endFrame = temp;
+ }
+
+ if( startFrame != mStartFrame || endFrame != mEndFrame )
+ {
+ ConditionalWait::ScopedLock lock( mConditionalWait );
+
+ mStartFrame = startFrame;
+ mEndFrame = endFrame;
+
+ // If the current frame is out of the range, change the current frame also.
+ if( mStartFrame > mCurrentFrame )
+ {
+ mCurrentFrame = mStartFrame;
+
+ mCurrentFrameUpdated = true;
+ mResourceReady = false;
+ }
+ else if( mEndFrame < mCurrentFrame )
+ {
+ mCurrentFrame = mEndFrame;
+
+ mCurrentFrameUpdated = true;
+ mResourceReady = false;
+ }
+
+ DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetPlayRange: [%d, %d] [%p]\n", mStartFrame, mEndFrame, this );
+ }
+ }
+}
+
+DevelImageVisual::PlayState::Type VectorRasterizeThread::GetPlayState() const
+{
+ DevelImageVisual::PlayState::Type state = DevelImageVisual::PlayState::STOPPED;
+
+ switch( mPlayState )
+ {
+ case PlayState::PLAYING:
+ {
+ state = DevelImageVisual::PlayState::PLAYING;
+ break;
+ }
+ case PlayState::PAUSED:
+ {
+ state = DevelImageVisual::PlayState::PAUSED;
+ break;
+ }
+ case PlayState::STOPPING:
+ case PlayState::STOPPED:
+ {
+ state = DevelImageVisual::PlayState::STOPPED;
+ break;
+ }
}
+
+ return state;
+}
+
+bool VectorRasterizeThread::IsResourceReady() const
+{
+ return mResourceReady;
+}
+
+void VectorRasterizeThread::SetCurrentFrameNumber( uint32_t frameNumber )
+{
+ ConditionalWait::ScopedLock lock( mConditionalWait );
+
+ if( mCurrentFrame == frameNumber )
+ {
+ DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetCurrentFrameNumber: Set same frame [%d] [%p]\n", frameNumber, this );
+ return;
+ }
+
+ if( frameNumber >= mStartFrame && frameNumber <= mEndFrame )
+ {
+ mCurrentFrame = frameNumber;
+ mCurrentFrameUpdated = true;
+
+ mResourceReady = false;
+
+ DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetCurrentFrameNumber: frame number = %d [%p]\n", mCurrentFrame, this );
+ }
+ else
+ {
+ DALI_LOG_ERROR( "Invalid frame number [%d (%d, %d)]\n", frameNumber, mStartFrame, mEndFrame );
+ }
+}
+
+uint32_t VectorRasterizeThread::GetCurrentFrameNumber() const
+{
+ return mCurrentFrame;
+}
+
+uint32_t VectorRasterizeThread::GetTotalFrameNumber() const
+{
+ return mTotalFrame;
+}
+
+void VectorRasterizeThread::GetDefaultSize( uint32_t& width, uint32_t& height ) const
+{
+ mVectorRenderer.GetDefaultSize( width, height );
+}
+
+void VectorRasterizeThread::SetStopBehavior( DevelImageVisual::StopBehavior::Type stopBehavior )
+{
+ ConditionalWait::ScopedLock lock( mConditionalWait );
+ mStopBehavior = stopBehavior;
+
+ DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetStopBehavior: stop behavor = %d [%p]\n", mStopBehavior, this );
+}
+
+void VectorRasterizeThread::SetLoopingMode( DevelImageVisual::LoopingMode::Type loopingMode )
+{
+ ConditionalWait::ScopedLock lock( mConditionalWait );
+ mLoopingMode = loopingMode;
+
+ DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::SetLoopingMode: looping mode = %d [%p]\n", mLoopingMode, this );
+}
+
+VectorRasterizeThread::UploadCompletedSignalType& VectorRasterizeThread::UploadCompletedSignal()
+{
+ return mVectorRenderer.UploadCompletedSignal();
+}
+
+void VectorRasterizeThread::Initialize()
+{
+ mVectorRenderer = VectorAnimationRenderer::New( mUrl );
+
+ mTotalFrame = mVectorRenderer.GetTotalFrameNumber();
+
+ mEndFrame = mTotalFrame - 1;
+
+ mFrameRate = mVectorRenderer.GetFrameRate();
+ mFrameDurationNanoSeconds = NANOSECONDS_PER_SECOND / mFrameRate;
+
+ uint32_t width, height;
+ mVectorRenderer.GetDefaultSize( width, height );
+
+ SetSize( width, height );
+
+ DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Initialize: file = %s [%d frames, %f fps] [%p]\n", mUrl.c_str(), mTotalFrame, mFrameRate, this );
}
void VectorRasterizeThread::Rasterize()
{
- VectorAnimationTaskPtr nextTask;
+ bool stopped = false, needAnimationFinishedTrigger;
+ uint32_t currentFrame, startFrame, endFrame;
+ int32_t loopCount, currentLoopCount;
+
{
- // Lock while popping task out from the queue
ConditionalWait::ScopedLock lock( mConditionalWait );
- // conditional wait
- if( mRasterizeTasks.empty() )
+ if( ( mPlayState == PlayState::PAUSED || mPlayState == PlayState::STOPPED ) && !mNeedRender && !mDestroyThread )
{
+ DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Wait [%p]\n", this );
mConditionalWait.Wait( lock );
}
- // pop out the next task from the queue
- if( !mRasterizeTasks.empty() )
+ if( mPlayState == PlayState::PLAYING && mUpdateFrameNumber )
{
- std::vector< VectorAnimationTaskPtr >::iterator next = mRasterizeTasks.begin();
- nextTask = *next;
- mRasterizeTasks.erase( next );
+ mCurrentFrame = mForward ? mCurrentFrame + 1 : mCurrentFrame - 1;
}
+
+ currentFrame = mCurrentFrame;
+ startFrame = mStartFrame;
+ endFrame = mEndFrame;
+ loopCount = mLoopCount;
+ currentLoopCount = mCurrentLoop;
+ needAnimationFinishedTrigger = mNeedAnimationFinishedTrigger;
+
+ mResourceReady = true;
+ mNeedRender = false;
+ mCurrentFrameUpdated = false;
+ mCurrentLoopUpdated = false;
+ mUpdateFrameNumber = true;
+ mNeedAnimationFinishedTrigger = true;
}
- if( nextTask )
+ auto currentFrameStartTime = std::chrono::system_clock::now();
+
+ if( mPlayState == PlayState::STOPPING )
{
- bool keepAnimation = nextTask->Rasterize();
+ currentFrame = GetStoppedFrame( startFrame, endFrame, currentFrame );
+ ResetValue( mCurrentFrameUpdated, mCurrentFrame, currentFrame, mConditionalWait );
+
+ stopped = true;
+ }
+ else if( mPlayState == PlayState::PLAYING )
+ {
+ bool animationFinished = false;
+
+ if( currentFrame >= endFrame ) // last frame
+ {
+ if( mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE )
+ {
+ mForward = false;
+ }
+ else
+ {
+ if( loopCount < 0 || ++currentLoopCount < loopCount ) // repeat forever or before the last loop
+ {
+ ResetValue( mCurrentFrameUpdated, mCurrentFrame, startFrame, mConditionalWait ); // If the current frame is changed in the event thread, don't overwrite it.
+ mUpdateFrameNumber = false;
+ }
+ else
+ {
+ animationFinished = true; // end of animation
+ }
+ ResetValue( mCurrentLoopUpdated, mCurrentLoop, currentLoopCount, mConditionalWait );
+ }
+ }
+ else if( currentFrame == startFrame && !mForward ) // first frame
+ {
+ if( loopCount < 0 || ++currentLoopCount < loopCount ) // repeat forever or before the last loop
+ {
+ mForward = true;
+ }
+ else
+ {
+ animationFinished = true; // end of animation
+ }
+ ResetValue( mCurrentLoopUpdated, mCurrentLoop, currentLoopCount, mConditionalWait );
+ }
- if( mCompletedCallback )
+ if( animationFinished )
{
- CallbackBase::Execute( *mCompletedCallback, nextTask, keepAnimation );
+ if( mStopBehavior == DevelImageVisual::StopBehavior::CURRENT_FRAME )
+ {
+ stopped = true;
+ }
+ else
+ {
+ mPlayState = PlayState::STOPPING;
+ }
}
}
+
+ // Rasterize
+ if( !mVectorRenderer.Render( currentFrame ) )
+ {
+ DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Rendering failed. Try again later.[%d] [%p]\n", currentFrame, this );
+ mUpdateFrameNumber = false;
+ }
+
+ if( stopped )
+ {
+ mPlayState = PlayState::STOPPED;
+ mForward = true;
+ mCurrentLoop = 0;
+
+ // Animation is finished
+ if( needAnimationFinishedTrigger )
+ {
+ mAnimationFinishedTrigger->Trigger();
+ }
+
+ DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: Animation is finished [current = %d] [%p]\n", currentFrame, this );
+ }
+
+ auto timeToSleepUntil = currentFrameStartTime + std::chrono::nanoseconds( mFrameDurationNanoSeconds );
+
+#if defined(DEBUG_ENABLED)
+ auto sleepDuration = std::chrono::duration_cast< std::chrono::milliseconds >( timeToSleepUntil - std::chrono::system_clock::now() );
+
+ DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorRasterizeThread::Rasterize: [current = %d, sleep duration = %lld] [%p]\n", currentFrame, sleepDuration.count(), this );
+#endif
+
+ std::this_thread::sleep_until( timeToSleepUntil );
+}
+
+uint32_t VectorRasterizeThread::GetStoppedFrame( uint32_t startFrame, uint32_t endFrame, uint32_t currentFrame )
+{
+ uint32_t frame = currentFrame;
+
+ switch( mStopBehavior )
+ {
+ case DevelImageVisual::StopBehavior::FIRST_FRAME:
+ {
+ frame = startFrame;
+ break;
+ }
+ case DevelImageVisual::StopBehavior::LAST_FRAME:
+ {
+ if( mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE )
+ {
+ frame = startFrame;
+ }
+ else
+ {
+ frame = endFrame;
+ }
+ break;
+ }
+ case DevelImageVisual::StopBehavior::CURRENT_FRAME:
+ {
+ frame = currentFrame;
+ break;
+ }
+ }
+
+ return frame;
}
} // namespace Internal
#define DALI_TOOLKIT_VECTOR_IMAGE_RASTERIZE_THREAD_H
/*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2018 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.
*/
// EXTERNAL INCLUDES
-//#include <dali/devel-api/adaptor-framework/event-thread-callback.h>
+#include <dali/devel-api/adaptor-framework/event-thread-callback.h>
+#include <dali/devel-api/adaptor-framework/vector-animation-renderer.h>
#include <dali/devel-api/threading/conditional-wait.h>
+#include <dali/devel-api/threading/mutex.h>
#include <dali/devel-api/threading/thread.h>
#include <dali/integration-api/adaptors/log-factory-interface.h>
-#include <vector>
+#include <string>
#include <memory>
-//#include <string>
// INTERNAL INCLUDES
-#include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h>
+#include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
namespace Dali
{
{
public:
+ using UploadCompletedSignalType = Dali::VectorAnimationRenderer::UploadCompletedSignalType;
+
/**
* @brief Constructor.
+ *
+ * @param[in] url The url of the vector animation file
*/
- VectorRasterizeThread();
+ VectorRasterizeThread( const std::string& url );
/**
* @brief Destructor.
virtual ~VectorRasterizeThread();
/**
- * The callback is called from the rasterize thread after the rasterization is completed.
- * @param[in] callBack The function to call.
+ * @brief Sets the renderer used to display the result image.
+ *
+ * @param[in] renderer The renderer used to display the result image
*/
- void SetCompletedCallback( CallbackBase* callback );
+ void SetRenderer( Renderer renderer );
/**
- * Add a task to rasterize.
+ * @brief Sets the target image size.
*
- * @param[in] task The task to rasterize
+ * @param[in] width The target image width
+ * @param[in] height The target image height
+ */
+ void SetSize( uint32_t width, uint32_t height );
+
+ /**
+ * @brief Play the vector animation.
+ */
+ void PlayAnimation();
+
+ /**
+ * @brief Stop the vector animation.
+ */
+ void StopAnimation();
+
+ /**
+ * @brief Pause the vector animation.
+ */
+ void PauseAnimation();
+
+ /**
+ * @brief Render one frame. The current frame number will be increased.
*/
- void AddTask( VectorAnimationTaskPtr task );
+ void RenderFrame();
+
+ /**
+ * @brief This callback is called after the animation is finished.
+ * @param[in] callback The animation finished callback
+ */
+ void SetAnimationFinishedCallback( EventThreadCallback* callback );
+
+ /**
+ * @brief Enable looping for 'count' repeats. -1 means to repeat forever.
+ * @param[in] count The number of times to loop
+ */
+ void SetLoopCount( int32_t count );
+
+ /**
+ * @brief Set the playing range in frame number.
+ * @param[in] startFrame The frame number to specify minimum progress.
+ * @param[in] endFrame The frame number to specify maximum progress.
+ * The animation will play between those values.
+ */
+ void SetPlayRange( uint32_t startFrame, uint32_t endFrame );
+
+ /**
+ * @brief Get the play state
+ * @return The play state
+ */
+ DevelImageVisual::PlayState::Type GetPlayState() const;
+
+ /**
+ * @brief Queries whether the resource is ready.
+ * @return true if ready, false otherwise
+ */
+ bool IsResourceReady() const;
+
+ /**
+ * @brief Sets the current frame number of the animation.
+ * @param[in] frameNumber The new frame number between [0, the maximum frame number] or between the play range if specified.
+ */
+ void SetCurrentFrameNumber( uint32_t frameNumber );
+
+ /**
+ * @brief Retrieves the current frame number of the animation.
+ * @return The current frame number
+ */
+ uint32_t GetCurrentFrameNumber() const;
+
+ /**
+ * @brief Retrieves the total frame number of the animation.
+ * @return The total frame number
+ */
+ uint32_t GetTotalFrameNumber() const;
+
+ /**
+ * @brief Gets the default size of the file,.
+ * @return The default size of the file
+ */
+ void GetDefaultSize( uint32_t& width, uint32_t& height ) const;
+
+ /**
+ * @brief Sets the stop behavior of the animation. This is performed when the animation is stopped.
+ * @param[in] stopBehavior The stop behavior
+ */
+ void SetStopBehavior( DevelImageVisual::StopBehavior::Type stopBehavior );
+
+ /**
+ * @brief Sets the looping mode.
+ * Animation plays forwards and then restarts from the beginning or runs backwards again.
+ * @param[in] loopingMode The looping mode
+ */
+ void SetLoopingMode( DevelImageVisual::LoopingMode::Type loopingMode );
+
+ /**
+ * @brief Connect to this signal to be notified when the texture upload is completed.
+ * @return The signal to connect to.
+ */
+ UploadCompletedSignalType& UploadCompletedSignal();
protected:
private:
/**
- * Rasterizes the tasks.
+ * @brief Initializes the vector renderer.
+ */
+ void Initialize();
+
+ /**
+ * @brief Rasterizes the current frame.
*/
void Rasterize();
-private:
+ /**
+ * @brief Gets the frame number when the animation is stopped according to the stop behavior.
+ */
+ uint32_t GetStoppedFrame( uint32_t startFrame, uint32_t endFrame, uint32_t currentFrame );
// Undefined
VectorRasterizeThread( const VectorRasterizeThread& thread ) = delete;
private:
- std::vector< VectorAnimationTaskPtr > mRasterizeTasks;
- ConditionalWait mConditionalWait;
- std::unique_ptr< CallbackBase > mCompletedCallback;
- bool mDestroyThread; ///< Whether the thread be destroyed
- bool mIsThreadStarted;
- const Dali::LogFactoryInterface& mLogFactory; ///< The log factory
+ enum class PlayState
+ {
+ STOPPING, ///< The animation is stopping
+ STOPPED, ///< The animation has stopped
+ PLAYING, ///< The animation is playing
+ PAUSED ///< The animation is paused
+ };
+
+ std::string mUrl;
+ VectorAnimationRenderer mVectorRenderer;
+ ConditionalWait mConditionalWait;
+ std::unique_ptr< EventThreadCallback > mAnimationFinishedTrigger;
+ Vector2 mPlayRange;
+ PlayState mPlayState;
+ DevelImageVisual::StopBehavior::Type mStopBehavior;
+ DevelImageVisual::LoopingMode::Type mLoopingMode;
+ int64_t mFrameDurationNanoSeconds;
+ float mFrameRate;
+ uint32_t mCurrentFrame;
+ uint32_t mTotalFrame;
+ uint32_t mStartFrame;
+ uint32_t mEndFrame;
+ uint32_t mWidth;
+ uint32_t mHeight;
+ int32_t mLoopCount;
+ int32_t mCurrentLoop;
+ bool mNeedRender;
+ bool mDestroyThread; ///< Whether the thread be destroyed
+ bool mResourceReady;
+ bool mCurrentFrameUpdated;
+ bool mCurrentLoopUpdated;
+ bool mForward;
+ bool mUpdateFrameNumber;
+ bool mNeedAnimationFinishedTrigger;
+ const Dali::LogFactoryInterface& mLogFactory; ///< The log factory
};
VisualFactoryCache::VisualFactoryCache( bool preMultiplyOnLoad )
: mSvgRasterizeThread( NULL ),
- mVectorAnimationThread(),
mBrokenImageUrl(""),
mPreMultiplyOnLoad( preMultiplyOnLoad )
{
return mSvgRasterizeThread;
}
-VectorAnimationThread& VisualFactoryCache::GetVectorAnimationThread()
-{
- if( !mVectorAnimationThread )
- {
- mVectorAnimationThread = std::unique_ptr< VectorAnimationThread >( new VectorAnimationThread() );
- mVectorAnimationThread->Start();
- }
- return *mVectorAnimationThread;
-}
-
void VisualFactoryCache::ApplyRasterizedSVGToSampler()
{
while( RasterizingTaskPtr task = mSvgRasterizeThread->NextCompletedTask() )
#include <dali-toolkit/internal/visuals/npatch-loader.h>
#include <dali-toolkit/internal/visuals/svg/svg-rasterize-thread.h>
#include <dali-toolkit/internal/visuals/texture-manager-impl.h>
-#include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.h>
namespace Dali
{
*/
SvgRasterizeThread* GetSVGRasterizationThread();
- /**
- * Get the vector animation thread.
- * @return A raw pointer pointing to the vector animation thread.
- */
- VectorAnimationThread& GetVectorAnimationThread();
-
private: // for svg rasterization thread
/**
Geometry mGeometry[GEOMETRY_TYPE_MAX+1];
Shader mShader[SHADER_TYPE_MAX+1];
- ImageAtlasManagerPtr mAtlasManager;
- TextureManager mTextureManager;
- NPatchLoader mNPatchLoader;
- SvgRasterizeThread* mSvgRasterizeThread;
- std::unique_ptr< VectorAnimationThread > mVectorAnimationThread;
- std::string mBrokenImageUrl;
- bool mPreMultiplyOnLoad;
+ ImageAtlasManagerPtr mAtlasManager;
+ TextureManager mTextureManager;
+ NPatchLoader mNPatchLoader;
+ SvgRasterizeThread* mSvgRasterizeThread;
+ std::string mBrokenImageUrl;
+ bool mPreMultiplyOnLoad;
};
} // namespace Internal