2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "dali/public-api/animation/constraints.h"
20 #include "dali/devel-api/common/map-wrapper.h"
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"
28 //#define DEBUG_SCENE_DEFINITION
29 //#define DEBUG_JOINTS
31 #if defined(DEBUG_SCENE_DEFINITION) || defined(DEBUG_JOINTS)
32 #define DEBUG_ONLY(x) x
37 #define LOGD(x) DEBUG_ONLY(printf x ; printf("\n"); fflush(stdout))
46 const std::string JOINT_MATRIX{ "jointMatrix" };
48 const std::map<Property::Type, Constraint(*)(Actor&, Property::Index)> sConstraintFactory = {
50 Property::Type::BOOLEAN,
51 [](Actor& a, Property::Index i) {
52 return Constraint::New<bool>(a, i, [](bool& current, const PropertyInputContainer& inputs) {
53 current = inputs[0]->GetBoolean();
58 Property::Type::INTEGER,
59 [](Actor& a, Property::Index i) {
60 return Constraint::New<int>(a, i, [](int& current, const PropertyInputContainer& inputs) {
61 current = inputs[0]->GetInteger();
66 Property::Type::FLOAT,
67 [](Actor& a, Property::Index i) {
68 return Constraint::New<float>(a, i, EqualToConstraint());
72 Property::Type::VECTOR2,
73 [](Actor& a, Property::Index i) {
74 return Constraint::New<Vector2>(a, i, EqualToConstraint());
78 Property::Type::VECTOR3,
79 [](Actor& a, Property::Index i) {
80 return Constraint::New<Vector3>(a, i, EqualToConstraint());
84 Property::Type::VECTOR4,
85 [](Actor& a, Property::Index i) {
86 return Constraint::New<Vector4>(a, i, EqualToConstraint());
90 Property::Type::MATRIX,
91 [](Actor& a, Property::Index i) {
92 return Constraint::New<Matrix>(a, i, EqualToConstraint());
96 Property::Type::MATRIX3,
97 [](Actor& a, Property::Index i) {
98 return Constraint::New<Matrix3>(a, i, EqualToConstraint());
102 Property::Type::ROTATION,
103 [](Actor& a, Property::Index i) {
104 return Constraint::New<Quaternion>(a, i, EqualToConstraint());
109 struct ResourceReflector : IResourceReflector
111 Index* iMesh = nullptr;
112 Index* iShader = nullptr;
114 void Reflect(ResourceType::Value type, Index& id)
118 case ResourceType::Shader:
119 DALI_ASSERT_ALWAYS(!iShader && "Shader index already assigned!");
123 case ResourceType::Mesh:
124 DALI_ASSERT_ALWAYS(!iMesh && "Mesh index already assigned!");
128 default: // Other resource types are not relevant to the problem at hand.
136 const char* JOINT_DEBUG_VSH = "#version 300 es\n"
138 precision mediump float;
139 uniform mat4 uMvpMatrix;
142 flat out float vColor;
145 gl_Position = uMvpMatrix * vec4(aPosition, 1.0);
148 const char* JOINT_DEBUG_FSH = "#version 300 es\n"
150 precision mediump float;
151 flat in float vColor;
154 vec3 rgb = vec3(fract(vColor), fract(vColor * 0.00390625), fract(vColor * 0.00390625 * 0.00390625));
155 FragColor = vec4(rgb, 1.);
158 Shader sJointDebugShader;
161 void EnsureJointDebugShaderCreated()
165 sJointDebugShader = Shader::New(JOINT_DEBUG_VSH, JOINT_DEBUG_FSH);
170 void AddJointDebugVisual(Actor aJoint)
172 Property::Map attribs;
173 attribs["aPosition"] = Property::Type::VECTOR3;
174 attribs["aColor"] = Property::Type::FLOAT;
176 PropertyBuffer vbo = PropertyBuffer::New(attribs);
183 { Vector3::ZERO, .999f + .999f * 256.f + .999f * 256.f * 256.f },
184 { Vector3::XAXIS, .999f },
185 { Vector3::YAXIS, .999f * 256.f },
186 { Vector3::ZAXIS, .999f * 256.f * 256.f },
189 vbo.SetData(&vertices, std::extent<decltype(vertices)>::value);
191 uint16_t indices[] = { 0, 1, 0, 2, 0, 3 };
193 Geometry geo = Geometry::New();
194 geo.AddVertexBuffer(vbo);
195 geo.SetIndexBuffer(indices, std::extent<decltype(indices)>::value);
196 geo.SetType(Geometry::LINES);
198 Renderer r = Renderer::New(geo, sJointDebugShader);
199 aJoint.AddRenderer(r);
201 aJoint.SetVisible(true);
203 #endif //DEBUG_JOINTS
205 class ActorCreatorVisitor : public NodeDefinition::IConstVisitor
208 ActorCreatorVisitor(NodeDefinition::CreateParams& params)
209 : mCreationContext(params)
212 void Start(const NodeDefinition& n)
214 mCreationContext.mXforms.modelStack.Push(n.GetLocalSpace());
216 Actor a = n.CreateActor(mCreationContext);
217 if (!mActorStack.empty())
219 mActorStack.back().Add(a);
225 mActorStack.push_back(a);
228 void Finish(const NodeDefinition& n)
230 mActorStack.pop_back();
231 mCreationContext.mXforms.modelStack.Pop();
234 Actor GetRoot() const
240 NodeDefinition::CreateParams& mCreationContext;
241 std::vector<Actor> mActorStack;
245 bool IsAncestor(const SceneDefinition& scene, Index ancestor, Index node, Index rootHint = INVALID_INDEX)
247 bool isAncestor = false;
248 while (node != rootHint && !isAncestor)
250 node = scene.GetNode(node)->mParentIdx;
251 isAncestor = ancestor == node;
256 void InsertUniqueSorted(std::vector<Index>& data, Index value)
258 auto iInsert = std::lower_bound(data.begin(), data.end(), value);
259 if (iInsert == data.end() || *iInsert != value)
261 data.insert(iInsert, value);
265 void RemoveFromSorted(std::vector<Index>& data, Index value)
267 auto iRemove = std::lower_bound(data.begin(), data.end(), value);
268 if (iRemove != data.end() && *iRemove == value)
274 Property::Index ConfigureJointMatrix(Actor actor, Actor ancestor, Property::Index propJointMatrix)
276 Actor parent = actor.GetParent();
277 if (parent != ancestor)
279 propJointMatrix = ConfigureJointMatrix(parent, ancestor, propJointMatrix);
282 auto myPropJointMatrix = actor.GetPropertyIndex(JOINT_MATRIX);
283 if (myPropJointMatrix == Property::INVALID_INDEX)
285 myPropJointMatrix = actor.RegisterProperty(JOINT_MATRIX, Matrix{ false });
286 Constraint constraint = Constraint::New<Matrix>(actor, propJointMatrix,
287 [](Matrix& output, const PropertyInputContainer& inputs)
289 Matrix jointMatrix{ false };
290 jointMatrix.SetTransformComponents(Vector3::ONE, inputs[0]->GetQuaternion(), inputs[1]->GetVector3());
292 Matrix::Multiply(output, jointMatrix, inputs[2]->GetMatrix());
294 constraint.AddSource(Source{ actor, Actor::Property::ORIENTATION });
295 constraint.AddSource(Source{ actor, Actor::Property::POSITION });
296 constraint.AddSource(Source{ parent, propJointMatrix });
300 return myPropJointMatrix;
303 void SortAndDeduplicateSkinningRequests(std::vector<SkinningShaderConfigurationRequest>& requests)
305 // Sort requests by shaders.
306 std::sort(requests.begin(), requests.end());
308 // Remove duplicates.
309 auto i = requests.begin();
310 auto iEnd = requests.end();
311 Shader s = i->mShader;
312 Index skeletonIdx = i->mSkeletonIdx;
316 // Multiple identical shader instances are removed.
317 while (i != iEnd && i->mShader == s)
319 // Cannot have multiple skeletons input to the same shader.
320 // NOTE: DliModel now makes sure this doesn't happen.
321 DALI_ASSERT_ALWAYS(i->mSkeletonIdx == skeletonIdx &&
322 "Skinning shader must not be shared between different skeletons.");
324 i->mShader = Shader();
333 skeletonIdx = i->mSkeletonIdx;
337 requests.erase(std::remove_if(requests.begin(), requests.end(), [](const SkinningShaderConfigurationRequest& sscr)
339 return !sscr.mShader;
343 void ConfigureBoneMatrix(const Matrix& ibm, Actor joint, Shader& shader, Index& boneIdx)
345 // Register bone transform on shader.
346 char propertyNameBuffer[32];
347 snprintf(propertyNameBuffer, sizeof(propertyNameBuffer), "%s[%d]", Skinning::BONE_UNIFORM_NAME.c_str(), boneIdx);
348 DALI_ASSERT_DEBUG(shader.GetPropertyIndex(propertyNameBuffer) == Property::INVALID_INDEX);
349 auto propBoneXform = shader.RegisterProperty(propertyNameBuffer, Matrix{ false });
351 // Constrain bone matrix to joint transform.
352 Constraint constraint = Constraint::New<Matrix>(shader, propBoneXform,
353 [ibm](Matrix& output, const PropertyInputContainer& inputs)
355 Matrix::Multiply(output, ibm, inputs[0]->GetMatrix());
358 auto propJointMatrix = joint.GetPropertyIndex(JOINT_MATRIX);
359 constraint.AddSource(Source{ joint, propJointMatrix });
365 template <class Visitor, class SceneDefinition>
366 void VisitInternal(Index iNode, const Customization::Choices& choices, Visitor& v, SceneDefinition& sd)
368 auto& node = *sd.GetNode(iNode);
371 if (node.mCustomization)
373 if (!node.mChildren.empty())
375 auto choice = choices.Get(node.mCustomization->mTag);
376 Index i = std::min(choice != Customization::NONE ? choice : 0, static_cast<Index>(node.mChildren.size() - 1));
377 sd.Visit(node.mChildren[i], choices, v);
382 for (auto i : node.mChildren)
384 sd.Visit(i, choices, v);
393 SceneDefinition::SceneDefinition()
398 EnsureJointDebugShaderCreated();
402 SceneDefinition::SceneDefinition(SceneDefinition&& other)
403 : mNodes(std::move(other.mNodes)),
404 mRootNodeIds(std::move(other.mRootNodeIds))
407 EnsureJointDebugShaderCreated();
411 SceneDefinition::~SceneDefinition()
417 sJointDebugShader = Shader();
422 uint32_t SceneLoader::SceneDefinition::AddRootNode(Index iNode)
424 if (iNode < mNodes.size())
426 uint32_t result = mRootNodeIds.size();
427 mRootNodeIds.push_back(iNode);
432 ExceptionFlinger(ASSERT_LOCATION) << "Failed to add new root with node " << iNode << " -- index out of bounds.";
437 const std::vector<Index>& SceneDefinition::GetRoots() const
442 void SceneDefinition::RemoveRootNode(Index iRoot)
444 if (iRoot < mRootNodeIds.size())
446 mRootNodeIds.erase(mRootNodeIds.begin() + iRoot);
450 ExceptionFlinger(ASSERT_LOCATION) << "Failed to remove root " << iRoot << " -- index out of bounds.";
454 uint32_t SceneDefinition::GetNodeCount() const
456 return mNodes.size();
459 const NodeDefinition* SceneDefinition::GetNode(Index iNode) const
461 return mNodes[iNode].get();
464 NodeDefinition* SceneDefinition::GetNode(Index iNode)
466 return mNodes[iNode].get();
469 void SceneDefinition::Visit(Index iNode, const Customization::Choices& choices, NodeDefinition::IVisitor& v)
471 VisitInternal(iNode, choices, v, *this);
474 void SceneDefinition::Visit(Index iNode, const Customization::Choices& choices, NodeDefinition::IConstVisitor& v) const
476 VisitInternal(iNode, choices, v, *this);
479 void SceneDefinition::CountResourceRefs(Index iNode, const Customization::Choices& choices, ResourceRefCounts& refCounts) const
481 struct RefCounter : IResourceReceiver
483 ResourceRefCounts* refCounts;
485 void Register(ResourceType::Value type, Index id)
487 ++(*refCounts)[type][id];
491 struct : NodeDefinition::IConstVisitor
495 void Start(const NodeDefinition& n)
499 n.mRenderable->RegisterResources(counter);
503 void Finish(const NodeDefinition& n)
507 refCounterVisitor.counter.refCounts = &refCounts;
509 Visit(iNode, choices, refCounterVisitor);
512 Actor SceneDefinition::CreateNodes(Index iNode, const Customization::Choices & choices,
513 NodeDefinition::CreateParams& params) const
515 ActorCreatorVisitor actorCreatorVisitor(params);
517 Visit(iNode, choices, actorCreatorVisitor);
519 return actorCreatorVisitor.GetRoot();
522 void SceneDefinition::GetCustomizationOptions(const Customization::Choices& choices,
523 Customization::Map& outCustomizationOptions, Customization::Choices* outMissingChoices) const
525 struct : NodeDefinition::IConstVisitor
527 const Customization::Choices* choices; // choices that we know about.
528 Customization::Map* options; // tags are registered here. NO OWNERSHIP.
529 Customization::Choices* missingChoices; // tags will be registered with the default 0. NO OWNERSHIP.
531 void Start(const NodeDefinition& n)
533 if (n.mCustomization)
535 const std::string& tag = n.mCustomization->mTag;
536 if (missingChoices != nullptr && choices->Get(tag) == Customization::NONE)
538 missingChoices->Set(tag, 0);
541 auto customization = options->Get(tag);
544 customization = options->Set(tag, {});
546 customization->nodes.push_back(n.mName);
547 customization->numOptions = std::max(customization->numOptions,
548 static_cast<uint32_t>(n.mChildren.size()));
552 void Finish(const NodeDefinition& n)
555 } customizationRegistrationVisitor;
556 customizationRegistrationVisitor.choices = &choices;
557 customizationRegistrationVisitor.options = &outCustomizationOptions;
558 customizationRegistrationVisitor.missingChoices = outMissingChoices;
560 for (auto i : mRootNodeIds)
562 Visit(i, choices, customizationRegistrationVisitor);
566 NodeDefinition* SceneDefinition::AddNode(std::unique_ptr<NodeDefinition>&& nodeDef)
568 if (FindNode(nodeDef->mName))
573 // add next index (to which we're about to push) as a child to the designated parent, if any.
574 if (nodeDef->mParentIdx != INVALID_INDEX)
576 mNodes[nodeDef->mParentIdx]->mChildren.push_back(mNodes.size());
579 mNodes.push_back(std::move(nodeDef));
581 return mNodes.back().get();
584 bool SceneDefinition::ReparentNode(const std::string& name, const std::string& newParentName, Index siblingOrder)
586 LOGD(("reparenting %s to %s @ %d", name.c_str(), newParentName.c_str(), siblingOrder));
588 std::unique_ptr<NodeDefinition>* nodePtr = nullptr;
589 std::unique_ptr<NodeDefinition>* newParentPtr = nullptr;
590 if (!FindNode(name, &nodePtr) || !FindNode(newParentName, &newParentPtr))
595 auto& node = *nodePtr;
596 auto iNode = std::distance(mNodes.data(), nodePtr);
598 DEBUG_ONLY(auto dumpNode = [](NodeDefinition const& n) {
599 std::ostringstream stream;
600 stream << n.mName << " (" << n.mParentIdx << "):";
601 for (auto i : n.mChildren)
605 LOGD(("%s", stream.str().c_str()));
608 // Remove node from children of previous parent (if any).
609 if (node->mParentIdx != INVALID_INDEX)
611 LOGD(("old parent:"));
612 DEBUG_ONLY(dumpNode(*mNodes[node->mParentIdx]);)
614 auto& children = mNodes[node->mParentIdx]->mChildren;
615 children.erase(std::remove(children.begin(), children.end(), iNode), children.end());
617 DEBUG_ONLY(dumpNode(*mNodes[node->mParentIdx]);)
620 // Register node to new parent.
621 LOGD(("new parent:"));
622 DEBUG_ONLY(dumpNode(**newParentPtr);)
623 auto& children = (*newParentPtr)->mChildren;
624 if (siblingOrder > children.size())
626 siblingOrder = children.size();
628 children.insert(children.begin() + siblingOrder, 1, iNode);
629 DEBUG_ONLY(dumpNode(**newParentPtr);)
631 // Update parent index.
633 DEBUG_ONLY(dumpNode(*node);)
634 auto iParent = std::distance(mNodes.data(), newParentPtr);
635 node->mParentIdx = iParent;
636 DEBUG_ONLY(dumpNode(*node);)
640 bool SceneDefinition::RemoveNode(const std::string& name)
642 std::unique_ptr<NodeDefinition>* node = nullptr;
643 if (!FindNode(name, &node))
648 // Reset node def pointers recursively.
649 auto& thisNodes = mNodes;
650 unsigned int numReset = 0;
651 std::function<void(std::unique_ptr<NodeDefinition>&)> resetFn =
652 [&thisNodes, &resetFn, &numReset](std::unique_ptr<NodeDefinition>& nd) {
653 LOGD(("resetting %d", &nd - thisNodes.data()));
654 for (auto i : nd->mChildren)
656 resetFn(thisNodes[i]);
664 // Gather indices of dead nodes into a vector which we sort on insertion.
665 std::vector<Index> offsets;
666 offsets.reserve(numReset);
667 for (auto& n : mNodes)
671 offsets.push_back(std::distance(mNodes.data(), &n));
675 // Erase dead nodes as they don't have to be processed anymore.
676 mNodes.erase(std::remove(mNodes.begin(), mNodes.end(), decltype(mNodes)::value_type()), mNodes.end());
678 // Offset all indices (parent and child) by the index they'd sort into in offsets.
679 enum { INDEX_FOR_REMOVAL = INVALID_INDEX };
680 auto offsetter = [&offsets](Index& i) {
681 auto iFind = std::lower_bound(offsets.begin(), offsets.end(), i);
682 if (iFind != offsets.end() && *iFind == i)
684 LOGD(("marking %d for removal.", i));
685 i = INDEX_FOR_REMOVAL;
690 auto distance = std::distance(offsets.begin(), iFind);
693 LOGD(("offsetting %d by %d.", i, distance));
700 for (auto& nd : mNodes)
702 bool parentOffsetResult = offsetter(nd->mParentIdx);
703 DALI_ASSERT_ALWAYS(parentOffsetResult); // since nodes were recursively removed, we should not be finding invalid parents at this point.
705 auto& children = nd->mChildren;
706 for (auto i0 = children.begin(), i1 = children.end(); i0 != i1; ++i0)
711 children.erase(std::remove(children.begin(), children.end(), INDEX_FOR_REMOVAL), children.end());
717 void SceneDefinition::GetNodeModelStack(Index index, MatrixStack& model) const
719 auto& thisNodes = mNodes;
720 std::function<void(int)> buildStack = [&model, &thisNodes, &buildStack](int i) {
721 auto node = thisNodes[i].get();
722 if (node->mParentIdx != INVALID_INDEX)
724 buildStack(node->mParentIdx);
726 model.Push(node->GetLocalSpace());
731 NodeDefinition* SceneDefinition::FindNode(const std::string &name, Index* outIndex)
733 auto iBegin = mNodes.begin();
734 auto iEnd = mNodes.end();
735 auto iFind = std::find_if(iBegin, iEnd, [&name](const std::unique_ptr<NodeDefinition>& nd) {
736 return nd->mName == name;
739 auto result = iFind != iEnd ? iFind->get() : nullptr;
740 if (result && outIndex)
742 *outIndex = std::distance(iBegin, iFind);
747 const NodeDefinition* SceneDefinition::FindNode(const std::string &name, Index* outIndex) const
749 auto iBegin = mNodes.begin();
750 auto iEnd = mNodes.end();
751 auto iFind = std::find_if(iBegin, iEnd, [&name](const std::unique_ptr<NodeDefinition>& nd) {
752 return nd->mName == name;
755 auto result = iFind != iEnd ? iFind->get() : nullptr;
756 if (result && outIndex)
758 *outIndex = std::distance(iBegin, iFind);
763 Index SceneDefinition::FindNodeIndex(const NodeDefinition& node) const
765 auto iBegin = mNodes.begin();
766 auto iEnd = mNodes.end();
767 auto iFind = std::find_if(iBegin, iEnd, [&node](const std::unique_ptr<NodeDefinition>& n) {
768 return n.get() == &node;
770 return iFind != iEnd ? std::distance(iBegin, iFind) : INVALID_INDEX;
773 void SceneDefinition::FindNodes(NodePredicate predicate, NodeConsumer consumer,
777 for (auto& defp : mNodes)
779 if (predicate(*defp))
791 void SceneDefinition::FindNodes(NodePredicate predicate, ConstNodeConsumer consumer,
792 unsigned int limit) const
795 for (auto& defp : mNodes)
797 if (predicate(*defp))
809 void SceneDefinition::ApplyConstraints(Actor& root,
810 std::vector<ConstraintRequest>&& constrainables, StringCallback onError) const
812 for (auto& cr : constrainables)
814 auto& nodeDef = mNodes[cr.mConstraint->mSourceIdx];
815 auto sourceName = nodeDef->mName.c_str();
816 Property::Index iTarget = cr.mTarget.GetPropertyIndex(cr.mConstraint->mProperty);
817 if (iTarget != Property::INVALID_INDEX)
819 auto propertyType = cr.mTarget.GetPropertyType(iTarget);
820 auto iFind = sConstraintFactory.find(propertyType);
821 if (iFind == sConstraintFactory.end())
823 onError(FormatString("node '%s': Property '%s' has unsupported type '%s'; ignored.",
824 sourceName, cr.mConstraint->mProperty.c_str(), PropertyTypes::GetName(propertyType)));
828 Constraint constraint = iFind->second(cr.mTarget, iTarget);
830 Actor source = root.FindChildByName(nodeDef->mName);
833 auto targetName = cr.mTarget.GetProperty(Actor::Property::NAME).Get<std::string>();
834 onError(FormatString("node '%s': Failed to locate constraint source %s@%s; ignored.",
835 sourceName, cr.mConstraint->mProperty.c_str(), targetName.c_str()));
838 else if (source == cr.mTarget)
840 onError(FormatString("node '%s': Cyclic constraint definition for property '%s'; ignored.",
841 sourceName, cr.mConstraint->mProperty.c_str()));
845 Property::Index iSource = source.GetPropertyIndex(cr.mConstraint->mProperty);
846 constraint.AddSource(Source{ source, iSource });
851 auto targetName = cr.mTarget.GetProperty(Actor::Property::NAME).Get<std::string>();
852 onError(FormatString("node '%s': Failed to create constraint for property %s@%s; ignored.",
853 sourceName, cr.mConstraint->mProperty.c_str(), targetName.c_str()));
858 void SceneDefinition::ConfigureSkeletonJoints(uint32_t iRoot, const SkeletonDefinition::Vector& skeletons, Actor root) const
860 // 1, For each skeleton, for each joint, walk upwards until we reach mNodes[iRoot]. If we do, record +1
861 // to the refcount of each node we have visited, in our temporary registry. Those with refcount 1
862 // are the leaves, while the most descendant node with the highest refcount is the root of the skeleton.
863 std::map<Index, std::vector<Index>> rootsJoints;
864 std::vector<Index> path;
866 for (auto& s : skeletons)
868 std::map<uint32_t, uint32_t> jointRefs;
869 for (auto& j : s.mJoints)
871 auto nodeIdx = j.mNodeIdx;
872 do // Traverse upwards and record each node we have visited until we reach the scene root.
874 path.push_back(nodeIdx);
875 if (nodeIdx == iRoot)
879 auto node = GetNode(nodeIdx);
880 nodeIdx = node->mParentIdx;
882 while (nodeIdx != INVALID_INDEX);
884 if (nodeIdx == iRoot) // If the joint is in the correct scene, increment the reference count for all visited nodes.
895 // Only record the skeleton if we have encountered the root of the current scene.
896 if (jointRefs.empty())
901 Index root = s.mRootNodeIdx;
903 auto iFind = jointRefs.find(root);
904 if (iFind != jointRefs.end())
906 maxRef = iFind->second;
909 std::vector<Index> joints;
910 for (auto& j : jointRefs) // NOTE: jointRefs are sorted, so joints will also be.
912 // The most descendant node with the highest ref count is the root of the skeleton.
913 if (j.second > maxRef || (j.second == maxRef && IsAncestor(*this, root, j.first, iRoot)))
917 RemoveFromSorted(joints, root);
920 else if (j.second == 1) // This one's a leaf.
922 InsertUniqueSorted(joints, j.first);
926 // Merge skeletons that share the same root.
927 auto& finalJoints = rootsJoints[root];
928 for (auto j : joints)
930 if (std::find_if(finalJoints.begin(), finalJoints.end(), [this, j, root](Index jj) {
931 return IsAncestor(*this, j, jj, root);
932 }) != finalJoints.end())
934 continue; // if the joint is found to be an ancestor of another joint already registered, move on.
938 while (i != root) // See if the current joint is a better leaf, i.e. descended from another leaf - which we'll then remove.
940 auto node = GetNode(i);
941 i = node->mParentIdx;
943 RemoveFromSorted(finalJoints, i);
946 InsertUniqueSorted(finalJoints, j);
950 // 2, Merge records where one root joint is descendant of another. Handle leaf node changes - remove previous
951 // leaf nodes that now have descendants, and add new ones.
952 auto iRoots = rootsJoints.begin();
953 auto iRootsEnd = rootsJoints.end();
954 while (iRoots != iRootsEnd)
956 auto i = iRoots->first;
958 while (i != iRoot) // Starting with the root joint of the skeleton, traverse upwards.
960 auto node = GetNode(i);
961 i = node->mParentIdx;
963 auto iFind = rootsJoints.find(i);
964 if (iFind != rootsJoints.end()) // Check if we've reached the root of another skeleton.
966 // Now find out which leaf of iFind is an ancestor, if any.
967 auto iFindLeaf = std::find_if(iFind->second.begin(), iFind->second.end(), [this, iRoots, iFind](Index j) {
968 return IsAncestor(*this, j, iRoots->first, iFind->first);
970 if (iFindLeaf != iFind->second.end())
972 iFind->second.erase(iFindLeaf); // Will no longer be a leaf -- remove it.
975 // Merge iRoots with iFind
976 auto& targetJoints = iFind->second;
977 if (iRoots->second.empty()) // The root is a leaf.
979 InsertUniqueSorted(targetJoints, iRoots->first);
981 else for (auto j : iRoots->second)
983 InsertUniqueSorted(targetJoints, j);
987 break; // Traverse no more
991 iRoots = merged ? rootsJoints.erase(iRoots) : std::next(iRoots);
994 // 3, For each root, register joint matrices and constraints
995 for (auto r : rootsJoints)
997 auto node = GetNode(r.first);
998 auto rootJoint = root.FindChildByName(node->mName);
999 DALI_ASSERT_ALWAYS(!!rootJoint);
1001 DALI_ASSERT_DEBUG(rootJoint.GetPropertyIndex(JOINT_MATRIX) == Property::INVALID_INDEX);
1002 auto propJointMatrix = rootJoint.RegisterProperty(JOINT_MATRIX, Matrix{ false });
1003 Constraint constraint = Constraint::New<Matrix>(rootJoint, propJointMatrix,
1004 [](Matrix& output, const PropertyInputContainer& inputs)
1006 output.SetTransformComponents(Vector3::ONE, inputs[0]->GetQuaternion(), inputs[1]->GetVector3());
1008 constraint.AddSource(Source(rootJoint, Actor::Property::ORIENTATION));
1009 constraint.AddSource(Source(rootJoint, Actor::Property::POSITION));
1012 for (auto j : r.second)
1015 auto joint = rootJoint.FindChildByName(node->mName);
1016 ConfigureJointMatrix(joint, rootJoint, propJointMatrix);
1021 void SceneDefinition::EnsureUniqueSkinningShaderInstances(ResourceBundle& resources) const
1023 std::map<Index, std::map<Index, std::vector<Index*>>> skinningShaderUsers;
1024 for (auto& node : mNodes)
1026 if (node->mRenderable)
1028 ResourceReflector reflector;
1029 node->mRenderable->ReflectResources(reflector);
1031 if (reflector.iMesh)
1033 const auto& mesh = resources.mMeshes[*reflector.iMesh].first;
1034 if (mesh.IsSkinned())
1036 skinningShaderUsers[*reflector.iShader][mesh.mSkeletonIdx].push_back(reflector.iShader);
1042 // For each shader, and each skeleton using the same shader as the first skeleton,
1043 // update the shader references (from nodes with skinned meshes) with a new copy of
1044 // the shader definition from the node using the first skeleton.
1045 for (auto& users : skinningShaderUsers)
1047 auto& skeletons = users.second;
1048 auto iterSkeleton = skeletons.begin();
1049 // skipping the first skeleton.
1052 resources.mShaders.reserve(resources.mShaders.size() + std::distance(iterSkeleton, skeletons.end()));
1053 const ShaderDefinition& shaderDef = resources.mShaders[users.first].first;
1055 while (iterSkeleton != skeletons.end())
1057 Index iShader = resources.mShaders.size();
1058 resources.mShaders.push_back({ shaderDef, Shader() });
1060 for (auto& i : iterSkeleton->second)
1069 void SceneDefinition::ConfigureSkinningShaders(const ResourceBundle& resources,
1070 Actor rootActor, std::vector<SkinningShaderConfigurationRequest>&& requests) const
1072 if (requests.empty())
1077 SortAndDeduplicateSkinningRequests(requests);
1079 for (auto& i : requests)
1081 auto& skeleton = resources.mSkeletons[i.mSkeletonIdx];
1082 if (skeleton.mJoints.empty())
1084 LOGD(("Skeleton %d has no joints.", i.mSkeletonIdx));
1089 for (auto& j : skeleton.mJoints)
1091 auto node = GetNode(j.mNodeIdx);
1092 Actor actor = rootActor.FindChildByName(node->mName);
1093 ConfigureBoneMatrix(j.mInverseBindMatrix, actor, i.mShader, boneIdx);
1098 bool SceneDefinition::ConfigureBlendshapeShaders(const ResourceBundle& resources,
1099 Actor rootActor, std::vector<BlendshapeShaderConfigurationRequest>&& requests,
1100 StringCallback onError ) const
1102 if (requests.empty())
1107 // Sort requests by shaders.
1108 std::sort(requests.begin(), requests.end());
1110 // Remove duplicates.
1111 auto i = requests.begin();
1112 auto iEnd = requests.end();
1113 Shader s = i->mShader;
1117 // Multiple identical shader instances are removed.
1118 while (i != iEnd && i->mShader == s)
1120 i->mShader = Shader();
1132 requests.erase(std::remove_if(requests.begin(), requests.end(), [](const BlendshapeShaderConfigurationRequest& bscr)
1134 return !bscr.mShader;
1135 }), requests.end());
1137 // Configure the rest.
1140 for (auto& i : requests)
1143 if (FindNode(i.mNodeName, &iNode))
1145 const auto& node = GetNode(iNode);
1147 const auto& mesh = resources.mMeshes[i.mMeshIdx];
1149 if (mesh.first.HasBlendShapes())
1151 Actor actor = rootActor.FindChildByName(node->mName);
1153 // Sets the property to be animated.
1154 BlendShapes::ConfigureProperties(mesh, i.mShader, actor);
1162 void SceneDefinition::EnsureUniqueBlendShapeShaderInstances(ResourceBundle& resources) const
1164 std::map<Index, std::map<std::string, std::vector<Index*>>> blendShapeShaderUsers;
1165 for (auto& node : mNodes)
1167 if (node->mRenderable)
1169 ResourceReflector reflector;
1170 node->mRenderable->ReflectResources(reflector);
1172 if (reflector.iMesh)
1174 const auto& mesh = resources.mMeshes[*reflector.iMesh].first;
1175 if (mesh.HasBlendShapes())
1177 blendShapeShaderUsers[*reflector.iShader][node->mName].push_back(reflector.iShader);
1183 for (auto& users : blendShapeShaderUsers)
1185 resources.mShaders.reserve(resources.mShaders.size() + users.second.size() - 1u);
1186 const ShaderDefinition& shaderDef = resources.mShaders[users.first].first;
1188 auto nodesIt = users.second.begin();
1189 auto nodesEndIt = users.second.end();
1190 // skipping the first node.
1192 while(nodesIt != nodesEndIt)
1194 Index iShader = resources.mShaders.size();
1195 resources.mShaders.push_back({ shaderDef, Shader() });
1197 auto& nodes = *nodesIt;
1198 for (auto& shader : nodes.second)
1207 SceneDefinition& SceneDefinition::operator=(SceneDefinition&& other)
1209 SceneDefinition temp(std::move(other));
1210 std::swap(mNodes, temp.mNodes);
1211 std::swap(mRootNodeIds, temp.mRootNodeIds);
1215 bool SceneDefinition::FindNode(const std::string& name, std::unique_ptr<NodeDefinition>** result)
1217 // We're searching from the end assuming a higher probability of operations targeting
1218 // recently added nodes. (conf.: root, which is immovable, cannot be removed, and was
1219 // the first to be added, is index 0.)
1220 auto iFind = std::find_if(mNodes.rbegin(), mNodes.rend(),
1221 [&name](const std::unique_ptr<NodeDefinition>& nd) {
1222 return nd->mName == name;
1225 const bool success = iFind != mNodes.begin();
1226 if (success && result)