[Tizen] Add Asynchronous loading for Model and SceneView
authorEunki, Hong <eunkiki.hong@samsung.com>
Tue, 4 Oct 2022 09:32:01 +0000 (18:32 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Tue, 4 Oct 2022 09:32:01 +0000 (18:32 +0900)
This reverts commit 570e3ee34bf31053131cbf9d1a3c3125d2ae228a.

Change-Id: I80df8b088232425d403e1ceca6ed2c10cba8fbec

dali-scene3d/internal/controls/model/model-impl.cpp
dali-scene3d/internal/controls/model/model-impl.h
dali-scene3d/internal/controls/scene-view/scene-view-impl.cpp
dali-scene3d/internal/controls/scene-view/scene-view-impl.h
dali-scene3d/public-api/controls/model/model.cpp
dali-scene3d/public-api/controls/model/model.h

index 24e7af5..3a6b11d 100644 (file)
@@ -23,6 +23,7 @@
 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
 #include <dali/devel-api/actors/actor-devel.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
 #include <dali/integration-api/debug.h>
 #include <dali/public-api/object/type-registry-helper.h>
 #include <dali/public-api/object/type-registry.h>
@@ -179,6 +180,8 @@ Model::Model(const std::string& modelUrl, const std::string& resourceDirectoryUr
   mModelUrl(modelUrl),
   mResourceDirectoryUrl(resourceDirectoryUrl),
   mModelRoot(),
+  mModelLoadedCallback(nullptr),
+  mIblLoadedCallback(nullptr),
   mNaturalSize(Vector3::ZERO),
   mModelPivot(AnchorPoint::CENTER),
   mIblScaleFactor(1.0f),
@@ -190,6 +193,17 @@ Model::Model(const std::string& modelUrl, const std::string& resourceDirectoryUr
 
 Model::~Model()
 {
+  if(mModelLoadedCallback && Adaptor::IsAvailable())
+  {
+    // Removes the callback from the callback manager in case the control is destroyed before the callback is executed.
+    Adaptor::Get().RemoveIdle(mModelLoadedCallback);
+  }
+
+  if(mIblLoadedCallback && Adaptor::IsAvailable())
+  {
+    // Removes the callback from the callback manager in case the control is destroyed before the callback is executed.
+    Adaptor::Get().RemoveIdle(mIblLoadedCallback);
+  }
 }
 
 Dali::Scene3D::Model Model::New(const std::string& modelUrl, const std::string& resourceDirectoryUrl)
@@ -229,17 +243,16 @@ bool Model::GetChildrenSensitive() const
 
 void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor)
 {
-  mIBLResourceReady       = false;
-  Texture diffuseTexture  = Dali::Scene3D::Loader::LoadCubeMap(diffuseUrl);
-  Texture specularTexture = Dali::Scene3D::Loader::LoadCubeMap(specularUrl);
-  SetImageBasedLightTexture(diffuseTexture, specularTexture, scaleFactor);
-  mIBLResourceReady = true;
-
-  // If Model resource is already ready, then set resource ready.
-  // If Model resource is still not ready, wait for model resource ready.
-  if(IsResourceReady())
+  // Request asynchronous model loading
+  if(!mIblLoadedCallback)
   {
-    SetResourceReady(false);
+    mIBLResourceReady = false;
+    mDiffuseIblUrl    = diffuseUrl;
+    mSpecularIblUrl   = specularUrl;
+    mIblScaleFactor   = scaleFactor;
+    // The callback manager takes the ownership of the callback object.
+    mIblLoadedCallback = MakeCallback(this, &Model::OnLoadComplete);
+    Adaptor::Get().AddIdle(mIblLoadedCallback, false);
   }
 }
 
@@ -316,7 +329,14 @@ void Model::OnSceneConnection(int depth)
 {
   if(!mModelRoot)
   {
-    LoadModel();
+    // Request asynchronous model loading
+    if(!mModelLoadedCallback)
+    {
+      mModelResourceReady = false;
+      // The callback manager takes the ownership of the callback object.
+      mModelLoadedCallback = MakeCallback(this, &Model::OnLoadComplete);
+      Adaptor::Get().AddIdle(mModelLoadedCallback, false);
+    }
   }
 
   Actor parent = Self().GetParent();
@@ -350,7 +370,8 @@ Vector3 Model::GetNaturalSize()
 {
   if(!mModelRoot)
   {
-    LoadModel();
+    DALI_LOG_ERROR("Model is still not loaded.\n");
+    return Vector3::ZERO;
   }
 
   return mNaturalSize;
@@ -509,10 +530,13 @@ void Model::LoadModel()
 
   Self().SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
   Self().SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3(mModelPivot.x, 1.0f - mModelPivot.y, mModelPivot.z));
+}
 
-  mModelResourceReady = true;
-
-  Control::SetResourceReady(false);
+void Model::LoadImageBasedLight()
+{
+  Texture diffuseTexture  = Dali::Scene3D::Loader::LoadCubeMap(mDiffuseIblUrl);
+  Texture specularTexture = Dali::Scene3D::Loader::LoadCubeMap(mSpecularIblUrl);
+  SetImageBasedLightTexture(diffuseTexture, specularTexture, mIblScaleFactor);
 }
 
 void Model::ScaleModel()
@@ -609,6 +633,37 @@ void Model::UpdateImageBasedLightScaleFactor()
   }
 }
 
+void Model::OnLoadComplete()
+{
+  // TODO: In this implementation, we cannot know which request occurs this OnLoadComplete Callback.
+  // Currently it is no problem because the all loading is processed in this method.
+
+  // Prevent to emit unnecessary resource ready signal.
+  if(IsResourceReady())
+  {
+    return;
+  }
+
+  if(!mIBLResourceReady)
+  {
+    LoadImageBasedLight();
+    mIBLResourceReady  = true;
+    mIblLoadedCallback = nullptr;
+  }
+
+  if(!mModelResourceReady)
+  {
+    LoadModel();
+    mModelResourceReady  = true;
+    mModelLoadedCallback = nullptr;
+  }
+
+  if(IsResourceReady())
+  {
+    Control::SetResourceReady(false);
+  }
+}
+
 } // namespace Internal
 } // namespace Scene3D
 } // namespace Dali
index 3db9c57..a037c93 100644 (file)
@@ -155,6 +155,11 @@ private:
   void LoadModel();
 
   /**
+   * @brief Loads image based light from file.
+   */
+  void LoadImageBasedLight();
+
+  /**
    * @brief Scales the model to fit the control or to return to original size.
    */
   void ScaleModel();
@@ -179,6 +184,11 @@ private:
    */
   void UpdateImageBasedLightScaleFactor();
 
+  /**
+   * @brief Asynchronously loading finished.
+   */
+  void OnLoadComplete();
+
 private:
   std::string                    mModelUrl;
   std::string                    mResourceDirectoryUrl;
@@ -187,6 +197,11 @@ private:
   std::vector<WeakHandle<Actor>> mRenderableActors;
   WeakHandle<Scene3D::SceneView> mParentSceneView;
 
+  CallbackBase* mModelLoadedCallback;
+  CallbackBase* mIblLoadedCallback;
+  std::string   mDiffuseIblUrl;
+  std::string   mSpecularIblUrl;
+
   Dali::Texture mSpecularTexture;
   Dali::Texture mDiffuseTexture;
   Vector3       mNaturalSize;
index 08afa17..61962b5 100644 (file)
@@ -26,6 +26,7 @@
 #include <dali-toolkit/public-api/image-loader/image-url.h>
 #include <dali-toolkit/public-api/image-loader/image.h>
 #include <dali/devel-api/common/stage.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
 #include <dali/integration-api/debug.h>
 #include <dali/public-api/object/type-registry-helper.h>
 #include <dali/public-api/object/type-registry.h>
@@ -60,11 +61,19 @@ Property::Index RENDERING_BUFFER = Dali::Toolkit::Control::CONTROL_PROPERTY_END_
 } // anonymous namespace
 
 SceneView::SceneView()
-: Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT))
+: Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
+  mIblLoadedCallback(nullptr)
 {
 }
 
-SceneView::~SceneView() = default;
+SceneView::~SceneView()
+{
+  if(mIblLoadedCallback && Adaptor::IsAvailable())
+  {
+    // Removes the callback from the callback manager in case the control is destroyed before the callback is executed.
+    Adaptor::Get().RemoveIdle(mIblLoadedCallback);
+  }
+}
 
 Dali::Scene3D::SceneView SceneView::New()
 {
@@ -188,28 +197,17 @@ void SceneView::UnregisterModel(Scene3D::Model model)
 
 void SceneView::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor)
 {
-  mIBLResourceReady = false;
-  Texture diffuseTexture = Dali::Scene3D::Loader::LoadCubeMap(diffuseUrl);
-  if(diffuseTexture)
+  // Request asynchronous model loading
+  if(!mIblLoadedCallback)
   {
-    Texture specularTexture = Dali::Scene3D::Loader::LoadCubeMap(specularUrl);
-    if(specularTexture)
-    {
-      mDiffuseTexture  = diffuseTexture;
-      mSpecularTexture = specularTexture;
-      mIblScaleFactor  = scaleFactor;
-
-      for(auto&& model : mModels)
-      {
-        if(model)
-        {
-          model.SetImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor);
-        }
-      }
-    }
+    mIBLResourceReady = false;
+    mDiffuseIblUrl    = diffuseUrl;
+    mSpecularIblUrl   = specularUrl;
+    mIblScaleFactor   = scaleFactor;
+    // The callback manager takes the ownership of the callback object.
+    mIblLoadedCallback = MakeCallback(this, &SceneView::OnLoadComplete);
+    Adaptor::Get().AddIdle(mIblLoadedCallback, false);
   }
-  mIBLResourceReady = true;
-  Control::SetResourceReady(false);
 }
 
 void SceneView::SetImageBasedLightScaleFactor(float scaleFactor)
@@ -354,14 +352,14 @@ void SceneView::UpdateRenderTask()
       mRenderTask.SetCameraActor(mSelectedCamera);
     }
 
-    Vector3 size = Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
+    Vector3     size        = Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
     const float aspectRatio = size.width / size.height;
     mSelectedCamera.SetAspectRatio(aspectRatio);
-    const float halfHeight = mSelectedCamera[Dali::CameraActor::Property::TOP_PLANE_DISTANCE];
-    const float halfWidth = aspectRatio * halfHeight;
+    const float halfHeight                                              = mSelectedCamera[Dali::CameraActor::Property::TOP_PLANE_DISTANCE];
+    const float halfWidth                                               = aspectRatio * halfHeight;
     mSelectedCamera[Dali::CameraActor::Property::LEFT_PLANE_DISTANCE]   = -halfWidth;
     mSelectedCamera[Dali::CameraActor::Property::RIGHT_PLANE_DISTANCE]  = halfWidth;
-    mSelectedCamera[Dali::CameraActor::Property::TOP_PLANE_DISTANCE]    = halfHeight; // Top is +ve to keep consistency with orthographic values
+    mSelectedCamera[Dali::CameraActor::Property::TOP_PLANE_DISTANCE]    = halfHeight;  // Top is +ve to keep consistency with orthographic values
     mSelectedCamera[Dali::CameraActor::Property::BOTTOM_PLANE_DISTANCE] = -halfHeight; // Bottom is -ve to keep consistency with orthographic values
     if(mUseFrameBuffer)
     {
@@ -412,6 +410,53 @@ void SceneView::UpdateRenderTask()
   }
 }
 
+void SceneView::LoadImageBasedLight()
+{
+  Texture diffuseTexture  = Dali::Scene3D::Loader::LoadCubeMap(mDiffuseIblUrl);
+  Texture specularTexture = Dali::Scene3D::Loader::LoadCubeMap(mSpecularIblUrl);
+
+  if(diffuseTexture)
+  {
+    if(specularTexture)
+    {
+      mDiffuseTexture  = diffuseTexture;
+      mSpecularTexture = specularTexture;
+
+      for(auto&& model : mModels)
+      {
+        if(model)
+        {
+          model.SetImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor);
+        }
+      }
+    }
+  }
+}
+
+void SceneView::OnLoadComplete()
+{
+  // TODO: In this implementation, we cannot know which request occurs this OnLoadComplete Callback.
+  // Currently it is no problem because the all loading is processed in this method.
+
+  // Prevent to emit unnecessary resource ready signal.
+  if(IsResourceReady())
+  {
+    return;
+  }
+
+  if(!mIBLResourceReady)
+  {
+    LoadImageBasedLight();
+    mIBLResourceReady  = true;
+    mIblLoadedCallback = nullptr;
+  }
+
+  if(IsResourceReady())
+  {
+    Control::SetResourceReady(false);
+  }
+}
+
 } // namespace Internal
 } // namespace Scene3D
 } // namespace Dali
index ddd7319..07ceda4 100644 (file)
@@ -30,8 +30,8 @@
 #include <dali/public-api/rendering/texture.h>
 
 // INTERNAL INCLUDES
-#include <dali-scene3d/public-api/controls/scene-view/scene-view.h>
 #include <dali-scene3d/public-api/controls/model/model.h>
+#include <dali-scene3d/public-api/controls/scene-view/scene-view.h>
 
 namespace Dali
 {
@@ -204,6 +204,16 @@ private:
    */
   void UpdateRenderTask();
 
+  /**
+   * @brief Loads image based light from file.
+   */
+  void LoadImageBasedLight();
+
+  /**
+   * @brief Asynchronously loading finished.
+   */
+  void OnLoadComplete();
+
 private:
   Toolkit::Visual::Base mVisual;
 
@@ -217,8 +227,11 @@ private:
   Dali::Texture               mTexture;
   Dali::RenderTask            mRenderTask;
 
-  Layer mRootLayer;
+  CallbackBase* mIblLoadedCallback;
+  std::string   mDiffuseIblUrl;
+  std::string   mSpecularIblUrl;
 
+  Layer         mRootLayer;
   Dali::Texture mSpecularTexture;
   Dali::Texture mDiffuseTexture;
   float         mIblScaleFactor{1.0f};
index 69029d9..41ecb92 100644 (file)
@@ -25,9 +25,7 @@ namespace Dali
 {
 namespace Scene3D
 {
-Model::Model()
-{
-}
+Model::Model() = default;
 
 Model::Model(const Model& model) = default;
 
@@ -37,9 +35,7 @@ Model& Model::operator=(const Model& model) = default;
 
 Model& Model::operator=(Model&& rhs) = default;
 
-Model::~Model()
-{
-}
+Model::~Model() = default;
 
 Model Model::New(const std::string& modelUrl, const std::string& resourceDirectoryUrl)
 {
index 104e054..acdc447 100644 (file)
@@ -188,6 +188,7 @@ public:
 
   /**
    * @brief Sets Image Based Light Texture.
+   * @note This method doesn't load texture from file, so this work is performed synchronously.
    *
    * @SINCE_2_1.41
    * @param[in] diffuseTexture cube map texture that can be used as a diffuse IBL source.