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