2 * Copyright (c) 2023 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/controls/model/model-impl.h>
22 #include <dali-toolkit/dali-toolkit.h>
23 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
24 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
25 #include <dali/devel-api/actors/actor-devel.h>
26 #include <dali/integration-api/adaptor-framework/adaptor.h>
27 #include <dali/integration-api/debug.h>
28 #include <dali/public-api/math/math-utils.h>
29 #include <dali/public-api/object/type-registry-helper.h>
30 #include <dali/public-api/object/type-registry.h>
34 #include <dali-scene3d/internal/common/model-cache-manager.h>
35 #include <dali-scene3d/internal/controls/scene-view/scene-view-impl.h>
36 #include <dali-scene3d/public-api/controls/model/model.h>
37 #include <dali-scene3d/public-api/loader/animation-definition.h>
38 #include <dali-scene3d/public-api/loader/camera-parameters.h>
39 #include <dali-scene3d/public-api/loader/dli-loader.h>
40 #include <dali-scene3d/public-api/loader/gltf2-loader.h>
41 #include <dali-scene3d/public-api/loader/light-parameters.h>
42 #include <dali-scene3d/public-api/loader/load-result.h>
43 #include <dali-scene3d/public-api/loader/node-definition.h>
44 #include <dali-scene3d/public-api/loader/scene-definition.h>
45 #include <dali-scene3d/public-api/loader/shader-definition-factory.h>
59 return Scene3D::Model::New(std::string());
62 // Setup properties, signals and actions using the type-registry.
63 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::Model, Toolkit::Control, Create);
64 DALI_TYPE_REGISTRATION_END()
66 static constexpr uint32_t OFFSET_FOR_DIFFUSE_CUBE_TEXTURE = 2u;
67 static constexpr uint32_t OFFSET_FOR_SPECULAR_CUBE_TEXTURE = 1u;
69 static constexpr Vector3 Y_DIRECTION(1.0f, -1.0f, 1.0f);
71 static constexpr bool DEFAULT_MODEL_CHILDREN_SENSITIVE = false;
72 static constexpr bool DEFAULT_MODEL_CHILDREN_FOCUSABLE = false;
78 pointMin = Vector3(std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
79 pointMax = Vector3(std::numeric_limits<float>::min(), std::numeric_limits<float>::min(), std::numeric_limits<float>::min());
82 void ConsiderNewPointInVolume(const Vector3& position)
84 pointMin.x = std::min(position.x, pointMin.x);
85 pointMin.y = std::min(position.y, pointMin.y);
86 pointMin.z = std::min(position.z, pointMin.z);
88 pointMax.x = std::max(position.x, pointMax.x);
89 pointMax.y = std::max(position.y, pointMax.y);
90 pointMax.z = std::max(position.z, pointMax.z);
93 Vector3 CalculateSize()
95 return pointMax - pointMin;
98 Vector3 CalculatePivot()
100 Vector3 pivot = pointMin / (pointMin - pointMax);
101 for(uint32_t i = 0; i < 3; ++i)
103 // To avoid divid by zero
104 if(Dali::Equals(pointMin[i], pointMax[i]))
116 void ConfigureBlendShapeShaders(
117 Dali::Scene3D::Loader::ResourceBundle& resources, const Dali::Scene3D::Loader::SceneDefinition& scene, Actor root, std::vector<Dali::Scene3D::Loader::BlendshapeShaderConfigurationRequest>&& requests)
119 std::vector<std::string> errors;
120 auto onError = [&errors](const std::string& msg) { errors.push_back(msg); };
121 if(!scene.ConfigureBlendshapeShaders(resources, root, std::move(requests), onError))
123 Dali::Scene3D::Loader::ExceptionFlinger flinger(ASSERT_LOCATION);
124 for(auto& msg : errors)
126 flinger << msg << '\n';
131 void AddModelTreeToAABB(BoundingVolume& AABB, const Dali::Scene3D::Loader::SceneDefinition& scene, const Dali::Scene3D::Loader::Customization::Choices& choices, Dali::Scene3D::Loader::Index iNode, Dali::Scene3D::Loader::NodeDefinition::CreateParams& nodeParams, Matrix parentMatrix)
133 static constexpr uint32_t BOX_POINT_COUNT = 8;
134 static uint32_t BBIndex[BOX_POINT_COUNT][3] = {{0, 0, 0}, {0, 1, 0}, {1, 0, 0}, {1, 1, 0}, {0, 0, 1}, {0, 1, 1}, {1, 0, 1}, {1, 1, 1}};
137 const Dali::Scene3D::Loader::NodeDefinition* node = scene.GetNode(iNode);
138 Matrix localMatrix = node->GetLocalSpace();
139 Matrix::Multiply(nodeMatrix, localMatrix, parentMatrix);
142 if(node->GetExtents(nodeParams.mResources, volume[0], volume[1]))
144 for(uint32_t i = 0; i < BOX_POINT_COUNT; ++i)
146 Vector4 position = Vector4(volume[BBIndex[i][0]].x, volume[BBIndex[i][1]].y, volume[BBIndex[i][2]].z, 1.0f);
147 Vector4 objectPosition = nodeMatrix * position;
148 objectPosition /= objectPosition.w;
150 AABB.ConsiderNewPointInVolume(Vector3(objectPosition));
154 if(node->mCustomization)
156 if(!node->mChildren.empty())
158 auto choice = choices.Get(node->mCustomization->mTag);
159 Dali::Scene3D::Loader::Index i = std::min(choice != Dali::Scene3D::Loader::Customization::NONE ? choice : 0, static_cast<Dali::Scene3D::Loader::Index>(node->mChildren.size() - 1));
161 AddModelTreeToAABB(AABB, scene, choices, node->mChildren[i], nodeParams, nodeMatrix);
166 for(auto i : node->mChildren)
168 AddModelTreeToAABB(AABB, scene, choices, i, nodeParams, nodeMatrix);
173 } // anonymous namespace
175 Model::Model(const std::string& modelUrl, const std::string& resourceDirectoryUrl)
176 : Control(ControlBehaviour(DISABLE_SIZE_NEGOTIATION | DISABLE_STYLE_CHANGE_SIGNALS)),
178 mResourceDirectoryUrl(resourceDirectoryUrl),
180 mNaturalSize(Vector3::ZERO),
181 mModelPivot(AnchorPoint::CENTER),
182 mSceneIblScaleFactor(1.0f),
183 mIblScaleFactor(1.0f),
184 mModelChildrenSensitive(DEFAULT_MODEL_CHILDREN_SENSITIVE),
185 mModelChildrenFocusable(DEFAULT_MODEL_CHILDREN_FOCUSABLE),
186 mModelResourceReady(false),
187 mIblDiffuseResourceReady(true),
188 mIblSpecularResourceReady(true),
189 mIblDiffuseDirty(false),
190 mIblSpecularDirty(false)
196 if(ModelCacheManager::Get())
198 ModelCacheManager::Get().UnreferenceModelCache(mModelUrl);
201 ResetResourceTasks();
204 Dali::Scene3D::Model Model::New(const std::string& modelUrl, const std::string& resourceDirectoryUrl)
206 Model* impl = new Model(modelUrl, resourceDirectoryUrl);
208 Dali::Scene3D::Model handle = Dali::Scene3D::Model(*impl);
210 // Second-phase init of the implementation
211 // This can only be done after the CustomActor connection has been made...
217 const Actor Model::GetModelRoot() const
222 void Model::SetChildrenSensitive(bool enable)
224 if(mModelChildrenSensitive != enable)
226 mModelChildrenSensitive = enable;
229 mModelRoot.SetProperty(Dali::Actor::Property::SENSITIVE, mModelChildrenSensitive);
234 bool Model::GetChildrenSensitive() const
236 return mModelChildrenSensitive;
239 void Model::SetChildrenFocusable(bool enable)
241 if(mModelChildrenFocusable != enable)
243 mModelChildrenFocusable = enable;
246 mModelRoot.SetProperty(Dali::Actor::Property::KEYBOARD_FOCUSABLE, mModelChildrenFocusable);
247 mModelRoot.SetProperty(Dali::DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN, mModelChildrenFocusable);
252 bool Model::GetChildrenFocusable() const
254 return mModelChildrenFocusable;
257 void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor)
259 bool needIblReset = false;
260 bool isOnScene = Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE);
261 if(mDiffuseIblUrl != diffuseUrl)
263 mDiffuseIblUrl = diffuseUrl;
264 if(mDiffuseIblUrl.empty())
270 mIblDiffuseDirty = true;
271 mIblDiffuseResourceReady = false;
275 if(mSpecularIblUrl != specularUrl)
277 mSpecularIblUrl = specularUrl;
278 if(mSpecularIblUrl.empty())
284 mIblSpecularDirty = true;
285 mIblSpecularResourceReady = false;
289 // If one or both of diffuse url and specular url are empty,
290 // we don't need to request to load texture.
293 ResetResourceTask(mIblDiffuseLoadTask);
294 ResetResourceTask(mIblSpecularLoadTask);
296 mIblDiffuseDirty = false;
297 mIblSpecularDirty = false;
298 mIblDiffuseResourceReady = true;
299 mIblSpecularResourceReady = true;
301 mDiffuseTexture.Reset();
302 mSpecularTexture.Reset();
303 UpdateImageBasedLightTexture();
307 if(isOnScene && mIblDiffuseDirty)
309 ResetResourceTask(mIblDiffuseLoadTask);
310 mIblDiffuseLoadTask = new EnvironmentMapLoadTask(mDiffuseIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &Model::OnIblDiffuseLoadComplete));
311 Dali::AsyncTaskManager::Get().AddTask(mIblDiffuseLoadTask);
312 mIblDiffuseDirty = false;
315 if(isOnScene && mIblSpecularDirty)
317 ResetResourceTask(mIblSpecularLoadTask);
318 mIblSpecularLoadTask = new EnvironmentMapLoadTask(mSpecularIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &Model::OnIblSpecularLoadComplete));
319 Dali::AsyncTaskManager::Get().AddTask(mIblSpecularLoadTask);
320 mIblSpecularDirty = false;
324 if(!Dali::Equals(mIblScaleFactor, scaleFactor))
326 mIblScaleFactor = scaleFactor;
327 UpdateImageBasedLightScaleFactor();
330 // If diffuse and specular textures are already loaded, emits resource ready signal here.
331 NotifyResourceReady();
334 void Model::SetImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float scaleFactor)
336 // If input texture is wrong, Model is rendered with SceneView's IBL.
337 if(mDiffuseTexture != diffuseTexture || mSpecularTexture != specularTexture)
339 mDiffuseTexture = diffuseTexture;
340 mSpecularTexture = specularTexture;
341 mIblScaleFactor = scaleFactor;
342 UpdateImageBasedLightTexture();
346 void Model::SetImageBasedLightScaleFactor(float scaleFactor)
348 mIblScaleFactor = scaleFactor;
349 if(mDiffuseTexture && mSpecularTexture)
351 UpdateImageBasedLightScaleFactor();
355 float Model::GetImageBasedLightScaleFactor() const
357 return mIblScaleFactor;
360 uint32_t Model::GetAnimationCount() const
362 return mAnimations.size();
365 Dali::Animation Model::GetAnimation(uint32_t index) const
367 Dali::Animation animation;
368 if(mAnimations.size() > index)
370 animation = mAnimations[index].second;
375 Dali::Animation Model::GetAnimation(const std::string& name) const
377 Dali::Animation animation;
380 for(auto&& animationData : mAnimations)
382 if(animationData.first == name)
384 animation = animationData.second;
392 uint32_t Model::GetCameraCount() const
394 return mCameraParameters.size();
397 Dali::CameraActor Model::GenerateCamera(uint32_t index) const
399 Dali::CameraActor camera;
400 if(mCameraParameters.size() > index)
402 camera = Dali::CameraActor::New3DCamera();
403 if(!mCameraParameters[index].ConfigureCamera(camera, false))
405 DALI_LOG_ERROR("Fail to generate %u's camera actor : Some property was not defined. Please check model file.\n", index);
410 ApplyCameraTransform(camera);
415 bool Model::ApplyCamera(uint32_t index, Dali::CameraActor camera) const
417 if(camera && mCameraParameters.size() > index)
419 if(!mCameraParameters[index].ConfigureCamera(camera, false))
421 DALI_LOG_ERROR("Fail to apply %u's camera actor : Some property was not defined. Please check model file.\n", index);
425 ApplyCameraTransform(camera);
431 ///////////////////////////////////////////////////////////
436 void Model::OnInitialize()
438 // Make ParentOrigin as Center.
439 Self().SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
442 void Model::OnSceneConnection(int depth)
444 if(!mModelLoadTask && !mModelRoot)
446 if(ModelCacheManager::Get())
448 ModelCacheManager::Get().ReferenceModelCache(mModelUrl);
451 Scene3D::Loader::InitializeGltfLoader();
452 mModelLoadTask = new ModelLoadTask(mModelUrl, mResourceDirectoryUrl, MakeCallback(this, &Model::OnModelLoadComplete));
453 Dali::AsyncTaskManager::Get().AddTask(mModelLoadTask);
455 // If diffuse and specular url is not valid, IBL does not need to be loaded.
456 if(!mDiffuseIblUrl.empty() && !mSpecularIblUrl.empty())
458 SetImageBasedLightSource(mDiffuseIblUrl, mSpecularIblUrl, mIblScaleFactor);
461 Actor parent = Self().GetParent();
464 Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(parent);
467 GetImpl(sceneView).RegisterSceneItem(this);
468 mParentSceneView = sceneView;
471 parent = parent.GetParent();
474 Control::OnSceneConnection(depth);
477 void Model::OnSceneDisconnection()
479 Scene3D::SceneView sceneView = mParentSceneView.GetHandle();
482 GetImpl(sceneView).UnregisterSceneItem(this);
483 mParentSceneView.Reset();
485 Control::OnSceneDisconnection();
488 Vector3 Model::GetNaturalSize()
492 DALI_LOG_ERROR("Model is still not loaded.\n");
493 return Vector3::ZERO;
499 float Model::GetHeightForWidth(float width)
502 padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
503 return Control::GetHeightForWidth(width) + padding.top + padding.bottom;
506 float Model::GetWidthForHeight(float height)
509 padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
510 return Control::GetWidthForHeight(height) + padding.start + padding.end;
513 void Model::OnRelayout(const Vector2& size, RelayoutContainer& container)
515 Control::OnRelayout(size, container);
519 bool Model::IsResourceReady() const
521 return mModelResourceReady && mIblDiffuseResourceReady && mIblSpecularResourceReady;
524 void Model::ScaleModel()
532 Vector3 size = Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
533 if(size.x > 0.0f && size.y > 0.0f)
536 scale = std::min(size.x / mNaturalSize.x, scale);
537 scale = std::min(size.y / mNaturalSize.y, scale);
539 // Models in glTF and dli are defined as right hand coordinate system.
540 // DALi uses left hand coordinate system. Scaling negative is for change winding order.
541 mModelRoot.SetProperty(Dali::Actor::Property::SCALE, Y_DIRECTION * scale);
544 void Model::FitModelPosition()
550 // Loaded model pivot is not the model center.
551 mModelRoot.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
552 mModelRoot.SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3::ONE - mModelPivot);
555 void Model::CollectRenderableActor(Actor actor)
557 uint32_t rendererCount = actor.GetRendererCount();
560 mRenderableActors.push_back(actor);
563 uint32_t childrenCount = actor.GetChildCount();
564 for(uint32_t i = 0; i < childrenCount; ++i)
566 CollectRenderableActor(actor.GetChildAt(i));
570 void Model::UpdateImageBasedLightTexture()
572 Dali::Texture currentDiffuseTexture = (mDiffuseTexture && mSpecularTexture) ? mDiffuseTexture : mSceneDiffuseTexture;
573 Dali::Texture currentSpecularTexture = (mDiffuseTexture && mSpecularTexture) ? mSpecularTexture : mSceneSpecularTexture;
574 float currentIblScaleFactor = (mDiffuseTexture && mSpecularTexture) ? mIblScaleFactor : mSceneIblScaleFactor;
576 if(!currentDiffuseTexture || !currentSpecularTexture)
578 currentDiffuseTexture = mDefaultDiffuseTexture;
579 currentSpecularTexture = mDefaultSpecularTexture;
580 currentIblScaleFactor = Dali::Scene3D::Loader::EnvironmentDefinition::GetDefaultIntensity();
583 for(auto&& actor : mRenderableActors)
585 Actor renderableActor = actor.GetHandle();
591 uint32_t rendererCount = renderableActor.GetRendererCount();
592 for(uint32_t i = 0; i < rendererCount; ++i)
594 Dali::Renderer renderer = renderableActor.GetRendererAt(i);
599 Dali::TextureSet textures = renderer.GetTextures();
604 uint32_t textureCount = textures.GetTextureCount();
605 // EnvMap requires at least 2 texture, diffuse and specular
606 if(textureCount > 2u &&
607 (textures.GetTexture(textureCount - OFFSET_FOR_DIFFUSE_CUBE_TEXTURE) != currentDiffuseTexture ||
608 textures.GetTexture(textureCount - OFFSET_FOR_SPECULAR_CUBE_TEXTURE) != currentSpecularTexture))
610 Dali::TextureSet newTextures = Dali::TextureSet::New();
612 for(uint32_t index = 0u; index < textureCount; ++index)
614 Dali::Texture texture = textures.GetTexture(index);
615 if(index == textureCount - OFFSET_FOR_DIFFUSE_CUBE_TEXTURE)
617 texture = currentDiffuseTexture;
619 else if(index == textureCount - OFFSET_FOR_SPECULAR_CUBE_TEXTURE)
621 texture = currentSpecularTexture;
624 newTextures.SetTexture(index, texture);
625 newTextures.SetSampler(index, textures.GetSampler(index));
628 renderer.SetTextures(newTextures);
631 renderableActor.RegisterProperty(Dali::Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName().data(), currentIblScaleFactor);
635 void Model::UpdateImageBasedLightScaleFactor()
637 if((!mDiffuseTexture || !mSpecularTexture) &&
638 (!mSceneDiffuseTexture || !mSceneSpecularTexture))
643 float currentIblScaleFactor = (mDiffuseTexture && mSpecularTexture) ? mIblScaleFactor : mSceneIblScaleFactor;
644 for(auto&& actor : mRenderableActors)
646 Actor renderableActor = actor.GetHandle();
649 renderableActor.RegisterProperty(Dali::Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName().data(), currentIblScaleFactor);
654 void Model::ApplyCameraTransform(Dali::CameraActor camera) const
656 Vector3 selfPosition = Self().GetProperty<Vector3>(Actor::Property::POSITION);
657 Quaternion selfOrientation = Self().GetProperty<Quaternion>(Actor::Property::ORIENTATION);
658 Vector3 selfScale = Self().GetProperty<Vector3>(Actor::Property::SCALE);
660 Vector3 cameraPosition = camera.GetProperty<Vector3>(Actor::Property::POSITION);
661 Quaternion cameraOrientation = camera.GetProperty<Quaternion>(Actor::Property::ORIENTATION);
662 Vector3 cameraScale = camera.GetProperty<Vector3>(Actor::Property::SCALE);
664 // Models in glTF and dli are defined as right hand coordinate system.
665 // DALi uses left hand coordinate system. Scaling negative is for change winding order.
666 if(!Dali::Equals(Y_DIRECTION.Dot(Vector3::YAXIS), 1.0f))
668 // Reflect by XZ plane
669 cameraPosition.y = -cameraPosition.y;
670 Quaternion yDirectionQuaternion;
671 yDirectionQuaternion.mVector = Vector3::YAXIS;
672 // Reflect orientation
673 cameraOrientation = yDirectionQuaternion * cameraOrientation * yDirectionQuaternion;
676 Vector3 resultPosition;
677 Quaternion resultOrientation;
680 Matrix selfMatrix(false);
681 Matrix cameraMatrix(false);
682 Matrix resultMatrix(false);
683 selfMatrix.SetTransformComponents(selfScale, selfOrientation, selfPosition);
684 cameraMatrix.SetTransformComponents(cameraScale, cameraOrientation, cameraPosition);
685 Matrix::Multiply(resultMatrix, cameraMatrix, selfMatrix);
686 resultMatrix.GetTransformComponents(resultPosition, resultOrientation, resultScale);
688 camera.SetProperty(Actor::Property::POSITION, resultPosition);
689 camera.SetProperty(Actor::Property::ORIENTATION, resultOrientation);
690 camera.SetProperty(Actor::Property::SCALE, resultScale);
693 void Model::NotifyImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float scaleFactor)
695 if(mSceneDiffuseTexture != diffuseTexture || mSceneSpecularTexture != specularTexture)
697 mSceneDiffuseTexture = diffuseTexture;
698 mSceneSpecularTexture = specularTexture;
699 mSceneIblScaleFactor = scaleFactor;
700 // If Model IBL is not set, use SceneView's IBL.
701 if(!mDiffuseTexture || !mSpecularTexture)
703 UpdateImageBasedLightTexture();
708 void Model::NotifyImageBasedLightScaleFactor(float scaleFactor)
710 mSceneIblScaleFactor = scaleFactor;
711 if(mSceneDiffuseTexture && mSceneSpecularTexture)
713 UpdateImageBasedLightScaleFactor();
717 void Model::OnModelLoadComplete()
719 if(!mModelLoadTask->HasSucceeded())
721 ResetResourceTasks();
723 if(ModelCacheManager::Get())
725 ModelCacheManager::Get().UnreferenceModelCache(mModelUrl);
732 mRenderableActors.clear();
733 CollectRenderableActor(mModelRoot);
735 CreateAnimations(mModelLoadTask->mLoadResult.mScene);
736 ResetCameraParameters();
738 if(!mModelLoadTask->mLoadResult.mResources.mEnvironmentMaps.empty())
740 mDefaultDiffuseTexture = mModelLoadTask->mLoadResult.mResources.mEnvironmentMaps.front().second.mDiffuse;
741 mDefaultSpecularTexture = mModelLoadTask->mLoadResult.mResources.mEnvironmentMaps.front().second.mSpecular;
744 UpdateImageBasedLightTexture();
745 UpdateImageBasedLightScaleFactor();
747 mModelRoot.SetProperty(Dali::Actor::Property::SENSITIVE, mModelChildrenSensitive);
748 mModelRoot.SetProperty(Dali::Actor::Property::KEYBOARD_FOCUSABLE, mModelChildrenFocusable);
749 mModelRoot.SetProperty(Dali::DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN, mModelChildrenFocusable);
751 Self().Add(mModelRoot);
752 Self().SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3(mModelPivot.x, 1.0f - mModelPivot.y, mModelPivot.z));
754 mModelResourceReady = true;
755 NotifyResourceReady();
756 ResetResourceTask(mModelLoadTask);
759 void Model::OnIblDiffuseLoadComplete()
761 mDiffuseTexture = mIblDiffuseLoadTask->GetLoadedTexture();
762 ResetResourceTask(mIblDiffuseLoadTask);
763 mIblDiffuseResourceReady = true;
764 if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
770 void Model::OnIblSpecularLoadComplete()
772 mSpecularTexture = mIblSpecularLoadTask->GetLoadedTexture();
773 ResetResourceTask(mIblSpecularLoadTask);
774 mIblSpecularResourceReady = true;
775 if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
781 void Model::OnIblLoadComplete()
783 UpdateImageBasedLightTexture();
784 NotifyResourceReady();
787 void Model::ResetResourceTasks()
789 if(!Dali::Adaptor::IsAvailable())
793 ResetResourceTask(mModelLoadTask);
794 ResetResourceTask(mIblDiffuseLoadTask);
795 ResetResourceTask(mIblSpecularLoadTask);
798 void Model::ResetResourceTask(IntrusivePtr<AsyncTask> asyncTask)
804 Dali::AsyncTaskManager::Get().RemoveTask(asyncTask);
808 void Model::NotifyResourceReady()
810 if(!IsResourceReady())
814 Control::SetResourceReady(false);
817 void Model::CreateModel()
819 mModelRoot = Actor::New();
820 mModelRoot.SetProperty(Actor::Property::COLOR_MODE, ColorMode::USE_OWN_MULTIPLY_PARENT_COLOR);
823 Dali::Scene3D::Loader::Transforms xforms{Dali::Scene3D::Loader::MatrixStack{}, Dali::Scene3D::Loader::ViewProjection{}};
824 Dali::Scene3D::Loader::NodeDefinition::CreateParams nodeParams{mModelLoadTask->mLoadResult.mResources, xforms, {}, {}, {}};
826 // Generate Dali handles from resource bundle. Note that we generate all scene's resouce immediatly.
827 mModelLoadTask->mLoadResult.mResources.GenerateResources(mModelLoadTask->mResourceRefCount);
829 for(auto iRoot : mModelLoadTask->mLoadResult.mScene.GetRoots())
831 if(auto actor = mModelLoadTask->mLoadResult.mScene.CreateNodes(iRoot, mModelLoadTask->mResourceChoices, nodeParams))
833 mModelLoadTask->mLoadResult.mScene.ConfigureSkeletonJoints(iRoot, mModelLoadTask->mLoadResult.mResources.mSkeletons, actor);
834 mModelLoadTask->mLoadResult.mScene.ConfigureSkinningShaders(mModelLoadTask->mLoadResult.mResources, actor, std::move(nodeParams.mSkinnables));
835 ConfigureBlendShapeShaders(mModelLoadTask->mLoadResult.mResources, mModelLoadTask->mLoadResult.mScene, actor, std::move(nodeParams.mBlendshapeRequests));
837 mModelLoadTask->mLoadResult.mScene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
839 mModelRoot.Add(actor);
842 AddModelTreeToAABB(AABB, mModelLoadTask->mLoadResult.mScene, mModelLoadTask->mResourceChoices, iRoot, nodeParams, Matrix::IDENTITY);
845 mNaturalSize = AABB.CalculateSize();
846 mModelPivot = AABB.CalculatePivot();
847 mModelRoot.SetProperty(Dali::Actor::Property::SIZE, mNaturalSize);
848 Vector3 controlSize = Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
849 if(Dali::EqualsZero(controlSize.x) || Dali::EqualsZero(controlSize.y))
851 Self().SetProperty(Dali::Actor::Property::SIZE, mNaturalSize);
857 void Model::CreateAnimations(Dali::Scene3D::Loader::SceneDefinition& scene)
860 if(!mModelLoadTask->mLoadResult.mAnimationDefinitions.empty())
862 auto getActor = [&](const Scene3D::Loader::AnimatedProperty& property) {
863 if(property.mNodeIndex == Scene3D::Loader::INVALID_INDEX)
865 return mModelRoot.FindChildByName(property.mNodeName);
867 auto* node = scene.GetNode(property.mNodeIndex);
870 return Dali::Actor();
872 return mModelRoot.FindChildById(node->mNodeId);
875 for(auto&& animation : mModelLoadTask->mLoadResult.mAnimationDefinitions)
877 Dali::Animation anim = animation.ReAnimate(getActor);
878 mAnimations.push_back({animation.mName, anim});
883 void Model::ResetCameraParameters()
885 mCameraParameters.clear();
886 if(!mModelLoadTask->mLoadResult.mCameraParameters.empty())
888 // Copy camera parameters.
889 std::copy(mModelLoadTask->mLoadResult.mCameraParameters.begin(), mModelLoadTask->mLoadResult.mCameraParameters.end(), std::back_inserter(mCameraParameters));
893 } // namespace Internal
894 } // namespace Scene3D