Allow duplicated name and use Actor ID as a unique key to define animation. 92/285392/11
authorseungho baek <sbsh.baek@samsung.com>
Mon, 12 Dec 2022 05:26:05 +0000 (14:26 +0900)
committerseungho baek <sbsh.baek@samsung.com>
Wed, 14 Dec 2022 03:26:29 +0000 (12:26 +0900)
 - We don't need to make crash when multiple nodes had same name.
 - DALi actor also allows duplicated name.
 - Because name is not an unique key, make AnimationDefinition use Actor ID as a key.(for glTF)
    - glTF don't use name as a key.

Change-Id: Ibcb3e21640cf2a8124bb450b73159eeaf1cdf4f3
Signed-off-by: seungho baek <sbsh.baek@samsung.com>
18 files changed:
automated-tests/resources/AnimatedCube.gltf
automated-tests/resources/BoxAnimated.gltf
automated-tests/src/dali-scene3d/utc-Dali-AnimatedProperty.cpp
automated-tests/src/dali-scene3d/utc-Dali-AnimationDefinition.cpp
automated-tests/src/dali-scene3d/utc-Dali-BvhLoader.cpp
automated-tests/src/dali-scene3d/utc-Dali-DliLoader.cpp
automated-tests/src/dali-scene3d/utc-Dali-FacialAnimation.cpp
automated-tests/src/dali-scene3d/utc-Dali-Gltf2Loader.cpp
automated-tests/src/dali-scene3d/utc-Dali-NodeDefinition.cpp
automated-tests/src/dali-scene3d/utc-Dali-SceneDefinition.cpp
dali-scene3d/internal/controls/model/model-impl.cpp
dali-scene3d/public-api/loader/animated-property.cpp
dali-scene3d/public-api/loader/animated-property.h
dali-scene3d/public-api/loader/gltf2-loader.cpp
dali-scene3d/public-api/loader/node-definition.cpp
dali-scene3d/public-api/loader/node-definition.h
dali-scene3d/public-api/loader/scene-definition.cpp
dali-scene3d/public-api/loader/scene-definition.h

index 455120d..7787c04 100644 (file)
       },
       {
          "mesh" : 1,
-         "name" : "AnimatedCube2"
+         "name" : "AnimatedCube"
       },
       {
 
index afa7afb..82e9702 100644 (file)
@@ -14,6 +14,7 @@
     ],\r
     "nodes": [\r
         {\r
+            "name" : "node0",\r
             "children": [\r
                 1\r
             ],\r
             ]\r
         },\r
         {\r
+            "name" : "node1",\r
             "children": [\r
                 2\r
             ]\r
         },\r
         {\r
+            "name" : "node2",\r
             "mesh": 0,\r
             "rotation": [\r
                 -0.0,\r
@@ -39,6 +42,7 @@
             ]\r
         },\r
         {\r
+            "name" : "node3",\r
             "mesh": 1\r
         }\r
     ],\r
index 0a59e26..6c4502f 100644 (file)
@@ -31,6 +31,7 @@ int UtcDaliAnimatedPropertyGetPropertyType(void)
   actor.SetProperty(Actor::Property::NAME, "ChristopherPlummer");
 
   AnimatedProperty animProp {
+    INVALID_INDEX,
    "ChristopherPlummer",
    "position",
    KeyFrames(),
index 5cde1b9..99b0aaf 100644 (file)
@@ -44,8 +44,8 @@ int UtcDaliAnimationDefinitionReAnimate(void)
   auto actor = Actor::New();
   actor.SetProperty(Actor::Property::NAME, "ChristopherPlummer");
 
-  auto getActor = [&actor](const std::string& name) {
-    return actor.FindChildByName(name);
+  auto getActor = [&actor](const Dali::Scene3D::Loader::AnimatedProperty& property) {
+    return actor.FindChildByName(property.mNodeName);
   };
 
   for (bool b: { false, true })
@@ -57,6 +57,7 @@ int UtcDaliAnimationDefinitionReAnimate(void)
     animDef.mEndAction = Animation::BAKE_FINAL;
     animDef.mSpeedFactor = .7f;
     animDef.mProperties.push_back(AnimatedProperty{
+     INVALID_INDEX,
      "ChristopherPlummer",
      "position",
      KeyFrames(),
@@ -84,8 +85,8 @@ int UtcDaliAnimationDefinitionReAnimateKeyFrames(void)
   auto actor = Actor::New();
   actor.SetProperty(Actor::Property::NAME, "ChristopherPlummer");
 
-  auto getActor = [&actor](const std::string& name) {
-    return actor.FindChildByName(name);
+  auto getActor = [&actor](const Dali::Scene3D::Loader::AnimatedProperty& property) {
+    return actor.FindChildByName(property.mNodeName);
   };
 
   KeyFrames kf = KeyFrames::New();
@@ -99,6 +100,7 @@ int UtcDaliAnimationDefinitionReAnimateKeyFrames(void)
   animDef.mEndAction = Animation::BAKE_FINAL;
   animDef.mSpeedFactor = .7f;
   animDef.mProperties.push_back(AnimatedProperty{
+   INVALID_INDEX,
    "ChristopherPlummer",
    "position",
    kf,
index 91fdb19..db5f525 100644 (file)
@@ -57,8 +57,8 @@ int UtcDaliLoadBvh(void)
   first.SetProperty(Actor::Property::NAME, "first");
   root.Add(first);
 
-  auto getActor = [&root](const std::string& name) {
-    return root.FindChildByName(name);
+  auto getActor = [&root](const Dali::Scene3D::Loader::AnimatedProperty& property) {
+    return root.FindChildByName(property.mNodeName);
   };
 
   Animation animation = animDef.ReAnimate(getActor);
index c663327..9d67ab4 100644 (file)
@@ -169,7 +169,6 @@ int UtcDaliDliLoaderLoadSceneAssertions(void)
     {"node-renderable-mesh-invalid-type", "Invalid Mesh index type"},
     {"node-renderable-mesh-out-of-bounds", "out of bounds"},
     {"node-child-invalid-type", "invalid index type"},
-    {"node-name-already-used", "name already used"},
     // from ParseAnimations()
     {"animation-failed-to-open", "Failed to open animation data"}};
   for(auto& i : pathExceptionPairs)
index 22692e0..2e97dc9 100644 (file)
@@ -77,8 +77,8 @@ int UtcDaliLoadFacialAnimation(void)
     actor.RegisterProperty(weightName, 0.0f);
   }
 
-  auto getActor = [&actor](const std::string& name) {
-    return actor.FindChildByName(name);
+  auto getActor = [&actor](const Dali::Scene3D::Loader::AnimatedProperty& property) {
+    return actor.FindChildByName(property.mNodeName);
   };
 
   auto anim = animDef.ReAnimate(getActor);
index eb19c4d..f7f20cd 100644 (file)
@@ -546,3 +546,59 @@ int UtcDaliGltfLoaderMRendererTest(void)
 
   END_TEST;
 }
+
+
+int UtcDaliGltfLoaderAnimationLoadingTest(void)
+{
+  Context ctx;
+
+  ShaderDefinitionFactory sdf;
+  sdf.SetResources(ctx.resources);
+  auto& resources = ctx.resources;
+
+  LoadGltfScene(TEST_RESOURCE_DIR "/BoxAnimated.gltf", sdf, ctx.loadResult);
+
+  auto& scene = ctx.scene;
+  auto& roots = scene.GetRoots();
+  DALI_TEST_EQUAL(roots.size(), 1u);
+
+  ViewProjection viewProjection;
+  Transforms     xforms{
+    MatrixStack{},
+    viewProjection};
+  NodeDefinition::CreateParams nodeParams{
+    resources,
+    xforms,
+  };
+
+  Customization::Choices choices;
+
+  TestApplication app;
+
+  Actor root = Actor::New();
+  SetActorCentered(root);
+  for(auto iRoot : roots)
+  {
+    auto resourceRefs = resources.CreateRefCounter();
+    scene.CountResourceRefs(iRoot, choices, resourceRefs);
+    resources.CountEnvironmentReferences(resourceRefs);
+    resources.LoadResources(resourceRefs, ctx.pathProvider);
+    if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
+    {
+      scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor);
+      scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
+      scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
+      root.Add(actor);
+    }
+  }
+
+  DALI_TEST_EQUAL(ctx.loadResult.mAnimationDefinitions.size(), 1u);
+  DALI_TEST_EQUAL(ctx.loadResult.mAnimationDefinitions[0].mProperties.size(), 2u);
+
+  uint32_t id = ctx.loadResult.mScene.GetNode(ctx.loadResult.mAnimationDefinitions[0].mProperties[0].mNodeIndex)->mNodeId;
+  DALI_TEST_EQUAL(id, root.FindChildByName("node2").GetProperty<int32_t>(Dali::Actor::Property::ID));
+  uint32_t id2 = ctx.loadResult.mScene.GetNode(ctx.loadResult.mAnimationDefinitions[0].mProperties[1].mNodeIndex)->mNodeId;
+  DALI_TEST_EQUAL(id2, root.FindChildByName("node0").GetProperty<int32_t>(Dali::Actor::Property::ID));
+
+  END_TEST;
+}
index 415e2e1..2b7c319 100644 (file)
@@ -101,6 +101,7 @@ int UtcDaliNodeDefinitionProperties(void)
   TestApplication testApp;
   NodeDefinition  nodeDef{
     "testRootNode",
+    INVALID_INDEX,
     Vector3{-100.f, 100.f, -500.f},
     Quaternion{Radian(Degree(45.f)), Vector3::ZAXIS},
     Vector3{2.f, 4.f, 8.f},
index dc2fc92..e7126eb 100644 (file)
@@ -42,10 +42,9 @@ int UtcDaliSceneDefinitionAddNode(void)
   auto node2 = new NodeDefinition();
   node2->mName = node->mName;
   result = sceneDef.AddNode(std::unique_ptr<NodeDefinition>{ node2 });
-  DALI_TEST_EQUAL(result, static_cast<NodeDefinition*>(nullptr)); // failed
-  DALI_TEST_EQUAL(sceneDef.GetNodeCount(), 1u); // still
-  DALI_TEST_EQUAL(sceneDef.GetNode(0), node); // still
-  DALI_TEST_EQUAL(sceneDef.FindNode(node->mName), node); // still
+  DALI_TEST_EQUAL(result, node2);
+  DALI_TEST_EQUAL(sceneDef.GetNodeCount(), 2u);
+  DALI_TEST_EQUAL(sceneDef.GetNode(1), node2);
 
   auto child = new NodeDefinition();
   child->mName = "Second";
@@ -55,11 +54,11 @@ int UtcDaliSceneDefinitionAddNode(void)
 
   result = sceneDef.AddNode(std::unique_ptr<NodeDefinition>{ child });
   DALI_TEST_EQUAL(result, child);
-  DALI_TEST_EQUAL(sceneDef.GetNodeCount(), 2u);
-  DALI_TEST_EQUAL(sceneDef.GetNode(1), child);
+  DALI_TEST_EQUAL(sceneDef.GetNodeCount(), 3u);
+  DALI_TEST_EQUAL(sceneDef.GetNode(2), child);
   DALI_TEST_EQUAL(sceneDef.FindNode(child->mName), child);
 
-  DALI_TEST_EQUAL(node->mChildren[0], 1u); // these are hooked up by AddNode, base on parent idx.
+  DALI_TEST_EQUAL(node->mChildren[0], 2u); // these are hooked up by AddNode, base on parent idx.
 
   END_TEST;
 }
index 73f1248..8b95f82 100644 (file)
@@ -507,8 +507,8 @@ void Model::LoadModel()
 
   if(!animations.empty())
   {
-    auto getActor = [&](const std::string& name) {
-      return mModelRoot.FindChildByName(name);
+    auto getActor = [&](const Scene3D::Loader::AnimatedProperty& property) {
+      return mModelRoot.FindChildById(scene.GetNode(property.mNodeIndex)->mNodeId);
     };
 
     mAnimations.clear();
index 5f15815..83ae2df 100644 (file)
@@ -24,7 +24,7 @@ namespace Loader
 {
 void AnimatedProperty::Animate(Animation& anim, GetActor getActor)
 {
-  if(Actor actor = getActor(mNodeName))
+  if(Actor actor = getActor(*this))
   {
     Property prop = GetProperty(actor);
     if(mKeyFrames)
index 6433d5c..87fe87a 100644 (file)
@@ -19,6 +19,8 @@
 
 // INTERNAL INCLUDES
 #include "dali-scene3d/public-api/api.h"
+#include "dali-scene3d/public-api/loader/index.h"
+
 
 // EXTERNAL INCLUDES
 #include <functional>
@@ -44,10 +46,10 @@ struct DALI_SCENE3D_API AnimatedProperty
 {
 public: // METHODS
   /**
-   * @brief Function to obtain an Actor based on its name. Its processing will
+   * @brief Function to obtain an Actor based on its property. Its processing will
    *  ignore empty handles returned by it.
    */
-  using GetActor = std::function<Actor(const std::string&)>;
+  using GetActor = std::function<Actor(const AnimatedProperty&)>;
 
   /**
    * @return The Property object (of the given @a actor) whose value is being animated.
@@ -82,6 +84,7 @@ public: // DATA
     bool            mIsRelative;
   };
 
+  Index       mNodeIndex = INVALID_INDEX;
   std::string mNodeName;
   std::string mPropertyName;
 
index 75d7ad0..dc0eb8a 100644 (file)
@@ -951,7 +951,7 @@ float LoadKeyFrames(const std::string& path, const gt::Animation::Channel& chann
   return duration;
 }
 
-float LoadBlendShapeKeyFrames(const std::string& path, const gt::Animation::Channel& channel, const std::string& nodeName, uint32_t& propertyIndex, std::vector<Dali::Scene3D::Loader::AnimatedProperty>& properties)
+float LoadBlendShapeKeyFrames(const std::string& path, const gt::Animation::Channel& channel, Index nodeIndex, uint32_t& propertyIndex, std::vector<Dali::Scene3D::Loader::AnimatedProperty>& properties)
 {
   const gltf2::Accessor& input  = *channel.mSampler->mInput;
   const gltf2::Accessor& output = *channel.mSampler->mOutput;
@@ -969,7 +969,7 @@ float LoadBlendShapeKeyFrames(const std::string& path, const gt::Animation::Chan
   {
     AnimatedProperty& animatedProperty = properties[propertyIndex++];
 
-    animatedProperty.mNodeName = nodeName;
+    animatedProperty.mNodeIndex = nodeIndex;
     snprintf(pWeightName, remainingSize, "%d]", weightIndex);
     animatedProperty.mPropertyName = std::string(weightNameBuffer);
 
@@ -1001,27 +1001,23 @@ void ConvertAnimations(const gt::Document& doc, ConversionContext& context)
     }
 
     uint32_t numberOfProperties = 0u;
-
-    for(const auto& channel : animation.mChannels)
-    {
-      numberOfProperties += channel.mSampler->mOutput->mCount;
-    }
-    animationDef.mProperties.resize(numberOfProperties);
-
-    Index propertyIndex = 0u;
     for(const auto& channel : animation.mChannels)
     {
-      std::string nodeName;
-      if(!channel.mTarget.mNode->mName.empty())
+      if(channel.mTarget.mPath == gt::Animation::Channel::Target::WEIGHTS)
       {
-        nodeName = channel.mTarget.mNode->mName;
+        numberOfProperties += channel.mSampler->mOutput->mCount / channel.mSampler->mInput->mCount;
       }
       else
       {
-        Index index = context.mNodeIndices.GetRuntimeId(channel.mTarget.mNode.GetIndex());
-        nodeName    = context.mOutput.mScene.GetNode(index)->mName;
+        numberOfProperties++;
       }
+    }
+    animationDef.mProperties.resize(numberOfProperties);
 
+    Index propertyIndex = 0u;
+    for(const auto& channel : animation.mChannels)
+    {
+      Index nodeIndex    = context.mNodeIndices.GetRuntimeId(channel.mTarget.mNode.GetIndex());
       float duration = 0.f;
 
       switch(channel.mTarget.mPath)
@@ -1030,7 +1026,7 @@ void ConvertAnimations(const gt::Document& doc, ConversionContext& context)
         {
           AnimatedProperty& animatedProperty = animationDef.mProperties[propertyIndex];
 
-          animatedProperty.mNodeName     = nodeName;
+          animatedProperty.mNodeIndex    = nodeIndex;
           animatedProperty.mPropertyName = POSITION_PROPERTY;
 
           animatedProperty.mKeyFrames = KeyFrames::New();
@@ -1043,7 +1039,7 @@ void ConvertAnimations(const gt::Document& doc, ConversionContext& context)
         {
           AnimatedProperty& animatedProperty = animationDef.mProperties[propertyIndex];
 
-          animatedProperty.mNodeName     = nodeName;
+          animatedProperty.mNodeIndex    = nodeIndex;
           animatedProperty.mPropertyName = ORIENTATION_PROPERTY;
 
           animatedProperty.mKeyFrames = KeyFrames::New();
@@ -1056,7 +1052,7 @@ void ConvertAnimations(const gt::Document& doc, ConversionContext& context)
         {
           AnimatedProperty& animatedProperty = animationDef.mProperties[propertyIndex];
 
-          animatedProperty.mNodeName     = nodeName;
+          animatedProperty.mNodeIndex    = nodeIndex;
           animatedProperty.mPropertyName = SCALE_PROPERTY;
 
           animatedProperty.mKeyFrames = KeyFrames::New();
@@ -1067,7 +1063,7 @@ void ConvertAnimations(const gt::Document& doc, ConversionContext& context)
         }
         case gt::Animation::Channel::Target::WEIGHTS:
         {
-          duration = LoadBlendShapeKeyFrames(context.mPath, channel, nodeName, propertyIndex, animationDef.mProperties);
+          duration = LoadBlendShapeKeyFrames(context.mPath, channel, nodeIndex, propertyIndex, animationDef.mProperties);
 
           break;
         }
index bbed301..cd32bc7 100644 (file)
@@ -63,9 +63,11 @@ void NodeDefinition::Renderable::OnCreate(const NodeDefinition& node, CreatePara
 
 const std::string NodeDefinition::ORIGINAL_MATRIX_PROPERTY_NAME = "originalMatrix";
 
-Actor NodeDefinition::CreateActor(CreateParams& params) const
+Actor NodeDefinition::CreateActor(CreateParams& params)
 {
   Actor actor = Actor::New();
+  mNodeId     = actor.GetProperty<int32_t>(Dali::Actor::Property::ID);
+
   SetActorCentered(actor);
 
   actor.SetProperty(Actor::Property::NAME, mName);
index fde74e2..d713ed5 100644 (file)
@@ -218,7 +218,7 @@ public: // METHODS
    * @brief Creates a DALi Actor from this definition only.
    * @note Not recursive.
    */
-  Actor CreateActor(CreateParams& params) const;
+  Actor CreateActor(CreateParams& params);
 
   /**
    * @brief Gets local space matrix of this node
@@ -253,6 +253,7 @@ public: // DATA
   static const std::string ORIGINAL_MATRIX_PROPERTY_NAME;
 
   std::string mName;
+  uint32_t    mNodeId = INVALID_INDEX;
 
   Vector3    mPosition    = Vector3::ZERO;
   Quaternion mOrientation = Quaternion::IDENTITY;
index a117e1e..b6a2743 100644 (file)
@@ -164,7 +164,7 @@ void AddJointDebugVisual(Actor aJoint)
 }
 #endif //DEBUG_JOINTS
 
-class ActorCreatorVisitor : public NodeDefinition::IConstVisitor
+class ActorCreatorVisitor : public NodeDefinition::IVisitor
 {
 public:
   ActorCreatorVisitor(NodeDefinition::CreateParams& params)
@@ -172,7 +172,7 @@ public:
   {
   }
 
-  void Start(const NodeDefinition& n)
+  void Start(NodeDefinition& n)
   {
     mCreationContext.mXforms.modelStack.Push(n.GetLocalSpace());
 
@@ -188,7 +188,7 @@ public:
     mActorStack.push_back(a);
   }
 
-  void Finish(const NodeDefinition& n)
+  void Finish(NodeDefinition& n)
   {
     mActorStack.pop_back();
     mCreationContext.mXforms.modelStack.Pop();
@@ -469,7 +469,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) const
+Actor SceneDefinition::CreateNodes(Index iNode, const Customization::Choices& choices, NodeDefinition::CreateParams& params)
 {
   ActorCreatorVisitor actorCreatorVisitor(params);
 
@@ -526,11 +526,6 @@ void SceneDefinition::GetCustomizationOptions(const Customization::Choices& choi
 
 NodeDefinition* SceneDefinition::AddNode(std::unique_ptr<NodeDefinition>&& nodeDef)
 {
-  if(!nodeDef->mName.empty() && FindNode(nodeDef->mName))
-  {
-    return nullptr;
-  }
-
   // add next index (to which we're about to push) as a child to the designated parent, if any.
   if(nodeDef->mParentIdx != INVALID_INDEX)
   {
index 0f40f5b..ecb5cff 100644 (file)
@@ -113,7 +113,7 @@ public: // METHODS
    *  from node definitions.
    * @return Handle to the root actor.
    */
-  Actor CreateNodes(Index iNode, const Customization::Choices& choices, NodeDefinition::CreateParams& params) const;
+  Actor CreateNodes(Index iNode, const Customization::Choices& choices, NodeDefinition::CreateParams& params);
 
   /*
    * @brief Creates / update a registry of mappings from customization tags to