Fix transform issue of skinned mesh
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / internal / model-components / model-node-data-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-data-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/model-components/model-primitive-impl.h>
28 #include <dali-scene3d/public-api/model-components/model-node.h>
29
30 namespace
31 {
32 } // namespace
33
34 namespace Dali
35 {
36 namespace Scene3D
37 {
38 namespace Internal
39 {
40 namespace
41 {
42 /**
43  * Creates control through type registry
44  */
45 BaseHandle Create()
46 {
47   return Scene3D::ModelNode::New();
48 }
49
50 // Setup properties, signals and actions using the type-registry.
51 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::ModelNode, Dali::CustomActor, Create);
52 DALI_TYPE_REGISTRATION_END()
53 } // unnamed namespace
54
55 ModelNode::Impl::Impl(ModelNode& modelNodeImpl)
56 : mModelNodeImpl(modelNodeImpl)
57 {
58 }
59
60 ModelNode::Impl::~Impl()
61 {
62   for(auto&& primitive : mModelPrimitiveContainer)
63   {
64     GetImplementation(primitive).RemovePrimitiveObserver(this);
65   }
66   for(auto&& boneData : mBoneDataContainer)
67   {
68     boneData.primitive.Reset();
69     if(boneData.constraint)
70     {
71       boneData.constraint.Remove();
72       boneData.constraint.Reset();
73     }
74   }
75 }
76
77 void ModelNode::Impl::OnSceneConnection(int depth)
78 {
79 }
80
81 void ModelNode::Impl::OnSceneDisconnection()
82 {
83 }
84
85 void ModelNode::Impl::OnRendererCreated(Renderer renderer)
86 {
87   mModelNodeImpl.Self().AddRenderer(renderer);
88 }
89
90 // Public Method
91
92 void ModelNode::Impl::AddModelPrimitive(Scene3D::ModelPrimitive modelPrimitive)
93 {
94   for(auto&& primitive : mModelPrimitiveContainer)
95   {
96     if(primitive == modelPrimitive)
97     {
98       return;
99     }
100   }
101
102   mModelPrimitiveContainer.push_back(modelPrimitive);
103
104   Actor self = mModelNodeImpl.Self();
105
106   GetImplementation(modelPrimitive).AddPrimitiveObserver(this);
107   if(mDiffuseTexture && mSpecularTexture)
108   {
109     GetImplementation(modelPrimitive).SetImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor, mSpecularMipmapLevels);
110   }
111
112   Dali::Renderer renderer = GetImplementation(modelPrimitive).GetRenderer();
113   if(renderer)
114   {
115     uint32_t rendererCount = self.GetRendererCount();
116     bool     exist         = false;
117     for(uint32_t i = 0; i < rendererCount; ++i)
118     {
119       if(renderer == self.GetRendererAt(i))
120       {
121         exist = true;
122         break;
123       }
124     }
125     if(!exist)
126     {
127       self.AddRenderer(renderer);
128     }
129   }
130 }
131
132 void ModelNode::Impl::RemoveModelPrimitive(Scene3D::ModelPrimitive modelPrimitive)
133 {
134   uint32_t primitiveCount = GetModelPrimitiveCount();
135   for(uint32_t i = 0; i < primitiveCount; ++i)
136   {
137     if(mModelPrimitiveContainer[i] != modelPrimitive)
138     {
139       continue;
140     }
141     RemoveModelPrimitive(i);
142     break;
143   }
144 }
145
146 void ModelNode::Impl::RemoveModelPrimitive(uint32_t index)
147 {
148   if(index >= mModelPrimitiveContainer.size())
149   {
150     return;
151   }
152
153   Actor self = mModelNodeImpl.Self();
154   GetImplementation(mModelPrimitiveContainer[index]).RemovePrimitiveObserver(this);
155
156   Dali::Renderer renderer = GetImplementation(mModelPrimitiveContainer[index]).GetRenderer();
157   if(renderer)
158   {
159     self.RemoveRenderer(renderer);
160   }
161
162   mModelPrimitiveContainer.erase(mModelPrimitiveContainer.begin() + index);
163 }
164
165 Scene3D::ModelPrimitive ModelNode::Impl::GetModelPrimitive(uint32_t index) const
166 {
167   if(index < mModelPrimitiveContainer.size())
168   {
169     return mModelPrimitiveContainer[index];
170   }
171   return Scene3D::ModelPrimitive();
172 }
173
174 void ModelNode::Impl::SetImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
175 {
176   mDiffuseTexture       = diffuseTexture;
177   mSpecularTexture      = specularTexture;
178   mIblScaleFactor       = iblScaleFactor;
179   mSpecularMipmapLevels = specularMipmapLevels;
180   for(auto&& primitive : mModelPrimitiveContainer)
181   {
182     GetImplementation(primitive).SetImageBasedLightTexture(diffuseTexture, specularTexture, iblScaleFactor, specularMipmapLevels);
183   }
184 }
185
186 void ModelNode::Impl::SetImageBasedLightScaleFactor(float iblScaleFactor)
187 {
188   mIblScaleFactor = iblScaleFactor;
189   for(auto&& primitive : mModelPrimitiveContainer)
190   {
191     GetImplementation(primitive).SetImageBasedLightScaleFactor(iblScaleFactor);
192   }
193 }
194
195 void ModelNode::Impl::SetBlendShapeData(Scene3D::Loader::BlendShapes::BlendShapeData& data, Scene3D::ModelPrimitive primitive)
196 {
197   GetImplementation(primitive).SetBlendShapeData(data);
198 }
199
200 void ModelNode::Impl::SetBoneMatrix(const Matrix& inverseMatrix, Scene3D::ModelPrimitive primitive, Scene3D::Loader::Index& boneIndex)
201 {
202   Dali::Scene3D::Loader::Skinning::BoneData boneData;
203   boneData.primitive = primitive;
204   boneData.boneIndex = boneIndex;
205   char propertyNameBuffer[32];
206   snprintf(propertyNameBuffer, sizeof(propertyNameBuffer), "%s[%d]", Dali::Scene3D::Loader::Skinning::BONE_UNIFORM_NAME, boneIndex);
207   boneData.propertyName  = propertyNameBuffer;
208   boneData.inverseMatrix = inverseMatrix;
209   mBoneDataContainer.push_back(std::move(boneData));
210
211   UpdateBoneMatrix(primitive);
212 }
213
214 void ModelNode::Impl::UpdateBoneMatrix(Scene3D::ModelPrimitive primitive)
215 {
216   for(auto&& boneData : mBoneDataContainer)
217   {
218     if(boneData.primitive != primitive)
219     {
220       continue;
221     }
222
223     Dali::Renderer renderer = GetImplementation(primitive).GetRenderer();
224     if(!renderer)
225     {
226       continue;
227     }
228
229     Dali::Shader shader = renderer.GetShader();
230     if(!shader)
231     {
232       continue;
233     }
234
235     if(boneData.constraint)
236     {
237       boneData.constraint.Remove();
238       boneData.constraint.Reset();
239     }
240
241     if(shader.GetPropertyIndex(boneData.propertyName) == Property::INVALID_INDEX)
242     {
243       auto propBoneXform = shader.RegisterProperty(boneData.propertyName, Matrix{false});
244
245       Matrix inverseMatrix = boneData.inverseMatrix;
246       // Constrain bone matrix to joint transform.
247       boneData.constraint = Constraint::New<Matrix>(shader, propBoneXform, [inverseMatrix](Matrix& output, const PropertyInputContainer& inputs)
248                                                     { Matrix::Multiply(output, inverseMatrix, inputs[0]->GetMatrix()); });
249
250       Actor joint = mModelNodeImpl.Self();
251       boneData.constraint.AddSource(Source{joint, Actor::Property::WORLD_MATRIX});
252       boneData.constraint.ApplyPost();
253     }
254     break;
255   }
256 }
257
258 } // namespace Internal
259
260 } // namespace Scene3D
261
262 } // namespace Dali