X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-scene3d%2Finternal%2Fcontrols%2Fmodel%2Fmodel-impl.cpp;h=f012aa6ac9ce8668513f6801add26c9a90637705;hb=7892a19ca3a420eb54bcafa007d82bb5fe44c55c;hp=bdbbf3bfd5d9ddd79d8487d5d7f21499334fd0a9;hpb=42b12368d0e630722a62c69ffd8dbcef96393d0d;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-scene3d/internal/controls/model/model-impl.cpp b/dali-scene3d/internal/controls/model/model-impl.cpp index bdbbf3b..f012aa6 100644 --- a/dali-scene3d/internal/controls/model/model-impl.cpp +++ b/dali-scene3d/internal/controls/model/model-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 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. @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -30,19 +31,22 @@ #include // INTERNAL INCLUDES +#include +#include #include +#include +#include +#include #include #include #include -#include -#include -#include #include #include #include #include -#include - +#include +#include +#include using namespace Dali; namespace Dali @@ -53,6 +57,9 @@ namespace Internal { namespace { +/** + * Creates control through type registry + */ BaseHandle Create() { return Scene3D::Model::New(std::string()); @@ -62,19 +69,12 @@ BaseHandle Create() 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 float SIZE_STEP_CONDITION = 0.1f; static constexpr bool DEFAULT_MODEL_CHILDREN_SENSITIVE = false; static constexpr bool DEFAULT_MODEL_CHILDREN_FOCUSABLE = false; -static constexpr std::string_view KTX_EXTENSION = ".ktx"; -static constexpr std::string_view OBJ_EXTENSION = ".obj"; -static constexpr std::string_view GLTF_EXTENSION = ".gltf"; -static constexpr std::string_view DLI_EXTENSION = ".dli"; - struct BoundingVolume { void Init() @@ -174,6 +174,77 @@ void AddModelTreeToAABB(BoundingVolume& AABB, const Dali::Scene3D::Loader::Scene } } +void UpdateBlendShapeNodeMapRecursively(Model::BlendShapeModelNodeMap& resultMap, const Scene3D::ModelNode& node) +{ + if(!node) + { + return; + } + const auto childCount = node.GetChildCount(); + for(auto i = 0u; i < childCount; ++i) + { + UpdateBlendShapeNodeMapRecursively(resultMap, Scene3D::ModelNode::DownCast(node.GetChildAt(i))); + } + + std::vector blendShapeNames; + node.RetrieveBlendShapeNames(blendShapeNames); + for(const auto& iter : blendShapeNames) + { + // Append or create new list. + resultMap[iter].push_back(node); + } +} + +void UpdateShaderRecursively(Scene3D::ModelNode node, Scene3D::Loader::ShaderManagerPtr shaderManager) +{ + if(!node) + { + return; + } + + 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) + { + UpdateShaderRecursively(childNode, shaderManager); + } + } +} + +void UpdateShadowMapTextureRecursively(Scene3D::ModelNode node, Dali::Texture shadowMapTexture) +{ + if(!node) + { + return; + } + + GetImplementation(node).SetShadowMapTexture(shadowMapTexture); + + uint32_t childrenCount = node.GetChildCount(); + for(uint32_t i = 0; i < childrenCount; ++i) + { + Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i)); + if(childNode) + { + UpdateShadowMapTextureRecursively(childNode, shadowMapTexture); + } + } +} + +void ResetResourceTask(IntrusivePtr&& asyncTask) +{ + if(!asyncTask) + { + return; + } + Dali::AsyncTaskManager::Get().RemoveTask(asyncTask); + asyncTask.Reset(); +} + } // anonymous namespace Model::Model(const std::string& modelUrl, const std::string& resourceDirectoryUrl) @@ -181,19 +252,33 @@ Model::Model(const std::string& modelUrl, const std::string& resourceDirectoryUr mModelUrl(modelUrl), mResourceDirectoryUrl(resourceDirectoryUrl), mModelRoot(), + mShaderManager(new Scene3D::Loader::ShaderManager()), mNaturalSize(Vector3::ZERO), 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), - mIBLResourceReady(true) + mIblDiffuseResourceReady(true), + mIblSpecularResourceReady(true), + mIblDiffuseDirty(false), + mIblSpecularDirty(false), + mIsShadowCasting(true), + mIsShadowReceiving(true) { } Model::~Model() { + ResetResourceTasks(); + + if(ModelCacheManager::Get() && !mModelUrl.empty()) + { + ModelCacheManager::Get().UnreferenceModelCache(mModelUrl); + } } Dali::Scene3D::Model Model::New(const std::string& modelUrl, const std::string& resourceDirectoryUrl) @@ -209,11 +294,88 @@ Dali::Scene3D::Model Model::New(const std::string& modelUrl, const std::string& 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; + } + + UpdateShaderRecursively(modelNode, mShaderManager); + + if(mShadowMapTexture) + { + UpdateShadowMapTextureRecursively(modelNode, mShadowMapTexture); + } + + if(mIblDiffuseResourceReady && mIblSpecularResourceReady) + { + UpdateImageBasedLightTexture(); + 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(Dali::Actor::Property::CONNECTED_TO_SCENE)) + { + NotifyResourceReady(); + } +} + +void Model::RegisterColliderMesh(Scene3D::ModelNode& modelNode) +{ + mColliderMeshes[modelNode.GetProperty(Actor::Property::ID)] = modelNode; + + // Add processor + Scene3D::ColliderMeshProcessor::Get().ColliderMeshChanged(Scene3D::Model::DownCast(Self())); +} + +void Model::RemoveColliderMesh(Scene3D::ModelNode& node) +{ + auto id = node.GetProperty(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); + mModelRoot.Remove(modelNode); + } +} + void Model::SetChildrenSensitive(bool enable) { if(mModelChildrenSensitive != enable) @@ -251,30 +413,88 @@ bool Model::GetChildrenFocusable() const void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor) { - mIBLResourceReady = false; - Texture diffuseTexture = (!diffuseUrl.empty()) ? Dali::Scene3D::Loader::LoadCubeMap(diffuseUrl) : Texture(); - Texture specularTexture = (!specularUrl.empty()) ? Dali::Scene3D::Loader::LoadCubeMap(specularUrl) : Texture(); - SetImageBasedLightTexture(diffuseTexture, specularTexture, scaleFactor); - mIBLResourceReady = true; + bool needIblReset = false; + bool isOnScene = Self().GetProperty(Dali::Actor::Property::CONNECTED_TO_SCENE); + if(mDiffuseIblUrl != diffuseUrl) + { + mDiffuseIblUrl = diffuseUrl; + if(mDiffuseIblUrl.empty()) + { + needIblReset = true; + } + else + { + mIblDiffuseDirty = true; + mIblDiffuseResourceReady = false; + } + } - // If Model resource is already ready, then set resource ready. - // If Model resource is still not ready, wait for model resource ready. - if(IsResourceReady()) + if(mSpecularIblUrl != specularUrl) { - SetResourceReady(false); + mSpecularIblUrl = specularUrl; + if(mSpecularIblUrl.empty()) + { + needIblReset = true; + } + else + { + mIblSpecularDirty = true; + mIblSpecularResourceReady = false; + } } -} -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) + // If one or both of diffuse url and specular url are empty, + // we don't need to request to load texture. + if(needIblReset) { - mDiffuseTexture = diffuseTexture; - mSpecularTexture = specularTexture; - mIblScaleFactor = scaleFactor; + ResetResourceTask(mIblDiffuseLoadTask); + ResetResourceTask(mIblSpecularLoadTask); + + mIblDiffuseDirty = false; + mIblSpecularDirty = false; + mIblDiffuseResourceReady = true; + mIblSpecularResourceReady = true; + + mDiffuseTexture.Reset(); + mSpecularTexture.Reset(); UpdateImageBasedLightTexture(); + + // Request image resource GC + Dali::Scene3D::Internal::ImageResourceLoader::RequestGarbageCollect(); + } + else + { + if(isOnScene && mIblDiffuseDirty) + { + ResetResourceTask(mIblDiffuseLoadTask); + 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) + { + ResetResourceTask(mIblSpecularLoadTask); + 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(); + } + } + + if(!Dali::Equals(mIblScaleFactor, scaleFactor)) + { + mIblScaleFactor = scaleFactor; + UpdateImageBasedLightScaleFactor(); } + + // If diffuse and specular textures are already loaded, emits resource ready signal here. + NotifyResourceReady(); } void Model::SetImageBasedLightScaleFactor(float scaleFactor) @@ -323,6 +543,298 @@ Dali::Animation Model::GetAnimation(const std::string& name) const return animation; } +uint32_t Model::GetCameraCount() const +{ + return mCameraParameters.size(); +} + +Dali::CameraActor Model::GenerateCamera(uint32_t index) const +{ + Dali::CameraActor camera; + if(mCameraParameters.size() > index) + { + camera = Dali::CameraActor::New3DCamera(); + if(!mCameraParameters[index].ConfigureCamera(camera, false)) + { + DALI_LOG_ERROR("Fail to generate %u's camera actor : Some property was not defined. Please check model file.\n", index); + camera.Reset(); + return camera; + } + + ApplyCameraTransform(camera); + } + return camera; +} + +bool Model::ApplyCamera(uint32_t index, Dali::CameraActor camera) const +{ + if(camera && mCameraParameters.size() > index) + { + if(!mCameraParameters[index].ConfigureCamera(camera, false)) + { + DALI_LOG_ERROR("Fail to apply %u's camera actor : Some property was not defined. Please check model file.\n", index); + return false; + } + + ApplyCameraTransform(camera); + return true; + } + return false; +} + +Scene3D::ModelNode Model::FindChildModelNodeByName(std::string_view nodeName) +{ + Actor childActor = Self().FindChildByName(nodeName); + return Scene3D::ModelNode::DownCast(childActor); +} + +void Model::RetrieveBlendShapeNames(std::vector& blendShapeNames) const +{ + blendShapeNames.reserve(blendShapeNames.size() + mBlendShapeModelNodeMap.size()); + for(const auto& iter : mBlendShapeModelNodeMap) + { + blendShapeNames.push_back(iter.first); + } +} + +void Model::RetrieveModelNodesByBlendShapeName(std::string_view blendShapeName, std::vector& modelNodes) const +{ + auto iter = mBlendShapeModelNodeMap.find(std::string(blendShapeName)); + if(iter != mBlendShapeModelNodeMap.end()) + { + const auto& modelNodeList = iter->second; + modelNodes.reserve(modelNodes.size() + modelNodeList.size()); + for(const auto& nodeIter : modelNodeList) + { + modelNodes.push_back(nodeIter); + } + } +} + +Dali::Animation Model::GenerateMotionDataAnimation(Scene3D::MotionData motionData) +{ + Dali::Animation animation; + + // TODO : Need to collect duplicated codes with SetMotionData() + + if(motionData) + { + const uint32_t motionCount = motionData.GetMotionCount(); + for(uint32_t i = 0u; i < motionCount; ++i) + { + auto motionIndex = motionData.GetIndex(i); + auto motionValue = motionData.GetValue(i); + if(motionIndex && motionValue) + { + if(motionIndex.GetModelNodeId() != Property::INVALID_KEY) + { + Scene3D::ModelNode modelNode; + if(motionIndex.GetModelNodeId().type == Property::Key::Type::STRING) + { + modelNode = FindChildModelNodeByName(motionIndex.GetModelNodeId().stringKey); + } + else if(motionIndex.GetModelNodeId().type == Property::Key::Type::INDEX) + { + // TODO : Not implement yet. + } + + if(modelNode) + { + KeyFrames keyFrames = motionValue.GetKeyFrames(); + + if(keyFrames) + { + // Try to use index first. If failed, try to use name + Property::Index animatedPropertyIndex = motionIndex.GetPropertyIndex(modelNode); + if(animatedPropertyIndex != Property::INVALID_INDEX) + { + if(DALI_UNLIKELY(!animation)) + { + animation = Animation::New(motionData.GetDuration()); + } + animation.AnimateBetween(Dali::Property(modelNode, animatedPropertyIndex), keyFrames); + } + else + { + std::string animatedPropertyName = motionIndex.GetPropertyName(modelNode); + Dali::Property property(modelNode, animatedPropertyName); + if(property.propertyIndex != Property::INVALID_INDEX) + { + if(DALI_UNLIKELY(!animation)) + { + animation = Animation::New(motionData.GetDuration()); + } + animation.AnimateBetween(property, keyFrames); + } + } + } + } + } + else + { + Scene3D::BlendShapeIndex blendShapeIndex = Scene3D::BlendShapeIndex::DownCast(motionIndex); + if(blendShapeIndex && blendShapeIndex.GetBlendShapeId().type == Property::Key::Type::STRING) + { + // Special case : For BlendShapeIndex that doesn't have ModelNodeId and has string BlendShapeId, + // we need to animate all kind of blendshapes + + KeyFrames keyFrames = motionValue.GetKeyFrames(); + + if(keyFrames) + { + std::vector modelNodes; + RetrieveModelNodesByBlendShapeName(blendShapeIndex.GetBlendShapeId().stringKey, modelNodes); + + for(auto& modelNode : modelNodes) + { + // Try to use index first. If failed, try to use name + Property::Index animatedPropertyIndex = motionIndex.GetPropertyIndex(modelNode); + if(animatedPropertyIndex != Property::INVALID_INDEX) + { + if(DALI_UNLIKELY(!animation)) + { + animation = Animation::New(motionData.GetDuration()); + } + animation.AnimateBetween(Dali::Property(modelNode, animatedPropertyIndex), keyFrames); + } + else + { + std::string animatedPropertyName = motionIndex.GetPropertyName(modelNode); + Dali::Property property(modelNode, animatedPropertyName); + + if(property.propertyIndex != Property::INVALID_INDEX) + { + if(DALI_UNLIKELY(!animation)) + { + animation = Animation::New(motionData.GetDuration()); + } + animation.AnimateBetween(property, keyFrames); + } + } + } + } + } + } + } + } + } + + return animation; +} + +void Model::SetMotionData(Scene3D::MotionData motionData) +{ + // TODO : Need to collect duplicated codes with GenerateMotionDataAnimation() + + if(motionData) + { + const uint32_t motionCount = motionData.GetMotionCount(); + for(uint32_t i = 0u; i < motionCount; ++i) + { + auto motionIndex = motionData.GetIndex(i); + auto motionValue = motionData.GetValue(i); + if(motionIndex && motionValue) + { + if(motionIndex.GetModelNodeId() != Property::INVALID_KEY) + { + Scene3D::ModelNode modelNode; + if(motionIndex.GetModelNodeId().type == Property::Key::Type::STRING) + { + modelNode = FindChildModelNodeByName(motionIndex.GetModelNodeId().stringKey); + } + else if(motionIndex.GetModelNodeId().type == Property::Key::Type::INDEX) + { + // TODO : Not implement yet. + } + + if(modelNode) + { + Property::Value value = motionValue.GetPropertyValue(); + + if(value.GetType() != Property::Type::NONE) + { + // Try to use index first. If failed, try to use name + Property::Index propertyIndex = motionIndex.GetPropertyIndex(modelNode); + if(propertyIndex != Property::INVALID_INDEX) + { + modelNode.SetProperty(propertyIndex, value); + } + else + { + std::string propertyName = motionIndex.GetPropertyName(modelNode); + Dali::Property property(modelNode, propertyName); + if(property.propertyIndex != Property::INVALID_INDEX) + { + modelNode.SetProperty(property.propertyIndex, value); + } + } + } + } + } + else + { + Scene3D::BlendShapeIndex blendShapeIndex = Scene3D::BlendShapeIndex::DownCast(motionIndex); + if(blendShapeIndex && blendShapeIndex.GetBlendShapeId().type == Property::Key::Type::STRING) + { + // Special case : For BlendShapeIndex that doesn't have ModelNodeId and has string BlendShapeId, + // we need to animate all kind of blendshapes + + Property::Value value = motionValue.GetPropertyValue(); + + if(value.GetType() != Property::Type::NONE) + { + std::vector modelNodes; + RetrieveModelNodesByBlendShapeName(blendShapeIndex.GetBlendShapeId().stringKey, modelNodes); + + for(auto& modelNode : modelNodes) + { + // Try to use index first. If failed, try to use name + Property::Index propertyIndex = motionIndex.GetPropertyIndex(modelNode); + if(propertyIndex != Property::INVALID_INDEX) + { + modelNode.SetProperty(propertyIndex, value); + } + else + { + std::string propertyName = motionIndex.GetPropertyName(modelNode); + Dali::Property property(modelNode, propertyName); + if(property.propertyIndex != Property::INVALID_INDEX) + { + modelNode.SetProperty(property.propertyIndex, value); + } + } + } + } + } + } + } + } + } +} + +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 @@ -332,47 +844,97 @@ 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) { - if(!mModelRoot) - { - LoadModel(); - } - 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) { - GetImpl(sceneView).RegisterSceneItem(this); 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. + 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()) + { + SetImageBasedLightSource(mDiffuseIblUrl, mSpecularIblUrl, mIblScaleFactor); + } + + NotifyResourceReady(); + + mSizeNotification = Self().AddPropertyNotification(Actor::Property::SIZE, StepCondition(SIZE_STEP_CONDITION)); + mSizeNotification.NotifySignal().Connect(this, &Model::OnSizeNotification); Control::OnSceneConnection(depth); } 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(Dali::Actor::Property::CONNECTED_TO_SCENE)) { GetImpl(sceneView).UnregisterSceneItem(this); mParentSceneView.Reset(); } + + mSizeNotification.NotifySignal().Disconnect(this, &Model::OnSizeNotification); + Self().RemovePropertyNotification(mSizeNotification); + mSizeNotification.Reset(); + Control::OnSceneDisconnection(); } +void Model::OnSizeSet(const Vector3& size) +{ + ScaleModel(false); +} + Vector3 Model::GetNaturalSize() { if(!mModelRoot) { - LoadModel(); + DALI_LOG_ERROR("Model is still not loaded.\n"); + return Vector3::ZERO; } return mNaturalSize; @@ -395,283 +957,428 @@ float Model::GetWidthForHeight(float height) void Model::OnRelayout(const Vector2& size, RelayoutContainer& container) { Control::OnRelayout(size, container); - ScaleModel(); + ScaleModel(false); } bool Model::IsResourceReady() const { - return mModelResourceReady && mIBLResourceReady; + 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::LoadModel() +void Model::ScaleModel(bool useCurrentSize) { - std::filesystem::path modelUrl(mModelUrl); - if(mResourceDirectoryUrl.empty()) + if(!mModelRoot) { - mResourceDirectoryUrl = std::string(modelUrl.parent_path()) + "/"; + return; } - std::string extension = modelUrl.extension(); - std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); - Dali::Scene3D::Loader::ResourceBundle::PathProvider pathProvider = [&](Dali::Scene3D::Loader::ResourceType::Value type) { - return mResourceDirectoryUrl; - }; + float scale = 1.0f; + Vector3 size = (useCurrentSize) ? Self().GetCurrentProperty(Dali::Actor::Property::SIZE) : Self().GetProperty(Dali::Actor::Property::SIZE); + if(size.x > 0.0f && size.y > 0.0f) + { + scale = MAXFLOAT; + scale = std::min(size.x / mNaturalSize.x, scale); + scale = std::min(size.y / mNaturalSize.y, scale); + } + // Models in glTF and dli are defined as right hand coordinate system. + // DALi uses left hand coordinate system. Scaling negative is for change winding order. + mModelRoot.SetProperty(Dali::Actor::Property::SCALE, Y_DIRECTION * scale); +} - Dali::Scene3D::Loader::ResourceBundle resources; - Dali::Scene3D::Loader::SceneDefinition scene; - std::vector animGroups; - std::vector cameraParameters; - std::vector lights; +void Model::FitModelPosition() +{ + if(!mModelRoot) + { + return; + } + // Loaded model pivot is not the model center. + mModelRoot.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); + mModelRoot.SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3::ONE - mModelPivot); +} - std::vector animations; - animations.clear(); +void Model::UpdateCastShadowRecursively(Scene3D::ModelNode node, bool castShadow) +{ + if(!node) + { + return; + } - Dali::Scene3D::Loader::SceneMetadata metaData; + 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); + } +} - std::filesystem::path metaDataUrl = modelUrl; - metaDataUrl.replace_extension("metadata"); +void Model::UpdateReceiveShadowRecursively(Scene3D::ModelNode node, bool receiveShadow) +{ + if(!node) + { + return; + } - Dali::Scene3D::Loader::LoadSceneMetadata(metaDataUrl.c_str(), metaData); + 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); + } +} - Dali::Scene3D::Loader::LoadResult output{resources, scene, metaData, animations, animGroups, cameraParameters, lights}; +void Model::UpdateImageBasedLightTextureRecursively(Scene3D::ModelNode node, Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels) +{ + if(!node) + { + return; + } - if(extension == DLI_EXTENSION) + GetImplementation(node).SetImageBasedLightTexture(diffuseTexture, specularTexture, iblScaleFactor, specularMipmapLevels); + uint32_t childrenCount = node.GetChildCount(); + for(uint32_t i = 0; i < childrenCount; ++i) { - Dali::Scene3D::Loader::DliLoader loader; - Dali::Scene3D::Loader::DliLoader::InputParams input{ - pathProvider(Dali::Scene3D::Loader::ResourceType::Mesh), - nullptr, - {}, - {}, - nullptr, - {}}; - Dali::Scene3D::Loader::DliLoader::LoadParams loadParams{input, output}; - if(!loader.LoadScene(mModelUrl, loadParams)) + Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i)); + if(!childNode) { - Dali::Scene3D::Loader::ExceptionFlinger(ASSERT_LOCATION) << "Failed to load scene from '" << mModelUrl << "': " << loader.GetParseError(); + continue; } + UpdateImageBasedLightTextureRecursively(childNode, diffuseTexture, specularTexture, iblScaleFactor, specularMipmapLevels); } - else if(extension == GLTF_EXTENSION) +} + +void Model::UpdateImageBasedLightScaleFactorRecursively(Scene3D::ModelNode node, float iblScaleFactor) +{ + if(!node) { - Dali::Scene3D::Loader::ShaderDefinitionFactory sdf; - sdf.SetResources(resources); - Dali::Scene3D::Loader::LoadGltfScene(mModelUrl, sdf, output); + return; + } + + GetImplementation(node).SetImageBasedLightScaleFactor(iblScaleFactor); - resources.mEnvironmentMaps.push_back({}); + 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; + } + UpdateImageBasedLightScaleFactorRecursively(childNode, iblScaleFactor); } - else +} + +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) { - DALI_LOG_ERROR("Unsupported model type.\n"); + currentDiffuseTexture = mDefaultDiffuseTexture; + currentSpecularTexture = mDefaultSpecularTexture; + currentIblScaleFactor = Dali::Scene3D::Loader::EnvironmentDefinition::GetDefaultIntensity(); + currentIblSpecularMipmapLevels = 1u; } - Dali::Scene3D::Loader::Transforms xforms{Dali::Scene3D::Loader::MatrixStack{}, Dali::Scene3D::Loader::ViewProjection{}}; - Dali::Scene3D::Loader::NodeDefinition::CreateParams nodeParams{resources, xforms, {}, {}, {}}; - Dali::Scene3D::Loader::Customization::Choices choices; + UpdateImageBasedLightTextureRecursively(mModelRoot, currentDiffuseTexture, currentSpecularTexture, currentIblScaleFactor, currentIblSpecularMipmapLevels); +} - mModelRoot = Actor::New(); +void Model::UpdateImageBasedLightScaleFactor() +{ + if((!mDiffuseTexture || !mSpecularTexture) && + (!mSceneDiffuseTexture || !mSceneSpecularTexture)) + { + return; + } - BoundingVolume AABB; - for(auto iRoot : scene.GetRoots()) + float currentIblScaleFactor = (mDiffuseTexture && mSpecularTexture) ? mIblScaleFactor : mSceneIblScaleFactor; + UpdateImageBasedLightScaleFactorRecursively(mModelRoot, currentIblScaleFactor); +} + +void Model::ApplyCameraTransform(Dali::CameraActor camera) const +{ + Vector3 selfPosition = Self().GetProperty(Actor::Property::POSITION); + Quaternion selfOrientation = Self().GetProperty(Actor::Property::ORIENTATION); + Vector3 selfScale = Self().GetProperty(Actor::Property::SCALE); + + Vector3 cameraPosition = camera.GetProperty(Actor::Property::POSITION); + Quaternion cameraOrientation = camera.GetProperty(Actor::Property::ORIENTATION); + Vector3 cameraScale = camera.GetProperty(Actor::Property::SCALE); + + // Models in glTF and dli are defined as right hand coordinate system. + // DALi uses left hand coordinate system. Scaling negative is for change winding order. + if(!Dali::Equals(Y_DIRECTION.Dot(Vector3::YAXIS), 1.0f)) { - auto resourceRefs = resources.CreateRefCounter(); - scene.CountResourceRefs(iRoot, choices, resourceRefs); - resources.CountEnvironmentReferences(resourceRefs); + // Reflect by XZ plane + cameraPosition.y = -cameraPosition.y; + Quaternion yDirectionQuaternion; + yDirectionQuaternion.mVector = Vector3::YAXIS; + // Reflect orientation + cameraOrientation = yDirectionQuaternion * cameraOrientation * yDirectionQuaternion; + } + + Vector3 resultPosition; + Quaternion resultOrientation; + Vector3 resultScale; + + Matrix selfMatrix(false); + Matrix cameraMatrix(false); + Matrix resultMatrix(false); + selfMatrix.SetTransformComponents(selfScale, selfOrientation, selfPosition); + cameraMatrix.SetTransformComponents(cameraScale, cameraOrientation, cameraPosition); + Matrix::Multiply(resultMatrix, cameraMatrix, selfMatrix); + resultMatrix.GetTransformComponents(resultPosition, resultOrientation, resultScale); + + camera.SetProperty(Actor::Property::POSITION, resultPosition); + camera.SetProperty(Actor::Property::ORIENTATION, resultOrientation); + camera.SetProperty(Actor::Property::SCALE, resultScale); +} - resources.LoadResources(resourceRefs, pathProvider); +void Model::NotifyShadowMapTexture(Dali::Texture shadowMapTexture) +{ + if(mShadowMapTexture != shadowMapTexture) + { + mShadowMapTexture = shadowMapTexture; + UpdateShadowMapTextureRecursively(mModelRoot, mShadowMapTexture); + } +} - // glTF Mesh is defined in right hand coordinate system, with positive Y for Up direction. - // Because DALi uses left hand system, Y direciton will be flipped for environment map sampling. - for(auto&& env : resources.mEnvironmentMaps) +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; + mSceneSpecularMipmapLevels = specularMipmapLevels; + // If Model IBL is not set, use SceneView's IBL. + if(!mDiffuseTexture || !mSpecularTexture) { - env.first.mYDirection = Y_DIRECTION; + UpdateImageBasedLightTexture(); } + } +} - if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams)) - { - scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor); - scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables)); - ConfigureBlendShapeShaders(resources, scene, actor, std::move(nodeParams.mBlendshapeRequests)); +void Model::NotifyImageBasedLightScaleFactor(float scaleFactor) +{ + mSceneIblScaleFactor = scaleFactor; + if(mSceneDiffuseTexture && mSceneSpecularTexture) + { + UpdateImageBasedLightScaleFactor(); + } +} - scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables)); +void Model::OnModelLoadComplete() +{ + IntrusivePtr self = this; // Keep reference until this API finished - mModelRoot.Add(actor); + if(!mModelLoadTask->HasSucceeded()) + { + ResetResourceTasks(); + + if(ModelCacheManager::Get() && !mModelUrl.empty()) + { + ModelCacheManager::Get().UnreferenceModelCache(mModelUrl); } - AddModelTreeToAABB(AABB, scene, choices, iRoot, nodeParams, Matrix::IDENTITY); + return; } - if(!resources.mEnvironmentMaps.empty()) + if(!mModelRoot) { - mDefaultDiffuseTexture = resources.mEnvironmentMaps.front().second.mDiffuse; - mDefaultSpecularTexture = resources.mEnvironmentMaps.front().second.mSpecular; + CreateModelRoot(); } + CreateModel(); - if(!animations.empty()) + auto& resources = mModelLoadTask->GetResources(); + auto& scene = mModelLoadTask->GetScene(); + CreateAnimations(scene); + ResetCameraParameters(); + if(!resources.mEnvironmentMaps.empty()) { - auto getActor = [&](const Scene3D::Loader::AnimatedProperty& property) { - return mModelRoot.FindChildById(scene.GetNode(property.mNodeIndex)->mNodeId); - }; - - mAnimations.clear(); - for(auto&& animation : animations) + if(resources.mEnvironmentMaps.front().second.mDiffuse) { - Dali::Animation anim = animation.ReAnimate(getActor); - - mAnimations.push_back({animation.mName, anim}); + mDefaultDiffuseTexture = resources.mEnvironmentMaps.front().second.mDiffuse; + } + if(resources.mEnvironmentMaps.front().second.mSpecular) + { + mDefaultSpecularTexture = resources.mEnvironmentMaps.front().second.mSpecular; } } - mRenderableActors.clear(); - CollectRenderableActor(mModelRoot); - UpdateImageBasedLightTexture(); - UpdateImageBasedLightScaleFactor(); - - mNaturalSize = AABB.CalculateSize(); - mModelPivot = AABB.CalculatePivot(); - mModelRoot.SetProperty(Dali::Actor::Property::SIZE, mNaturalSize); - Vector3 controlSize = Self().GetProperty(Dali::Actor::Property::SIZE); - if(Dali::EqualsZero(controlSize.x) || Dali::EqualsZero(controlSize.y)) + if(mShadowMapTexture) { - Self().SetProperty(Dali::Actor::Property::SIZE, mNaturalSize); + UpdateShadowMapTextureRecursively(mModelRoot, mShadowMapTexture); } - - FitModelPosition(); - ScaleModel(); - - 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); - + UpdateImageBasedLightTexture(); + UpdateImageBasedLightScaleFactor(); Self().SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3(mModelPivot.x, 1.0f - mModelPivot.y, mModelPivot.z)); mModelResourceReady = true; - - Control::SetResourceReady(false); + ResetResourceTask(mModelLoadTask); + NotifyResourceReady(); } -void Model::ScaleModel() +void Model::OnIblDiffuseLoadComplete() { - if(mModelRoot) + mDiffuseTexture = mIblDiffuseLoadTask->GetLoadedTexture(); + ResetResourceTask(mIblDiffuseLoadTask); + mIblDiffuseResourceReady = true; + if(mIblDiffuseResourceReady && mIblSpecularResourceReady) { - float scale = 1.0f; - Vector3 size = Self().GetProperty(Dali::Actor::Property::SIZE); - if(size.x > 0.0f && size.y > 0.0f) - { - scale = MAXFLOAT; - scale = std::min(size.x / mNaturalSize.x, scale); - scale = std::min(size.y / mNaturalSize.y, scale); - } - // Models in glTF and dli are defined as right hand coordinate system. - // DALi uses left hand coordinate system. Scaling negative is for change winding order. - mModelRoot.SetProperty(Dali::Actor::Property::SCALE, Y_DIRECTION * scale); + OnIblLoadComplete(); } } -void Model::FitModelPosition() +void Model::OnIblSpecularLoadComplete() { - if(mModelRoot) + mSpecularTexture = mIblSpecularLoadTask->GetLoadedTexture(); + mSpecularMipmapLevels = mIblSpecularLoadTask->GetMipmapLevels(); + ResetResourceTask(mIblSpecularLoadTask); + mIblSpecularResourceReady = true; + if(mIblDiffuseResourceReady && mIblSpecularResourceReady) { - // Loaded model pivot is not the model center. - mModelRoot.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER); - mModelRoot.SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3::ONE - mModelPivot); + OnIblLoadComplete(); } } -void Model::CollectRenderableActor(Actor actor) +void Model::OnIblLoadComplete() { - uint32_t rendererCount = actor.GetRendererCount(); - if(rendererCount) - { - mRenderableActors.push_back(actor); - } + UpdateImageBasedLightTexture(); + NotifyResourceReady(); +} - uint32_t childrenCount = actor.GetChildCount(); - for(uint32_t i = 0; i < childrenCount; ++i) +void Model::OnSizeNotification(Dali::PropertyNotification& source) +{ + ScaleModel(true); +} + +void Model::ResetResourceTasks() +{ + if(!Dali::Adaptor::IsAvailable()) { - CollectRenderableActor(actor.GetChildAt(i)); + return; } + ResetResourceTask(mModelLoadTask); + ResetResourceTask(mIblDiffuseLoadTask); + ResetResourceTask(mIblSpecularLoadTask); } -void Model::UpdateImageBasedLightTexture() +void Model::NotifyResourceReady() { - Dali::Texture currentDiffuseTexture = (mDiffuseTexture) ? mDiffuseTexture : mSceneDiffuseTexture; - Dali::Texture currentSpecularTexture = (mSpecularTexture) ? mSpecularTexture : mSceneSpecularTexture; - float currentIBLScaleFactor = (mDiffuseTexture && mSpecularTexture) ? mIblScaleFactor : mSceneIblScaleFactor; - if(!currentDiffuseTexture || !currentSpecularTexture) + if(!IsResourceReady()) { - currentDiffuseTexture = mDefaultDiffuseTexture; - currentSpecularTexture = mDefaultSpecularTexture; - currentIBLScaleFactor = Dali::Scene3D::Loader::EnvironmentDefinition::GetDefaultIntensity(); + return; } + Control::SetResourceReady(); +} + +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, mShaderManager, {}, {}, {}}; - for(auto&& actor : mRenderableActors) + // Generate Dali handles from resource bundle. Note that we generate all scene's resouce immediatly. + resources.GenerateResources(); + for(auto iRoot : scene.GetRoots()) { - Actor renderableActor = actor.GetHandle(); - if(renderableActor) + if(auto modelNode = scene.CreateNodes(iRoot, resourceChoices, nodeParams)) { - uint32_t rendererCount = renderableActor.GetRendererCount(); - for(uint32_t i = 0; i < rendererCount; ++i) - { - Dali::Renderer renderer = renderableActor.GetRendererAt(i); - if(renderer) - { - Dali::TextureSet textures = renderer.GetTextures(); - if(textures) - { - 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); + scene.ConfigureSkinningShaders(resources, modelNode, std::move(nodeParams.mSkinnables)); + ConfigureBlendShapeShaders(resources, scene, modelNode, std::move(nodeParams.mBlendshapeRequests)); + + scene.ApplyConstraints(modelNode, std::move(nodeParams.mConstrainables)); + + mModelRoot.Add(modelNode); } + + AddModelTreeToAABB(AABB, scene, resourceChoices, iRoot, nodeParams, Matrix::IDENTITY); } -} -void Model::UpdateImageBasedLightScaleFactor() -{ - if((!mDiffuseTexture || !mSpecularTexture) && - (!mSceneDiffuseTexture || !mSceneSpecularTexture)) + UpdateBlendShapeNodeMap(); + + mNaturalSize = AABB.CalculateSize(); + mModelPivot = AABB.CalculatePivot(); + mModelRoot.SetProperty(Dali::Actor::Property::SIZE, mNaturalSize); + Vector3 controlSize = Self().GetProperty(Dali::Actor::Property::SIZE); + if(Dali::EqualsZero(controlSize.x) || Dali::EqualsZero(controlSize.y)) { - return; + Self().SetProperty(Dali::Actor::Property::SIZE, mNaturalSize); } + FitModelPosition(); + ScaleModel(false); +} - float currentIBLScaleFactor = (mDiffuseTexture && mSpecularTexture) ? mIblScaleFactor : mSceneIblScaleFactor; - for(auto&& actor : mRenderableActors) +void Model::CreateAnimations(Dali::Scene3D::Loader::SceneDefinition& scene) +{ + mAnimations.clear(); + if(!mModelLoadTask->GetAnimations().empty()) { - Actor renderableActor = actor.GetHandle(); - if(renderableActor) + auto getActor = [&](const Scene3D::Loader::AnimatedProperty& property) { + if(property.mNodeIndex == Scene3D::Loader::INVALID_INDEX) + { + return mModelRoot.FindChildByName(property.mNodeName); + } + auto* node = scene.GetNode(property.mNodeIndex); + if(node == nullptr) + { + return Dali::Actor(); + } + return mModelRoot.FindChildById(node->mNodeId); + }; + + for(auto&& animation : mModelLoadTask->GetAnimations()) { - renderableActor.RegisterProperty(Dali::Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName().data(), currentIBLScaleFactor); + Dali::Animation anim = animation.ReAnimate(getActor); + mAnimations.push_back({animation.GetName(), anim}); } } } -void Model::NotifyImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float scaleFactor) +void Model::ResetCameraParameters() { - if(mSceneDiffuseTexture != diffuseTexture || mSceneSpecularTexture != specularTexture) + mCameraParameters.clear(); + if(!mModelLoadTask->GetCameras().empty()) { - mSceneDiffuseTexture = diffuseTexture; - mSceneSpecularTexture = specularTexture; - mSceneIblScaleFactor = scaleFactor; - UpdateImageBasedLightTexture(); + // Copy camera parameters. + std::copy(mModelLoadTask->GetCameras().begin(), mModelLoadTask->GetCameras().end(), std::back_inserter(mCameraParameters)); } } -void Model::NotifyImageBasedLightScaleFactor(float scaleFactor) +void Model::UpdateBlendShapeNodeMap() { - mSceneIblScaleFactor = scaleFactor; - if(mSceneDiffuseTexture && mSceneSpecularTexture) - { - UpdateImageBasedLightScaleFactor(); - } + // Remove privous node map + mBlendShapeModelNodeMap.clear(); + + UpdateBlendShapeNodeMapRecursively(mBlendShapeModelNodeMap, mModelRoot); } } // namespace Internal