[Tizen] Add Asynchronous loading for Model and SceneView
authorHeeyong Song <heeyong.song@samsung.com>
Mon, 26 Sep 2022 05:14:03 +0000 (14:14 +0900)
committerHeeyong Song <heeyong.song@samsung.com>
Mon, 26 Sep 2022 05:14:09 +0000 (14:14 +0900)
Change-Id: I288e1a6aa2e3225a1a83b23d258f2071c6cee46d

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 ed5d3bd..2f90682 100644 (file)
@@ -25,6 +25,7 @@
 #include <dali/integration-api/debug.h>
 #include <dali/public-api/object/type-registry-helper.h>
 #include <dali/public-api/object/type-registry.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
 #include <filesystem>
 
 // INTERNAL INCLUDES
@@ -176,6 +177,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),
@@ -186,6 +189,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)
@@ -208,17 +222,16 @@ const Actor Model::GetModelRoot() 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);
   }
 }
 
@@ -237,7 +250,6 @@ void Model::SetImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Textur
       mIblScaleFactor = scaleFactor;
       UpdateImageBasedLightScaleFactor();
     }
-
   }
 }
 
@@ -296,7 +308,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();
@@ -330,7 +349,8 @@ Vector3 Model::GetNaturalSize()
 {
   if(!mModelRoot)
   {
-    LoadModel();
+    DALI_LOG_ERROR("Model is still not loaded.\n");
+    return Vector3::ZERO;
   }
 
   return mNaturalSize;
@@ -487,10 +507,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()
@@ -587,6 +610,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 7e97977..6c254c9 100644 (file)
@@ -145,6 +145,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();
@@ -169,6 +174,11 @@ private:
    */
   void UpdateImageBasedLightScaleFactor();
 
+  /**
+   * @brief Asynchronously loading finished.
+   */
+  void OnLoadComplete();
+
 private:
   std::string                    mModelUrl;
   std::string                    mResourceDirectoryUrl;
@@ -177,6 +187,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..f0d08c2 100644 (file)
@@ -29,6 +29,7 @@
 #include <dali/integration-api/debug.h>
 #include <dali/public-api/object/type-registry-helper.h>
 #include <dali/public-api/object/type-registry.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
 
 // INTERNAL INCLUDES
 #include <dali-scene3d/internal/controls/model/model-impl.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)
@@ -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..4dfe593 100644 (file)
@@ -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 e315cb9..6b0c4bf 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 6678d9f..a71a77c 100644 (file)
@@ -146,6 +146,7 @@ public:
 
   /**
    * @brief Sets Image Based Light Texture.
+   * @note This method doesn't load texture from file, so this work is performed synchronously.
    *
    * @param[in] diffuseTexture cube map texture that can be used as a diffuse IBL source.
    * @param[in] specularTexture cube map texture that can be used as a specular IBL source.