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