X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali-scene3d%2Fpublic-api%2Floader%2Fscene-definition.cpp;h=7d2805371b566b6e6550b73ff087b2af947a4f08;hb=HEAD;hp=f41422e1580265f632f7c2c82ed779c3cf97dc12;hpb=c70520ff81c009acafc2a2cfd1ac38adb64ffcae;p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git diff --git a/dali-scene3d/public-api/loader/scene-definition.cpp b/dali-scene3d/public-api/loader/scene-definition.cpp index f41422e..7d28053 100644 --- a/dali-scene3d/public-api/loader/scene-definition.cpp +++ b/dali-scene3d/public-api/loader/scene-definition.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,19 +15,22 @@ * */ -// EXTERNAL -#include "dali/devel-api/common/map-wrapper.h" -#include "dali/public-api/animation/constraints.h" +// CLASS HEADER +#include + +// EXTERNAL INCLUDES +#include +#include // INTERNAL -#include "dali-scene3d/internal/graphics/builtin-shader-extern-gen.h" -#include "dali-scene3d/public-api/loader/blend-shape-details.h" -#include "dali-scene3d/public-api/loader/scene-definition.h" -#include "dali-scene3d/public-api/loader/skinning-details.h" -#include "dali-scene3d/public-api/loader/utils.h" +#include +#include +#include +#include +#include -//#define DEBUG_SCENE_DEFINITION -//#define DEBUG_JOINTS +// #define DEBUG_SCENE_DEFINITION +// #define DEBUG_JOINTS #if defined(DEBUG_SCENE_DEFINITION) || defined(DEBUG_JOINTS) #define DEBUG_ONLY(x) x @@ -37,58 +40,52 @@ #define LOGD(x) DEBUG_ONLY(printf x; printf("\n"); fflush(stdout)) -namespace Dali -{ -namespace Scene3D -{ -namespace Loader +namespace Dali::Scene3D::Loader { namespace { -const char* JOINT_MATRIX{"jointMatrix"}; - -const std::map sConstraintFactory = { - {Property::Type::BOOLEAN, - [](Actor& a, Property::Index i) { - return Constraint::New(a, i, [](bool& current, const PropertyInputContainer& inputs) { - current = inputs[0]->GetBoolean(); - }); - }}, - {Property::Type::INTEGER, - [](Actor& a, Property::Index i) { - return Constraint::New(a, i, [](int& current, const PropertyInputContainer& inputs) { - current = inputs[0]->GetInteger(); - }); - }}, - {Property::Type::FLOAT, - [](Actor& a, Property::Index i) { - return Constraint::New(a, i, EqualToConstraint()); - }}, - {Property::Type::VECTOR2, - [](Actor& a, Property::Index i) { - return Constraint::New(a, i, EqualToConstraint()); - }}, - {Property::Type::VECTOR3, - [](Actor& a, Property::Index i) { - return Constraint::New(a, i, EqualToConstraint()); - }}, - {Property::Type::VECTOR4, - [](Actor& a, Property::Index i) { - return Constraint::New(a, i, EqualToConstraint()); - }}, - {Property::Type::MATRIX, - [](Actor& a, Property::Index i) { - return Constraint::New(a, i, EqualToConstraint()); - }}, - {Property::Type::MATRIX3, - [](Actor& a, Property::Index i) { - return Constraint::New(a, i, EqualToConstraint()); - }}, - {Property::Type::ROTATION, - [](Actor& a, Property::Index i) { - return Constraint::New(a, i, EqualToConstraint()); - }}, -}; +const std::map& GetConstraintFactory() +{ + static const std::map sConstraintFactory = { + {Property::Type::BOOLEAN, + [](Actor& a, Property::Index i) { + return Constraint::New(a, i, [](bool& current, const PropertyInputContainer& inputs) { current = inputs[0]->GetBoolean(); }); + }}, + {Property::Type::INTEGER, + [](Actor& a, Property::Index i) { + return Constraint::New(a, i, [](int& current, const PropertyInputContainer& inputs) { current = inputs[0]->GetInteger(); }); + }}, + {Property::Type::FLOAT, + [](Actor& a, Property::Index i) { + return Constraint::New(a, i, EqualToConstraint()); + }}, + {Property::Type::VECTOR2, + [](Actor& a, Property::Index i) { + return Constraint::New(a, i, EqualToConstraint()); + }}, + {Property::Type::VECTOR3, + [](Actor& a, Property::Index i) { + return Constraint::New(a, i, EqualToConstraint()); + }}, + {Property::Type::VECTOR4, + [](Actor& a, Property::Index i) { + return Constraint::New(a, i, EqualToConstraint()); + }}, + {Property::Type::MATRIX, + [](Actor& a, Property::Index i) { + return Constraint::New(a, i, EqualToConstraint()); + }}, + {Property::Type::MATRIX3, + [](Actor& a, Property::Index i) { + return Constraint::New(a, i, EqualToConstraint()); + }}, + {Property::Type::ROTATION, + [](Actor& a, Property::Index i) { + return Constraint::New(a, i, EqualToConstraint()); + }}, + }; + return sConstraintFactory; +} struct ResourceReflector : IResourceReflector { @@ -124,7 +121,7 @@ void EnsureJointDebugShaderCreated() { if(0 == sNumScenes) { - sJointDebugShader = Shader::New(SHADER_SCENE3D_JOINT_DEBUG_VERT, SHADER_SCENE3D_JOINT_DEBUG_FRAG); + sJointDebugShader = Shader::New(SHADER_SCENE3D_JOINT_DEBUG_VERT, SHADER_SCENE3D_JOINT_DEBUG_FRAG, Shader::Hint::NONE, "SCENE3D_JOINT_DEBUG"); } ++sNumScenes; } @@ -162,7 +159,7 @@ void AddJointDebugVisual(Actor aJoint) aJoint.SetVisible(true); } -#endif //DEBUG_JOINTS +#endif // DEBUG_JOINTS class ActorCreatorVisitor : public NodeDefinition::IVisitor { @@ -176,7 +173,7 @@ public: { mCreationContext.mXforms.modelStack.Push(n.GetLocalSpace()); - Actor a = n.CreateActor(mCreationContext); + ModelNode a = n.CreateModelNode(mCreationContext); if(!mActorStack.empty()) { mActorStack.back().Add(a); @@ -194,130 +191,57 @@ public: mCreationContext.mXforms.modelStack.Pop(); } - Actor GetRoot() const + ModelNode GetRoot() const { return mRoot; } private: NodeDefinition::CreateParams& mCreationContext; - std::vector mActorStack; - Actor mRoot; + std::vector mActorStack; + ModelNode mRoot; }; -bool IsAncestor(const SceneDefinition& scene, Index ancestor, Index node, Index rootHint = INVALID_INDEX) -{ - bool isAncestor = false; - while(node != rootHint && !isAncestor) - { - node = scene.GetNode(node)->mParentIdx; - isAncestor = ancestor == node; - } - return isAncestor; -} - -void InsertUniqueSorted(std::vector& data, Index value) -{ - auto iInsert = std::lower_bound(data.begin(), data.end(), value); - if(iInsert == data.end() || *iInsert != value) - { - data.insert(iInsert, value); - } -} - -void RemoveFromSorted(std::vector& data, Index value) -{ - auto iRemove = std::lower_bound(data.begin(), data.end(), value); - if(iRemove != data.end() && *iRemove == value) - { - data.erase(iRemove); - } -} - -Property::Index ConfigureJointMatrix(Actor actor, Actor ancestor, Property::Index propJointMatrix) -{ - Actor parent = actor.GetParent(); - if(parent != ancestor) - { - propJointMatrix = ConfigureJointMatrix(parent, ancestor, propJointMatrix); - } - - auto myPropJointMatrix = actor.GetPropertyIndex(JOINT_MATRIX); - if(myPropJointMatrix == Property::INVALID_INDEX) - { - myPropJointMatrix = actor.RegisterProperty(JOINT_MATRIX, Matrix{false}); - Constraint constraint = Constraint::New(actor, propJointMatrix, [](Matrix& output, const PropertyInputContainer& inputs) { - Matrix jointMatrix{false}; - jointMatrix.SetTransformComponents(Vector3::ONE, inputs[0]->GetQuaternion(), inputs[1]->GetVector3()); - - Matrix::Multiply(output, jointMatrix, inputs[2]->GetMatrix()); - }); - constraint.AddSource(Source{actor, Actor::Property::ORIENTATION}); - constraint.AddSource(Source{actor, Actor::Property::POSITION}); - constraint.AddSource(Source{parent, propJointMatrix}); - constraint.Apply(); - } - - return myPropJointMatrix; -} - -void SortAndDeduplicateSkinningRequests(std::vector& requests) +template +void SortAndDeduplicateRequests(std::vector& requests) { - // Sort requests by shaders. + // Sort requests by shaders and primitives. std::sort(requests.begin(), requests.end()); // Remove duplicates. - auto i = requests.begin(); - auto iEnd = requests.end(); - Shader s = i->mShader; - Index skeletonIdx = i->mSkeletonIdx; - ++i; + auto iter = requests.begin(); + auto iterEnd = requests.end(); + + Shader shader = iter->mShader; + ModelPrimitive modelPrimitive = iter->mPrimitive; + ++iter; do { - // Multiple identical shader instances are removed. - while(i != iEnd && i->mShader == s) + // Multiple identical shader and primitive instances are removed. + while(iter != iterEnd && iter->mShader == shader && iter->mPrimitive == modelPrimitive) { - // Cannot have multiple skeletons input to the same shader. - // NOTE: DliModel now makes sure this doesn't happen. - DALI_ASSERT_ALWAYS(i->mSkeletonIdx == skeletonIdx && - "Skinning shader must not be shared between different skeletons."); - - i->mShader = Shader(); - ++i; + // Mark as removed + iter->mShader = Shader(); + ++iter; } - if(i == iEnd) + if(iter == iterEnd) { break; } - s = i->mShader; - skeletonIdx = i->mSkeletonIdx; - ++i; + shader = iter->mShader; + modelPrimitive = iter->mPrimitive; + ++iter; } while(true); - requests.erase(std::remove_if(requests.begin(), requests.end(), [](const SkinningShaderConfigurationRequest& sscr) { - return !sscr.mShader; - }), + requests.erase(std::remove_if(requests.begin(), requests.end(), [](const RequestType& sscr) { return !sscr.mShader; }), requests.end()); } -void ConfigureBoneMatrix(const Matrix& ibm, Actor joint, Shader& shader, Index& boneIdx) +void ConfigureBoneMatrix(const Matrix& ibm, ModelNode joint, ModelPrimitive primitive, Index& boneIdx) { // Register bone transform on shader. - char propertyNameBuffer[32]; - snprintf(propertyNameBuffer, sizeof(propertyNameBuffer), "%s[%d]", Skinning::BONE_UNIFORM_NAME, boneIdx); - DALI_ASSERT_DEBUG(shader.GetPropertyIndex(propertyNameBuffer) == Property::INVALID_INDEX); - auto propBoneXform = shader.RegisterProperty(propertyNameBuffer, Matrix{false}); - - // Constrain bone matrix to joint transform. - Constraint constraint = Constraint::New(shader, propBoneXform, [ibm](Matrix& output, const PropertyInputContainer& inputs) { - Matrix::Multiply(output, ibm, inputs[0]->GetMatrix()); - }); - - auto propJointMatrix = joint.GetPropertyIndex(JOINT_MATRIX); - constraint.AddSource(Source{joint, propJointMatrix}); - constraint.Apply(); - + Internal::GetImplementation(joint).SetBoneMatrix(ibm, primitive, boneIdx); ++boneIdx; } @@ -447,7 +371,10 @@ void SceneDefinition::CountResourceRefs(Index iNode, const Customization::Choice void Register(ResourceType::Value type, Index id) { - ++(*refCounts)[type][id]; + if((!(*refCounts)[type].Empty()) && ((*refCounts)[type].Size() > id)) + { + ++(*refCounts)[type][id]; + } } }; @@ -473,7 +400,7 @@ void SceneDefinition::CountResourceRefs(Index iNode, const Customization::Choice Visit(iNode, choices, refCounterVisitor); } -Actor SceneDefinition::CreateNodes(Index iNode, const Customization::Choices& choices, NodeDefinition::CreateParams& params) +ModelNode SceneDefinition::CreateNodes(Index iNode, const Customization::Choices& choices, NodeDefinition::CreateParams& params) { ActorCreatorVisitor actorCreatorVisitor(params); @@ -562,8 +489,7 @@ bool SceneDefinition::ReparentNode(const std::string& name, const std::string& n { stream << i << ", "; } - LOGD(("%s", stream.str().c_str())); - };) + LOGD(("%s", stream.str().c_str())); };) // Remove node from children of previous parent (if any). if(node->mParentIdx != INVALID_INDEX) @@ -695,9 +621,7 @@ NodeDefinition* SceneDefinition::FindNode(const std::string& name, Index* outInd { auto iBegin = mNodes.begin(); auto iEnd = mNodes.end(); - auto iFind = std::find_if(iBegin, iEnd, [&name](const std::unique_ptr& nd) { - return nd->mName == name; - }); + auto iFind = std::find_if(iBegin, iEnd, [&name](const std::unique_ptr& nd) { return nd->mName == name; }); auto result = iFind != iEnd ? iFind->get() : nullptr; if(result && outIndex) @@ -711,9 +635,7 @@ const NodeDefinition* SceneDefinition::FindNode(const std::string& name, Index* { auto iBegin = mNodes.begin(); auto iEnd = mNodes.end(); - auto iFind = std::find_if(iBegin, iEnd, [&name](const std::unique_ptr& nd) { - return nd->mName == name; - }); + auto iFind = std::find_if(iBegin, iEnd, [&name](const std::unique_ptr& nd) { return nd->mName == name; }); auto result = iFind != iEnd ? iFind->get() : nullptr; if(result && outIndex) @@ -727,9 +649,7 @@ Index SceneDefinition::FindNodeIndex(const NodeDefinition& node) const { auto iBegin = mNodes.begin(); auto iEnd = mNodes.end(); - auto iFind = std::find_if(iBegin, iEnd, [&node](const std::unique_ptr& n) { - return n.get() == &node; - }); + auto iFind = std::find_if(iBegin, iEnd, [&node](const std::unique_ptr& n) { return n.get() == &node; }); return iFind != iEnd ? std::distance(iBegin, iFind) : INVALID_INDEX; } @@ -779,8 +699,8 @@ void SceneDefinition::ApplyConstraints(Actor& root, if(iTarget != Property::INVALID_INDEX) { auto propertyType = cr.mTarget.GetPropertyType(iTarget); - auto iFind = sConstraintFactory.find(propertyType); - if(iFind == sConstraintFactory.end()) + auto iFind = GetConstraintFactory().find(propertyType); + if(iFind == GetConstraintFactory().end()) { onError(FormatString("node '%s': Property '%s' has unsupported type '%s'; ignored.", sourceName, @@ -824,167 +744,6 @@ void SceneDefinition::ApplyConstraints(Actor& root, } } -void SceneDefinition::ConfigureSkeletonJoints(uint32_t iRoot, const SkeletonDefinition::Vector& skeletons, Actor root) const -{ - // 1, For each skeleton, for each joint, walk upwards until we reach mNodes[iRoot]. If we do, record +1 - // to the refcount of each node we have visited, in our temporary registry. Those with refcount 1 - // are the leaves, while the most descendant node with the highest refcount is the root of the skeleton. - std::map> rootsJoints; - std::vector path; - path.reserve(16); - for(auto& s : skeletons) - { - std::map jointRefs; - for(auto& j : s.mJoints) - { - auto nodeIdx = j.mNodeIdx; - do // Traverse upwards and record each node we have visited until we reach the scene root. - { - path.push_back(nodeIdx); - if(nodeIdx == iRoot) - { - break; - } - auto node = GetNode(nodeIdx); - nodeIdx = node->mParentIdx; - } while(nodeIdx != INVALID_INDEX); - - if(nodeIdx == iRoot) // If the joint is in the correct scene, increment the reference count for all visited nodes. - { - for(auto i : path) - { - ++jointRefs[i]; - } - } - - path.clear(); - } - - // Only record the skeleton if we have encountered the root of the current scene. - if(jointRefs.empty()) - { - continue; - } - - Index root = s.mRootNodeIdx; - uint32_t maxRef = 0; - auto iFind = jointRefs.find(root); - if(iFind != jointRefs.end()) - { - maxRef = iFind->second; - } - - std::vector joints; - for(auto& j : jointRefs) // NOTE: jointRefs are sorted, so joints will also be. - { - // The most descendant node with the highest ref count is the root of the skeleton. - if(j.second > maxRef || (j.second == maxRef && IsAncestor(*this, root, j.first, iRoot))) - { - maxRef = j.second; - - RemoveFromSorted(joints, root); - root = j.first; - } - else if(j.second == 1) // This one's a leaf. - { - InsertUniqueSorted(joints, j.first); - } - } - - // Merge skeletons that share the same root. - auto& finalJoints = rootsJoints[root]; - for(auto j : joints) - { - if(std::find_if(finalJoints.begin(), finalJoints.end(), [this, j, root](Index jj) { - return IsAncestor(*this, j, jj, root); - }) != finalJoints.end()) - { - continue; // if the joint is found to be an ancestor of another joint already registered, move on. - } - - auto i = j; - while(i != root) // See if the current joint is a better leaf, i.e. descended from another leaf - which we'll then remove. - { - auto node = GetNode(i); - i = node->mParentIdx; - - RemoveFromSorted(finalJoints, i); - } - - InsertUniqueSorted(finalJoints, j); - } - } - - // 2, Merge records where one root joint is descendant of another. Handle leaf node changes - remove previous - // leaf nodes that now have descendants, and add new ones. - auto iRoots = rootsJoints.begin(); - auto iRootsEnd = rootsJoints.end(); - while(iRoots != iRootsEnd) - { - auto i = iRoots->first; - bool merged = false; - while(i != iRoot) // Starting with the root joint of the skeleton, traverse upwards. - { - auto node = GetNode(i); - i = node->mParentIdx; - - auto iFind = rootsJoints.find(i); - if(iFind != rootsJoints.end()) // Check if we've reached the root of another skeleton. - { - // Now find out which leaf of iFind is an ancestor, if any. - auto iFindLeaf = std::find_if(iFind->second.begin(), iFind->second.end(), [this, iRoots, iFind](Index j) { - return IsAncestor(*this, j, iRoots->first, iFind->first); - }); - if(iFindLeaf != iFind->second.end()) - { - iFind->second.erase(iFindLeaf); // Will no longer be a leaf -- remove it. - } - - // Merge iRoots with iFind - auto& targetJoints = iFind->second; - if(iRoots->second.empty()) // The root is a leaf. - { - InsertUniqueSorted(targetJoints, iRoots->first); - } - else - for(auto j : iRoots->second) - { - InsertUniqueSorted(targetJoints, j); - } - - merged = true; - break; // Traverse no more - } - } - - iRoots = merged ? rootsJoints.erase(iRoots) : std::next(iRoots); - } - - // 3, For each root, register joint matrices and constraints - for(const auto& r : rootsJoints) - { - auto node = GetNode(r.first); - auto rootJoint = root.FindChildByName(node->mName); - DALI_ASSERT_ALWAYS(!!rootJoint); - - DALI_ASSERT_DEBUG(rootJoint.GetPropertyIndex(JOINT_MATRIX) == Property::INVALID_INDEX); - auto propJointMatrix = rootJoint.RegisterProperty(JOINT_MATRIX, Matrix{false}); - Constraint constraint = Constraint::New(rootJoint, propJointMatrix, [](Matrix& output, const PropertyInputContainer& inputs) { - output.SetTransformComponents(Vector3::ONE, inputs[0]->GetQuaternion(), inputs[1]->GetVector3()); - }); - constraint.AddSource(Source(rootJoint, Actor::Property::ORIENTATION)); - constraint.AddSource(Source(rootJoint, Actor::Property::POSITION)); - constraint.Apply(); - - for(const auto j : r.second) - { - node = GetNode(j); - auto joint = rootJoint.FindChildByName(node->mName); - ConfigureJointMatrix(joint, rootJoint, propJointMatrix); - } - } -} - void SceneDefinition::EnsureUniqueSkinningShaderInstances(ResourceBundle& resources) const { std::map>> skinningShaderUsers; @@ -1042,7 +801,7 @@ void SceneDefinition::ConfigureSkinningShaders(const ResourceBundle& return; } - SortAndDeduplicateSkinningRequests(requests); + SortAndDeduplicateRequests(requests); for(auto& request : requests) { @@ -1056,9 +815,13 @@ void SceneDefinition::ConfigureSkinningShaders(const ResourceBundle& Index boneIdx = 0; for(auto& joint : skeleton.mJoints) { - auto node = GetNode(joint.mNodeIdx); - Actor actor = rootActor.FindChildByName(node->mName); - ConfigureBoneMatrix(joint.mInverseBindMatrix, actor, request.mShader, boneIdx); + auto node = GetNode(joint.mNodeIdx); + ModelNode modelNode = ModelNode::DownCast(rootActor.FindChildByName(node->mName)); + if(!modelNode) + { + continue; + } + ConfigureBoneMatrix(joint.mInverseBindMatrix, modelNode, request.mPrimitive, boneIdx); } } } @@ -1073,49 +836,45 @@ bool SceneDefinition::ConfigureBlendshapeShaders(const ResourceBundle& return true; } - // Sort requests by shaders. - std::sort(requests.begin(), requests.end()); - - // Remove duplicates. - auto i = requests.begin(); - auto iEnd = requests.end(); - Shader s = i->mShader; - ++i; - do - { - // Multiple identical shader instances are removed. - while(i != iEnd && i->mShader == s) - { - i->mShader = Shader(); - ++i; - } - - if(i == iEnd) - { - break; - } - s = i->mShader; - ++i; - } while(true); + SortAndDeduplicateRequests(requests); // Configure the rest. bool ok = true; - for(auto& i : requests) + for(auto& request : requests) { Index iNode; - if(FindNode(i.mNodeName, &iNode)) + if(FindNode(request.mNodeName, &iNode)) { const auto& node = GetNode(iNode); - const auto& mesh = resources.mMeshes[i.mMeshIdx]; + const auto& mesh = resources.mMeshes[request.mMeshIdx]; if(mesh.first.HasBlendShapes()) { - Actor actor = rootActor.FindChildByName(node->mName); - - // Sets the property to be animated. - BlendShapes::ConfigureProperties(mesh, i.mShader, actor); + Actor actor = rootActor.FindChildByName(node->mName); + Scene3D::ModelNode node = Scene3D::ModelNode::DownCast(actor); + if(!node) + { + continue; + } + BlendShapes::BlendShapeData data; + data.components = 0x0; + for(auto&& blendShape : mesh.first.mBlendShapes) + { + data.names.push_back(blendShape.name); + data.weights.push_back(blendShape.weight); + data.components |= (blendShape.deltas.IsDefined() * BlendShapes::Component::POSITIONS) | + (blendShape.normals.IsDefined() * BlendShapes::Component::NORMALS) | (blendShape.tangents.IsDefined() * BlendShapes::Component::TANGENTS); + } + for(auto&& factor : mesh.second.blendShapeUnnormalizeFactor) + { + data.unnormalizeFactors.push_back(factor); + } + data.version = mesh.first.mBlendShapeVersion; + data.bufferOffset = mesh.second.blendShapeBufferOffset; + data.mActor = actor; + Internal::GetImplementation(node).SetBlendShapeData(data, request.mPrimitive); } } } @@ -1181,9 +940,8 @@ bool SceneDefinition::FindNode(const std::string& name, std::unique_ptr& nd) { - return nd->mName == name; - }).base(); + auto iFind = std::find_if(mNodes.rbegin(), mNodes.rend(), [&name](const std::unique_ptr& nd) { return nd->mName == name; }) + .base(); const bool success = iFind != mNodes.begin(); if(success && result) @@ -1195,6 +953,4 @@ bool SceneDefinition::FindNode(const std::string& name, std::unique_ptr