Add CastShadow and ReceiveShadow for Model and ModelNode
[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/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 : Control(static_cast<ControlBehaviour>(ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS | 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   Actor self = Self();
84   self.RegisterProperty("uIsShadowCasting", static_cast<int>(mIsShadowCasting));
85   self.RegisterProperty("uIsShadowReceiving", static_cast<int>(mIsShadowReceiving));
86 }
87
88 void ModelNode::OnSceneConnection(int depth)
89 {
90 }
91
92 void ModelNode::OnSceneDisconnection()
93 {
94 }
95
96 void ModelNode::OnChildAdd(Actor& child)
97 {
98 }
99
100 void ModelNode::OnChildRemove(Actor& child)
101 {
102 }
103
104 void ModelNode::OnPropertySet(Property::Index index, const Property::Value& propertyValue)
105 {
106 }
107
108 void ModelNode::OnSizeSet(const Vector3& targetSize)
109 {
110 }
111
112 void ModelNode::OnSizeAnimation(Animation& animation, const Vector3& targetSize)
113 {
114   // @todo size negotiate background to new size, animate as well?
115 }
116
117 void ModelNode::OnRelayout(const Vector2& size, RelayoutContainer& container)
118 {
119 }
120
121 void ModelNode::OnSetResizePolicy(ResizePolicy::Type policy, Dimension::Type dimension)
122 {
123 }
124
125 Vector3 ModelNode::GetNaturalSize()
126 {
127   return Vector3::ZERO;
128 }
129
130 float ModelNode::CalculateChildSize(const Dali::Actor& child, Dimension::Type dimension)
131 {
132   return 0.0f;
133 }
134
135 float ModelNode::GetHeightForWidth(float width)
136 {
137   return 0.0f;
138 }
139
140 float ModelNode::GetWidthForHeight(float height)
141 {
142   return 0.0f;
143 }
144
145 bool ModelNode::RelayoutDependentOnChildren(Dimension::Type dimension)
146 {
147   return false;
148 }
149
150 void ModelNode::OnCalculateRelayoutSize(Dimension::Type dimension)
151 {
152 }
153
154 void ModelNode::OnLayoutNegotiated(float size, Dimension::Type dimension)
155 {
156 }
157
158 ModelNode& GetImplementation(Dali::Scene3D::ModelNode& handle)
159 {
160   CustomActorImpl& customInterface = handle.GetImplementation();
161   ModelNode&       impl            = dynamic_cast<Internal::ModelNode&>(customInterface);
162   return impl;
163 }
164
165 const ModelNode& GetImplementation(const Dali::Scene3D::ModelNode& handle)
166 {
167   const CustomActorImpl& customInterface = handle.GetImplementation();
168   // downcast to control
169   const ModelNode& impl = dynamic_cast<const Internal::ModelNode&>(customInterface);
170   return impl;
171 }
172
173 // Public Method
174
175 uint32_t ModelNode::GetModelPrimitiveCount() const
176 {
177   return static_cast<uint32_t>(mModelPrimitiveContainer.size());
178 }
179
180 void ModelNode::AddModelPrimitive(Dali::Scene3D::ModelPrimitive modelPrimitive, Loader::ShaderOption::HashType hash)
181 {
182   for(auto&& primitive : mModelPrimitiveContainer)
183   {
184     if(primitive == modelPrimitive)
185     {
186       return;
187     }
188   }
189
190   mModelPrimitiveContainer.push_back(modelPrimitive);
191
192   Actor self = Self();
193   GetImplementation(modelPrimitive).AddPrimitiveObserver(this);
194   if(mShadowMapTexture)
195   {
196     GetImplementation(modelPrimitive).SetShadowMapTexture(mShadowMapTexture);
197   }
198
199   if(mDiffuseTexture && mSpecularTexture)
200   {
201     GetImplementation(modelPrimitive).SetImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor, mSpecularMipmapLevels);
202   }
203
204   GetImplementation(modelPrimitive).UpdateShader(mShaderManager, hash);
205
206   Dali::Renderer renderer = GetImplementation(modelPrimitive).GetRenderer();
207   if(renderer)
208   {
209     uint32_t rendererCount = self.GetRendererCount();
210     bool     exist         = false;
211     for(uint32_t i = 0; i < rendererCount; ++i)
212     {
213       if(renderer == self.GetRendererAt(i))
214       {
215         exist = true;
216         break;
217       }
218     }
219     if(!exist)
220     {
221       self.AddRenderer(renderer);
222     }
223   }
224 }
225
226 void ModelNode::RemoveModelPrimitive(Dali::Scene3D::ModelPrimitive modelPrimitive)
227 {
228   uint32_t primitiveCount = GetModelPrimitiveCount();
229   for(uint32_t i = 0; i < primitiveCount; ++i)
230   {
231     if(mModelPrimitiveContainer[i] != modelPrimitive)
232     {
233       continue;
234     }
235
236     RemoveModelPrimitive(i);
237     break;
238   }
239 }
240
241 void ModelNode::RemoveModelPrimitive(uint32_t index)
242 {
243   if(index >= mModelPrimitiveContainer.size())
244   {
245     return;
246   }
247
248   GetImplementation(mModelPrimitiveContainer[index]).UpdateShader(nullptr, 0u);
249
250   Actor self = Self();
251   GetImplementation(mModelPrimitiveContainer[index]).RemovePrimitiveObserver(this);
252
253   Dali::Renderer renderer = GetImplementation(mModelPrimitiveContainer[index]).GetRenderer();
254   if(renderer)
255   {
256     self.RemoveRenderer(renderer);
257   }
258
259   mModelPrimitiveContainer.erase(mModelPrimitiveContainer.begin() + index);
260 }
261
262 Dali::Scene3D::ModelPrimitive ModelNode::GetModelPrimitive(uint32_t index) const
263 {
264   if(index < mModelPrimitiveContainer.size())
265   {
266     return mModelPrimitiveContainer[index];
267   }
268   return Scene3D::ModelPrimitive();
269 }
270
271 Scene3D::ModelNode ModelNode::FindChildModelNodeByName(std::string_view nodeName)
272 {
273   Actor childActor = Self().FindChildByName(nodeName);
274   return Scene3D::ModelNode::DownCast(childActor);
275 }
276
277 void ModelNode::RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const
278 {
279   blendShapeNames.reserve(blendShapeNames.size() + mBlendShapeIndexMap.size());
280   for(const auto& iter : mBlendShapeIndexMap)
281   {
282     blendShapeNames.push_back(iter.first);
283   }
284 }
285
286 Loader::BlendShapes::Index ModelNode::GetBlendShapeIndexByName(std::string_view blendShapeName) const
287 {
288   auto iter = mBlendShapeIndexMap.find(std::string(blendShapeName));
289   if(iter != mBlendShapeIndexMap.end())
290   {
291     return iter->second;
292   }
293   return Loader::BlendShapes::INVALID_INDEX;
294 }
295
296 void ModelNode::SetShadowMapTexture(Dali::Texture shadowMapTexture)
297 {
298   mShadowMapTexture = shadowMapTexture;
299   for(auto&& primitive : mModelPrimitiveContainer)
300   {
301     GetImplementation(primitive).SetShadowMapTexture(mShadowMapTexture);
302   }
303 }
304
305 void ModelNode::CastShadow(bool castShadow)
306 {
307   if(mIsShadowCasting == castShadow)
308   {
309     return;
310   }
311
312   mIsShadowCasting = castShadow;
313
314   Actor self = Self();
315   self.RegisterProperty("uIsShadowCasting", static_cast<int>(mIsShadowCasting));
316 }
317
318 bool ModelNode::IsShadowCasting() const
319 {
320   return mIsShadowCasting;
321 }
322
323 void ModelNode::ReceiveShadow(bool receiveShadow)
324 {
325   if(mIsShadowReceiving == receiveShadow)
326   {
327     return;
328   }
329
330   mIsShadowReceiving = receiveShadow;
331
332   Actor self = Self();
333   self.RegisterProperty("uIsShadowReceiving", static_cast<int>(mIsShadowReceiving));
334 }
335
336 bool ModelNode::IsShadowReceiving() const
337 {
338   return mIsShadowReceiving;
339 }
340
341 void ModelNode::SetImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
342 {
343   mDiffuseTexture       = diffuseTexture;
344   mSpecularTexture      = specularTexture;
345   mIblScaleFactor       = iblScaleFactor;
346   mSpecularMipmapLevels = specularMipmapLevels;
347   for(auto&& primitive : mModelPrimitiveContainer)
348   {
349     GetImplementation(primitive).SetImageBasedLightTexture(diffuseTexture, specularTexture, iblScaleFactor, specularMipmapLevels);
350   }
351 }
352
353 void ModelNode::SetImageBasedLightScaleFactor(float iblScaleFactor)
354 {
355   mIblScaleFactor = iblScaleFactor;
356   for(auto&& primitive : mModelPrimitiveContainer)
357   {
358     GetImplementation(primitive).SetImageBasedLightScaleFactor(iblScaleFactor);
359   }
360 }
361
362 void ModelNode::UpdateShader(Scene3D::Loader::ShaderManagerPtr shaderManager)
363 {
364   if(mShaderManager != shaderManager)
365   {
366     mShaderManager = shaderManager;
367     for(auto&& primitive : mModelPrimitiveContainer)
368     {
369       GetImplementation(primitive).UpdateShader(mShaderManager, 0u);
370     }
371   }
372 }
373
374 void ModelNode::SetBlendShapeData(Scene3D::Loader::BlendShapes::BlendShapeData& data, Scene3D::ModelPrimitive primitive)
375 {
376   // Update mBlendShapeIndexMap
377   mBlendShapeIndexMap.clear();
378   const auto blendShapeCount = data.names.size();
379   for(Loader::BlendShapes::Index index = 0u; index < blendShapeCount; ++index)
380   {
381     auto& name = data.names[index];
382     if(!name.empty())
383     {
384       mBlendShapeIndexMap[name] = index;
385     }
386   }
387
388   GetImplementation(primitive).SetBlendShapeData(data);
389 }
390
391 void ModelNode::SetBoneMatrix(const Matrix& inverseMatrix, Scene3D::ModelPrimitive primitive, Scene3D::Loader::Index& boneIndex)
392 {
393   Dali::Scene3D::Loader::Skinning::BoneData boneData;
394   boneData.primitive = primitive;
395   boneData.boneIndex = boneIndex;
396   char propertyNameBuffer[32];
397   snprintf(propertyNameBuffer, sizeof(propertyNameBuffer), "%s[%d]", Dali::Scene3D::Loader::Skinning::BONE_UNIFORM_NAME, boneIndex);
398   boneData.propertyName  = propertyNameBuffer;
399   boneData.inverseMatrix = inverseMatrix;
400   mBoneDataContainer.push_back(std::move(boneData));
401
402   UpdateBoneMatrix(primitive);
403 }
404
405 void ModelNode::OnRendererCreated(Renderer renderer)
406 {
407   Self().AddRenderer(renderer);
408 }
409
410 void ModelNode::UpdateBoneMatrix(Scene3D::ModelPrimitive primitive)
411 {
412   for(auto&& boneData : mBoneDataContainer)
413   {
414     if(boneData.primitive != primitive)
415     {
416       continue;
417     }
418
419     Dali::Renderer renderer = GetImplementation(primitive).GetRenderer();
420     if(!renderer)
421     {
422       continue;
423     }
424
425     if(boneData.constraint)
426     {
427       boneData.constraint.Remove();
428       boneData.constraint.Reset();
429     }
430
431     auto propBoneXform = renderer.GetPropertyIndex(boneData.propertyName);
432     if(propBoneXform == Property::INVALID_INDEX)
433     {
434       propBoneXform = renderer.RegisterProperty(boneData.propertyName, Matrix{false});
435     }
436
437     Matrix inverseMatrix = boneData.inverseMatrix;
438     // Constrain bone matrix to joint transform.
439     boneData.constraint = Constraint::New<Matrix>(renderer, propBoneXform, [inverseMatrix](Matrix& output, const PropertyInputContainer& inputs) { Matrix::Multiply(output, inverseMatrix, inputs[0]->GetMatrix()); });
440
441     Actor joint = Self();
442     boneData.constraint.AddSource(Source{joint, Actor::Property::WORLD_MATRIX});
443     boneData.constraint.ApplyPost();
444     break;
445   }
446 }
447
448 void ModelNode::SetColliderMesh(ColliderMeshUniquePtr&& colliderMesh)
449 {
450   if(!colliderMesh && !mColliderMesh)
451   {
452     return;
453   }
454
455   if(!mParentModel) // find parent model if not set
456   {
457     auto parent = Self().GetParent();
458     while(parent)
459     {
460       auto modelHandle = Scene3D::Model::DownCast(parent);
461       if(modelHandle)
462       {
463         mParentModel = &GetImpl(modelHandle);
464         break;
465       }
466       parent = parent.GetParent();
467     }
468   }
469
470   // Resetting collider mesh if argument is nullptr
471   auto handle = Scene3D::ModelNode::DownCast(Self());
472   if(mParentModel)
473   {
474     if(mColliderMesh)
475     {
476       mParentModel->RemoveColliderMesh(handle);
477     }
478
479     // If collider mesh is to be set then register it with the parent model.
480     // If nullptr, ignore.
481     if(colliderMesh)
482     {
483       mParentModel->RegisterColliderMesh(handle);
484     }
485   }
486
487   mColliderMesh = std::move(colliderMesh);
488 }
489
490 bool ModelNode::HasColliderMesh() const
491 {
492   return mColliderMesh != nullptr;
493 }
494
495 const Scene3D::Algorithm::ColliderMesh& ModelNode::GetColliderMesh() const
496 {
497   return *mColliderMesh;
498 }
499
500 } // namespace Internal
501
502 } // namespace Scene3D
503
504 } // namespace Dali