From f1577bfbe8f0f6e1df4267f0808b9e6c93810dff Mon Sep 17 00:00:00 2001 From: "Seungho, Baek" Date: Thu, 12 Mar 2020 16:39:50 +0900 Subject: [PATCH] Add Jump_to frame and StopBehavior of Animated-image-visual(agif) - Added Jump_to action. To directly go to a frame. - Added StopBehavior to stop agif at the first, current, and last frame Change-Id: I76fe813fd694df89e8cc8748cc2a82b69ed7a613 Signed-off-by: Seungho, Baek --- .../dali-toolkit/utc-Dali-AnimatedImageVisual.cpp | 191 ++++++++++++++++++++- .../visuals/animated-image-visual-actions-devel.h | 5 +- .../visuals/image-visual-properties-devel.h | 4 +- .../animated-image/animated-image-visual.cpp | 130 +++++++++++--- .../visuals/animated-image/animated-image-visual.h | 4 +- .../visuals/animated-image/fixed-image-cache.cpp | 24 ++- .../visuals/animated-image/fixed-image-cache.h | 6 + .../internal/visuals/animated-image/image-cache.h | 10 +- .../animated-image/rolling-gif-image-cache.cpp | 43 ++++- .../animated-image/rolling-gif-image-cache.h | 8 +- .../visuals/animated-image/rolling-image-cache.cpp | 51 +++++- .../visuals/animated-image/rolling-image-cache.h | 6 + 12 files changed, 434 insertions(+), 48 deletions(-) diff --git a/automated-tests/src/dali-toolkit/utc-Dali-AnimatedImageVisual.cpp b/automated-tests/src/dali-toolkit/utc-Dali-AnimatedImageVisual.cpp index 082bbe0..bb591dd 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-AnimatedImageVisual.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-AnimatedImageVisual.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -159,6 +159,191 @@ int UtcDaliAnimatedImageVisualGetPropertyMap02(void) } +int UtcDaliAnimatedImageVisualJumpToAction(void) +{ + ToolkitTestApplication application; + TestGlAbstraction& gl = application.GetGlAbstraction(); + + Property::Array urls; + CopyUrlsIntoArray( urls ); + + { + Property::Map propertyMap; + propertyMap.Insert(Visual::Property::TYPE, Visual::IMAGE ); + propertyMap.Insert( ImageVisual::Property::URL, Property::Value(urls) ); + propertyMap.Insert( ImageVisual::Property::BATCH_SIZE, 4); + propertyMap.Insert( ImageVisual::Property::CACHE_SIZE, 12); + propertyMap.Insert( ImageVisual::Property::FRAME_DELAY, 20); + + VisualFactory factory = VisualFactory::Get(); + Visual::Base visual = factory.CreateVisual( propertyMap ); + + DummyControl dummyControl = DummyControl::New(true); + Impl::DummyControl& dummyImpl = static_cast(dummyControl.GetImplementation()); + dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual ); + + dummyControl.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); + Stage::GetCurrent().Add( dummyControl ); + application.SendNotification(); + application.Render(20); + + tet_infoline( "Ready the visual after the visual is on stage" ); + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 4 ), true, TEST_LOCATION ); + + tet_infoline( "Test that a timer has been started" ); + DALI_TEST_EQUALS( Test::GetTimerCount(), 1, TEST_LOCATION ); + + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + application.SendNotification(); + application.Render(20); + + DALI_TEST_EQUALS( gl.GetLastGenTextureId(), 4, TEST_LOCATION ); + + DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedImageVisual::Action::STOP, Property::Map() ); + + DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 4, TEST_LOCATION ); + + DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedImageVisual::Action::JUMP_TO, 20 ); + + DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 4, TEST_LOCATION ); + + DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedImageVisual::Action::JUMP_TO, 6 ); + + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 6 ), true, TEST_LOCATION ); + DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 4, TEST_LOCATION ); + + dummyControl.Unparent(); + } + tet_infoline("Test that removing the visual from stage deletes all textures"); + application.SendNotification(); + application.Render(16); + DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 0, TEST_LOCATION ); + + END_TEST; +} + + +int UtcDaliAnimatedImageVisualStopBehavior(void) +{ + ToolkitTestApplication application; + TestGlAbstraction& gl = application.GetGlAbstraction(); + + Property::Array urls; + CopyUrlsIntoArray( urls ); + + { + Property::Map propertyMap; + propertyMap.Insert( Visual::Property::TYPE, Visual::IMAGE ); + propertyMap.Insert( ImageVisual::Property::URL, Property::Value(urls) ); + propertyMap.Insert( DevelImageVisual::Property::STOP_BEHAVIOR, DevelImageVisual::StopBehavior::FIRST_FRAME); + propertyMap.Insert( ImageVisual::Property::BATCH_SIZE, 4); + propertyMap.Insert( ImageVisual::Property::CACHE_SIZE, 8); + propertyMap.Insert( ImageVisual::Property::FRAME_DELAY, 20); + + VisualFactory factory = VisualFactory::Get(); + Visual::Base visual = factory.CreateVisual( propertyMap ); + + // Expect that a batch of 4 textures has been requested. These will be serially loaded + // below. + + DummyControl dummyControl = DummyControl::New(true); + Impl::DummyControl& dummyImpl = static_cast(dummyControl.GetImplementation()); + dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual ); + + dummyControl.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); + Stage::GetCurrent().Add( dummyControl ); + application.SendNotification(); + application.Render(20); + + tet_infoline( "Ready the visual after the visual is on stage" ); + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 4 ), true, TEST_LOCATION ); + + tet_infoline( "Test that a timer has been started" ); + DALI_TEST_EQUALS( Test::GetTimerCount(), 1, TEST_LOCATION ); + + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + application.SendNotification(); + application.Render(20); + + DALI_TEST_EQUALS( gl.GetLastGenTextureId(), 4, TEST_LOCATION ); + + DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedImageVisual::Action::STOP, Property::Map() ); + + DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 4, TEST_LOCATION ); + + DevelControl::DoAction( dummyControl, DummyControl::Property::TEST_VISUAL, Dali::Toolkit::DevelAnimatedImageVisual::Action::JUMP_TO, 1 ); + + // Expect the second batch has been requested + DALI_TEST_EQUALS( Test::WaitForEventThreadTrigger( 4 ), true, TEST_LOCATION ); + + DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 4, TEST_LOCATION ); + + dummyControl.Unparent(); + } + tet_infoline("Test that removing the visual from stage deletes all textures"); + application.SendNotification(); + application.Render(16); + DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 0, TEST_LOCATION ); + + END_TEST; +} + + +int UtcDaliAnimatedImageVisualGif01(void) +{ + ToolkitTestApplication application; + TestGlAbstraction& gl = application.GetGlAbstraction(); + + { + Property::Map propertyMap; + propertyMap.Insert(Visual::Property::TYPE, Visual::ANIMATED_IMAGE ); + propertyMap.Insert( ImageVisual::Property::URL, TEST_GIF_FILE_NAME ); + propertyMap.Insert( ImageVisual::Property::BATCH_SIZE, 2); + propertyMap.Insert( ImageVisual::Property::CACHE_SIZE, 4); + propertyMap.Insert( ImageVisual::Property::FRAME_DELAY, 20); + + VisualFactory factory = VisualFactory::Get(); + Visual::Base visual = factory.CreateVisual( propertyMap ); + + // Expect that a batch of 4 textures has been requested. These will be serially loaded + // below. + + DummyControl dummyControl = DummyControl::New(true); + Impl::DummyControl& dummyImpl = static_cast(dummyControl.GetImplementation()); + dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual ); + + dummyControl.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); + Stage::GetCurrent().Add( dummyControl ); + application.SendNotification(); + application.Render(20); + + DALI_TEST_EQUALS( gl.GetLastGenTextureId(), 2, TEST_LOCATION ); + + tet_infoline( "Test that a timer has been started" ); + + TraceCallStack& textureTrace = gl.GetTextureTrace(); + textureTrace.Enable(true); + + Test::EmitGlobalTimerSignal(); + + application.SendNotification(); + application.Render(20); + + DALI_TEST_EQUALS( gl.GetLastGenTextureId(), 4, TEST_LOCATION ); + + dummyControl.Unparent(); + } + tet_infoline("Test that removing the visual from stage deletes all textures"); + application.SendNotification(); + application.Render(20); + DALI_TEST_EQUALS( gl.GetNumGeneratedTextures(), 0, TEST_LOCATION ); + + END_TEST; +} int UtcDaliAnimatedImageVisualMultiImage01(void) @@ -574,6 +759,10 @@ void TestLoopCount( ToolkitTestApplication &application, DummyControl &dummyCont { for ( uint16_t j = 0; j < frameCount; j++ ) { + if( i == 0 && j == 0 ) + { + continue; // Because first frame is already showed and we call 2nd frame at the first time of timer animation. + } tet_printf( "Test that after %u ticks, and we have %u frame \n", j + 1u, j + 1u ); Test::EmitGlobalTimerSignal(); application.SendNotification(); diff --git a/dali-toolkit/devel-api/visuals/animated-image-visual-actions-devel.h b/dali-toolkit/devel-api/visuals/animated-image-visual-actions-devel.h index b654a69..4218045 100644 --- a/dali-toolkit/devel-api/visuals/animated-image-visual-actions-devel.h +++ b/dali-toolkit/devel-api/visuals/animated-image-visual-actions-devel.h @@ -2,7 +2,7 @@ #define DALI_TOOLKIT_DEVEL_API_VISUALS_ANIMATED_IMAGE_VISUAL_ACTIONS_DEVEL_H /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -39,7 +39,8 @@ enum Type { PLAY, ///< Play the animated GIF. This is also Default playback mode. PAUSE, ///< Pause the animated GIF. - STOP ///< Stop the animated GIF. + STOP, ///< Stop the animated GIF. + JUMP_TO ///< Jump to the specified frame. Property::INTEGER value should be passed. }; } // namespace Action diff --git a/dali-toolkit/devel-api/visuals/image-visual-properties-devel.h b/dali-toolkit/devel-api/visuals/image-visual-properties-devel.h index 5419799..e6e5303 100644 --- a/dali-toolkit/devel-api/visuals/image-visual-properties-devel.h +++ b/dali-toolkit/devel-api/visuals/image-visual-properties-devel.h @@ -2,7 +2,7 @@ #define DALI_TOOLKIT_DEVEL_API_VISUALS_IMAGE_VISUAL_PROPERTIES_DEVEL_H /* - * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -122,7 +122,7 @@ enum Type TOTAL_FRAME_NUMBER = ORIENTATION_CORRECTION + 7, /** - * @brief The stop behavior the AnimatedVectorImageVisual will use. + * @brief The stop behavior the AnimatedImageVisual and AnimatedVectorImageVisual will use. * @details Name "stopBehavior", Type StopBehavior::Type (Property::INTEGER) * @note Default value is StopBehavior::CURRENT_FRAME. */ diff --git a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp index b1463ba..a0ebe45 100755 --- a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp +++ b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -49,6 +49,13 @@ namespace Internal namespace { +// stop behavior +DALI_ENUM_TO_STRING_TABLE_BEGIN( STOP_BEHAVIOR ) +DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::Toolkit::DevelImageVisual::StopBehavior, CURRENT_FRAME ) +DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::Toolkit::DevelImageVisual::StopBehavior, FIRST_FRAME ) +DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::Toolkit::DevelImageVisual::StopBehavior, LAST_FRAME ) +DALI_ENUM_TO_STRING_TABLE_END( STOP_BEHAVIOR ) + // wrap modes DALI_ENUM_TO_STRING_TABLE_BEGIN( WRAP_MODE ) DALI_ENUM_TO_STRING_WITH_SCOPE( Dali::WrapMode, DEFAULT ) @@ -182,7 +189,9 @@ AnimatedImageVisual::AnimatedImageVisual( VisualFactoryCache& factoryCache, Imag mWrapModeU( WrapMode::DEFAULT ), mWrapModeV( WrapMode::DEFAULT ), mActionStatus( DevelAnimatedImageVisual::Action::PLAY ), - mStartFirstFrame(false) + mStopBehavior( DevelImageVisual::StopBehavior::CURRENT_FRAME ), + mStartFirstFrame(false), + mIsJumpTo( false ) {} AnimatedImageVisual::~AnimatedImageVisual() @@ -238,6 +247,8 @@ void AnimatedImageVisual::DoCreatePropertyMap( Property::Map& map ) const map.Insert( Toolkit::ImageVisual::Property::CACHE_SIZE, static_cast(mCacheSize) ); map.Insert( Toolkit::ImageVisual::Property::FRAME_DELAY, static_cast(mFrameDelay) ); map.Insert( Toolkit::DevelImageVisual::Property::LOOP_COUNT, static_cast(mLoopCount) ); + + map.Insert( Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, mStopBehavior ); } void AnimatedImageVisual::DoCreateInstancePropertyMap( Property::Map& map ) const @@ -270,8 +281,32 @@ void AnimatedImageVisual::OnDoAction( const Dali::Property::Index actionId, cons { // STOP reset functionality will actually be done in a future change // Stop will be executed on next timer tick - mCurrentFrameIndex = 0; mActionStatus = DevelAnimatedImageVisual::Action::STOP; + if( IsOnStage() ) + { + DisplayNextFrame(); + } + break; + } + case DevelAnimatedImageVisual::Action::JUMP_TO: + { + int32_t frameNumber; + if( attributes.Get( frameNumber ) ) + { + if( frameNumber < 0 || frameNumber >= static_cast( mFrameCount ) ) + { + DALI_LOG_ERROR( "Invalid frame index used.\n" ); + } + else + { + mIsJumpTo = true; + mCurrentFrameIndex = frameNumber; + if( IsOnStage() ) + { + DisplayNextFrame(); + } + } + } break; } } @@ -318,6 +353,10 @@ void AnimatedImageVisual::DoSetProperties( const Property::Map& propertyMap ) { DoSetProperty( Toolkit::DevelImageVisual::Property::LOOP_COUNT, keyValue.second ); } + else if( keyValue.first == STOP_BEHAVIOR_NAME ) + { + DoSetProperty( Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR, keyValue.second ); + } } } } @@ -398,6 +437,16 @@ void AnimatedImageVisual::DoSetProperty( Property::Index index, } break; } + + case Toolkit::DevelImageVisual::Property::STOP_BEHAVIOR: + { + int32_t stopBehavior = mStopBehavior; + if( Scripting::GetEnumerationProperty( value, STOP_BEHAVIOR_TABLE, STOP_BEHAVIOR_TABLE_COUNT, stopBehavior ) ) + { + mStopBehavior = DevelImageVisual::StopBehavior::Type( stopBehavior ); + } + break; + } } } @@ -518,7 +567,7 @@ void AnimatedImageVisual::LoadFirstBatch() if (!mImageCache) { - DALI_LOG_ERROR("mImageCache is null"); + DALI_LOG_ERROR("mImageCache is null\n"); } } @@ -606,45 +655,75 @@ void AnimatedImageVisual::FrameReady( TextureSet textureSet ) bool AnimatedImageVisual::DisplayNextFrame() { - if( mActionStatus == DevelAnimatedImageVisual::Action::STOP || mActionStatus == DevelAnimatedImageVisual::Action::PAUSE ) + if( mIsJumpTo ) + { + mIsJumpTo = false; + } + else if( mActionStatus == DevelAnimatedImageVisual::Action::PAUSE ) { return false; } - if( mFrameCount > 1 ) + else if( mActionStatus == DevelAnimatedImageVisual::Action::STOP ) { - // Wrap the frame index - ++mCurrentFrameIndex; - - if( mLoopCount < 0 || mCurrentLoopIndex < mLoopCount) + mCurrentLoopIndex = 0; + if( mStopBehavior == DevelImageVisual::StopBehavior::FIRST_FRAME ) { - mCurrentFrameIndex %= mFrameCount; - if( mCurrentFrameIndex == 0 ) - { - ++mCurrentLoopIndex; - } + mCurrentFrameIndex = 0; + } + else if( mStopBehavior == DevelImageVisual::StopBehavior::LAST_FRAME ) + { + mCurrentFrameIndex = mFrameCount - 1; } else { - // This will stop timer - return false; + return false; // Do not draw already rendered scene twice. } } - DALI_LOG_INFO( gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::DisplayNextFrame(this:%p) FrameCount:%d\n", this, mCurrentFrameIndex); - - if( mFrameDelayContainer.Count() > 0 ) + else { - unsigned int delay = mFrameDelayContainer[mCurrentFrameIndex]; + if( mFrameCount > 1 ) + { + // Wrap the frame index + bool finished = false; + ++mCurrentFrameIndex; + if( mCurrentFrameIndex >= mFrameCount ) + { + ++mCurrentLoopIndex; + finished = true; + } - if( mFrameDelayTimer.GetInterval() != delay ) + if( mLoopCount < 0 || mCurrentLoopIndex < mLoopCount) + { + if( finished ) + { + mCurrentFrameIndex = 0; // Back to the first frame + } + } + else + { + // This will stop timer + mActionStatus = DevelAnimatedImageVisual::Action::STOP; + return DisplayNextFrame(); + } + } + + if( mFrameDelayContainer.Count() > 0 ) { - mFrameDelayTimer.SetInterval( delay ); + unsigned int delay = mFrameDelayContainer[mCurrentFrameIndex]; + + if( mFrameDelayTimer.GetInterval() != delay ) + { + mFrameDelayTimer.SetInterval( delay ); + } } } + DALI_LOG_INFO( gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::DisplayNextFrame(this:%p) CurrentFrameIndex:%d\n", this, mCurrentFrameIndex); + TextureSet textureSet; if( mImageCache ) { - textureSet = mImageCache->NextFrame(); + textureSet = mImageCache->Frame( mCurrentFrameIndex ); if( textureSet ) { SetImageSize( textureSet ); @@ -652,8 +731,7 @@ bool AnimatedImageVisual::DisplayNextFrame() } } - // Keep timer ticking - return true; + return ( mActionStatus == DevelAnimatedImageVisual::Action::PLAY ) ? true : false; } diff --git a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.h b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.h index 791783d..0d21f97 100755 --- a/dali-toolkit/internal/visuals/animated-image/animated-image-visual.h +++ b/dali-toolkit/internal/visuals/animated-image/animated-image-visual.h @@ -2,7 +2,7 @@ #define DALI_TOOLKIT_INTERNAL_ANIMATED_IMAGE_VISUAL_H /* - * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -265,7 +265,9 @@ private: Dali::WrapMode::Type mWrapModeU:3; Dali::WrapMode::Type mWrapModeV:3; DevelAnimatedImageVisual::Action::Type mActionStatus:3; + DevelImageVisual::StopBehavior::Type mStopBehavior:2; bool mStartFirstFrame:1; + bool mIsJumpTo:1; }; } // namespace Internal diff --git a/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp b/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp index 9acf1af..d71ee94 100644 --- a/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp +++ b/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp @@ -54,6 +54,27 @@ FixedImageCache::~FixedImageCache() } } +TextureSet FixedImageCache::Frame( uint32_t frameIndex ) +{ + while( frameIndex > mFront ) + { + NextFrame(); + } + mFront = frameIndex; + + TextureSet textureSet; + if( IsFrontReady() == true ) + { + textureSet = GetFrontTextureSet(); + } + else + { + mWaitingForReadyFrame = true; + } + + return textureSet; +} + TextureSet FixedImageCache::FirstFrame() { TextureSet textureSet = GetFrontTextureSet(); @@ -80,7 +101,6 @@ TextureSet FixedImageCache::NextFrame() { mWaitingForReadyFrame = true; } - LoadBatch(); return textureSet; @@ -96,7 +116,7 @@ void FixedImageCache::LoadBatch() // Try and load up to mBatchSize images, until the cache is filled. // Once the cache is filled, mUrlIndex exceeds mImageUrls size and // no more images are loaded. - bool frontFrameReady = IsFrontReady();; + bool frontFrameReady = IsFrontReady(); for( unsigned int i=0; i< mBatchSize && mUrlIndex < mImageUrls.size(); ++i ) { diff --git a/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h b/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h index 72484a4..d884e28 100644 --- a/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h +++ b/dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h @@ -49,6 +49,12 @@ public: virtual ~FixedImageCache(); /** + * Get the Nth frame. If it's not ready, this will trigger the + * sending of FrameReady() when the image becomes ready. + */ + TextureSet Frame( uint32_t frameIndex ) override; + + /** * Get the first frame. If it's not ready, this will trigger the * sending of FrameReady() when the image becomes ready. */ diff --git a/dali-toolkit/internal/visuals/animated-image/image-cache.h b/dali-toolkit/internal/visuals/animated-image/image-cache.h index ef1efed..7354992 100644 --- a/dali-toolkit/internal/visuals/animated-image/image-cache.h +++ b/dali-toolkit/internal/visuals/animated-image/image-cache.h @@ -2,7 +2,7 @@ #define DALI_TOOLKIT_INTERNAL_IMAGE_CACHE_H /* - * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -46,7 +46,7 @@ public: struct UrlStore { - TextureManager::TextureId mTextureId; + TextureManager::TextureId mTextureId = TextureManager::INVALID_TEXTURE_ID; std::string mUrl; }; @@ -85,6 +85,12 @@ public: */ virtual TextureSet NextFrame() = 0; + /** + * Get the Nth frame. If it's not ready, this will trigger the + * sending of FrameReady() when the image becomes ready. + */ + virtual TextureSet Frame( uint32_t frameIndex ) = 0; + private: /** diff --git a/dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.cpp b/dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.cpp index 4854076..04f0f1d 100644 --- a/dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.cpp +++ b/dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -84,16 +84,49 @@ RollingGifImageCache::~RollingGifImageCache() } } +TextureSet RollingGifImageCache::Frame( uint32_t frameIndex ) +{ + // If a frame of frameIndex is not loaded, clear the queue and remove all loaded textures. + if( mImageUrls[ frameIndex ].mTextureId == TextureManager::INVALID_TEXTURE_ID ) + { + mFrameIndex = frameIndex; + while( !mQueue.IsEmpty() ) + { + ImageFrame imageFrame = mQueue.PopFront(); + Dali::Toolkit::TextureManager::RemoveTexture( mImageUrls[ imageFrame.mFrameNumber ].mUrl ); + mImageUrls[ imageFrame.mFrameNumber ].mTextureId = TextureManager::INVALID_TEXTURE_ID; + } + LoadBatch(); + } + // If the frame is already loaded, remove previous frames of the frame in the queue + // and load new frames amount of removed frames. + else + { + bool popExist = false; + while( !mQueue.IsEmpty() && mQueue.Front().mFrameNumber != frameIndex ) + { + ImageFrame imageFrame = mQueue.PopFront(); + Dali::Toolkit::TextureManager::RemoveTexture( mImageUrls[ imageFrame.mFrameNumber ].mUrl ); + mImageUrls[ imageFrame.mFrameNumber ].mTextureId = TextureManager::INVALID_TEXTURE_ID; + popExist = true; + } + if( popExist ) + { + mFrameIndex = ( mQueue.Back().mFrameNumber + 1 ) % mFrameCount; + LoadBatch(); + } + } + + return GetFrontTextureSet(); +} TextureSet RollingGifImageCache::FirstFrame() { - return GetFrontTextureSet(); + return Frame( 0u ); } TextureSet RollingGifImageCache::NextFrame() { - TextureSet textureSet; - ImageFrame imageFrame = mQueue.PopFront(); Dali::Toolkit::TextureManager::RemoveTexture( mImageUrls[ imageFrame.mFrameNumber ].mUrl ); mImageUrls[ imageFrame.mFrameNumber ].mTextureId = TextureManager::INVALID_TEXTURE_ID; @@ -120,7 +153,7 @@ void RollingGifImageCache::LoadBatch() int batchSize = std::min( std::size_t(mBatchSize), mCacheSize - mQueue.Count() ); DALI_LOG_INFO( gAnimImgLogFilter, Debug::Concise, "RollingGifImageCache::LoadBatch() mFrameIndex:%d batchSize:%d\n", mFrameIndex, batchSize ); - if( mGifLoading.LoadNextNFrames( mFrameIndex, batchSize, pixelDataList) ) + if( mGifLoading.LoadNextNFrames( mFrameIndex, batchSize, pixelDataList) ) { unsigned int pixelDataListCount = pixelDataList.size(); diff --git a/dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.h b/dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.h index 981274c..91a1210 100644 --- a/dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.h +++ b/dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.h @@ -2,7 +2,7 @@ #define DALI_TOOLKIT_INTERNAL_ROLLING_GIF_IMAGE_CACHE_H /* - * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * Copyright (c) 2020 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. @@ -65,6 +65,12 @@ public: virtual ~RollingGifImageCache(); /** + * Get the Nth frame. If it's not ready, this will trigger the + * sending of FrameReady() when the image becomes ready. + */ + TextureSet Frame( uint32_t frameIndex ) override; + + /** * Get the first frame. If it's not ready, this will trigger the * sending of FrameReady() when the image becomes ready. */ diff --git a/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp b/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp index b7b45ff..21f81b7 100644 --- a/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp +++ b/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp @@ -80,11 +80,45 @@ RollingImageCache::~RollingImageCache() } } -TextureSet RollingImageCache::FirstFrame() +TextureSet RollingImageCache::Frame( uint32_t frameIndex ) { - TextureSet textureSet = GetFrontTextureSet(); + // If a frame of frameIndex is not loaded, clear the queue and remove all loaded textures. + if( mImageUrls[ frameIndex ].mTextureId == TextureManager::INVALID_TEXTURE_ID ) + { + mUrlIndex = frameIndex; + while( !mQueue.IsEmpty() ) + { + ImageFrame imageFrame = mQueue.PopFront(); + mTextureManager.Remove( mImageUrls[ imageFrame.mUrlIndex ].mTextureId, this ); + mImageUrls[ imageFrame.mUrlIndex ].mTextureId = TextureManager::INVALID_TEXTURE_ID; + } + LoadBatch(); + } + // If the frame is already loaded, remove previous frames of the frame in the queue + // and load new frames amount of removed frames. + else + { + bool popExist = false; + while( !mQueue.IsEmpty() && mQueue.Front().mUrlIndex != frameIndex ) + { + ImageFrame imageFrame = mQueue.PopFront(); + mTextureManager.Remove( mImageUrls[ imageFrame.mUrlIndex ].mTextureId, this ); + mImageUrls[ imageFrame.mUrlIndex ].mTextureId = TextureManager::INVALID_TEXTURE_ID; + popExist = true; + } + if( popExist ) + { + mUrlIndex = ( mQueue.Back().mUrlIndex + 1 ) % mImageUrls.size(); + LoadBatch(); + } + } - if( ! textureSet ) + TextureSet textureSet; + if( IsFrontReady() == true ) + { + textureSet = GetFrontTextureSet(); + } + else { mWaitingForReadyFrame = true; } @@ -92,6 +126,11 @@ TextureSet RollingImageCache::FirstFrame() return textureSet; } +TextureSet RollingImageCache::FirstFrame() +{ + return Frame( 0u ); +} + TextureSet RollingImageCache::NextFrame() { TextureSet textureSet; @@ -100,6 +139,8 @@ TextureSet RollingImageCache::NextFrame() mTextureManager.Remove( mImageUrls[ imageFrame.mUrlIndex ].mTextureId, this ); mImageUrls[ imageFrame.mUrlIndex ].mTextureId = TextureManager::INVALID_TEXTURE_ID; + LoadBatch(); + if( IsFrontReady() == true ) { textureSet = GetFrontTextureSet(); @@ -109,8 +150,6 @@ TextureSet RollingImageCache::NextFrame() mWaitingForReadyFrame = true; } - LoadBatch(); - return textureSet; } @@ -124,7 +163,7 @@ void RollingImageCache::LoadBatch() // Try and load up to mBatchSize images, until the cache is filled. // Once the cache is filled, as frames progress, the old frame is // cleared, but not erased, and another image is loaded - bool frontFrameReady = IsFrontReady();; + bool frontFrameReady = IsFrontReady(); for( unsigned int i=0; i< mBatchSize && !mQueue.IsFull(); ++i ) { diff --git a/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h b/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h index a0d734d..47a5155 100644 --- a/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h +++ b/dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h @@ -60,6 +60,12 @@ public: virtual ~RollingImageCache(); /** + * Get the Nth frame. If it's not ready, this will trigger the + * sending of FrameReady() when the image becomes ready. + */ + TextureSet Frame( uint32_t frameIndex ) override; + + /** * Get the first frame. If it's not ready, this will trigger the * sending of FrameReady() when the image becomes ready. */ -- 2.7.4