vector-animation-renderer for Ubuntu 42/301242/2
authorJiyun Yang <ji.yang@samsung.com>
Wed, 28 Jun 2023 04:06:30 +0000 (13:06 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Mon, 13 Nov 2023 02:31:03 +0000 (11:31 +0900)
Cherry-pick patch of
https://review.tizen.org/gerrit/c/platform/core/uifw/dali-extension/+/294877
and
https://review.tizen.org/gerrit/c/platform/core/uifw/dali-extension/+/300778

Change-Id: I8f83a9e751f72b3e8573bf78083b5359671cd517

README.md [new file with mode: 0644]
build/ubuntu/.gitignore [new file with mode: 0644]
build/ubuntu/CMakeLists.txt [new file with mode: 0644]
build/ubuntu/vector-animation-renderer/CMakeLists.txt [new file with mode: 0644]
dali-extension/vector-animation-renderer/file-ubuntu.list [new file with mode: 0644]
dali-extension/vector-animation-renderer/tizen-vector-animation-renderer-x.cpp [new file with mode: 0644]
dali-extension/vector-animation-renderer/tizen-vector-animation-renderer-x.h [new file with mode: 0644]

diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..f93f0b0
--- /dev/null
+++ b/README.md
@@ -0,0 +1,28 @@
+# How to build lottie extenstion for Ubuntu
+
+## Prerequisites
+### Environment setup
+- Need environment created using dali_env script in dali-core repository
+
+### Dali
+- Install Dali libraries with reference to dali-core/README.md
+    - https://review.tizen.org/gerrit/#/admin/projects/platform/core/uifw/dali-core
+    - https://review.tizen.org/gerrit/#/admin/projects/platform/core/uifw/dali-adaptor
+    - https://review.tizen.org/gerrit/#/admin/projects/platform/core/uifw/dali-toolkit
+
+### rLottie
+```sh
+git clone https://github.com/Samsung/rlottie.git
+```
+```sh
+cmake -DCMAKE_INSTALL_PREFIX=$DESKTOP_PREFIX -DLIB_INSTALL_DIR=$DESKTOP_PREFIX/lib
+make install -j
+```
+<br/>
+
+## Build & Install
+```sh
+cd build/ubuntu
+cmake -DCMAKE_INSTALL_PREFIX=$DESKTOP_PREFIX
+make install -j
+```
diff --git a/build/ubuntu/.gitignore b/build/ubuntu/.gitignore
new file mode 100644 (file)
index 0000000..c323b48
--- /dev/null
@@ -0,0 +1,6 @@
+CMakeFiles/
+*.cmake
+CMakeCache.txt
+install_manifest.txt
+Makefile
+*.so
diff --git a/build/ubuntu/CMakeLists.txt b/build/ubuntu/CMakeLists.txt
new file mode 100644 (file)
index 0000000..afe9ea3
--- /dev/null
@@ -0,0 +1,16 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 3.8.2)
+CMAKE_POLICY(SET CMP0012 NEW) # Prevent dereferencing of OFF/ON as variables
+
+OPTION(ENABLE_DEBUG "Enable Debug" OFF)
+
+IF(CMAKE_BUILD_TYPE MATCHES Debug)
+  SET( ENABLE_DEBUG ON )
+ENDIF()
+
+# from root/build/tizen, get back to root
+SET(ROOT_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../..)
+
+# Make sure the path is absolute
+GET_FILENAME_COMPONENT(ROOT_SRC_DIR ${ROOT_SRC_DIR} ABSOLUTE)
+
+ADD_SUBDIRECTORY(vector-animation-renderer)
diff --git a/build/ubuntu/vector-animation-renderer/CMakeLists.txt b/build/ubuntu/vector-animation-renderer/CMakeLists.txt
new file mode 100644 (file)
index 0000000..8833841
--- /dev/null
@@ -0,0 +1,146 @@
+SET(name "dali2-vector-animation-renderer-plugin")
+
+SET(CMAKE_C_STANDARD 99)
+SET(CMAKE_CXX_STANDARD 17)
+PROJECT(${name})
+SET(PKG_NAME ${name})
+
+SET(GCC_COMPILER_VERSION_REQUIRED "6")
+IF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+  IF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS GCC_COMPILER_VERSION_REQUIRED)
+    MESSAGE(FATAL_ERROR "The GCC required compiler version is " ${GCC_COMPILER_VERSION_REQUIRED})
+  ENDIF()
+ENDIF()
+
+FIND_PACKAGE( PkgConfig REQUIRED )
+PKG_CHECK_MODULES(DALICORE REQUIRED dali2-core)
+PKG_CHECK_MODULES(DALIADAPTOR REQUIRED dali2-adaptor)
+PKG_CHECK_MODULES(DALITOOLKIT REQUIRED dali2-toolkit)
+PKG_CHECK_MODULES(RLOTTIE REQUIRED rlottie)
+
+# Deployment folder should come from spec file or command line:
+SET( PREFIX ${CMAKE_INSTALL_PREFIX})
+SET( EXEC_PREFIX ${CMAKE_INSTALL_PREFIX})
+
+# Set up the include dir
+SET( INCLUDE_DIR $ENV{includedir} )
+IF( NOT INCLUDE_DIR )
+  SET( INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR} )
+ENDIF()
+IF( NOT INCLUDE_DIR )
+  SET( INCLUDE_DIR ${PREFIX}/include )
+ENDIF()
+
+# Set up the lib dir
+SET( LIB_DIR $ENV{libdir} )
+IF( NOT LIB_DIR )
+  SET( LIB_DIR ${CMAKE_INSTALL_LIBDIR} )
+ENDIF()
+IF( NOT LIB_DIR )
+  SET( LIB_DIR ${PREFIX}/lib )
+ENDIF()
+
+# Set up the bin dir
+SET( BIN_DIR $ENV{bindir} )
+IF( NOT BIN_DIR )
+  SET( BIN_DIR ${CMAKE_INSTALL_BINDIR} )
+ENDIF()
+IF( NOT BIN_DIR )
+  SET( BIN_DIR ${PREFIX}/bin )
+ENDIF()
+
+INCLUDE(CheckCXXCompilerFlag)
+
+ADD_COMPILE_OPTIONS( -Werror -Wall -Wextra -Wno-unused-parameter -Wfloat-equal )
+CHECK_CXX_COMPILER_FLAG(-Wno-class-memaccess HAVE_NO_CLASS_MEMACCESS)
+IF (HAVE_NO_CLASS_MEMACCESS)
+  ADD_COMPILE_OPTIONS( -Wno-class-memaccess )
+ENDIF()
+
+CHECK_CXX_COMPILER_FLAG(-Wno-cast-function-type HAVE_NO_CAST_FUNCTION_TYPE)
+IF (HAVE_NO_CAST_FUNCTION_TYPE)
+  ADD_COMPILE_OPTIONS( -Wno-cast-function-type )
+ENDIF()
+
+IF( NOT ${ENABLE_EXPORTALL} )
+  ADD_COMPILE_OPTIONS( "-fvisibility=hidden" )
+ENDIF()
+
+INCLUDE_DIRECTORIES(
+  ${ROOT_SRC_DIR}
+  ${DALICORE_INCLUDE_DIRS}
+  ${DALIADAPTOR_INCLUDE_DIRS}
+  ${INCLUDE_DIR}
+)
+
+SET(SOURCE_DIR "${ROOT_SRC_DIR}/dali-extension/vector-animation-renderer")
+
+SET(SOURCES "")
+
+INCLUDE( ${ROOT_SRC_DIR}/dali-extension/vector-animation-renderer/file-ubuntu.list )
+
+SET(LIBTYPE SHARED)
+IF(DEFINED STATIC)
+  SET(LIBTYPE STATIC)
+ENDIF()
+
+ADD_LIBRARY( ${name} ${LIBTYPE} ${SOURCES} )
+
+SET(OPTIONAL_LIBS ${OPTIONAL_LIBS} -lpthread)
+
+TARGET_LINK_LIBRARIES( ${name}
+  ${OPTIONAL_LIBS}
+  ${DALICORE_LDFLAGS}
+  ${DALIADAPTOR_LDFLAGS}
+  ${RLOTTIE_LDFLAGS}
+)
+
+IF( INSTALL_CMAKE_MODULES )
+  IF( ENABLE_DEBUG )
+    SET( BIN_DIR "${BIN_DIR}/debug" )
+    SET( LIB_DIR "${LIB_DIR}/debug" )
+  ENDIF()
+
+  # Install the library files.
+  INSTALL( TARGETS ${name}
+    EXPORT ${name}-targets
+    LIBRARY DESTINATION ${LIB_DIR}
+    ARCHIVE DESTINATION ${LIB_DIR}
+    RUNTIME DESTINATION ${BIN_DIR}
+  )
+
+  # Install the cmake modules.
+  INSTALL(
+    EXPORT ${name}-targets
+    NAMESPACE ${name}::
+    FILE ${name}-targets.cmake
+    DESTINATION share/${name}
+  )
+
+  FILE( WRITE ${CMAKE_CURRENT_BINARY_DIR}/${name}-config.cmake "
+    include(CMakeFindDependencyMacro)
+    include(\${CMAKE_CURRENT_LIST_DIR}/${name}-targets.cmake)
+  ")
+  INSTALL( FILES ${CMAKE_CURRENT_BINARY_DIR}/${name}-config.cmake DESTINATION share/${name} )
+
+ELSE()
+  # Install the library so file and symlinks.
+  INSTALL( TARGETS ${name} DESTINATION ${LIB_DIR} )
+ENDIF()
+
+# Configuration Messages
+MESSAGE( STATUS "Configuration:\n" )
+MESSAGE( STATUS "Prefix:                " ${PREFIX} )
+MESSAGE( STATUS "Lib Dir:               " ${LIB_DIR} )
+MESSAGE( STATUS "Bin Dir:               " ${BIN_DIR} )
+MESSAGE( STATUS "Include Dir:           " ${INCLUDE_DIR} )
+MESSAGE( STATUS "Debug build:           " ${ENABLE_DEBUG} )
+MESSAGE( STATUS "Export all symbols:    " ${ENABLE_EXPORTALL} )
+MESSAGE( STATUS "Backtrace:             " ${ENABLE_BACKTRACE} )
+MESSAGE( STATUS "Scoped Lock backtrace: " ${ENABLE_LOCK_BACKTRACE} )
+MESSAGE( STATUS "Coverage:              " ${ENABLE_COVERAGE} )
+MESSAGE( STATUS "Trace:                 " ${ENABLE_TRACE} )
+MESSAGE( STATUS "Use pkg configure:     " ${ENABLE_PKG_CONFIGURE} )
+MESSAGE( STATUS "Enable link test:      " ${ENABLE_LINK_TEST} )
+MESSAGE( STATUS "CXXFLAGS:              " ${CMAKE_CXX_FLAGS} )
+MESSAGE( STATUS "LDFLAGS:               " ${CMAKE_SHARED_LINKER_FLAGS_INIT}${CMAKE_SHARED_LINKER_FLAGS} )
diff --git a/dali-extension/vector-animation-renderer/file-ubuntu.list b/dali-extension/vector-animation-renderer/file-ubuntu.list
new file mode 100644 (file)
index 0000000..a5dc753
--- /dev/null
@@ -0,0 +1,6 @@
+SET( root_dir ${ROOT_SRC_DIR}/dali-extension/vector-animation-renderer )
+
+SET( SOURCES ${SOURCES}
+  ${root_dir}/tizen-vector-animation-manager.cpp
+  ${root_dir}/tizen-vector-animation-renderer-x.cpp
+)
diff --git a/dali-extension/vector-animation-renderer/tizen-vector-animation-renderer-x.cpp b/dali-extension/vector-animation-renderer/tizen-vector-animation-renderer-x.cpp
new file mode 100644 (file)
index 0000000..9d553f1
--- /dev/null
@@ -0,0 +1,529 @@
+/*
+ * Copyright (c) 2023 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-extension/vector-animation-renderer/tizen-vector-animation-renderer-x.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/common/hash.h>
+#include <dali/devel-api/rendering/texture-devel.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/object/property-array.h>
+
+#include <cstring> // for strlen()
+
+// INTERNAL INCLUDES
+#include <dali-extension/vector-animation-renderer/tizen-vector-animation-manager.h>
+
+// The plugin factories
+extern "C" DALI_EXPORT_API Dali::VectorAnimationRendererPlugin* CreateVectorAnimationRendererPlugin(void)
+{
+  return new Dali::Plugin::TizenVectorAnimationRenderer;
+}
+
+namespace Dali
+{
+namespace Plugin
+{
+namespace
+{
+const char* const PIXEL_AREA_UNIFORM_NAME("pixelArea");
+const Vector4     FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VECTOR_ANIMATION");
+#endif
+} // unnamed namespace
+
+TizenVectorAnimationRenderer::TizenVectorAnimationRenderer()
+: mUrl(),
+  mMutex(),
+  mRenderer(),
+  mTexture(),
+  mLottieSurface(),
+  mVectorRenderer(),
+  mUploadCompletedSignal(),
+  mTotalFrameNumber(0),
+  mWidth(0),
+  mHeight(0),
+  mDefaultWidth(0),
+  mDefaultHeight(0),
+  mFrameRate(60.0f),
+  mLoadFailed(false),
+  mResourceReady(false),
+  mShaderChanged(false),
+  mResourceReadyTriggered(false),
+  mRenderCallback(std::unique_ptr<EventThreadCallback>(new EventThreadCallback(MakeCallback(this, &TizenVectorAnimationRenderer::OnLottieRendered))))
+{
+  TizenVectorAnimationManager::Get().AddEventHandler(*this);
+}
+
+TizenVectorAnimationRenderer::~TizenVectorAnimationRenderer()
+{
+  Dali::Mutex::ScopedLock lock(mMutex);
+
+  ResetBuffers();
+  DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "this = %p\n", this);
+}
+
+void TizenVectorAnimationRenderer::Finalize()
+{
+  Dali::Mutex::ScopedLock lock(mMutex);
+
+  TizenVectorAnimationManager::Get().RemoveEventHandler(*this);
+
+  mRenderer.Reset();
+  mTexture.Reset();
+  mVectorRenderer.reset();
+  mPropertyCallbacks.clear();
+
+  DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "[%p]\n", this);
+}
+
+bool TizenVectorAnimationRenderer::Load(const std::string& url)
+{
+  Dali::Mutex::ScopedLock lock(mMutex);
+
+  mUrl = url;
+
+  mVectorRenderer = rlottie::Animation::loadFromFile(mUrl);
+  if(!mVectorRenderer)
+  {
+    DALI_LOG_ERROR("Failed to load a Lottie file [%s] [%p]\n", mUrl.c_str(), this);
+    mLoadFailed = true;
+    return false;
+  }
+
+  mTotalFrameNumber = static_cast<uint32_t>(mVectorRenderer->totalFrame());
+  mFrameRate        = static_cast<float>(mVectorRenderer->frameRate());
+
+  size_t w, h;
+  mVectorRenderer->size(w, h);
+  mDefaultWidth  = static_cast<uint32_t>(w);
+  mDefaultHeight = static_cast<uint32_t>(h);
+
+  DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "file [%s] [%p]\n", url.c_str(), this);
+
+  return true;
+}
+
+bool TizenVectorAnimationRenderer::Load(const Dali::Vector<uint8_t>& data)
+{
+  Dali::Mutex::ScopedLock lock(mMutex);
+
+  std::string jsonData(data.Begin(), data.End());    ///< Convert from raw buffer to string.
+  auto        hashValue = Dali::CalculateHash(data); ///< Will be used for rlottie internal cache system.
+
+  mVectorRenderer = rlottie::Animation::loadFromData(std::move(jsonData), std::to_string(hashValue));
+  if(!mVectorRenderer)
+  {
+    DALI_LOG_ERROR("Failed to load a Lottie data [data size : %zu byte] [%p]\n", data.Size(), this);
+    mLoadFailed = true;
+    return false;
+  }
+
+  mTotalFrameNumber = static_cast<uint32_t>(mVectorRenderer->totalFrame());
+  mFrameRate        = static_cast<float>(mVectorRenderer->frameRate());
+
+  size_t w, h;
+  mVectorRenderer->size(w, h);
+  mDefaultWidth  = static_cast<uint32_t>(w);
+  mDefaultHeight = static_cast<uint32_t>(h);
+
+  DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "data [data size : %zu byte] [%p]\n", data.Size(), this);
+
+  return true;
+}
+
+void TizenVectorAnimationRenderer::OnLottieRendered()
+{
+  Dali::Mutex::ScopedLock lock(mMutex);
+
+  if(mPixelBuffer && mTexture)
+  {
+    PixelData pixelData = mPixelBuffer.CreatePixelData();
+    mTexture.Upload(pixelData);
+  }
+}
+
+void TizenVectorAnimationRenderer::SetRenderer(Renderer renderer)
+{
+  mRenderer      = renderer;
+  mShaderChanged = false;
+
+  if(mPixelBuffer)
+  {
+    Dali::Mutex::ScopedLock lock(mMutex);
+
+    if(mResourceReady && mTexture)
+    {
+      TextureSet textureSet = renderer.GetTextures();
+
+      textureSet.SetTexture(0, mTexture);
+
+      mUploadCompletedSignal.Emit();
+    }
+
+    SetShader();
+  }
+}
+
+void TizenVectorAnimationRenderer::SetSize(uint32_t width, uint32_t height)
+{
+  Dali::Mutex::ScopedLock lock(mMutex);
+
+  if(mWidth == width && mHeight == height)
+  {
+    DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "Same size (%d, %d) [%p]\n", mWidth, mHeight, this);
+    return;
+  }
+
+  if(mLoadFailed)
+  {
+    DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "Load is failed. Do not make texture [%p]\n", this);
+    return;
+  }
+
+  mTexture = Texture::New(Dali::TextureType::TEXTURE_2D, Dali::Pixel::BGRA8888, width, height);
+
+  mPixelBuffer   = Dali::Devel::PixelBuffer::New(width, height, Dali::Pixel::BGRA8888);
+  mLottieSurface = rlottie::Surface(reinterpret_cast<uint32_t*>(mPixelBuffer.GetBuffer()), width, height, static_cast<size_t>(mPixelBuffer.GetStride() * 4));
+
+  if(mRenderer)
+  {
+    SetShader();
+  }
+
+  mWidth  = width;
+  mHeight = height;
+
+  mResourceReady = false;
+
+  DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "width = %d, height = %d [%p]\n", mWidth, mHeight, this);
+}
+
+bool TizenVectorAnimationRenderer::Render(uint32_t frameNumber)
+{
+  Dali::Mutex::ScopedLock lock(mMutex);
+
+  if(!mVectorRenderer || !mPixelBuffer)
+  {
+    return false;
+  }
+
+  mVectorRenderer->renderSync(frameNumber, mLottieSurface);
+  mRenderCallback->Trigger();
+
+  if(!mResourceReady)
+  {
+    mResourceReady          = true;
+    mResourceReadyTriggered = true;
+
+    TizenVectorAnimationManager::Get().TriggerEvent(*this);
+  }
+
+  return true;
+}
+
+void TizenVectorAnimationRenderer::RenderStopped()
+{
+}
+
+uint32_t TizenVectorAnimationRenderer::GetTotalFrameNumber() const
+{
+  return mTotalFrameNumber;
+}
+
+float TizenVectorAnimationRenderer::GetFrameRate() const
+{
+  return mFrameRate;
+}
+
+void TizenVectorAnimationRenderer::GetDefaultSize(uint32_t& width, uint32_t& height) const
+{
+  width  = mDefaultWidth;
+  height = mDefaultHeight;
+}
+
+void TizenVectorAnimationRenderer::GetLayerInfo(Property::Map& map) const
+{
+  Dali::Mutex::ScopedLock lock(mMutex);
+
+  if(mVectorRenderer)
+  {
+    auto layerInfo = mVectorRenderer->layers();
+
+    for(auto&& iter : layerInfo)
+    {
+      Property::Array frames;
+      frames.PushBack(std::get<1>(iter));
+      frames.PushBack(std::get<2>(iter));
+      map.Add(std::get<0>(iter), frames);
+    }
+  }
+}
+
+bool TizenVectorAnimationRenderer::GetMarkerInfo(const std::string& marker, uint32_t& startFrame, uint32_t& endFrame) const
+{
+  Dali::Mutex::ScopedLock lock(mMutex);
+
+  if(mVectorRenderer)
+  {
+    auto markerList = mVectorRenderer->markers();
+    for(auto&& iter : markerList)
+    {
+      if(std::get<0>(iter).compare(marker) == 0)
+      {
+        startFrame = static_cast<uint32_t>(std::get<1>(iter));
+        endFrame   = static_cast<uint32_t>(std::get<2>(iter));
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+void TizenVectorAnimationRenderer::GetMarkerInfo(Property::Map& map) const
+{
+  Dali::Mutex::ScopedLock lock(mMutex);
+
+  if(mVectorRenderer)
+  {
+    auto markerList = mVectorRenderer->markers();
+    for(auto&& iter : markerList)
+    {
+      Property::Array frames;
+      frames.PushBack(std::get<1>(iter));
+      frames.PushBack(std::get<2>(iter));
+      map.Add(std::get<0>(iter), frames);
+    }
+  }
+}
+
+void TizenVectorAnimationRenderer::InvalidateBuffer()
+{
+  Dali::Mutex::ScopedLock lock(mMutex);
+  mResourceReady = false;
+}
+
+void TizenVectorAnimationRenderer::AddPropertyValueCallback(const std::string& keyPath, VectorProperty property, CallbackBase* callback, int32_t id)
+{
+  Dali::Mutex::ScopedLock lock(mMutex);
+
+  mPropertyCallbacks.push_back(std::unique_ptr<CallbackBase>(callback));
+
+  switch(property)
+  {
+    case VectorProperty::FILL_COLOR:
+    {
+      mVectorRenderer->setValue<rlottie::Property::FillColor>(keyPath,
+                                                              [property, callback, id](const rlottie::FrameInfo& info) {
+                                                                Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
+                                                                Vector3         color;
+                                                                if(value.Get(color))
+                                                                {
+                                                                  return rlottie::Color(color.r, color.g, color.b);
+                                                                }
+                                                                return rlottie::Color(1.0f, 1.0f, 1.0f);
+                                                              });
+      break;
+    }
+    case VectorProperty::FILL_OPACITY:
+    {
+      mVectorRenderer->setValue<rlottie::Property::FillOpacity>(keyPath,
+                                                                [property, callback, id](const rlottie::FrameInfo& info) {
+                                                                  Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
+                                                                  float           opacity;
+                                                                  if(value.Get(opacity))
+                                                                  {
+                                                                    return opacity * 100;
+                                                                  }
+                                                                  return 100.0f;
+                                                                });
+      break;
+    }
+    case VectorProperty::STROKE_COLOR:
+    {
+      mVectorRenderer->setValue<rlottie::Property::StrokeColor>(keyPath,
+                                                                [property, callback, id](const rlottie::FrameInfo& info) {
+                                                                  Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
+                                                                  Vector3         color;
+                                                                  if(value.Get(color))
+                                                                  {
+                                                                    return rlottie::Color(color.r, color.g, color.b);
+                                                                  }
+                                                                  return rlottie::Color(1.0f, 1.0f, 1.0f);
+                                                                });
+      break;
+    }
+    case VectorProperty::STROKE_OPACITY:
+    {
+      mVectorRenderer->setValue<rlottie::Property::StrokeOpacity>(keyPath,
+                                                                  [property, callback, id](const rlottie::FrameInfo& info) {
+                                                                    Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
+                                                                    float           opacity;
+                                                                    if(value.Get(opacity))
+                                                                    {
+                                                                      return opacity * 100;
+                                                                    }
+                                                                    return 100.0f;
+                                                                  });
+      break;
+    }
+    case VectorProperty::STROKE_WIDTH:
+    {
+      mVectorRenderer->setValue<rlottie::Property::StrokeWidth>(keyPath,
+                                                                [property, callback, id](const rlottie::FrameInfo& info) {
+                                                                  Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
+                                                                  float           width;
+                                                                  if(value.Get(width))
+                                                                  {
+                                                                    return width;
+                                                                  }
+                                                                  return 1.0f;
+                                                                });
+      break;
+    }
+    case VectorProperty::TRANSFORM_ANCHOR:
+    {
+      mVectorRenderer->setValue<rlottie::Property::TrAnchor>(keyPath,
+                                                             [property, callback, id](const rlottie::FrameInfo& info) {
+                                                               Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
+                                                               Vector2         point;
+                                                               if(value.Get(point))
+                                                               {
+                                                                 return rlottie::Point(point.x, point.y);
+                                                               }
+                                                               return rlottie::Point(0.0f, 0.0f);
+                                                             });
+      break;
+    }
+    case VectorProperty::TRANSFORM_POSITION:
+    {
+      mVectorRenderer->setValue<rlottie::Property::TrPosition>(keyPath,
+                                                               [property, callback, id](const rlottie::FrameInfo& info) {
+                                                                 Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
+                                                                 Vector2         position;
+                                                                 if(value.Get(position))
+                                                                 {
+                                                                   return rlottie::Point(position.x, position.y);
+                                                                 }
+                                                                 return rlottie::Point(0.0f, 0.0f);
+                                                               });
+      break;
+    }
+    case VectorProperty::TRANSFORM_SCALE:
+    {
+      mVectorRenderer->setValue<rlottie::Property::TrScale>(keyPath,
+                                                            [property, callback, id](const rlottie::FrameInfo& info) {
+                                                              Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
+                                                              Vector2         scale;
+                                                              if(value.Get(scale))
+                                                              {
+                                                                return rlottie::Size(scale.x, scale.y);
+                                                              }
+                                                              return rlottie::Size(100.0f, 100.0f);
+                                                            });
+      break;
+    }
+    case VectorProperty::TRANSFORM_ROTATION:
+    {
+      mVectorRenderer->setValue<rlottie::Property::TrRotation>(keyPath,
+                                                               [property, callback, id](const rlottie::FrameInfo& info) {
+                                                                 Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
+                                                                 float           rotation;
+                                                                 if(value.Get(rotation))
+                                                                 {
+                                                                   return rotation;
+                                                                 }
+                                                                 return 0.0f;
+                                                               });
+      break;
+    }
+    case VectorProperty::TRANSFORM_OPACITY:
+    {
+      mVectorRenderer->setValue<rlottie::Property::TrOpacity>(keyPath,
+                                                              [property, callback, id](const rlottie::FrameInfo& info) {
+                                                                Property::Value value = CallbackBase::ExecuteReturn<Property::Value>(*callback, id, property, info.curFrame());
+                                                                float           opacity;
+                                                                if(value.Get(opacity))
+                                                                {
+                                                                  return opacity * 100;
+                                                                }
+                                                                return 100.0f;
+                                                              });
+      break;
+    }
+  }
+}
+
+VectorAnimationRendererPlugin::UploadCompletedSignalType& TizenVectorAnimationRenderer::UploadCompletedSignal()
+{
+  return mUploadCompletedSignal;
+}
+
+void TizenVectorAnimationRenderer::NotifyEvent()
+{
+  bool emitSignal = false;
+  {
+    Dali::Mutex::ScopedLock lock(mMutex);
+
+    if(mResourceReadyTriggered)
+    {
+      DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "Set Texture [%p]\n", this);
+
+      // Set texture
+      if(mRenderer && mTexture)
+      {
+        TextureSet textureSet = mRenderer.GetTextures();
+        textureSet.SetTexture(0, mTexture);
+      }
+
+      mResourceReadyTriggered = false;
+      emitSignal              = true;
+    }
+  }
+  if(emitSignal)
+  {
+    mUploadCompletedSignal.Emit();
+  }
+}
+
+void TizenVectorAnimationRenderer::SetShader()
+{
+  if(mShaderChanged || !mTexture)
+  {
+    return;
+  }
+
+  // Not implemented
+
+  mShaderChanged = true;
+}
+
+void TizenVectorAnimationRenderer::ResetBuffers()
+{
+  if(mPixelBuffer)
+  {
+    uint32_t bufferSize = mPixelBuffer.GetWidth() * mPixelBuffer.GetHeight() * Dali::Pixel::GetBytesPerPixel(mPixelBuffer.GetPixelFormat());
+    memset(mPixelBuffer.GetBuffer(), 0, bufferSize);
+  }
+}
+
+} // namespace Plugin
+
+} // namespace Dali
diff --git a/dali-extension/vector-animation-renderer/tizen-vector-animation-renderer-x.h b/dali-extension/vector-animation-renderer/tizen-vector-animation-renderer-x.h
new file mode 100644 (file)
index 0000000..22b7a6e
--- /dev/null
@@ -0,0 +1,184 @@
+#ifndef DALI_TIZEN_VECTOR_ANIMATION_RENDERER_X_H
+#define DALI_TIZEN_VECTOR_ANIMATION_RENDERER_X_H
+
+/*
+ * Copyright (c) 2023 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/pixel-buffer.h>
+#include <dali/devel-api/adaptor-framework/vector-animation-renderer-plugin.h>
+#include <dali/devel-api/threading/mutex.h>
+#include <dali/public-api/adaptor-framework/native-image-source.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <rlottie.h>
+#include <memory>
+
+// INTERNAL INCLUDES
+#include <dali-extension/vector-animation-renderer/tizen-vector-animation-event-handler.h>
+
+namespace Dali
+{
+namespace Plugin
+{
+/**
+ * @brief Implementation of the Tizen vector animation renderer class which has Tizen platform dependency.
+ */
+class TizenVectorAnimationRenderer : public Dali::VectorAnimationRendererPlugin, public TizenVectorAnimationEventHandler
+{
+public:
+  /**
+   * @brief Constructor.
+   */
+  TizenVectorAnimationRenderer();
+
+  /**
+   * @brief Destructor.
+   */
+  virtual ~TizenVectorAnimationRenderer();
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::Finalize()
+   */
+  void Finalize() override;
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::Load()
+   */
+  bool Load(const std::string& url) override;
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::Load()
+   */
+  bool Load(const Dali::Vector<uint8_t>& data) override;
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::SetRenderer()
+   */
+  void SetRenderer(Renderer renderer) override;
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::SetSize()
+   */
+  void SetSize(uint32_t width, uint32_t height) override;
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::Render()
+   */
+  bool Render(uint32_t frameNumber) override;
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::RenderStopped()
+   */
+  void RenderStopped() override;
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::GetTotalFrameNumber()
+   */
+  uint32_t GetTotalFrameNumber() const override;
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::GetFrameRate()
+   */
+  float GetFrameRate() const override;
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::GetDefaultSize()
+   */
+  void GetDefaultSize(uint32_t& width, uint32_t& height) const override;
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::GetLayerInfo()
+   */
+  void GetLayerInfo(Property::Map& map) const override;
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::GetMarkerInfo()
+   */
+  bool GetMarkerInfo(const std::string& marker, uint32_t& startFrame, uint32_t& endFrame) const override;
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::GetMarkerInfo()
+   */
+  void GetMarkerInfo(Property::Map& map) const override;
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::InvalidateBuffer()
+   */
+  void InvalidateBuffer() override;
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::AddPropertyValueCallback()
+   */
+  void AddPropertyValueCallback(const std::string& keyPath, VectorProperty property, CallbackBase* callback, int32_t id) override;
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::UploadCompletedSignal()
+   */
+  UploadCompletedSignalType& UploadCompletedSignal() override;
+
+protected: // Implementation of TizenVectorAnimationEventHandler
+  /**
+   * @copydoc Dali::Plugin::TizenVectorAnimationEventHandler::NotifyEvent()
+   */
+  void NotifyEvent() override;
+
+private:
+  /**
+   * @brief Set shader for NativeImageSourceQueue with custom sampler type and prefix.
+   */
+  void SetShader();
+
+  /**
+   * @brief Reset buffer list.
+   */
+  void ResetBuffers();
+
+  /**
+   * @brief Event callback to process events.
+   */
+  void OnLottieRendered();
+
+private:
+  std::string                                mUrl;               ///< The content file path
+  std::vector<std::unique_ptr<CallbackBase>> mPropertyCallbacks; ///< Property callback list
+
+  mutable Dali::Mutex                  mMutex;                  ///< Mutex
+  Dali::Renderer                       mRenderer;               ///< Renderer
+  Dali::Texture                        mTexture;                ///< Texture
+  rlottie::Surface                     mLottieSurface;          ///
+  std::unique_ptr<rlottie::Animation>  mVectorRenderer;         ///< The vector animation renderer
+  UploadCompletedSignalType            mUploadCompletedSignal;  ///< Upload completed signal
+  uint32_t                             mTotalFrameNumber;       ///< The total frame number
+  uint32_t                             mWidth;                  ///< The width of the surface
+  uint32_t                             mHeight;                 ///< The height of the surface
+  uint32_t                             mDefaultWidth;           ///< The width of the surface
+  uint32_t                             mDefaultHeight;          ///< The height of the surface
+  float                                mFrameRate;              ///< The frame rate of the content
+  bool                                 mLoadFailed;             ///< Whether the file is loaded
+  bool                                 mResourceReady;          ///< Whether the resource is ready
+  bool                                 mShaderChanged;          ///< Whether the shader is changed to support native image
+  bool                                 mResourceReadyTriggered; ///< Whether the resource ready is triggered
+  Dali::Devel::PixelBuffer             mPixelBuffer;            ///
+  std::unique_ptr<EventThreadCallback> mRenderCallback;         ///
+};
+
+} // namespace Plugin
+
+} // namespace Dali
+
+#endif // DALI_TIZEN_VECTOR_ANIMATION_RENDERER_X_H