Merge "Make sure that global variables are initialized lazily in scene3d." into devel...
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / public-api / loader / scene-definition.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/public-api/loader/scene-definition.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/common/map-wrapper.h>
23 #include <dali/public-api/animation/constraints.h>
24
25 // INTERNAL
26 #include <dali-scene3d/internal/graphics/builtin-shader-extern-gen.h>
27 #include <dali-scene3d/public-api/loader/blend-shape-details.h>
28 #include <dali-scene3d/public-api/loader/skinning-details.h>
29 #include <dali-scene3d/public-api/loader/utils.h>
30
31 //#define DEBUG_SCENE_DEFINITION
32 //#define DEBUG_JOINTS
33
34 #if defined(DEBUG_SCENE_DEFINITION) || defined(DEBUG_JOINTS)
35 #define DEBUG_ONLY(x) x
36 #else
37 #define DEBUG_ONLY(x)
38 #endif
39
40 #define LOGD(x) DEBUG_ONLY(printf x; printf("\n"); fflush(stdout))
41
42 namespace Dali::Scene3D::Loader
43 {
44 namespace
45 {
46 const char* JOINT_MATRIX{"jointMatrix"};
47
48 const std::map<Property::Type, Constraint (*)(Actor&, Property::Index)>& GetConstraintFactory()
49 {
50   static const std::map<Property::Type, Constraint (*)(Actor&, Property::Index)> sConstraintFactory = {
51     {Property::Type::BOOLEAN,
52      [](Actor& a, Property::Index i) {
53        return Constraint::New<bool>(a, i, [](bool& current, const PropertyInputContainer& inputs) {
54          current = inputs[0]->GetBoolean();
55        });
56      }},
57     {Property::Type::INTEGER,
58      [](Actor& a, Property::Index i) {
59        return Constraint::New<int>(a, i, [](int& current, const PropertyInputContainer& inputs) {
60          current = inputs[0]->GetInteger();
61        });
62      }},
63     {Property::Type::FLOAT,
64      [](Actor& a, Property::Index i) {
65        return Constraint::New<float>(a, i, EqualToConstraint());
66      }},
67     {Property::Type::VECTOR2,
68      [](Actor& a, Property::Index i) {
69        return Constraint::New<Vector2>(a, i, EqualToConstraint());
70      }},
71     {Property::Type::VECTOR3,
72      [](Actor& a, Property::Index i) {
73        return Constraint::New<Vector3>(a, i, EqualToConstraint());
74      }},
75     {Property::Type::VECTOR4,
76      [](Actor& a, Property::Index i) {
77        return Constraint::New<Vector4>(a, i, EqualToConstraint());
78      }},
79     {Property::Type::MATRIX,
80      [](Actor& a, Property::Index i) {
81        return Constraint::New<Matrix>(a, i, EqualToConstraint());
82      }},
83     {Property::Type::MATRIX3,
84      [](Actor& a, Property::Index i) {
85        return Constraint::New<Matrix3>(a, i, EqualToConstraint());
86      }},
87     {Property::Type::ROTATION,
88      [](Actor& a, Property::Index i) {
89        return Constraint::New<Quaternion>(a, i, EqualToConstraint());
90      }},
91   };
92   return sConstraintFactory;
93 }
94
95 struct ResourceReflector : IResourceReflector
96 {
97   Index* iMesh   = nullptr;
98   Index* iShader = nullptr;
99
100   void Reflect(ResourceType::Value type, Index& id)
101   {
102     switch(type)
103     {
104       case ResourceType::Shader:
105         DALI_ASSERT_ALWAYS(!iShader && "Shader index already assigned!");
106         iShader = &id;
107         break;
108
109       case ResourceType::Mesh:
110         DALI_ASSERT_ALWAYS(!iMesh && "Mesh index already assigned!");
111         iMesh = &id;
112         break;
113
114       default: // Other resource types are not relevant to the problem at hand.
115         break;
116     }
117   }
118 };
119
120 #ifdef DEBUG_JOINTS
121
122 Shader sJointDebugShader;
123 int    sNumScenes = 0;
124
125 void EnsureJointDebugShaderCreated()
126 {
127   if(0 == sNumScenes)
128   {
129     sJointDebugShader = Shader::New(SHADER_SCENE3D_JOINT_DEBUG_VERT, SHADER_SCENE3D_JOINT_DEBUG_FRAG);
130   }
131   ++sNumScenes;
132 }
133
134 void AddJointDebugVisual(Actor aJoint)
135 {
136   Property::Map attribs;
137   attribs["aPosition"] = Property::Type::VECTOR3;
138   attribs["aColor"]    = Property::Type::FLOAT;
139
140   PropertyBuffer vbo = PropertyBuffer::New(attribs);
141
142   struct Vertex
143   {
144     Vector3 pos;
145     float   color;
146   } vertices[] = {
147     {Vector3::ZERO, .999f + .999f * 256.f + .999f * 256.f * 256.f},
148     {Vector3::XAXIS, .999f},
149     {Vector3::YAXIS, .999f * 256.f},
150     {Vector3::ZAXIS, .999f * 256.f * 256.f},
151   };
152
153   vbo.SetData(&vertices, std::extent<decltype(vertices)>::value);
154
155   uint16_t indices[] = {0, 1, 0, 2, 0, 3};
156
157   Geometry geo = Geometry::New();
158   geo.AddVertexBuffer(vbo);
159   geo.SetIndexBuffer(indices, std::extent<decltype(indices)>::value);
160   geo.SetType(Geometry::LINES);
161
162   Renderer r = Renderer::New(geo, sJointDebugShader);
163   aJoint.AddRenderer(r);
164
165   aJoint.SetVisible(true);
166 }
167 #endif //DEBUG_JOINTS
168
169 class ActorCreatorVisitor : public NodeDefinition::IVisitor
170 {
171 public:
172   ActorCreatorVisitor(NodeDefinition::CreateParams& params)
173   : mCreationContext(params)
174   {
175   }
176
177   void Start(NodeDefinition& n)
178   {
179     mCreationContext.mXforms.modelStack.Push(n.GetLocalSpace());
180
181     Actor a = n.CreateActor(mCreationContext);
182     if(!mActorStack.empty())
183     {
184       mActorStack.back().Add(a);
185     }
186     else
187     {
188       mRoot = a;
189     }
190     mActorStack.push_back(a);
191   }
192
193   void Finish(NodeDefinition& n)
194   {
195     mActorStack.pop_back();
196     mCreationContext.mXforms.modelStack.Pop();
197   }
198
199   Actor GetRoot() const
200   {
201     return mRoot;
202   }
203
204 private:
205   NodeDefinition::CreateParams& mCreationContext;
206   std::vector<Actor>            mActorStack;
207   Actor                         mRoot;
208 };
209
210 bool IsAncestor(const SceneDefinition& scene, Index ancestor, Index node, Index rootHint = INVALID_INDEX)
211 {
212   bool isAncestor = false;
213   while(node != rootHint && !isAncestor)
214   {
215     node       = scene.GetNode(node)->mParentIdx;
216     isAncestor = ancestor == node;
217   }
218   return isAncestor;
219 }
220
221 void InsertUniqueSorted(std::vector<Index>& data, Index value)
222 {
223   auto iInsert = std::lower_bound(data.begin(), data.end(), value);
224   if(iInsert == data.end() || *iInsert != value)
225   {
226     data.insert(iInsert, value);
227   }
228 }
229
230 void RemoveFromSorted(std::vector<Index>& data, Index value)
231 {
232   auto iRemove = std::lower_bound(data.begin(), data.end(), value);
233   if(iRemove != data.end() && *iRemove == value)
234   {
235     data.erase(iRemove);
236   }
237 }
238
239 Property::Index ConfigureJointMatrix(Actor actor, Actor ancestor, Property::Index propJointMatrix)
240 {
241   Actor parent = actor.GetParent();
242   if(parent != ancestor)
243   {
244     propJointMatrix = ConfigureJointMatrix(parent, ancestor, propJointMatrix);
245   }
246
247   auto myPropJointMatrix = actor.GetPropertyIndex(JOINT_MATRIX);
248   if(myPropJointMatrix == Property::INVALID_INDEX)
249   {
250     myPropJointMatrix     = actor.RegisterProperty(JOINT_MATRIX, Matrix{false});
251     Constraint constraint = Constraint::New<Matrix>(actor, propJointMatrix, [](Matrix& output, const PropertyInputContainer& inputs) {
252       Matrix jointMatrix{false};
253       jointMatrix.SetTransformComponents(Vector3::ONE, inputs[0]->GetQuaternion(), inputs[1]->GetVector3());
254
255       Matrix::Multiply(output, jointMatrix, inputs[2]->GetMatrix());
256     });
257     constraint.AddSource(Source{actor, Actor::Property::ORIENTATION});
258     constraint.AddSource(Source{actor, Actor::Property::POSITION});
259     constraint.AddSource(Source{parent, propJointMatrix});
260     constraint.Apply();
261   }
262
263   return myPropJointMatrix;
264 }
265
266 void SortAndDeduplicateSkinningRequests(std::vector<SkinningShaderConfigurationRequest>& requests)
267 {
268   // Sort requests by shaders.
269   std::sort(requests.begin(), requests.end());
270
271   // Remove duplicates.
272   auto   i           = requests.begin();
273   auto   iEnd        = requests.end();
274   Shader s           = i->mShader;
275   Index  skeletonIdx = i->mSkeletonIdx;
276   ++i;
277   do
278   {
279     // Multiple identical shader instances are removed.
280     while(i != iEnd && i->mShader == s)
281     {
282       // Cannot have multiple skeletons input to the same shader.
283       // NOTE: DliModel now makes sure this doesn't happen.
284       DALI_ASSERT_ALWAYS(i->mSkeletonIdx == skeletonIdx &&
285                          "Skinning shader must not be shared between different skeletons.");
286
287       i->mShader = Shader();
288       ++i;
289     }
290
291     if(i == iEnd)
292     {
293       break;
294     }
295     s           = i->mShader;
296     skeletonIdx = i->mSkeletonIdx;
297     ++i;
298   } while(true);
299
300   requests.erase(std::remove_if(requests.begin(), requests.end(), [](const SkinningShaderConfigurationRequest& sscr) {
301                    return !sscr.mShader;
302                  }),
303                  requests.end());
304 }
305
306 void ConfigureBoneMatrix(const Matrix& ibm, Actor joint, Shader& shader, Index& boneIdx)
307 {
308   // Register bone transform on shader.
309   char propertyNameBuffer[32];
310   snprintf(propertyNameBuffer, sizeof(propertyNameBuffer), "%s[%d]", Skinning::BONE_UNIFORM_NAME, boneIdx);
311   DALI_ASSERT_DEBUG(shader.GetPropertyIndex(propertyNameBuffer) == Property::INVALID_INDEX);
312   auto propBoneXform = shader.RegisterProperty(propertyNameBuffer, Matrix{false});
313
314   // Constrain bone matrix to joint transform.
315   Constraint constraint = Constraint::New<Matrix>(shader, propBoneXform, [ibm](Matrix& output, const PropertyInputContainer& inputs) {
316     Matrix::Multiply(output, ibm, inputs[0]->GetMatrix());
317   });
318
319   auto propJointMatrix = joint.GetPropertyIndex(JOINT_MATRIX);
320   constraint.AddSource(Source{joint, propJointMatrix});
321   constraint.Apply();
322
323   ++boneIdx;
324 }
325
326 template<class Visitor, class SceneDefinition>
327 void VisitInternal(Index iNode, const Customization::Choices& choices, Visitor& v, SceneDefinition& sd)
328 {
329   auto& node = *sd.GetNode(iNode);
330   v.Start(node);
331
332   if(node.mCustomization)
333   {
334     if(!node.mChildren.empty())
335     {
336       auto  choice = choices.Get(node.mCustomization->mTag);
337       Index i      = std::min(choice != Customization::NONE ? choice : 0, static_cast<Index>(node.mChildren.size() - 1));
338       sd.Visit(node.mChildren[i], choices, v);
339     }
340   }
341   else
342   {
343     for(auto i : node.mChildren)
344     {
345       sd.Visit(i, choices, v);
346     }
347   }
348
349   v.Finish(node);
350 }
351
352 } // namespace
353
354 SceneDefinition::SceneDefinition()
355 {
356   mNodes.reserve(128);
357
358 #ifdef DEBUG_JOINTS
359   EnsureJointDebugShaderCreated();
360 #endif
361 }
362
363 SceneDefinition::SceneDefinition(SceneDefinition&& other)
364 : mNodes(std::move(other.mNodes)),
365   mRootNodeIds(std::move(other.mRootNodeIds))
366 {
367 #ifdef DEBUG_JOINTS
368   EnsureJointDebugShaderCreated();
369 #endif
370 }
371
372 SceneDefinition::~SceneDefinition()
373 {
374 #ifdef DEBUG_JOINTS
375   --sNumScenes;
376   if(sNumScenes == 0)
377   {
378     sJointDebugShader = Shader();
379   }
380 #endif
381 }
382
383 uint32_t Dali::Scene3D::Loader::SceneDefinition::AddRootNode(Index iNode)
384 {
385   if(iNode < mNodes.size())
386   {
387     uint32_t result = mRootNodeIds.size();
388     mRootNodeIds.push_back(iNode);
389     return result;
390   }
391   else
392   {
393     ExceptionFlinger(ASSERT_LOCATION) << "Failed to add new root with node " << iNode << " -- index out of bounds.";
394     return -1;
395   }
396 }
397
398 const std::vector<Index>& SceneDefinition::GetRoots() const
399 {
400   return mRootNodeIds;
401 }
402
403 void SceneDefinition::RemoveRootNode(Index iRoot)
404 {
405   if(iRoot < mRootNodeIds.size())
406   {
407     mRootNodeIds.erase(mRootNodeIds.begin() + iRoot);
408   }
409   else
410   {
411     ExceptionFlinger(ASSERT_LOCATION) << "Failed to remove root " << iRoot << " -- index out of bounds.";
412   }
413 }
414
415 uint32_t SceneDefinition::GetNodeCount() const
416 {
417   return mNodes.size();
418 }
419
420 const NodeDefinition* SceneDefinition::GetNode(Index iNode) const
421 {
422   return mNodes[iNode].get();
423 }
424
425 NodeDefinition* SceneDefinition::GetNode(Index iNode)
426 {
427   if(iNode != Scene3D::Loader::INVALID_INDEX && iNode < mNodes.size())
428   {
429     return mNodes[iNode].get();
430   }
431   return nullptr;
432 }
433
434 void SceneDefinition::Visit(Index iNode, const Customization::Choices& choices, NodeDefinition::IVisitor& v)
435 {
436   VisitInternal(iNode, choices, v, *this);
437 }
438
439 void SceneDefinition::Visit(Index iNode, const Customization::Choices& choices, NodeDefinition::IConstVisitor& v) const
440 {
441   VisitInternal(iNode, choices, v, *this);
442 }
443
444 void SceneDefinition::CountResourceRefs(Index iNode, const Customization::Choices& choices, ResourceRefCounts& refCounts) const
445 {
446   struct RefCounter : IResourceReceiver
447   {
448     ResourceRefCounts* refCounts;
449
450     void Register(ResourceType::Value type, Index id)
451     {
452       ++(*refCounts)[type][id];
453     }
454   };
455
456   struct : NodeDefinition::IConstVisitor
457   {
458     RefCounter counter;
459
460     void Start(const NodeDefinition& n)
461     {
462       for(auto& renderable : n.mRenderables)
463       {
464         renderable->RegisterResources(counter);
465       }
466     }
467
468     void Finish(const NodeDefinition& n)
469     {
470     }
471
472   } refCounterVisitor;
473   refCounterVisitor.counter.refCounts = &refCounts;
474
475   Visit(iNode, choices, refCounterVisitor);
476 }
477
478 Actor SceneDefinition::CreateNodes(Index iNode, const Customization::Choices& choices, NodeDefinition::CreateParams& params)
479 {
480   ActorCreatorVisitor actorCreatorVisitor(params);
481
482   Visit(iNode, choices, actorCreatorVisitor);
483
484   return actorCreatorVisitor.GetRoot();
485 }
486
487 void SceneDefinition::GetCustomizationOptions(const Customization::Choices& choices,
488                                               Customization::Map&           outCustomizationOptions,
489                                               Customization::Choices*       outMissingChoices) const
490 {
491   struct : NodeDefinition::IConstVisitor
492   {
493     const Customization::Choices* choices;        // choices that we know about.
494     Customization::Map*           options;        // tags are registered here. NO OWNERSHIP.
495     Customization::Choices*       missingChoices; // tags will be registered with the default 0. NO OWNERSHIP.
496
497     void Start(const NodeDefinition& n)
498     {
499       if(n.mCustomization)
500       {
501         const std::string& tag = n.mCustomization->mTag;
502         if(missingChoices != nullptr && choices->Get(tag) == Customization::NONE)
503         {
504           missingChoices->Set(tag, 0);
505         }
506
507         auto customization = options->Get(tag);
508         if(!customization)
509         {
510           customization = options->Set(tag, {});
511         }
512         customization->nodes.push_back(n.mName);
513         customization->numOptions = std::max(customization->numOptions,
514                                              static_cast<uint32_t>(n.mChildren.size()));
515       }
516     }
517
518     void Finish(const NodeDefinition& n)
519     {
520     }
521
522   } customizationRegistrationVisitor;
523   customizationRegistrationVisitor.choices        = &choices;
524   customizationRegistrationVisitor.options        = &outCustomizationOptions;
525   customizationRegistrationVisitor.missingChoices = outMissingChoices;
526
527   for(auto i : mRootNodeIds)
528   {
529     Visit(i, choices, customizationRegistrationVisitor);
530   }
531 }
532
533 NodeDefinition* SceneDefinition::AddNode(std::unique_ptr<NodeDefinition>&& nodeDef)
534 {
535   // add next index (to which we're about to push) as a child to the designated parent, if any.
536   if(nodeDef->mParentIdx != INVALID_INDEX)
537   {
538     mNodes[nodeDef->mParentIdx]->mChildren.push_back(mNodes.size());
539   }
540
541   mNodes.push_back(std::move(nodeDef));
542
543   return mNodes.back().get();
544 }
545
546 bool SceneDefinition::ReparentNode(const std::string& name, const std::string& newParentName, Index siblingOrder)
547 {
548   LOGD(("reparenting %s to %s @ %d", name.c_str(), newParentName.c_str(), siblingOrder));
549
550   std::unique_ptr<NodeDefinition>* nodePtr      = nullptr;
551   std::unique_ptr<NodeDefinition>* newParentPtr = nullptr;
552   if(!FindNode(name, &nodePtr) || !FindNode(newParentName, &newParentPtr))
553   {
554     return false;
555   }
556
557   auto& node  = *nodePtr;
558   auto  iNode = std::distance(mNodes.data(), nodePtr);
559
560   DEBUG_ONLY(auto dumpNode = [](NodeDefinition const& n) {
561     std::ostringstream stream;
562     stream << n.mName << " (" << n.mParentIdx << "):";
563     for(auto i : n.mChildren)
564     {
565       stream << i << ", ";
566     }
567     LOGD(("%s", stream.str().c_str()));
568   };)
569
570   // Remove node from children of previous parent (if any).
571   if(node->mParentIdx != INVALID_INDEX)
572   {
573     LOGD(("old parent:"));
574     DEBUG_ONLY(dumpNode(*mNodes[node->mParentIdx]);)
575
576     auto& children = mNodes[node->mParentIdx]->mChildren;
577     children.erase(std::remove(children.begin(), children.end(), iNode), children.end());
578
579     DEBUG_ONLY(dumpNode(*mNodes[node->mParentIdx]);)
580   }
581
582   // Register node to new parent.
583   LOGD(("new parent:"));
584   DEBUG_ONLY(dumpNode(**newParentPtr);)
585   auto& children = (*newParentPtr)->mChildren;
586   if(siblingOrder > children.size())
587   {
588     siblingOrder = children.size();
589   }
590   children.insert(children.begin() + siblingOrder, 1, iNode);
591   DEBUG_ONLY(dumpNode(**newParentPtr);)
592
593   // Update parent index.
594   LOGD(("node:"));
595   DEBUG_ONLY(dumpNode(*node);)
596   auto iParent     = std::distance(mNodes.data(), newParentPtr);
597   node->mParentIdx = iParent;
598   DEBUG_ONLY(dumpNode(*node);)
599   return true;
600 }
601
602 bool SceneDefinition::RemoveNode(const std::string& name)
603 {
604   std::unique_ptr<NodeDefinition>* node = nullptr;
605   if(!FindNode(name, &node))
606   {
607     return false;
608   }
609
610   // Reset node def pointers recursively.
611   auto&                                                 thisNodes = mNodes;
612   unsigned int                                          numReset  = 0;
613   std::function<void(std::unique_ptr<NodeDefinition>&)> resetFn =
614     [&thisNodes, &resetFn, &numReset](std::unique_ptr<NodeDefinition>& nd) {
615       LOGD(("resetting %d", &nd - thisNodes.data()));
616       for(auto i : nd->mChildren)
617       {
618         resetFn(thisNodes[i]);
619       }
620       nd.reset();
621       ++numReset;
622     };
623
624   resetFn(*node);
625
626   // Gather indices of dead nodes into a vector which we sort on insertion.
627   std::vector<Index> offsets;
628   offsets.reserve(numReset);
629   for(auto& n : mNodes)
630   {
631     if(!n)
632     {
633       offsets.push_back(std::distance(mNodes.data(), &n));
634     }
635   }
636
637   // Erase dead nodes as they don't have to be processed anymore.
638   mNodes.erase(std::remove(mNodes.begin(), mNodes.end(), decltype(mNodes)::value_type()), mNodes.end());
639
640   // Offset all indices (parent and child) by the index they'd sort into in offsets.
641   enum
642   {
643     INDEX_FOR_REMOVAL = INVALID_INDEX
644   };
645   auto offsetter = [&offsets](Index& i) {
646     auto iFind = std::lower_bound(offsets.begin(), offsets.end(), i);
647     if(iFind != offsets.end() && *iFind == i)
648     {
649       LOGD(("marking %d for removal.", i));
650       i = INDEX_FOR_REMOVAL;
651       return false;
652     }
653     else
654     {
655       auto distance = std::distance(offsets.begin(), iFind);
656       if(distance > 0)
657       {
658         LOGD(("offsetting %d by %d.", i, distance));
659         i -= distance;
660       }
661       return true;
662     }
663   };
664
665   for(auto& nd : mNodes)
666   {
667     bool parentOffsetResult = offsetter(nd->mParentIdx);
668     DALI_ASSERT_ALWAYS(parentOffsetResult); // since nodes were recursively removed, we should not be finding invalid parents at this point.
669
670     auto& children = nd->mChildren;
671     for(auto i0 = children.begin(), i1 = children.end(); i0 != i1; ++i0)
672     {
673       offsetter(*i0);
674     }
675
676     children.erase(std::remove(children.begin(), children.end(), INDEX_FOR_REMOVAL), children.end());
677   }
678
679   return true;
680 }
681
682 void SceneDefinition::GetNodeModelStack(Index index, MatrixStack& model) const
683 {
684   auto&                    thisNodes  = mNodes;
685   std::function<void(int)> buildStack = [&model, &thisNodes, &buildStack](int i) {
686     auto node = thisNodes[i].get();
687     if(node->mParentIdx != INVALID_INDEX)
688     {
689       buildStack(node->mParentIdx);
690     }
691     model.Push(node->GetLocalSpace());
692   };
693   buildStack(index);
694 }
695
696 NodeDefinition* SceneDefinition::FindNode(const std::string& name, Index* outIndex)
697 {
698   auto iBegin = mNodes.begin();
699   auto iEnd   = mNodes.end();
700   auto iFind  = std::find_if(iBegin, iEnd, [&name](const std::unique_ptr<NodeDefinition>& nd) {
701     return nd->mName == name;
702   });
703
704   auto result = iFind != iEnd ? iFind->get() : nullptr;
705   if(result && outIndex)
706   {
707     *outIndex = std::distance(iBegin, iFind);
708   }
709   return result;
710 }
711
712 const NodeDefinition* SceneDefinition::FindNode(const std::string& name, Index* outIndex) const
713 {
714   auto iBegin = mNodes.begin();
715   auto iEnd   = mNodes.end();
716   auto iFind  = std::find_if(iBegin, iEnd, [&name](const std::unique_ptr<NodeDefinition>& nd) {
717     return nd->mName == name;
718   });
719
720   auto result = iFind != iEnd ? iFind->get() : nullptr;
721   if(result && outIndex)
722   {
723     *outIndex = std::distance(iBegin, iFind);
724   }
725   return result;
726 }
727
728 Index SceneDefinition::FindNodeIndex(const NodeDefinition& node) const
729 {
730   auto iBegin = mNodes.begin();
731   auto iEnd   = mNodes.end();
732   auto iFind  = std::find_if(iBegin, iEnd, [&node](const std::unique_ptr<NodeDefinition>& n) {
733     return n.get() == &node;
734   });
735   return iFind != iEnd ? std::distance(iBegin, iFind) : INVALID_INDEX;
736 }
737
738 void SceneDefinition::FindNodes(NodePredicate predicate, NodeConsumer consumer, unsigned int limit)
739 {
740   unsigned int n = 0;
741   for(auto& defp : mNodes)
742   {
743     if(predicate(*defp))
744     {
745       consumer(*defp);
746       ++n;
747       if(n == limit)
748       {
749         break;
750       }
751     }
752   }
753 }
754
755 void SceneDefinition::FindNodes(NodePredicate predicate, ConstNodeConsumer consumer, unsigned int limit) const
756 {
757   unsigned int n = 0;
758   for(auto& defp : mNodes)
759   {
760     if(predicate(*defp))
761     {
762       consumer(*defp);
763       ++n;
764       if(n == limit)
765       {
766         break;
767       }
768     }
769   }
770 }
771
772 void SceneDefinition::ApplyConstraints(Actor&                           root,
773                                        std::vector<ConstraintRequest>&& constrainables,
774                                        StringCallback                   onError) const
775 {
776   for(auto& cr : constrainables)
777   {
778     auto&           nodeDef    = mNodes[cr.mConstraint->mSourceIdx];
779     auto            sourceName = nodeDef->mName.c_str();
780     Property::Index iTarget    = cr.mTarget.GetPropertyIndex(cr.mConstraint->mProperty);
781     if(iTarget != Property::INVALID_INDEX)
782     {
783       auto propertyType = cr.mTarget.GetPropertyType(iTarget);
784       auto iFind        = GetConstraintFactory().find(propertyType);
785       if(iFind == GetConstraintFactory().end())
786       {
787         onError(FormatString("node '%s': Property '%s' has unsupported type '%s'; ignored.",
788                              sourceName,
789                              cr.mConstraint->mProperty.c_str(),
790                              PropertyTypes::GetName(propertyType)));
791         continue;
792       }
793
794       Constraint constraint = iFind->second(cr.mTarget, iTarget);
795
796       Actor source = root.FindChildByName(nodeDef->mName);
797       if(!source)
798       {
799         auto targetName = cr.mTarget.GetProperty(Actor::Property::NAME).Get<std::string>();
800         onError(FormatString("node '%s': Failed to locate constraint source %s@%s; ignored.",
801                              sourceName,
802                              cr.mConstraint->mProperty.c_str(),
803                              targetName.c_str()));
804         continue;
805       }
806       else if(source == cr.mTarget)
807       {
808         onError(FormatString("node '%s': Cyclic constraint definition for property '%s'; ignored.",
809                              sourceName,
810                              cr.mConstraint->mProperty.c_str()));
811         continue;
812       }
813
814       Property::Index iSource = source.GetPropertyIndex(cr.mConstraint->mProperty);
815       constraint.AddSource(Source{source, iSource});
816       constraint.Apply();
817     }
818     else
819     {
820       auto targetName = cr.mTarget.GetProperty(Actor::Property::NAME).Get<std::string>();
821       onError(FormatString("node '%s': Failed to create constraint for property %s@%s; ignored.",
822                            sourceName,
823                            cr.mConstraint->mProperty.c_str(),
824                            targetName.c_str()));
825     }
826   }
827 }
828
829 void SceneDefinition::ConfigureSkeletonJoints(uint32_t iRoot, const SkeletonDefinition::Vector& skeletons, Actor root) const
830 {
831   // 1, For each skeleton, for each joint, walk upwards until we reach mNodes[iRoot]. If we do, record +1
832   // to the refcount of each node we have visited, in our temporary registry. Those with refcount 1
833   // are the leaves, while the most descendant node with the highest refcount is the root of the skeleton.
834   std::map<Index, std::vector<Index>> rootsJoints;
835   std::vector<Index>                  path;
836   path.reserve(16);
837   for(auto& s : skeletons)
838   {
839     std::map<uint32_t, uint32_t> jointRefs;
840     for(auto& j : s.mJoints)
841     {
842       auto nodeIdx = j.mNodeIdx;
843       do // Traverse upwards and record each node we have visited until we reach the scene root.
844       {
845         path.push_back(nodeIdx);
846         if(nodeIdx == iRoot)
847         {
848           break;
849         }
850         auto node = GetNode(nodeIdx);
851         nodeIdx   = node->mParentIdx;
852       } while(nodeIdx != INVALID_INDEX);
853
854       if(nodeIdx == iRoot) // If the joint is in the correct scene, increment the reference count for all visited nodes.
855       {
856         for(auto i : path)
857         {
858           ++jointRefs[i];
859         }
860       }
861
862       path.clear();
863     }
864
865     // Only record the skeleton if we have encountered the root of the current scene.
866     if(jointRefs.empty())
867     {
868       continue;
869     }
870
871     Index    root   = s.mRootNodeIdx;
872     uint32_t maxRef = 0;
873     auto     iFind  = jointRefs.find(root);
874     if(iFind != jointRefs.end())
875     {
876       maxRef = iFind->second;
877     }
878
879     std::vector<Index> joints;
880     for(auto& j : jointRefs) // NOTE: jointRefs are sorted, so joints will also be.
881     {
882       // The most descendant node with the highest ref count is the root of the skeleton.
883       if(j.second > maxRef || (j.second == maxRef && IsAncestor(*this, root, j.first, iRoot)))
884       {
885         maxRef = j.second;
886
887         RemoveFromSorted(joints, root);
888         root = j.first;
889       }
890       else if(j.second == 1) // This one's a leaf.
891       {
892         InsertUniqueSorted(joints, j.first);
893       }
894     }
895
896     // Merge skeletons that share the same root.
897     auto& finalJoints = rootsJoints[root];
898     for(auto j : joints)
899     {
900       if(std::find_if(finalJoints.begin(), finalJoints.end(), [this, j, root](Index jj) {
901            return IsAncestor(*this, j, jj, root);
902          }) != finalJoints.end())
903       {
904         continue; // if the joint is found to be an ancestor of another joint already registered, move on.
905       }
906
907       auto i = j;
908       while(i != root) // See if the current joint is a better leaf, i.e. descended from another leaf - which we'll then remove.
909       {
910         auto node = GetNode(i);
911         i         = node->mParentIdx;
912
913         RemoveFromSorted(finalJoints, i);
914       }
915
916       InsertUniqueSorted(finalJoints, j);
917     }
918   }
919
920   // 2, Merge records where one root joint is descendant of another. Handle leaf node changes - remove previous
921   // leaf nodes that now have descendants, and add new ones.
922   auto iRoots    = rootsJoints.begin();
923   auto iRootsEnd = rootsJoints.end();
924   while(iRoots != iRootsEnd)
925   {
926     auto i      = iRoots->first;
927     bool merged = false;
928     while(i != iRoot) // Starting with the root joint of the skeleton, traverse upwards.
929     {
930       auto node = GetNode(i);
931       i         = node->mParentIdx;
932
933       auto iFind = rootsJoints.find(i);
934       if(iFind != rootsJoints.end()) // Check if we've reached the root of another skeleton.
935       {
936         // Now find out which leaf of iFind is an ancestor, if any.
937         auto iFindLeaf = std::find_if(iFind->second.begin(), iFind->second.end(), [this, iRoots, iFind](Index j) {
938           return IsAncestor(*this, j, iRoots->first, iFind->first);
939         });
940         if(iFindLeaf != iFind->second.end())
941         {
942           iFind->second.erase(iFindLeaf); // Will no longer be a leaf -- remove it.
943         }
944
945         // Merge iRoots with iFind
946         auto& targetJoints = iFind->second;
947         if(iRoots->second.empty()) // The root is a leaf.
948         {
949           InsertUniqueSorted(targetJoints, iRoots->first);
950         }
951         else
952           for(auto j : iRoots->second)
953           {
954             InsertUniqueSorted(targetJoints, j);
955           }
956
957         merged = true;
958         break; // Traverse no more
959       }
960     }
961
962     iRoots = merged ? rootsJoints.erase(iRoots) : std::next(iRoots);
963   }
964
965   // 3, For each root, register joint matrices and constraints
966   for(const auto& r : rootsJoints)
967   {
968     auto node      = GetNode(r.first);
969     auto rootJoint = root.FindChildByName(node->mName);
970     DALI_ASSERT_ALWAYS(!!rootJoint);
971
972     DALI_ASSERT_DEBUG(rootJoint.GetPropertyIndex(JOINT_MATRIX) == Property::INVALID_INDEX);
973     auto       propJointMatrix = rootJoint.RegisterProperty(JOINT_MATRIX, Matrix{false});
974     Constraint constraint      = Constraint::New<Matrix>(rootJoint, propJointMatrix, [](Matrix& output, const PropertyInputContainer& inputs) {
975       output.SetTransformComponents(Vector3::ONE, inputs[0]->GetQuaternion(), inputs[1]->GetVector3());
976     });
977     constraint.AddSource(Source(rootJoint, Actor::Property::ORIENTATION));
978     constraint.AddSource(Source(rootJoint, Actor::Property::POSITION));
979     constraint.Apply();
980
981     for(const auto j : r.second)
982     {
983       node       = GetNode(j);
984       auto joint = rootJoint.FindChildByName(node->mName);
985       ConfigureJointMatrix(joint, rootJoint, propJointMatrix);
986     }
987   }
988 }
989
990 void SceneDefinition::EnsureUniqueSkinningShaderInstances(ResourceBundle& resources) const
991 {
992   std::map<Index, std::map<Index, std::vector<Index*>>> skinningShaderUsers;
993   for(auto& node : mNodes)
994   {
995     for(auto& renderable : node->mRenderables)
996     {
997       ResourceReflector reflector;
998       renderable->ReflectResources(reflector);
999
1000       if(reflector.iMesh)
1001       {
1002         const auto& mesh = resources.mMeshes[*reflector.iMesh].first;
1003         if(mesh.IsSkinned())
1004         {
1005           skinningShaderUsers[*reflector.iShader][mesh.mSkeletonIdx].push_back(reflector.iShader);
1006         }
1007       }
1008     }
1009   }
1010
1011   // For each shader, and each skeleton using the same shader as the first skeleton,
1012   // update the shader references (from nodes with skinned meshes) with a new copy of
1013   // the shader definition from the node using the first skeleton.
1014   for(auto& users : skinningShaderUsers)
1015   {
1016     auto& skeletons    = users.second;
1017     auto  iterSkeleton = skeletons.begin();
1018     // skipping the first skeleton.
1019     ++iterSkeleton;
1020
1021     resources.mShaders.reserve(resources.mShaders.size() + std::distance(iterSkeleton, skeletons.end()));
1022     const ShaderDefinition& shaderDef = resources.mShaders[users.first].first;
1023
1024     while(iterSkeleton != skeletons.end())
1025     {
1026       Index iShader = resources.mShaders.size();
1027       resources.mShaders.push_back({shaderDef, Shader()});
1028
1029       for(auto& i : iterSkeleton->second)
1030       {
1031         *i = iShader;
1032       }
1033       ++iterSkeleton;
1034     }
1035   }
1036 }
1037
1038 void SceneDefinition::ConfigureSkinningShaders(const ResourceBundle&                             resources,
1039                                                Actor                                             rootActor,
1040                                                std::vector<SkinningShaderConfigurationRequest>&& requests) const
1041 {
1042   if(requests.empty())
1043   {
1044     return;
1045   }
1046
1047   SortAndDeduplicateSkinningRequests(requests);
1048
1049   for(auto& request : requests)
1050   {
1051     auto& skeleton = resources.mSkeletons[request.mSkeletonIdx];
1052     if(skeleton.mJoints.empty())
1053     {
1054       LOGD(("Skeleton %d has no joints.", request.mSkeletonIdx));
1055       continue;
1056     }
1057
1058     Index boneIdx = 0;
1059     for(auto& joint : skeleton.mJoints)
1060     {
1061       auto  node  = GetNode(joint.mNodeIdx);
1062       Actor actor = rootActor.FindChildByName(node->mName);
1063       ConfigureBoneMatrix(joint.mInverseBindMatrix, actor, request.mShader, boneIdx);
1064     }
1065   }
1066 }
1067
1068 bool SceneDefinition::ConfigureBlendshapeShaders(const ResourceBundle&                               resources,
1069                                                  Actor                                               rootActor,
1070                                                  std::vector<BlendshapeShaderConfigurationRequest>&& requests,
1071                                                  StringCallback                                      onError) const
1072 {
1073   if(requests.empty())
1074   {
1075     return true;
1076   }
1077
1078   // Sort requests by shaders.
1079   std::sort(requests.begin(), requests.end());
1080
1081   // Remove duplicates.
1082   auto   i    = requests.begin();
1083   auto   iEnd = requests.end();
1084   Shader s    = i->mShader;
1085   ++i;
1086   do
1087   {
1088     // Multiple identical shader instances are removed.
1089     while(i != iEnd && i->mShader == s)
1090     {
1091       i->mShader = Shader();
1092       ++i;
1093     }
1094
1095     if(i == iEnd)
1096     {
1097       break;
1098     }
1099     s = i->mShader;
1100     ++i;
1101   } while(true);
1102
1103   // Configure the rest.
1104   bool ok = true;
1105
1106   for(auto& i : requests)
1107   {
1108     Index iNode;
1109     if(FindNode(i.mNodeName, &iNode))
1110     {
1111       const auto& node = GetNode(iNode);
1112
1113       const auto& mesh = resources.mMeshes[i.mMeshIdx];
1114
1115       if(mesh.first.HasBlendShapes())
1116       {
1117         Actor actor = rootActor.FindChildByName(node->mName);
1118
1119         // Sets the property to be animated.
1120         BlendShapes::ConfigureProperties(mesh, i.mShader, actor);
1121       }
1122     }
1123   }
1124
1125   return ok;
1126 }
1127
1128 void SceneDefinition::EnsureUniqueBlendShapeShaderInstances(ResourceBundle& resources) const
1129 {
1130   std::map<Index, std::map<std::string, std::vector<Index*>>> blendShapeShaderUsers;
1131   for(auto& node : mNodes)
1132   {
1133     for(auto& renderable : node->mRenderables)
1134     {
1135       ResourceReflector reflector;
1136       renderable->ReflectResources(reflector);
1137
1138       if(reflector.iMesh)
1139       {
1140         const auto& mesh = resources.mMeshes[*reflector.iMesh].first;
1141         if(mesh.HasBlendShapes())
1142         {
1143           blendShapeShaderUsers[*reflector.iShader][node->mName].push_back(reflector.iShader);
1144         }
1145       }
1146     }
1147   }
1148
1149   for(auto& users : blendShapeShaderUsers)
1150   {
1151     resources.mShaders.reserve(resources.mShaders.size() + users.second.size() - 1u);
1152     const ShaderDefinition& shaderDef = resources.mShaders[users.first].first;
1153
1154     auto nodesIt    = users.second.begin();
1155     auto nodesEndIt = users.second.end();
1156     // skipping the first node.
1157     ++nodesIt;
1158     while(nodesIt != nodesEndIt)
1159     {
1160       Index iShader = resources.mShaders.size();
1161       resources.mShaders.push_back({shaderDef, Shader()});
1162
1163       auto& nodes = *nodesIt;
1164       for(auto& shader : nodes.second)
1165       {
1166         *shader = iShader;
1167       }
1168       ++nodesIt;
1169     }
1170   }
1171 }
1172
1173 SceneDefinition& SceneDefinition::operator=(SceneDefinition&& other)
1174 {
1175   SceneDefinition temp(std::move(other));
1176   std::swap(mNodes, temp.mNodes);
1177   std::swap(mRootNodeIds, temp.mRootNodeIds);
1178   return *this;
1179 }
1180
1181 bool SceneDefinition::FindNode(const std::string& name, std::unique_ptr<NodeDefinition>** result)
1182 {
1183   // We're searching from the end assuming a higher probability of operations targeting
1184   // recently added nodes. (conf.: root, which is immovable, cannot be removed, and was
1185   // the first to be added, is index 0.)
1186   auto iFind = std::find_if(mNodes.rbegin(), mNodes.rend(), [&name](const std::unique_ptr<NodeDefinition>& nd) {
1187                  return nd->mName == name;
1188                }).base();
1189
1190   const bool success = iFind != mNodes.begin();
1191   if(success && result)
1192   {
1193     --iFind;
1194     *result = &*iFind;
1195   }
1196
1197   return success;
1198 }
1199
1200 } // namespace Dali::Scene3D::Loader