[dali_2.2.16] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / internal / controls / model / model-impl.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-scene3d/internal/controls/model/model-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali-toolkit/dali-toolkit.h>
23 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
24 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
25 #include <dali/devel-api/actors/actor-devel.h>
26 #include <dali/integration-api/adaptor-framework/adaptor.h>
27 #include <dali/integration-api/debug.h>
28 #include <dali/public-api/math/math-utils.h>
29 #include <dali/public-api/object/type-registry-helper.h>
30 #include <dali/public-api/object/type-registry.h>
31 #include <filesystem>
32
33 // INTERNAL INCLUDES
34 #include <dali-scene3d/internal/common/model-cache-manager.h>
35 #include <dali-scene3d/internal/controls/scene-view/scene-view-impl.h>
36 #include <dali-scene3d/public-api/controls/model/model.h>
37 #include <dali-scene3d/public-api/loader/animation-definition.h>
38 #include <dali-scene3d/public-api/loader/camera-parameters.h>
39 #include <dali-scene3d/public-api/loader/dli-loader.h>
40 #include <dali-scene3d/public-api/loader/gltf2-loader.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
47 using namespace Dali;
48
49 namespace Dali
50 {
51 namespace Scene3D
52 {
53 namespace Internal
54 {
55 namespace
56 {
57 BaseHandle Create()
58 {
59   return Scene3D::Model::New(std::string());
60 }
61
62 // Setup properties, signals and actions using the type-registry.
63 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::Model, Toolkit::Control, Create);
64 DALI_TYPE_REGISTRATION_END()
65
66 static constexpr uint32_t OFFSET_FOR_DIFFUSE_CUBE_TEXTURE  = 2u;
67 static constexpr uint32_t OFFSET_FOR_SPECULAR_CUBE_TEXTURE = 1u;
68
69 static constexpr Vector3 Y_DIRECTION(1.0f, -1.0f, 1.0f);
70
71 static constexpr bool DEFAULT_MODEL_CHILDREN_SENSITIVE = false;
72 static constexpr bool DEFAULT_MODEL_CHILDREN_FOCUSABLE = false;
73
74 struct BoundingVolume
75 {
76   void Init()
77   {
78     pointMin = Vector3(std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
79     pointMax = Vector3(std::numeric_limits<float>::min(), std::numeric_limits<float>::min(), std::numeric_limits<float>::min());
80   }
81
82   void ConsiderNewPointInVolume(const Vector3& position)
83   {
84     pointMin.x = std::min(position.x, pointMin.x);
85     pointMin.y = std::min(position.y, pointMin.y);
86     pointMin.z = std::min(position.z, pointMin.z);
87
88     pointMax.x = std::max(position.x, pointMax.x);
89     pointMax.y = std::max(position.y, pointMax.y);
90     pointMax.z = std::max(position.z, pointMax.z);
91   }
92
93   Vector3 CalculateSize()
94   {
95     return pointMax - pointMin;
96   }
97
98   Vector3 CalculatePivot()
99   {
100     Vector3 pivot = pointMin / (pointMin - pointMax);
101     for(uint32_t i = 0; i < 3; ++i)
102     {
103       // To avoid divid by zero
104       if(Dali::Equals(pointMin[i], pointMax[i]))
105       {
106         pivot[i] = 0.5f;
107       }
108     }
109     return pivot;
110   }
111
112   Vector3 pointMin;
113   Vector3 pointMax;
114 };
115
116 void ConfigureBlendShapeShaders(
117   Dali::Scene3D::Loader::ResourceBundle& resources, const Dali::Scene3D::Loader::SceneDefinition& scene, Actor root, std::vector<Dali::Scene3D::Loader::BlendshapeShaderConfigurationRequest>&& requests)
118 {
119   std::vector<std::string> errors;
120   auto                     onError = [&errors](const std::string& msg) { errors.push_back(msg); };
121   if(!scene.ConfigureBlendshapeShaders(resources, root, std::move(requests), onError))
122   {
123     Dali::Scene3D::Loader::ExceptionFlinger flinger(ASSERT_LOCATION);
124     for(auto& msg : errors)
125     {
126       flinger << msg << '\n';
127     }
128   }
129 }
130
131 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)
132 {
133   static constexpr uint32_t BOX_POINT_COUNT             = 8;
134   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}};
135
136   Matrix                                       nodeMatrix;
137   const Dali::Scene3D::Loader::NodeDefinition* node        = scene.GetNode(iNode);
138   Matrix                                       localMatrix = node->GetLocalSpace();
139   Matrix::Multiply(nodeMatrix, localMatrix, parentMatrix);
140
141   Vector3 volume[2];
142   if(node->GetExtents(nodeParams.mResources, volume[0], volume[1]))
143   {
144     for(uint32_t i = 0; i < BOX_POINT_COUNT; ++i)
145     {
146       Vector4 position       = Vector4(volume[BBIndex[i][0]].x, volume[BBIndex[i][1]].y, volume[BBIndex[i][2]].z, 1.0f);
147       Vector4 objectPosition = nodeMatrix * position;
148       objectPosition /= objectPosition.w;
149
150       AABB.ConsiderNewPointInVolume(Vector3(objectPosition));
151     }
152   }
153
154   if(node->mCustomization)
155   {
156     if(!node->mChildren.empty())
157     {
158       auto                         choice = choices.Get(node->mCustomization->mTag);
159       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));
160
161       AddModelTreeToAABB(AABB, scene, choices, node->mChildren[i], nodeParams, nodeMatrix);
162     }
163   }
164   else
165   {
166     for(auto i : node->mChildren)
167     {
168       AddModelTreeToAABB(AABB, scene, choices, i, nodeParams, nodeMatrix);
169     }
170   }
171 }
172
173 } // anonymous namespace
174
175 Model::Model(const std::string& modelUrl, const std::string& resourceDirectoryUrl)
176 : Control(ControlBehaviour(DISABLE_SIZE_NEGOTIATION | DISABLE_STYLE_CHANGE_SIGNALS)),
177   mModelUrl(modelUrl),
178   mResourceDirectoryUrl(resourceDirectoryUrl),
179   mModelRoot(),
180   mNaturalSize(Vector3::ZERO),
181   mModelPivot(AnchorPoint::CENTER),
182   mSceneIblScaleFactor(1.0f),
183   mIblScaleFactor(1.0f),
184   mModelChildrenSensitive(DEFAULT_MODEL_CHILDREN_SENSITIVE),
185   mModelChildrenFocusable(DEFAULT_MODEL_CHILDREN_FOCUSABLE),
186   mModelResourceReady(false),
187   mIblDiffuseResourceReady(true),
188   mIblSpecularResourceReady(true),
189   mIblDiffuseDirty(false),
190   mIblSpecularDirty(false)
191 {
192 }
193
194 Model::~Model()
195 {
196   if(ModelCacheManager::Get())
197   {
198     ModelCacheManager::Get().UnreferenceModelCache(mModelUrl);
199   }
200
201   ResetResourceTasks();
202 }
203
204 Dali::Scene3D::Model Model::New(const std::string& modelUrl, const std::string& resourceDirectoryUrl)
205 {
206   Model* impl = new Model(modelUrl, resourceDirectoryUrl);
207
208   Dali::Scene3D::Model handle = Dali::Scene3D::Model(*impl);
209
210   // Second-phase init of the implementation
211   // This can only be done after the CustomActor connection has been made...
212   impl->Initialize();
213
214   return handle;
215 }
216
217 const Actor Model::GetModelRoot() const
218 {
219   return mModelRoot;
220 }
221
222 void Model::SetChildrenSensitive(bool enable)
223 {
224   if(mModelChildrenSensitive != enable)
225   {
226     mModelChildrenSensitive = enable;
227     if(mModelRoot)
228     {
229       mModelRoot.SetProperty(Dali::Actor::Property::SENSITIVE, mModelChildrenSensitive);
230     }
231   }
232 }
233
234 bool Model::GetChildrenSensitive() const
235 {
236   return mModelChildrenSensitive;
237 }
238
239 void Model::SetChildrenFocusable(bool enable)
240 {
241   if(mModelChildrenFocusable != enable)
242   {
243     mModelChildrenFocusable = enable;
244     if(mModelRoot)
245     {
246       mModelRoot.SetProperty(Dali::Actor::Property::KEYBOARD_FOCUSABLE, mModelChildrenFocusable);
247       mModelRoot.SetProperty(Dali::DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN, mModelChildrenFocusable);
248     }
249   }
250 }
251
252 bool Model::GetChildrenFocusable() const
253 {
254   return mModelChildrenFocusable;
255 }
256
257 void Model::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor)
258 {
259   bool needIblReset = false;
260   bool isOnScene    = Self().GetProperty<bool>(Dali::Actor::Property::CONNECTED_TO_SCENE);
261   if(mDiffuseIblUrl != diffuseUrl)
262   {
263     mDiffuseIblUrl = diffuseUrl;
264     if(mDiffuseIblUrl.empty())
265     {
266       needIblReset = true;
267     }
268     else
269     {
270       mIblDiffuseDirty         = true;
271       mIblDiffuseResourceReady = false;
272     }
273   }
274
275   if(mSpecularIblUrl != specularUrl)
276   {
277     mSpecularIblUrl = specularUrl;
278     if(mSpecularIblUrl.empty())
279     {
280       needIblReset = true;
281     }
282     else
283     {
284       mIblSpecularDirty         = true;
285       mIblSpecularResourceReady = false;
286     }
287   }
288
289   // If one or both of diffuse url and specular url are empty,
290   // we don't need to request to load texture.
291   if(needIblReset)
292   {
293     ResetResourceTask(mIblDiffuseLoadTask);
294     ResetResourceTask(mIblSpecularLoadTask);
295
296     mIblDiffuseDirty          = false;
297     mIblSpecularDirty         = false;
298     mIblDiffuseResourceReady  = true;
299     mIblSpecularResourceReady = true;
300
301     mDiffuseTexture.Reset();
302     mSpecularTexture.Reset();
303     UpdateImageBasedLightTexture();
304   }
305   else
306   {
307     if(isOnScene && mIblDiffuseDirty)
308     {
309       ResetResourceTask(mIblDiffuseLoadTask);
310       mIblDiffuseLoadTask = new EnvironmentMapLoadTask(mDiffuseIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &Model::OnIblDiffuseLoadComplete));
311       Dali::AsyncTaskManager::Get().AddTask(mIblDiffuseLoadTask);
312       mIblDiffuseDirty = false;
313     }
314
315     if(isOnScene && mIblSpecularDirty)
316     {
317       ResetResourceTask(mIblSpecularLoadTask);
318       mIblSpecularLoadTask = new EnvironmentMapLoadTask(mSpecularIblUrl, Scene3D::EnvironmentMapType::CUBEMAP, MakeCallback(this, &Model::OnIblSpecularLoadComplete));
319       Dali::AsyncTaskManager::Get().AddTask(mIblSpecularLoadTask);
320       mIblSpecularDirty = false;
321     }
322   }
323
324   if(!Dali::Equals(mIblScaleFactor, scaleFactor))
325   {
326     mIblScaleFactor = scaleFactor;
327     UpdateImageBasedLightScaleFactor();
328   }
329
330   // If diffuse and specular textures are already loaded, emits resource ready signal here.
331   NotifyResourceReady();
332 }
333
334 void Model::SetImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float scaleFactor)
335 {
336   // If input texture is wrong, Model is rendered with SceneView's IBL.
337   if(mDiffuseTexture != diffuseTexture || mSpecularTexture != specularTexture)
338   {
339     mDiffuseTexture  = diffuseTexture;
340     mSpecularTexture = specularTexture;
341     mIblScaleFactor  = scaleFactor;
342     UpdateImageBasedLightTexture();
343   }
344 }
345
346 void Model::SetImageBasedLightScaleFactor(float scaleFactor)
347 {
348   mIblScaleFactor = scaleFactor;
349   if(mDiffuseTexture && mSpecularTexture)
350   {
351     UpdateImageBasedLightScaleFactor();
352   }
353 }
354
355 float Model::GetImageBasedLightScaleFactor() const
356 {
357   return mIblScaleFactor;
358 }
359
360 uint32_t Model::GetAnimationCount() const
361 {
362   return mAnimations.size();
363 }
364
365 Dali::Animation Model::GetAnimation(uint32_t index) const
366 {
367   Dali::Animation animation;
368   if(mAnimations.size() > index)
369   {
370     animation = mAnimations[index].second;
371   }
372   return animation;
373 }
374
375 Dali::Animation Model::GetAnimation(const std::string& name) const
376 {
377   Dali::Animation animation;
378   if(!name.empty())
379   {
380     for(auto&& animationData : mAnimations)
381     {
382       if(animationData.first == name)
383       {
384         animation = animationData.second;
385         break;
386       }
387     }
388   }
389   return animation;
390 }
391
392 uint32_t Model::GetCameraCount() const
393 {
394   return mCameraParameters.size();
395 }
396
397 Dali::CameraActor Model::GenerateCamera(uint32_t index) const
398 {
399   Dali::CameraActor camera;
400   if(mCameraParameters.size() > index)
401   {
402     camera = Dali::CameraActor::New3DCamera();
403     if(!mCameraParameters[index].ConfigureCamera(camera, false))
404     {
405       DALI_LOG_ERROR("Fail to generate %u's camera actor : Some property was not defined. Please check model file.\n", index);
406       camera.Reset();
407       return camera;
408     }
409
410     ApplyCameraTransform(camera);
411   }
412   return camera;
413 }
414
415 bool Model::ApplyCamera(uint32_t index, Dali::CameraActor camera) const
416 {
417   if(camera && mCameraParameters.size() > index)
418   {
419     if(!mCameraParameters[index].ConfigureCamera(camera, false))
420     {
421       DALI_LOG_ERROR("Fail to apply %u's camera actor : Some property was not defined. Please check model file.\n", index);
422       return false;
423     }
424
425     ApplyCameraTransform(camera);
426     return true;
427   }
428   return false;
429 }
430
431 ///////////////////////////////////////////////////////////
432 //
433 // Private methods
434 //
435
436 void Model::OnInitialize()
437 {
438   // Make ParentOrigin as Center.
439   Self().SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
440 }
441
442 void Model::OnSceneConnection(int depth)
443 {
444   if(!mModelLoadTask && !mModelRoot)
445   {
446     if(ModelCacheManager::Get())
447     {
448       ModelCacheManager::Get().ReferenceModelCache(mModelUrl);
449     }
450
451     Scene3D::Loader::InitializeGltfLoader();
452     mModelLoadTask = new ModelLoadTask(mModelUrl, mResourceDirectoryUrl, MakeCallback(this, &Model::OnModelLoadComplete));
453     Dali::AsyncTaskManager::Get().AddTask(mModelLoadTask);
454   }
455   // If diffuse and specular url is not valid, IBL does not need to be loaded.
456   if(!mDiffuseIblUrl.empty() && !mSpecularIblUrl.empty())
457   {
458     SetImageBasedLightSource(mDiffuseIblUrl, mSpecularIblUrl, mIblScaleFactor);
459   }
460
461   Actor parent = Self().GetParent();
462   while(parent)
463   {
464     Scene3D::SceneView sceneView = Scene3D::SceneView::DownCast(parent);
465     if(sceneView)
466     {
467       GetImpl(sceneView).RegisterSceneItem(this);
468       mParentSceneView = sceneView;
469       break;
470     }
471     parent = parent.GetParent();
472   }
473
474   Control::OnSceneConnection(depth);
475 }
476
477 void Model::OnSceneDisconnection()
478 {
479   Scene3D::SceneView sceneView = mParentSceneView.GetHandle();
480   if(sceneView)
481   {
482     GetImpl(sceneView).UnregisterSceneItem(this);
483     mParentSceneView.Reset();
484   }
485   Control::OnSceneDisconnection();
486 }
487
488 Vector3 Model::GetNaturalSize()
489 {
490   if(!mModelRoot)
491   {
492     DALI_LOG_ERROR("Model is still not loaded.\n");
493     return Vector3::ZERO;
494   }
495
496   return mNaturalSize;
497 }
498
499 float Model::GetHeightForWidth(float width)
500 {
501   Extents padding;
502   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
503   return Control::GetHeightForWidth(width) + padding.top + padding.bottom;
504 }
505
506 float Model::GetWidthForHeight(float height)
507 {
508   Extents padding;
509   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
510   return Control::GetWidthForHeight(height) + padding.start + padding.end;
511 }
512
513 void Model::OnRelayout(const Vector2& size, RelayoutContainer& container)
514 {
515   Control::OnRelayout(size, container);
516   ScaleModel();
517 }
518
519 bool Model::IsResourceReady() const
520 {
521   return mModelResourceReady && mIblDiffuseResourceReady && mIblSpecularResourceReady;
522 }
523
524 void Model::ScaleModel()
525 {
526   if(!mModelRoot)
527   {
528     return;
529   }
530
531   float   scale = 1.0f;
532   Vector3 size  = Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
533   if(size.x > 0.0f && size.y > 0.0f)
534   {
535     scale = MAXFLOAT;
536     scale = std::min(size.x / mNaturalSize.x, scale);
537     scale = std::min(size.y / mNaturalSize.y, scale);
538   }
539   // Models in glTF and dli are defined as right hand coordinate system.
540   // DALi uses left hand coordinate system. Scaling negative is for change winding order.
541   mModelRoot.SetProperty(Dali::Actor::Property::SCALE, Y_DIRECTION * scale);
542 }
543
544 void Model::FitModelPosition()
545 {
546   if(!mModelRoot)
547   {
548     return;
549   }
550   // Loaded model pivot is not the model center.
551   mModelRoot.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
552   mModelRoot.SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3::ONE - mModelPivot);
553 }
554
555 void Model::CollectRenderableActor(Actor actor)
556 {
557   uint32_t rendererCount = actor.GetRendererCount();
558   if(rendererCount)
559   {
560     mRenderableActors.push_back(actor);
561   }
562
563   uint32_t childrenCount = actor.GetChildCount();
564   for(uint32_t i = 0; i < childrenCount; ++i)
565   {
566     CollectRenderableActor(actor.GetChildAt(i));
567   }
568 }
569
570 void Model::UpdateImageBasedLightTexture()
571 {
572   Dali::Texture currentDiffuseTexture  = (mDiffuseTexture && mSpecularTexture) ? mDiffuseTexture : mSceneDiffuseTexture;
573   Dali::Texture currentSpecularTexture = (mDiffuseTexture && mSpecularTexture) ? mSpecularTexture : mSceneSpecularTexture;
574   float         currentIblScaleFactor  = (mDiffuseTexture && mSpecularTexture) ? mIblScaleFactor : mSceneIblScaleFactor;
575
576   if(!currentDiffuseTexture || !currentSpecularTexture)
577   {
578     currentDiffuseTexture  = mDefaultDiffuseTexture;
579     currentSpecularTexture = mDefaultSpecularTexture;
580     currentIblScaleFactor  = Dali::Scene3D::Loader::EnvironmentDefinition::GetDefaultIntensity();
581   }
582
583   for(auto&& actor : mRenderableActors)
584   {
585     Actor renderableActor = actor.GetHandle();
586     if(!renderableActor)
587     {
588       continue;
589     }
590
591     uint32_t rendererCount = renderableActor.GetRendererCount();
592     for(uint32_t i = 0; i < rendererCount; ++i)
593     {
594       Dali::Renderer renderer = renderableActor.GetRendererAt(i);
595       if(!renderer)
596       {
597         continue;
598       }
599       Dali::TextureSet textures = renderer.GetTextures();
600       if(!textures)
601       {
602         continue;
603       }
604       uint32_t textureCount = textures.GetTextureCount();
605       // EnvMap requires at least 2 texture, diffuse and specular
606       if(textureCount > 2u &&
607          (textures.GetTexture(textureCount - OFFSET_FOR_DIFFUSE_CUBE_TEXTURE) != currentDiffuseTexture ||
608           textures.GetTexture(textureCount - OFFSET_FOR_SPECULAR_CUBE_TEXTURE) != currentSpecularTexture))
609       {
610         Dali::TextureSet newTextures = Dali::TextureSet::New();
611
612         for(uint32_t index = 0u; index < textureCount; ++index)
613         {
614           Dali::Texture texture = textures.GetTexture(index);
615           if(index == textureCount - OFFSET_FOR_DIFFUSE_CUBE_TEXTURE)
616           {
617             texture = currentDiffuseTexture;
618           }
619           else if(index == textureCount - OFFSET_FOR_SPECULAR_CUBE_TEXTURE)
620           {
621             texture = currentSpecularTexture;
622           }
623
624           newTextures.SetTexture(index, texture);
625           newTextures.SetSampler(index, textures.GetSampler(index));
626         }
627
628         renderer.SetTextures(newTextures);
629       }
630     }
631     renderableActor.RegisterProperty(Dali::Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName().data(), currentIblScaleFactor);
632   }
633 }
634
635 void Model::UpdateImageBasedLightScaleFactor()
636 {
637   if((!mDiffuseTexture || !mSpecularTexture) &&
638      (!mSceneDiffuseTexture || !mSceneSpecularTexture))
639   {
640     return;
641   }
642
643   float currentIblScaleFactor = (mDiffuseTexture && mSpecularTexture) ? mIblScaleFactor : mSceneIblScaleFactor;
644   for(auto&& actor : mRenderableActors)
645   {
646     Actor renderableActor = actor.GetHandle();
647     if(renderableActor)
648     {
649       renderableActor.RegisterProperty(Dali::Scene3D::Loader::NodeDefinition::GetIblScaleFactorUniformName().data(), currentIblScaleFactor);
650     }
651   }
652 }
653
654 void Model::ApplyCameraTransform(Dali::CameraActor camera) const
655 {
656   Vector3    selfPosition    = Self().GetProperty<Vector3>(Actor::Property::POSITION);
657   Quaternion selfOrientation = Self().GetProperty<Quaternion>(Actor::Property::ORIENTATION);
658   Vector3    selfScale       = Self().GetProperty<Vector3>(Actor::Property::SCALE);
659
660   Vector3    cameraPosition    = camera.GetProperty<Vector3>(Actor::Property::POSITION);
661   Quaternion cameraOrientation = camera.GetProperty<Quaternion>(Actor::Property::ORIENTATION);
662   Vector3    cameraScale       = camera.GetProperty<Vector3>(Actor::Property::SCALE);
663
664   // Models in glTF and dli are defined as right hand coordinate system.
665   // DALi uses left hand coordinate system. Scaling negative is for change winding order.
666   if(!Dali::Equals(Y_DIRECTION.Dot(Vector3::YAXIS), 1.0f))
667   {
668     // Reflect by XZ plane
669     cameraPosition.y = -cameraPosition.y;
670     Quaternion yDirectionQuaternion;
671     yDirectionQuaternion.mVector = Vector3::YAXIS;
672     // Reflect orientation
673     cameraOrientation = yDirectionQuaternion * cameraOrientation * yDirectionQuaternion;
674   }
675
676   Vector3    resultPosition;
677   Quaternion resultOrientation;
678   Vector3    resultScale;
679
680   Matrix selfMatrix(false);
681   Matrix cameraMatrix(false);
682   Matrix resultMatrix(false);
683   selfMatrix.SetTransformComponents(selfScale, selfOrientation, selfPosition);
684   cameraMatrix.SetTransformComponents(cameraScale, cameraOrientation, cameraPosition);
685   Matrix::Multiply(resultMatrix, cameraMatrix, selfMatrix);
686   resultMatrix.GetTransformComponents(resultPosition, resultOrientation, resultScale);
687
688   camera.SetProperty(Actor::Property::POSITION, resultPosition);
689   camera.SetProperty(Actor::Property::ORIENTATION, resultOrientation);
690   camera.SetProperty(Actor::Property::SCALE, resultScale);
691 }
692
693 void Model::NotifyImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float scaleFactor)
694 {
695   if(mSceneDiffuseTexture != diffuseTexture || mSceneSpecularTexture != specularTexture)
696   {
697     mSceneDiffuseTexture  = diffuseTexture;
698     mSceneSpecularTexture = specularTexture;
699     mSceneIblScaleFactor  = scaleFactor;
700     // If Model IBL is not set, use SceneView's IBL.
701     if(!mDiffuseTexture || !mSpecularTexture)
702     {
703       UpdateImageBasedLightTexture();
704     }
705   }
706 }
707
708 void Model::NotifyImageBasedLightScaleFactor(float scaleFactor)
709 {
710   mSceneIblScaleFactor = scaleFactor;
711   if(mSceneDiffuseTexture && mSceneSpecularTexture)
712   {
713     UpdateImageBasedLightScaleFactor();
714   }
715 }
716
717 void Model::OnModelLoadComplete()
718 {
719   if(!mModelLoadTask->HasSucceeded())
720   {
721     ResetResourceTasks();
722
723     if(ModelCacheManager::Get())
724     {
725       ModelCacheManager::Get().UnreferenceModelCache(mModelUrl);
726     }
727
728     return;
729   }
730
731   CreateModel();
732   mRenderableActors.clear();
733   CollectRenderableActor(mModelRoot);
734
735   CreateAnimations(mModelLoadTask->mLoadResult.mScene);
736   ResetCameraParameters();
737
738   if(!mModelLoadTask->mLoadResult.mResources.mEnvironmentMaps.empty())
739   {
740     mDefaultDiffuseTexture  = mModelLoadTask->mLoadResult.mResources.mEnvironmentMaps.front().second.mDiffuse;
741     mDefaultSpecularTexture = mModelLoadTask->mLoadResult.mResources.mEnvironmentMaps.front().second.mSpecular;
742   }
743
744   UpdateImageBasedLightTexture();
745   UpdateImageBasedLightScaleFactor();
746
747   mModelRoot.SetProperty(Dali::Actor::Property::SENSITIVE, mModelChildrenSensitive);
748   mModelRoot.SetProperty(Dali::Actor::Property::KEYBOARD_FOCUSABLE, mModelChildrenFocusable);
749   mModelRoot.SetProperty(Dali::DevelActor::Property::KEYBOARD_FOCUSABLE_CHILDREN, mModelChildrenFocusable);
750
751   Self().Add(mModelRoot);
752   Self().SetProperty(Dali::Actor::Property::ANCHOR_POINT, Vector3(mModelPivot.x, 1.0f - mModelPivot.y, mModelPivot.z));
753
754   mModelResourceReady = true;
755   NotifyResourceReady();
756   ResetResourceTask(mModelLoadTask);
757 }
758
759 void Model::OnIblDiffuseLoadComplete()
760 {
761   mDiffuseTexture = mIblDiffuseLoadTask->GetLoadedTexture();
762   ResetResourceTask(mIblDiffuseLoadTask);
763   mIblDiffuseResourceReady = true;
764   if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
765   {
766     OnIblLoadComplete();
767   }
768 }
769
770 void Model::OnIblSpecularLoadComplete()
771 {
772   mSpecularTexture = mIblSpecularLoadTask->GetLoadedTexture();
773   ResetResourceTask(mIblSpecularLoadTask);
774   mIblSpecularResourceReady = true;
775   if(mIblDiffuseResourceReady && mIblSpecularResourceReady)
776   {
777     OnIblLoadComplete();
778   }
779 }
780
781 void Model::OnIblLoadComplete()
782 {
783   UpdateImageBasedLightTexture();
784   NotifyResourceReady();
785 }
786
787 void Model::ResetResourceTasks()
788 {
789   if(!Dali::Adaptor::IsAvailable())
790   {
791     return;
792   }
793   ResetResourceTask(mModelLoadTask);
794   ResetResourceTask(mIblDiffuseLoadTask);
795   ResetResourceTask(mIblSpecularLoadTask);
796 }
797
798 void Model::ResetResourceTask(IntrusivePtr<AsyncTask> asyncTask)
799 {
800   if(!asyncTask)
801   {
802     return;
803   }
804   Dali::AsyncTaskManager::Get().RemoveTask(asyncTask);
805   asyncTask.Reset();
806 }
807
808 void Model::NotifyResourceReady()
809 {
810   if(!IsResourceReady())
811   {
812     return;
813   }
814   Control::SetResourceReady(false);
815 }
816
817 void Model::CreateModel()
818 {
819   mModelRoot = Actor::New();
820   mModelRoot.SetProperty(Actor::Property::COLOR_MODE, ColorMode::USE_OWN_MULTIPLY_PARENT_COLOR);
821
822   BoundingVolume                                      AABB;
823   Dali::Scene3D::Loader::Transforms                   xforms{Dali::Scene3D::Loader::MatrixStack{}, Dali::Scene3D::Loader::ViewProjection{}};
824   Dali::Scene3D::Loader::NodeDefinition::CreateParams nodeParams{mModelLoadTask->mLoadResult.mResources, xforms, {}, {}, {}};
825
826   // Generate Dali handles from resource bundle. Note that we generate all scene's resouce immediatly.
827   mModelLoadTask->mLoadResult.mResources.GenerateResources(mModelLoadTask->mResourceRefCount);
828
829   for(auto iRoot : mModelLoadTask->mLoadResult.mScene.GetRoots())
830   {
831     if(auto actor = mModelLoadTask->mLoadResult.mScene.CreateNodes(iRoot, mModelLoadTask->mResourceChoices, nodeParams))
832     {
833       mModelLoadTask->mLoadResult.mScene.ConfigureSkeletonJoints(iRoot, mModelLoadTask->mLoadResult.mResources.mSkeletons, actor);
834       mModelLoadTask->mLoadResult.mScene.ConfigureSkinningShaders(mModelLoadTask->mLoadResult.mResources, actor, std::move(nodeParams.mSkinnables));
835       ConfigureBlendShapeShaders(mModelLoadTask->mLoadResult.mResources, mModelLoadTask->mLoadResult.mScene, actor, std::move(nodeParams.mBlendshapeRequests));
836
837       mModelLoadTask->mLoadResult.mScene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
838
839       mModelRoot.Add(actor);
840     }
841
842     AddModelTreeToAABB(AABB, mModelLoadTask->mLoadResult.mScene, mModelLoadTask->mResourceChoices, iRoot, nodeParams, Matrix::IDENTITY);
843   }
844
845   mNaturalSize = AABB.CalculateSize();
846   mModelPivot  = AABB.CalculatePivot();
847   mModelRoot.SetProperty(Dali::Actor::Property::SIZE, mNaturalSize);
848   Vector3 controlSize = Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
849   if(Dali::EqualsZero(controlSize.x) || Dali::EqualsZero(controlSize.y))
850   {
851     Self().SetProperty(Dali::Actor::Property::SIZE, mNaturalSize);
852   }
853   FitModelPosition();
854   ScaleModel();
855 }
856
857 void Model::CreateAnimations(Dali::Scene3D::Loader::SceneDefinition& scene)
858 {
859   mAnimations.clear();
860   if(!mModelLoadTask->mLoadResult.mAnimationDefinitions.empty())
861   {
862     auto getActor = [&](const Scene3D::Loader::AnimatedProperty& property) {
863       if(property.mNodeIndex == Scene3D::Loader::INVALID_INDEX)
864       {
865         return mModelRoot.FindChildByName(property.mNodeName);
866       }
867       auto* node = scene.GetNode(property.mNodeIndex);
868       if(node == nullptr)
869       {
870         return Dali::Actor();
871       }
872       return mModelRoot.FindChildById(node->mNodeId);
873     };
874
875     for(auto&& animation : mModelLoadTask->mLoadResult.mAnimationDefinitions)
876     {
877       Dali::Animation anim = animation.ReAnimate(getActor);
878       mAnimations.push_back({animation.mName, anim});
879     }
880   }
881 }
882
883 void Model::ResetCameraParameters()
884 {
885   mCameraParameters.clear();
886   if(!mModelLoadTask->mLoadResult.mCameraParameters.empty())
887   {
888     // Copy camera parameters.
889     std::copy(mModelLoadTask->mLoadResult.mCameraParameters.begin(), mModelLoadTask->mLoadResult.mCameraParameters.end(), std::back_inserter(mCameraParameters));
890   }
891 }
892
893 } // namespace Internal
894 } // namespace Scene3D
895 } // namespace Dali