/*
- * 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>
#include <dali-scene3d/public-api/loader/load-result.h>
#include <dali-scene3d/public-api/loader/node-definition.h>
#include <dali-scene3d/public-api/loader/scene-definition.h>
-#include <dali-scene3d/public-api/loader/shader-definition-factory.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
}
}
-void AddLightRecursively(Scene3D::ModelNode node, Scene3D::Light light, uint32_t lightIndex)
+void UpdateBlendShapeNodeMapRecursively(Model::BlendShapeModelNodeMap& resultMap, const Scene3D::ModelNode& node)
{
if(!node)
{
return;
}
- GetImplementation(node).AddLight(light, lightIndex);
+ const auto childCount = node.GetChildCount();
+ for(auto i = 0u; i < childCount; ++i)
+ {
+ UpdateBlendShapeNodeMapRecursively(resultMap, Scene3D::ModelNode::DownCast(node.GetChildAt(i)));
+ }
- uint32_t childrenCount = node.GetChildCount();
- for(uint32_t i = 0; i < childrenCount; ++i)
+ std::vector<std::string> blendShapeNames;
+ node.RetrieveBlendShapeNames(blendShapeNames);
+ for(const auto& iter : blendShapeNames)
{
- Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
- if(childNode)
- {
- AddLightRecursively(childNode, light, lightIndex);
- }
+ // Append or create new list.
+ resultMap[iter].push_back(node);
}
}
-void RemoveLightRecursively(Scene3D::ModelNode node, uint32_t lightIndex)
+void UpdateShaderRecursively(Scene3D::ModelNode node, Scene3D::Loader::ShaderManagerPtr shaderManager)
{
if(!node)
{
return;
}
- GetImplementation(node).RemoveLight(lightIndex);
+ GetImplementation(node).UpdateShader(shaderManager);
uint32_t childrenCount = node.GetChildCount();
for(uint32_t i = 0; i < childrenCount; ++i)
Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
if(childNode)
{
- RemoveLightRecursively(childNode, lightIndex);
+ UpdateShaderRecursively(childNode, shaderManager);
}
}
}
-void UpdateBlendShapeNodeMapRecursively(Model::BlendShapeModelNodeMap& resultMap, const Scene3D::ModelNode& node)
+void UpdateShadowMapTextureRecursively(Scene3D::ModelNode node, Dali::Texture shadowMapTexture)
{
if(!node)
{
return;
}
- const auto childCount = node.GetChildCount();
- for(auto i = 0u; i < childCount; ++i)
+
+ GetImplementation(node).SetShadowMapTexture(shadowMapTexture);
+
+ uint32_t childrenCount = node.GetChildCount();
+ for(uint32_t i = 0; i < childrenCount; ++i)
{
- UpdateBlendShapeNodeMapRecursively(resultMap, Scene3D::ModelNode::DownCast(node.GetChildAt(i)));
+ Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
+ if(childNode)
+ {
+ UpdateShadowMapTextureRecursively(childNode, shadowMapTexture);
+ }
}
+}
- std::vector<std::string> blendShapeNames;
- node.RetrieveBlendShapeNames(blendShapeNames);
- for(const auto& iter : blendShapeNames)
+void ResetResourceTask(IntrusivePtr<AsyncTask>&& asyncTask)
+{
+ if(!asyncTask)
{
- // Append or create new list.
- resultMap[iter].push_back(node);
+ return;
}
+ Dali::AsyncTaskManager::Get().RemoveTask(asyncTask);
+ asyncTask.Reset();
}
} // anonymous namespace
mModelUrl(modelUrl),
mResourceDirectoryUrl(resourceDirectoryUrl),
mModelRoot(),
+ mShaderManager(new Scene3D::Loader::ShaderManager()),
mNaturalSize(Vector3::ZERO),
mModelPivot(AnchorPoint::CENTER),
mSceneIblScaleFactor(1.0f),
mIblDiffuseResourceReady(true),
mIblSpecularResourceReady(true),
mIblDiffuseDirty(false),
- mIblSpecularDirty(false)
+ mIblSpecularDirty(false),
+ mIsShadowCasting(true),
+ mIsShadowReceiving(true)
{
}
mModelResourceReady = true;
}
+ UpdateShaderRecursively(modelNode, mShaderManager);
+
+ if(mShadowMapTexture)
+ {
+ UpdateShadowMapTextureRecursively(modelNode, mShadowMapTexture);
+ }
+
if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
{
UpdateImageBasedLightTexture();
UpdateImageBasedLightScaleFactor();
}
- uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
- for(uint32_t i = 0; i < maxLightCount; ++i)
+ GetImplementation(modelNode).SetRootModel(this);
+
+ // If model has a collider mesh set, add it to the container
+ if(modelNode.HasColliderMesh())
{
- if(mLights[i])
- {
- AddLightRecursively(modelNode, mLights[i], i);
- }
+ RegisterColliderMesh(modelNode);
+ Scene3D::ColliderMeshProcessor::Get().ColliderMeshChanged(Scene3D::Model::DownCast(Self()));
}
if(Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE))
}
}
+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)
{
- uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
- for(uint32_t i = 0; i < maxLightCount; ++i)
- {
- if(mLights[i])
- {
- RemoveLightRecursively(modelNode, i);
- }
- }
+ UpdateShaderRecursively(modelNode, nullptr);
mModelRoot.Remove(modelNode);
}
}
mDiffuseTexture.Reset();
mSpecularTexture.Reset();
UpdateImageBasedLightTexture();
+
+ // Request image resource GC
+ Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect();
}
else
{
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)
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();
}
}
}
}
+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
{
// Make ParentOrigin as Center.
Self().SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
- mLights.resize(Scene3D::Internal::Light::GetMaximumEnabledLightCount());
+
+ mDefaultDiffuseTexture = ImageResourceLoader::GetEmptyTextureWhiteRGB();
+ mDefaultSpecularTexture = ImageResourceLoader::GetEmptyTextureWhiteRGB();
}
void Model::OnSceneConnection(int depth)
{
+ Actor parent = Self().GetParent();
+ while(parent)
+ {
+ // If this Model has parent SceneView and the its ShaderManager is same with privious ShaderManager,
+ // this Model don't need to update shader.
+ Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(parent);
+ if(sceneView)
+ {
+ mParentSceneView = sceneView;
+ GetImpl(sceneView).RegisterSceneItem(this);
+ Scene3D::Loader::ShaderManagerPtr shaderManager = GetImpl(sceneView).GetShaderManager();
+ if(mShaderManager != shaderManager)
+ {
+ mShaderManager = shaderManager;
+ UpdateShaderRecursively(mModelRoot, mShaderManager);
+ }
+ break;
+ }
+ parent = parent.GetParent();
+ }
+
+ // Model can be added on Dali::Scene directly without SceneView.
+ // So, Model's mShaderManager and shaders of child ModelNodes are needed to be reset when this Model has not parent SceneView.
+ Scene3D::SceneView parentSceneView = mParentSceneView.GetHandle();
+ if(!parentSceneView)
+ {
+ mShaderManager = new Dali::Scene3D::Loader::ShaderManager();
+ UpdateShaderRecursively(mModelRoot, mShaderManager);
+ }
+
if(!mModelLoadTask && !mModelResourceReady && !mModelUrl.empty())
{
// Request model load only if we setup url.
SetImageBasedLightSource(mDiffuseIblUrl, mSpecularIblUrl, mIblScaleFactor);
}
- Actor parent = Self().GetParent();
- while(parent)
- {
- Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(parent);
- if(sceneView)
- {
- GetImpl(sceneView).RegisterSceneItem(this);
- mParentSceneView = sceneView;
- break;
- }
- parent = parent.GetParent();
- }
-
NotifyResourceReady();
mSizeNotification = Self().AddPropertyNotification(Actor::Property::SIZE, StepCondition(SIZE_STEP_CONDITION));
void Model::OnSceneDisconnection()
{
+ // If mParentSceneView is still onScene, that means this model
+ // is disconnected from mParentSceneView's sub tree.
+ // So, Unregister this Model from SceneView.
Scene3D::SceneView sceneView = mParentSceneView.GetHandle();
- if(sceneView)
+ if(sceneView && sceneView.GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE))
{
GetImpl(sceneView).UnregisterSceneItem(this);
mParentSceneView.Reset();
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)
camera.SetProperty(Actor::Property::SCALE, resultScale);
}
+void Model::NotifyShadowMapTexture(Dali::Texture shadowMapTexture)
+{
+ if(mShadowMapTexture != shadowMapTexture)
+ {
+ mShadowMapTexture = shadowMapTexture;
+ UpdateShadowMapTextureRecursively(mModelRoot, mShadowMapTexture);
+ }
+}
+
void Model::NotifyImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float scaleFactor, uint32_t specularMipmapLevels)
{
if(mSceneDiffuseTexture != diffuseTexture || mSceneSpecularTexture != specularTexture)
}
}
-void Model::NotifyLightAdded(uint32_t lightIndex, Scene3D::Light light)
-{
- mLights[lightIndex] = light;
- AddLightRecursively(mModelRoot, light, lightIndex);
-}
-
-void Model::NotifyLightRemoved(uint32_t lightIndex)
-{
- if(mLights[lightIndex])
- {
- RemoveLightRecursively(mModelRoot, lightIndex);
- mLights[lightIndex].Reset();
- }
-}
-
void Model::OnModelLoadComplete()
{
+ IntrusivePtr<Model> self = this; // Keep reference until this API finished
+
if(!mModelLoadTask->HasSucceeded())
{
ResetResourceTasks();
ResetCameraParameters();
if(!resources.mEnvironmentMaps.empty())
{
- mDefaultDiffuseTexture = resources.mEnvironmentMaps.front().second.mDiffuse;
- mDefaultSpecularTexture = resources.mEnvironmentMaps.front().second.mSpecular;
- }
-
- uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
- for(uint32_t i = 0; i < maxLightCount; ++i)
- {
- if(mLights[i])
+ if(resources.mEnvironmentMaps.front().second.mDiffuse)
{
- AddLightRecursively(mModelRoot, mLights[i], i);
+ mDefaultDiffuseTexture = resources.mEnvironmentMaps.front().second.mDiffuse;
+ }
+ if(resources.mEnvironmentMaps.front().second.mSpecular)
+ {
+ mDefaultSpecularTexture = resources.mEnvironmentMaps.front().second.mSpecular;
}
}
+ if(mShadowMapTexture)
+ {
+ UpdateShadowMapTextureRecursively(mModelRoot, mShadowMapTexture);
+ }
UpdateImageBasedLightTexture();
UpdateImageBasedLightScaleFactor();
Self().SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3(mModelPivot.x, 1.0f - mModelPivot.y, mModelPivot.z));
mModelResourceReady = true;
- NotifyResourceReady();
ResetResourceTask(mModelLoadTask);
+ NotifyResourceReady();
}
void Model::OnIblDiffuseLoadComplete()
ResetResourceTask(mIblSpecularLoadTask);
}
-void Model::ResetResourceTask(IntrusivePtr<AsyncTask> asyncTask)
-{
- if(!asyncTask)
- {
- return;
- }
- Dali::AsyncTaskManager::Get().RemoveTask(asyncTask);
- asyncTask.Reset();
-}
-
void Model::NotifyResourceReady()
{
if(!IsResourceReady())
void Model::CreateModel()
{
- BoundingVolume AABB;
- auto& resources = mModelLoadTask->GetResources();
- auto& scene = mModelLoadTask->GetScene();
- auto& resourceChoices = mModelLoadTask->GetResourceChoices();
- Dali::Scene3D::Loader::Transforms xforms{Dali::Scene3D::Loader::MatrixStack{}, Dali::Scene3D::Loader::ViewProjection{}};
- Dali::Scene3D::Loader::NodeDefinition::CreateParams nodeParams{resources, xforms, {}, {}, {}};
+ BoundingVolume AABB;
+ auto& resources = mModelLoadTask->GetResources();
+ auto& scene = mModelLoadTask->GetScene();
+ auto& resourceChoices = mModelLoadTask->GetResourceChoices();
+ Dali::Scene3D::Loader::Transforms xforms{Dali::Scene3D::Loader::MatrixStack{}, Dali::Scene3D::Loader::ViewProjection{}};
+
+ Dali::Scene3D::Loader::NodeDefinition::CreateParams nodeParams{resources, xforms, mShaderManager, {}, {}, {}};
// Generate Dali handles from resource bundle. Note that we generate all scene's resouce immediatly.
resources.GenerateResources();