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