[dali_2.3.24] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / internal / controls / model / model-impl.cpp
index 1823476..f012aa6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 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.
 #include <filesystem>
 
 // INTERNAL INCLUDES
+#include <dali-scene3d/internal/common/image-resource-loader.h>
 #include <dali-scene3d/internal/common/model-cache-manager.h>
 #include <dali-scene3d/internal/controls/scene-view/scene-view-impl.h>
+#include <dali-scene3d/internal/event/collider-mesh-processor.h>
 #include <dali-scene3d/internal/light/light-impl.h>
 #include <dali-scene3d/internal/model-components/model-node-impl.h>
 #include <dali-scene3d/public-api/controls/model/model.h>
@@ -44,7 +46,7 @@
 #include <dali-scene3d/public-api/loader/scene-definition.h>
 #include <dali-scene3d/public-api/loader/shader-manager.h>
 #include <dali-scene3d/public-api/model-motion/motion-index/blend-shape-index.h>
-
+#include <dali-toolkit/public-api/controls/control-impl.h>
 using namespace Dali;
 
 namespace Dali
@@ -233,6 +235,16 @@ void UpdateShadowMapTextureRecursively(Scene3D::ModelNode node, Dali::Texture sh
   }
 }
 
+void ResetResourceTask(IntrusivePtr<AsyncTask>&& asyncTask)
+{
+  if(!asyncTask)
+  {
+    return;
+  }
+  Dali::AsyncTaskManager::Get().RemoveTask(asyncTask);
+  asyncTask.Reset();
+}
+
 } // anonymous namespace
 
 Model::Model(const std::string& modelUrl, const std::string& resourceDirectoryUrl)
@@ -253,7 +265,9 @@ Model::Model(const std::string& modelUrl, const std::string& resourceDirectoryUr
   mIblDiffuseResourceReady(true),
   mIblSpecularResourceReady(true),
   mIblDiffuseDirty(false),
-  mIblSpecularDirty(false)
+  mIblSpecularDirty(false),
+  mIsShadowCasting(true),
+  mIsShadowReceiving(true)
 {
 }
 
@@ -311,14 +325,50 @@ void Model::AddModelNode(Scene3D::ModelNode modelNode)
     UpdateImageBasedLightScaleFactor();
   }
 
+  GetImplementation(modelNode).SetRootModel(this);
+
+  // If model has a collider mesh set, add it to the container
+  if(modelNode.HasColliderMesh())
+  {
+    RegisterColliderMesh(modelNode);
+    Scene3D::ColliderMeshProcessor::Get().ColliderMeshChanged(Scene3D::Model::DownCast(Self()));
+  }
+
   if(Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE))
   {
     NotifyResourceReady();
   }
 }
 
+void Model::RegisterColliderMesh(Scene3D::ModelNode& modelNode)
+{
+  mColliderMeshes[modelNode.GetProperty<int>(Actor::Property::ID)] = modelNode;
+
+  // Add processor
+  Scene3D::ColliderMeshProcessor::Get().ColliderMeshChanged(Scene3D::Model::DownCast(Self()));
+}
+
+void Model::RemoveColliderMesh(Scene3D::ModelNode& node)
+{
+  auto id   = node.GetProperty<int>(Actor::Property::ID);
+  auto iter = std::find_if(mColliderMeshes.begin(), mColliderMeshes.end(), [id](auto& item) {
+    return item.first == id;
+  });
+  if(iter != mColliderMeshes.end())
+  {
+    mColliderMeshes.erase(iter);
+  }
+}
+
 void Model::RemoveModelNode(Scene3D::ModelNode modelNode)
 {
+  // remove collider mesh from the list if node is being removed
+  if(modelNode.HasColliderMesh())
+  {
+    RemoveColliderMesh(modelNode);
+    GetImplementation(modelNode).SetRootModel(nullptr);
+  }
+
   if(mModelRoot)
   {
     UpdateShaderRecursively(modelNode, nullptr);
@@ -408,6 +458,9 @@ void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::s
     mDiffuseTexture.Reset();
     mSpecularTexture.Reset();
     UpdateImageBasedLightTexture();
+
+    // Request image resource GC
+    Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
   }
   else
   {
@@ -417,6 +470,9 @@ void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::s
       mIblDiffuseLoadTask = new EnvironmentMapLoadTask(mDiffuseIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &Model::OnIblDiffuseLoadComplete));
       Dali::AsyncTaskManager::Get().AddTask(mIblDiffuseLoadTask);
       mIblDiffuseDirty = false;
+
+      // Request image resource GC
+      Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
     }
 
     if(isOnScene && mIblSpecularDirty)
@@ -425,6 +481,9 @@ void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::s
       mIblSpecularLoadTask = new EnvironmentMapLoadTask(mSpecularIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &Model::OnIblSpecularLoadComplete));
       Dali::AsyncTaskManager::Get().AddTask(mIblSpecularLoadTask);
       mIblSpecularDirty = false;
+
+      // Request image resource GC
+      Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
     }
   }
 
@@ -753,6 +812,29 @@ void Model::SetMotionData(Scene3D::MotionData motionData)
   }
 }
 
+void Model::CastShadow(bool castShadow)
+{
+  mIsShadowCasting = castShadow;
+  UpdateCastShadowRecursively(mModelRoot, mIsShadowCasting);
+}
+
+bool Model::IsShadowCasting() const
+{
+  return mIsShadowCasting;
+}
+
+void Model::ReceiveShadow(bool receiveShadow)
+{
+  mIsShadowReceiving = receiveShadow;
+  UpdateReceiveShadowRecursively(mModelRoot, mIsShadowReceiving);
+}
+
+bool Model::IsShadowReceiving() const
+{
+  return mIsShadowReceiving;
+}
+
+
 ///////////////////////////////////////////////////////////
 //
 // Private methods
@@ -762,6 +844,9 @@ void Model::OnInitialize()
 {
   // Make ParentOrigin as Center.
   Self().SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
+
+  mDefaultDiffuseTexture  = ImageResourceLoader::GetEmptyTextureWhiteRGB();
+  mDefaultSpecularTexture = ImageResourceLoader::GetEmptyTextureWhiteRGB();
 }
 
 void Model::OnSceneConnection(int depth)
@@ -922,6 +1007,46 @@ void Model::FitModelPosition()
   mModelRoot.SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3::ONE - mModelPivot);
 }
 
+void Model::UpdateCastShadowRecursively(Scene3D::ModelNode node, bool castShadow)
+{
+  if(!node)
+  {
+    return;
+  }
+
+  GetImplementation(node).CastShadow(castShadow);
+  uint32_t childrenCount = node.GetChildCount();
+  for(uint32_t i = 0; i < childrenCount; ++i)
+  {
+    Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
+    if(!childNode)
+    {
+      continue;
+    }
+    UpdateCastShadowRecursively(childNode, castShadow);
+  }
+}
+
+void Model::UpdateReceiveShadowRecursively(Scene3D::ModelNode node, bool receiveShadow)
+{
+  if(!node)
+  {
+    return;
+  }
+
+  GetImplementation(node).ReceiveShadow(receiveShadow);
+  uint32_t childrenCount = node.GetChildCount();
+  for(uint32_t i = 0; i < childrenCount; ++i)
+  {
+    Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
+    if(!childNode)
+    {
+      continue;
+    }
+    UpdateReceiveShadowRecursively(childNode, receiveShadow);
+  }
+}
+
 void Model::UpdateImageBasedLightTextureRecursively(Scene3D::ModelNode node, Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
 {
   if(!node)
@@ -1094,8 +1219,14 @@ void Model::OnModelLoadComplete()
   ResetCameraParameters();
   if(!resources.mEnvironmentMaps.empty())
   {
-    mDefaultDiffuseTexture  = resources.mEnvironmentMaps.front().second.mDiffuse;
-    mDefaultSpecularTexture = resources.mEnvironmentMaps.front().second.mSpecular;
+    if(resources.mEnvironmentMaps.front().second.mDiffuse)
+    {
+      mDefaultDiffuseTexture = resources.mEnvironmentMaps.front().second.mDiffuse;
+    }
+    if(resources.mEnvironmentMaps.front().second.mSpecular)
+    {
+      mDefaultSpecularTexture = resources.mEnvironmentMaps.front().second.mSpecular;
+    }
   }
 
   if(mShadowMapTexture)
@@ -1156,16 +1287,6 @@ void Model::ResetResourceTasks()
   ResetResourceTask(mIblSpecularLoadTask);
 }
 
-void Model::ResetResourceTask(IntrusivePtr<AsyncTask> asyncTask)
-{
-  if(!asyncTask)
-  {
-    return;
-  }
-  Dali::AsyncTaskManager::Get().RemoveTask(asyncTask);
-  asyncTask.Reset();
-}
-
 void Model::NotifyResourceReady()
 {
   if(!IsResourceReady())