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