Removed Texture Atlas for the GIF image. 70/159570/26
authorUmar <m.umar@partner.samsung.com>
Thu, 9 Nov 2017 20:48:49 +0000 (20:48 +0000)
committerUmar <m.umar@partner.samsung.com>
Fri, 22 Dec 2017 16:38:54 +0000 (16:38 +0000)
Added new RollingGifImageCache for animated images.

Change-Id: Idda4fecb7f4c5303f459a9e6b18222fdb3c83a41

17 files changed:
automated-tests/src/dali-toolkit/utc-Dali-VisualFactory.cpp
dali-toolkit/internal/file.list
dali-toolkit/internal/visuals/animated-image/animated-image-visual.cpp [changed mode: 0644->0755]
dali-toolkit/internal/visuals/animated-image/animated-image-visual.h
dali-toolkit/internal/visuals/animated-image/fixed-image-cache.cpp
dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h
dali-toolkit/internal/visuals/animated-image/image-cache.cpp
dali-toolkit/internal/visuals/animated-image/image-cache.h
dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.cpp [new file with mode: 0644]
dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.h [new file with mode: 0644]
dali-toolkit/internal/visuals/animated-image/rolling-image-cache.cpp
dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h
dali-toolkit/internal/visuals/texture-manager-impl.cpp
dali-toolkit/internal/visuals/texture-manager-impl.h
dali-toolkit/internal/visuals/visual-base-impl.cpp [changed mode: 0644->0755]
dali-toolkit/internal/visuals/visual-url.cpp
dali-toolkit/internal/visuals/visual-url.h

index 54a45a3..9556968 100644 (file)
@@ -1905,14 +1905,14 @@ int UtcDaliVisualFactoryGetAnimatedImageVisual1(void)
   ToolkitTestApplication application;
   tet_infoline( "UtcDaliVisualFactoryGetAnimatedImageVisual1: Request animated image visual with a gif url" );
 
-  VisualFactory factory = VisualFactory::Get();
-  Visual::Base visual = factory.CreateVisual( TEST_GIF_FILE_NAME, ImageDimensions() );
-  DALI_TEST_CHECK( visual );
-
   TestGlAbstraction& gl = application.GetGlAbstraction();
   TraceCallStack& textureTrace = gl.GetTextureTrace();
   textureTrace.Enable(true);
 
+  VisualFactory factory = VisualFactory::Get();
+  Visual::Base visual = factory.CreateVisual( TEST_GIF_FILE_NAME, ImageDimensions() );
+  DALI_TEST_CHECK( visual );
+
   DummyControl actor = DummyControl::New(true);
   DummyControlImpl& dummyImpl = static_cast<DummyControlImpl&>(actor.GetImplementation());
   dummyImpl.RegisterVisual( DummyControl::Property::TEST_VISUAL, visual );
@@ -1924,54 +1924,34 @@ int UtcDaliVisualFactoryGetAnimatedImageVisual1(void)
 
   // renderer is added to actor
   DALI_TEST_CHECK( actor.GetRendererCount() == 1u );
-
-  // test the uniforms which used to handle the atlas rect
-  // the four frames should be located inside atlas as follows: atlas size 100*100
-  // -------------
-  // |     |     |
-  // |  0  |  1  |
-  // -------------
-  // |     |     |
-  // |  2  |  3  |
-  // -------------
-
   Renderer renderer = actor.GetRendererAt( 0u );
   DALI_TEST_CHECK( renderer );
 
-  Property::Value atlasRectValue = renderer.GetProperty( renderer.GetPropertyIndex( "uAtlasRect" ) );
-  // take into consideration the half pixel correction
-  DALI_TEST_EQUALS( atlasRectValue.Get<Vector4>(), Vector4(0.5f, 0.5f, 49.5f, 49.5f)/100.f, Math::MACHINE_EPSILON_100, TEST_LOCATION );
-
-  // waiting for the resource uploading
-  application.SendNotification();
-  application.Render();
-
-  DALI_TEST_EQUALS( textureTrace.FindMethod("BindTexture"), true, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  textureTrace.Reset();
 
   // Force the timer used by the animatedImageVisual to tick,
   Dali::Timer timer = Timer::New( 0 );
   timer.MockEmitSignal();
   application.SendNotification();
   application.Render();
-  atlasRectValue = renderer.GetProperty( renderer.GetPropertyIndex( "uAtlasRect" ) );
-  // take into consideration the half pixel correction
-  DALI_TEST_EQUALS( atlasRectValue.Get<Vector4>(), Vector4(50.5f, 0.5f, 99.5f, 49.5f)/100.f, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  textureTrace.Reset();
+
 
   // Force the timer used by the animatedImageVisual to tick,
   timer.MockEmitSignal();
   application.SendNotification();
   application.Render();
-  atlasRectValue = renderer.GetProperty( renderer.GetPropertyIndex( "uAtlasRect" ) );
-  // take into consideration the half pixel correction
-  DALI_TEST_EQUALS( atlasRectValue.Get<Vector4>(), Vector4(0.5f, 50.5f, 49.5f, 99.5f)/100.f, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  textureTrace.Reset();
 
   // Force the timer used by the animatedImageVisual to tick,
   timer.MockEmitSignal();
   application.SendNotification();
   application.Render();
-  atlasRectValue = renderer.GetProperty( renderer.GetPropertyIndex( "uAtlasRect" ) );
-  // take into consideration the half pixel correction
-  DALI_TEST_EQUALS( atlasRectValue.Get<Vector4>(), Vector4(50.5f, 50.5f, 99.5f, 99.5f)/100.f, Math::MACHINE_EPSILON_100, TEST_LOCATION );
+  DALI_TEST_EQUALS( textureTrace.FindMethod("GenTextures"), true, TEST_LOCATION );
+  textureTrace.Reset();
 
   // Test SetOffStage().
   actor.Unparent();
index b5c1aaf..a83612d 100755 (executable)
@@ -15,6 +15,7 @@ toolkit_src_files = \
    $(toolkit_src_dir)/visuals/animated-image/image-cache.cpp \
    $(toolkit_src_dir)/visuals/animated-image/fixed-image-cache.cpp \
    $(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/border/border-visual.cpp \
    $(toolkit_src_dir)/visuals/color/color-visual.cpp \
    $(toolkit_src_dir)/visuals/gradient/gradient-visual.cpp \
old mode 100644 (file)
new mode 100755 (executable)
index 9ac0b90..84ae1c9
@@ -19,9 +19,9 @@
 #include "animated-image-visual.h"
 
 // EXTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/gif-loading.h>
 #include <dali/devel-api/adaptor-framework/image-loading.h>
 #include <dali/integration-api/debug.h>
+#include <memory>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/public-api/visuals/image-visual-properties.h>
 #include <dali-toolkit/internal/visuals/visual-base-data-impl.h>
 #include <dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h>
 #include <dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h>
+#include <dali-toolkit/internal/visuals/animated-image/rolling-gif-image-cache.h>
 #include <dali-toolkit/internal/visuals/image/image-visual.h>
 #include <dali-toolkit/devel-api/image-loader/image-atlas.h>
+#include <dali-toolkit/devel-api/image-loader/texture-manager.h>
 
 namespace Dali
 {
@@ -65,12 +67,17 @@ Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "
 /**
  * Multi-image  Flow of execution
  *
- *   | DoSetProperties()
+ *   | New
+ *   |   DoSetProperties()
  *   |   LoadFirstBatch()
- *   |     cache->LoadBatch()
+ *   |     new cache
+ *   |       cache->LoadBatch()
  *   |
  *   | DoSetOnStage()
+ *   |   PrepareTextureSet()
+ *   |     cache->FirstFrame()
  *   |   CreateRenderer()    (Doesn't become ready until first frame loads)
+ *   |   StartFirstFrame()
  *   |
  *   | FrameReady(textureSet)
  *   |   start first frame:
@@ -94,16 +101,21 @@ Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "
 
 AnimatedImageVisualPtr AnimatedImageVisual::New( VisualFactoryCache& factoryCache, const VisualUrl& imageUrl, const Property::Map& properties )
 {
-  AnimatedImageVisual* visual = new AnimatedImageVisual( factoryCache );
-  visual->mImageUrl = imageUrl;
+  AnimatedImageVisualPtr visual( new AnimatedImageVisual( factoryCache ) );
+  visual->InitializeGif( imageUrl );
   visual->SetProperties( properties );
 
+  if( visual->mFrameCount > 0 )
+  {
+    visual->LoadFirstBatch();
+  }
+
   return visual;
 }
 
 AnimatedImageVisualPtr AnimatedImageVisual::New( VisualFactoryCache& factoryCache, const Property::Array& imageUrls, const Property::Map& properties )
 {
-  AnimatedImageVisual* visual = new AnimatedImageVisual( factoryCache );
+  AnimatedImageVisualPtr visual( new AnimatedImageVisual( factoryCache ) );
   visual->mImageUrls = new ImageCache::UrlList();
   visual->mImageUrls->reserve( imageUrls.Count() );
 
@@ -114,26 +126,45 @@ AnimatedImageVisualPtr AnimatedImageVisual::New( VisualFactoryCache& factoryCach
     urlStore.mUrl = imageUrls[i].Get<std::string>();
     visual->mImageUrls->push_back( urlStore );
   }
-
+  visual->mFrameCount = imageUrls.Count();
   visual->SetProperties( properties );
-  // starts loading immediately
+
+  if( visual->mFrameCount > 0 )
+  {
+    visual->LoadFirstBatch();
+  }
+
   return visual;
 }
 
 AnimatedImageVisualPtr AnimatedImageVisual::New( VisualFactoryCache& factoryCache, const VisualUrl& imageUrl )
 {
-  AnimatedImageVisual* visual = new AnimatedImageVisual( factoryCache );
-  visual->mImageUrl = imageUrl;
+  AnimatedImageVisualPtr visual( new AnimatedImageVisual( factoryCache ) );
+  visual->InitializeGif( imageUrl );
+
+  if( visual->mFrameCount > 0 )
+  {
+    visual->LoadFirstBatch();
+  }
 
   return visual;
 }
 
+void AnimatedImageVisual::InitializeGif( const VisualUrl& imageUrl )
+{
+  mImageUrl = imageUrl;
+  mGifLoading = GifLoading::New( imageUrl.GetUrl() );
+  mFrameCount = mGifLoading->GetImageCount();
+  mGifLoading->LoadFrameDelays( mFrameDelayContainer );
+}
+
 AnimatedImageVisual::AnimatedImageVisual( VisualFactoryCache& factoryCache )
 : Visual::Base( factoryCache ),
   mFrameDelayTimer(),
   mPlacementActor(),
   mPixelArea( FULL_TEXTURE_RECT ),
   mImageUrl(),
+  mGifLoading( nullptr ),
   mCurrentFrameIndex( 0 ),
   mImageUrls( NULL ),
   mImageCache( NULL ),
@@ -141,6 +172,7 @@ AnimatedImageVisual::AnimatedImageVisual( VisualFactoryCache& factoryCache )
   mBatchSize( 1 ),
   mFrameDelay( 100 ),
   mUrlIndex( 0 ),
+  mFrameCount( 0 ),
   mImageSize(),
   mWrapModeU( WrapMode::DEFAULT ),
   mWrapModeV( WrapMode::DEFAULT ),
@@ -159,7 +191,7 @@ void AnimatedImageVisual::GetNaturalSize( Vector2& naturalSize )
   {
     if( mImageUrl.IsValid() )
     {
-      mImageSize = Dali::GetGifImageSize( mImageUrl.GetUrl() );
+      mImageSize = mGifLoading->GetImageSize();
     }
     else if( mImageUrls && mImageUrls->size() > 0 )
     {
@@ -245,11 +277,6 @@ void AnimatedImageVisual::DoSetProperties( const Property::Map& propertyMap )
       }
     }
   }
-
-  if( mImageUrls && mImageUrls->size() > 0 )
-  {
-    LoadFirstBatch();
-  }
 }
 
 void AnimatedImageVisual::DoSetProperty( Property::Index index,
@@ -347,9 +374,6 @@ void AnimatedImageVisual::DoSetOffStage( Actor& actor )
     mFrameDelayTimer.Reset();
   }
 
-  mTextureRectContainer.Clear();
-  mFrameDelayContainer.Clear();
-
   actor.RemoveRenderer( mImpl->mRenderer );
   mImpl->mRenderer.Reset();
   mPlacementActor.Reset();
@@ -366,7 +390,7 @@ void AnimatedImageVisual::OnSetTransform()
 void AnimatedImageVisual::CreateRenderer()
 {
   bool defaultWrapMode = mWrapModeU <= WrapMode::CLAMP_TO_EDGE && mWrapModeV <= WrapMode::CLAMP_TO_EDGE;
-  bool atlasing = (mTextureRectContainer.Count() > 0) ;
+  bool atlasing = false;
   Shader shader = ImageVisual::GetImageShader( mFactoryCache, atlasing, defaultWrapMode );
 
   Geometry geometry = mFactoryCache.GetGeometry( VisualFactoryCache::QUAD_GEOMETRY );
@@ -389,27 +413,38 @@ void AnimatedImageVisual::CreateRenderer()
   }
 
   mCurrentFrameIndex = 0;
-
-  if( mTextureRectContainer.Count() > 0 )
-  {
-    mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mTextureRectContainer[mCurrentFrameIndex] );
-  }
 }
 
 void AnimatedImageVisual::LoadFirstBatch()
 {
-  DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::LoadFirstBatch()\n");
-
   // Ensure the batch size and cache size are no bigger than the number of URLs,
   // and that the cache is at least as big as the batch size.
-  uint16_t numUrls = mImageUrls->size();
-  uint16_t batchSize = std::min( mBatchSize, numUrls );
-  uint16_t cacheSize = std::min( std::max( batchSize, mCacheSize ), numUrls );
+  uint16_t numUrls = 0;
+  uint16_t batchSize = 1;
+  uint16_t cacheSize = 1;
+
+  if( mImageUrls )
+  {
+    numUrls = mImageUrls->size();
+  }
+  else
+  {
+    numUrls = mFrameCount;
+  }
+
+  batchSize = std::min( mBatchSize, numUrls );
+  cacheSize = std::min( std::max( batchSize, mCacheSize ), numUrls );
+
+  DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::LoadFirstBatch()  batchSize:%d  cacheSize:%d\n", batchSize, cacheSize);
 
   mUrlIndex = 0;
   TextureManager& textureManager = mFactoryCache.GetTextureManager();
 
-  if( batchSize > 0 && cacheSize > 0 )
+  if( mGifLoading != nullptr )
+  {
+    mImageCache = new RollingGifImageCache( textureManager, *mGifLoading, mFrameCount, *this, cacheSize, batchSize );
+  }
+  else if( batchSize > 0 && cacheSize > 0 )
   {
     if( cacheSize < numUrls )
     {
@@ -424,6 +459,10 @@ void AnimatedImageVisual::LoadFirstBatch()
   {
     mImageCache = new RollingImageCache( textureManager, *mImageUrls, *this, 1, 1 );
   }
+  if (!mImageCache)
+  {
+    DALI_LOG_ERROR("mImageCache is null");
+  }
 }
 
 void AnimatedImageVisual::StartFirstFrame( TextureSet& textureSet )
@@ -439,55 +478,37 @@ void AnimatedImageVisual::StartFirstFrame( TextureSet& textureSet )
     mPlacementActor.Reset();
   }
 
-  int frameDelay = mFrameDelay;
-  if( mFrameDelayContainer.Count() > 1 )
+  mCurrentFrameIndex = 0;
+
+  if( mFrameCount > 1 )
   {
-    frameDelay = mFrameDelayContainer[0];
-  }
-  mFrameDelayTimer = Timer::New( frameDelay );
-  mFrameDelayTimer.TickSignal().Connect( this, &AnimatedImageVisual::DisplayNextFrame );
-  mFrameDelayTimer.Start();
+    int frameDelay = mFrameDelay; // from URL array
+    if( mFrameDelayContainer.Count() > 0 ) // from GIF
+    {
+      frameDelay = mFrameDelayContainer[0];
+    }
 
-  DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"ResourceReady()\n");
+    mFrameDelayTimer = Timer::New( frameDelay );
+    mFrameDelayTimer.TickSignal().Connect( this, &AnimatedImageVisual::DisplayNextFrame );
+    mFrameDelayTimer.Start();
+  }
+  DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"ResourceReady(ResourceStatus::READY)\n");
   ResourceReady( Toolkit::Visual::ResourceStatus::READY );
 }
 
 TextureSet AnimatedImageVisual::PrepareTextureSet()
 {
   TextureSet textureSet;
-  if( mImageUrl.IsValid() )
+  if (mImageCache)
+    textureSet = mImageCache->FirstFrame();
+  if( textureSet )
   {
-    textureSet = PrepareAnimatedGifImage();
+    SetImageSize( textureSet );
   }
   else
   {
-    textureSet = mImageCache->FirstFrame();
-    if( textureSet )
-    {
-      SetImageSize( textureSet );
-    }
-  }
-  return textureSet;
-}
-
-TextureSet AnimatedImageVisual::PrepareAnimatedGifImage()
-{
-  TextureSet textureSet;
-
-  // load from image file
-  std::vector<Dali::PixelData> pixelDataList;
-
-  if( mImageUrl.IsLocalResource() )
-  {
-    if( Dali::LoadAnimatedGifFromFile( mImageUrl.GetUrl().c_str() , pixelDataList, mFrameDelayContainer ) )
-    {
-      mImageSize.SetWidth( pixelDataList[0].GetWidth() );
-      mImageSize.SetHeight( pixelDataList[0].GetHeight() );
-
-      Texture texture = Toolkit::ImageAtlas::PackToAtlas( pixelDataList, mTextureRectContainer );
-      textureSet = TextureSet::New();
-      textureSet.SetTexture( 0, texture );
-    }
+    DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"ResourceReady(ResourceStatus::FAILED)\n");
+    ResourceReady( Toolkit::Visual::ResourceStatus::FAILED );
   }
 
   return textureSet;
@@ -522,29 +543,31 @@ void AnimatedImageVisual::FrameReady( TextureSet textureSet )
 
 bool AnimatedImageVisual::DisplayNextFrame()
 {
-  DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::DisplayNextFrame() start\n");
-
-  if( mFrameDelayContainer.Count() > 0 )
+  if( mFrameCount > 1 )
   {
     // Wrap the frame index
     ++mCurrentFrameIndex;
-    mCurrentFrameIndex %= mFrameDelayContainer.Count();
+    mCurrentFrameIndex %= mFrameCount;
+  }
+  DALI_LOG_INFO( gAnimImgLogFilter,Debug::Concise,"AnimatedImageVisual::DisplayNextFrame(this:%p) FrameCount:%d\n", this, mCurrentFrameIndex);
 
-    mImpl->mRenderer.RegisterProperty( ATLAS_RECT_UNIFORM_NAME, mTextureRectContainer[mCurrentFrameIndex] );
+  if( mFrameDelayContainer.Count() > 0 )
+  {
+    unsigned int delay = mFrameDelayContainer[mCurrentFrameIndex];
 
-    if( mFrameDelayTimer.GetInterval() != mFrameDelayContainer[mCurrentFrameIndex] )
+    if( mFrameDelayTimer.GetInterval() != delay )
     {
-      mFrameDelayTimer.SetInterval( mFrameDelayContainer[mCurrentFrameIndex] );
+      mFrameDelayTimer.SetInterval( delay );
     }
   }
-  else if( mImageCache )
+
+  TextureSet textureSet;
+  if (mImageCache)
+    textureSet = mImageCache->NextFrame();
+  if( textureSet )
   {
-    TextureSet textureSet = mImageCache->NextFrame();
-    if( textureSet )
-    {
-      SetImageSize( textureSet );
-      mImpl->mRenderer.SetTextures( textureSet );
-    }
+    SetImageSize( textureSet );
+    mImpl->mRenderer.SetTextures( textureSet );
   }
 
   // Keep timer ticking
index 1e71ba1..5c9b31c 100644 (file)
@@ -24,6 +24,7 @@
 #include <dali/public-api/math/vector4.h>
 #include <dali/public-api/object/weak-handle.h>
 #include <dali/public-api/adaptor-framework/timer.h>
+#include <dali/devel-api/adaptor-framework/gif-loading.h>
 
 // INTERNAL INCLUDES
 #include <dali-toolkit/internal/visuals/visual-base-impl.h>
@@ -184,6 +185,7 @@ private:
   /**
    * Adds the texture set to the renderer, and the renderer to the
    * placement actor, and starts the frame timer
+   * @param[in] textureSet The texture set to apply
    */
   void StartFirstFrame( TextureSet& textureSet );
 
@@ -193,18 +195,14 @@ private:
   TextureSet PrepareTextureSet();
 
   /**
-   * Load the gif image and pack the frames into atlas.
-   * @return The atlas texture.
-   */
-  TextureSet PrepareAnimatedGifImage();
-
-  /**
    * Set the image size from the texture set
+   * @param[in] textureSet The texture set to get the size from
    */
   void SetImageSize( TextureSet& textureSet );
 
   /**
    * Called when the next frame is ready.
+   * @param[in] textureSet the texture set to apply
    */
   void FrameReady( TextureSet textureSet );
 
@@ -214,6 +212,11 @@ private:
    */
   bool DisplayNextFrame();
 
+  /**
+   * Initialize the gif variables.
+   * @param[in] imageUrl The url of the animated gif
+   */
+  void InitializeGif( const VisualUrl& imageUrl );
 
   // Undefined
   AnimatedImageVisual( const AnimatedImageVisual& animatedImageVisual );
@@ -227,10 +230,10 @@ private:
   WeakHandle<Actor> mPlacementActor;
 
   // Variables for GIF player
-  Dali::Vector<Vector4> mTextureRectContainer;
   Dali::Vector<uint32_t> mFrameDelayContainer;
   Vector4 mPixelArea;
   VisualUrl mImageUrl;
+  std::unique_ptr<Dali::GifLoading> mGifLoading; // Only needed for animated gifs
   uint32_t mCurrentFrameIndex; // Frame index into textureRects
 
   // Variables for Multi-Image player
@@ -242,6 +245,7 @@ private:
   uint16_t mUrlIndex;
 
   // Shared variables
+  uint32_t mFrameCount; // Number of frames
   ImageDimensions mImageSize;
 
   Dali::WrapMode::Type mWrapModeU:3;
index 03dbcbc..3764500 100644 (file)
@@ -17,6 +17,9 @@
 // CLASS HEADER
 #include <dali-toolkit/internal/visuals/animated-image/fixed-image-cache.h>
 
+// INTERNAL HEADERS
+#include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
+
 namespace Dali
 {
 namespace Toolkit
@@ -32,7 +35,8 @@ const bool ENABLE_ORIENTATION_CORRECTION( true );
 FixedImageCache::FixedImageCache(
   TextureManager& textureManager, UrlList& urlList, ImageCache::FrameReadyObserver& observer,
   unsigned int batchSize )
-: ImageCache( textureManager, urlList, observer, batchSize ),
+: ImageCache( textureManager, observer, batchSize ),
+  mImageUrls( urlList ),
   mFront(0u)
 {
   mReadyFlags.reserve( mImageUrls.size() );
@@ -102,10 +106,26 @@ void FixedImageCache::LoadBatch()
     // need to account for this inside the UploadComplete method using mRequestingLoad.
     mRequestingLoad = true;
 
-    mImageUrls[ mUrlIndex ].mTextureId =
-      mTextureManager.RequestLoad( url, ImageDimensions(), FittingMode::SCALE_TO_FILL,
-                                   SamplingMode::BOX_THEN_LINEAR, TextureManager::NO_ATLAS,
-                                   this, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED  );
+    bool synchronousLoading = false;
+    bool atlasingStatus = false;
+    bool loadingStatus = false;
+    TextureManager::MaskingDataPointer maskInfo = nullptr;
+    AtlasUploadObserver* atlasObserver = nullptr;
+    ImageAtlasManagerPtr imageAtlasManager = nullptr;
+    Vector4 textureRect;
+
+    mTextureManager.LoadTexture(
+      url, ImageDimensions(), FittingMode::SCALE_TO_FILL,
+      SamplingMode::BOX_THEN_LINEAR, maskInfo,
+      synchronousLoading, mImageUrls[ mUrlIndex ].mTextureId, textureRect,
+      atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT,
+      Dali::WrapMode::Type::DEFAULT, this,
+      atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED );
+
+    if( loadingStatus == false )  // not loading, means it's already ready.
+    {
+      SetImageFrameReady( mImageUrls[ mUrlIndex ].mTextureId );
+    }
     mRequestingLoad = false;
     ++mUrlIndex;
   }
index 4c59447..b9b2ddb 100644 (file)
@@ -28,7 +28,7 @@ namespace Toolkit
 namespace Internal
 {
 
-class FixedImageCache : public ImageCache
+class FixedImageCache : public ImageCache, public TextureUploadObserver
 {
 public:
   /**
@@ -97,7 +97,8 @@ protected:
     bool           useAtlasing,
     const Vector4& atlasRect );
 
-protected:
+private:
+  std::vector<UrlStore>& mImageUrls;
   std::vector<bool> mReadyFlags;
   unsigned int      mFront;
 };
index 1d0db6f..84e5f66 100644 (file)
@@ -24,12 +24,10 @@ namespace Internal
 {
 
 ImageCache::ImageCache( TextureManager&                 textureManager,
-                        UrlList&                        urlList,
                         ImageCache::FrameReadyObserver& observer,
                         unsigned int                    batchSize )
 : mTextureManager( textureManager ),
   mObserver( observer ),
-  mImageUrls( urlList ),
   mBatchSize( batchSize ),
   mUrlIndex(0u),
   mWaitingForReadyFrame(false),
index 12e89e9..1a7ae75 100644 (file)
@@ -28,7 +28,7 @@ namespace Toolkit
 namespace Internal
 {
 
-class ImageCache : public TextureUploadObserver
+class ImageCache
 {
 public:
   /**
@@ -67,7 +67,6 @@ public:
    * batch and cache sizes. The cache is as large as the number of urls.
    */
   ImageCache( TextureManager&                 textureManager,
-              UrlList&                        urlList,
               ImageCache::FrameReadyObserver& observer,
               unsigned int                    batchSize );
 
@@ -89,7 +88,6 @@ public:
 protected:
   TextureManager&        mTextureManager;
   FrameReadyObserver&    mObserver;
-  std::vector<UrlStore>& mImageUrls;
   unsigned int           mBatchSize;
   unsigned int           mUrlIndex;
   bool                   mWaitingForReadyFrame:1;
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
new file mode 100644 (file)
index 0000000..5922f74
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include "rolling-gif-image-cache.h"
+
+// EXTERNAL HEADERS
+
+// INTERNAL HEADERS
+#include <dali-toolkit/devel-api/image-loader/texture-manager.h>
+#include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
+#include <dali/integration-api/debug.h>
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gAnimImgLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ANIMATED_IMAGE");
+
+#define LOG_CACHE                                                       \
+  {                                                                     \
+    std::ostringstream oss;                                             \
+    oss<<"Size:"<<mQueue.Count()<<" [ ";                                \
+    for(std::size_t _i=0; _i<mQueue.Count(); ++_i)                      \
+    {                                                                   \
+      oss<<_i<<                                                         \
+        "={ frm#: " << mQueue[_i].mFrameNumber <<                        \
+           " tex: " << mImageUrls[mQueue[_i].mFrameNumber].mTextureId<<"}, ";  \
+    }                                                                   \
+    oss<<" ]"<<std::endl;                                               \
+    DALI_LOG_INFO(gAnimImgLogFilter,Debug::Concise,"%s",oss.str().c_str()); \
+  }
+
+#else
+  #define LOG_CACHE
+#endif
+
+const bool ENABLE_ORIENTATION_CORRECTION( true );
+
+}
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+RollingGifImageCache::RollingGifImageCache(
+  TextureManager& textureManager, GifLoading& gifLoading, uint32_t frameCount, ImageCache::FrameReadyObserver& observer,
+  uint16_t cacheSize, uint16_t batchSize )
+: ImageCache( textureManager, observer, batchSize ),
+  mGifLoading( gifLoading ),
+  mFrameCount( frameCount ),
+  mFrameIndex( 0 ),
+  mCacheSize( cacheSize ),
+  mQueue( cacheSize )
+{
+  mImageUrls.resize( mFrameCount );
+  LoadBatch();
+}
+
+RollingGifImageCache::~RollingGifImageCache()
+{
+  while( !mQueue.IsEmpty() )
+  {
+    ImageFrame imageFrame = mQueue.PopFront();
+    Dali::Toolkit::TextureManager::RemoveTexture( mImageUrls[ imageFrame.mFrameNumber ].mUrl );
+  }
+}
+
+TextureSet RollingGifImageCache::FirstFrame()
+{
+  return GetFrontTextureSet();
+}
+
+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;
+
+  LoadBatch();
+
+  return GetFrontTextureSet();
+}
+
+bool RollingGifImageCache::IsFrontReady() const
+{
+  return ( !mQueue.IsEmpty() );
+}
+
+void RollingGifImageCache::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
+  // removed, and another frame is loaded
+
+  std::vector<Dali::PixelData> pixelDataList;
+
+  // Get the smallest number of frames we need to load
+  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) )
+  {
+    unsigned int pixelDataListCount = pixelDataList.size();
+
+    for( unsigned int i = 0; i < pixelDataListCount && !mQueue.IsFull(); ++i )
+    {
+      ImageFrame imageFrame;
+
+      // create the texture for uploading the pixel data
+      Texture texture = Texture::New( Dali::TextureType::TEXTURE_2D,
+                                      pixelDataList[i].GetPixelFormat(),
+                                      pixelDataList[i].GetWidth(),
+                                      pixelDataList[i].GetHeight() );
+
+      texture.Upload( pixelDataList[i] );
+
+      mImageUrls[ mUrlIndex ].mUrl = Dali::Toolkit::TextureManager::AddTexture(texture);
+      imageFrame.mFrameNumber = mUrlIndex;
+
+      ++mUrlIndex;
+      mUrlIndex %= mImageUrls.size();
+
+      mQueue.PushBack( imageFrame );
+
+      bool synchronousLoading = false;
+      bool atlasingStatus = false;
+      bool loadingStatus = false;
+      TextureManager::MaskingDataPointer maskInfo = nullptr;
+      AtlasUploadObserver* atlasObserver = nullptr;
+      ImageAtlasManagerPtr imageAtlasManager = nullptr;
+      Vector4 textureRect;
+
+      mTextureManager.LoadTexture(
+        mImageUrls[ imageFrame.mFrameNumber ].mUrl, ImageDimensions(), FittingMode::SCALE_TO_FILL,
+        SamplingMode::BOX_THEN_LINEAR, maskInfo,
+        synchronousLoading, mImageUrls[ imageFrame.mFrameNumber ].mTextureId, textureRect,
+        atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT,
+        Dali::WrapMode::Type::DEFAULT, NULL,
+        atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED );
+    }
+
+    mFrameIndex += batchSize;
+    mFrameIndex %= mFrameCount;
+  }
+
+  LOG_CACHE;
+}
+
+TextureSet RollingGifImageCache::GetFrontTextureSet() const
+{
+  DALI_LOG_INFO( gAnimImgLogFilter, Debug::Concise, "RollingGifImageCache::GetFrontTextureSet() FrameNumber:%d\n", mQueue[ 0 ].mFrameNumber );
+
+  TextureManager::TextureId textureId = GetCachedTextureId( 0 );
+  return mTextureManager.GetTextureSet( textureId );
+}
+
+TextureManager::TextureId RollingGifImageCache::GetCachedTextureId( int index ) const
+{
+  return mImageUrls[ mQueue[ index ].mFrameNumber ].mTextureId;
+}
+
+} //namespace Internal
+} //namespace Toolkit
+} //namespace Dali
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
new file mode 100644 (file)
index 0000000..778eeda
--- /dev/null
@@ -0,0 +1,123 @@
+#ifndef DALI_TOOLKIT_INTERNAL_ROLLING_GIF_IMAGE_CACHE_H
+#define DALI_TOOLKIT_INTERNAL_ROLLING_GIF_IMAGE_CACHE_H
+
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/gif-loading.h>
+#include <dali/devel-api/common/circular-queue.h>
+#include <dali-toolkit/internal/visuals/animated-image/image-cache.h>
+#include <dali-toolkit/internal/visuals/texture-manager-impl.h>
+
+namespace Dali
+{
+namespace Toolkit
+{
+namespace Internal
+{
+
+/**
+ * Class to manage a rolling cache of GIF images, where the cache size
+ * is smaller than the total number of images.
+ *
+ * Frames are always ready, so the observer.FrameReady callback is never triggered;
+ * the FirstFrame and NextFrame APIs will always return a texture.
+ */
+class RollingGifImageCache : public ImageCache
+{
+public:
+  /**
+   * Constructor.
+   * @param[in] textureManager The texture manager
+   * @param[in] gifLoader The loaded gif image
+   * @param[in] frameCount The number of frames in the gif
+   * @param[in] observer FrameReady observer
+   * @param[in] cacheSize The size of the cache
+   * @param[in] batchSize The size of a batch to load
+   *
+   * This will start loading textures immediately, according to the
+   * batch and cache sizes.
+   */
+  RollingGifImageCache( TextureManager&                 textureManager,
+                        GifLoading&                     gifLoader,
+                        uint32_t                        frameCount,
+                        ImageCache::FrameReadyObserver& observer,
+                        uint16_t                        cacheSize,
+                        uint16_t                        batchSize );
+
+  /**
+   * Destructor
+   */
+  virtual ~RollingGifImageCache();
+
+  /**
+   * Get the first frame. If it's not ready, this will trigger the
+   * sending of FrameReady() when the image becomes ready.
+   */
+  virtual TextureSet FirstFrame();
+
+  /**
+   * Get the next frame. If it's not ready, this will trigger the
+   * sending of FrameReady() when the image becomes ready.
+   * This will trigger the loading of the next batch.
+   */
+  virtual TextureSet NextFrame();
+
+private:
+  /**
+   * @return true if the front frame is ready
+   */
+  bool IsFrontReady() const;
+
+  /**
+   * Load the next batch of images
+   */
+  void LoadBatch();
+
+  /**
+   * Get the texture set of the front frame.
+   * @return the texture set
+   */
+  TextureSet GetFrontTextureSet() const;
+
+  /**
+   * Get the texture id of the given index
+   */
+  TextureManager::TextureId GetCachedTextureId( int index ) const;
+
+private:
+  /**
+   * Secondary class to hold readiness and index into url
+   */
+  struct ImageFrame
+  {
+    unsigned int mFrameNumber;
+  };
+
+  GifLoading&               mGifLoading;
+  uint32_t                  mFrameCount;
+  int                       mFrameIndex;
+  std::vector<UrlStore>     mImageUrls;
+  uint16_t                  mCacheSize;
+  CircularQueue<ImageFrame> mQueue;
+};
+
+} // namespace Internal
+} // namespace Toolkit
+} // namespace Dali
+
+#endif
index 9c3f82f..62599e5 100644 (file)
@@ -18,6 +18,7 @@
 #include <dali-toolkit/internal/visuals/animated-image/rolling-image-cache.h>
 
 // INTERNAL HEADERS
+#include <dali-toolkit/internal/visuals/image-atlas-manager.h> // For ImageAtlasManagerPtr
 #include <dali/integration-api/debug.h>
 
 // EXTERNAL HEADERS
@@ -60,7 +61,8 @@ namespace Internal
 RollingImageCache::RollingImageCache(
   TextureManager& textureManager, UrlList& urlList, ImageCache::FrameReadyObserver& observer,
   uint16_t cacheSize, uint16_t batchSize )
-: ImageCache( textureManager, urlList, observer, batchSize ),
+: ImageCache( textureManager, observer, batchSize ),
+  mImageUrls( urlList ),
   mQueue( cacheSize )
 {
   LoadBatch();
@@ -139,10 +141,22 @@ void RollingImageCache::LoadBatch()
     // need to account for this inside the UploadComplete method using mRequestingLoad.
     mRequestingLoad = true;
 
-    mImageUrls[ imageFrame.mUrlIndex ].mTextureId =
-      mTextureManager.RequestLoad( url, ImageDimensions(), FittingMode::SCALE_TO_FILL,
-                                   SamplingMode::BOX_THEN_LINEAR, TextureManager::NO_ATLAS,
-                                   this, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED );
+    bool synchronousLoading = false;
+    bool atlasingStatus = false;
+    bool loadingStatus = false;
+    TextureManager::MaskingDataPointer maskInfo = nullptr;
+    AtlasUploadObserver* atlasObserver = nullptr;
+    ImageAtlasManagerPtr imageAtlasManager = nullptr;
+    Vector4 textureRect;
+
+    mTextureManager.LoadTexture(
+      url, ImageDimensions(), FittingMode::SCALE_TO_FILL,
+      SamplingMode::BOX_THEN_LINEAR, maskInfo,
+      synchronousLoading, mImageUrls[ imageFrame.mUrlIndex ].mTextureId, textureRect,
+      atlasingStatus, loadingStatus, Dali::WrapMode::Type::DEFAULT,
+      Dali::WrapMode::Type::DEFAULT, this,
+      atlasObserver, imageAtlasManager, ENABLE_ORIENTATION_CORRECTION, TextureManager::ReloadPolicy::CACHED );
+
     mRequestingLoad = false;
   }
 
index 1aed961..06240c6 100644 (file)
@@ -34,7 +34,7 @@ namespace Internal
  * Class to manage a rolling cache of images, where the cache size
  * is smaller than the total number of images.
  */
-class RollingImageCache : public ImageCache
+class RollingImageCache : public ImageCache, public TextureUploadObserver
 {
 public:
   /**
@@ -123,6 +123,7 @@ private:
     bool mReady;
   };
 
+  std::vector<UrlStore>& mImageUrls;
   CircularQueue<ImageFrame> mQueue;
 };
 
index 11d3b0f..6b31322 100644 (file)
@@ -105,7 +105,7 @@ TextureManager::TextureManager()
 }
 
 TextureSet TextureManager::LoadTexture(
-    VisualUrl& url, Dali::ImageDimensions desiredSize, Dali::FittingMode::Type fittingMode,
+    const VisualUrl& url, Dali::ImageDimensions desiredSize, Dali::FittingMode::Type fittingMode,
     Dali::SamplingMode::Type samplingMode, const MaskingDataPointer& maskInfo,
     bool synchronousLoading, TextureManager::TextureId& textureId, Vector4& textureRect,
     bool& atlasingStatus, bool& loadingStatus, Dali::WrapMode::Type wrapModeU,
@@ -128,6 +128,7 @@ TextureSet TextureManager::LoadTexture(
       {
         if( elem.textureId == id )
         {
+          textureId = elem.textureId;
           return elem.textureSet;
         }
       }
@@ -206,7 +207,7 @@ TextureSet TextureManager::LoadTexture(
                                  reloadPolicy );
       }
 
-      TextureManager::LoadState loadState = GetTextureState( textureId );
+      TextureManager::LoadState loadState = GetTextureStateInternal( textureId );
       loadingStatus = ( loadState == TextureManager::LOADING );
 
       if( loadState == TextureManager::UPLOADED )
@@ -456,6 +457,31 @@ TextureManager::LoadState TextureManager::GetTextureState( TextureId textureId )
     TextureInfo& cachedTextureInfo( mTextureInfoContainer[ cacheIndex ] );
     loadState = cachedTextureInfo.loadState;
   }
+  else
+  {
+    for( auto&& elem : mExternalTextures )
+    {
+      if( elem.textureId == textureId )
+      {
+        loadState = LoadState::UPLOADED;
+        break;
+      }
+    }
+  }
+  return loadState;
+}
+
+TextureManager::LoadState TextureManager::GetTextureStateInternal( TextureId textureId )
+{
+  LoadState loadState = TextureManager::NOT_STARTED;
+
+  int cacheIndex = GetCacheIndexFromId( textureId );
+  if( cacheIndex != INVALID_CACHE_INDEX )
+  {
+    TextureInfo& cachedTextureInfo( mTextureInfoContainer[ cacheIndex ] );
+    loadState = cachedTextureInfo.loadState;
+  }
+
   return loadState;
 }
 
@@ -469,6 +495,17 @@ TextureSet TextureManager::GetTextureSet( TextureId textureId )
     TextureInfo& cachedTextureInfo( mTextureInfoContainer[ cacheIndex ] );
     textureSet = cachedTextureInfo.textureSet;
   }
+  else
+  {
+    for( auto&& elem : mExternalTextures )
+    {
+      if( elem.textureId == textureId )
+      {
+        textureSet = elem.textureSet;
+        break;
+      }
+    }
+  }
   return textureSet;
 }
 
@@ -590,7 +627,7 @@ void TextureManager::PostLoad( TextureInfo& textureInfo, Devel::PixelBuffer& pix
       // wait for the mask to finish loading.
       if( textureInfo.maskTextureId != INVALID_TEXTURE_ID )
       {
-        LoadState maskLoadState = GetTextureState( textureInfo.maskTextureId );
+        LoadState maskLoadState = GetTextureStateInternal( textureInfo.maskTextureId );
         if( maskLoadState == LOADING )
         {
           textureInfo.pixelBuffer = pixelBuffer; // Store the pixel buffer temporarily
@@ -764,7 +801,6 @@ int TextureManager::GetCacheIndexFromId( const TextureId textureId )
     }
   }
 
-  DALI_LOG_WARNING( "Cannot locate TextureId: %d\n", textureId );
   return INVALID_CACHE_INDEX;
 }
 
index d27b87f..8d46f04 100644 (file)
@@ -140,7 +140,7 @@ public:
 
   // TextureManager Main API:
 
-  TextureSet LoadTexture(VisualUrl& url, Dali::ImageDimensions desiredSize,
+  TextureSet LoadTexture(const VisualUrl& url, Dali::ImageDimensions desiredSize,
                          Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode,
                          const MaskingDataPointer& maskInfo, bool synchronousLoading,
                          TextureManager::TextureId& textureId, Vector4& textureRect,
@@ -318,6 +318,13 @@ private:
     bool                                orientationCorrection,
     TextureManager::ReloadPolicy        reloadPolicy );
 
+  /**
+   * @brief Get the current state of a texture
+   * @param[in] textureId The texture id to query
+   * @return The loading state if the texture is valid, or NOT_STARTED if the textureId
+   * is not valid.
+   */
+  LoadState GetTextureStateInternal( TextureId textureId );
 
   typedef size_t TextureHash; ///< The type used to store the hash used for Texture caching.
 
index 907b428..b1f5f3e 100644 (file)
@@ -234,7 +234,7 @@ bool VisualUrl::IsLocalResource() const
   return mLocation == VisualUrl::LOCAL;
 }
 
-std::string VisualUrl::GetLocation()
+std::string VisualUrl::GetLocation() const
 {
   const auto location = mUrl.find( "://" );
   if( std::string::npos != location )
index b261813..aac605c 100644 (file)
@@ -107,7 +107,7 @@ public:
   /**
    * @return the location part of the url
    */
-  std::string GetLocation();
+  std::string GetLocation() const;
 
   /**
    * Helper to create a URL of type TEXTURE