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