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