[dali_2.3.21] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / internal / model-components / model-node-impl.cpp
1 /*
2  * Copyright (c) 2024 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-scene3d/internal/model-components/model-node-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali-toolkit/devel-api/controls/control-devel.h>
23 #include <dali/integration-api/debug.h>
24 #include <dali/public-api/object/type-registry-helper.h>
25 #include <dali/public-api/object/type-registry.h>
26
27 // INTERNAL INCLUDES
28 #include <dali-scene3d/internal/controls/model/model-impl.h>
29 #include <dali-scene3d/internal/light/light-impl.h>
30 #include <dali-scene3d/internal/model-components/model-primitive-impl.h>
31
32 namespace Dali
33 {
34 namespace Scene3D
35 {
36 namespace Internal
37 {
38 namespace
39 {
40 /**
41  * Creates control through type registry
42  */
43 BaseHandle Create()
44 {
45   return Scene3D::ModelNode::New();
46 }
47
48 // Setup properties, signals and actions using the type-registry.
49 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::ModelNode, Dali::CustomActor, Create);
50 DALI_TYPE_REGISTRATION_END()
51 } // unnamed namespace
52
53 Dali::Scene3D::ModelNode ModelNode::New()
54 {
55   // Create the implementation, temporarily owned on stack
56   IntrusivePtr<ModelNode> nodeImpl = new ModelNode();
57
58   // Pass ownership to handle
59   Scene3D::ModelNode handle(*nodeImpl);
60
61   // Second-phase init of the implementation
62   // This can only be done after the CustomActor connection has been made...
63   nodeImpl->Initialize();
64
65   return handle;
66 }
67
68 ModelNode::ModelNode()
69 : Control(static_cast<ControlBehaviour>(ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS | ActorFlags::DISABLE_SIZE_NEGOTIATION))
70 {
71 }
72
73 ModelNode::~ModelNode()
74 {
75 }
76
77 // From Internal::Control.
78
79 void ModelNode::OnInitialize()
80 {
81   Actor self = Self();
82
83   // TODO : We need to check this is enough.
84   Toolkit::DevelControl::EnableCreateAccessible(Toolkit::Control::DownCast(self), false);
85
86   self.RegisterProperty("uIsShadowCasting", static_cast<int>(mIsShadowCasting));
87   self.RegisterProperty("uIsShadowReceiving", static_cast<int>(mIsShadowReceiving));
88 }
89
90 // From CustomActorImpl.
91
92 void ModelNode::OnSceneConnection(int depth)
93 {
94 }
95
96 void ModelNode::OnSceneDisconnection()
97 {
98 }
99
100 void ModelNode::OnChildAdd(Actor& child)
101 {
102 }
103
104 void ModelNode::OnChildRemove(Actor& child)
105 {
106 }
107
108 void ModelNode::OnPropertySet(Property::Index index, const Property::Value& propertyValue)
109 {
110 }
111
112 void ModelNode::OnSizeSet(const Vector3& targetSize)
113 {
114 }
115
116 void ModelNode::OnSizeAnimation(Animation& animation, const Vector3& targetSize)
117 {
118   // @todo size negotiate background to new size, animate as well?
119 }
120
121 void ModelNode::OnRelayout(const Vector2& size, RelayoutContainer& container)
122 {
123 }
124
125 void ModelNode::OnSetResizePolicy(ResizePolicy::Type policy, Dimension::Type dimension)
126 {
127 }
128
129 Vector3 ModelNode::GetNaturalSize()
130 {
131   return Vector3::ZERO;
132 }
133
134 float ModelNode::CalculateChildSize(const Dali::Actor& child, Dimension::Type dimension)
135 {
136   return 0.0f;
137 }
138
139 float ModelNode::GetHeightForWidth(float width)
140 {
141   return 0.0f;
142 }
143
144 float ModelNode::GetWidthForHeight(float height)
145 {
146   return 0.0f;
147 }
148
149 bool ModelNode::RelayoutDependentOnChildren(Dimension::Type dimension)
150 {
151   return false;
152 }
153
154 void ModelNode::OnCalculateRelayoutSize(Dimension::Type dimension)
155 {
156 }
157
158 void ModelNode::OnLayoutNegotiated(float size, Dimension::Type dimension)
159 {
160 }
161
162 ModelNode& GetImplementation(Dali::Scene3D::ModelNode& handle)
163 {
164   CustomActorImpl& customInterface = handle.GetImplementation();
165   ModelNode&       impl            = dynamic_cast<Internal::ModelNode&>(customInterface);
166   return impl;
167 }
168
169 const ModelNode& GetImplementation(const Dali::Scene3D::ModelNode& handle)
170 {
171   const CustomActorImpl& customInterface = handle.GetImplementation();
172   // downcast to control
173   const ModelNode& impl = dynamic_cast<const Internal::ModelNode&>(customInterface);
174   return impl;
175 }
176
177 // Public Method
178
179 uint32_t ModelNode::GetModelPrimitiveCount() const
180 {
181   return static_cast<uint32_t>(mModelPrimitiveContainer.size());
182 }
183
184 void ModelNode::AddModelPrimitive(Dali::Scene3D::ModelPrimitive modelPrimitive, Loader::ShaderOption::HashType hash)
185 {
186   for(auto&& primitive : mModelPrimitiveContainer)
187   {
188     if(primitive == modelPrimitive)
189     {
190       return;
191     }
192   }
193
194   mModelPrimitiveContainer.push_back(modelPrimitive);
195
196   Actor self = Self();
197   GetImplementation(modelPrimitive).AddPrimitiveObserver(this);
198   if(mShadowMapTexture)
199   {
200     GetImplementation(modelPrimitive).SetShadowMapTexture(mShadowMapTexture);
201   }
202
203   if(mDiffuseTexture && mSpecularTexture)
204   {
205     GetImplementation(modelPrimitive).SetImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor, mSpecularMipmapLevels);
206   }
207
208   GetImplementation(modelPrimitive).UpdateShader(mShaderManager, hash);
209
210   Dali::Renderer renderer = GetImplementation(modelPrimitive).GetRenderer();
211   if(renderer)
212   {
213     uint32_t rendererCount = self.GetRendererCount();
214     bool     exist         = false;
215     for(uint32_t i = 0; i < rendererCount; ++i)
216     {
217       if(renderer == self.GetRendererAt(i))
218       {
219         exist = true;
220         break;
221       }
222     }
223     if(!exist)
224     {
225       self.AddRenderer(renderer);
226     }
227   }
228 }
229
230 void ModelNode::RemoveModelPrimitive(Dali::Scene3D::ModelPrimitive modelPrimitive)
231 {
232   uint32_t primitiveCount = GetModelPrimitiveCount();
233   for(uint32_t i = 0; i < primitiveCount; ++i)
234   {
235     if(mModelPrimitiveContainer[i] != modelPrimitive)
236     {
237       continue;
238     }
239
240     RemoveModelPrimitive(i);
241     break;
242   }
243 }
244
245 void ModelNode::RemoveModelPrimitive(uint32_t index)
246 {
247   if(index >= mModelPrimitiveContainer.size())
248   {
249     return;
250   }
251
252   GetImplementation(mModelPrimitiveContainer[index]).UpdateShader(nullptr, 0u);
253
254   Actor self = Self();
255   GetImplementation(mModelPrimitiveContainer[index]).RemovePrimitiveObserver(this);
256
257   Dali::Renderer renderer = GetImplementation(mModelPrimitiveContainer[index]).GetRenderer();
258   if(renderer)
259   {
260     self.RemoveRenderer(renderer);
261   }
262
263   mModelPrimitiveContainer.erase(mModelPrimitiveContainer.begin() + index);
264 }
265
266 Dali::Scene3D::ModelPrimitive ModelNode::GetModelPrimitive(uint32_t index) const
267 {
268   if(index < mModelPrimitiveContainer.size())
269   {
270     return mModelPrimitiveContainer[index];
271   }
272   return Scene3D::ModelPrimitive();
273 }
274
275 Scene3D::ModelNode ModelNode::FindChildModelNodeByName(std::string_view nodeName)
276 {
277   Actor childActor = Self().FindChildByName(nodeName);
278   return Scene3D::ModelNode::DownCast(childActor);
279 }
280
281 void ModelNode::RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const
282 {
283   blendShapeNames.reserve(blendShapeNames.size() + mBlendShapeIndexMap.size());
284   for(const auto& iter : mBlendShapeIndexMap)
285   {
286     blendShapeNames.push_back(iter.first);
287   }
288 }
289
290 Loader::BlendShapes::Index ModelNode::GetBlendShapeIndexByName(std::string_view blendShapeName) const
291 {
292   auto iter = mBlendShapeIndexMap.find(std::string(blendShapeName));
293   if(iter != mBlendShapeIndexMap.end())
294   {
295     return iter->second;
296   }
297   return Loader::BlendShapes::INVALID_INDEX;
298 }
299
300 void ModelNode::SetShadowMapTexture(Dali::Texture shadowMapTexture)
301 {
302   mShadowMapTexture = shadowMapTexture;
303   for(auto&& primitive : mModelPrimitiveContainer)
304   {
305     GetImplementation(primitive).SetShadowMapTexture(mShadowMapTexture);
306   }
307 }
308
309 void ModelNode::CastShadow(bool castShadow)
310 {
311   if(mIsShadowCasting == castShadow)
312   {
313     return;
314   }
315
316   mIsShadowCasting = castShadow;
317
318   Actor self = Self();
319   self.RegisterProperty("uIsShadowCasting", static_cast<int>(mIsShadowCasting));
320 }
321
322 bool ModelNode::IsShadowCasting() const
323 {
324   return mIsShadowCasting;
325 }
326
327 void ModelNode::ReceiveShadow(bool receiveShadow)
328 {
329   if(mIsShadowReceiving == receiveShadow)
330   {
331     return;
332   }
333
334   mIsShadowReceiving = receiveShadow;
335
336   Actor self = Self();
337   self.RegisterProperty("uIsShadowReceiving", static_cast<int>(mIsShadowReceiving));
338 }
339
340 bool ModelNode::IsShadowReceiving() const
341 {
342   return mIsShadowReceiving;
343 }
344
345 void ModelNode::SetImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
346 {
347   mDiffuseTexture       = diffuseTexture;
348   mSpecularTexture      = specularTexture;
349   mIblScaleFactor       = iblScaleFactor;
350   mSpecularMipmapLevels = specularMipmapLevels;
351   for(auto&& primitive : mModelPrimitiveContainer)
352   {
353     GetImplementation(primitive).SetImageBasedLightTexture(diffuseTexture, specularTexture, iblScaleFactor, specularMipmapLevels);
354   }
355 }
356
357 void ModelNode::SetImageBasedLightScaleFactor(float iblScaleFactor)
358 {
359   mIblScaleFactor = iblScaleFactor;
360   for(auto&& primitive : mModelPrimitiveContainer)
361   {
362     GetImplementation(primitive).SetImageBasedLightScaleFactor(iblScaleFactor);
363   }
364 }
365
366 void ModelNode::UpdateShader(Scene3D::Loader::ShaderManagerPtr shaderManager)
367 {
368   if(mShaderManager != shaderManager)
369   {
370     mShaderManager = shaderManager;
371     for(auto&& primitive : mModelPrimitiveContainer)
372     {
373       GetImplementation(primitive).UpdateShader(mShaderManager, 0u);
374     }
375   }
376 }
377
378 void ModelNode::SetBlendShapeData(Scene3D::Loader::BlendShapes::BlendShapeData& data, Scene3D::ModelPrimitive primitive)
379 {
380   // Update mBlendShapeIndexMap
381   mBlendShapeIndexMap.clear();
382   const auto blendShapeCount = data.names.size();
383   for(Loader::BlendShapes::Index index = 0u; index < blendShapeCount; ++index)
384   {
385     auto& name = data.names[index];
386     if(!name.empty())
387     {
388       mBlendShapeIndexMap[name] = index;
389     }
390   }
391
392   GetImplementation(primitive).SetBlendShapeData(data);
393 }
394
395 void ModelNode::SetBoneMatrix(const Matrix& inverseMatrix, Scene3D::ModelPrimitive primitive, Scene3D::Loader::Index& boneIndex)
396 {
397   Dali::Scene3D::Loader::Skinning::BoneData boneData;
398   boneData.primitive = primitive;
399   boneData.boneIndex = boneIndex;
400   char propertyNameBuffer[32];
401   snprintf(propertyNameBuffer, sizeof(propertyNameBuffer), "%s[%d]", Dali::Scene3D::Loader::Skinning::BONE_UNIFORM_NAME, boneIndex);
402   boneData.propertyName  = propertyNameBuffer;
403   boneData.inverseMatrix = inverseMatrix;
404   mBoneDataContainer.push_back(std::move(boneData));
405
406   UpdateBoneMatrix(primitive);
407 }
408
409 void ModelNode::OnRendererCreated(Renderer renderer)
410 {
411   Self().AddRenderer(renderer);
412 }
413
414 void ModelNode::UpdateBoneMatrix(Scene3D::ModelPrimitive primitive)
415 {
416   for(auto&& boneData : mBoneDataContainer)
417   {
418     if(boneData.primitive != primitive)
419     {
420       continue;
421     }
422
423     Dali::Renderer renderer = GetImplementation(primitive).GetRenderer();
424     if(!renderer)
425     {
426       continue;
427     }
428
429     if(boneData.constraint)
430     {
431       boneData.constraint.Remove();
432       boneData.constraint.Reset();
433     }
434
435     auto propBoneXform = renderer.GetPropertyIndex(boneData.propertyName);
436     if(propBoneXform == Property::INVALID_INDEX)
437     {
438       propBoneXform = renderer.RegisterProperty(boneData.propertyName, Matrix{false});
439     }
440
441     Matrix inverseMatrix = boneData.inverseMatrix;
442     // Constrain bone matrix to joint transform.
443     boneData.constraint = Constraint::New<Matrix>(renderer, propBoneXform, [inverseMatrix](Matrix& output, const PropertyInputContainer& inputs) { Matrix::Multiply(output, inverseMatrix, inputs[0]->GetMatrix()); });
444
445     Actor joint = Self();
446     boneData.constraint.AddSource(Source{joint, Actor::Property::WORLD_MATRIX});
447     boneData.constraint.ApplyPost();
448     break;
449   }
450 }
451
452 void ModelNode::SetColliderMesh(ColliderMeshUniquePtr&& colliderMesh)
453 {
454   if(!colliderMesh && !mColliderMesh)
455   {
456     return;
457   }
458
459   if(!mParentModel) // find parent model if not set
460   {
461     auto parent = Self().GetParent();
462     while(parent)
463     {
464       auto modelHandle = Scene3D::Model::DownCast(parent);
465       if(modelHandle)
466       {
467         mParentModel = &GetImpl(modelHandle);
468         break;
469       }
470       parent = parent.GetParent();
471     }
472   }
473
474   // Resetting collider mesh if argument is nullptr
475   auto handle = Scene3D::ModelNode::DownCast(Self());
476   if(mParentModel)
477   {
478     if(mColliderMesh)
479     {
480       mParentModel->RemoveColliderMesh(handle);
481     }
482
483     // If collider mesh is to be set then register it with the parent model.
484     // If nullptr, ignore.
485     if(colliderMesh)
486     {
487       mParentModel->RegisterColliderMesh(handle);
488     }
489   }
490
491   mColliderMesh = std::move(colliderMesh);
492 }
493
494 bool ModelNode::HasColliderMesh() const
495 {
496   return mColliderMesh != nullptr;
497 }
498
499 const Scene3D::Algorithm::ColliderMesh& ModelNode::GetColliderMesh() const
500 {
501   return *mColliderMesh;
502 }
503
504 } // namespace Internal
505
506 } // namespace Scene3D
507
508 } // namespace Dali