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