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