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