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