[dali_2.3.21] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / public-api / loader / scene-definition.cpp
1 /*
2  * Copyright (c) 2024 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-scene3d/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/internal/model-components/model-node-impl.h>
28 #include <dali-scene3d/public-api/loader/blend-shape-details.h>
29 #include <dali-scene3d/public-api/loader/skinning-details.h>
30 #include <dali-scene3d/public-api/loader/utils.h>
31
32 // #define DEBUG_SCENE_DEFINITION
33 // #define DEBUG_JOINTS
34
35 #if defined(DEBUG_SCENE_DEFINITION) || defined(DEBUG_JOINTS)
36 #define DEBUG_ONLY(x) x
37 #else
38 #define DEBUG_ONLY(x)
39 #endif
40
41 #define LOGD(x) DEBUG_ONLY(printf x; printf("\n"); fflush(stdout))
42
43 namespace Dali::Scene3D::Loader
44 {
45 namespace
46 {
47 const std::map<Property::Type, Constraint (*)(Actor&, Property::Index)>& GetConstraintFactory()
48 {
49   static const std::map<Property::Type, Constraint (*)(Actor&, Property::Index)> sConstraintFactory = {
50     {Property::Type::BOOLEAN,
51      [](Actor& a, Property::Index i) {
52        return Constraint::New<bool>(a, i, [](bool& current, const PropertyInputContainer& inputs) { current = inputs[0]->GetBoolean(); });
53      }},
54     {Property::Type::INTEGER,
55      [](Actor& a, Property::Index i) {
56        return Constraint::New<int>(a, i, [](int& current, const PropertyInputContainer& inputs) { current = inputs[0]->GetInteger(); });
57      }},
58     {Property::Type::FLOAT,
59      [](Actor& a, Property::Index i) {
60        return Constraint::New<float>(a, i, EqualToConstraint());
61      }},
62     {Property::Type::VECTOR2,
63      [](Actor& a, Property::Index i) {
64        return Constraint::New<Vector2>(a, i, EqualToConstraint());
65      }},
66     {Property::Type::VECTOR3,
67      [](Actor& a, Property::Index i) {
68        return Constraint::New<Vector3>(a, i, EqualToConstraint());
69      }},
70     {Property::Type::VECTOR4,
71      [](Actor& a, Property::Index i) {
72        return Constraint::New<Vector4>(a, i, EqualToConstraint());
73      }},
74     {Property::Type::MATRIX,
75      [](Actor& a, Property::Index i) {
76        return Constraint::New<Matrix>(a, i, EqualToConstraint());
77      }},
78     {Property::Type::MATRIX3,
79      [](Actor& a, Property::Index i) {
80        return Constraint::New<Matrix3>(a, i, EqualToConstraint());
81      }},
82     {Property::Type::ROTATION,
83      [](Actor& a, Property::Index i) {
84        return Constraint::New<Quaternion>(a, i, EqualToConstraint());
85      }},
86   };
87   return sConstraintFactory;
88 }
89
90 struct ResourceReflector : IResourceReflector
91 {
92   Index* iMesh   = nullptr;
93   Index* iShader = nullptr;
94
95   void Reflect(ResourceType::Value type, Index& id)
96   {
97     switch(type)
98     {
99       case ResourceType::Shader:
100         DALI_ASSERT_ALWAYS(!iShader && "Shader index already assigned!");
101         iShader = &id;
102         break;
103
104       case ResourceType::Mesh:
105         DALI_ASSERT_ALWAYS(!iMesh && "Mesh index already assigned!");
106         iMesh = &id;
107         break;
108
109       default: // Other resource types are not relevant to the problem at hand.
110         break;
111     }
112   }
113 };
114
115 #ifdef DEBUG_JOINTS
116
117 Shader sJointDebugShader;
118 int    sNumScenes = 0;
119
120 void EnsureJointDebugShaderCreated()
121 {
122   if(0 == sNumScenes)
123   {
124     sJointDebugShader = Shader::New(SHADER_SCENE3D_JOINT_DEBUG_VERT, SHADER_SCENE3D_JOINT_DEBUG_FRAG, Shader::Hint::NONE, "SCENE3D_JOINT_DEBUG");
125   }
126   ++sNumScenes;
127 }
128
129 void AddJointDebugVisual(Actor aJoint)
130 {
131   Property::Map attribs;
132   attribs["aPosition"] = Property::Type::VECTOR3;
133   attribs["aColor"]    = Property::Type::FLOAT;
134
135   PropertyBuffer vbo = PropertyBuffer::New(attribs);
136
137   struct Vertex
138   {
139     Vector3 pos;
140     float   color;
141   } vertices[] = {
142     {Vector3::ZERO, .999f + .999f * 256.f + .999f * 256.f * 256.f},
143     {Vector3::XAXIS, .999f},
144     {Vector3::YAXIS, .999f * 256.f},
145     {Vector3::ZAXIS, .999f * 256.f * 256.f},
146   };
147
148   vbo.SetData(&vertices, std::extent<decltype(vertices)>::value);
149
150   uint16_t indices[] = {0, 1, 0, 2, 0, 3};
151
152   Geometry geo = Geometry::New();
153   geo.AddVertexBuffer(vbo);
154   geo.SetIndexBuffer(indices, std::extent<decltype(indices)>::value);
155   geo.SetType(Geometry::LINES);
156
157   Renderer r = Renderer::New(geo, sJointDebugShader);
158   aJoint.AddRenderer(r);
159
160   aJoint.SetVisible(true);
161 }
162 #endif // DEBUG_JOINTS
163
164 class ActorCreatorVisitor : public NodeDefinition::IVisitor
165 {
166 public:
167   ActorCreatorVisitor(NodeDefinition::CreateParams& params)
168   : mCreationContext(params)
169   {
170   }
171
172   void Start(NodeDefinition& n)
173   {
174     mCreationContext.mXforms.modelStack.Push(n.GetLocalSpace());
175
176     ModelNode a = n.CreateModelNode(mCreationContext);
177     if(!mActorStack.empty())
178     {
179       mActorStack.back().Add(a);
180     }
181     else
182     {
183       mRoot = a;
184     }
185     mActorStack.push_back(a);
186   }
187
188   void Finish(NodeDefinition& n)
189   {
190     mActorStack.pop_back();
191     mCreationContext.mXforms.modelStack.Pop();
192   }
193
194   ModelNode GetRoot() const
195   {
196     return mRoot;
197   }
198
199 private:
200   NodeDefinition::CreateParams& mCreationContext;
201   std::vector<ModelNode>        mActorStack;
202   ModelNode                     mRoot;
203 };
204
205 template<typename RequestType>
206 void SortAndDeduplicateRequests(std::vector<RequestType>& requests)
207 {
208   // Sort requests by shaders and primitives.
209   std::sort(requests.begin(), requests.end());
210
211   // Remove duplicates.
212   auto iter    = requests.begin();
213   auto iterEnd = requests.end();
214
215   Shader         shader         = iter->mShader;
216   ModelPrimitive modelPrimitive = iter->mPrimitive;
217   ++iter;
218   do
219   {
220     // Multiple identical shader and primitive instances are removed.
221     while(iter != iterEnd && iter->mShader == shader && iter->mPrimitive == modelPrimitive)
222     {
223       // Mark as removed
224       iter->mShader = Shader();
225       ++iter;
226     }
227
228     if(iter == iterEnd)
229     {
230       break;
231     }
232     shader         = iter->mShader;
233     modelPrimitive = iter->mPrimitive;
234     ++iter;
235   } while(true);
236
237   requests.erase(std::remove_if(requests.begin(), requests.end(), [](const RequestType& sscr) { return !sscr.mShader; }),
238                  requests.end());
239 }
240
241 void ConfigureBoneMatrix(const Matrix& ibm, ModelNode joint, ModelPrimitive primitive, Index& boneIdx)
242 {
243   // Register bone transform on shader.
244   Internal::GetImplementation(joint).SetBoneMatrix(ibm, primitive, boneIdx);
245   ++boneIdx;
246 }
247
248 template<class Visitor, class SceneDefinition>
249 void VisitInternal(Index iNode, const Customization::Choices& choices, Visitor& v, SceneDefinition& sd)
250 {
251   auto& node = *sd.GetNode(iNode);
252   v.Start(node);
253
254   if(node.mCustomization)
255   {
256     if(!node.mChildren.empty())
257     {
258       auto  choice = choices.Get(node.mCustomization->mTag);
259       Index i      = std::min(choice != Customization::NONE ? choice : 0, static_cast<Index>(node.mChildren.size() - 1));
260       sd.Visit(node.mChildren[i], choices, v);
261     }
262   }
263   else
264   {
265     for(auto i : node.mChildren)
266     {
267       sd.Visit(i, choices, v);
268     }
269   }
270
271   v.Finish(node);
272 }
273
274 } // namespace
275
276 SceneDefinition::SceneDefinition()
277 {
278   mNodes.reserve(128);
279
280 #ifdef DEBUG_JOINTS
281   EnsureJointDebugShaderCreated();
282 #endif
283 }
284
285 SceneDefinition::SceneDefinition(SceneDefinition&& other)
286 : mNodes(std::move(other.mNodes)),
287   mRootNodeIds(std::move(other.mRootNodeIds))
288 {
289 #ifdef DEBUG_JOINTS
290   EnsureJointDebugShaderCreated();
291 #endif
292 }
293
294 SceneDefinition::~SceneDefinition()
295 {
296 #ifdef DEBUG_JOINTS
297   --sNumScenes;
298   if(sNumScenes == 0)
299   {
300     sJointDebugShader = Shader();
301   }
302 #endif
303 }
304
305 uint32_t Dali::Scene3D::Loader::SceneDefinition::AddRootNode(Index iNode)
306 {
307   if(iNode < mNodes.size())
308   {
309     uint32_t result = mRootNodeIds.size();
310     mRootNodeIds.push_back(iNode);
311     return result;
312   }
313   else
314   {
315     ExceptionFlinger(ASSERT_LOCATION) << "Failed to add new root with node " << iNode << " -- index out of bounds.";
316     return -1;
317   }
318 }
319
320 const std::vector<Index>& SceneDefinition::GetRoots() const
321 {
322   return mRootNodeIds;
323 }
324
325 void SceneDefinition::RemoveRootNode(Index iRoot)
326 {
327   if(iRoot < mRootNodeIds.size())
328   {
329     mRootNodeIds.erase(mRootNodeIds.begin() + iRoot);
330   }
331   else
332   {
333     ExceptionFlinger(ASSERT_LOCATION) << "Failed to remove root " << iRoot << " -- index out of bounds.";
334   }
335 }
336
337 uint32_t SceneDefinition::GetNodeCount() const
338 {
339   return mNodes.size();
340 }
341
342 const NodeDefinition* SceneDefinition::GetNode(Index iNode) const
343 {
344   return mNodes[iNode].get();
345 }
346
347 NodeDefinition* SceneDefinition::GetNode(Index iNode)
348 {
349   if(iNode != Scene3D::Loader::INVALID_INDEX && iNode < mNodes.size())
350   {
351     return mNodes[iNode].get();
352   }
353   return nullptr;
354 }
355
356 void SceneDefinition::Visit(Index iNode, const Customization::Choices& choices, NodeDefinition::IVisitor& v)
357 {
358   VisitInternal(iNode, choices, v, *this);
359 }
360
361 void SceneDefinition::Visit(Index iNode, const Customization::Choices& choices, NodeDefinition::IConstVisitor& v) const
362 {
363   VisitInternal(iNode, choices, v, *this);
364 }
365
366 void SceneDefinition::CountResourceRefs(Index iNode, const Customization::Choices& choices, ResourceRefCounts& refCounts) const
367 {
368   struct RefCounter : IResourceReceiver
369   {
370     ResourceRefCounts* refCounts;
371
372     void Register(ResourceType::Value type, Index id)
373     {
374       if((!(*refCounts)[type].Empty()) && ((*refCounts)[type].Size() > id))
375       {
376         ++(*refCounts)[type][id];
377       }
378     }
379   };
380
381   struct : NodeDefinition::IConstVisitor
382   {
383     RefCounter counter;
384
385     void Start(const NodeDefinition& n)
386     {
387       for(auto& renderable : n.mRenderables)
388       {
389         renderable->RegisterResources(counter);
390       }
391     }
392
393     void Finish(const NodeDefinition& n)
394     {
395     }
396
397   } refCounterVisitor;
398   refCounterVisitor.counter.refCounts = &refCounts;
399
400   Visit(iNode, choices, refCounterVisitor);
401 }
402
403 ModelNode SceneDefinition::CreateNodes(Index iNode, const Customization::Choices& choices, NodeDefinition::CreateParams& params)
404 {
405   ActorCreatorVisitor actorCreatorVisitor(params);
406
407   Visit(iNode, choices, actorCreatorVisitor);
408
409   return actorCreatorVisitor.GetRoot();
410 }
411
412 void SceneDefinition::GetCustomizationOptions(const Customization::Choices& choices,
413                                               Customization::Map&           outCustomizationOptions,
414                                               Customization::Choices*       outMissingChoices) const
415 {
416   struct : NodeDefinition::IConstVisitor
417   {
418     const Customization::Choices* choices;        // choices that we know about.
419     Customization::Map*           options;        // tags are registered here. NO OWNERSHIP.
420     Customization::Choices*       missingChoices; // tags will be registered with the default 0. NO OWNERSHIP.
421
422     void Start(const NodeDefinition& n)
423     {
424       if(n.mCustomization)
425       {
426         const std::string& tag = n.mCustomization->mTag;
427         if(missingChoices != nullptr && choices->Get(tag) == Customization::NONE)
428         {
429           missingChoices->Set(tag, 0);
430         }
431
432         auto customization = options->Get(tag);
433         if(!customization)
434         {
435           customization = options->Set(tag, {});
436         }
437         customization->nodes.push_back(n.mName);
438         customization->numOptions = std::max(customization->numOptions,
439                                              static_cast<uint32_t>(n.mChildren.size()));
440       }
441     }
442
443     void Finish(const NodeDefinition& n)
444     {
445     }
446
447   } customizationRegistrationVisitor;
448   customizationRegistrationVisitor.choices        = &choices;
449   customizationRegistrationVisitor.options        = &outCustomizationOptions;
450   customizationRegistrationVisitor.missingChoices = outMissingChoices;
451
452   for(auto i : mRootNodeIds)
453   {
454     Visit(i, choices, customizationRegistrationVisitor);
455   }
456 }
457
458 NodeDefinition* SceneDefinition::AddNode(std::unique_ptr<NodeDefinition>&& nodeDef)
459 {
460   // add next index (to which we're about to push) as a child to the designated parent, if any.
461   if(nodeDef->mParentIdx != INVALID_INDEX)
462   {
463     mNodes[nodeDef->mParentIdx]->mChildren.push_back(mNodes.size());
464   }
465
466   mNodes.push_back(std::move(nodeDef));
467
468   return mNodes.back().get();
469 }
470
471 bool SceneDefinition::ReparentNode(const std::string& name, const std::string& newParentName, Index siblingOrder)
472 {
473   LOGD(("reparenting %s to %s @ %d", name.c_str(), newParentName.c_str(), siblingOrder));
474
475   std::unique_ptr<NodeDefinition>* nodePtr      = nullptr;
476   std::unique_ptr<NodeDefinition>* newParentPtr = nullptr;
477   if(!FindNode(name, &nodePtr) || !FindNode(newParentName, &newParentPtr))
478   {
479     return false;
480   }
481
482   auto& node  = *nodePtr;
483   auto  iNode = std::distance(mNodes.data(), nodePtr);
484
485   DEBUG_ONLY(auto dumpNode = [](NodeDefinition const& n) {
486     std::ostringstream stream;
487     stream << n.mName << " (" << n.mParentIdx << "):";
488     for(auto i : n.mChildren)
489     {
490       stream << i << ", ";
491     }
492     LOGD(("%s", stream.str().c_str())); };)
493
494   // Remove node from children of previous parent (if any).
495   if(node->mParentIdx != INVALID_INDEX)
496   {
497     LOGD(("old parent:"));
498     DEBUG_ONLY(dumpNode(*mNodes[node->mParentIdx]);)
499
500     auto& children = mNodes[node->mParentIdx]->mChildren;
501     children.erase(std::remove(children.begin(), children.end(), iNode), children.end());
502
503     DEBUG_ONLY(dumpNode(*mNodes[node->mParentIdx]);)
504   }
505
506   // Register node to new parent.
507   LOGD(("new parent:"));
508   DEBUG_ONLY(dumpNode(**newParentPtr);)
509   auto& children = (*newParentPtr)->mChildren;
510   if(siblingOrder > children.size())
511   {
512     siblingOrder = children.size();
513   }
514   children.insert(children.begin() + siblingOrder, 1, iNode);
515   DEBUG_ONLY(dumpNode(**newParentPtr);)
516
517   // Update parent index.
518   LOGD(("node:"));
519   DEBUG_ONLY(dumpNode(*node);)
520   auto iParent     = std::distance(mNodes.data(), newParentPtr);
521   node->mParentIdx = iParent;
522   DEBUG_ONLY(dumpNode(*node);)
523   return true;
524 }
525
526 bool SceneDefinition::RemoveNode(const std::string& name)
527 {
528   std::unique_ptr<NodeDefinition>* node = nullptr;
529   if(!FindNode(name, &node))
530   {
531     return false;
532   }
533
534   // Reset node def pointers recursively.
535   auto&                                                 thisNodes = mNodes;
536   unsigned int                                          numReset  = 0;
537   std::function<void(std::unique_ptr<NodeDefinition>&)> resetFn =
538     [&thisNodes, &resetFn, &numReset](std::unique_ptr<NodeDefinition>& nd) {
539       LOGD(("resetting %d", &nd - thisNodes.data()));
540       for(auto i : nd->mChildren)
541       {
542         resetFn(thisNodes[i]);
543       }
544       nd.reset();
545       ++numReset;
546     };
547
548   resetFn(*node);
549
550   // Gather indices of dead nodes into a vector which we sort on insertion.
551   std::vector<Index> offsets;
552   offsets.reserve(numReset);
553   for(auto& n : mNodes)
554   {
555     if(!n)
556     {
557       offsets.push_back(std::distance(mNodes.data(), &n));
558     }
559   }
560
561   // Erase dead nodes as they don't have to be processed anymore.
562   mNodes.erase(std::remove(mNodes.begin(), mNodes.end(), decltype(mNodes)::value_type()), mNodes.end());
563
564   // Offset all indices (parent and child) by the index they'd sort into in offsets.
565   enum
566   {
567     INDEX_FOR_REMOVAL = INVALID_INDEX
568   };
569   auto offsetter = [&offsets](Index& i) {
570     auto iFind = std::lower_bound(offsets.begin(), offsets.end(), i);
571     if(iFind != offsets.end() && *iFind == i)
572     {
573       LOGD(("marking %d for removal.", i));
574       i = INDEX_FOR_REMOVAL;
575       return false;
576     }
577     else
578     {
579       auto distance = std::distance(offsets.begin(), iFind);
580       if(distance > 0)
581       {
582         LOGD(("offsetting %d by %d.", i, distance));
583         i -= distance;
584       }
585       return true;
586     }
587   };
588
589   for(auto& nd : mNodes)
590   {
591     bool parentOffsetResult = offsetter(nd->mParentIdx);
592     DALI_ASSERT_ALWAYS(parentOffsetResult); // since nodes were recursively removed, we should not be finding invalid parents at this point.
593
594     auto& children = nd->mChildren;
595     for(auto i0 = children.begin(), i1 = children.end(); i0 != i1; ++i0)
596     {
597       offsetter(*i0);
598     }
599
600     children.erase(std::remove(children.begin(), children.end(), INDEX_FOR_REMOVAL), children.end());
601   }
602
603   return true;
604 }
605
606 void SceneDefinition::GetNodeModelStack(Index index, MatrixStack& model) const
607 {
608   auto&                    thisNodes  = mNodes;
609   std::function<void(int)> buildStack = [&model, &thisNodes, &buildStack](int i) {
610     auto node = thisNodes[i].get();
611     if(node->mParentIdx != INVALID_INDEX)
612     {
613       buildStack(node->mParentIdx);
614     }
615     model.Push(node->GetLocalSpace());
616   };
617   buildStack(index);
618 }
619
620 NodeDefinition* SceneDefinition::FindNode(const std::string& name, Index* outIndex)
621 {
622   auto iBegin = mNodes.begin();
623   auto iEnd   = mNodes.end();
624   auto iFind  = std::find_if(iBegin, iEnd, [&name](const std::unique_ptr<NodeDefinition>& nd) { return nd->mName == name; });
625
626   auto result = iFind != iEnd ? iFind->get() : nullptr;
627   if(result && outIndex)
628   {
629     *outIndex = std::distance(iBegin, iFind);
630   }
631   return result;
632 }
633
634 const NodeDefinition* SceneDefinition::FindNode(const std::string& name, Index* outIndex) const
635 {
636   auto iBegin = mNodes.begin();
637   auto iEnd   = mNodes.end();
638   auto iFind  = std::find_if(iBegin, iEnd, [&name](const std::unique_ptr<NodeDefinition>& nd) { return nd->mName == name; });
639
640   auto result = iFind != iEnd ? iFind->get() : nullptr;
641   if(result && outIndex)
642   {
643     *outIndex = std::distance(iBegin, iFind);
644   }
645   return result;
646 }
647
648 Index SceneDefinition::FindNodeIndex(const NodeDefinition& node) const
649 {
650   auto iBegin = mNodes.begin();
651   auto iEnd   = mNodes.end();
652   auto iFind  = std::find_if(iBegin, iEnd, [&node](const std::unique_ptr<NodeDefinition>& n) { return n.get() == &node; });
653   return iFind != iEnd ? std::distance(iBegin, iFind) : INVALID_INDEX;
654 }
655
656 void SceneDefinition::FindNodes(NodePredicate predicate, NodeConsumer consumer, unsigned int limit)
657 {
658   unsigned int n = 0;
659   for(auto& defp : mNodes)
660   {
661     if(predicate(*defp))
662     {
663       consumer(*defp);
664       ++n;
665       if(n == limit)
666       {
667         break;
668       }
669     }
670   }
671 }
672
673 void SceneDefinition::FindNodes(NodePredicate predicate, ConstNodeConsumer consumer, unsigned int limit) const
674 {
675   unsigned int n = 0;
676   for(auto& defp : mNodes)
677   {
678     if(predicate(*defp))
679     {
680       consumer(*defp);
681       ++n;
682       if(n == limit)
683       {
684         break;
685       }
686     }
687   }
688 }
689
690 void SceneDefinition::ApplyConstraints(Actor&                           root,
691                                        std::vector<ConstraintRequest>&& constrainables,
692                                        StringCallback                   onError) const
693 {
694   for(auto& cr : constrainables)
695   {
696     auto&           nodeDef    = mNodes[cr.mConstraint->mSourceIdx];
697     auto            sourceName = nodeDef->mName.c_str();
698     Property::Index iTarget    = cr.mTarget.GetPropertyIndex(cr.mConstraint->mProperty);
699     if(iTarget != Property::INVALID_INDEX)
700     {
701       auto propertyType = cr.mTarget.GetPropertyType(iTarget);
702       auto iFind        = GetConstraintFactory().find(propertyType);
703       if(iFind == GetConstraintFactory().end())
704       {
705         onError(FormatString("node '%s': Property '%s' has unsupported type '%s'; ignored.",
706                              sourceName,
707                              cr.mConstraint->mProperty.c_str(),
708                              PropertyTypes::GetName(propertyType)));
709         continue;
710       }
711
712       Constraint constraint = iFind->second(cr.mTarget, iTarget);
713
714       Actor source = root.FindChildByName(nodeDef->mName);
715       if(!source)
716       {
717         auto targetName = cr.mTarget.GetProperty(Actor::Property::NAME).Get<std::string>();
718         onError(FormatString("node '%s': Failed to locate constraint source %s@%s; ignored.",
719                              sourceName,
720                              cr.mConstraint->mProperty.c_str(),
721                              targetName.c_str()));
722         continue;
723       }
724       else if(source == cr.mTarget)
725       {
726         onError(FormatString("node '%s': Cyclic constraint definition for property '%s'; ignored.",
727                              sourceName,
728                              cr.mConstraint->mProperty.c_str()));
729         continue;
730       }
731
732       Property::Index iSource = source.GetPropertyIndex(cr.mConstraint->mProperty);
733       constraint.AddSource(Source{source, iSource});
734       constraint.Apply();
735     }
736     else
737     {
738       auto targetName = cr.mTarget.GetProperty(Actor::Property::NAME).Get<std::string>();
739       onError(FormatString("node '%s': Failed to create constraint for property %s@%s; ignored.",
740                            sourceName,
741                            cr.mConstraint->mProperty.c_str(),
742                            targetName.c_str()));
743     }
744   }
745 }
746
747 void SceneDefinition::EnsureUniqueSkinningShaderInstances(ResourceBundle& resources) const
748 {
749   std::map<Index, std::map<Index, std::vector<Index*>>> skinningShaderUsers;
750   for(auto& node : mNodes)
751   {
752     for(auto& renderable : node->mRenderables)
753     {
754       ResourceReflector reflector;
755       renderable->ReflectResources(reflector);
756
757       if(reflector.iMesh)
758       {
759         const auto& mesh = resources.mMeshes[*reflector.iMesh].first;
760         if(mesh.IsSkinned())
761         {
762           skinningShaderUsers[*reflector.iShader][mesh.mSkeletonIdx].push_back(reflector.iShader);
763         }
764       }
765     }
766   }
767
768   // For each shader, and each skeleton using the same shader as the first skeleton,
769   // update the shader references (from nodes with skinned meshes) with a new copy of
770   // the shader definition from the node using the first skeleton.
771   for(auto& users : skinningShaderUsers)
772   {
773     auto& skeletons    = users.second;
774     auto  iterSkeleton = skeletons.begin();
775     // skipping the first skeleton.
776     ++iterSkeleton;
777
778     resources.mShaders.reserve(resources.mShaders.size() + std::distance(iterSkeleton, skeletons.end()));
779     const ShaderDefinition& shaderDef = resources.mShaders[users.first].first;
780
781     while(iterSkeleton != skeletons.end())
782     {
783       Index iShader = resources.mShaders.size();
784       resources.mShaders.push_back({shaderDef, Shader()});
785
786       for(auto& i : iterSkeleton->second)
787       {
788         *i = iShader;
789       }
790       ++iterSkeleton;
791     }
792   }
793 }
794
795 void SceneDefinition::ConfigureSkinningShaders(const ResourceBundle&                             resources,
796                                                Actor                                             rootActor,
797                                                std::vector<SkinningShaderConfigurationRequest>&& requests) const
798 {
799   if(requests.empty())
800   {
801     return;
802   }
803
804   SortAndDeduplicateRequests(requests);
805
806   for(auto& request : requests)
807   {
808     auto& skeleton = resources.mSkeletons[request.mSkeletonIdx];
809     if(skeleton.mJoints.empty())
810     {
811       LOGD(("Skeleton %d has no joints.", request.mSkeletonIdx));
812       continue;
813     }
814
815     Index boneIdx = 0;
816     for(auto& joint : skeleton.mJoints)
817     {
818       auto      node      = GetNode(joint.mNodeIdx);
819       ModelNode modelNode = ModelNode::DownCast(rootActor.FindChildByName(node->mName));
820       if(!modelNode)
821       {
822         continue;
823       }
824       ConfigureBoneMatrix(joint.mInverseBindMatrix, modelNode, request.mPrimitive, boneIdx);
825     }
826   }
827 }
828
829 bool SceneDefinition::ConfigureBlendshapeShaders(const ResourceBundle&                               resources,
830                                                  Actor                                               rootActor,
831                                                  std::vector<BlendshapeShaderConfigurationRequest>&& requests,
832                                                  StringCallback                                      onError) const
833 {
834   if(requests.empty())
835   {
836     return true;
837   }
838
839   SortAndDeduplicateRequests(requests);
840
841   // Configure the rest.
842   bool ok = true;
843
844   for(auto& request : requests)
845   {
846     Index iNode;
847     if(FindNode(request.mNodeName, &iNode))
848     {
849       const auto& node = GetNode(iNode);
850
851       const auto& mesh = resources.mMeshes[request.mMeshIdx];
852
853       if(mesh.first.HasBlendShapes())
854       {
855         Actor              actor = rootActor.FindChildByName(node->mName);
856         Scene3D::ModelNode node  = Scene3D::ModelNode::DownCast(actor);
857         if(!node)
858         {
859           continue;
860         }
861         BlendShapes::BlendShapeData data;
862         data.components = 0x0;
863         for(auto&& blendShape : mesh.first.mBlendShapes)
864         {
865           data.names.push_back(blendShape.name);
866           data.weights.push_back(blendShape.weight);
867           data.components |= (blendShape.deltas.IsDefined() * BlendShapes::Component::POSITIONS) |
868                              (blendShape.normals.IsDefined() * BlendShapes::Component::NORMALS) | (blendShape.tangents.IsDefined() * BlendShapes::Component::TANGENTS);
869         }
870         for(auto&& factor : mesh.second.blendShapeUnnormalizeFactor)
871         {
872           data.unnormalizeFactors.push_back(factor);
873         }
874         data.version      = mesh.first.mBlendShapeVersion;
875         data.bufferOffset = mesh.second.blendShapeBufferOffset;
876         data.mActor       = actor;
877         Internal::GetImplementation(node).SetBlendShapeData(data, request.mPrimitive);
878       }
879     }
880   }
881
882   return ok;
883 }
884
885 void SceneDefinition::EnsureUniqueBlendShapeShaderInstances(ResourceBundle& resources) const
886 {
887   std::map<Index, std::map<std::string, std::vector<Index*>>> blendShapeShaderUsers;
888   for(auto& node : mNodes)
889   {
890     for(auto& renderable : node->mRenderables)
891     {
892       ResourceReflector reflector;
893       renderable->ReflectResources(reflector);
894
895       if(reflector.iMesh)
896       {
897         const auto& mesh = resources.mMeshes[*reflector.iMesh].first;
898         if(mesh.HasBlendShapes())
899         {
900           blendShapeShaderUsers[*reflector.iShader][node->mName].push_back(reflector.iShader);
901         }
902       }
903     }
904   }
905
906   for(auto& users : blendShapeShaderUsers)
907   {
908     resources.mShaders.reserve(resources.mShaders.size() + users.second.size() - 1u);
909     const ShaderDefinition& shaderDef = resources.mShaders[users.first].first;
910
911     auto nodesIt    = users.second.begin();
912     auto nodesEndIt = users.second.end();
913     // skipping the first node.
914     ++nodesIt;
915     while(nodesIt != nodesEndIt)
916     {
917       Index iShader = resources.mShaders.size();
918       resources.mShaders.push_back({shaderDef, Shader()});
919
920       auto& nodes = *nodesIt;
921       for(auto& shader : nodes.second)
922       {
923         *shader = iShader;
924       }
925       ++nodesIt;
926     }
927   }
928 }
929
930 SceneDefinition& SceneDefinition::operator=(SceneDefinition&& other)
931 {
932   SceneDefinition temp(std::move(other));
933   std::swap(mNodes, temp.mNodes);
934   std::swap(mRootNodeIds, temp.mRootNodeIds);
935   return *this;
936 }
937
938 bool SceneDefinition::FindNode(const std::string& name, std::unique_ptr<NodeDefinition>** result)
939 {
940   // We're searching from the end assuming a higher probability of operations targeting
941   // recently added nodes. (conf.: root, which is immovable, cannot be removed, and was
942   // the first to be added, is index 0.)
943   auto iFind = std::find_if(mNodes.rbegin(), mNodes.rend(), [&name](const std::unique_ptr<NodeDefinition>& nd) { return nd->mName == name; })
944                  .base();
945
946   const bool success = iFind != mNodes.begin();
947   if(success && result)
948   {
949     --iFind;
950     *result = &*iFind;
951   }
952
953   return success;
954 }
955
956 } // namespace Dali::Scene3D::Loader