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