Parse gltf mesh extra and extensions + Get BlendShape index by name
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / internal / controls / model / model-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/controls/model/model-impl.h>
20
21 // EXTERNAL INCLUDES
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>
31 #include <filesystem>
32
33 // INTERNAL INCLUDES
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/internal/light/light-impl.h>
37 #include <dali-scene3d/internal/model-components/model-node-impl.h>
38 #include <dali-scene3d/public-api/controls/model/model.h>
39 #include <dali-scene3d/public-api/loader/animation-definition.h>
40 #include <dali-scene3d/public-api/loader/camera-parameters.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>
46
47 using namespace Dali;
48
49 namespace Dali
50 {
51 namespace Scene3D
52 {
53 namespace Internal
54 {
55 namespace
56 {
57 /**
58  * Creates control through type registry
59  */
60 BaseHandle Create()
61 {
62   return Scene3D::Model::New(std::string());
63 }
64
65 // Setup properties, signals and actions using the type-registry.
66 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::Model, Toolkit::Control, Create);
67 DALI_TYPE_REGISTRATION_END()
68
69 static constexpr Vector3 Y_DIRECTION(1.0f, -1.0f, 1.0f);
70 static constexpr float   SIZE_STEP_CONDITION = 0.1f;
71
72 static constexpr bool DEFAULT_MODEL_CHILDREN_SENSITIVE = false;
73 static constexpr bool DEFAULT_MODEL_CHILDREN_FOCUSABLE = false;
74
75 struct BoundingVolume
76 {
77   void Init()
78   {
79     pointMin = Vector3(std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
80     pointMax = Vector3(std::numeric_limits<float>::min(), std::numeric_limits<float>::min(), std::numeric_limits<float>::min());
81   }
82
83   void ConsiderNewPointInVolume(const Vector3& position)
84   {
85     pointMin.x = std::min(position.x, pointMin.x);
86     pointMin.y = std::min(position.y, pointMin.y);
87     pointMin.z = std::min(position.z, pointMin.z);
88
89     pointMax.x = std::max(position.x, pointMax.x);
90     pointMax.y = std::max(position.y, pointMax.y);
91     pointMax.z = std::max(position.z, pointMax.z);
92   }
93
94   Vector3 CalculateSize()
95   {
96     return pointMax - pointMin;
97   }
98
99   Vector3 CalculatePivot()
100   {
101     Vector3 pivot = pointMin / (pointMin - pointMax);
102     for(uint32_t i = 0; i < 3; ++i)
103     {
104       // To avoid divid by zero
105       if(Dali::Equals(pointMin[i], pointMax[i]))
106       {
107         pivot[i] = 0.5f;
108       }
109     }
110     return pivot;
111   }
112
113   Vector3 pointMin;
114   Vector3 pointMax;
115 };
116
117 void ConfigureBlendShapeShaders(
118   Dali::Scene3D::Loader::ResourceBundle& resources, const Dali::Scene3D::Loader::SceneDefinition& scene, Actor root, std::vector<Dali::Scene3D::Loader::BlendshapeShaderConfigurationRequest>&& requests)
119 {
120   std::vector<std::string> errors;
121   auto                     onError = [&errors](const std::string& msg) { errors.push_back(msg); };
122   if(!scene.ConfigureBlendshapeShaders(resources, root, std::move(requests), onError))
123   {
124     Dali::Scene3D::Loader::ExceptionFlinger flinger(ASSERT_LOCATION);
125     for(auto& msg : errors)
126     {
127       flinger << msg << '\n';
128     }
129   }
130 }
131
132 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 {
134   static constexpr uint32_t BOX_POINT_COUNT             = 8;
135   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}};
136
137   Matrix                                       nodeMatrix;
138   const Dali::Scene3D::Loader::NodeDefinition* node        = scene.GetNode(iNode);
139   Matrix                                       localMatrix = node->GetLocalSpace();
140   Matrix::Multiply(nodeMatrix, localMatrix, parentMatrix);
141
142   Vector3 volume[2];
143   if(node->GetExtents(nodeParams.mResources, volume[0], volume[1]))
144   {
145     for(uint32_t i = 0; i < BOX_POINT_COUNT; ++i)
146     {
147       Vector4 position       = Vector4(volume[BBIndex[i][0]].x, volume[BBIndex[i][1]].y, volume[BBIndex[i][2]].z, 1.0f);
148       Vector4 objectPosition = nodeMatrix * position;
149       objectPosition /= objectPosition.w;
150
151       AABB.ConsiderNewPointInVolume(Vector3(objectPosition));
152     }
153   }
154
155   if(node->mCustomization)
156   {
157     if(!node->mChildren.empty())
158     {
159       auto                         choice = choices.Get(node->mCustomization->mTag);
160       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
162       AddModelTreeToAABB(AABB, scene, choices, node->mChildren[i], nodeParams, nodeMatrix);
163     }
164   }
165   else
166   {
167     for(auto i : node->mChildren)
168     {
169       AddModelTreeToAABB(AABB, scene, choices, i, nodeParams, nodeMatrix);
170     }
171   }
172 }
173
174 void AddLightRecursively(Scene3D::ModelNode node, Scene3D::Light light, uint32_t lightIndex)
175 {
176   if(!node)
177   {
178     return;
179   }
180   GetImplementation(node).AddLight(light, lightIndex);
181
182   uint32_t childrenCount = node.GetChildCount();
183   for(uint32_t i = 0; i < childrenCount; ++i)
184   {
185     Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
186     if(childNode)
187     {
188       AddLightRecursively(childNode, light, lightIndex);
189     }
190   }
191 }
192
193 void RemoveLightRecursively(Scene3D::ModelNode node, uint32_t lightIndex)
194 {
195   if(!node)
196   {
197     return;
198   }
199
200   GetImplementation(node).RemoveLight(lightIndex);
201
202   uint32_t childrenCount = node.GetChildCount();
203   for(uint32_t i = 0; i < childrenCount; ++i)
204   {
205     Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
206     if(childNode)
207     {
208       RemoveLightRecursively(childNode, lightIndex);
209     }
210   }
211 }
212
213 void UpdateBlendShapeNodeMapRecursively(Model::BlendShapeModelNodeMap& resultMap, const Scene3D::ModelNode& node)
214 {
215   if(!node)
216   {
217     return;
218   }
219   const auto childCount = node.GetChildCount();
220   for(auto i = 0u; i < childCount; ++i)
221   {
222     UpdateBlendShapeNodeMapRecursively(resultMap, Scene3D::ModelNode::DownCast(node.GetChildAt(i)));
223   }
224
225   std::vector<std::string> blendShapeNames;
226   node.RetrieveBlendShapeNames(blendShapeNames);
227   for(const auto& iter : blendShapeNames)
228   {
229     // Append or create new list.
230     resultMap[iter].push_back(node);
231   }
232 }
233
234 } // anonymous namespace
235
236 Model::Model(const std::string& modelUrl, const std::string& resourceDirectoryUrl)
237 : Control(ControlBehaviour(DISABLE_SIZE_NEGOTIATION | DISABLE_STYLE_CHANGE_SIGNALS)),
238   mModelUrl(modelUrl),
239   mResourceDirectoryUrl(resourceDirectoryUrl),
240   mModelRoot(),
241   mNaturalSize(Vector3::ZERO),
242   mModelPivot(AnchorPoint::CENTER),
243   mSceneIblScaleFactor(1.0f),
244   mIblScaleFactor(1.0f),
245   mSceneSpecularMipmapLevels(1u),
246   mSpecularMipmapLevels(1u),
247   mModelChildrenSensitive(DEFAULT_MODEL_CHILDREN_SENSITIVE),
248   mModelChildrenFocusable(DEFAULT_MODEL_CHILDREN_FOCUSABLE),
249   mModelResourceReady(false),
250   mIblDiffuseResourceReady(true),
251   mIblSpecularResourceReady(true),
252   mIblDiffuseDirty(false),
253   mIblSpecularDirty(false)
254 {
255 }
256
257 Model::~Model()
258 {
259   ResetResourceTasks();
260
261   if(ModelCacheManager::Get() && !mModelUrl.empty())
262   {
263     ModelCacheManager::Get().UnreferenceModelCache(mModelUrl);
264   }
265 }
266
267 Dali::Scene3D::Model Model::New(const std::string& modelUrl, const std::string& resourceDirectoryUrl)
268 {
269   Model* impl = new Model(modelUrl, resourceDirectoryUrl);
270
271   Dali::Scene3D::Model handle = Dali::Scene3D::Model(*impl);
272
273   // Second-phase init of the implementation
274   // This can only be done after the CustomActor connection has been made...
275   impl->Initialize();
276
277   return handle;
278 }
279
280 const Scene3D::ModelNode Model::GetModelRoot() const
281 {
282   return mModelRoot;
283 }
284
285 void Model::AddModelNode(Scene3D::ModelNode modelNode)
286 {
287   if(!mModelRoot)
288   {
289     CreateModelRoot();
290   }
291
292   mModelRoot.Add(modelNode);
293   if(mModelUrl.empty())
294   {
295     mModelResourceReady = true;
296   }
297
298   if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
299   {
300     UpdateImageBasedLightTexture();
301     UpdateImageBasedLightScaleFactor();
302   }
303
304   uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
305   for(uint32_t i = 0; i < maxLightCount; ++i)
306   {
307     if(mLights[i])
308     {
309       AddLightRecursively(modelNode, mLights[i], i);
310     }
311   }
312
313   if(Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE))
314   {
315     NotifyResourceReady();
316   }
317 }
318
319 void Model::RemoveModelNode(Scene3D::ModelNode modelNode)
320 {
321   if(mModelRoot)
322   {
323     uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
324     for(uint32_t i = 0; i < maxLightCount; ++i)
325     {
326       if(mLights[i])
327       {
328         RemoveLightRecursively(modelNode, i);
329       }
330     }
331     mModelRoot.Remove(modelNode);
332   }
333 }
334
335 void Model::SetChildrenSensitive(bool enable)
336 {
337   if(mModelChildrenSensitive != enable)
338   {
339     mModelChildrenSensitive = enable;
340     if(mModelRoot)
341     {
342       mModelRoot.SetProperty(Dali::Actor::Property::SENSITIVE, mModelChildrenSensitive);
343     }
344   }
345 }
346
347 bool Model::GetChildrenSensitive() const
348 {
349   return mModelChildrenSensitive;
350 }
351
352 void Model::SetChildrenFocusable(bool enable)
353 {
354   if(mModelChildrenFocusable != enable)
355   {
356     mModelChildrenFocusable = enable;
357     if(mModelRoot)
358     {
359       mModelRoot.SetProperty(Dali::Actor::Property::KEYBOARD_FOCUSABLE, mModelChildrenFocusable);
360       mModelRoot.SetProperty(Dali::DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN, mModelChildrenFocusable);
361     }
362   }
363 }
364
365 bool Model::GetChildrenFocusable() const
366 {
367   return mModelChildrenFocusable;
368 }
369
370 void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor)
371 {
372   bool needIblReset = false;
373   bool isOnScene    = Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE);
374   if(mDiffuseIblUrl != diffuseUrl)
375   {
376     mDiffuseIblUrl = diffuseUrl;
377     if(mDiffuseIblUrl.empty())
378     {
379       needIblReset = true;
380     }
381     else
382     {
383       mIblDiffuseDirty         = true;
384       mIblDiffuseResourceReady = false;
385     }
386   }
387
388   if(mSpecularIblUrl != specularUrl)
389   {
390     mSpecularIblUrl = specularUrl;
391     if(mSpecularIblUrl.empty())
392     {
393       needIblReset = true;
394     }
395     else
396     {
397       mIblSpecularDirty         = true;
398       mIblSpecularResourceReady = false;
399     }
400   }
401
402   // If one or both of diffuse url and specular url are empty,
403   // we don't need to request to load texture.
404   if(needIblReset)
405   {
406     ResetResourceTask(mIblDiffuseLoadTask);
407     ResetResourceTask(mIblSpecularLoadTask);
408
409     mIblDiffuseDirty          = false;
410     mIblSpecularDirty         = false;
411     mIblDiffuseResourceReady  = true;
412     mIblSpecularResourceReady = true;
413
414     mDiffuseTexture.Reset();
415     mSpecularTexture.Reset();
416     UpdateImageBasedLightTexture();
417   }
418   else
419   {
420     if(isOnScene && mIblDiffuseDirty)
421     {
422       ResetResourceTask(mIblDiffuseLoadTask);
423       mIblDiffuseLoadTask = new EnvironmentMapLoadTask(mDiffuseIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &Model::OnIblDiffuseLoadComplete));
424       Dali::AsyncTaskManager::Get().AddTask(mIblDiffuseLoadTask);
425       mIblDiffuseDirty = false;
426     }
427
428     if(isOnScene && mIblSpecularDirty)
429     {
430       ResetResourceTask(mIblSpecularLoadTask);
431       mIblSpecularLoadTask = new EnvironmentMapLoadTask(mSpecularIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &Model::OnIblSpecularLoadComplete));
432       Dali::AsyncTaskManager::Get().AddTask(mIblSpecularLoadTask);
433       mIblSpecularDirty = false;
434     }
435   }
436
437   if(!Dali::Equals(mIblScaleFactor, scaleFactor))
438   {
439     mIblScaleFactor = scaleFactor;
440     UpdateImageBasedLightScaleFactor();
441   }
442
443   // If diffuse and specular textures are already loaded, emits resource ready signal here.
444   NotifyResourceReady();
445 }
446
447 void Model::SetImageBasedLightScaleFactor(float scaleFactor)
448 {
449   mIblScaleFactor = scaleFactor;
450   if(mDiffuseTexture && mSpecularTexture)
451   {
452     UpdateImageBasedLightScaleFactor();
453   }
454 }
455
456 float Model::GetImageBasedLightScaleFactor() const
457 {
458   return mIblScaleFactor;
459 }
460
461 uint32_t Model::GetAnimationCount() const
462 {
463   return mAnimations.size();
464 }
465
466 Dali::Animation Model::GetAnimation(uint32_t index) const
467 {
468   Dali::Animation animation;
469   if(mAnimations.size() > index)
470   {
471     animation = mAnimations[index].second;
472   }
473   return animation;
474 }
475
476 Dali::Animation Model::GetAnimation(const std::string& name) const
477 {
478   Dali::Animation animation;
479   if(!name.empty())
480   {
481     for(auto&& animationData : mAnimations)
482     {
483       if(animationData.first == name)
484       {
485         animation = animationData.second;
486         break;
487       }
488     }
489   }
490   return animation;
491 }
492
493 uint32_t Model::GetCameraCount() const
494 {
495   return mCameraParameters.size();
496 }
497
498 Dali::CameraActor Model::GenerateCamera(uint32_t index) const
499 {
500   Dali::CameraActor camera;
501   if(mCameraParameters.size() > index)
502   {
503     camera = Dali::CameraActor::New3DCamera();
504     if(!mCameraParameters[index].ConfigureCamera(camera, false))
505     {
506       DALI_LOG_ERROR("Fail to generate %u's camera actor : Some property was not defined. Please check model file.\n", index);
507       camera.Reset();
508       return camera;
509     }
510
511     ApplyCameraTransform(camera);
512   }
513   return camera;
514 }
515
516 bool Model::ApplyCamera(uint32_t index, Dali::CameraActor camera) const
517 {
518   if(camera && mCameraParameters.size() > index)
519   {
520     if(!mCameraParameters[index].ConfigureCamera(camera, false))
521     {
522       DALI_LOG_ERROR("Fail to apply %u's camera actor : Some property was not defined. Please check model file.\n", index);
523       return false;
524     }
525
526     ApplyCameraTransform(camera);
527     return true;
528   }
529   return false;
530 }
531
532 Scene3D::ModelNode Model::FindChildModelNodeByName(std::string_view nodeName)
533 {
534   Actor childActor = Self().FindChildByName(nodeName);
535   return Scene3D::ModelNode::DownCast(childActor);
536 }
537
538 void Model::RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const
539 {
540   blendShapeNames.reserve(blendShapeNames.size() + mBlendShapeModelNodeMap.size());
541   for(const auto& iter : mBlendShapeModelNodeMap)
542   {
543     blendShapeNames.push_back(iter.first);
544   }
545 }
546
547 void Model::RetrieveModelNodesByBlendShapeName(std::string_view blendShapeName, std::vector<Scene3D::ModelNode>& modelNodes) const
548 {
549   auto iter = mBlendShapeModelNodeMap.find(std::string(blendShapeName));
550   if(iter != mBlendShapeModelNodeMap.end())
551   {
552     const auto& modelNodeList = iter->second;
553     modelNodes.reserve(modelNodes.size() + modelNodeList.size());
554     for(const auto& nodeIter : modelNodeList)
555     {
556       modelNodes.push_back(nodeIter);
557     }
558   }
559 }
560
561 ///////////////////////////////////////////////////////////
562 //
563 // Private methods
564 //
565
566 void Model::OnInitialize()
567 {
568   // Make ParentOrigin as Center.
569   Self().SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
570   mLights.resize(Scene3D::Internal::Light::GetMaximumEnabledLightCount());
571 }
572
573 void Model::OnSceneConnection(int depth)
574 {
575   if(!mModelLoadTask && !mModelResourceReady && !mModelUrl.empty())
576   {
577     // Request model load only if we setup url.
578     if(ModelCacheManager::Get())
579     {
580       ModelCacheManager::Get().ReferenceModelCache(mModelUrl);
581     }
582     mModelLoadTask = new ModelLoadTask(mModelUrl, mResourceDirectoryUrl, MakeCallback(this, &Model::OnModelLoadComplete));
583     Dali::AsyncTaskManager::Get().AddTask(mModelLoadTask);
584   }
585
586   // If diffuse and specular url is not valid, IBL does not need to be loaded.
587   if(!mDiffuseIblUrl.empty() && !mSpecularIblUrl.empty())
588   {
589     SetImageBasedLightSource(mDiffuseIblUrl, mSpecularIblUrl, mIblScaleFactor);
590   }
591
592   Actor parent = Self().GetParent();
593   while(parent)
594   {
595     Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(parent);
596     if(sceneView)
597     {
598       GetImpl(sceneView).RegisterSceneItem(this);
599       mParentSceneView = sceneView;
600       break;
601     }
602     parent = parent.GetParent();
603   }
604
605   NotifyResourceReady();
606
607   mSizeNotification = Self().AddPropertyNotification(Actor::Property::SIZE, StepCondition(SIZE_STEP_CONDITION));
608   mSizeNotification.NotifySignal().Connect(this, &Model::OnSizeNotification);
609   Control::OnSceneConnection(depth);
610 }
611
612 void Model::OnSceneDisconnection()
613 {
614   Scene3D::SceneView sceneView = mParentSceneView.GetHandle();
615   if(sceneView)
616   {
617     GetImpl(sceneView).UnregisterSceneItem(this);
618     mParentSceneView.Reset();
619   }
620
621   mSizeNotification.NotifySignal().Disconnect(this, &Model::OnSizeNotification);
622   Self().RemovePropertyNotification(mSizeNotification);
623   mSizeNotification.Reset();
624
625   Control::OnSceneDisconnection();
626 }
627
628 void Model::OnSizeSet(const Vector3& size)
629 {
630   ScaleModel(false);
631 }
632
633 Vector3 Model::GetNaturalSize()
634 {
635   if(!mModelRoot)
636   {
637     DALI_LOG_ERROR("Model is still not loaded.\n");
638     return Vector3::ZERO;
639   }
640
641   return mNaturalSize;
642 }
643
644 float Model::GetHeightForWidth(float width)
645 {
646   Extents padding;
647   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
648   return Control::GetHeightForWidth(width) + padding.top + padding.bottom;
649 }
650
651 float Model::GetWidthForHeight(float height)
652 {
653   Extents padding;
654   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
655   return Control::GetWidthForHeight(height) + padding.start + padding.end;
656 }
657
658 void Model::OnRelayout(const Vector2& size, RelayoutContainer& container)
659 {
660   Control::OnRelayout(size, container);
661   ScaleModel(false);
662 }
663
664 bool Model::IsResourceReady() const
665 {
666   return mModelResourceReady && mIblDiffuseResourceReady && mIblSpecularResourceReady;
667 }
668
669 void Model::CreateModelRoot()
670 {
671   mModelRoot = Scene3D::ModelNode::New();
672   mModelRoot.SetProperty(Actor::Property::COLOR_MODE, ColorMode::USE_OWN_MULTIPLY_PARENT_COLOR);
673   mModelRoot.SetProperty(Dali::Actor::Property::SCALE, Y_DIRECTION);
674   mModelRoot.SetProperty(Dali::Actor::Property::SENSITIVE, mModelChildrenSensitive);
675   mModelRoot.SetProperty(Dali::Actor::Property::KEYBOARD_FOCUSABLE, mModelChildrenFocusable);
676   mModelRoot.SetProperty(Dali::DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN, mModelChildrenFocusable);
677   Self().Add(mModelRoot);
678 }
679
680 void Model::ScaleModel(bool useCurrentSize)
681 {
682   if(!mModelRoot)
683   {
684     return;
685   }
686
687   float   scale = 1.0f;
688   Vector3 size  = (useCurrentSize) ? Self().GetCurrentProperty<Vector3>(Dali::Actor::Property::SIZE) : Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
689   if(size.x > 0.0f && size.y > 0.0f)
690   {
691     scale = MAXFLOAT;
692     scale = std::min(size.x / mNaturalSize.x, scale);
693     scale = std::min(size.y / mNaturalSize.y, scale);
694   }
695   // Models in glTF and dli are defined as right hand coordinate system.
696   // DALi uses left hand coordinate system. Scaling negative is for change winding order.
697   mModelRoot.SetProperty(Dali::Actor::Property::SCALE, Y_DIRECTION * scale);
698 }
699
700 void Model::FitModelPosition()
701 {
702   if(!mModelRoot)
703   {
704     return;
705   }
706   // Loaded model pivot is not the model center.
707   mModelRoot.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
708   mModelRoot.SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3::ONE - mModelPivot);
709 }
710
711 void Model::UpdateImageBasedLightTextureRecursively(Scene3D::ModelNode node, Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
712 {
713   if(!node)
714   {
715     return;
716   }
717
718   GetImplementation(node).SetImageBasedLightTexture(diffuseTexture, specularTexture, iblScaleFactor, specularMipmapLevels);
719   uint32_t childrenCount = node.GetChildCount();
720   for(uint32_t i = 0; i < childrenCount; ++i)
721   {
722     Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
723     if(!childNode)
724     {
725       continue;
726     }
727     UpdateImageBasedLightTextureRecursively(childNode, diffuseTexture, specularTexture, iblScaleFactor, specularMipmapLevels);
728   }
729 }
730
731 void Model::UpdateImageBasedLightScaleFactorRecursively(Scene3D::ModelNode node, float iblScaleFactor)
732 {
733   if(!node)
734   {
735     return;
736   }
737
738   GetImplementation(node).SetImageBasedLightScaleFactor(iblScaleFactor);
739
740   uint32_t childrenCount = node.GetChildCount();
741   for(uint32_t i = 0; i < childrenCount; ++i)
742   {
743     Scene3D::ModelNode childNode = Scene3D::ModelNode::DownCast(node.GetChildAt(i));
744     if(!childNode)
745     {
746       continue;
747     }
748     UpdateImageBasedLightScaleFactorRecursively(childNode, iblScaleFactor);
749   }
750 }
751
752 void Model::UpdateImageBasedLightTexture()
753 {
754   Dali::Texture currentDiffuseTexture          = (mDiffuseTexture && mSpecularTexture) ? mDiffuseTexture : mSceneDiffuseTexture;
755   Dali::Texture currentSpecularTexture         = (mDiffuseTexture && mSpecularTexture) ? mSpecularTexture : mSceneSpecularTexture;
756   float         currentIblScaleFactor          = (mDiffuseTexture && mSpecularTexture) ? mIblScaleFactor : mSceneIblScaleFactor;
757   uint32_t      currentIblSpecularMipmapLevels = (mDiffuseTexture && mSpecularTexture) ? mSpecularMipmapLevels : mSceneSpecularMipmapLevels;
758
759   if(!currentDiffuseTexture || !currentSpecularTexture)
760   {
761     currentDiffuseTexture          = mDefaultDiffuseTexture;
762     currentSpecularTexture         = mDefaultSpecularTexture;
763     currentIblScaleFactor          = Dali::Scene3D::Loader::EnvironmentDefinition::GetDefaultIntensity();
764     currentIblSpecularMipmapLevels = 1u;
765   }
766
767   UpdateImageBasedLightTextureRecursively(mModelRoot, currentDiffuseTexture, currentSpecularTexture, currentIblScaleFactor, currentIblSpecularMipmapLevels);
768 }
769
770 void Model::UpdateImageBasedLightScaleFactor()
771 {
772   if((!mDiffuseTexture || !mSpecularTexture) &&
773      (!mSceneDiffuseTexture || !mSceneSpecularTexture))
774   {
775     return;
776   }
777
778   float currentIblScaleFactor = (mDiffuseTexture && mSpecularTexture) ? mIblScaleFactor : mSceneIblScaleFactor;
779   UpdateImageBasedLightScaleFactorRecursively(mModelRoot, currentIblScaleFactor);
780 }
781
782 void Model::ApplyCameraTransform(Dali::CameraActor camera) const
783 {
784   Vector3    selfPosition    = Self().GetProperty<Vector3>(Actor::Property::POSITION);
785   Quaternion selfOrientation = Self().GetProperty<Quaternion>(Actor::Property::ORIENTATION);
786   Vector3    selfScale       = Self().GetProperty<Vector3>(Actor::Property::SCALE);
787
788   Vector3    cameraPosition    = camera.GetProperty<Vector3>(Actor::Property::POSITION);
789   Quaternion cameraOrientation = camera.GetProperty<Quaternion>(Actor::Property::ORIENTATION);
790   Vector3    cameraScale       = camera.GetProperty<Vector3>(Actor::Property::SCALE);
791
792   // Models in glTF and dli are defined as right hand coordinate system.
793   // DALi uses left hand coordinate system. Scaling negative is for change winding order.
794   if(!Dali::Equals(Y_DIRECTION.Dot(Vector3::YAXIS), 1.0f))
795   {
796     // Reflect by XZ plane
797     cameraPosition.y = -cameraPosition.y;
798     Quaternion yDirectionQuaternion;
799     yDirectionQuaternion.mVector = Vector3::YAXIS;
800     // Reflect orientation
801     cameraOrientation = yDirectionQuaternion * cameraOrientation * yDirectionQuaternion;
802   }
803
804   Vector3    resultPosition;
805   Quaternion resultOrientation;
806   Vector3    resultScale;
807
808   Matrix selfMatrix(false);
809   Matrix cameraMatrix(false);
810   Matrix resultMatrix(false);
811   selfMatrix.SetTransformComponents(selfScale, selfOrientation, selfPosition);
812   cameraMatrix.SetTransformComponents(cameraScale, cameraOrientation, cameraPosition);
813   Matrix::Multiply(resultMatrix, cameraMatrix, selfMatrix);
814   resultMatrix.GetTransformComponents(resultPosition, resultOrientation, resultScale);
815
816   camera.SetProperty(Actor::Property::POSITION, resultPosition);
817   camera.SetProperty(Actor::Property::ORIENTATION, resultOrientation);
818   camera.SetProperty(Actor::Property::SCALE, resultScale);
819 }
820
821 void Model::NotifyImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float scaleFactor, uint32_t specularMipmapLevels)
822 {
823   if(mSceneDiffuseTexture != diffuseTexture || mSceneSpecularTexture != specularTexture)
824   {
825     mSceneDiffuseTexture       = diffuseTexture;
826     mSceneSpecularTexture      = specularTexture;
827     mSceneIblScaleFactor       = scaleFactor;
828     mSceneSpecularMipmapLevels = specularMipmapLevels;
829     // If Model IBL is not set, use SceneView's IBL.
830     if(!mDiffuseTexture || !mSpecularTexture)
831     {
832       UpdateImageBasedLightTexture();
833     }
834   }
835 }
836
837 void Model::NotifyImageBasedLightScaleFactor(float scaleFactor)
838 {
839   mSceneIblScaleFactor = scaleFactor;
840   if(mSceneDiffuseTexture && mSceneSpecularTexture)
841   {
842     UpdateImageBasedLightScaleFactor();
843   }
844 }
845
846 void Model::NotifyLightAdded(uint32_t lightIndex, Scene3D::Light light)
847 {
848   mLights[lightIndex] = light;
849   AddLightRecursively(mModelRoot, light, lightIndex);
850 }
851
852 void Model::NotifyLightRemoved(uint32_t lightIndex)
853 {
854   if(mLights[lightIndex])
855   {
856     RemoveLightRecursively(mModelRoot, lightIndex);
857     mLights[lightIndex].Reset();
858   }
859 }
860
861 void Model::OnModelLoadComplete()
862 {
863   if(!mModelLoadTask->HasSucceeded())
864   {
865     ResetResourceTasks();
866
867     if(ModelCacheManager::Get() && !mModelUrl.empty())
868     {
869       ModelCacheManager::Get().UnreferenceModelCache(mModelUrl);
870     }
871
872     return;
873   }
874
875   if(!mModelRoot)
876   {
877     CreateModelRoot();
878   }
879   CreateModel();
880
881   auto& resources = mModelLoadTask->GetResources();
882   auto& scene     = mModelLoadTask->GetScene();
883   CreateAnimations(scene);
884   ResetCameraParameters();
885   if(!resources.mEnvironmentMaps.empty())
886   {
887     mDefaultDiffuseTexture  = resources.mEnvironmentMaps.front().second.mDiffuse;
888     mDefaultSpecularTexture = resources.mEnvironmentMaps.front().second.mSpecular;
889   }
890
891   uint32_t maxLightCount = Scene3D::Internal::Light::GetMaximumEnabledLightCount();
892   for(uint32_t i = 0; i < maxLightCount; ++i)
893   {
894     if(mLights[i])
895     {
896       AddLightRecursively(mModelRoot, mLights[i], i);
897     }
898   }
899
900   UpdateImageBasedLightTexture();
901   UpdateImageBasedLightScaleFactor();
902   Self().SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3(mModelPivot.x, 1.0f - mModelPivot.y, mModelPivot.z));
903
904   mModelResourceReady = true;
905   NotifyResourceReady();
906   ResetResourceTask(mModelLoadTask);
907 }
908
909 void Model::OnIblDiffuseLoadComplete()
910 {
911   mDiffuseTexture = mIblDiffuseLoadTask->GetLoadedTexture();
912   ResetResourceTask(mIblDiffuseLoadTask);
913   mIblDiffuseResourceReady = true;
914   if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
915   {
916     OnIblLoadComplete();
917   }
918 }
919
920 void Model::OnIblSpecularLoadComplete()
921 {
922   mSpecularTexture      = mIblSpecularLoadTask->GetLoadedTexture();
923   mSpecularMipmapLevels = mIblSpecularLoadTask->GetMipmapLevels();
924   ResetResourceTask(mIblSpecularLoadTask);
925   mIblSpecularResourceReady = true;
926   if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
927   {
928     OnIblLoadComplete();
929   }
930 }
931
932 void Model::OnIblLoadComplete()
933 {
934   UpdateImageBasedLightTexture();
935   NotifyResourceReady();
936 }
937
938 void Model::OnSizeNotification(Dali::PropertyNotification& source)
939 {
940   ScaleModel(true);
941 }
942
943 void Model::ResetResourceTasks()
944 {
945   if(!Dali::Adaptor::IsAvailable())
946   {
947     return;
948   }
949   ResetResourceTask(mModelLoadTask);
950   ResetResourceTask(mIblDiffuseLoadTask);
951   ResetResourceTask(mIblSpecularLoadTask);
952 }
953
954 void Model::ResetResourceTask(IntrusivePtr<AsyncTask> asyncTask)
955 {
956   if(!asyncTask)
957   {
958     return;
959   }
960   Dali::AsyncTaskManager::Get().RemoveTask(asyncTask);
961   asyncTask.Reset();
962 }
963
964 void Model::NotifyResourceReady()
965 {
966   if(!IsResourceReady())
967   {
968     return;
969   }
970   Control::SetResourceReady();
971 }
972
973 void Model::CreateModel()
974 {
975   BoundingVolume                                      AABB;
976   auto&                                               resources       = mModelLoadTask->GetResources();
977   auto&                                               scene           = mModelLoadTask->GetScene();
978   auto&                                               resourceChoices = mModelLoadTask->GetResourceChoices();
979   Dali::Scene3D::Loader::Transforms                   xforms{Dali::Scene3D::Loader::MatrixStack{}, Dali::Scene3D::Loader::ViewProjection{}};
980   Dali::Scene3D::Loader::NodeDefinition::CreateParams nodeParams{resources, xforms, {}, {}, {}};
981
982   // Generate Dali handles from resource bundle. Note that we generate all scene's resouce immediatly.
983   resources.GenerateResources();
984   for(auto iRoot : scene.GetRoots())
985   {
986     if(auto modelNode = scene.CreateNodes(iRoot, resourceChoices, nodeParams))
987     {
988       scene.ConfigureSkinningShaders(resources, modelNode, std::move(nodeParams.mSkinnables));
989       ConfigureBlendShapeShaders(resources, scene, modelNode, std::move(nodeParams.mBlendshapeRequests));
990
991       scene.ApplyConstraints(modelNode, std::move(nodeParams.mConstrainables));
992
993       mModelRoot.Add(modelNode);
994     }
995
996     AddModelTreeToAABB(AABB, scene, resourceChoices, iRoot, nodeParams, Matrix::IDENTITY);
997   }
998
999   UpdateBlendShapeNodeMap();
1000
1001   mNaturalSize = AABB.CalculateSize();
1002   mModelPivot  = AABB.CalculatePivot();
1003   mModelRoot.SetProperty(Dali::Actor::Property::SIZE, mNaturalSize);
1004   Vector3 controlSize = Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
1005   if(Dali::EqualsZero(controlSize.x) || Dali::EqualsZero(controlSize.y))
1006   {
1007     Self().SetProperty(Dali::Actor::Property::SIZE, mNaturalSize);
1008   }
1009   FitModelPosition();
1010   ScaleModel(false);
1011 }
1012
1013 void Model::CreateAnimations(Dali::Scene3D::Loader::SceneDefinition& scene)
1014 {
1015   mAnimations.clear();
1016   if(!mModelLoadTask->GetAnimations().empty())
1017   {
1018     auto getActor = [&](const Scene3D::Loader::AnimatedProperty& property) {
1019       if(property.mNodeIndex == Scene3D::Loader::INVALID_INDEX)
1020       {
1021         return mModelRoot.FindChildByName(property.mNodeName);
1022       }
1023       auto* node = scene.GetNode(property.mNodeIndex);
1024       if(node == nullptr)
1025       {
1026         return Dali::Actor();
1027       }
1028       return mModelRoot.FindChildById(node->mNodeId);
1029     };
1030
1031     for(auto&& animation : mModelLoadTask->GetAnimations())
1032     {
1033       Dali::Animation anim = animation.ReAnimate(getActor);
1034       mAnimations.push_back({animation.GetName(), anim});
1035     }
1036   }
1037 }
1038
1039 void Model::ResetCameraParameters()
1040 {
1041   mCameraParameters.clear();
1042   if(!mModelLoadTask->GetCameras().empty())
1043   {
1044     // Copy camera parameters.
1045     std::copy(mModelLoadTask->GetCameras().begin(), mModelLoadTask->GetCameras().end(), std::back_inserter(mCameraParameters));
1046   }
1047 }
1048
1049 void Model::UpdateBlendShapeNodeMap()
1050 {
1051   // Remove privous node map
1052   mBlendShapeModelNodeMap.clear();
1053
1054   UpdateBlendShapeNodeMapRecursively(mBlendShapeModelNodeMap, mModelRoot);
1055 }
1056
1057 } // namespace Internal
1058 } // namespace Scene3D
1059 } // namespace Dali