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