Support model size change
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / internal / controls / model / model-impl.cpp
index 5aa4a5f..b0f8294 100644 (file)
@@ -33,6 +33,7 @@
 // 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>
@@ -52,6 +53,9 @@ namespace Internal
 {
 namespace
 {
+/**
+ * Creates control through type registry
+ */
 BaseHandle Create()
 {
   return Scene3D::Model::New(std::string());
@@ -61,10 +65,8 @@ 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;
@@ -180,6 +182,8 @@ Model::Model(const std::string& modelUrl, const std::string& resourceDirectoryUr
   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),
@@ -192,7 +196,7 @@ Model::Model(const std::string& modelUrl, const std::string& resourceDirectoryUr
 
 Model::~Model()
 {
-  if(ModelCacheManager::Get())
+  if(ModelCacheManager::Get() && !mModelUrl.empty())
   {
     ModelCacheManager::Get().UnreferenceModelCache(mModelUrl);
   }
@@ -213,11 +217,44 @@ 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;
+  }
+
+  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)
@@ -330,18 +367,6 @@ void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::s
   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;
@@ -427,6 +452,12 @@ bool Model::ApplyCamera(uint32_t index, Dali::CameraActor camera) const
   return false;
 }
 
+Scene3D::ModelNode Model::FindChildModelNodeByName(std::string_view nodeName)
+{
+  Actor childActor = Self().FindChildByName(nodeName);
+  return Scene3D::ModelNode::DownCast(childActor);
+}
+
 ///////////////////////////////////////////////////////////
 //
 // Private methods
@@ -440,8 +471,9 @@ void Model::OnInitialize()
 
 void Model::OnSceneConnection(int depth)
 {
-  if(!mModelLoadTask && !mModelRoot)
+  if(!mModelLoadTask && !mModelResourceReady && !mModelUrl.empty())
   {
+    // Request model load only if we setup url.
     if(ModelCacheManager::Get())
     {
       ModelCacheManager::Get().ReferenceModelCache(mModelUrl);
@@ -449,6 +481,7 @@ void Model::OnSceneConnection(int depth)
     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())
   {
@@ -468,6 +501,10 @@ void Model::OnSceneConnection(int depth)
     parent = parent.GetParent();
   }
 
+  NotifyResourceReady();
+
+  mSizeNotification = Self().AddPropertyNotification(Actor::Property::SIZE, StepCondition(SIZE_STEP_CONDITION));
+  mSizeNotification.NotifySignal().Connect(this, &Model::OnSizeNotification);
   Control::OnSceneConnection(depth);
 }
 
@@ -479,9 +516,19 @@ void Model::OnSceneDisconnection()
     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)
@@ -510,7 +557,7 @@ float Model::GetWidthForHeight(float height)
 void Model::OnRelayout(const Vector2& size, RelayoutContainer& container)
 {
   Control::OnRelayout(size, container);
-  ScaleModel();
+  ScaleModel(false);
 }
 
 bool Model::IsResourceReady() const
@@ -518,7 +565,18 @@ bool Model::IsResourceReady() const
   return mModelResourceReady && mIblDiffuseResourceReady && mIblSpecularResourceReady;
 }
 
-void Model::ScaleModel()
+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(bool useCurrentSize)
 {
   if(!mModelRoot)
   {
@@ -526,7 +584,7 @@ void Model::ScaleModel()
   }
 
   float   scale = 1.0f;
-  Vector3 size  = Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
+  Vector3 size  = (useCurrentSize) ? Self().GetCurrentProperty<Vector3>(Dali::Actor::Property::SIZE) : Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
   if(size.x > 0.0f && size.y > 0.0f)
   {
     scale = MAXFLOAT;
@@ -549,84 +607,64 @@ void Model::FitModelPosition()
   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.GetTexture(textureCount - OFFSET_FOR_DIFFUSE_CUBE_TEXTURE) != currentDiffuseTexture ||
-          textures.GetTexture(textureCount - OFFSET_FOR_SPECULAR_CUBE_TEXTURE) != currentSpecularTexture))
-      {
-        Dali::TextureSet newTextures = Dali::TextureSet::New();
-
-        for(uint32_t index = 0u; index < textureCount; ++index)
-        {
-          Dali::Texture texture = textures.GetTexture(index);
-          if(index == textureCount - OFFSET_FOR_DIFFUSE_CUBE_TEXTURE)
-          {
-            texture = currentDiffuseTexture;
-          }
-          else if(index == textureCount - OFFSET_FOR_SPECULAR_CUBE_TEXTURE)
-          {
-            texture = currentSpecularTexture;
-          }
-
-          newTextures.SetTexture(index, texture);
-          newTextures.SetSampler(index, textures.GetSampler(index));
-        }
-
-        renderer.SetTextures(newTextures);
-      }
-    }
-    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()
@@ -638,14 +676,7 @@ 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
@@ -687,13 +718,14 @@ 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)
     {
@@ -717,7 +749,7 @@ void Model::OnModelLoadComplete()
   {
     ResetResourceTasks();
 
-    if(ModelCacheManager::Get())
+    if(ModelCacheManager::Get() && !mModelUrl.empty())
     {
       ModelCacheManager::Get().UnreferenceModelCache(mModelUrl);
     }
@@ -725,9 +757,11 @@ void Model::OnModelLoadComplete()
     return;
   }
 
+  if(!mModelRoot)
+  {
+    CreateModelRoot();
+  }
   CreateModel();
-  mRenderableActors.clear();
-  CollectRenderableActor(mModelRoot);
 
   auto& resources = mModelLoadTask->GetResources();
   auto& scene     = mModelLoadTask->GetScene();
@@ -741,12 +775,6 @@ void Model::OnModelLoadComplete()
 
   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;
@@ -767,7 +795,8 @@ void Model::OnIblDiffuseLoadComplete()
 
 void Model::OnIblSpecularLoadComplete()
 {
-  mSpecularTexture = mIblSpecularLoadTask->GetLoadedTexture();
+  mSpecularTexture      = mIblSpecularLoadTask->GetLoadedTexture();
+  mSpecularMipmapLevels = mIblSpecularLoadTask->GetMipmapLevels();
   ResetResourceTask(mIblSpecularLoadTask);
   mIblSpecularResourceReady = true;
   if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
@@ -782,6 +811,11 @@ void Model::OnIblLoadComplete()
   NotifyResourceReady();
 }
 
+void Model::OnSizeNotification(Dali::PropertyNotification& source)
+{
+  ScaleModel(true);
+}
+
 void Model::ResetResourceTasks()
 {
   if(!Dali::Adaptor::IsAvailable())
@@ -814,13 +848,10 @@ void Model::NotifyResourceReady()
 
 void Model::CreateModel()
 {
-  mModelRoot = Actor::New();
-  mModelRoot.SetProperty(Actor::Property::COLOR_MODE, ColorMode::USE_OWN_MULTIPLY_PARENT_COLOR);
-
   BoundingVolume                                      AABB;
-  auto&                                               resources        = mModelLoadTask->GetResources();
-  auto&                                               scene            = mModelLoadTask->GetScene();
-  auto&                                               resourceChoices  = mModelLoadTask->GetResourceChoices();
+  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, {}, {}, {}};
 
@@ -830,7 +861,6 @@ void Model::CreateModel()
   {
     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));
 
@@ -851,7 +881,7 @@ void Model::CreateModel()
     Self().SetProperty(Dali::Actor::Property::SIZE, mNaturalSize);
   }
   FitModelPosition();
-  ScaleModel();
+  ScaleModel(false);
 }
 
 void Model::CreateAnimations(Dali::Scene3D::Loader::SceneDefinition& scene)
@@ -876,7 +906,7 @@ void Model::CreateAnimations(Dali::Scene3D::Loader::SceneDefinition& scene)
     for(auto&& animation : mModelLoadTask->GetAnimations())
     {
       Dali::Animation anim = animation.ReAnimate(getActor);
-      mAnimations.push_back({animation.mName, anim});
+      mAnimations.push_back({animation.GetName(), anim});
     }
   }
 }