Makes Models use common shader manager
[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/light/light-impl.h>
28 #include <dali-scene3d/internal/model-components/model-primitive-impl.h>
29
30 namespace Dali
31 {
32 namespace Scene3D
33 {
34 namespace Internal
35 {
36 namespace
37 {
38 /**
39  * Creates control through type registry
40  */
41 BaseHandle Create()
42 {
43   return Scene3D::ModelNode::New();
44 }
45
46 // Setup properties, signals and actions using the type-registry.
47 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::ModelNode, Dali::CustomActor, Create);
48 DALI_TYPE_REGISTRATION_END()
49 } // unnamed namespace
50
51 Dali::Scene3D::ModelNode ModelNode::New()
52 {
53   // Create the implementation, temporarily owned on stack
54   IntrusivePtr<ModelNode> nodeImpl = new ModelNode();
55
56   // Pass ownership to handle
57   Scene3D::ModelNode handle(*nodeImpl);
58
59   // Second-phase init of the implementation
60   // This can only be done after the CustomActor connection has been made...
61   nodeImpl->Initialize();
62
63   return handle;
64 }
65
66 ModelNode::ModelNode()
67 : CustomActorImpl(ActorFlags::DISABLE_SIZE_NEGOTIATION)
68 {
69 }
70
71 ModelNode::~ModelNode()
72 {
73 }
74
75 void ModelNode::Initialize()
76 {
77   OnInitialize();
78   mLights.resize(Scene3D::Internal::Light::GetMaximumEnabledLightCount());
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)
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(mDiffuseTexture && mSpecularTexture)
192   {
193     GetImplementation(modelPrimitive).SetImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor, mSpecularMipmapLevels);
194   }
195
196   uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
197   for(uint32_t i = 0; i < maxLightCount; ++i)
198   {
199     if(mLights[i])
200     {
201       GetImplementation(modelPrimitive).AddLight(mLights[i], i);
202     }
203   }
204
205   GetImplementation(modelPrimitive).UpdateShader(mShaderManager);
206
207   Dali::Renderer renderer = GetImplementation(modelPrimitive).GetRenderer();
208   if(renderer)
209   {
210     uint32_t rendererCount = self.GetRendererCount();
211     bool     exist         = false;
212     for(uint32_t i = 0; i < rendererCount; ++i)
213     {
214       if(renderer == self.GetRendererAt(i))
215       {
216         exist = true;
217         break;
218       }
219     }
220     if(!exist)
221     {
222       self.AddRenderer(renderer);
223     }
224   }
225 }
226
227 void ModelNode::RemoveModelPrimitive(Dali::Scene3D::ModelPrimitive modelPrimitive)
228 {
229   uint32_t primitiveCount = GetModelPrimitiveCount();
230   for(uint32_t i = 0; i < primitiveCount; ++i)
231   {
232     if(mModelPrimitiveContainer[i] != modelPrimitive)
233     {
234       continue;
235     }
236
237     RemoveModelPrimitive(i);
238     break;
239   }
240 }
241
242 void ModelNode::RemoveModelPrimitive(uint32_t index)
243 {
244   if(index >= mModelPrimitiveContainer.size())
245   {
246     return;
247   }
248
249   GetImplementation(mModelPrimitiveContainer[index]).UpdateShader(nullptr);
250
251   uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
252   for(uint32_t i = 0; i < maxLightCount; ++i)
253   {
254     if(mLights[i])
255     {
256       GetImplementation(mModelPrimitiveContainer[index]).RemoveLight(i);
257     }
258   }
259
260   Actor self = Self();
261   GetImplementation(mModelPrimitiveContainer[index]).RemovePrimitiveObserver(this);
262
263   Dali::Renderer renderer = GetImplementation(mModelPrimitiveContainer[index]).GetRenderer();
264   if(renderer)
265   {
266     self.RemoveRenderer(renderer);
267   }
268
269   mModelPrimitiveContainer.erase(mModelPrimitiveContainer.begin() + index);
270 }
271
272 Dali::Scene3D::ModelPrimitive ModelNode::GetModelPrimitive(uint32_t index) const
273 {
274   if(index < mModelPrimitiveContainer.size())
275   {
276     return mModelPrimitiveContainer[index];
277   }
278   return Scene3D::ModelPrimitive();
279 }
280
281 Scene3D::ModelNode ModelNode::FindChildModelNodeByName(std::string_view nodeName)
282 {
283   Actor childActor = Self().FindChildByName(nodeName);
284   return Scene3D::ModelNode::DownCast(childActor);
285 }
286
287 void ModelNode::RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const
288 {
289   blendShapeNames.reserve(blendShapeNames.size() + mBlendShapeIndexMap.size());
290   for(const auto& iter : mBlendShapeIndexMap)
291   {
292     blendShapeNames.push_back(iter.first);
293   }
294 }
295
296 Loader::BlendShapes::Index ModelNode::GetBlendShapeIndexByName(std::string_view blendShapeName) const
297 {
298   auto iter = mBlendShapeIndexMap.find(std::string(blendShapeName));
299   if(iter != mBlendShapeIndexMap.end())
300   {
301     return iter->second;
302   }
303   return Loader::BlendShapes::INVALID_INDEX;
304 }
305
306 void ModelNode::SetImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
307 {
308   mDiffuseTexture       = diffuseTexture;
309   mSpecularTexture      = specularTexture;
310   mIblScaleFactor       = iblScaleFactor;
311   mSpecularMipmapLevels = specularMipmapLevels;
312   for(auto&& primitive : mModelPrimitiveContainer)
313   {
314     GetImplementation(primitive).SetImageBasedLightTexture(diffuseTexture, specularTexture, iblScaleFactor, specularMipmapLevels);
315   }
316 }
317
318 void ModelNode::SetImageBasedLightScaleFactor(float iblScaleFactor)
319 {
320   mIblScaleFactor = iblScaleFactor;
321   for(auto&& primitive : mModelPrimitiveContainer)
322   {
323     GetImplementation(primitive).SetImageBasedLightScaleFactor(iblScaleFactor);
324   }
325 }
326
327 void ModelNode::AddLight(Scene3D::Light light, uint32_t lightIndex)
328 {
329   mLights[lightIndex] = light;
330   for(auto&& primitive : mModelPrimitiveContainer)
331   {
332     GetImplementation(primitive).AddLight(light, lightIndex);
333   }
334 }
335
336 void ModelNode::RemoveLight(uint32_t lightIndex)
337 {
338   for(auto&& primitive : mModelPrimitiveContainer)
339   {
340     GetImplementation(primitive).RemoveLight(lightIndex);
341   }
342   mLights[lightIndex].Reset();
343 }
344
345 void ModelNode::UpdateShader(Scene3D::Loader::ShaderManagerPtr shaderManager)
346 {
347   if(mShaderManager != shaderManager)
348   {
349     mShaderManager = shaderManager;
350     for(auto&& primitive : mModelPrimitiveContainer)
351     {
352       GetImplementation(primitive).UpdateShader(mShaderManager);
353     }
354   }
355 }
356
357 void ModelNode::SetBlendShapeData(Scene3D::Loader::BlendShapes::BlendShapeData& data, Scene3D::ModelPrimitive primitive)
358 {
359   // Update mBlendShapeIndexMap
360   mBlendShapeIndexMap.clear();
361   const auto blendShapeCount = data.names.size();
362   for(Loader::BlendShapes::Index index = 0u; index < blendShapeCount; ++index)
363   {
364     auto& name = data.names[index];
365     if(!name.empty())
366     {
367       mBlendShapeIndexMap[name] = index;
368     }
369   }
370
371   GetImplementation(primitive).SetBlendShapeData(data);
372 }
373
374 void ModelNode::SetBoneMatrix(const Matrix& inverseMatrix, Scene3D::ModelPrimitive primitive, Scene3D::Loader::Index& boneIndex)
375 {
376   Dali::Scene3D::Loader::Skinning::BoneData boneData;
377   boneData.primitive = primitive;
378   boneData.boneIndex = boneIndex;
379   char propertyNameBuffer[32];
380   snprintf(propertyNameBuffer, sizeof(propertyNameBuffer), "%s[%d]", Dali::Scene3D::Loader::Skinning::BONE_UNIFORM_NAME, boneIndex);
381   boneData.propertyName  = propertyNameBuffer;
382   boneData.inverseMatrix = inverseMatrix;
383   mBoneDataContainer.push_back(std::move(boneData));
384
385   UpdateBoneMatrix(primitive);
386 }
387
388 void ModelNode::OnRendererCreated(Renderer renderer)
389 {
390   Self().AddRenderer(renderer);
391 }
392
393 void ModelNode::UpdateBoneMatrix(Scene3D::ModelPrimitive primitive)
394 {
395   for(auto&& boneData : mBoneDataContainer)
396   {
397     if(boneData.primitive != primitive)
398     {
399       continue;
400     }
401
402     Dali::Renderer renderer = GetImplementation(primitive).GetRenderer();
403     if(!renderer)
404     {
405       continue;
406     }
407
408     if(boneData.constraint)
409     {
410       boneData.constraint.Remove();
411       boneData.constraint.Reset();
412     }
413
414     auto propBoneXform = renderer.GetPropertyIndex(boneData.propertyName);
415     if(propBoneXform == Property::INVALID_INDEX)
416     {
417       propBoneXform = renderer.RegisterProperty(boneData.propertyName, Matrix{false});
418     }
419
420     Matrix inverseMatrix = boneData.inverseMatrix;
421     // Constrain bone matrix to joint transform.
422     boneData.constraint = Constraint::New<Matrix>(renderer, propBoneXform, [inverseMatrix](Matrix& output, const PropertyInputContainer& inputs) { Matrix::Multiply(output, inverseMatrix, inputs[0]->GetMatrix()); });
423
424     Actor joint = Self();
425     boneData.constraint.AddSource(Source{joint, Actor::Property::WORLD_MATRIX});
426     boneData.constraint.ApplyPost();
427     break;
428   }
429 }
430
431 } // namespace Internal
432
433 } // namespace Scene3D
434
435 } // namespace Dali