2 * Copyright (c) 2024 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali-scene3d/internal/model-components/model-node-impl.h>
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>
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>
41 * Creates control through type registry
45 return Scene3D::ModelNode::New();
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
53 Dali::Scene3D::ModelNode ModelNode::New()
55 // Create the implementation, temporarily owned on stack
56 IntrusivePtr<ModelNode> nodeImpl = new ModelNode();
58 // Pass ownership to handle
59 Scene3D::ModelNode handle(*nodeImpl);
61 // Second-phase init of the implementation
62 // This can only be done after the CustomActor connection has been made...
63 nodeImpl->Initialize();
68 ModelNode::ModelNode()
69 : Control(static_cast<ControlBehaviour>(ControlBehaviour::DISABLE_STYLE_CHANGE_SIGNALS | ActorFlags::DISABLE_SIZE_NEGOTIATION))
73 ModelNode::~ModelNode()
77 // From Internal::Control.
79 void ModelNode::OnInitialize()
83 // TODO : We need to check this is enough.
84 Toolkit::DevelControl::EnableCreateAccessible(Toolkit::Control::DownCast(self), false);
86 self.RegisterProperty("uIsShadowCasting", static_cast<int>(mIsShadowCasting));
87 self.RegisterProperty("uIsShadowReceiving", static_cast<int>(mIsShadowReceiving));
90 // From CustomActorImpl.
92 void ModelNode::OnSceneConnection(int depth)
96 void ModelNode::OnSceneDisconnection()
100 void ModelNode::OnChildAdd(Actor& child)
104 void ModelNode::OnChildRemove(Actor& child)
108 void ModelNode::OnPropertySet(Property::Index index, const Property::Value& propertyValue)
112 void ModelNode::OnSizeSet(const Vector3& targetSize)
116 void ModelNode::OnSizeAnimation(Animation& animation, const Vector3& targetSize)
118 // @todo size negotiate background to new size, animate as well?
121 void ModelNode::OnRelayout(const Vector2& size, RelayoutContainer& container)
125 void ModelNode::OnSetResizePolicy(ResizePolicy::Type policy, Dimension::Type dimension)
129 Vector3 ModelNode::GetNaturalSize()
131 return Vector3::ZERO;
134 float ModelNode::CalculateChildSize(const Dali::Actor& child, Dimension::Type dimension)
139 float ModelNode::GetHeightForWidth(float width)
144 float ModelNode::GetWidthForHeight(float height)
149 bool ModelNode::RelayoutDependentOnChildren(Dimension::Type dimension)
154 void ModelNode::OnCalculateRelayoutSize(Dimension::Type dimension)
158 void ModelNode::OnLayoutNegotiated(float size, Dimension::Type dimension)
162 ModelNode& GetImplementation(Dali::Scene3D::ModelNode& handle)
164 CustomActorImpl& customInterface = handle.GetImplementation();
165 ModelNode& impl = dynamic_cast<Internal::ModelNode&>(customInterface);
169 const ModelNode& GetImplementation(const Dali::Scene3D::ModelNode& handle)
171 const CustomActorImpl& customInterface = handle.GetImplementation();
172 // downcast to control
173 const ModelNode& impl = dynamic_cast<const Internal::ModelNode&>(customInterface);
179 uint32_t ModelNode::GetModelPrimitiveCount() const
181 return static_cast<uint32_t>(mModelPrimitiveContainer.size());
184 void ModelNode::AddModelPrimitive(Dali::Scene3D::ModelPrimitive modelPrimitive, Loader::ShaderOption::HashType hash)
186 for(auto&& primitive : mModelPrimitiveContainer)
188 if(primitive == modelPrimitive)
194 mModelPrimitiveContainer.push_back(modelPrimitive);
197 GetImplementation(modelPrimitive).AddPrimitiveObserver(this);
198 if(mShadowMapTexture)
200 GetImplementation(modelPrimitive).SetShadowMapTexture(mShadowMapTexture);
203 if(mDiffuseTexture && mSpecularTexture)
205 GetImplementation(modelPrimitive).SetImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor, mSpecularMipmapLevels);
208 GetImplementation(modelPrimitive).UpdateShader(mShaderManager, hash);
210 Dali::Renderer renderer = GetImplementation(modelPrimitive).GetRenderer();
213 uint32_t rendererCount = self.GetRendererCount();
215 for(uint32_t i = 0; i < rendererCount; ++i)
217 if(renderer == self.GetRendererAt(i))
225 self.AddRenderer(renderer);
230 void ModelNode::RemoveModelPrimitive(Dali::Scene3D::ModelPrimitive modelPrimitive)
232 uint32_t primitiveCount = GetModelPrimitiveCount();
233 for(uint32_t i = 0; i < primitiveCount; ++i)
235 if(mModelPrimitiveContainer[i] != modelPrimitive)
240 RemoveModelPrimitive(i);
245 void ModelNode::RemoveModelPrimitive(uint32_t index)
247 if(index >= mModelPrimitiveContainer.size())
252 GetImplementation(mModelPrimitiveContainer[index]).UpdateShader(nullptr, 0u);
255 GetImplementation(mModelPrimitiveContainer[index]).RemovePrimitiveObserver(this);
257 Dali::Renderer renderer = GetImplementation(mModelPrimitiveContainer[index]).GetRenderer();
260 self.RemoveRenderer(renderer);
263 mModelPrimitiveContainer.erase(mModelPrimitiveContainer.begin() + index);
266 Dali::Scene3D::ModelPrimitive ModelNode::GetModelPrimitive(uint32_t index) const
268 if(index < mModelPrimitiveContainer.size())
270 return mModelPrimitiveContainer[index];
272 return Scene3D::ModelPrimitive();
275 Scene3D::ModelNode ModelNode::FindChildModelNodeByName(std::string_view nodeName)
277 Actor childActor = Self().FindChildByName(nodeName);
278 return Scene3D::ModelNode::DownCast(childActor);
281 void ModelNode::RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const
283 blendShapeNames.reserve(blendShapeNames.size() + mBlendShapeIndexMap.size());
284 for(const auto& iter : mBlendShapeIndexMap)
286 blendShapeNames.push_back(iter.first);
290 Loader::BlendShapes::Index ModelNode::GetBlendShapeIndexByName(std::string_view blendShapeName) const
292 auto iter = mBlendShapeIndexMap.find(std::string(blendShapeName));
293 if(iter != mBlendShapeIndexMap.end())
297 return Loader::BlendShapes::INVALID_INDEX;
300 void ModelNode::SetShadowMapTexture(Dali::Texture shadowMapTexture)
302 mShadowMapTexture = shadowMapTexture;
303 for(auto&& primitive : mModelPrimitiveContainer)
305 GetImplementation(primitive).SetShadowMapTexture(mShadowMapTexture);
309 void ModelNode::CastShadow(bool castShadow)
311 if(mIsShadowCasting == castShadow)
316 mIsShadowCasting = castShadow;
319 self.RegisterProperty("uIsShadowCasting", static_cast<int>(mIsShadowCasting));
322 bool ModelNode::IsShadowCasting() const
324 return mIsShadowCasting;
327 void ModelNode::ReceiveShadow(bool receiveShadow)
329 if(mIsShadowReceiving == receiveShadow)
334 mIsShadowReceiving = receiveShadow;
337 self.RegisterProperty("uIsShadowReceiving", static_cast<int>(mIsShadowReceiving));
340 bool ModelNode::IsShadowReceiving() const
342 return mIsShadowReceiving;
345 void ModelNode::SetImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
347 mDiffuseTexture = diffuseTexture;
348 mSpecularTexture = specularTexture;
349 mIblScaleFactor = iblScaleFactor;
350 mSpecularMipmapLevels = specularMipmapLevels;
351 for(auto&& primitive : mModelPrimitiveContainer)
353 GetImplementation(primitive).SetImageBasedLightTexture(diffuseTexture, specularTexture, iblScaleFactor, specularMipmapLevels);
357 void ModelNode::SetImageBasedLightScaleFactor(float iblScaleFactor)
359 mIblScaleFactor = iblScaleFactor;
360 for(auto&& primitive : mModelPrimitiveContainer)
362 GetImplementation(primitive).SetImageBasedLightScaleFactor(iblScaleFactor);
366 void ModelNode::UpdateShader(Scene3D::Loader::ShaderManagerPtr shaderManager)
368 if(mShaderManager != shaderManager)
370 mShaderManager = shaderManager;
371 for(auto&& primitive : mModelPrimitiveContainer)
373 GetImplementation(primitive).UpdateShader(mShaderManager, 0u);
378 void ModelNode::SetBlendShapeData(Scene3D::Loader::BlendShapes::BlendShapeData& data, Scene3D::ModelPrimitive primitive)
380 // Update mBlendShapeIndexMap
381 mBlendShapeIndexMap.clear();
382 const auto blendShapeCount = data.names.size();
383 for(Loader::BlendShapes::Index index = 0u; index < blendShapeCount; ++index)
385 auto& name = data.names[index];
388 mBlendShapeIndexMap[name] = index;
392 GetImplementation(primitive).SetBlendShapeData(data);
395 void ModelNode::SetBoneMatrix(const Matrix& inverseMatrix, Scene3D::ModelPrimitive primitive, Scene3D::Loader::Index& boneIndex)
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));
406 UpdateBoneMatrix(primitive);
409 void ModelNode::OnRendererCreated(Renderer renderer)
411 Self().AddRenderer(renderer);
414 void ModelNode::UpdateBoneMatrix(Scene3D::ModelPrimitive primitive)
416 for(auto&& boneData : mBoneDataContainer)
418 if(boneData.primitive != primitive)
423 Dali::Renderer renderer = GetImplementation(primitive).GetRenderer();
429 if(boneData.constraint)
431 boneData.constraint.Remove();
432 boneData.constraint.Reset();
435 auto propBoneXform = renderer.GetPropertyIndex(boneData.propertyName);
436 if(propBoneXform == Property::INVALID_INDEX)
438 propBoneXform = renderer.RegisterProperty(boneData.propertyName, Matrix{false});
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()); });
445 Actor joint = Self();
446 boneData.constraint.AddSource(Source{joint, Actor::Property::WORLD_MATRIX});
447 boneData.constraint.ApplyPost();
452 void ModelNode::SetColliderMesh(ColliderMeshUniquePtr&& colliderMesh)
454 if(!colliderMesh && !mColliderMesh)
459 if(!mParentModel) // find parent model if not set
461 auto parent = Self().GetParent();
464 auto modelHandle = Scene3D::Model::DownCast(parent);
467 mParentModel = &GetImpl(modelHandle);
470 parent = parent.GetParent();
474 // Resetting collider mesh if argument is nullptr
475 auto handle = Scene3D::ModelNode::DownCast(Self());
480 mParentModel->RemoveColliderMesh(handle);
483 // If collider mesh is to be set then register it with the parent model.
484 // If nullptr, ignore.
487 mParentModel->RegisterColliderMesh(handle);
491 mColliderMesh = std::move(colliderMesh);
494 bool ModelNode::HasColliderMesh() const
496 return mColliderMesh != nullptr;
499 const Scene3D::Algorithm::ColliderMesh& ModelNode::GetColliderMesh() const
501 return *mColliderMesh;
504 } // namespace Internal
506 } // namespace Scene3D