#include <filesystem>
// INTERNAL INCLUDES
+#include <dali-scene3d/internal/common/model-cache-manager.h>
#include <dali-scene3d/internal/controls/scene-view/scene-view-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/animation-definition.h>
#include <dali-scene3d/public-api/loader/camera-parameters.h>
-#include <dali-scene3d/public-api/loader/dli-loader.h>
-#include <dali-scene3d/public-api/loader/gltf2-loader.h>
#include <dali-scene3d/public-api/loader/light-parameters.h>
#include <dali-scene3d/public-api/loader/load-result.h>
#include <dali-scene3d/public-api/loader/node-definition.h>
{
namespace
{
+/**
+ * Creates control through type registry
+ */
BaseHandle Create()
{
return Scene3D::Model::New(std::string());
DALI_TYPE_REGISTRATION_BEGIN(Scene3D::Model, Toolkit::Control, Create);
DALI_TYPE_REGISTRATION_END()
-static constexpr uint32_t OFFSET_FOR_DIFFUSE_CUBE_TEXTURE = 2u;
-static constexpr uint32_t OFFSET_FOR_SPECULAR_CUBE_TEXTURE = 1u;
-
static constexpr Vector3 Y_DIRECTION(1.0f, -1.0f, 1.0f);
static constexpr bool DEFAULT_MODEL_CHILDREN_SENSITIVE = false;
Dali::Scene3D::Loader::ResourceBundle& resources, const Dali::Scene3D::Loader::SceneDefinition& scene, Actor root, std::vector<Dali::Scene3D::Loader::BlendshapeShaderConfigurationRequest>&& requests)
{
std::vector<std::string> errors;
- auto onError = [&errors](const std::string& msg) { errors.push_back(msg); };
+ auto onError = [&errors](const std::string& msg)
+ { errors.push_back(msg); };
if(!scene.ConfigureBlendshapeShaders(resources, root, std::move(requests), onError))
{
Dali::Scene3D::Loader::ExceptionFlinger flinger(ASSERT_LOCATION);
mModelPivot(AnchorPoint::CENTER),
mSceneIblScaleFactor(1.0f),
mIblScaleFactor(1.0f),
+ mSceneSpecularMipmapLevels(1u),
+ mSpecularMipmapLevels(1u),
mModelChildrenSensitive(DEFAULT_MODEL_CHILDREN_SENSITIVE),
mModelChildrenFocusable(DEFAULT_MODEL_CHILDREN_FOCUSABLE),
mModelResourceReady(false),
Model::~Model()
{
+ if(ModelCacheManager::Get() && !mModelUrl.empty())
+ {
+ ModelCacheManager::Get().UnreferenceModelCache(mModelUrl);
+ }
+
ResetResourceTasks();
}
return handle;
}
-const Actor Model::GetModelRoot() const
+const Scene3D::ModelNode Model::GetModelRoot() const
{
return mModelRoot;
}
+void Model::AddModelNode(Scene3D::ModelNode modelNode)
+{
+ if(!mModelRoot)
+ {
+ CreateModelRoot();
+ }
+
+ mModelRoot.Add(modelNode);
+ if(mModelUrl.empty())
+ {
+ mModelResourceReady = true;
+ }
+
+ if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
+ {
+ UpdateImageBasedLightTexture();
+ UpdateImageBasedLightScaleFactor();
+ }
+
+ if(Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE))
+ {
+ NotifyResourceReady();
+ }
+}
+
+void Model::RemoveModelNode(Scene3D::ModelNode modelNode)
+{
+ if(mModelRoot)
+ {
+ mModelRoot.Remove(modelNode);
+ }
+}
+
void Model::SetChildrenSensitive(bool enable)
{
if(mModelChildrenSensitive != enable)
NotifyResourceReady();
}
-void Model::SetImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float scaleFactor)
-{
- // If input texture is wrong, Model is rendered with SceneView's IBL.
- if(mDiffuseTexture != diffuseTexture || mSpecularTexture != specularTexture)
- {
- mDiffuseTexture = diffuseTexture;
- mSpecularTexture = specularTexture;
- mIblScaleFactor = scaleFactor;
- UpdateImageBasedLightTexture();
- }
-}
-
void Model::SetImageBasedLightScaleFactor(float scaleFactor)
{
mIblScaleFactor = scaleFactor;
return false;
}
+Scene3D::ModelNode Model::FindChildModelNodeByName(std::string_view nodeName)
+{
+ Actor childActor = Self().FindChildByName(nodeName);
+ return Scene3D::ModelNode::DownCast(childActor);
+}
+
///////////////////////////////////////////////////////////
//
// Private methods
void Model::OnSceneConnection(int depth)
{
- if(!mModelLoadTask && !mModelRoot)
+ if(!mModelLoadTask && !mModelResourceReady && !mModelUrl.empty())
{
- Scene3D::Loader::InitializeGltfLoader();
+ // Request model load only if we setup url.
+ if(ModelCacheManager::Get())
+ {
+ ModelCacheManager::Get().ReferenceModelCache(mModelUrl);
+ }
mModelLoadTask = new ModelLoadTask(mModelUrl, mResourceDirectoryUrl, MakeCallback(this, &Model::OnModelLoadComplete));
Dali::AsyncTaskManager::Get().AddTask(mModelLoadTask);
}
+
// If diffuse and specular url is not valid, IBL does not need to be loaded.
if(!mDiffuseIblUrl.empty() && !mSpecularIblUrl.empty())
{
parent = parent.GetParent();
}
+ NotifyResourceReady();
Control::OnSceneConnection(depth);
}
return mModelResourceReady && mIblDiffuseResourceReady && mIblSpecularResourceReady;
}
+void Model::CreateModelRoot()
+{
+ mModelRoot = Scene3D::ModelNode::New();
+ mModelRoot.SetProperty(Actor::Property::COLOR_MODE, ColorMode::USE_OWN_MULTIPLY_PARENT_COLOR);
+ mModelRoot.SetProperty(Dali::Actor::Property::SCALE, Y_DIRECTION);
+ mModelRoot.SetProperty(Dali::Actor::Property::SENSITIVE, mModelChildrenSensitive);
+ mModelRoot.SetProperty(Dali::Actor::Property::KEYBOARD_FOCUSABLE, mModelChildrenFocusable);
+ mModelRoot.SetProperty(Dali::DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN, mModelChildrenFocusable);
+ Self().Add(mModelRoot);
+}
+
void Model::ScaleModel()
{
if(!mModelRoot)
mModelRoot.SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3::ONE - mModelPivot);
}
-void Model::CollectRenderableActor(Actor actor)
+void Model::UpdateImageBasedLightTextureRecursively(Scene3D::ModelNode node, Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
{
- uint32_t rendererCount = actor.GetRendererCount();
- if(rendererCount)
+ if(!node)
{
- mRenderableActors.push_back(actor);
+ return;
}
- uint32_t childrenCount = actor.GetChildCount();
+ GetImplementation(node).SetImageBasedLightTexture(diffuseTexture, specularTexture, iblScaleFactor, specularMipmapLevels);
+ uint32_t childrenCount = node.GetChildCount();
for(uint32_t i = 0; i < childrenCount; ++i)
{
- CollectRenderableActor(actor.GetChildAt(i));
+ Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
+ if(!childNode)
+ {
+ continue;
+ }
+ UpdateImageBasedLightTextureRecursively(childNode, diffuseTexture, specularTexture, iblScaleFactor, specularMipmapLevels);
}
}
-void Model::UpdateImageBasedLightTexture()
+void Model::UpdateImageBasedLightScaleFactorRecursively(Scene3D::ModelNode node, float iblScaleFactor)
{
- Dali::Texture currentDiffuseTexture = (mDiffuseTexture && mSpecularTexture) ? mDiffuseTexture : mSceneDiffuseTexture;
- Dali::Texture currentSpecularTexture = (mDiffuseTexture && mSpecularTexture) ? mSpecularTexture : mSceneSpecularTexture;
- float currentIblScaleFactor = (mDiffuseTexture && mSpecularTexture) ? mIblScaleFactor : mSceneIblScaleFactor;
-
- if(!currentDiffuseTexture || !currentSpecularTexture)
+ if(!node)
{
- currentDiffuseTexture = mDefaultDiffuseTexture;
- currentSpecularTexture = mDefaultSpecularTexture;
- currentIblScaleFactor = Dali::Scene3D::Loader::EnvironmentDefinition::GetDefaultIntensity();
+ return;
}
- for(auto&& actor : mRenderableActors)
+ node.RegisterProperty(Dali::Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName().data(), iblScaleFactor);
+ GetImplementation(node).SetImageBasedLightScaleFactor(iblScaleFactor);
+
+ uint32_t childrenCount = node.GetChildCount();
+ for(uint32_t i = 0; i < childrenCount; ++i)
{
- Actor renderableActor = actor.GetHandle();
- if(!renderableActor)
+ Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
+ if(!childNode)
{
continue;
}
+ UpdateImageBasedLightScaleFactorRecursively(childNode, iblScaleFactor);
+ }
+}
- uint32_t rendererCount = renderableActor.GetRendererCount();
- for(uint32_t i = 0; i < rendererCount; ++i)
- {
- Dali::Renderer renderer = renderableActor.GetRendererAt(i);
- if(!renderer)
- {
- continue;
- }
- Dali::TextureSet textures = renderer.GetTextures();
- if(!textures)
- {
- continue;
- }
- uint32_t textureCount = textures.GetTextureCount();
- // EnvMap requires at least 2 texture, diffuse and specular
- if(textureCount > 2u)
- {
- textures.SetTexture(textureCount - OFFSET_FOR_DIFFUSE_CUBE_TEXTURE, currentDiffuseTexture);
- textures.SetTexture(textureCount - OFFSET_FOR_SPECULAR_CUBE_TEXTURE, currentSpecularTexture);
- }
- }
- renderableActor.RegisterProperty(Dali::Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName().data(), currentIblScaleFactor);
+void Model::UpdateImageBasedLightTexture()
+{
+ Dali::Texture currentDiffuseTexture = (mDiffuseTexture && mSpecularTexture) ? mDiffuseTexture : mSceneDiffuseTexture;
+ Dali::Texture currentSpecularTexture = (mDiffuseTexture && mSpecularTexture) ? mSpecularTexture : mSceneSpecularTexture;
+ float currentIblScaleFactor = (mDiffuseTexture && mSpecularTexture) ? mIblScaleFactor : mSceneIblScaleFactor;
+ uint32_t currentIblSpecularMipmapLevels = (mDiffuseTexture && mSpecularTexture) ? mSpecularMipmapLevels : mSceneSpecularMipmapLevels;
+
+ if(!currentDiffuseTexture || !currentSpecularTexture)
+ {
+ currentDiffuseTexture = mDefaultDiffuseTexture;
+ currentSpecularTexture = mDefaultSpecularTexture;
+ currentIblScaleFactor = Dali::Scene3D::Loader::EnvironmentDefinition::GetDefaultIntensity();
+ currentIblSpecularMipmapLevels = 1u;
}
+
+ UpdateImageBasedLightTextureRecursively(mModelRoot, currentDiffuseTexture, currentSpecularTexture, currentIblScaleFactor, currentIblSpecularMipmapLevels);
}
void Model::UpdateImageBasedLightScaleFactor()
}
float currentIblScaleFactor = (mDiffuseTexture && mSpecularTexture) ? mIblScaleFactor : mSceneIblScaleFactor;
- for(auto&& actor : mRenderableActors)
- {
- Actor renderableActor = actor.GetHandle();
- if(renderableActor)
- {
- renderableActor.RegisterProperty(Dali::Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName().data(), currentIblScaleFactor);
- }
- }
+ UpdateImageBasedLightScaleFactorRecursively(mModelRoot, currentIblScaleFactor);
}
void Model::ApplyCameraTransform(Dali::CameraActor camera) const
camera.SetProperty(Actor::Property::SCALE, resultScale);
}
-void Model::NotifyImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float scaleFactor)
+void Model::NotifyImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float scaleFactor, uint32_t specularMipmapLevels)
{
if(mSceneDiffuseTexture != diffuseTexture || mSceneSpecularTexture != specularTexture)
{
- mSceneDiffuseTexture = diffuseTexture;
- mSceneSpecularTexture = specularTexture;
- mSceneIblScaleFactor = scaleFactor;
+ mSceneDiffuseTexture = diffuseTexture;
+ mSceneSpecularTexture = specularTexture;
+ mSceneIblScaleFactor = scaleFactor;
+ mSceneSpecularMipmapLevels = specularMipmapLevels;
// If Model IBL is not set, use SceneView's IBL.
if(!mDiffuseTexture || !mSpecularTexture)
{
if(!mModelLoadTask->HasSucceeded())
{
ResetResourceTasks();
+
+ if(ModelCacheManager::Get() && !mModelUrl.empty())
+ {
+ ModelCacheManager::Get().UnreferenceModelCache(mModelUrl);
+ }
+
return;
}
+ if(!mModelRoot)
+ {
+ CreateModelRoot();
+ }
CreateModel();
- mRenderableActors.clear();
- CollectRenderableActor(mModelRoot);
- auto* resources = &(mModelLoadTask->mResources);
- auto* scene = &(mModelLoadTask->mScene);
- CreateAnimations(*scene);
+ auto& resources = mModelLoadTask->GetResources();
+ auto& scene = mModelLoadTask->GetScene();
+ CreateAnimations(scene);
ResetCameraParameters();
-
- if(!resources->mEnvironmentMaps.empty())
+ if(!resources.mEnvironmentMaps.empty())
{
- mDefaultDiffuseTexture = resources->mEnvironmentMaps.front().second.mDiffuse;
- mDefaultSpecularTexture = resources->mEnvironmentMaps.front().second.mSpecular;
+ mDefaultDiffuseTexture = resources.mEnvironmentMaps.front().second.mDiffuse;
+ mDefaultSpecularTexture = resources.mEnvironmentMaps.front().second.mSpecular;
}
UpdateImageBasedLightTexture();
UpdateImageBasedLightScaleFactor();
-
- mModelRoot.SetProperty(Dali::Actor::Property::SENSITIVE, mModelChildrenSensitive);
- mModelRoot.SetProperty(Dali::Actor::Property::KEYBOARD_FOCUSABLE, mModelChildrenFocusable);
- mModelRoot.SetProperty(Dali::DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN, mModelChildrenFocusable);
-
- Self().Add(mModelRoot);
Self().SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3(mModelPivot.x, 1.0f - mModelPivot.y, mModelPivot.z));
mModelResourceReady = true;
void Model::OnIblSpecularLoadComplete()
{
- mSpecularTexture = mIblSpecularLoadTask->GetLoadedTexture();
+ mSpecularTexture = mIblSpecularLoadTask->GetLoadedTexture();
+ mSpecularMipmapLevels = mIblSpecularLoadTask->GetMipmapLevels();
ResetResourceTask(mIblSpecularLoadTask);
mIblSpecularResourceReady = true;
if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
void Model::CreateModel()
{
- mModelRoot = Actor::New();
- mModelRoot.SetProperty(Actor::Property::COLOR_MODE, ColorMode::USE_OWN_MULTIPLY_PARENT_COLOR);
-
BoundingVolume AABB;
- auto* resources = &(mModelLoadTask->mResources);
- auto* scene = &(mModelLoadTask->mScene);
+ 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, {}, {}, {}};
- uint32_t rootCount = 0u;
- for(auto iRoot : scene->GetRoots())
- {
- resources->GenerateResources(mModelLoadTask->mResourceRefCounts[rootCount]);
+ Dali::Scene3D::Loader::NodeDefinition::CreateParams nodeParams{resources, xforms, {}, {}, {}};
- if(auto actor = scene->CreateNodes(iRoot, mModelLoadTask->mResourceChoices, nodeParams))
+ // Generate Dali handles from resource bundle. Note that we generate all scene's resouce immediatly.
+ resources.GenerateResources();
+ for(auto iRoot : scene.GetRoots())
+ {
+ if(auto actor = scene.CreateNodes(iRoot, resourceChoices, nodeParams))
{
- scene->ConfigureSkeletonJoints(iRoot, resources->mSkeletons, actor);
- scene->ConfigureSkinningShaders(*resources, actor, std::move(nodeParams.mSkinnables));
- ConfigureBlendShapeShaders(*resources, *scene, actor, std::move(nodeParams.mBlendshapeRequests));
+ scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor);
+ scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
+ ConfigureBlendShapeShaders(resources, scene, actor, std::move(nodeParams.mBlendshapeRequests));
- scene->ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
+ scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
mModelRoot.Add(actor);
}
- AddModelTreeToAABB(AABB, *scene, mModelLoadTask->mResourceChoices, iRoot, nodeParams, Matrix::IDENTITY);
- rootCount++;
+ AddModelTreeToAABB(AABB, scene, resourceChoices, iRoot, nodeParams, Matrix::IDENTITY);
}
mNaturalSize = AABB.CalculateSize();
void Model::CreateAnimations(Dali::Scene3D::Loader::SceneDefinition& scene)
{
mAnimations.clear();
- if(!mModelLoadTask->mAnimations.empty())
+ if(!mModelLoadTask->GetAnimations().empty())
{
- auto getActor = [&](const Scene3D::Loader::AnimatedProperty& property) {
+ auto getActor = [&](const Scene3D::Loader::AnimatedProperty& property)
+ {
if(property.mNodeIndex == Scene3D::Loader::INVALID_INDEX)
{
return mModelRoot.FindChildByName(property.mNodeName);
return mModelRoot.FindChildById(node->mNodeId);
};
- for(auto&& animation : mModelLoadTask->mAnimations)
+ for(auto&& animation : mModelLoadTask->GetAnimations())
{
Dali::Animation anim = animation.ReAnimate(getActor);
- mAnimations.push_back({animation.mName, anim});
+ mAnimations.push_back({animation.GetName(), anim});
}
}
}
void Model::ResetCameraParameters()
{
mCameraParameters.clear();
- if(!mModelLoadTask->mCameraParameters.empty())
+ if(!mModelLoadTask->GetCameras().empty())
{
// Copy camera parameters.
- std::copy(mModelLoadTask->mCameraParameters.begin(), mModelLoadTask->mCameraParameters.end(), std::back_inserter(mCameraParameters));
+ std::copy(mModelLoadTask->GetCameras().begin(), mModelLoadTask->GetCameras().end(), std::back_inserter(mCameraParameters));
}
}