[Tizen] Add MotionData class and generate Animation by this
authorEverLEEst(SangHyeon Lee) <sh10233.lee@samsung.com>
Wed, 28 Jun 2023 05:39:34 +0000 (14:39 +0900)
committerEverLEEst(SangHyeon Lee) <sh10233.lee@samsung.com>
Wed, 28 Jun 2023 05:39:34 +0000 (14:39 +0900)
This reverts commit 469fdeab34b1f319e0d9a73a799f1a48732a0410.

56 files changed:
automated-tests/resources/AnimatedMorphCubeAnimateNonZeroFrame.gltf
automated-tests/resources/MorphPrimitivesTest.gltf
automated-tests/src/dali-scene3d/CMakeLists.txt
automated-tests/src/dali-scene3d/utc-Dali-BlendShapeIndex.cpp [new file with mode: 0644]
automated-tests/src/dali-scene3d/utc-Dali-Model.cpp
automated-tests/src/dali-scene3d/utc-Dali-MotionData.cpp [new file with mode: 0644]
automated-tests/src/dali-scene3d/utc-Dali-MotionIndex.cpp [new file with mode: 0644]
automated-tests/src/dali-scene3d/utc-Dali-MotionPropertyIndex.cpp [new file with mode: 0644]
automated-tests/src/dali-scene3d/utc-Dali-MotionTransformIndex.cpp [new file with mode: 0644]
automated-tests/src/dali-scene3d/utc-Dali-MotionValue.cpp [new file with mode: 0644]
dali-scene3d/dali-scene3d.h
dali-scene3d/internal/controls/model/model-impl.cpp
dali-scene3d/internal/controls/model/model-impl.h
dali-scene3d/internal/file.list
dali-scene3d/internal/loader/gltf2-asset.h
dali-scene3d/internal/loader/gltf2-util.cpp
dali-scene3d/internal/loader/json-reader.h
dali-scene3d/internal/model-components/model-node-impl.cpp
dali-scene3d/internal/model-components/model-node-impl.h
dali-scene3d/internal/model-motion/motion-data-impl.cpp [new file with mode: 0644]
dali-scene3d/internal/model-motion/motion-data-impl.h [new file with mode: 0644]
dali-scene3d/internal/model-motion/motion-data-load-task.cpp [new file with mode: 0644]
dali-scene3d/internal/model-motion/motion-data-load-task.h [new file with mode: 0644]
dali-scene3d/internal/model-motion/motion-index/blend-shape-index-impl.cpp [new file with mode: 0644]
dali-scene3d/internal/model-motion/motion-index/blend-shape-index-impl.h [new file with mode: 0644]
dali-scene3d/internal/model-motion/motion-index/motion-index-impl.cpp [new file with mode: 0644]
dali-scene3d/internal/model-motion/motion-index/motion-index-impl.h [new file with mode: 0644]
dali-scene3d/internal/model-motion/motion-index/motion-property-index-impl.cpp [new file with mode: 0644]
dali-scene3d/internal/model-motion/motion-index/motion-property-index-impl.h [new file with mode: 0644]
dali-scene3d/internal/model-motion/motion-index/motion-transform-index-impl.cpp [new file with mode: 0644]
dali-scene3d/internal/model-motion/motion-index/motion-transform-index-impl.h [new file with mode: 0644]
dali-scene3d/internal/model-motion/motion-value-impl.cpp [new file with mode: 0644]
dali-scene3d/internal/model-motion/motion-value-impl.h [new file with mode: 0644]
dali-scene3d/public-api/controls/model/model.cpp
dali-scene3d/public-api/controls/model/model.h
dali-scene3d/public-api/file.list
dali-scene3d/public-api/loader/animated-property.cpp
dali-scene3d/public-api/loader/animated-property.h
dali-scene3d/public-api/loader/animation-definition.cpp
dali-scene3d/public-api/loader/animation-definition.h
dali-scene3d/public-api/loader/blend-shape-details.h
dali-scene3d/public-api/loader/scene-definition.cpp
dali-scene3d/public-api/model-components/model-node.cpp
dali-scene3d/public-api/model-components/model-node.h
dali-scene3d/public-api/model-motion/motion-data.cpp [new file with mode: 0644]
dali-scene3d/public-api/model-motion/motion-data.h [new file with mode: 0644]
dali-scene3d/public-api/model-motion/motion-index/blend-shape-index.cpp [new file with mode: 0644]
dali-scene3d/public-api/model-motion/motion-index/blend-shape-index.h [new file with mode: 0644]
dali-scene3d/public-api/model-motion/motion-index/motion-index.cpp [new file with mode: 0644]
dali-scene3d/public-api/model-motion/motion-index/motion-index.h [new file with mode: 0644]
dali-scene3d/public-api/model-motion/motion-index/motion-property-index.cpp [new file with mode: 0644]
dali-scene3d/public-api/model-motion/motion-index/motion-property-index.h [new file with mode: 0644]
dali-scene3d/public-api/model-motion/motion-index/motion-transform-index.cpp [new file with mode: 0644]
dali-scene3d/public-api/model-motion/motion-index/motion-transform-index.h [new file with mode: 0644]
dali-scene3d/public-api/model-motion/motion-value.cpp [new file with mode: 0644]
dali-scene3d/public-api/model-motion/motion-value.h [new file with mode: 0644]

index 08c8daf..48a9d20 100644 (file)
   ],\r
   "meshes": [\r
     {\r
+      "extras": {\r
+        "targetNames": [\r
+          "Target_0",\r
+          "Target_1"\r
+        ]\r
+      },\r
       "primitives": [\r
         {\r
           "attributes": {\r
index a987f2d..10fb1e7 100644 (file)
           ],\r
           "mode": 4\r
         }\r
-      ]\r
+      ],\r
+      "extensions": {\r
+        "SXR_targets_names": {\r
+          "Target_0": 0\r
+        },\r
+        "avatar_shape_names": {\r
+          "Target_0": 0\r
+        }\r
+      }\r
     }\r
   ],\r
   "nodes": [\r
index 4dff80c..1eed33c 100755 (executable)
@@ -11,6 +11,7 @@ SET(TC_SOURCES
   utc-Dali-AnimationDefinition.cpp
   utc-Dali-AnimatedProperty.cpp
   utc-Dali-BvhLoader.cpp
+  utc-Dali-BlendShapeIndex.cpp
   utc-Dali-CameraParameters.cpp
   utc-Dali-EnvironmentMapLoader.cpp
   utc-Dali-EnvironmentDefinition.cpp
@@ -20,6 +21,11 @@ SET(TC_SOURCES
   utc-Dali-Model.cpp
   utc-Dali-ModelNode.cpp
   utc-Dali-ModelPrimitive.cpp
+  utc-Dali-MotionData.cpp
+  utc-Dali-MotionIndex.cpp
+  utc-Dali-MotionPropertyIndex.cpp
+  utc-Dali-MotionTransformIndex.cpp
+  utc-Dali-MotionValue.cpp
   utc-Dali-SceneView.cpp
   utc-Dali-MatrixStack.cpp
   utc-Dali-MeshDefinition.cpp
diff --git a/automated-tests/src/dali-scene3d/utc-Dali-BlendShapeIndex.cpp b/automated-tests/src/dali-scene3d/utc-Dali-BlendShapeIndex.cpp
new file mode 100644 (file)
index 0000000..b7c34ff
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <stdlib.h>
+#include <iostream>
+
+#include <dali-scene3d/public-api/model-motion/motion-index/blend-shape-index.h>
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-index.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+using namespace Dali::Scene3D;
+
+void model_motion_blend_shape_index_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void model_motion_blend_shape_index_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+const char* const WEIGHTS_UNIFORM = "uBlendShapeWeight";
+
+std::string GetPropertyNameFromIndex(int index)
+{
+  if(index >= 0)
+  {
+    char weightNameBuffer[32];
+
+    // Get return value of snprintf to avoid SVACE.
+    [[maybe_unused]] auto prefixSize = snprintf(weightNameBuffer, sizeof(weightNameBuffer), "%s[%d]", WEIGHTS_UNIFORM, index);
+
+    return weightNameBuffer;
+  }
+  return "";
+}
+} // namespace
+
+// Positive test case for a method
+int UtcDaliBlendShapeIndexNew(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliBlendShapeIndexNew");
+
+  BlendShapeIndex blendShapeIndex = BlendShapeIndex::New();
+  DALI_TEST_CHECK(blendShapeIndex);
+  DALI_TEST_EQUALS(blendShapeIndex.GetModelNodeId().stringKey, "", TEST_LOCATION);
+  DALI_TEST_EQUALS(blendShapeIndex.GetBlendShapeId().indexKey, Property::INVALID_INDEX, TEST_LOCATION);
+
+  blendShapeIndex = BlendShapeIndex::New("dummy", 3u);
+  DALI_TEST_CHECK(blendShapeIndex);
+  DALI_TEST_EQUALS(blendShapeIndex.GetModelNodeId().stringKey, "dummy", TEST_LOCATION);
+  DALI_TEST_EQUALS(blendShapeIndex.GetBlendShapeId().indexKey, 3u, TEST_LOCATION);
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliBlendShapeIndexDownCast(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliBlendShapeIndexDownCast");
+
+  BlendShapeIndex blendShapeIndex = BlendShapeIndex::New();
+  BaseHandle      handle(blendShapeIndex);
+
+  BlendShapeIndex blendShapeIndex2 = BlendShapeIndex::DownCast(handle);
+  DALI_TEST_CHECK(blendShapeIndex);
+  DALI_TEST_CHECK(blendShapeIndex2);
+  DALI_TEST_CHECK(blendShapeIndex2 == blendShapeIndex);
+  END_TEST;
+}
+
+int UtcDaliBlendShapeIndexTypeRegistry(void)
+{
+  ToolkitTestApplication application;
+
+  TypeRegistry typeRegistry = TypeRegistry::Get();
+  DALI_TEST_CHECK(typeRegistry);
+
+  TypeInfo typeInfo = typeRegistry.GetTypeInfo("BlendShapeIndex");
+  DALI_TEST_CHECK(typeInfo);
+
+  BaseHandle handle = typeInfo.CreateInstance();
+  DALI_TEST_CHECK(handle);
+
+  BlendShapeIndex blendShapeIndex = BlendShapeIndex::DownCast(handle);
+  DALI_TEST_CHECK(blendShapeIndex);
+
+  END_TEST;
+}
+
+int UtcDaliBlendShapeIndexCopyAndAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  BlendShapeIndex blendShapeIndex = BlendShapeIndex::New();
+  DALI_TEST_CHECK(blendShapeIndex);
+
+  BlendShapeIndex copy(blendShapeIndex);
+  DALI_TEST_CHECK(blendShapeIndex == copy);
+
+  BlendShapeIndex assign;
+  DALI_TEST_CHECK(!assign);
+
+  assign = copy;
+  DALI_TEST_CHECK(assign == blendShapeIndex);
+
+  END_TEST;
+}
+
+int UtcDaliBlendShapeIndexMoveConstructor(void)
+{
+  ToolkitTestApplication application;
+
+  BlendShapeIndex blendShapeIndex = BlendShapeIndex::New();
+  DALI_TEST_EQUALS(1, blendShapeIndex.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+
+  BlendShapeIndex moved = std::move(blendShapeIndex);
+  DALI_TEST_CHECK(moved);
+  DALI_TEST_EQUALS(1, moved.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+  DALI_TEST_CHECK(!blendShapeIndex);
+
+  END_TEST;
+}
+
+int UtcDaliBlendShapeIndexMoveAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  BlendShapeIndex blendShapeIndex = BlendShapeIndex::New();
+  DALI_TEST_EQUALS(1, blendShapeIndex.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+
+  BlendShapeIndex moved;
+  moved = std::move(blendShapeIndex);
+  DALI_TEST_CHECK(moved);
+  DALI_TEST_EQUALS(1, moved.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+
+  END_TEST;
+}
+
+// Method test
+
+int UtcDaliBlendShapeIndexGetPropertyName(void)
+{
+  std::string     expectPropertyName  = "";
+  Property::Index expectPropertyIndex = Property::INVALID_INDEX;
+
+  uint32_t blendShapeIndex;
+
+  MotionIndex index = BlendShapeIndex::New();
+
+  // Invalid motion index return empty string, invalid index
+  DALI_TEST_EQUALS(expectPropertyName, index.GetPropertyName(), TEST_LOCATION);
+  DALI_TEST_EQUALS(expectPropertyIndex, index.GetPropertyIndex(), TEST_LOCATION);
+
+  blendShapeIndex    = 0u;
+  index              = BlendShapeIndex::New("", blendShapeIndex);
+  expectPropertyName = GetPropertyNameFromIndex(blendShapeIndex);
+  DALI_TEST_EQUALS(expectPropertyName, index.GetPropertyName(), TEST_LOCATION);
+
+  blendShapeIndex    = 45u;
+  index              = BlendShapeIndex::New("", blendShapeIndex);
+  expectPropertyName = GetPropertyNameFromIndex(blendShapeIndex);
+  DALI_TEST_EQUALS(expectPropertyName, index.GetPropertyName(), TEST_LOCATION);
+
+  blendShapeIndex    = 109u;
+  index              = BlendShapeIndex::New("", blendShapeIndex);
+  expectPropertyName = GetPropertyNameFromIndex(blendShapeIndex);
+  DALI_TEST_EQUALS(expectPropertyName, index.GetPropertyName(), TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliBlendShapeIndexSetGetBlendShapeId(void)
+{
+  Property::Index expectPropertyIndex = 0u;
+
+  BlendShapeIndex index = BlendShapeIndex::New("", expectPropertyIndex);
+
+  // Invalid motion index return empty string, invalid index
+  DALI_TEST_CHECK(index.GetBlendShapeId().type == Property::Key::Type::INDEX);
+  DALI_TEST_EQUALS(expectPropertyIndex, index.GetBlendShapeId().indexKey, TEST_LOCATION);
+
+  std::string expectPropertyName = "hello";
+  index.SetBlendShapeId(expectPropertyName);
+  DALI_TEST_CHECK(index.GetBlendShapeId().type == Property::Key::Type::STRING);
+  DALI_TEST_EQUALS(expectPropertyName, index.GetBlendShapeId().stringKey, TEST_LOCATION);
+
+  expectPropertyIndex = 100u;
+  index.SetBlendShapeId(expectPropertyIndex);
+  DALI_TEST_CHECK(index.GetBlendShapeId().type == Property::Key::Type::INDEX);
+  DALI_TEST_EQUALS(expectPropertyIndex, index.GetBlendShapeId().indexKey, TEST_LOCATION);
+
+  END_TEST;
+}
\ No newline at end of file
index c219f93..30b755d 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <dali-toolkit-test-suite-utils.h>
 #include <dali-toolkit/dali-toolkit.h>
+#include <dali/devel-api/common/map-wrapper.h>
 #include <stdlib.h>
 #include <iostream>
 
 #include <dali-scene3d/public-api/controls/model/model.h>
 #include <dali-scene3d/public-api/model-components/model-node.h>
 
+#include <dali-scene3d/public-api/model-motion/motion-data.h>
+#include <dali-scene3d/public-api/model-motion/motion-index/blend-shape-index.h>
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-transform-index.h>
+
 #include <dali/devel-api/actors/camera-actor-devel.h>
 
 using namespace Dali;
@@ -53,7 +58,9 @@ const bool DEFAULT_MODEL_CHILDREN_FOCUSABLE = false;
  */
 const char* TEST_GLTF_FILE_NAME                    = TEST_RESOURCE_DIR "/AnimatedCube.gltf";
 const char* TEST_GLTF_ANIMATION_TEST_FILE_NAME     = TEST_RESOURCE_DIR "/animationTest.gltf";
+const char* TEST_GLTF_EXTRAS_FILE_NAME             = TEST_RESOURCE_DIR "/AnimatedMorphCubeAnimateNonZeroFrame.gltf";
 const char* TEST_GLTF_MULTIPLE_PRIMITIVE_FILE_NAME = TEST_RESOURCE_DIR "/simpleMultiplePrimitiveTest.gltf";
+const char* TEST_GLTF_MORPH_FILE_NAME              = TEST_RESOURCE_DIR "/AnimatedMorphCube.gltf";
 const char* TEST_DLI_FILE_NAME                     = TEST_RESOURCE_DIR "/arc.dli";
 const char* TEST_DLI_EXERCISE_FILE_NAME            = TEST_RESOURCE_DIR "/exercise.dli";
 
@@ -1135,8 +1142,7 @@ int UtcDaliModelCameraGenerate02(void)
   CameraActor appliedCamera;
   DALI_TEST_EQUALS(model.ApplyCamera(0u, appliedCamera), false, TEST_LOCATION); // Cannot apply into empty camera.
 
-  auto CompareCameraProperties = [](CameraActor lhs, CameraActor rhs, const char* location)
-  {
+  auto CompareCameraProperties = [](CameraActor lhs, CameraActor rhs, const char* location) {
     DALI_TEST_EQUALS(lhs.GetProperty<int>(Dali::CameraActor::Property::PROJECTION_MODE), rhs.GetProperty<int>(Dali::CameraActor::Property::PROJECTION_MODE), TEST_LOCATION);
     DALI_TEST_EQUALS(lhs.GetProperty<float>(Dali::CameraActor::Property::NEAR_PLANE_DISTANCE), rhs.GetProperty<float>(Dali::CameraActor::Property::NEAR_PLANE_DISTANCE), TEST_LOCATION);
 
@@ -1488,3 +1494,196 @@ int UtcDaliModelSizeChange2(void)
 
   END_TEST;
 }
+
+int UtcDaliModelRetrieveBlendShapeNames(void)
+{
+  tet_infoline(" UtcDaliModelRetrieveBlendShapeByName.");
+
+  ToolkitTestApplication application;
+
+  Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_EXTRAS_FILE_NAME);
+  model.SetProperty(Dali::Actor::Property::SIZE, Vector3(300, 300, 300));
+  application.GetScene().Add(model);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(model.GetChildCount(), 1u, TEST_LOCATION);
+
+  // Get target ModelNode that has extras
+  Scene3D::ModelNode expectNode = model.FindChildModelNodeByName("AnimatedMorphCube");
+
+  // Pair of expected blend shape index from expectNode.
+  std::map<std::string, Scene3D::Loader::BlendShapes::Index> expectBlendShapeNames = {
+    {"Target_0", 0u},
+    {"Target_1", 1u},
+  };
+
+  std::vector<std::string> blendShapeNameList;
+  model.RetrieveBlendShapeNames(blendShapeNameList);
+
+  DALI_TEST_EQUALS(blendShapeNameList.size(), expectBlendShapeNames.size(), TEST_LOCATION);
+  for(auto i = 0u; i < blendShapeNameList.size(); ++i)
+  {
+    const auto& name = blendShapeNameList[i];
+    tet_printf("Check retrieved blendshape name : %s\n", name.c_str());
+
+    const auto& iter = expectBlendShapeNames.find(name);
+    DALI_TEST_CHECK(iter != expectBlendShapeNames.end());
+
+    std::vector<Scene3D::ModelNode> nodeList;
+    model.RetrieveModelNodesByBlendShapeName(name, nodeList);
+    DALI_TEST_EQUALS(nodeList.size(), 1u, TEST_LOCATION);
+    DALI_TEST_EQUALS(nodeList[0], expectNode, TEST_LOCATION);
+    DALI_TEST_EQUALS(nodeList[0].GetBlendShapeIndexByName(name), iter->second, TEST_LOCATION);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliModelGenerateMotionDataAnimation01(void)
+{
+  ToolkitTestApplication application;
+
+  Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_MORPH_FILE_NAME);
+  model.SetProperty(Dali::Actor::Property::SIZE, Vector2(50, 50));
+  application.GetScene().Add(model);
+
+  gResourceReadyCalled = false;
+  model.ResourceReadySignal().Connect(&OnResourceReady);
+  DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION);
+
+  KeyFrames floatKeyFrames = KeyFrames::New();
+  floatKeyFrames.Add(0.0f, 1.0f);
+  floatKeyFrames.Add(1.0f, 0.5f);
+
+  float               duration   = 3.0f;
+  Scene3D::MotionData motionData = Scene3D::MotionData::New(duration);
+  motionData.Add(Scene3D::MotionTransformIndex::New("AnimatedMorphCube", Scene3D::MotionTransformIndex::TransformType::SCALE_Y), Scene3D::MotionValue::New(2.0f));
+  motionData.Add(Scene3D::MotionTransformIndex::New("AnimatedMorphCube", Scene3D::MotionTransformIndex::TransformType::SCALE_Z), Scene3D::MotionValue::New(floatKeyFrames));
+  motionData.Add(Scene3D::BlendShapeIndex::New("AnimatedMorphCube", 0), Scene3D::MotionValue::New(0.5f));
+  motionData.Add(Scene3D::BlendShapeIndex::New("AnimatedMorphCube", 1), Scene3D::MotionValue::New(floatKeyFrames));
+
+  Animation generatedAnimation = model.GenerateMotionDataAnimation(motionData);
+  DALI_TEST_CHECK(generatedAnimation);
+  DALI_TEST_EQUALS(generatedAnimation.GetDuration(), duration, TEST_LOCATION);
+
+  Scene3D::MotionData invalidMotionData = Scene3D::MotionData::New(duration);
+  invalidMotionData.Add(Scene3D::MotionTransformIndex::New("NotAnimatedMorphCube", Scene3D::MotionTransformIndex::TransformType::SCALE_Y), Scene3D::MotionValue::New(2.0f));
+  invalidMotionData.Add(Scene3D::MotionTransformIndex::New("NotAnimatedMorphCube", Scene3D::MotionTransformIndex::TransformType::SCALE_Z), Scene3D::MotionValue::New(floatKeyFrames));
+  invalidMotionData.Add(Scene3D::BlendShapeIndex::New("NotAnimatedMorphCube", 0), Scene3D::MotionValue::New(0.5f));
+  invalidMotionData.Add(Scene3D::BlendShapeIndex::New("NotAnimatedMorphCube", 1), Scene3D::MotionValue::New(floatKeyFrames));
+
+  generatedAnimation = model.GenerateMotionDataAnimation(invalidMotionData);
+  DALI_TEST_CHECK(!generatedAnimation); // Animation should be empty if motion data have invalid index.
+
+  END_TEST;
+}
+
+int UtcDaliModelSetMotionData(void)
+{
+  ToolkitTestApplication application;
+
+  Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_MORPH_FILE_NAME);
+  model.SetProperty(Dali::Actor::Property::SIZE, Vector2(50, 50));
+  application.GetScene().Add(model);
+
+  gResourceReadyCalled = false;
+  model.ResourceReadySignal().Connect(&OnResourceReady);
+  DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION);
+
+  KeyFrames floatKeyFrames = KeyFrames::New();
+  floatKeyFrames.Add(0.0f, 1.0f);
+  floatKeyFrames.Add(1.0f, 0.5f);
+
+  float               duration   = 3.0f;
+  Scene3D::MotionData motionData = Scene3D::MotionData::New(duration);
+  motionData.Add(Scene3D::MotionTransformIndex::New("AnimatedMorphCube", Scene3D::MotionTransformIndex::TransformType::SCALE_Y), Scene3D::MotionValue::New(2.0f));
+  motionData.Add(Scene3D::MotionTransformIndex::New("AnimatedMorphCube", Scene3D::MotionTransformIndex::TransformType::SCALE_Z), Scene3D::MotionValue::New(floatKeyFrames));
+  motionData.Add(Scene3D::BlendShapeIndex::New("AnimatedMorphCube", 0), Scene3D::MotionValue::New(0.5f));
+  motionData.Add(Scene3D::BlendShapeIndex::New("AnimatedMorphCube", 1), Scene3D::MotionValue::New(floatKeyFrames));
+
+  auto cubeModelNode = model.FindChildModelNodeByName("AnimatedMorphCube");
+
+  float expectScaleX = cubeModelNode.GetProperty<float>(Actor::Property::SCALE_X);
+
+  model.SetMotionData(motionData);
+
+  DALI_TEST_EQUALS(cubeModelNode.GetProperty<float>(Actor::Property::SCALE_X), expectScaleX, TEST_LOCATION);
+  DALI_TEST_EQUALS(cubeModelNode.GetProperty<float>(Actor::Property::SCALE_Y), 2.0f, TEST_LOCATION);
+  DALI_TEST_EQUALS(cubeModelNode.GetProperty<float>(Actor::Property::SCALE_Z), 0.5f, TEST_LOCATION); ///< Last value of keyframes
+
+  END_TEST;
+}
+
+int UtcDaliModelBlendShapeMotionDataByName(void)
+{
+  ToolkitTestApplication application;
+
+  Scene3D::Model model = Scene3D::Model::New(TEST_GLTF_EXTRAS_FILE_NAME);
+  model.SetProperty(Dali::Actor::Property::SIZE, Vector2(50, 50));
+  application.GetScene().Add(model);
+
+  gResourceReadyCalled = false;
+  model.ResourceReadySignal().Connect(&OnResourceReady);
+  DALI_TEST_EQUALS(gResourceReadyCalled, false, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(gResourceReadyCalled, true, TEST_LOCATION);
+
+  KeyFrames floatKeyFrames = KeyFrames::New();
+  floatKeyFrames.Add(0.0f, 0.5f);
+  floatKeyFrames.Add(1.0f, 1.0f);
+
+  float               duration   = 3.0f;
+  Scene3D::MotionData motionData = Scene3D::MotionData::New(duration);
+  motionData.Add(Scene3D::BlendShapeIndex::New("Target_0"), Scene3D::MotionValue::New(0.5f));
+  motionData.Add(Scene3D::BlendShapeIndex::New("Target_1"), Scene3D::MotionValue::New(floatKeyFrames));
+
+  Animation generatedAnimation = model.GenerateMotionDataAnimation(motionData);
+  DALI_TEST_CHECK(generatedAnimation);
+  DALI_TEST_EQUALS(generatedAnimation.GetDuration(), duration, TEST_LOCATION);
+
+  model.SetMotionData(motionData);
+
+  // Get target ModelNode that has extras
+  Scene3D::ModelNode expectNode    = model.FindChildModelNodeByName("AnimatedMorphCube");
+  auto               propertyIndex = expectNode.GetPropertyIndex(motionData.GetIndex(0u).GetPropertyName(expectNode));
+
+  DALI_TEST_CHECK(propertyIndex != Property::INVALID_INDEX);
+  DALI_TEST_EQUALS(expectNode.GetProperty<float>(propertyIndex), 0.5f, TEST_LOCATION);
+
+  propertyIndex = expectNode.GetPropertyIndex(motionData.GetIndex(1u).GetPropertyName(expectNode));
+  DALI_TEST_CHECK(propertyIndex != Property::INVALID_INDEX);
+  DALI_TEST_EQUALS(expectNode.GetProperty<float>(propertyIndex), 1.0f, TEST_LOCATION);
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-scene3d/utc-Dali-MotionData.cpp b/automated-tests/src/dali-scene3d/utc-Dali-MotionData.cpp
new file mode 100644 (file)
index 0000000..54fc168
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <stdlib.h>
+#include <fstream>
+#include <iostream>
+
+#include <toolkit-event-thread-callback.h>
+
+#include <dali-scene3d/public-api/model-motion/motion-data.h>
+#include <dali-scene3d/public-api/model-motion/motion-value.h>
+
+#include <dali-scene3d/public-api/model-motion/motion-index/blend-shape-index.h>
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-index.h>
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-transform-index.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+using namespace Dali::Scene3D;
+
+void model_motion_motion_data_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void model_motion_motion_data_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+const char* TEST_BVH_FILE_NAME    = TEST_RESOURCE_DIR "/test.bvh";
+const char* TEST_FACIAL_FILE_NAME = TEST_RESOURCE_DIR "/facial-blendshape-animation.json";
+
+std::string ReadBufferFromFile(const std::string& url)
+{
+  std::string  rawString;
+  std::fstream fileStream;
+
+  fileStream.open(url, std::ios::in | std::ios::binary);
+  if(!fileStream.is_open())
+  {
+    DALI_LOG_WARNING("stream open failed for: \"%s\", in mode: \"%d\".\n", url.c_str(), static_cast<int>(std::ios::in | std::ios::binary));
+  }
+
+  // get length of file:
+  fileStream.seekg(0, std::ios::end);
+  auto length = fileStream.tellg();
+  fileStream.seekg(0, std::ios::beg);
+
+  rawString.resize(length);
+  fileStream.read(rawString.data(), length);
+
+  fileStream.close();
+
+  return rawString;
+}
+
+// For LoadCompleted
+static bool gLoadCompleted = false;
+void        OnLoadCompleted(MotionData data)
+{
+  gLoadCompleted = true;
+}
+} // namespace
+
+// Positive test case for a method
+int UtcDaliMotionDataNew(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliMotionDataNew");
+
+  float      expectDuration = 0.0f;
+  MotionData motionData     = MotionData::New();
+  DALI_TEST_CHECK(motionData);
+  DALI_TEST_EQUALS(motionData.GetDuration(), expectDuration, TEST_LOCATION);
+
+  expectDuration = 10.0f;
+  motionData     = MotionData::New(expectDuration);
+  DALI_TEST_CHECK(motionData);
+  DALI_TEST_EQUALS(motionData.GetDuration(), expectDuration, TEST_LOCATION);
+  END_TEST;
+}
+
+int UtcDaliMotionDataDownCast(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliMotionDataDownCast");
+
+  MotionData motionData = MotionData::New();
+  BaseHandle handle(motionData);
+
+  MotionData motionData2 = MotionData::DownCast(handle);
+  DALI_TEST_CHECK(motionData);
+  DALI_TEST_CHECK(motionData2);
+  DALI_TEST_CHECK(motionData2 == motionData);
+  END_TEST;
+}
+
+int UtcDaliMotionDataTypeRegistry(void)
+{
+  ToolkitTestApplication application;
+
+  TypeRegistry typeRegistry = TypeRegistry::Get();
+  DALI_TEST_CHECK(typeRegistry);
+
+  TypeInfo typeInfo = typeRegistry.GetTypeInfo("MotionData");
+  DALI_TEST_CHECK(typeInfo);
+
+  BaseHandle handle = typeInfo.CreateInstance();
+  DALI_TEST_CHECK(handle);
+
+  MotionData motionData = MotionData::DownCast(handle);
+  DALI_TEST_CHECK(motionData);
+
+  END_TEST;
+}
+
+int UtcDaliMotionDataCopyAndAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  MotionData motionData = MotionData::New();
+  DALI_TEST_CHECK(motionData);
+
+  MotionData copy(motionData);
+  DALI_TEST_CHECK(motionData == copy);
+
+  MotionData assign;
+  DALI_TEST_CHECK(!assign);
+
+  assign = copy;
+  DALI_TEST_CHECK(assign == motionData);
+
+  END_TEST;
+}
+
+int UtcDaliMotionDataMoveConstructor(void)
+{
+  ToolkitTestApplication application;
+
+  MotionData motionData = MotionData::New();
+  DALI_TEST_EQUALS(1, motionData.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+
+  MotionData moved = std::move(motionData);
+  DALI_TEST_CHECK(moved);
+  DALI_TEST_EQUALS(1, moved.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+  DALI_TEST_CHECK(!motionData);
+
+  END_TEST;
+}
+
+int UtcDaliMotionDataMoveAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  MotionData motionData = MotionData::New();
+  DALI_TEST_EQUALS(1, motionData.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+
+  MotionData moved;
+  moved = std::move(motionData);
+  DALI_TEST_CHECK(moved);
+  DALI_TEST_EQUALS(1, moved.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+
+  END_TEST;
+}
+
+// Method test
+
+int UtcDaliMotionDataAddMotion(void)
+{
+  ToolkitTestApplication application;
+
+  MotionData motionData = MotionData::New(3.0f);
+
+  const uint32_t countMax = 4;
+  MotionIndex    index[countMax];
+  MotionValue    value[countMax];
+  for(uint32_t i = 0u; i < countMax; ++i)
+  {
+    // Generate index
+    if(i & 1)
+    {
+      index[i] = BlendShapeIndex::New("node", 0);
+    }
+    else
+    {
+      index[i] = MotionTransformIndex::New("node", MotionTransformIndex::TransformType::POSITION_X);
+    }
+
+    // Generate value
+    if(i & 2)
+    {
+      value[i] = MotionValue::New(3.0f);
+    }
+    else
+    {
+      KeyFrames keyFrames = KeyFrames::New();
+      keyFrames.Add(0.0f, 9.0f);
+      keyFrames.Add(1.0f, 5.0f);
+      value[i] = MotionValue::New(keyFrames);
+    }
+
+    DALI_TEST_CHECK(index[i]);
+    DALI_TEST_CHECK(value[i]);
+    motionData.Add(index[i], value[i]);
+
+    DALI_TEST_EQUALS(i + 1, motionData.GetMotionCount(), TEST_LOCATION);
+  }
+
+  for(uint32_t i = 0u; i < countMax; ++i)
+  {
+    DALI_TEST_EQUALS(index[i], motionData.GetIndex(i), TEST_LOCATION);
+    DALI_TEST_EQUALS(value[i], motionData.GetValue(i), TEST_LOCATION);
+  }
+
+  DALI_TEST_CHECK(!motionData.GetIndex(countMax));
+  DALI_TEST_CHECK(!motionData.GetValue(countMax));
+
+  motionData.Clear();
+
+  DALI_TEST_EQUALS(0u, motionData.GetMotionCount(), TEST_LOCATION);
+  DALI_TEST_CHECK(!motionData.GetIndex(0u));
+  DALI_TEST_CHECK(!motionData.GetValue(0u));
+
+  END_TEST;
+}
+
+int UtcDaliMotionDataSetGetDuration(void)
+{
+  ToolkitTestApplication application;
+
+  float      expectDuration = 3.0f;
+  MotionData motionData     = MotionData::New(expectDuration);
+  DALI_TEST_EQUALS(motionData.GetDuration(), expectDuration, TEST_LOCATION);
+
+  expectDuration = 7.0f;
+  motionData.SetDuration(expectDuration);
+  DALI_TEST_EQUALS(motionData.GetDuration(), expectDuration, TEST_LOCATION);
+
+  expectDuration = 1.0f;
+  motionData.SetDuration(expectDuration);
+  DALI_TEST_EQUALS(motionData.GetDuration(), expectDuration, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliMotionDataLoadBvhAndFacialAsync(void)
+{
+  ToolkitTestApplication application;
+
+  for(uint32_t tc = 0; tc < 4; ++tc)
+  {
+    MotionData motionData = MotionData::New();
+    gLoadCompleted        = false;
+    motionData.LoadCompletedSignal().Connect(&OnLoadCompleted);
+
+    switch(tc)
+    {
+      case 0:
+      default:
+      {
+        motionData.LoadBvh(TEST_BVH_FILE_NAME);
+        break;
+      }
+      case 1:
+      {
+        motionData.LoadFacialAnimation(TEST_FACIAL_FILE_NAME);
+        break;
+      }
+      case 2:
+      {
+        std::string rawString = ReadBufferFromFile(TEST_BVH_FILE_NAME);
+        motionData.LoadBvhFromBuffer(reinterpret_cast<uint8_t*>(rawString.data()), static_cast<int>(rawString.length()));
+        break;
+      }
+      case 3:
+      {
+        std::string rawString = ReadBufferFromFile(TEST_FACIAL_FILE_NAME);
+        motionData.LoadFacialAnimationFromBuffer(reinterpret_cast<uint8_t*>(rawString.data()), static_cast<int>(rawString.length()));
+        break;
+      }
+    }
+
+    DALI_TEST_EQUALS(gLoadCompleted, false, TEST_LOCATION);
+
+    application.SendNotification();
+    application.Render();
+
+    DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+    application.SendNotification();
+    application.Render();
+
+    // Check LoadCompletedSignal emitted.
+    DALI_TEST_EQUALS(gLoadCompleted, true, TEST_LOCATION);
+
+    // Check MotionData load successfully.
+    DALI_TEST_GREATER(motionData.GetMotionCount(), 0u, TEST_LOCATION);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliMotionDataLoadBvhAndFacialSync(void)
+{
+  ToolkitTestApplication application;
+
+  for(uint32_t tc = 0; tc < 4; ++tc)
+  {
+    MotionData motionData = MotionData::New();
+    gLoadCompleted        = false;
+    motionData.LoadCompletedSignal().Connect(&OnLoadCompleted);
+
+    switch(tc)
+    {
+      case 0:
+      default:
+      {
+        motionData.LoadBvh(TEST_BVH_FILE_NAME, Vector3::ONE, true);
+        break;
+      }
+      case 1:
+      {
+        motionData.LoadFacialAnimation(TEST_FACIAL_FILE_NAME, true);
+        break;
+      }
+      case 2:
+      {
+        std::string rawString = ReadBufferFromFile(TEST_BVH_FILE_NAME);
+        motionData.LoadBvhFromBuffer(reinterpret_cast<uint8_t*>(rawString.data()), static_cast<int>(rawString.length()), Vector3::ONE, true);
+        break;
+      }
+      case 3:
+      {
+        std::string rawString = ReadBufferFromFile(TEST_FACIAL_FILE_NAME);
+        motionData.LoadFacialAnimationFromBuffer(reinterpret_cast<uint8_t*>(rawString.data()), static_cast<int>(rawString.length()), true);
+        break;
+      }
+    }
+
+    // Check LoadCompletedSignal emitted.
+    DALI_TEST_EQUALS(gLoadCompleted, true, TEST_LOCATION);
+
+    // Check MotionData load successfully.
+    DALI_TEST_GREATER(motionData.GetMotionCount(), 0u, TEST_LOCATION);
+  }
+
+  END_TEST;
+}
+
+int UtcDaliMotionDataLoadAsyncMultiple(void)
+{
+  ToolkitTestApplication application;
+
+  MotionData motionData = MotionData::New();
+  gLoadCompleted        = false;
+  motionData.LoadCompletedSignal().Connect(&OnLoadCompleted);
+
+  auto tryCount = 10u;
+  for(auto i = 0u; i < tryCount; ++i)
+  {
+    motionData.LoadBvh(TEST_BVH_FILE_NAME);
+  }
+
+  DALI_TEST_EQUALS(gLoadCompleted, false, TEST_LOCATION);
+
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1), true, TEST_LOCATION);
+  application.SendNotification();
+  application.Render();
+
+  DALI_TEST_EQUALS(gLoadCompleted, true, TEST_LOCATION);
+
+  // Check MotionData load successfully.
+  DALI_TEST_GREATER(motionData.GetMotionCount(), 0u, TEST_LOCATION);
+
+  // Check if completed request comes only 1 time.
+  DALI_TEST_EQUALS(Test::WaitForEventThreadTrigger(1, 1), false, TEST_LOCATION);
+
+  END_TEST;
+}
\ No newline at end of file
diff --git a/automated-tests/src/dali-scene3d/utc-Dali-MotionIndex.cpp b/automated-tests/src/dali-scene3d/utc-Dali-MotionIndex.cpp
new file mode 100644 (file)
index 0000000..1e28a46
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <stdlib.h>
+#include <iostream>
+
+#include <dali-scene3d/public-api/model-motion/motion-index/blend-shape-index.h>
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-index.h>
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-property-index.h>
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-transform-index.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+using namespace Dali::Scene3D;
+
+void model_motion_motion_index_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void model_motion_motion_index_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+} // namespace
+
+// Positive test case for a method
+int UtcDaliMotionIndexDownCast(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliMotionIndexDownCast");
+
+  MotionIndex blendShapeIndex = BlendShapeIndex::New();
+  BaseHandle  handle(blendShapeIndex);
+
+  MotionIndex blendShapeIndex2 = MotionIndex::DownCast(handle);
+  DALI_TEST_CHECK(blendShapeIndex);
+  DALI_TEST_CHECK(blendShapeIndex2);
+  DALI_TEST_CHECK(blendShapeIndex2 == blendShapeIndex);
+  END_TEST;
+}
+
+int UtcDaliMotionIndexDownCastNotMatchedType(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliMotionIndexDownCastNotMatchedType");
+
+  {
+    MotionIndex baseIndex = BlendShapeIndex::New();
+    DALI_TEST_CHECK(baseIndex);
+
+    BaseHandle handle(baseIndex);
+
+    MotionIndex motionPropertyIndex = MotionPropertyIndex::DownCast(handle);
+    DALI_TEST_CHECK(!motionPropertyIndex);
+
+    MotionIndex motionTransformIndex = MotionTransformIndex::DownCast(handle);
+    DALI_TEST_CHECK(!motionTransformIndex);
+
+    MotionIndex blendShapeIndex = BlendShapeIndex::DownCast(handle);
+    DALI_TEST_CHECK(blendShapeIndex);
+    DALI_TEST_CHECK(blendShapeIndex == baseIndex);
+  }
+  END_TEST;
+}
+
+int UtcDaliMotionIndexCopyAndAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  MotionIndex blendShapeIndex = BlendShapeIndex::New();
+  DALI_TEST_CHECK(blendShapeIndex);
+
+  MotionIndex copy(blendShapeIndex);
+  DALI_TEST_CHECK(blendShapeIndex == copy);
+
+  MotionIndex assign;
+  DALI_TEST_CHECK(!assign);
+
+  assign = copy;
+  DALI_TEST_CHECK(assign == blendShapeIndex);
+
+  END_TEST;
+}
+
+int UtcDaliMotionIndexMoveConstructor(void)
+{
+  ToolkitTestApplication application;
+
+  MotionIndex blendShapeIndex = MotionTransformIndex::New();
+  DALI_TEST_EQUALS(1, blendShapeIndex.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+
+  MotionIndex moved = std::move(blendShapeIndex);
+  DALI_TEST_CHECK(moved);
+  DALI_TEST_EQUALS(1, moved.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+  DALI_TEST_CHECK(!blendShapeIndex);
+
+  END_TEST;
+}
+
+int UtcDaliMotionIndexMoveAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  MotionIndex blendShapeIndex = BlendShapeIndex::New();
+  DALI_TEST_EQUALS(1, blendShapeIndex.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+
+  MotionIndex moved;
+  moved = std::move(blendShapeIndex);
+  DALI_TEST_CHECK(moved);
+  DALI_TEST_EQUALS(1, moved.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+
+  END_TEST;
+}
+
+// Method test
+
+int UtcDaliMotionIndexSetGetModelNodeId(void)
+{
+  std::string expectModelNodeStringId = "nodeId";
+  MotionIndex index                   = MotionTransformIndex::New(expectModelNodeStringId, MotionTransformIndex::TransformType::POSITION);
+
+  auto propertyKey = index.GetModelNodeId();
+  DALI_TEST_CHECK(propertyKey.type == Property::Key::Type::STRING);
+  DALI_TEST_EQUALS(expectModelNodeStringId, propertyKey.stringKey, TEST_LOCATION);
+
+  expectModelNodeStringId = "anotherId";
+  index.SetModelNodeId(expectModelNodeStringId);
+
+  propertyKey = index.GetModelNodeId();
+  DALI_TEST_CHECK(propertyKey.type == Property::Key::Type::STRING);
+  DALI_TEST_EQUALS(expectModelNodeStringId, propertyKey.stringKey, TEST_LOCATION);
+
+  Property::Index expectModelNodeIndexId = 193u;
+  index.SetModelNodeId(expectModelNodeIndexId);
+
+  propertyKey = index.GetModelNodeId();
+  DALI_TEST_CHECK(propertyKey.type == Property::Key::Type::INDEX);
+  DALI_TEST_EQUALS(expectModelNodeIndexId, propertyKey.indexKey, TEST_LOCATION);
+
+  END_TEST;
+}
\ No newline at end of file
diff --git a/automated-tests/src/dali-scene3d/utc-Dali-MotionPropertyIndex.cpp b/automated-tests/src/dali-scene3d/utc-Dali-MotionPropertyIndex.cpp
new file mode 100644 (file)
index 0000000..d0aa20d
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <stdlib.h>
+#include <iostream>
+
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-index.h>
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-property-index.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+using namespace Dali::Scene3D;
+
+void model_motion_motion_property_index_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void model_motion_motion_property_index_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+} // namespace
+
+// Positive test case for a method
+int UtcDaliMotionPropertyIndexNew(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliMotionPropertyIndexNew");
+
+  MotionPropertyIndex motionPropertyIndex = MotionPropertyIndex::New();
+  DALI_TEST_CHECK(motionPropertyIndex);
+  DALI_TEST_EQUALS(motionPropertyIndex.GetModelNodeId().stringKey, "", TEST_LOCATION);
+  DALI_TEST_EQUALS(motionPropertyIndex.GetPropertyId().indexKey, Property::INVALID_INDEX, TEST_LOCATION);
+
+  motionPropertyIndex = MotionPropertyIndex::New("dummy", 3u);
+  DALI_TEST_CHECK(motionPropertyIndex);
+  DALI_TEST_EQUALS(motionPropertyIndex.GetModelNodeId().stringKey, "dummy", TEST_LOCATION);
+  DALI_TEST_EQUALS(motionPropertyIndex.GetPropertyId().indexKey, 3u, TEST_LOCATION);
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliMotionPropertyIndexDownCast(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliMotionPropertyIndexDownCast");
+
+  MotionPropertyIndex motionPropertyIndex = MotionPropertyIndex::New();
+  BaseHandle          handle(motionPropertyIndex);
+
+  MotionPropertyIndex motionPropertyIndex2 = MotionPropertyIndex::DownCast(handle);
+  DALI_TEST_CHECK(motionPropertyIndex);
+  DALI_TEST_CHECK(motionPropertyIndex2);
+  DALI_TEST_CHECK(motionPropertyIndex2 == motionPropertyIndex);
+  END_TEST;
+}
+
+int UtcDaliMotionPropertyIndexTypeRegistry(void)
+{
+  ToolkitTestApplication application;
+
+  TypeRegistry typeRegistry = TypeRegistry::Get();
+  DALI_TEST_CHECK(typeRegistry);
+
+  TypeInfo typeInfo = typeRegistry.GetTypeInfo("MotionPropertyIndex");
+  DALI_TEST_CHECK(typeInfo);
+
+  BaseHandle handle = typeInfo.CreateInstance();
+  DALI_TEST_CHECK(handle);
+
+  MotionPropertyIndex motionPropertyIndex = MotionPropertyIndex::DownCast(handle);
+  DALI_TEST_CHECK(motionPropertyIndex);
+
+  END_TEST;
+}
+
+int UtcDaliMotionPropertyIndexCopyAndAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  MotionPropertyIndex motionPropertyIndex = MotionPropertyIndex::New();
+  DALI_TEST_CHECK(motionPropertyIndex);
+
+  MotionPropertyIndex copy(motionPropertyIndex);
+  DALI_TEST_CHECK(motionPropertyIndex == copy);
+
+  MotionPropertyIndex assign;
+  DALI_TEST_CHECK(!assign);
+
+  assign = copy;
+  DALI_TEST_CHECK(assign == motionPropertyIndex);
+
+  END_TEST;
+}
+
+int UtcDaliMotionPropertyIndexMoveConstructor(void)
+{
+  ToolkitTestApplication application;
+
+  MotionPropertyIndex motionPropertyIndex = MotionPropertyIndex::New();
+  DALI_TEST_EQUALS(1, motionPropertyIndex.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+
+  MotionPropertyIndex moved = std::move(motionPropertyIndex);
+  DALI_TEST_CHECK(moved);
+  DALI_TEST_EQUALS(1, moved.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+  DALI_TEST_CHECK(!motionPropertyIndex);
+
+  END_TEST;
+}
+
+int UtcDaliMotionPropertyIndexMoveAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  MotionPropertyIndex motionPropertyIndex = MotionPropertyIndex::New();
+  DALI_TEST_EQUALS(1, motionPropertyIndex.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+
+  MotionPropertyIndex moved;
+  moved = std::move(motionPropertyIndex);
+  DALI_TEST_CHECK(moved);
+  DALI_TEST_EQUALS(1, moved.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+
+  END_TEST;
+}
+
+// Method test
+
+int UtcDaliMotionPropertyIndexGetPropertyName(void)
+{
+  std::string     expectPropertyName  = "";
+  Property::Index expectPropertyIndex = Property::INVALID_INDEX;
+
+  MotionIndex index = MotionPropertyIndex::New();
+
+  // Invalid motion index return empty string, invalid index
+  DALI_TEST_EQUALS(expectPropertyName, index.GetPropertyName(), TEST_LOCATION);
+  DALI_TEST_EQUALS(expectPropertyIndex, index.GetPropertyIndex(), TEST_LOCATION);
+
+  expectPropertyIndex = 0u;
+  index               = MotionPropertyIndex::New("", expectPropertyIndex);
+  DALI_TEST_EQUALS(expectPropertyIndex, index.GetPropertyIndex(), TEST_LOCATION);
+
+  expectPropertyIndex = 45u;
+  index               = MotionPropertyIndex::New("", expectPropertyIndex);
+  DALI_TEST_EQUALS(expectPropertyIndex, index.GetPropertyIndex(), TEST_LOCATION);
+
+  expectPropertyName = "name";
+  index              = MotionPropertyIndex::New("", expectPropertyName);
+  DALI_TEST_EQUALS(expectPropertyName, index.GetPropertyName(), TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliMotionPropertyIndexSetGetPropertyId(void)
+{
+  Property::Index expectPropertyIndex = 0u;
+
+  MotionPropertyIndex index = MotionPropertyIndex::New("", expectPropertyIndex);
+
+  // Invalid motion index return empty string, invalid index
+  DALI_TEST_CHECK(index.GetPropertyId().type == Property::Key::Type::INDEX);
+  DALI_TEST_EQUALS(expectPropertyIndex, index.GetPropertyId().indexKey, TEST_LOCATION);
+
+  std::string expectPropertyName = "hello";
+  index.SetPropertyId(expectPropertyName);
+  DALI_TEST_CHECK(index.GetPropertyId().type == Property::Key::Type::STRING);
+  DALI_TEST_EQUALS(expectPropertyName, index.GetPropertyId().stringKey, TEST_LOCATION);
+
+  expectPropertyIndex = 100u;
+  index.SetPropertyId(expectPropertyIndex);
+  DALI_TEST_CHECK(index.GetPropertyId().type == Property::Key::Type::INDEX);
+  DALI_TEST_EQUALS(expectPropertyIndex, index.GetPropertyId().indexKey, TEST_LOCATION);
+
+  END_TEST;
+}
\ No newline at end of file
diff --git a/automated-tests/src/dali-scene3d/utc-Dali-MotionTransformIndex.cpp b/automated-tests/src/dali-scene3d/utc-Dali-MotionTransformIndex.cpp
new file mode 100644 (file)
index 0000000..0dd0814
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <stdlib.h>
+#include <iostream>
+
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-index.h>
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-transform-index.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+using namespace Dali::Scene3D;
+
+void model_motion_motion_transform_index_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void model_motion_motion_transform_index_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+struct PropertyStringIndex
+{
+  const MotionTransformIndex::TransformType type;
+
+  const char* const     name;
+  const Property::Index index;
+};
+const PropertyStringIndex PROPERTY_TABLE[] =
+  {
+    {MotionTransformIndex::TransformType::POSITION, "position", Actor::Property::POSITION},
+    {MotionTransformIndex::TransformType::POSITION_X, "positionX", Actor::Property::POSITION_X},
+    {MotionTransformIndex::TransformType::POSITION_Y, "positionY", Actor::Property::POSITION_Y},
+    {MotionTransformIndex::TransformType::POSITION_Z, "positionZ", Actor::Property::POSITION_Z},
+    {MotionTransformIndex::TransformType::ORIENTATION, "orientation", Actor::Property::ORIENTATION},
+    {MotionTransformIndex::TransformType::SCALE, "scale", Actor::Property::SCALE},
+    {MotionTransformIndex::TransformType::SCALE_X, "scaleX", Actor::Property::SCALE_X},
+    {MotionTransformIndex::TransformType::SCALE_Y, "scaleY", Actor::Property::SCALE_Y},
+    {MotionTransformIndex::TransformType::SCALE_Z, "scaleZ", Actor::Property::SCALE_Z},
+};
+} // namespace
+
+// Positive test case for a method
+int UtcDaliMotionTransformIndexNew(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliMotionTransformIndexNew");
+
+  MotionTransformIndex motionTransformIndex = MotionTransformIndex::New();
+  DALI_TEST_CHECK(motionTransformIndex);
+  DALI_TEST_EQUALS(motionTransformIndex.GetModelNodeId().stringKey, "", TEST_LOCATION);
+  DALI_TEST_EQUALS(motionTransformIndex.GetTransformType(), MotionTransformIndex::TransformType::INVALID, TEST_LOCATION);
+
+  motionTransformIndex = MotionTransformIndex::New("dummy", MotionTransformIndex::TransformType::SCALE);
+  DALI_TEST_CHECK(motionTransformIndex);
+  DALI_TEST_EQUALS(motionTransformIndex.GetModelNodeId().stringKey, "dummy", TEST_LOCATION);
+  DALI_TEST_EQUALS(motionTransformIndex.GetTransformType(), MotionTransformIndex::TransformType::SCALE, TEST_LOCATION);
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliMotionTransformIndexDownCast(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliMotionTransformIndexDownCast");
+
+  MotionTransformIndex motionTransformIndex = MotionTransformIndex::New();
+  BaseHandle           handle(motionTransformIndex);
+
+  MotionTransformIndex motionTransformIndex2 = MotionTransformIndex::DownCast(handle);
+  DALI_TEST_CHECK(motionTransformIndex);
+  DALI_TEST_CHECK(motionTransformIndex2);
+  DALI_TEST_CHECK(motionTransformIndex2 == motionTransformIndex);
+  END_TEST;
+}
+
+int UtcDaliMotionTransformIndexTypeRegistry(void)
+{
+  ToolkitTestApplication application;
+
+  TypeRegistry typeRegistry = TypeRegistry::Get();
+  DALI_TEST_CHECK(typeRegistry);
+
+  TypeInfo typeInfo = typeRegistry.GetTypeInfo("MotionTransformIndex");
+  DALI_TEST_CHECK(typeInfo);
+
+  BaseHandle handle = typeInfo.CreateInstance();
+  DALI_TEST_CHECK(handle);
+
+  MotionTransformIndex motionTransformIndex = MotionTransformIndex::DownCast(handle);
+  DALI_TEST_CHECK(motionTransformIndex);
+
+  END_TEST;
+}
+
+int UtcDaliMotionTransformIndexCopyAndAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  MotionTransformIndex motionTransformIndex = MotionTransformIndex::New();
+  DALI_TEST_CHECK(motionTransformIndex);
+
+  MotionTransformIndex copy(motionTransformIndex);
+  DALI_TEST_CHECK(motionTransformIndex == copy);
+
+  MotionTransformIndex assign;
+  DALI_TEST_CHECK(!assign);
+
+  assign = copy;
+  DALI_TEST_CHECK(assign == motionTransformIndex);
+
+  END_TEST;
+}
+
+int UtcDaliMotionTransformIndexMoveConstructor(void)
+{
+  ToolkitTestApplication application;
+
+  MotionTransformIndex motionTransformIndex = MotionTransformIndex::New();
+  DALI_TEST_EQUALS(1, motionTransformIndex.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+
+  MotionTransformIndex moved = std::move(motionTransformIndex);
+  DALI_TEST_CHECK(moved);
+  DALI_TEST_EQUALS(1, moved.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+  DALI_TEST_CHECK(!motionTransformIndex);
+
+  END_TEST;
+}
+
+int UtcDaliMotionTransformIndexMoveAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  MotionTransformIndex motionTransformIndex = MotionTransformIndex::New();
+  DALI_TEST_EQUALS(1, motionTransformIndex.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+
+  MotionTransformIndex moved;
+  moved = std::move(motionTransformIndex);
+  DALI_TEST_CHECK(moved);
+  DALI_TEST_EQUALS(1, moved.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+
+  END_TEST;
+}
+
+// Method test
+
+int UtcDaliMotionTransformIndexGetPropertyNameAndIndex(void)
+{
+  auto transfromTypeCount = sizeof(PROPERTY_TABLE) / sizeof(PROPERTY_TABLE[0]);
+  for(auto i = 0u; i < transfromTypeCount; i++)
+  {
+    auto type = PROPERTY_TABLE[i].type;
+
+    std::string     expectPropertyName  = PROPERTY_TABLE[i].name;
+    Property::Index expectPropertyIndex = PROPERTY_TABLE[i].index;
+
+    MotionIndex index = MotionTransformIndex::New("", type);
+
+    DALI_TEST_EQUALS(expectPropertyName, index.GetPropertyName(), TEST_LOCATION);
+    DALI_TEST_EQUALS(expectPropertyIndex, index.GetPropertyIndex(), TEST_LOCATION);
+  }
+  END_TEST;
+}
+
+int UtcDaliMotionTransformIndexGetPropertyInvalid(void)
+{
+  std::string     expectPropertyName  = "";
+  Property::Index expectPropertyIndex = Property::INVALID_INDEX;
+
+  MotionIndex index = MotionTransformIndex::New();
+
+  // Invalid motion index return empty string, invalid index
+  DALI_TEST_EQUALS(expectPropertyName, index.GetPropertyName(), TEST_LOCATION);
+  DALI_TEST_EQUALS(expectPropertyIndex, index.GetPropertyIndex(), TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliMotionTransformIndexSetGetPropertType(void)
+{
+  auto                 expectType = MotionTransformIndex::TransformType::POSITION;
+  MotionTransformIndex index      = MotionTransformIndex::New("", expectType);
+
+  // Invalid motion index return empty string, invalid index
+  DALI_TEST_EQUALS(expectType, index.GetTransformType(), TEST_LOCATION);
+
+  expectType = MotionTransformIndex::TransformType::ORIENTATION;
+  index.SetTransformType(expectType);
+  DALI_TEST_EQUALS(expectType, index.GetTransformType(), TEST_LOCATION);
+
+  END_TEST;
+}
\ No newline at end of file
diff --git a/automated-tests/src/dali-scene3d/utc-Dali-MotionValue.cpp b/automated-tests/src/dali-scene3d/utc-Dali-MotionValue.cpp
new file mode 100644 (file)
index 0000000..103b533
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <stdlib.h>
+#include <iostream>
+
+#include <dali-scene3d/public-api/model-motion/motion-value.h>
+#include <dali/devel-api/animation/key-frames-devel.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+using namespace Dali::Scene3D;
+
+void model_motion_motion_value_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void model_motion_motion_value_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+} // namespace
+
+// Positive test case for a method
+int UtcDaliMotionValueNew(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliMotionValueNew");
+
+  MotionValue motionValue = MotionValue::New();
+  DALI_TEST_CHECK(motionValue);
+  END_TEST;
+}
+
+// Positive test case for a method
+int UtcDaliMotionValueDownCast(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline(" UtcDaliMotionValueDownCast");
+
+  MotionValue motionValue = MotionValue::New();
+  BaseHandle  handle(motionValue);
+
+  MotionValue motionValue2 = MotionValue::DownCast(handle);
+  DALI_TEST_CHECK(motionValue);
+  DALI_TEST_CHECK(motionValue2);
+  DALI_TEST_CHECK(motionValue2 == motionValue);
+  END_TEST;
+}
+
+int UtcDaliMotionValueTypeRegistry(void)
+{
+  ToolkitTestApplication application;
+
+  TypeRegistry typeRegistry = TypeRegistry::Get();
+  DALI_TEST_CHECK(typeRegistry);
+
+  TypeInfo typeInfo = typeRegistry.GetTypeInfo("MotionValue");
+  DALI_TEST_CHECK(typeInfo);
+
+  BaseHandle handle = typeInfo.CreateInstance();
+  DALI_TEST_CHECK(handle);
+
+  MotionValue motionValue = MotionValue::DownCast(handle);
+  DALI_TEST_CHECK(motionValue);
+
+  END_TEST;
+}
+
+int UtcDaliMotionValueCopyAndAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  MotionValue motionValue = MotionValue::New(1);
+  DALI_TEST_CHECK(motionValue);
+  DALI_TEST_CHECK(motionValue.GetValueType() == MotionValue::ValueType::PROPERTY_VALUE);
+
+  MotionValue copy(motionValue);
+  DALI_TEST_CHECK(motionValue == copy);
+  DALI_TEST_CHECK(copy.GetValueType() == MotionValue::ValueType::PROPERTY_VALUE);
+
+  MotionValue assign;
+  DALI_TEST_CHECK(!assign);
+
+  assign = copy;
+  DALI_TEST_CHECK(assign == motionValue);
+  DALI_TEST_CHECK(assign.GetValueType() == MotionValue::ValueType::PROPERTY_VALUE);
+
+  END_TEST;
+}
+
+int UtcDaliMotionValueMoveConstructor(void)
+{
+  ToolkitTestApplication application;
+
+  MotionValue motionValue = MotionValue::New(3.0f);
+  DALI_TEST_EQUALS(1, motionValue.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+  DALI_TEST_CHECK(motionValue.GetValueType() == MotionValue::ValueType::PROPERTY_VALUE);
+
+  MotionValue moved = std::move(motionValue);
+  DALI_TEST_CHECK(moved);
+  DALI_TEST_EQUALS(1, moved.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+  DALI_TEST_CHECK(moved.GetValueType() == MotionValue::ValueType::PROPERTY_VALUE);
+  DALI_TEST_CHECK(!motionValue);
+
+  END_TEST;
+}
+
+int UtcDaliMotionValueMoveAssignment(void)
+{
+  ToolkitTestApplication application;
+
+  MotionValue motionValue = MotionValue::New(KeyFrames::New());
+  DALI_TEST_EQUALS(1, motionValue.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+  DALI_TEST_CHECK(motionValue.GetValueType() == MotionValue::ValueType::KEY_FRAMES);
+
+  MotionValue moved;
+  moved = std::move(motionValue);
+  DALI_TEST_CHECK(moved);
+  DALI_TEST_EQUALS(1, moved.GetBaseObject().ReferenceCount(), TEST_LOCATION);
+  DALI_TEST_CHECK(moved.GetValueType() == MotionValue::ValueType::KEY_FRAMES);
+
+  END_TEST;
+}
+
+// Method test
+
+int UtcDaliMotionValueGetSetValue(void)
+{
+  ToolkitTestApplication application;
+
+  MotionValue motionValue = MotionValue::New();
+  DALI_TEST_CHECK(motionValue.GetValueType() == MotionValue::ValueType::INVALID);
+  DALI_TEST_CHECK(motionValue.GetPropertyValue().GetType() == Property::Type::NONE);
+  DALI_TEST_CHECK(!motionValue.GetKeyFrames());
+
+  float expectValue = 3.0f;
+  motionValue.SetValue(expectValue);
+  DALI_TEST_CHECK(motionValue.GetValueType() == MotionValue::ValueType::PROPERTY_VALUE);
+  DALI_TEST_CHECK(motionValue.GetPropertyValue().GetType() == Property::Type::FLOAT);
+  DALI_TEST_CHECK(motionValue.GetPropertyValue().Get<float>() == expectValue);
+
+  // Check the converted KeyFrames
+  auto convertedKeyFrames = motionValue.GetKeyFrames();
+  DALI_TEST_CHECK(convertedKeyFrames);
+  auto convertedKeyFrameCount = DevelKeyFrames::GetKeyFrameCount(convertedKeyFrames);
+  for(auto i = 0u; i < convertedKeyFrameCount; ++i)
+  {
+    float           progress;
+    Property::Value value;
+    DevelKeyFrames::GetKeyFrame(convertedKeyFrames, i, progress, value);
+
+    // Check all value has same as expect property.
+    DALI_TEST_EQUALS(value.Get<float>(), expectValue, TEST_LOCATION);
+  }
+
+  KeyFrames expectKeyFrames = KeyFrames::New();
+  expectValue               = 2.0f;
+  expectKeyFrames.Add(0.0f, expectValue - 1.0f);
+  expectKeyFrames.Add(1.0f, expectValue);
+  motionValue.SetValue(expectKeyFrames);
+
+  DALI_TEST_CHECK(motionValue.GetValueType() == MotionValue::ValueType::KEY_FRAMES);
+  DALI_TEST_CHECK(motionValue.GetKeyFrames() == expectKeyFrames);
+
+  // Check property value return last frame value.
+  DALI_TEST_CHECK(motionValue.GetPropertyValue().GetType() == Property::Type::FLOAT);
+  DALI_TEST_EQUALS(motionValue.GetPropertyValue().Get<float>(), expectValue, TEST_LOCATION);
+
+  motionValue.Clear();
+  DALI_TEST_CHECK(motionValue.GetValueType() == MotionValue::ValueType::INVALID);
+  DALI_TEST_CHECK(motionValue.GetPropertyValue().GetType() == Property::Type::NONE);
+  DALI_TEST_CHECK(!motionValue.GetKeyFrames());
+
+  END_TEST;
+}
\ No newline at end of file
index 2d3bad9..eb7c60a 100644 (file)
 #include <dali-scene3d/public-api/model-components/model-node.h>
 #include <dali-scene3d/public-api/model-components/model-primitive.h>
 
+#include <dali-scene3d/public-api/model-motion/motion-data.h>
+#include <dali-scene3d/public-api/model-motion/motion-index/blend-shape-index.h>
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-index.h>
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-property-index.h>
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-transform-index.h>
+#include <dali-scene3d/public-api/model-motion/motion-value.h>
+
 #endif // DALI_SCENE3D_H
\ No newline at end of file
index 73823d5..acaccbf 100644 (file)
@@ -43,6 +43,7 @@
 #include <dali-scene3d/public-api/loader/node-definition.h>
 #include <dali-scene3d/public-api/loader/scene-definition.h>
 #include <dali-scene3d/public-api/loader/shader-definition-factory.h>
+#include <dali-scene3d/public-api/model-motion/motion-index/blend-shape-index.h>
 
 using namespace Dali;
 
@@ -118,8 +119,7 @@ void ConfigureBlendShapeShaders(
   Dali::Scene3D::Loader::ResourceBundle& resources, const Dali::Scene3D::Loader::SceneDefinition& scene, Actor root, std::vector<Dali::Scene3D::Loader::BlendshapeShaderConfigurationRequest>&& requests)
 {
   std::vector<std::string> errors;
-  auto                     onError = [&errors](const std::string& msg)
-  { errors.push_back(msg); };
+  auto                     onError = [&errors](const std::string& msg) { errors.push_back(msg); };
   if(!scene.ConfigureBlendshapeShaders(resources, root, std::move(requests), onError))
   {
     Dali::Scene3D::Loader::ExceptionFlinger flinger(ASSERT_LOCATION);
@@ -178,7 +178,6 @@ void AddLightRecursively(Scene3D::ModelNode node, Scene3D::Light light, uint32_t
   {
     return;
   }
-
   GetImplementation(node).AddLight(light, lightIndex);
 
   uint32_t childrenCount = node.GetChildCount();
@@ -212,6 +211,27 @@ void RemoveLightRecursively(Scene3D::ModelNode node, uint32_t lightIndex)
   }
 }
 
+void UpdateBlendShapeNodeMapRecursively(Model::BlendShapeModelNodeMap& resultMap, const Scene3D::ModelNode& node)
+{
+  if(!node)
+  {
+    return;
+  }
+  const auto childCount = node.GetChildCount();
+  for(auto i = 0u; i < childCount; ++i)
+  {
+    UpdateBlendShapeNodeMapRecursively(resultMap, Scene3D::ModelNode::DownCast(node.GetChildAt(i)));
+  }
+
+  std::vector<std::string> blendShapeNames;
+  node.RetrieveBlendShapeNames(blendShapeNames);
+  for(const auto& iter : blendShapeNames)
+  {
+    // Append or create new list.
+    resultMap[iter].push_back(node);
+  }
+}
+
 } // anonymous namespace
 
 Model::Model(const std::string& modelUrl, const std::string& resourceDirectoryUrl)
@@ -516,6 +536,229 @@ Scene3D::ModelNode Model::FindChildModelNodeByName(std::string_view nodeName)
   return Scene3D::ModelNode::DownCast(childActor);
 }
 
+void Model::RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const
+{
+  blendShapeNames.reserve(blendShapeNames.size() + mBlendShapeModelNodeMap.size());
+  for(const auto& iter : mBlendShapeModelNodeMap)
+  {
+    blendShapeNames.push_back(iter.first);
+  }
+}
+
+void Model::RetrieveModelNodesByBlendShapeName(std::string_view blendShapeName, std::vector<Scene3D::ModelNode>& modelNodes) const
+{
+  auto iter = mBlendShapeModelNodeMap.find(std::string(blendShapeName));
+  if(iter != mBlendShapeModelNodeMap.end())
+  {
+    const auto& modelNodeList = iter->second;
+    modelNodes.reserve(modelNodes.size() + modelNodeList.size());
+    for(const auto& nodeIter : modelNodeList)
+    {
+      modelNodes.push_back(nodeIter);
+    }
+  }
+}
+
+Dali::Animation Model::GenerateMotionDataAnimation(Scene3D::MotionData motionData)
+{
+  Dali::Animation animation;
+
+  // TODO : Collect duplicated codes.
+
+  if(motionData)
+  {
+    const uint32_t motionCount = motionData.GetMotionCount();
+    for(uint32_t i = 0u; i < motionCount; ++i)
+    {
+      auto motionIndex = motionData.GetIndex(i);
+      auto motionValue = motionData.GetValue(i);
+      if(motionIndex && motionValue)
+      {
+        if(motionIndex.GetModelNodeId() != Property::INVALID_KEY)
+        {
+          Scene3D::ModelNode modelNode;
+          if(motionIndex.GetModelNodeId().type == Property::Key::Type::STRING)
+          {
+            modelNode = FindChildModelNodeByName(motionIndex.GetModelNodeId().stringKey);
+          }
+          else if(motionIndex.GetModelNodeId().type == Property::Key::Type::INDEX)
+          {
+            // TODO : Not implement yet.
+          }
+
+          if(modelNode)
+          {
+            KeyFrames keyFrames = motionValue.GetKeyFrames();
+
+            if(keyFrames)
+            {
+              // Try to use index first. If failed, try to use name
+              Property::Index animatedPropertyIndex = motionIndex.GetPropertyIndex(modelNode);
+              if(animatedPropertyIndex != Property::INVALID_INDEX)
+              {
+                if(DALI_UNLIKELY(!animation))
+                {
+                  animation = Animation::New(motionData.GetDuration());
+                }
+                animation.AnimateBetween(Dali::Property(modelNode, animatedPropertyIndex), keyFrames);
+              }
+              else
+              {
+                std::string    animatedPropertyName = motionIndex.GetPropertyName(modelNode);
+                Dali::Property property(modelNode, animatedPropertyName);
+                if(property.propertyIndex != Property::INVALID_INDEX)
+                {
+                  if(DALI_UNLIKELY(!animation))
+                  {
+                    animation = Animation::New(motionData.GetDuration());
+                  }
+                  animation.AnimateBetween(property, keyFrames);
+                }
+              }
+            }
+          }
+        }
+        else
+        {
+          Scene3D::BlendShapeIndex blendShapeIndex = Scene3D::BlendShapeIndex::DownCast(motionIndex);
+          if(blendShapeIndex && blendShapeIndex.GetBlendShapeId().type == Property::Key::Type::STRING)
+          {
+            // Special case : For BlendShapeIndex that doesn't have ModelNodeId and has string BlendShapeId,
+            // we need to animate all kind of blendshapes
+
+            KeyFrames keyFrames = motionValue.GetKeyFrames();
+
+            if(keyFrames)
+            {
+              std::vector<Scene3D::ModelNode> modelNodes;
+              RetrieveModelNodesByBlendShapeName(blendShapeIndex.GetBlendShapeId().stringKey, modelNodes);
+
+              for(auto& modelNode : modelNodes)
+              {
+                // Try to use index first. If failed, try to use name
+                Property::Index animatedPropertyIndex = motionIndex.GetPropertyIndex(modelNode);
+                if(animatedPropertyIndex != Property::INVALID_INDEX)
+                {
+                  if(DALI_UNLIKELY(!animation))
+                  {
+                    animation = Animation::New(motionData.GetDuration());
+                  }
+                  animation.AnimateBetween(Dali::Property(modelNode, animatedPropertyIndex), keyFrames);
+                }
+                else
+                {
+                  std::string    animatedPropertyName = motionIndex.GetPropertyName(modelNode);
+                  Dali::Property property(modelNode, animatedPropertyName);
+
+                  if(property.propertyIndex != Property::INVALID_INDEX)
+                  {
+                    if(DALI_UNLIKELY(!animation))
+                    {
+                      animation = Animation::New(motionData.GetDuration());
+                    }
+                    animation.AnimateBetween(property, keyFrames);
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  return animation;
+}
+
+void Model::SetMotionData(Scene3D::MotionData motionData)
+{
+  // TODO : Collect duplicated codes.
+  if(motionData)
+  {
+    const uint32_t motionCount = motionData.GetMotionCount();
+    for(uint32_t i = 0u; i < motionCount; ++i)
+    {
+      auto motionIndex = motionData.GetIndex(i);
+      auto motionValue = motionData.GetValue(i);
+      if(motionIndex && motionValue)
+      {
+        if(motionIndex.GetModelNodeId() != Property::INVALID_KEY)
+        {
+          Scene3D::ModelNode modelNode;
+          if(motionIndex.GetModelNodeId().type == Property::Key::Type::STRING)
+          {
+            modelNode = FindChildModelNodeByName(motionIndex.GetModelNodeId().stringKey);
+          }
+          else if(motionIndex.GetModelNodeId().type == Property::Key::Type::INDEX)
+          {
+            // TODO : Not implement yet.
+          }
+
+          if(modelNode)
+          {
+            Property::Value value = motionValue.GetPropertyValue();
+
+            if(value.GetType() != Property::Type::NONE)
+            {
+              // Try to use index first. If failed, try to use name
+              Property::Index propertyIndex = motionIndex.GetPropertyIndex(modelNode);
+              if(propertyIndex != Property::INVALID_INDEX)
+              {
+                modelNode.SetProperty(propertyIndex, value);
+              }
+              else
+              {
+                std::string    propertyName = motionIndex.GetPropertyName(modelNode);
+                Dali::Property property(modelNode, propertyName);
+                if(property.propertyIndex != Property::INVALID_INDEX)
+                {
+                  modelNode.SetProperty(property.propertyIndex, value);
+                }
+              }
+            }
+          }
+        }
+        else
+        {
+          Scene3D::BlendShapeIndex blendShapeIndex = Scene3D::BlendShapeIndex::DownCast(motionIndex);
+          if(blendShapeIndex && blendShapeIndex.GetBlendShapeId().type == Property::Key::Type::STRING)
+          {
+            // Special case : For BlendShapeIndex that doesn't have ModelNodeId and has string BlendShapeId,
+            // we need to animate all kind of blendshapes
+
+            Property::Value value = motionValue.GetPropertyValue();
+
+            if(value.GetType() != Property::Type::NONE)
+            {
+              std::vector<Scene3D::ModelNode> modelNodes;
+              RetrieveModelNodesByBlendShapeName(blendShapeIndex.GetBlendShapeId().stringKey, modelNodes);
+
+              for(auto& modelNode : modelNodes)
+              {
+                // Try to use index first. If failed, try to use name
+                Property::Index propertyIndex = motionIndex.GetPropertyIndex(modelNode);
+                if(propertyIndex != Property::INVALID_INDEX)
+                {
+                  modelNode.SetProperty(propertyIndex, value);
+                }
+                else
+                {
+                  std::string    propertyName = motionIndex.GetPropertyName(modelNode);
+                  Dali::Property property(modelNode, propertyName);
+                  if(property.propertyIndex != Property::INVALID_INDEX)
+                  {
+                    modelNode.SetProperty(property.propertyIndex, value);
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
 ///////////////////////////////////////////////////////////
 //
 // Private methods
@@ -941,19 +1184,21 @@ void Model::CreateModel()
   resources.GenerateResources();
   for(auto iRoot : scene.GetRoots())
   {
-    if(auto actor = scene.CreateNodes(iRoot, resourceChoices, nodeParams))
+    if(auto modelNode = scene.CreateNodes(iRoot, resourceChoices, nodeParams))
     {
-      scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
-      ConfigureBlendShapeShaders(resources, scene, actor, std::move(nodeParams.mBlendshapeRequests));
+      scene.ConfigureSkinningShaders(resources, modelNode, std::move(nodeParams.mSkinnables));
+      ConfigureBlendShapeShaders(resources, scene, modelNode, std::move(nodeParams.mBlendshapeRequests));
 
-      scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
+      scene.ApplyConstraints(modelNode, std::move(nodeParams.mConstrainables));
 
-      mModelRoot.Add(actor);
+      mModelRoot.Add(modelNode);
     }
 
     AddModelTreeToAABB(AABB, scene, resourceChoices, iRoot, nodeParams, Matrix::IDENTITY);
   }
 
+  UpdateBlendShapeNodeMap();
+
   mNaturalSize = AABB.CalculateSize();
   mModelPivot  = AABB.CalculatePivot();
   mModelRoot.SetProperty(Dali::Actor::Property::SIZE, mNaturalSize);
@@ -971,8 +1216,7 @@ void Model::CreateAnimations(Dali::Scene3D::Loader::SceneDefinition& scene)
   mAnimations.clear();
   if(!mModelLoadTask->GetAnimations().empty())
   {
-    auto getActor = [&](const Scene3D::Loader::AnimatedProperty& property)
-    {
+    auto getActor = [&](const Scene3D::Loader::AnimatedProperty& property) {
       if(property.mNodeIndex == Scene3D::Loader::INVALID_INDEX)
       {
         return mModelRoot.FindChildByName(property.mNodeName);
@@ -1003,6 +1247,14 @@ void Model::ResetCameraParameters()
   }
 }
 
+void Model::UpdateBlendShapeNodeMap()
+{
+  // Remove privous node map
+  mBlendShapeModelNodeMap.clear();
+
+  UpdateBlendShapeNodeMapRecursively(mBlendShapeModelNodeMap, mModelRoot);
+}
+
 } // namespace Internal
 } // namespace Scene3D
 } // namespace Dali
index 52aed7d..f383aff 100644 (file)
@@ -20,6 +20,7 @@
 
 // EXTERNAL INCLUDES
 #include <dali-toolkit/public-api/controls/control-impl.h>
+#include <dali/devel-api/common/map-wrapper.h>
 #include <dali/public-api/actors/camera-actor.h>
 #include <dali/public-api/actors/layer.h>
 #include <dali/public-api/animation/animation.h>
@@ -51,8 +52,9 @@ namespace Internal
 class Model : public Dali::Toolkit::Internal::Control, public LightObserver
 {
 public:
-  using AnimationData = std::pair<std::string, Dali::Animation>;
-  using CameraData    = Loader::CameraParameters;
+  using AnimationData          = std::pair<std::string, Dali::Animation>;
+  using CameraData             = Loader::CameraParameters;
+  using BlendShapeModelNodeMap = std::map<std::string, std::vector<Scene3D::ModelNode>>;
 
   /**
    * @copydoc Model::New()
@@ -144,6 +146,26 @@ public:
    */
   Scene3D::ModelNode FindChildModelNodeByName(std::string_view nodeName);
 
+  /**
+   * @copydoc Model::RetrieveBlendShapeNames()
+   */
+  void RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const;
+
+  /**
+   * @copydoc Model::RetrieveModelNodesByBlendShapeName()
+   */
+  void RetrieveModelNodesByBlendShapeName(std::string_view blendShapeName, std::vector<Scene3D::ModelNode>& modelNodes) const;
+
+  /**
+   * @copydoc Model::GenerateMotionDataAnimation()
+   */
+  Dali::Animation GenerateMotionDataAnimation(Scene3D::MotionData motionData);
+
+  /**
+   * @copydoc Model::SetMotionData()
+   */
+  void SetMotionData(Scene3D::MotionData motionData);
+
 protected:
   /**
    * @brief Constructs a new Model.
@@ -325,6 +347,11 @@ private:
    */
   void ResetCameraParameters();
 
+  /**
+   * @brief Collect ModelNode list by blendshape name
+   */
+  void UpdateBlendShapeNodeMap();
+
 private:
   std::string                    mModelUrl;
   std::string                    mResourceDirectoryUrl;
@@ -337,6 +364,9 @@ private:
   // Light
   std::vector<Scene3D::Light> mLights;
 
+  // List of ModelNode for name of blend shape.
+  BlendShapeModelNodeMap mBlendShapeModelNodeMap;
+
   // Asynchronous loading variable
   ModelLoadTaskPtr          mModelLoadTask;
   EnvironmentMapLoadTaskPtr mIblDiffuseLoadTask;
index 56200d2..9ea43a8 100644 (file)
@@ -22,4 +22,11 @@ set(scene3d_src_files ${scene3d_src_files}
        ${scene3d_internal_dir}/model-components/material-impl.cpp
        ${scene3d_internal_dir}/model-components/model-node-impl.cpp
        ${scene3d_internal_dir}/model-components/model-primitive-impl.cpp
+       ${scene3d_internal_dir}/model-motion/motion-data-impl.cpp
+       ${scene3d_internal_dir}/model-motion/motion-data-load-task.cpp
+       ${scene3d_internal_dir}/model-motion/motion-index/blend-shape-index-impl.cpp
+       ${scene3d_internal_dir}/model-motion/motion-index/motion-index-impl.cpp
+       ${scene3d_internal_dir}/model-motion/motion-index/motion-property-index-impl.cpp
+       ${scene3d_internal_dir}/model-motion/motion-index/motion-transform-index-impl.cpp
+       ${scene3d_internal_dir}/model-motion/motion-value-impl.cpp
 )
index 7a8af2b..7d2c332 100644 (file)
@@ -426,10 +426,25 @@ struct Mesh : Named
     //TODO: extensions
   };
 
+  struct Extras
+  {
+    std::vector<std::string_view> mTargetNames;
+
+    //TODO: extras
+  };
+
+  struct Extensions
+  {
+    std::vector<std::string_view> mSXRTargetsNames;
+    std::vector<std::string_view> mAvatarShapeNames;
+
+    //TODO: extensions
+  };
+
   std::vector<Primitive> mPrimitives;
   std::vector<float>     mWeights;
-  //TODO: extras
-  //TODO: extensions
+  Extras                 mExtras;
+  Extensions             mExtensions;
 };
 
 struct Node;
index 219f207..90deac9 100644 (file)
@@ -281,6 +281,44 @@ const json::Reader<gltf2::Mesh::Primitive>& GetMeshPrimitiveReader()
   return MESH_PRIMITIVE_READER;
 }
 
+const json::Reader<gltf2::Mesh::Extras>& GetMeshExtrasReader()
+{
+  static const auto MESH_EXTRAS_READER = std::move(json::Reader<gltf2::Mesh::Extras>()
+                                                     .Register(*json::MakeProperty("targetNames", json::Read::Array<std::string_view, json::Read::StringView>, &gltf2::Mesh::Extras::mTargetNames)));
+  return MESH_EXTRAS_READER;
+}
+
+std::vector<std::string_view> ReadMeshExtensionsTargetsName(const json_value_s& j)
+{
+  auto&                         jsonObject = json::Cast<json_object_s>(j);
+  std::vector<std::string_view> result;
+
+  auto element = jsonObject.start;
+  while(element)
+  {
+    auto     jsonString = *element->name;
+    uint32_t index      = json::Read::Number<uint32_t>(*element->value);
+
+    if(result.size() <= index)
+    {
+      result.resize(index + 1u);
+    }
+
+    result[index] = json::Read::StringView(jsonString);
+
+    element = element->next;
+  }
+  return result;
+}
+
+const json::Reader<gltf2::Mesh::Extensions>& GetMeshExtensionsReader()
+{
+  static const auto MESH_EXTENSIONS_READER = std::move(json::Reader<gltf2::Mesh::Extensions>()
+                                                         .Register(*json::MakeProperty("SXR_targets_names", ReadMeshExtensionsTargetsName, &gltf2::Mesh::Extensions::mSXRTargetsNames))
+                                                         .Register(*json::MakeProperty("avatar_shape_names", ReadMeshExtensionsTargetsName, &gltf2::Mesh::Extensions::mAvatarShapeNames)));
+  return MESH_EXTENSIONS_READER;
+}
+
 const json::Reader<gltf2::Mesh>& GetMeshReader()
 {
   static const auto MESH_READER = std::move(json::Reader<gltf2::Mesh>()
@@ -288,7 +326,9 @@ const json::Reader<gltf2::Mesh>& GetMeshReader()
                                               .Register(*json::MakeProperty("primitives",
                                                                             json::Read::Array<gltf2::Mesh::Primitive, json::ObjectReader<gltf2::Mesh::Primitive>::Read>,
                                                                             &gltf2::Mesh::mPrimitives))
-                                              .Register(*json::MakeProperty("weights", json::Read::Array<float, json::Read::Number>, &gltf2::Mesh::mWeights)));
+                                              .Register(*json::MakeProperty("weights", json::Read::Array<float, json::Read::Number>, &gltf2::Mesh::mWeights))
+                                              .Register(*json::MakeProperty("extras", json::ObjectReader<gltf2::Mesh::Extras>::Read, &gltf2::Mesh::mExtras))
+                                              .Register(*json::MakeProperty("extensions", json::ObjectReader<gltf2::Mesh::Extensions>::Read, &gltf2::Mesh::mExtensions)));
   return MESH_READER;
 }
 
@@ -541,8 +581,7 @@ void AddTextureStage(uint32_t semantic, MaterialDefinition& materialDefinition,
 
 void ConvertMaterial(const gltf2::Material& material, const std::unordered_map<std::string, ImageMetadata>& imageMetaData, decltype(ResourceBundle::mMaterials)& outMaterials, ConversionContext& context)
 {
-  auto getTextureMetaData = [](const std::unordered_map<std::string, ImageMetadata>& metaData, const gltf2::TextureInfo& info)
-  {
+  auto getTextureMetaData = [](const std::unordered_map<std::string, ImageMetadata>& metaData, const gltf2::TextureInfo& info) {
     if(!info.mTexture->mSource->mUri.empty())
     {
       if(auto search = metaData.find(info.mTexture->mSource->mUri.data()); search != metaData.end())
@@ -796,6 +835,7 @@ void ConvertMeshes(const gltf2::Document& document, ConversionContext& context)
       {
         meshDefinition.mBlendShapes.reserve(primitive.mTargets.size());
         meshDefinition.mBlendShapeVersion = BlendShapes::Version::VERSION_2_0;
+        uint32_t blendShapeIndex          = 0u;
         for(const auto& target : primitive.mTargets)
         {
           MeshDefinition::BlendShape blendShape;
@@ -822,7 +862,22 @@ void ConvertMeshes(const gltf2::Document& document, ConversionContext& context)
             blendShape.weight = mesh.mWeights[meshDefinition.mBlendShapes.size()];
           }
 
+          // Get blendshape name from extras / SXR_targets_names / avatar_shape_names.
+          if(blendShapeIndex < mesh.mExtras.mTargetNames.size())
+          {
+            blendShape.name = mesh.mExtras.mTargetNames[blendShapeIndex];
+          }
+          else if(blendShapeIndex < mesh.mExtensions.mSXRTargetsNames.size())
+          {
+            blendShape.name = mesh.mExtensions.mSXRTargetsNames[blendShapeIndex];
+          }
+          else if(blendShapeIndex < mesh.mExtensions.mAvatarShapeNames.size())
+          {
+            blendShape.name = mesh.mExtensions.mAvatarShapeNames[blendShapeIndex];
+          }
+
           meshDefinition.mBlendShapes.push_back(std::move(blendShape));
+          ++blendShapeIndex;
         }
       }
 
@@ -900,8 +955,7 @@ void ConvertNode(gltf2::Node const& node, const Index gltfIndex, Index parentInd
   auto& resources = output.mResources;
 
   const auto index    = scene.GetNodeCount();
-  auto       weakNode = scene.AddNode([&]()
-                                {
+  auto       weakNode = scene.AddNode([&]() {
     std::unique_ptr<NodeDefinition> nodeDefinition{new NodeDefinition()};
 
     nodeDefinition->mParentIdx = parentIndex;
@@ -1333,6 +1387,8 @@ void SetObjectReaders()
   json::SetObjectReader(GetMaterialExtensionsReader());
   json::SetObjectReader(GetMaterialReader());
   json::SetObjectReader(GetMeshPrimitiveReader());
+  json::SetObjectReader(GetMeshExtrasReader());
+  json::SetObjectReader(GetMeshExtensionsReader());
   json::SetObjectReader(GetMeshReader());
   json::SetObjectReader(GetSkinReader());
   json::SetObjectReader(GetCameraPerspectiveReader());
index 100472a..45e4e42 100644 (file)
@@ -170,10 +170,15 @@ struct Read
     return static_cast<E>(number);
   }
 
+  static std::string_view StringView(const json_string_s& js)
+  {
+    return std::string_view(js.string, js.string_size);
+  }
+
   static std::string_view StringView(const json_value_s& j)
   {
     auto& js = Cast<json_string_s>(j);
-    return std::string_view(js.string, js.string_size);
+    return StringView(js);
   }
 
   static std::string String(const json_value_s& j)
index 64b3ec2..a37d4a8 100644 (file)
@@ -24,8 +24,8 @@
 #include <dali/public-api/object/type-registry.h>
 
 // INTERNAL INCLUDES
-#include <dali-scene3d/internal/model-components/model-primitive-impl.h>
 #include <dali-scene3d/internal/light/light-impl.h>
+#include <dali-scene3d/internal/model-components/model-primitive-impl.h>
 
 namespace Dali
 {
@@ -280,6 +280,25 @@ Scene3D::ModelNode ModelNode::FindChildModelNodeByName(std::string_view nodeName
   return Scene3D::ModelNode::DownCast(childActor);
 }
 
+void ModelNode::RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const
+{
+  blendShapeNames.reserve(blendShapeNames.size() + mBlendShapeIndexMap.size());
+  for(const auto& iter : mBlendShapeIndexMap)
+  {
+    blendShapeNames.push_back(iter.first);
+  }
+}
+
+Loader::BlendShapes::Index ModelNode::GetBlendShapeIndexByName(std::string_view blendShapeName) const
+{
+  auto iter = mBlendShapeIndexMap.find(std::string(blendShapeName));
+  if(iter != mBlendShapeIndexMap.end())
+  {
+    return iter->second;
+  }
+  return Loader::BlendShapes::INVALID_INDEX;
+}
+
 void ModelNode::SetImageBasedLightTexture(Dali::Texture diffuseTexture, Dali::Texture specularTexture, float iblScaleFactor, uint32_t specularMipmapLevels)
 {
   mDiffuseTexture       = diffuseTexture;
@@ -321,6 +340,18 @@ void ModelNode::RemoveLight(uint32_t lightIndex)
 
 void ModelNode::SetBlendShapeData(Scene3D::Loader::BlendShapes::BlendShapeData& data, Scene3D::ModelPrimitive primitive)
 {
+  // Update mBlendShapeIndexMap
+  mBlendShapeIndexMap.clear();
+  const auto blendShapeCount = data.names.size();
+  for(Loader::BlendShapes::Index index = 0u; index < blendShapeCount; ++index)
+  {
+    auto& name = data.names[index];
+    if(!name.empty())
+    {
+      mBlendShapeIndexMap[name] = index;
+    }
+  }
+
   GetImplementation(primitive).SetBlendShapeData(data);
 }
 
@@ -372,8 +403,7 @@ void ModelNode::UpdateBoneMatrix(Scene3D::ModelPrimitive primitive)
 
     Matrix inverseMatrix = boneData.inverseMatrix;
     // Constrain bone matrix to joint transform.
-    boneData.constraint = Constraint::New<Matrix>(renderer, propBoneXform, [inverseMatrix](Matrix& output, const PropertyInputContainer& inputs)
-                                                  { Matrix::Multiply(output, inverseMatrix, inputs[0]->GetMatrix()); });
+    boneData.constraint = Constraint::New<Matrix>(renderer, propBoneXform, [inverseMatrix](Matrix& output, const PropertyInputContainer& inputs) { Matrix::Multiply(output, inverseMatrix, inputs[0]->GetMatrix()); });
 
     Actor joint = Self();
     boneData.constraint.AddSource(Source{joint, Actor::Property::WORLD_MATRIX});
index 4b9a66d..8a06116 100644 (file)
  */
 
 // EXTERNAL INCLUDES
+#include <dali/devel-api/common/map-wrapper.h>
 #include <dali/public-api/actors/custom-actor-impl.h>
 #include <dali/public-api/common/dali-common.h>
 #include <memory> // for std::unique_ptr
+#include <string>
 
 // INTERNAL INCLUDES
 #include <dali-scene3d/internal/model-components/model-primitive-modify-observer.h>
@@ -52,6 +54,7 @@ class DALI_SCENE3D_API ModelNode : public CustomActorImpl, public ModelPrimitive
 public:
   using ModelPrimitiveContainer = std::vector<Scene3D::ModelPrimitive>;
   using BoneDataContainer       = std::vector<Dali::Scene3D::Loader::Skinning::BoneData>;
+  using BlendShapeIndexMap      = std::map<std::string, Loader::BlendShapes::Index>;
 
   // Creation & Destruction
   /**
@@ -217,6 +220,16 @@ public: // Public Method
   Scene3D::ModelNode FindChildModelNodeByName(std::string_view nodeName);
 
   /**
+   * @copydoc Dali::Scene3D::ModelNode::RetrieveBlendShapeNames()
+   */
+  void RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const;
+
+  /**
+   * @copydoc Dali::Scene3D::ModelNode::GetBlendShapeIndexByName()
+   */
+  Loader::BlendShapes::Index GetBlendShapeIndexByName(std::string_view blendShapeName) const;
+
+  /**
    * @brief Sets the diffuse and specular image-based lighting textures for a ModelPrimitive.
    *
    * @param[in] diffuseTexture The diffuse texture.
@@ -272,14 +285,15 @@ private:
   /// @cond internal
 
   // Not copyable or movable
-  DALI_INTERNAL            ModelNode(const ModelNode&) = delete; ///< Deleted copy constructor.
-  DALI_INTERNAL            ModelNode(ModelNode&&)      = delete; ///< Deleted move constructor.
+  DALI_INTERNAL ModelNode(const ModelNode&) = delete;            ///< Deleted copy constructor.
+  DALI_INTERNAL ModelNode(ModelNode&&)      = delete;            ///< Deleted move constructor.
   DALI_INTERNAL ModelNode& operator=(const ModelNode&) = delete; ///< Deleted copy assignment operator.
-  DALI_INTERNAL ModelNode& operator=(ModelNode&&)      = delete; ///< Deleted move assignment operator.
+  DALI_INTERNAL ModelNode& operator=(ModelNode&&) = delete;      ///< Deleted move assignment operator.
 
 private:
   ModelPrimitiveContainer mModelPrimitiveContainer; ///< List of model primitives
   BoneDataContainer       mBoneDataContainer;
+  BlendShapeIndexMap      mBlendShapeIndexMap; ///< Index of blend shape by name
   Dali::Texture           mSpecularTexture;
   Dali::Texture           mDiffuseTexture;
   float                   mIblScaleFactor{1.0f};
diff --git a/dali-scene3d/internal/model-motion/motion-data-impl.cpp b/dali-scene3d/internal/model-motion/motion-data-impl.cpp
new file mode 100644 (file)
index 0000000..bb3f1cc
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-scene3d/internal/model-motion/motion-data-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/public-api/adaptor-framework/async-task-manager.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/public-api/object/type-registry.h>
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-property-index.h>
+
+namespace Dali
+{
+namespace Scene3D
+{
+namespace Internal
+{
+namespace
+{
+/**
+ * Creates control through type registry
+ */
+BaseHandle Create()
+{
+  return Scene3D::MotionData::New();
+}
+
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN(Scene3D::MotionData, Dali::BaseHandle, Create);
+DALI_TYPE_REGISTRATION_END()
+
+} // unnamed namespace
+
+MotionDataPtr MotionData::New()
+{
+  MotionDataPtr motionData = new MotionData();
+
+  motionData->Initialize();
+
+  return motionData;
+}
+
+MotionData::MotionData()
+{
+}
+
+MotionData::~MotionData()
+{
+  if(Dali::Adaptor::IsAvailable())
+  {
+    CancelMotionDataLoad();
+  }
+}
+
+void MotionData::Initialize()
+{
+}
+
+uint32_t MotionData::GetMotionCount() const
+{
+  return static_cast<uint32_t>(mMotions.size());
+}
+
+Scene3D::MotionIndex MotionData::GetIndex(uint32_t index) const
+{
+  if(index < mMotions.size())
+  {
+    return mMotions[index].first;
+  }
+  return Scene3D::MotionIndex();
+}
+
+Scene3D::MotionValue MotionData::GetValue(uint32_t index) const
+{
+  if(index < mMotions.size())
+  {
+    return mMotions[index].second;
+  }
+  return Scene3D::MotionValue();
+}
+
+void MotionData::Add(Scene3D::MotionIndex index, Scene3D::MotionValue value)
+{
+  mMotions.emplace_back(index, value);
+}
+
+void MotionData::Clear()
+{
+  mMotions.clear();
+}
+
+void MotionData::SetDuration(float durationSeconds)
+{
+  mDurationSeconds = durationSeconds;
+}
+
+float MotionData::GetDuration() const
+{
+  return mDurationSeconds;
+}
+
+void MotionData::LoadBvh(const std::string& path, const Vector3& scale, bool synchronousLoad)
+{
+  CancelMotionDataLoad();
+  mMotionDataLoadTask = new MotionDataLoadTask(path, scale, MakeCallback(this, &MotionData::OnLoadCompleted));
+  RequestMotionDataLoad(synchronousLoad);
+}
+
+void MotionData::LoadBvhFromBuffer(const uint8_t* rawBuffer, int rawBufferLength, const Vector3& scale, bool synchronousLoad)
+{
+  CancelMotionDataLoad();
+  mMotionDataLoadTask = new MotionDataLoadTask(rawBuffer, rawBufferLength, scale, MakeCallback(this, &MotionData::OnLoadCompleted));
+  RequestMotionDataLoad(synchronousLoad);
+}
+
+void MotionData::LoadFacialAnimation(const std::string& url, bool synchronousLoad)
+{
+  CancelMotionDataLoad();
+  mMotionDataLoadTask = new MotionDataLoadTask(url, MakeCallback(this, &MotionData::OnLoadCompleted));
+  RequestMotionDataLoad(synchronousLoad);
+}
+
+void MotionData::LoadFacialAnimationFromBuffer(const uint8_t* rawBuffer, int rawBufferLength, bool synchronousLoad)
+{
+  CancelMotionDataLoad();
+  mMotionDataLoadTask = new MotionDataLoadTask(rawBuffer, rawBufferLength, MakeCallback(this, &MotionData::OnLoadCompleted));
+  RequestMotionDataLoad(synchronousLoad);
+}
+
+// Private method
+void MotionData::RequestMotionDataLoad(bool synchronousLoad)
+{
+  if(mMotionDataLoadTask)
+  {
+    if(synchronousLoad)
+    {
+      mMotionDataLoadTask->Process();
+      OnLoadCompleted(mMotionDataLoadTask);
+    }
+    else
+    {
+      Dali::AsyncTaskManager::Get().AddTask(mMotionDataLoadTask);
+    }
+  }
+}
+
+void MotionData::CancelMotionDataLoad()
+{
+  if(mMotionDataLoadTask)
+  {
+    Dali::AsyncTaskManager::Get().RemoveTask(mMotionDataLoadTask);
+    mMotionDataLoadTask.Reset();
+  }
+}
+
+// Called from MotionDataLoadTask
+void MotionData::OnLoadCompleted(MotionDataLoadTaskPtr task)
+{
+  if(mMotionDataLoadTask == task)
+  {
+    const Scene3D::Loader::AnimationDefinition& animationDefinition = mMotionDataLoadTask->GetAnimationDefinition();
+
+    mDurationSeconds = animationDefinition.GetDuration();
+
+    auto animatedPropertyCount = animationDefinition.GetPropertyCount();
+
+    mMotions.clear();
+    mMotions.reserve(animatedPropertyCount);
+
+    for(uint32_t i = 0u; i < animatedPropertyCount; ++i)
+    {
+      const auto& animatedProperty = animationDefinition.GetPropertyAt(i);
+
+      // TODO : Currently, we only support KeyFrames without alpha function and time period now.
+      if(animatedProperty.mKeyFrames)
+      {
+        Add(Scene3D::MotionPropertyIndex::New(animatedProperty.mNodeName, animatedProperty.mPropertyName), Scene3D::MotionValue::New(animatedProperty.mKeyFrames));
+      }
+    }
+
+    // Reset task before emit load competed signal.
+    mMotionDataLoadTask.Reset();
+    {
+      Scene3D::MotionData handle(this); ///< Keep handle for lifecycle.
+      LoadCompletedSignal().Emit(handle);
+    }
+  }
+}
+
+} // namespace Internal
+
+} // namespace Scene3D
+
+} // namespace Dali
\ No newline at end of file
diff --git a/dali-scene3d/internal/model-motion/motion-data-impl.h b/dali-scene3d/internal/model-motion/motion-data-impl.h
new file mode 100644 (file)
index 0000000..7b5316a
--- /dev/null
@@ -0,0 +1,192 @@
+#ifndef DALI_SCENE3D_MODEL_MOTION_MOTION_DATA_IMPL_H
+#define DALI_SCENE3D_MODEL_MOTION_MOTION_DATA_IMPL_H
+
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/object/base-object.h>
+
+#include <dali/public-api/common/vector-wrapper.h>
+#include <utility> ///< for std::pair
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/internal/model-motion/motion-data-load-task.h>
+#include <dali-scene3d/public-api/loader/animation-definition.h>
+#include <dali-scene3d/public-api/model-motion/motion-data.h>
+
+namespace Dali
+{
+namespace Scene3D
+{
+namespace Internal
+{
+using MotionDataPtr = IntrusivePtr<MotionData>;
+
+/**
+ * @brief Internal data for Scene3D::MotionData.
+ */
+class MotionData : public BaseObject
+{
+public: // Creation & Destruction
+  /**
+   * @brief Create a new MotionData object.
+   * @return A smart-pointer to the newly allocated MotionData.
+   */
+  static MotionDataPtr New();
+
+protected:
+  /**
+   * @brief Construct a new MotionData.
+   */
+  MotionData();
+
+  /**
+   * @brief Second-phase constructor.
+   */
+  void Initialize();
+
+  /**
+   * @brief Virtual destructor.
+   */
+  virtual ~MotionData();
+
+public: // Public Method
+  /**
+   * @copydoc Dali::Scene3D::MotionData::GetMotionCount()
+   */
+  uint32_t GetMotionCount() const;
+
+  /**
+   * @copydoc Dali::Scene3D::MotionData::GetIndex()
+   */
+  Scene3D::MotionIndex GetIndex(uint32_t index) const;
+
+  /**
+   * @copydoc Dali::Scene3D::MotionData::GetValue()
+   */
+  Scene3D::MotionValue GetValue(uint32_t index) const;
+
+  /**
+   * @copydoc Dali::Scene3D::MotionData::Add()
+   */
+  void Add(Scene3D::MotionIndex index, Scene3D::MotionValue value);
+
+  /**
+   * @copydoc Dali::Scene3D::MotionData::Clear()
+   */
+  void Clear();
+
+  /**
+   * @copydoc Dali::Scene3D::MotionData::SetDuration()
+   */
+  void SetDuration(float durationSeconds);
+
+  /**
+   * @copydoc Dali::Scene3D::MotionData::GetDuration()
+   */
+  float GetDuration() const;
+
+  /**
+   * @copydoc Dali::Scene3D::MotionData::LoadBvh()
+   */
+  void LoadBvh(const std::string& path, const Vector3& scale = Vector3::ONE, bool synchronousLoad = false);
+
+  /**
+   * @copydoc Dali::Scene3D::MotionData::LoadBvhFromBuffer()
+   */
+  void LoadBvhFromBuffer(const uint8_t* rawBuffer, int rawBufferLength, const Vector3& scale = Vector3::ONE, bool synchronousLoad = false);
+
+  /**
+   * @copydoc Dali::Scene3D::MotionData::LoadFacialAnimation()
+   */
+  void LoadFacialAnimation(const std::string& url, bool synchronousLoad = false);
+
+  /**
+   * @copydoc Dali::Scene3D::MotionData::LoadFacialAnimationFromBuffer()
+   */
+  void LoadFacialAnimationFromBuffer(const uint8_t* rawBuffer, int rawBufferLength, bool synchronousLoad = false);
+
+public:
+  /**
+   * @copydoc Dali::Scene3D::MotionData::LoadCompletedSignal()
+   */
+  Scene3D::MotionData::LoadCompletedSignalType& LoadCompletedSignal()
+  {
+    return mLoadCompletedSignal;
+  }
+
+private:
+  /**
+   * @brief Request motion data load task process.
+   *
+   * @param[in] synchronousLoad True if we want to load result synchronously.
+   */
+  void RequestMotionDataLoad(bool synchronousLoad);
+
+  /**
+   * @brief Cancel requested motion data load task process.
+   */
+  void CancelMotionDataLoad();
+
+private:
+  /**
+   * @brief Called when async load task completed.
+   *
+   * @param[in] task Completed tasks
+   */
+  void OnLoadCompleted(MotionDataLoadTaskPtr task);
+
+private:
+  // Asynchronous loading variable
+  MotionDataLoadTaskPtr                        mMotionDataLoadTask{nullptr};
+  Scene3D::MotionData::LoadCompletedSignalType mLoadCompletedSignal;
+
+  std::vector<std::pair<Scene3D::MotionIndex, Scene3D::MotionValue>> mMotions{};
+
+  float mDurationSeconds{0.0f}; ///< Duration of animation if we generate this motion data as Dali::Animation.
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::MotionData& GetImplementation(Dali::Scene3D::MotionData& motionData)
+{
+  DALI_ASSERT_ALWAYS(motionData && "MotionData handle is empty");
+
+  BaseObject& handle = motionData.GetBaseObject();
+
+  return static_cast<Internal::MotionData&>(handle);
+}
+
+inline const Internal::MotionData& GetImplementation(const Dali::Scene3D::MotionData& motionData)
+{
+  DALI_ASSERT_ALWAYS(motionData && "MotionData handle is empty");
+
+  const BaseObject& handle = motionData.GetBaseObject();
+
+  return static_cast<const Internal::MotionData&>(handle);
+}
+
+} // namespace Scene3D
+
+} // namespace Dali
+
+#endif // DALI_SCENE3D_MODEL_MOTION_MOTION_DATA_IMPL_H
\ No newline at end of file
diff --git a/dali-scene3d/internal/model-motion/motion-data-load-task.cpp b/dali-scene3d/internal/model-motion/motion-data-load-task.cpp
new file mode 100644 (file)
index 0000000..89bcf33
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-scene3d/internal/model-motion/motion-data-load-task.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/public-api/loader/bvh-loader.h>
+#include <dali-scene3d/public-api/loader/facial-animation-loader.h>
+
+namespace Dali
+{
+namespace Scene3D
+{
+namespace Internal
+{
+MotionDataLoadTask::MotionDataLoadTask(const std::string& path, const Vector3& scale, CallbackBase* callback)
+: AsyncTask(callback),
+  mFileUrl(path),
+  mRawBuffer(nullptr),
+  mRawBufferLength(0),
+  mScale(scale),
+  mAnimationDefinition{},
+  mLoadMethod(MotionDataLoadTask::LoadMethod::BVH_FILE)
+{
+}
+
+MotionDataLoadTask::MotionDataLoadTask(const uint8_t* rawBuffer, int rawBufferLength, const Vector3& scale, CallbackBase* callback)
+: AsyncTask(callback),
+  mFileUrl(),
+  mRawBuffer(nullptr),
+  mRawBufferLength(rawBufferLength),
+  mScale(scale),
+  mAnimationDefinition{},
+  mLoadMethod(MotionDataLoadTask::LoadMethod::BVH_BUFFER)
+{
+  // To keep life of raw buffer, let we copy data now.
+  mRawBuffer = new uint8_t[mRawBufferLength];
+  memcpy(mRawBuffer, rawBuffer, sizeof(uint8_t) * mRawBufferLength);
+}
+
+MotionDataLoadTask::MotionDataLoadTask(const std::string& url, CallbackBase* callback)
+: AsyncTask(callback),
+  mFileUrl(url),
+  mRawBuffer(nullptr),
+  mRawBufferLength(0),
+  mScale(),
+  mAnimationDefinition{},
+  mLoadMethod(MotionDataLoadTask::LoadMethod::FACIAL_FILE)
+{
+}
+
+MotionDataLoadTask::MotionDataLoadTask(const uint8_t* rawBuffer, int rawBufferLength, CallbackBase* callback)
+: AsyncTask(callback),
+  mFileUrl(),
+  mRawBuffer(nullptr),
+  mRawBufferLength(rawBufferLength),
+  mScale(),
+  mAnimationDefinition{},
+  mLoadMethod(MotionDataLoadTask::LoadMethod::FACIAL_BUFFER)
+{
+  // To keep life of raw buffer, let we copy data now.
+  mRawBuffer = new uint8_t[mRawBufferLength];
+  memcpy(mRawBuffer, rawBuffer, sizeof(uint8_t) * mRawBufferLength);
+}
+
+MotionDataLoadTask::~MotionDataLoadTask()
+{
+  if(mRawBuffer)
+  {
+    delete[] mRawBuffer;
+  }
+}
+
+void MotionDataLoadTask::Process()
+{
+  switch(mLoadMethod)
+  {
+    case LoadMethod::BVH_FILE:
+    {
+      mAnimationDefinition = std::move(Loader::LoadBvh(mFileUrl, "LoadedBvhMotionData", mScale));
+      break;
+    }
+    case LoadMethod::BVH_BUFFER:
+    {
+      mAnimationDefinition = std::move(Loader::LoadBvhFromBuffer(mRawBuffer, mRawBufferLength, "LoadedBvhMotionData", mScale));
+      break;
+    }
+    case LoadMethod::FACIAL_FILE:
+    {
+      mAnimationDefinition = std::move(Loader::LoadFacialAnimation(mFileUrl));
+      break;
+    }
+    case LoadMethod::FACIAL_BUFFER:
+    {
+      mAnimationDefinition = std::move(Loader::LoadFacialAnimationFromBuffer(mRawBuffer, mRawBufferLength));
+      break;
+    }
+  }
+}
+
+bool MotionDataLoadTask::IsReady()
+{
+  return true;
+}
+
+const Scene3D::Loader::AnimationDefinition& MotionDataLoadTask::GetAnimationDefinition() const
+{
+  return mAnimationDefinition;
+}
+
+} // namespace Internal
+
+} // namespace Scene3D
+
+} // namespace Dali
\ No newline at end of file
diff --git a/dali-scene3d/internal/model-motion/motion-data-load-task.h b/dali-scene3d/internal/model-motion/motion-data-load-task.h
new file mode 100644 (file)
index 0000000..89e9f21
--- /dev/null
@@ -0,0 +1,115 @@
+#ifndef DALI_SCENE3D_MODEL_MOTION_MOTION_DATA_LOAD_TASK_H
+#define DALI_SCENE3D_MODEL_MOTION_MOTION_DATA_LOAD_TASK_H
+
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/async-task-manager.h>
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/public-api/loader/animation-definition.h>
+#include <dali-scene3d/public-api/model-motion/motion-data.h>
+
+namespace Dali
+{
+namespace Scene3D
+{
+namespace Internal
+{
+class MotionDataLoadTask;
+typedef IntrusivePtr<MotionDataLoadTask> MotionDataLoadTaskPtr;
+
+/**
+ * @brief AsyncTask for load MotionData from various type.
+ * After load finished, it will keep result as Loader::AnimationDefinition.
+ */
+class MotionDataLoadTask : public AsyncTask
+{
+public:
+  enum class LoadMethod
+  {
+    BVH_FILE,
+    BVH_BUFFER,
+    FACIAL_FILE,
+    FACIAL_BUFFER,
+  };
+
+public:
+  /**
+   * Constructor for load bvh from file.
+   */
+  MotionDataLoadTask(const std::string& path, const Vector3& scale, CallbackBase* callback);
+
+  /**
+   * Constructor for load bvh from buffer.
+   */
+  MotionDataLoadTask(const uint8_t* rawBuffer, int rawBufferLength, const Vector3& scale, CallbackBase* callback);
+
+  /**
+   * Constructor for load facial from file.
+   */
+  MotionDataLoadTask(const std::string& url, CallbackBase* callback);
+
+  /**
+   * Constructor for load facial from buffer.
+   */
+  MotionDataLoadTask(const uint8_t* rawBuffer, int rawBufferLength, CallbackBase* callback);
+
+  /**
+   * Destructor.
+   */
+  ~MotionDataLoadTask();
+
+  /**
+   * Process the task
+   */
+  void Process() override;
+
+  /**
+   * Whether the task is ready to process.
+   * @return True if the task is ready to process.
+   */
+  bool IsReady() override;
+
+public:
+  const Scene3D::Loader::AnimationDefinition& GetAnimationDefinition() const;
+
+private:
+  // Undefined
+  MotionDataLoadTask(const MotionDataLoadTask& task) = delete;
+
+  // Undefined
+  MotionDataLoadTask& operator=(const MotionDataLoadTask& task) = delete;
+
+private:
+  std::string mFileUrl;
+  uint8_t*    mRawBuffer;
+  int         mRawBufferLength;
+  Vector3     mScale;
+
+  Scene3D::Loader::AnimationDefinition mAnimationDefinition;
+  LoadMethod                           mLoadMethod;
+};
+
+} // namespace Internal
+
+} // namespace Scene3D
+
+} // namespace Dali
+
+#endif // DALI_SCENE3D_MODEL_MOTION_MOTION_DATA_LOAD_TASK_H
\ No newline at end of file
diff --git a/dali-scene3d/internal/model-motion/motion-index/blend-shape-index-impl.cpp b/dali-scene3d/internal/model-motion/motion-index/blend-shape-index-impl.cpp
new file mode 100644 (file)
index 0000000..3848d04
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-scene3d/internal/model-motion/motion-index/blend-shape-index-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/public-api/object/type-registry.h>
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/public-api/loader/blend-shape-details.h> ///< For BlendShapes::WEIGHTS_UNIFORM
+
+namespace Dali
+{
+namespace Scene3D
+{
+namespace Internal
+{
+namespace
+{
+/**
+ * Creates control through type registry
+ */
+BaseHandle Create()
+{
+  return Scene3D::BlendShapeIndex::New();
+}
+
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN(Scene3D::BlendShapeIndex, Dali::BaseHandle, Create);
+DALI_TYPE_REGISTRATION_END()
+
+std::string GetBlendShapePropertyNameFromIndex(int index)
+{
+  if(index >= 0)
+  {
+    char weightNameBuffer[32];
+
+    // Get return value of snprintf to avoid SVACE.
+    [[maybe_unused]] auto prefixSize = snprintf(weightNameBuffer, sizeof(weightNameBuffer), "%s[%d]", Loader::BlendShapes::WEIGHTS_UNIFORM, index);
+
+    return weightNameBuffer;
+  }
+  return "";
+}
+
+} // namespace
+
+BlendShapeIndexPtr BlendShapeIndex::New()
+{
+  BlendShapeIndexPtr blendShapeIndex = new BlendShapeIndex();
+
+  blendShapeIndex->Initialize();
+
+  return blendShapeIndex;
+}
+
+BlendShapeIndex::BlendShapeIndex()
+{
+}
+
+BlendShapeIndex::~BlendShapeIndex()
+{
+}
+
+void BlendShapeIndex::Initialize()
+{
+}
+
+void BlendShapeIndex::SetBlendShapeId(Property::Key blendShapeId)
+{
+  mBlendShapeId = blendShapeId;
+}
+
+Property::Key BlendShapeIndex::GetBlendShapeId() const
+{
+  return mBlendShapeId;
+}
+
+std::string BlendShapeIndex::GetPropertyName(Scene3D::ModelNode node)
+{
+  if(mBlendShapeId.type == Property::Key::Type::INDEX)
+  {
+    if(mBlendShapeId.indexKey != Property::INVALID_INDEX)
+    {
+      return GetBlendShapePropertyNameFromIndex(mBlendShapeId.indexKey);
+    }
+  }
+  else if(mBlendShapeId.type == Property::Key::Type::STRING)
+  {
+    if(node)
+    {
+      auto index = node.GetBlendShapeIndexByName(mBlendShapeId.stringKey);
+      if(index != Scene3D::Loader::BlendShapes::INVALID_INDEX)
+      {
+        return GetBlendShapePropertyNameFromIndex(index);
+      }
+    }
+  }
+  return "";
+}
+
+Property::Index BlendShapeIndex::GetPropertyIndex(Scene3D::ModelNode node)
+{
+  // Not surport now
+  return Property::INVALID_INDEX;
+}
+
+} // namespace Internal
+
+} // namespace Scene3D
+
+} // namespace Dali
\ No newline at end of file
diff --git a/dali-scene3d/internal/model-motion/motion-index/blend-shape-index-impl.h b/dali-scene3d/internal/model-motion/motion-index/blend-shape-index-impl.h
new file mode 100644 (file)
index 0000000..42a3b35
--- /dev/null
@@ -0,0 +1,118 @@
+#ifndef DALI_SCENE3D_MODEL_MOTION_BLEND_SHAPE_INDEX_IMPL_H
+#define DALI_SCENE3D_MODEL_MOTION_BLEND_SHAPE_INDEX_IMPL_H
+
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/internal/model-motion/motion-index/motion-index-impl.h>
+#include <dali-scene3d/public-api/model-motion/motion-index/blend-shape-index.h>
+
+namespace Dali
+{
+namespace Scene3D
+{
+namespace Internal
+{
+using BlendShapeIndexPtr = IntrusivePtr<BlendShapeIndex>;
+
+/**
+ * @brief Internal data for Scene3D::BlendShapeIndex.
+ */
+class BlendShapeIndex : public MotionIndex
+{
+public: // Creation & Destruction
+  /**
+   * @brief Create a new BlendShapeIndex object.
+   * @return A smart-pointer to the newly allocated BlendShapeIndex.
+   */
+  static BlendShapeIndexPtr New();
+
+protected:
+  /**
+   * @brief Construct a new BlendShapeIndex.
+   */
+  BlendShapeIndex();
+
+  /**
+   * @brief Second-phase constructor.
+   */
+  void Initialize();
+
+  /**
+   * @brief Virtual destructor.
+   */
+  virtual ~BlendShapeIndex();
+
+public: // Public Method
+  /**
+   * @copydoc Dali::Scene3D::BlendShapeIndex::SetBlendShapeId()
+   */
+  void SetBlendShapeId(Property::Key blendShapeId);
+
+  /**
+   * @copydoc Dali::Scene3D::BlendShapeIndex::GetBlendShapeId()
+   */
+  Property::Key GetBlendShapeId() const;
+
+public: // MotionIndex Override Method
+  /**
+   * @copydoc Dali::Scene3D::Internal::MotionIndex::GetPropertyName()
+   */
+  std::string GetPropertyName(Scene3D::ModelNode node = Scene3D::ModelNode()) override;
+
+  /**
+   * @copydoc Dali::Scene3D::Internal::MotionIndex::GetPropertyIndex()
+   */
+  Property::Index GetPropertyIndex(Scene3D::ModelNode node = Scene3D::ModelNode()) override;
+
+protected:
+  Property::Key mBlendShapeId{Property::INVALID_KEY}; ///< The id of blend shape
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::BlendShapeIndex& GetImplementation(Dali::Scene3D::BlendShapeIndex& blendShapeIndex)
+{
+  DALI_ASSERT_ALWAYS(blendShapeIndex && "BlendShapeIndex handle is empty");
+
+  BaseObject& handle = blendShapeIndex.GetBaseObject();
+
+  return static_cast<Internal::BlendShapeIndex&>(handle);
+}
+
+inline const Internal::BlendShapeIndex& GetImplementation(const Dali::Scene3D::BlendShapeIndex& blendShapeIndex)
+{
+  DALI_ASSERT_ALWAYS(blendShapeIndex && "BlendShapeIndex handle is empty");
+
+  const BaseObject& handle = blendShapeIndex.GetBaseObject();
+
+  return static_cast<const Internal::BlendShapeIndex&>(handle);
+}
+
+} // namespace Scene3D
+
+} // namespace Dali
+
+#endif // DALI_SCENE3D_MODEL_MOTION_BLEND_SHAPE_INDEX_IMPL_H
\ No newline at end of file
diff --git a/dali-scene3d/internal/model-motion/motion-index/motion-index-impl.cpp b/dali-scene3d/internal/model-motion/motion-index/motion-index-impl.cpp
new file mode 100644 (file)
index 0000000..2482c30
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-scene3d/internal/model-motion/motion-index/motion-index-impl.h>
+
+// EXTERNAL INCLUDES
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+namespace Scene3D
+{
+namespace Internal
+{
+namespace
+{
+} // unnamed namespace
+
+MotionIndex::MotionIndex()
+{
+}
+
+MotionIndex::~MotionIndex()
+{
+}
+
+void MotionIndex::SetModelNodeId(Property::Key modelNodeId)
+{
+  mModelNodeId = modelNodeId;
+}
+
+Property::Key MotionIndex::GetModelNodeId() const
+{
+  return mModelNodeId;
+}
+
+} // namespace Internal
+
+} // namespace Scene3D
+
+} // namespace Dali
\ No newline at end of file
diff --git a/dali-scene3d/internal/model-motion/motion-index/motion-index-impl.h b/dali-scene3d/internal/model-motion/motion-index/motion-index-impl.h
new file mode 100644 (file)
index 0000000..8ca93a6
--- /dev/null
@@ -0,0 +1,106 @@
+#ifndef DALI_SCENE3D_MODEL_MOTION_MOTION_INDEX_IMPL_H
+#define DALI_SCENE3D_MODEL_MOTION_MOTION_INDEX_IMPL_H
+
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-index.h>
+
+namespace Dali
+{
+namespace Scene3D
+{
+namespace Internal
+{
+using MotionIndexPtr = IntrusivePtr<MotionIndex>;
+
+/**
+ * @brief Internal abstract data for Scene3D::MotionIndex.
+ * The drived class can implemet there own GetPropertyIndex() and GetPropertyName() API.
+ */
+class MotionIndex : public BaseObject
+{
+protected:
+  /**
+   * @brief Construct a new MotionIndex.
+   */
+  MotionIndex();
+
+  /**
+   * @brief Virtual destructor.
+   */
+  virtual ~MotionIndex();
+
+public: // Public Method
+  /**
+   * @copydoc Dali::Scene3D::MotionIndex::SetModelNodeId()
+   */
+  void SetModelNodeId(Property::Key modelNodeId);
+
+  /**
+   * @copydoc Dali::Scene3D::MotionIndex::GetModelNodeId()
+   */
+  Property::Key GetModelNodeId() const;
+
+public: // Virtual Method
+  /**
+   * @copydoc Dali::Scene3D::MotionIndex::GetPropertyName()
+   */
+  virtual std::string GetPropertyName(Scene3D::ModelNode node = Scene3D::ModelNode()) = 0;
+
+  /**
+   * @copydoc Dali::Scene3D::MotionIndex::GetPropertyIndex()
+   */
+  virtual Property::Index GetPropertyIndex(Scene3D::ModelNode node = Scene3D::ModelNode()) = 0;
+
+protected:
+  Property::Key mModelNodeId{Property::INVALID_KEY}; ///< The id of model node
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::MotionIndex& GetImplementation(Dali::Scene3D::MotionIndex& motionIndex)
+{
+  DALI_ASSERT_ALWAYS(motionIndex && "MotionIndex handle is empty");
+
+  BaseObject& handle = motionIndex.GetBaseObject();
+
+  return static_cast<Internal::MotionIndex&>(handle);
+}
+
+inline const Internal::MotionIndex& GetImplementation(const Dali::Scene3D::MotionIndex& motionIndex)
+{
+  DALI_ASSERT_ALWAYS(motionIndex && "MotionIndex handle is empty");
+
+  const BaseObject& handle = motionIndex.GetBaseObject();
+
+  return static_cast<const Internal::MotionIndex&>(handle);
+}
+
+} // namespace Scene3D
+
+} // namespace Dali
+
+#endif // DALI_SCENE3D_MODEL_MOTION_MOTION_INDEX_IMPL_H
\ No newline at end of file
diff --git a/dali-scene3d/internal/model-motion/motion-index/motion-property-index-impl.cpp b/dali-scene3d/internal/model-motion/motion-index/motion-property-index-impl.cpp
new file mode 100644 (file)
index 0000000..3bfe3a5
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-scene3d/internal/model-motion/motion-index/motion-property-index-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/public-api/object/type-registry.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+namespace Scene3D
+{
+namespace Internal
+{
+namespace
+{
+/**
+ * Creates control through type registry
+ */
+BaseHandle Create()
+{
+  return Scene3D::MotionPropertyIndex::New();
+}
+
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN(Scene3D::MotionPropertyIndex, Dali::BaseHandle, Create);
+DALI_TYPE_REGISTRATION_END()
+
+} // namespace
+
+MotionPropertyIndexPtr MotionPropertyIndex::New()
+{
+  MotionPropertyIndexPtr motionPropertyIndex = new MotionPropertyIndex();
+
+  motionPropertyIndex->Initialize();
+
+  return motionPropertyIndex;
+}
+
+MotionPropertyIndex::MotionPropertyIndex()
+{
+}
+
+MotionPropertyIndex::~MotionPropertyIndex()
+{
+}
+
+void MotionPropertyIndex::Initialize()
+{
+}
+
+void MotionPropertyIndex::SetPropertyId(Property::Key propertyId)
+{
+  mPropertyId = propertyId;
+}
+
+Property::Key MotionPropertyIndex::GetPropertyId() const
+{
+  return mPropertyId;
+}
+
+std::string MotionPropertyIndex::GetPropertyName(Scene3D::ModelNode node)
+{
+  if(mPropertyId.type == Property::Key::Type::STRING)
+  {
+    return mPropertyId.stringKey;
+  }
+  return "";
+}
+
+Property::Index MotionPropertyIndex::GetPropertyIndex(Scene3D::ModelNode node)
+{
+  if(mPropertyId.type == Property::Key::Type::INDEX)
+  {
+    return mPropertyId.indexKey;
+  }
+  return Property::INVALID_INDEX;
+}
+
+} // namespace Internal
+
+} // namespace Scene3D
+
+} // namespace Dali
\ No newline at end of file
diff --git a/dali-scene3d/internal/model-motion/motion-index/motion-property-index-impl.h b/dali-scene3d/internal/model-motion/motion-index/motion-property-index-impl.h
new file mode 100644 (file)
index 0000000..081dd97
--- /dev/null
@@ -0,0 +1,118 @@
+#ifndef DALI_SCENE3D_MODEL_MOTION_MOTION_PROPERTY_INDEX_IMPL_H
+#define DALI_SCENE3D_MODEL_MOTION_MOTION_PROPERTY_INDEX_IMPL_H
+
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/internal/model-motion/motion-index/motion-index-impl.h>
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-property-index.h>
+
+namespace Dali
+{
+namespace Scene3D
+{
+namespace Internal
+{
+using MotionPropertyIndexPtr = IntrusivePtr<MotionPropertyIndex>;
+
+/**
+ * @brief Internal data for Scene3D::MotionPropertyIndex.
+ */
+class MotionPropertyIndex : public MotionIndex
+{
+public: // Creation & Destruction
+  /**
+   * @brief Create a new MotionPropertyIndex object.
+   * @return A smart-pointer to the newly allocated MotionPropertyIndex.
+   */
+  static MotionPropertyIndexPtr New();
+
+protected:
+  /**
+   * @brief Construct a new MotionPropertyIndex.
+   */
+  MotionPropertyIndex();
+
+  /**
+   * @brief Second-phase constructor.
+   */
+  void Initialize();
+
+  /**
+   * @brief Virtual destructor.
+   */
+  virtual ~MotionPropertyIndex();
+
+public: // Public Method
+  /**
+   * @copydoc Dali::Scene3D::MotionPropertyIndex::SetPropertyId()
+   */
+  void SetPropertyId(Property::Key propertyId);
+
+  /**
+   * @copydoc Dali::Scene3D::MotionPropertyIndex::GetPropertyId()
+   */
+  Property::Key GetPropertyId() const;
+
+public: // MotionIndex Override Method
+  /**
+   * @copydoc Dali::Scene3D::Internal::MotionIndex::GetPropertyName()
+   */
+  std::string GetPropertyName(Scene3D::ModelNode node = Scene3D::ModelNode()) override;
+
+  /**
+   * @copydoc Dali::Scene3D::Internal::MotionIndex::GetPropertyIndex()
+   */
+  Property::Index GetPropertyIndex(Scene3D::ModelNode node = Scene3D::ModelNode()) override;
+
+protected:
+  Property::Key mPropertyId{Property::INVALID_KEY}; ///< The id of blend shape
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::MotionPropertyIndex& GetImplementation(Dali::Scene3D::MotionPropertyIndex& motionPropertyIndex)
+{
+  DALI_ASSERT_ALWAYS(motionPropertyIndex && "MotionPropertyIndex handle is empty");
+
+  BaseObject& handle = motionPropertyIndex.GetBaseObject();
+
+  return static_cast<Internal::MotionPropertyIndex&>(handle);
+}
+
+inline const Internal::MotionPropertyIndex& GetImplementation(const Dali::Scene3D::MotionPropertyIndex& motionPropertyIndex)
+{
+  DALI_ASSERT_ALWAYS(motionPropertyIndex && "MotionPropertyIndex handle is empty");
+
+  const BaseObject& handle = motionPropertyIndex.GetBaseObject();
+
+  return static_cast<const Internal::MotionPropertyIndex&>(handle);
+}
+
+} // namespace Scene3D
+
+} // namespace Dali
+
+#endif // DALI_SCENE3D_MODEL_MOTION_MOTION_PROPERTY_INDEX_IMPL_H
\ No newline at end of file
diff --git a/dali-scene3d/internal/model-motion/motion-index/motion-transform-index-impl.cpp b/dali-scene3d/internal/model-motion/motion-index/motion-transform-index-impl.cpp
new file mode 100644 (file)
index 0000000..e3babc8
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-scene3d/internal/model-motion/motion-index/motion-transform-index-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/public-api/object/type-registry.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+namespace Scene3D
+{
+namespace Internal
+{
+namespace
+{
+/**
+ * Creates control through type registry
+ */
+BaseHandle Create()
+{
+  return Scene3D::MotionTransformIndex::New();
+}
+
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN(Scene3D::MotionTransformIndex, Dali::BaseHandle, Create);
+DALI_TYPE_REGISTRATION_END()
+} // namespace
+
+MotionTransformIndexPtr MotionTransformIndex::New()
+{
+  MotionTransformIndexPtr motionTransformIndex = new MotionTransformIndex();
+
+  motionTransformIndex->Initialize();
+
+  return motionTransformIndex;
+}
+
+MotionTransformIndex::MotionTransformIndex()
+{
+}
+
+MotionTransformIndex::~MotionTransformIndex()
+{
+}
+
+void MotionTransformIndex::Initialize()
+{
+}
+
+void MotionTransformIndex::SetTransformType(Scene3D::MotionTransformIndex::TransformType type)
+{
+  mTransformType = type;
+}
+
+Scene3D::MotionTransformIndex::TransformType MotionTransformIndex::GetTransformType() const
+{
+  return mTransformType;
+}
+
+std::string MotionTransformIndex::GetPropertyName(Scene3D::ModelNode node)
+{
+  using TransformType = Scene3D::MotionTransformIndex::TransformType;
+
+  switch(mTransformType)
+  {
+    case TransformType::POSITION:
+    {
+      return "position";
+    }
+    case TransformType::POSITION_X:
+    {
+      return "positionX";
+    }
+    case TransformType::POSITION_Y:
+    {
+      return "positionY";
+    }
+    case TransformType::POSITION_Z:
+    {
+      return "positionZ";
+    }
+    case TransformType::ORIENTATION:
+    {
+      return "orientation";
+    }
+    case TransformType::SCALE:
+    {
+      return "scale";
+    }
+    case TransformType::SCALE_X:
+    {
+      return "scaleX";
+    }
+    case TransformType::SCALE_Y:
+    {
+      return "scaleY";
+    }
+    case TransformType::SCALE_Z:
+    {
+      return "scaleZ";
+    }
+    default:
+    {
+      DALI_LOG_ERROR("Invalid transform type used\n");
+      return "";
+    }
+  }
+}
+
+Property::Index MotionTransformIndex::GetPropertyIndex(Scene3D::ModelNode node)
+{
+  using TransformType = Scene3D::MotionTransformIndex::TransformType;
+
+  switch(mTransformType)
+  {
+    case TransformType::POSITION:
+    {
+      return Dali::Actor::Property::POSITION;
+    }
+    case TransformType::POSITION_X:
+    {
+      return Dali::Actor::Property::POSITION_X;
+    }
+    case TransformType::POSITION_Y:
+    {
+      return Dali::Actor::Property::POSITION_Y;
+    }
+    case TransformType::POSITION_Z:
+    {
+      return Dali::Actor::Property::POSITION_Z;
+    }
+    case TransformType::ORIENTATION:
+    {
+      return Dali::Actor::Property::ORIENTATION;
+    }
+    case TransformType::SCALE:
+    {
+      return Dali::Actor::Property::SCALE;
+    }
+    case TransformType::SCALE_X:
+    {
+      return Dali::Actor::Property::SCALE_X;
+    }
+    case TransformType::SCALE_Y:
+    {
+      return Dali::Actor::Property::SCALE_Y;
+    }
+    case TransformType::SCALE_Z:
+    {
+      return Dali::Actor::Property::SCALE_Z;
+    }
+    default:
+    {
+      DALI_LOG_ERROR("Invalid transform type used\n");
+      return Property::INVALID_INDEX;
+    }
+  }
+}
+
+} // namespace Internal
+
+} // namespace Scene3D
+
+} // namespace Dali
\ No newline at end of file
diff --git a/dali-scene3d/internal/model-motion/motion-index/motion-transform-index-impl.h b/dali-scene3d/internal/model-motion/motion-index/motion-transform-index-impl.h
new file mode 100644 (file)
index 0000000..72dc345
--- /dev/null
@@ -0,0 +1,118 @@
+#ifndef DALI_SCENE3D_MODEL_MOTION_MOTION_TRANSFORM_INDEX_IMPL_H
+#define DALI_SCENE3D_MODEL_MOTION_MOTION_TRANSFORM_INDEX_IMPL_H
+
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/internal/model-motion/motion-index/motion-index-impl.h>
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-transform-index.h>
+
+namespace Dali
+{
+namespace Scene3D
+{
+namespace Internal
+{
+using MotionTransformIndexPtr = IntrusivePtr<MotionTransformIndex>;
+
+/**
+ * @brief Internal data for Scene3D::MotionTransformIndex.
+ */
+class MotionTransformIndex : public MotionIndex
+{
+public: // Creation & Destruction
+  /**
+   * @brief Create a new MotionTransformIndex object.
+   * @return A smart-pointer to the newly allocated MotionTransformIndex.
+   */
+  static MotionTransformIndexPtr New();
+
+protected:
+  /**
+   * @brief Construct a new MotionTransformIndex.
+   */
+  MotionTransformIndex();
+
+  /**
+   * @brief Second-phase constructor.
+   */
+  void Initialize();
+
+  /**
+   * @brief Virtual destructor.
+   */
+  virtual ~MotionTransformIndex();
+
+public: // Public Method
+  /**
+   * @copydoc Dali::Scene3D::MotionTransformIndex::SetTransformType()
+   */
+  void SetTransformType(Scene3D::MotionTransformIndex::TransformType type);
+
+  /**
+   * @copydoc Dali::Scene3D::BlendShapeIndex::GetTransformType()
+   */
+  Scene3D::MotionTransformIndex::TransformType GetTransformType() const;
+
+public: // MotionIndex Override Method
+  /**
+   * @copydoc Dali::Scene3D::Internal::MotionIndex::GetPropertyName()
+   */
+  std::string GetPropertyName(Scene3D::ModelNode node = Scene3D::ModelNode()) override;
+
+  /**
+   * @copydoc Dali::Scene3D::Internal::MotionIndex::GetPropertyIndex()
+   */
+  Property::Index GetPropertyIndex(Scene3D::ModelNode node = Scene3D::ModelNode()) override;
+
+protected:
+  Scene3D::MotionTransformIndex::TransformType mTransformType{Scene3D::MotionTransformIndex::TransformType::INVALID}; ///< The type of transform
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::MotionTransformIndex& GetImplementation(Dali::Scene3D::MotionTransformIndex& motionTransformIndex)
+{
+  DALI_ASSERT_ALWAYS(motionTransformIndex && "MotionTransformIndex handle is empty");
+
+  BaseObject& handle = motionTransformIndex.GetBaseObject();
+
+  return static_cast<Internal::MotionTransformIndex&>(handle);
+}
+
+inline const Internal::MotionTransformIndex& GetImplementation(const Dali::Scene3D::MotionTransformIndex& motionTransformIndex)
+{
+  DALI_ASSERT_ALWAYS(motionTransformIndex && "MotionTransformIndex handle is empty");
+
+  const BaseObject& handle = motionTransformIndex.GetBaseObject();
+
+  return static_cast<const Internal::MotionTransformIndex&>(handle);
+}
+
+} // namespace Scene3D
+
+} // namespace Dali
+
+#endif // DALI_SCENE3D_MODEL_MOTION_MOTION_TRANSFORM_INDEX_IMPL_H
\ No newline at end of file
diff --git a/dali-scene3d/internal/model-motion/motion-value-impl.cpp b/dali-scene3d/internal/model-motion/motion-value-impl.cpp
new file mode 100644 (file)
index 0000000..d8189d1
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-scene3d/internal/model-motion/motion-value-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/animation/key-frames-devel.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/public-api/object/type-registry.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+namespace Scene3D
+{
+namespace Internal
+{
+namespace
+{
+/**
+ * Creates control through type registry
+ */
+BaseHandle Create()
+{
+  return Scene3D::MotionValue::New();
+}
+
+// Setup properties, signals and actions using the type-registry.
+DALI_TYPE_REGISTRATION_BEGIN(Scene3D::MotionValue, Dali::BaseHandle, Create);
+DALI_TYPE_REGISTRATION_END()
+
+} // unnamed namespace
+
+MotionValuePtr MotionValue::New()
+{
+  MotionValuePtr motionValue = new MotionValue();
+
+  motionValue->Initialize();
+
+  return motionValue;
+}
+
+MotionValue::MotionValue()
+{
+}
+
+MotionValue::~MotionValue()
+{
+}
+
+void MotionValue::Initialize()
+{
+}
+
+// Public Method
+
+Scene3D::MotionValue::ValueType MotionValue::GetValueType() const
+{
+  return mType;
+}
+
+void MotionValue::SetValue(Property::Value propertyValue)
+{
+  mType = Scene3D::MotionValue::ValueType::PROPERTY_VALUE;
+
+  mKeyFrames.Reset();
+  mPropertyValue = propertyValue;
+}
+
+void MotionValue::SetValue(Dali::KeyFrames keyFrames)
+{
+  mType = Scene3D::MotionValue::ValueType::KEY_FRAMES;
+
+  mKeyFrames     = keyFrames;
+  mPropertyValue = Property::Value();
+}
+
+void MotionValue::Clear()
+{
+  mType = Scene3D::MotionValue::ValueType::INVALID;
+
+  mKeyFrames.Reset();
+  mPropertyValue = Property::Value();
+}
+
+Property::Value MotionValue::GetPropertyValue() const
+{
+  if(mType == Scene3D::MotionValue::ValueType::PROPERTY_VALUE)
+  {
+    return mPropertyValue;
+  }
+  else if(mType == Scene3D::MotionValue::ValueType::KEY_FRAMES)
+  {
+    // Get last value of keyframes
+    auto keyFrameCount = DevelKeyFrames::GetKeyFrameCount(mKeyFrames);
+    if(keyFrameCount > 0u)
+    {
+      float           dummyProgress;
+      Property::Value propertyValue;
+      DevelKeyFrames::GetKeyFrame(mKeyFrames, keyFrameCount - 1u, dummyProgress, propertyValue);
+
+      return propertyValue;
+    }
+  }
+  return Property::Value();
+}
+
+KeyFrames MotionValue::GetKeyFrames() const
+{
+  if(mType == Scene3D::MotionValue::ValueType::KEY_FRAMES)
+  {
+    return mKeyFrames;
+  }
+  else if(mType == Scene3D::MotionValue::ValueType::PROPERTY_VALUE)
+  {
+    // Generate stable keyframe animation here.
+    // TODO : Should we check property value is animatable type or not?
+    KeyFrames keyFrames = KeyFrames::New();
+    keyFrames.Add(0.0f, mPropertyValue);
+    keyFrames.Add(1.0f, mPropertyValue);
+    return keyFrames;
+  }
+  return Dali::KeyFrames();
+}
+
+} // namespace Internal
+
+} // namespace Scene3D
+
+} // namespace Dali
\ No newline at end of file
diff --git a/dali-scene3d/internal/model-motion/motion-value-impl.h b/dali-scene3d/internal/model-motion/motion-value-impl.h
new file mode 100644 (file)
index 0000000..b5bf343
--- /dev/null
@@ -0,0 +1,129 @@
+#ifndef DALI_SCENE3D_MODEL_MOTION_MOTION_VALUE_IMPL_H
+#define DALI_SCENE3D_MODEL_MOTION_MOTION_VALUE_IMPL_H
+
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/public-api/model-motion/motion-value.h>
+
+namespace Dali
+{
+namespace Scene3D
+{
+namespace Internal
+{
+using MotionValuePtr = IntrusivePtr<MotionValue>;
+
+/**
+ * @brief Internal data for Scene3D::MotionValue.
+ */
+class MotionValue : public BaseObject
+{
+public: // Creation & Destruction
+  /**
+   * @brief Create a new MotionValue object.
+   * @return A smart-pointer to the newly allocated MotionValue.
+   */
+  static MotionValuePtr New();
+
+protected:
+  /**
+   * @brief Construct a new MotionValue.
+   */
+  MotionValue();
+
+  /**
+   * @brief Second-phase constructor.
+   */
+  void Initialize();
+
+  /**
+   * @brief Virtual destructor.
+   */
+  virtual ~MotionValue();
+
+public: // Public Method
+  /**
+   * @copydoc Dali::Scene3D::MotionValue::GetValueType()
+   */
+  Scene3D::MotionValue::ValueType GetValueType() const;
+
+  /**
+   * @copydoc Dali::Scene3D::MotionValue::SetValue()
+   */
+  void SetValue(Property::Value propertyValue);
+
+  /**
+   * @copydoc Dali::Scene3D::MotionValue::SetValue()
+   */
+  void SetValue(Dali::KeyFrames keyFrames);
+
+  /**
+   * @copydoc Dali::Scene3D::MotionValue::Clear()
+   */
+  void Clear();
+
+  /**
+   * @copydoc Dali::Scene3D::MotionValue::GetPropertyValue()
+   */
+  Property::Value GetPropertyValue() const;
+
+  /**
+   * @copydoc Dali::Scene3D::MotionValue::GetKeyFrames()
+   */
+  KeyFrames GetKeyFrames() const;
+
+private:
+  Scene3D::MotionValue::ValueType mType{Scene3D::MotionValue::ValueType::INVALID};
+
+  Property::Value mPropertyValue{};
+  Dali::KeyFrames mKeyFrames{};
+};
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::MotionValue& GetImplementation(Dali::Scene3D::MotionValue& motionValue)
+{
+  DALI_ASSERT_ALWAYS(motionValue && "MotionValue handle is empty");
+
+  BaseObject& handle = motionValue.GetBaseObject();
+
+  return static_cast<Internal::MotionValue&>(handle);
+}
+
+inline const Internal::MotionValue& GetImplementation(const Dali::Scene3D::MotionValue& motionValue)
+{
+  DALI_ASSERT_ALWAYS(motionValue && "MotionValue handle is empty");
+
+  const BaseObject& handle = motionValue.GetBaseObject();
+
+  return static_cast<const Internal::MotionValue&>(handle);
+}
+
+} // namespace Scene3D
+
+} // namespace Dali
+
+#endif // DALI_SCENE3D_MODEL_MOTION_MOTION_VALUE_IMPL_H
\ No newline at end of file
index 0df438c..a02e466 100644 (file)
@@ -148,6 +148,26 @@ ModelNode Model::FindChildModelNodeByName(std::string_view nodeName)
   return GetImpl(*this).FindChildModelNodeByName(nodeName);
 }
 
+void Model::RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const
+{
+  GetImpl(*this).RetrieveBlendShapeNames(blendShapeNames);
+}
+
+void Model::RetrieveModelNodesByBlendShapeName(std::string_view blendShapeName, std::vector<ModelNode>& modelNodes) const
+{
+  GetImpl(*this).RetrieveModelNodesByBlendShapeName(blendShapeName, modelNodes);
+}
+
+Dali::Animation Model::GenerateMotionDataAnimation(MotionData motionData)
+{
+  return GetImpl(*this).GenerateMotionDataAnimation(motionData);
+}
+
+void Model::SetMotionData(MotionData motionData)
+{
+  GetImpl(*this).SetMotionData(motionData);
+}
+
 } // namespace Scene3D
 
 } // namespace Dali
index 8025c64..bbb2a6d 100644 (file)
@@ -27,6 +27,7 @@
 // INTERNAL INCLUDES
 #include <dali-scene3d/public-api/api.h>
 #include <dali-scene3d/public-api/model-components/model-node.h>
+#include <dali-scene3d/public-api/model-motion/motion-data.h>
 
 namespace Dali
 {
@@ -323,6 +324,47 @@ public:
    */
   ModelNode FindChildModelNodeByName(std::string_view nodeName);
 
+  /**
+   * @brief Retrieve the list of blendshape name that current Model hold.
+   * The name will be appended end of input list.
+   *
+   * @SINCE_2_2.99
+   * @param[in, out] blendShapeNames The name of blendShape list collected.
+   * @note This method should be called after Model load finished.
+   */
+  void RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const;
+
+  /**
+   * @brief Retrieve the list of ModelNode that contains given blend shape name.
+   * The ModelNode will be appended end of input list.
+   *
+   * @SINCE_2_2.99
+   * @param[in] blendShapeName The name of blendShape that want to collect.
+   * @param[in, out] modelNodes The ModelNode list collected.
+   * @note This method should be called after Model load finished.
+   */
+  void RetrieveModelNodesByBlendShapeName(std::string_view blendShapeName, std::vector<ModelNode>& modelNodes) const;
+
+  /**
+   * @brief Generate specific animation of this Model by inputed MotionData.
+   *
+   * @SINCE_2_2.99
+   * @param[in] motionData the data of motion animation.
+   * @return Animation that be generated by MotionData. Or empty handle if there is no valid animation generated.
+   * @note This method should be called after Model load finished.
+   */
+  Dali::Animation GenerateMotionDataAnimation(MotionData motionData);
+
+  /**
+   * @brief Set specific values of this Model by inputed MotionData.
+   * @note If MotionValue's ValueType is ValueType::KEY_FRAMES, the last value will be setted.
+   *
+   * @SINCE_2_2.99
+   * @param[in] motionData the data of motion to be set.
+   * @note This method should be called after Model load finished.
+   */
+  void SetMotionData(Scene3D::MotionData motionData);
+
 public: // Not intended for application developers
   /// @cond internal
   /**
index 43e992f..70c1f6c 100644 (file)
@@ -41,4 +41,10 @@ set(scene3d_src_files ${scene3d_src_files}
        ${scene3d_public_api_dir}/model-components/material.cpp
        ${scene3d_public_api_dir}/model-components/model-node.cpp
        ${scene3d_public_api_dir}/model-components/model-primitive.cpp
+       ${scene3d_public_api_dir}/model-motion/motion-data.cpp
+       ${scene3d_public_api_dir}/model-motion/motion-index/blend-shape-index.cpp
+       ${scene3d_public_api_dir}/model-motion/motion-index/motion-index.cpp
+       ${scene3d_public_api_dir}/model-motion/motion-index/motion-property-index.cpp
+       ${scene3d_public_api_dir}/model-motion/motion-index/motion-transform-index.cpp
+       ${scene3d_public_api_dir}/model-motion/motion-value.cpp
 )
\ No newline at end of file
index 15110c7..e357516 100644 (file)
@@ -20,7 +20,7 @@
 
 namespace Dali::Scene3D::Loader
 {
-void AnimatedProperty::Animate(Animation& anim, GetActor getActor)
+void AnimatedProperty::Animate(Animation& anim, GetActor getActor) const
 {
   if(Actor actor = getActor(*this))
   {
index 07b251f..90b8a02 100644 (file)
@@ -49,7 +49,7 @@ public: // METHODS
   /**
    * @return The Property object (of the given @a actor) whose value is being animated.
    */
-  Property GetProperty(Actor& actor)
+  Property GetProperty(Actor& actor) const
   {
     auto idx = actor.GetPropertyIndex(mPropertyName);
     return Property(actor, idx);
@@ -58,7 +58,7 @@ public: // METHODS
   /**
    * @brief The type of the Property (of the given @a actor) that is being animated.
    */
-  Property::Type GetPropertyType(Actor& actor)
+  Property::Type GetPropertyType(Actor& actor) const
   {
     auto idx = actor.GetPropertyIndex(mPropertyName);
     return actor.GetPropertyType(idx);
@@ -70,7 +70,7 @@ public: // METHODS
    *  Failing to find the actor purely means that this property will not be
    *  animated.
    */
-  void Animate(Animation& anim, GetActor getActor);
+  void Animate(Animation& anim, GetActor getActor) const;
 
 public: // DATA
   struct Value
index d35631d..d9ee5dd 100644 (file)
@@ -158,9 +158,9 @@ void AnimationDefinition::ReserveSize(uint32_t size)
   mProperties.reserve(size);
 }
 
-uint32_t AnimationDefinition::GetPropertyCount()
+uint32_t AnimationDefinition::GetPropertyCount() const
 {
-  return mProperties.size();
+  return static_cast<uint32_t>(mProperties.size());
 }
 
 void AnimationDefinition::SetProperty(uint32_t index, AnimatedProperty&& property)
@@ -177,4 +177,9 @@ AnimatedProperty& AnimationDefinition::GetPropertyAt(uint32_t index)
   return mProperties[index];
 }
 
+const AnimatedProperty& AnimationDefinition::GetPropertyAt(uint32_t index) const
+{
+  return mProperties[index];
+}
+
 } // namespace Dali::Scene3D::Loader
index 9b8393c..914dfa7 100644 (file)
@@ -173,7 +173,7 @@ public: // METHODS
    *
    * @return The count of animated properties.
    */
-  uint32_t GetPropertyCount();
+  uint32_t GetPropertyCount() const;
 
   /**
    * @brief Add a property that will be animated by this AnimationDefinition
@@ -190,6 +190,13 @@ public: // METHODS
    */
   AnimatedProperty& GetPropertyAt(uint32_t index);
 
+  /**
+   * @brief Retrieves animated property at the index
+   *
+   * @param[in] index The index of property to be retrieved.
+   */
+  const AnimatedProperty& GetPropertyAt(uint32_t index) const;
+
 private: // DATA
   std::string mName;
 
index e7d2eb4..d7d6325 100644 (file)
@@ -22,6 +22,7 @@
 #include <dali/public-api/common/vector-wrapper.h>
 #include <dali/public-api/object/weak-handle.h>
 #include <dali/public-api/rendering/shader.h>
+#include <limits> ///< for std::numeric_limits
 #include <string>
 
 // INTERNAL INCLUDES
@@ -34,6 +35,9 @@ struct MeshGeometry;
 
 struct DALI_SCENE3D_API BlendShapes
 {
+  using Index                          = uint32_t;
+  static constexpr Index INVALID_INDEX = std::numeric_limits<Index>::max();
+
   enum class Version
   {
     VERSION_1_0,
@@ -53,12 +57,13 @@ struct DALI_SCENE3D_API BlendShapes
 
   struct BlendShapeData
   {
-    std::vector<float>      weights;
-    std::vector<float>      unnormalizeFactors;
-    Version                 version{Scene3D::Loader::BlendShapes::Version::INVALID};
-    uint32_t                bufferOffset{0};
-    int32_t                 components{0x0};
-    Dali::WeakHandle<Actor> mActor;
+    std::vector<std::string> names;
+    std::vector<float>       weights;
+    std::vector<float>       unnormalizeFactors;
+    Version                  version{Scene3D::Loader::BlendShapes::Version::INVALID};
+    uint32_t                 bufferOffset{0};
+    int32_t                  components{0x0};
+    Dali::WeakHandle<Actor>  mActor;
   };
 
   // shader properties - animatable (uniforms)
index 10f6866..cf5aa61 100644 (file)
@@ -860,6 +860,7 @@ bool SceneDefinition::ConfigureBlendshapeShaders(const ResourceBundle&
         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);
index 583cdd0..a664eeb 100644 (file)
@@ -118,6 +118,16 @@ ModelNode ModelNode::FindChildModelNodeByName(std::string_view nodeName)
   return Internal::GetImplementation(*this).FindChildModelNodeByName(nodeName);
 }
 
+void ModelNode::RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const
+{
+  return Internal::GetImplementation(*this).RetrieveBlendShapeNames(blendShapeNames);
+}
+
+Loader::BlendShapes::Index ModelNode::GetBlendShapeIndexByName(std::string_view blendShapeName) const
+{
+  return Internal::GetImplementation(*this).GetBlendShapeIndexByName(blendShapeName);
+}
+
 } // namespace Scene3D
 
 } // namespace Dali
index dc3e717..ffd469d 100644 (file)
@@ -24,6 +24,7 @@
 
 // INTERNAL INCLUDES
 #include <dali-scene3d/public-api/api.h>
+#include <dali-scene3d/public-api/loader/blend-shape-details.h> ///< For Loader::BlendShapes::Index
 #include <dali-scene3d/public-api/model-components/model-primitive.h>
 
 namespace Dali
@@ -136,7 +137,6 @@ public:
   static ModelNode DownCast(BaseHandle handle);
 
 public: // Public Method
-
   /**
    * @brief Gets the number of ModelPrimitives this node has.
    *
@@ -186,6 +186,22 @@ public: // Public Method
    */
   ModelNode FindChildModelNodeByName(std::string_view nodeName);
 
+  /**
+   * @brief Retrieve the list of blendshape name that current ModelNode hold.
+   * The name will be appended end of input list.
+   *
+   * @param[in, out] blendShapeNames The name of blendShape list collected.
+   */
+  void RetrieveBlendShapeNames(std::vector<std::string>& blendShapeNames) const;
+
+  /**
+   * @brief Get the index of blend shape by given name.
+   *
+   * @param[in] blendShapeName The name of blendshape that is not empty.
+   * @return Index of blendshape, or return invalid if there is no blendshape with given name.
+   */
+  Loader::BlendShapes::Index GetBlendShapeIndexByName(std::string_view blendShapeName) const;
+
 public: // Not intended for application developers
   /// @cond internal
   /**
diff --git a/dali-scene3d/public-api/model-motion/motion-data.cpp b/dali-scene3d/public-api/model-motion/motion-data.cpp
new file mode 100644 (file)
index 0000000..f9418b5
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-scene3d/public-api/model-motion/motion-data.h>
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/internal/model-motion/motion-data-impl.h>
+
+namespace Dali
+{
+namespace Scene3D
+{
+MotionData MotionData::New()
+{
+  Internal::MotionDataPtr internal = Internal::MotionData::New();
+
+  return MotionData(internal.Get());
+}
+
+MotionData MotionData::New(float durationSeconds)
+{
+  Internal::MotionDataPtr internal = Internal::MotionData::New();
+
+  internal->SetDuration(durationSeconds);
+
+  return MotionData(internal.Get());
+}
+
+MotionData::MotionData()
+{
+}
+
+MotionData::MotionData(const MotionData& motionData) = default;
+
+MotionData::MotionData(MotionData&& rhs) noexcept = default;
+
+MotionData::~MotionData()
+{
+}
+
+MotionData& MotionData::operator=(const MotionData& handle) = default;
+
+MotionData& MotionData::operator=(MotionData&& rhs) noexcept = default;
+
+MotionData MotionData::DownCast(BaseHandle handle)
+{
+  return MotionData(dynamic_cast<Dali::Scene3D::Internal::MotionData*>(handle.GetObjectPtr()));
+}
+
+MotionData::MotionData(Dali::Scene3D::Internal::MotionData* internal)
+: BaseHandle(internal)
+{
+}
+
+// Public Method
+
+uint32_t MotionData::GetMotionCount() const
+{
+  return GetImplementation(*this).GetMotionCount();
+}
+
+MotionIndex MotionData::GetIndex(uint32_t index) const
+{
+  return GetImplementation(*this).GetIndex(index);
+}
+
+MotionValue MotionData::GetValue(uint32_t index) const
+{
+  return GetImplementation(*this).GetValue(index);
+}
+
+void MotionData::Add(MotionIndex index, MotionValue value)
+{
+  GetImplementation(*this).Add(index, value);
+}
+
+void MotionData::Clear()
+{
+  GetImplementation(*this).Clear();
+}
+
+void MotionData::SetDuration(float durationSeconds)
+{
+  GetImplementation(*this).SetDuration(durationSeconds);
+}
+
+float MotionData::GetDuration() const
+{
+  return GetImplementation(*this).GetDuration();
+}
+
+void MotionData::LoadBvh(const std::string& path, const Vector3& scale, bool synchronousLoad)
+{
+  GetImplementation(*this).LoadBvh(path, scale, synchronousLoad);
+}
+
+void MotionData::LoadBvhFromBuffer(const uint8_t* rawBuffer, int rawBufferLength, const Vector3& scale, bool synchronousLoad)
+{
+  GetImplementation(*this).LoadBvhFromBuffer(rawBuffer, rawBufferLength, scale, synchronousLoad);
+}
+
+void MotionData::LoadFacialAnimation(const std::string& url, bool synchronousLoad)
+{
+  GetImplementation(*this).LoadFacialAnimation(url, synchronousLoad);
+}
+
+void MotionData::LoadFacialAnimationFromBuffer(const uint8_t* rawBuffer, int rawBufferLength, bool synchronousLoad)
+{
+  GetImplementation(*this).LoadFacialAnimationFromBuffer(rawBuffer, rawBufferLength, synchronousLoad);
+}
+
+MotionData::LoadCompletedSignalType& MotionData::LoadCompletedSignal()
+{
+  return GetImplementation(*this).LoadCompletedSignal();
+}
+
+} // namespace Scene3D
+
+} // namespace Dali
\ No newline at end of file
diff --git a/dali-scene3d/public-api/model-motion/motion-data.h b/dali-scene3d/public-api/model-motion/motion-data.h
new file mode 100644 (file)
index 0000000..438e6af
--- /dev/null
@@ -0,0 +1,331 @@
+#ifndef DALI_SCENE3D_MODEL_MOTION_MOTION_DATA_H
+#define DALI_SCENE3D_MODEL_MOTION_MOTION_DATA_H
+
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/object/base-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/public-api/api.h>
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-index.h>
+#include <dali-scene3d/public-api/model-motion/motion-value.h>
+
+namespace Dali
+{
+namespace Scene3D
+{
+//Forward declarations.
+namespace Internal
+{
+class MotionData;
+} // namespace Internal
+
+/**
+ * @addtogroup dali_scene3d_model_motion_motion_data
+ * @{
+ */
+
+/**
+ * @brief List of model motion definitions.
+ * Each motion has pair of MotionIndex and MotionValue.
+ * MotionIndex is abstract class that specify the target of motion.
+ * MotionValue is target value of motion. It can be KeyFrames.
+ *
+ * We can generate list of motions by MotionIndex and MotionValue classes.
+ *
+ * @code
+ *
+ * MotionData motionData = MotionData::New(3.0f);
+ *
+ * // Make MotionIndex with MotionPropertyIndex
+ * // Make MotionValue with Dali::Property::Value
+ * motionData.Add(MotionPropertyIndex::New("nodeName", "color"), MotionValue::New(Color::RED));
+ *
+ * // Make MotionIndex with MotionTransformIndex
+ * // Make MotionValue with Dali::KeyFrames
+ * KeyFrames keyFrames = KeyFrames::New();
+ * keyFrames.Add(0.0f, 0.0f);
+ * keyFrames.Add(0.0f, 1.0f);
+ * motionData.Add(MotionTransformIndex::New("nodeName", MotionTransformIndex::TransformType::POSITION_X), MotionValue::New(keyFrames));
+ *
+ * // Make MotionIndex with BlendShapeIndex
+ * motionData.Add(BlendShapeIndex::New("nodeName", 0u), motionData.GetValue(1u));
+ *
+ * @endcode
+ *
+ * We can request to load MotionData from file or buffer asynchronously.
+ * If load completed, LoadCompetedSignal will be emmited.
+ *
+ * @code
+ *
+ * MotionData motionData = MotionData::New();
+ * motionData.LoadCompletedSignal().Connect(&OnLoadCompleted);
+ * motionData.LoadBvh("bvhFilename.bvh", Vector3::ONE);
+ *
+ * @endcode
+ *
+ * We can generate animation of Scene3D::Model from MotionData class.
+ * Or, just set values.
+ *
+ * @code
+ *
+ * // Generate animation from loaded Model
+ * Dali::Animation animation = model.GenerateMotionDataAnimation(motionData);
+ * animation.Play();
+ *
+ * // Set values from loaded Model.
+ * model2.SetMotionData(motionData);
+ *
+ * @endcode
+ * @note We don't check duplicated MotionIndex internally.
+ * @SINCE_2_2.99
+ */
+class DALI_SCENE3D_API MotionData : public Dali::BaseHandle
+{
+public:
+  /// @brief LoadCompleted signal type. @SINCE_2_2.99
+  typedef Signal<void(MotionData)> LoadCompletedSignalType;
+
+public: // Creation & Destruction
+  /**
+   * @brief Create an initialized MotionData.
+   *
+   * @SINCE_2_2.99
+   * @return A handle to a newly allocated Dali resource
+   */
+  static MotionData New();
+
+  /**
+   * @brief Create an initialized MotionData with duration.
+   *
+   * @SINCE_2_2.99
+   * @param[in] durationSeconds Duration of animation as seconds.
+   * @return A handle to a newly allocated Dali resource
+   */
+  static MotionData New(float durationSeconds);
+
+  /**
+   * @brief Creates an uninitialized MotionData.
+   *
+   * Only derived versions can be instantiated. Calling member
+   * functions with an uninitialized Dali::Object is not allowed.
+   *
+   * @SINCE_2_2.99
+   */
+  MotionData();
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   *
+   * @SINCE_2_2.99
+   */
+  ~MotionData();
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @SINCE_2_2.99
+   * @param[in] motionData Handle to an object
+   */
+  MotionData(const MotionData& motionData);
+
+  /**
+   * @brief Move constructor
+   *
+   * @SINCE_2_2.99
+   * @param[in] rhs A reference to the moved handle
+   */
+  MotionData(MotionData&& rhs) noexcept;
+
+  /**
+   * @brief Assignment operator.
+   *
+   * @SINCE_2_2.99
+   * @param[in] motionData Handle to an object
+   * @return reference to this
+   */
+  MotionData& operator=(const MotionData& motionData);
+
+  /**
+   * @brief Move assignment
+   *
+   * @SINCE_2_2.99
+   * @param[in] rhs A reference to the moved handle
+   * @return A reference to this
+   */
+  MotionData& operator=(MotionData&& rhs) noexcept;
+
+  /**
+   * @brief Downcasts an Object handle to MotionData.
+   *
+   * If handle points to a MotionData, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   *
+   * @SINCE_2_2.99
+   * @param[in] handle Handle to an object
+   * @return Handle to a MotionData or an uninitialized handle
+   */
+  static MotionData DownCast(BaseHandle handle);
+
+public: // Public Method
+  /**
+   * @brief Get the number of motions what we added
+   *
+   * @SINCE_2_2.99
+   * @return The number of motions
+   */
+  uint32_t GetMotionCount() const;
+
+  /**
+   * @brief Get MotionIndex from given index'th.
+   *
+   * @SINCE_2_2.99
+   * @param[in] index The index of motion list.
+   * @return Index of motion, or empty handle if invalid index inputed.
+   */
+  MotionIndex GetIndex(uint32_t index) const;
+
+  /**
+   * @brief Get MotionValue from given index'th.
+   *
+   * @SINCE_2_2.99
+   * @param[in] index The index of motion list.
+   * @return Value of motion, or empty handle if invalid index inputed.
+   */
+  MotionValue GetValue(uint32_t index) const;
+
+  /**
+   * @brief Append new motion.
+   * @note We don't check duplicated MotionIndex internally.
+   *
+   * @SINCE_2_2.99
+   * @param[in] index index of motion.
+   * @param[in] value value of motion.
+   */
+  void Add(MotionIndex index, MotionValue value);
+
+  /**
+   * @brief Clear all stored motion data.
+   *
+   * @SINCE_2_2.99
+   */
+  void Clear();
+
+  /**
+   * @brief Set the duration of this motion data if it be generated as Dali::Animation.
+   *
+   * @SINCE_2_2.99
+   * @param[in] durationSeconds Duration of animation as seconds.
+   */
+  void SetDuration(float durationSeconds);
+
+  /**
+   * @brief Get the duration of this motion data if it be generated as Dali::Animation.
+   *
+   * @SINCE_2_2.99
+   * @return The duration of this motion data seconds. Default is 0.0f
+   */
+  float GetDuration() const;
+
+  /**
+   * @brief Load MotionData from bvh file.
+   * It will use Dali::Scene3D::Loader::LoadBvh() internally.
+   * LoadCompleteSignal() will be emitted after load completed.
+   *
+   * @SINCE_2_2.99
+   * @param[in] path The file path.
+   * @param[in] scale The scale factor to set on the position property manually.
+   * @param[in] synchronousLoad True if we want to load result synchronously. Default is false.
+   */
+  void LoadBvh(const std::string& path, const Vector3& scale = Vector3::ONE, bool synchronousLoad = false);
+
+  /**
+   * @brief Load MotionData from bvh buffer.
+   * It will use Dali::Scene3D::Loader::LoadBvhFromBuffer() internally.
+   * LoadCompleteSignal() will be emitted after load completed.
+   *
+   * @SINCE_2_2.99
+   * @param[in] rawBuffer The bvh buffer.
+   * @param[in] rawBufferLength The length of buffer.
+   * @param[in] scale The scale factor to set on the position property manually.
+   * @param[in] synchronousLoad True if we want to load result synchronously. Default is false.
+   */
+  void LoadBvhFromBuffer(const uint8_t* rawBuffer, int rawBufferLength, const Vector3& scale = Vector3::ONE, bool synchronousLoad = false);
+
+  /**
+   * @brief Load MotionData from facail defined json file.
+   * It will use Dali::Scene3D::Loader::LoadFacialAnimation() internally.
+   * LoadCompleteSignal() will be emitted after load completed.
+   *
+   * @SINCE_2_2.99
+   * @param[in] url The file path.
+   * @param[in] synchronousLoad True if we want to load result synchronously. Default is false.
+   */
+  void LoadFacialAnimation(const std::string& url, bool synchronousLoad = false);
+
+  /**
+   * @brief Load MotionData from facail defined json file.
+   * It will use Dali::Scene3D::Loader::LoadFacialAnimationFromBuffer() internally.
+   * LoadCompleteSignal() will be emitted after load completed.
+   *
+   * @SINCE_2_2.99
+   * @param[in] rawBuffer The raw buffer containing the facial animation.
+   * @param[in] rawBufferLength The length of raw buffer.
+   * @param[in] synchronousLoad True if we want to load result synchronously. Default is false.
+   */
+  void LoadFacialAnimationFromBuffer(const uint8_t* rawBuffer, int rawBufferLength, bool synchronousLoad = false);
+
+public:
+  /**
+   * @brief This signal is emitted after motion data are loaded completed.
+   * @note Signal will be emitted even if we request load synchronously.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName(MotionData motionData);
+   * @endcode
+   *
+   * @SINCE_2_2.99
+   * @return The signal to connect to.
+   */
+  LoadCompletedSignalType& LoadCompletedSignal();
+
+public: // Not intended for application developers
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Scene3D::Internal implementation.
+   *
+   * @param[in] implementation The MotionData implementation
+   */
+  DALI_INTERNAL MotionData(Dali::Scene3D::Internal::MotionData* implementation);
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+
+} // namespace Scene3D
+
+} // namespace Dali
+
+#endif // DALI_SCENE3D_MODEL_MOTION_MOTION_DATA_H
\ No newline at end of file
diff --git a/dali-scene3d/public-api/model-motion/motion-index/blend-shape-index.cpp b/dali-scene3d/public-api/model-motion/motion-index/blend-shape-index.cpp
new file mode 100644 (file)
index 0000000..549c80a
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-scene3d/public-api/model-motion/motion-index/blend-shape-index.h>
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/internal/model-motion/motion-index/blend-shape-index-impl.h>
+
+namespace Dali
+{
+namespace Scene3D
+{
+BlendShapeIndex BlendShapeIndex::New()
+{
+  Internal::BlendShapeIndexPtr internal = Internal::BlendShapeIndex::New();
+
+  return BlendShapeIndex(internal.Get());
+}
+
+BlendShapeIndex BlendShapeIndex::New(Property::Key blendShapeId)
+{
+  Internal::BlendShapeIndexPtr internal = Internal::BlendShapeIndex::New();
+
+  internal->SetBlendShapeId(blendShapeId);
+
+  return BlendShapeIndex(internal.Get());
+}
+
+BlendShapeIndex BlendShapeIndex::New(Property::Key modelNodeId, Property::Key blendShapeId)
+{
+  Internal::BlendShapeIndexPtr internal = Internal::BlendShapeIndex::New();
+
+  internal->SetModelNodeId(modelNodeId);
+  internal->SetBlendShapeId(blendShapeId);
+
+  return BlendShapeIndex(internal.Get());
+}
+
+BlendShapeIndex::BlendShapeIndex()
+{
+}
+
+BlendShapeIndex::BlendShapeIndex(const BlendShapeIndex& blendShapeIndex) = default;
+
+BlendShapeIndex::BlendShapeIndex(BlendShapeIndex&& rhs) noexcept = default;
+
+BlendShapeIndex::~BlendShapeIndex()
+{
+}
+
+BlendShapeIndex& BlendShapeIndex::operator=(const BlendShapeIndex& handle) = default;
+
+BlendShapeIndex& BlendShapeIndex::operator=(BlendShapeIndex&& rhs) noexcept = default;
+
+BlendShapeIndex BlendShapeIndex::DownCast(BaseHandle handle)
+{
+  return BlendShapeIndex(dynamic_cast<Dali::Scene3D::Internal::BlendShapeIndex*>(handle.GetObjectPtr()));
+}
+
+BlendShapeIndex::BlendShapeIndex(Dali::Scene3D::Internal::BlendShapeIndex* internal)
+: MotionIndex(internal)
+{
+}
+
+// Public Method
+
+void BlendShapeIndex::SetBlendShapeId(Property::Key blendShapeId)
+{
+  GetImplementation(*this).SetBlendShapeId(blendShapeId);
+}
+
+Property::Key BlendShapeIndex::GetBlendShapeId() const
+{
+  return GetImplementation(*this).GetBlendShapeId();
+}
+
+} // namespace Scene3D
+
+} // namespace Dali
\ No newline at end of file
diff --git a/dali-scene3d/public-api/model-motion/motion-index/blend-shape-index.h b/dali-scene3d/public-api/model-motion/motion-index/blend-shape-index.h
new file mode 100644 (file)
index 0000000..901f37d
--- /dev/null
@@ -0,0 +1,179 @@
+#ifndef DALI_SCENE3D_MODEL_MOTION_BLEND_SHAPE_INDEX_H
+#define DALI_SCENE3D_MODEL_MOTION_BLEND_SHAPE_INDEX_H
+
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-index.h>
+
+namespace Dali
+{
+namespace Scene3D
+{
+//Forward declarations.
+namespace Internal
+{
+class BlendShapeIndex;
+} // namespace Internal
+
+/**
+ * @addtogroup dali_scene3d_model_motion_blend_shape_index
+ * @{
+ */
+
+/**
+ * @brief Specialized MotionIndex to control blendshape.
+ * Specially, if ModelNodeId is Property::INVALID_KEY and BlendShapeId is StringKey,
+ * It will control all ModelNode that has the inputed BlendShape name.
+ *
+ * @SINCE_2_2.99
+ */
+class DALI_SCENE3D_API BlendShapeIndex : public MotionIndex
+{
+public: // Creation & Destruction
+  /**
+   * @brief Create an initialized BlendShapeIndex.
+   *
+   * @SINCE_2_2.99
+   * @return A handle to a newly allocated Dali resource
+   */
+  static BlendShapeIndex New();
+
+  /**
+   * @brief Create an initialized BlendShapeIndex with values.
+   *
+   * @SINCE_2_2.99
+   * @param[in] blendShapeId The id of blendshape what this motion index looks.
+   * @return A handle to a newly allocated Dali resource
+   */
+  static BlendShapeIndex New(Property::Key blendShapeId);
+
+  /**
+   * @brief Create an initialized BlendShapeIndex with values.
+   *
+   * @SINCE_2_2.99
+   * @param[in] modelNodeId The id of model node what this motion index looks.
+   * @param[in] blendShapeId The id of blendshape what this motion index looks.
+   * @return A handle to a newly allocated Dali resource
+   */
+  static BlendShapeIndex New(Property::Key modelNodeId, Property::Key blendShapeId);
+
+  /**
+   * @brief Creates an uninitialized BlendShapeIndex.
+   *
+   * Only derived versions can be instantiated. Calling member
+   * functions with an uninitialized Dali::Object is not allowed.
+   *
+   * @SINCE_2_2.99
+   */
+  BlendShapeIndex();
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   *
+   * @SINCE_2_2.99
+   */
+  ~BlendShapeIndex();
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @SINCE_2_2.99
+   * @param[in] blendShapeIndex Handle to an object
+   */
+  BlendShapeIndex(const BlendShapeIndex& blendShapeIndex);
+
+  /**
+   * @brief Move constructor
+   *
+   * @SINCE_2_2.99
+   * @param[in] rhs A reference to the moved handle
+   */
+  BlendShapeIndex(BlendShapeIndex&& rhs) noexcept;
+
+  /**
+   * @brief Assignment operator.
+   *
+   * @SINCE_2_2.99
+   * @param[in] blendShapeIndex Handle to an object
+   * @return reference to this
+   */
+  BlendShapeIndex& operator=(const BlendShapeIndex& blendShapeIndex);
+
+  /**
+   * @brief Move assignment
+   *
+   * @SINCE_2_2.99
+   * @param[in] rhs A reference to the moved handle
+   * @return A reference to this
+   */
+  BlendShapeIndex& operator=(BlendShapeIndex&& rhs) noexcept;
+
+  /**
+   * @brief Downcasts an Object handle to BlendShapeIndex.
+   *
+   * If handle points to a BlendShapeIndex, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   *
+   * @SINCE_2_2.99
+   * @param[in] handle Handle to an object
+   * @return Handle to a BlendShapeIndex or an uninitialized handle
+   */
+  static BlendShapeIndex DownCast(BaseHandle handle);
+
+public: // Public Method
+  /**
+   * @brief Set the id of BlendShape what this motion index looks.
+   *
+   * @SINCE_2_2.99
+   * @param[in] blendShapeId The blend shape id.
+   */
+  void SetBlendShapeId(Property::Key blendShapeId);
+
+  /**
+   * @brief Get the id of BlendShape what this motion index looks.
+   *
+   * @SINCE_2_2.99
+   * @return The blend shape id.
+   */
+  Property::Key GetBlendShapeId() const;
+
+public: // Not intended for application developers
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Scene3D::Internal implementation.
+   *
+   * @param[in] implementation The BlendShapeIndex implementation
+   */
+  DALI_INTERNAL BlendShapeIndex(Dali::Scene3D::Internal::BlendShapeIndex* implementation);
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+
+} // namespace Scene3D
+
+} // namespace Dali
+
+#endif // DALI_SCENE3D_MODEL_MOTION_BLEND_SHAPE_INDEX_H
\ No newline at end of file
diff --git a/dali-scene3d/public-api/model-motion/motion-index/motion-index.cpp b/dali-scene3d/public-api/model-motion/motion-index/motion-index.cpp
new file mode 100644 (file)
index 0000000..eaa3ad9
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-index.h>
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/internal/model-motion/motion-index/motion-index-impl.h>
+
+namespace Dali
+{
+namespace Scene3D
+{
+MotionIndex::MotionIndex()
+{
+}
+
+MotionIndex::MotionIndex(const MotionIndex& motionIndex) = default;
+
+MotionIndex::MotionIndex(MotionIndex&& rhs) noexcept = default;
+
+MotionIndex::~MotionIndex()
+{
+}
+
+MotionIndex& MotionIndex::operator=(const MotionIndex& handle) = default;
+
+MotionIndex& MotionIndex::operator=(MotionIndex&& rhs) noexcept = default;
+
+MotionIndex MotionIndex::DownCast(BaseHandle handle)
+{
+  return MotionIndex(dynamic_cast<Dali::Scene3D::Internal::MotionIndex*>(handle.GetObjectPtr()));
+}
+
+MotionIndex::MotionIndex(Dali::Scene3D::Internal::MotionIndex* internal)
+: BaseHandle(internal)
+{
+}
+
+// Public Method
+
+void MotionIndex::SetModelNodeId(Property::Key modelNodeId)
+{
+  GetImplementation(*this).SetModelNodeId(modelNodeId);
+}
+
+Property::Key MotionIndex::GetModelNodeId() const
+{
+  return GetImplementation(*this).GetModelNodeId();
+}
+
+std::string MotionIndex::GetPropertyName(ModelNode node)
+{
+  return GetImplementation(*this).GetPropertyName(node);
+}
+
+Property::Index MotionIndex::GetPropertyIndex(ModelNode node)
+{
+  return GetImplementation(*this).GetPropertyIndex(node);
+}
+
+} // namespace Scene3D
+
+} // namespace Dali
\ No newline at end of file
diff --git a/dali-scene3d/public-api/model-motion/motion-index/motion-index.h b/dali-scene3d/public-api/model-motion/motion-index/motion-index.h
new file mode 100644 (file)
index 0000000..4355b99
--- /dev/null
@@ -0,0 +1,176 @@
+#ifndef DALI_SCENE3D_MODEL_MOTION_MOTION_INDEX_H
+#define DALI_SCENE3D_MODEL_MOTION_MOTION_INDEX_H
+
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/property-key.h>
+#include <dali/public-api/object/property.h>
+#include <string>
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/public-api/model-components/model-node.h>
+
+namespace Dali
+{
+namespace Scene3D
+{
+//Forward declarations.
+namespace Internal
+{
+class MotionIndex;
+} // namespace Internal
+
+/**
+ * @addtogroup dali_scene3d_model_motion_motion_index
+ * @{
+ */
+
+/**
+ * @brief Key of motion data to specify what ModelNode's property will be moved.
+ * MotionIndex itself is abstract classes. We need to create New from one of below classes.
+ * - BlendShapeIndex : To control blendshape.
+ * - MotionPropertyIndex : To control the property by Dali::Property.
+ * - MotionTransfromIndex : To control the transform property. Usually be used on CSharp binded API who cannot use Dali::Property directly.
+ * @todo Need to implement ModelNodeId as IndexKey. Currently, StringKey only works well.
+ *
+ * @SINCE_2_2.99
+ */
+class DALI_SCENE3D_API MotionIndex : public Dali::BaseHandle
+{
+public: // Creation & Destruction
+  /**
+   * @brief Creates an uninitialized MotionIndex.
+   *
+   * Only derived versions can be instantiated. Calling member
+   * functions with an uninitialized Dali::Object is not allowed.
+   *
+   * @SINCE_2_2.99
+   */
+  MotionIndex();
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   *
+   * @SINCE_2_2.99
+   */
+  ~MotionIndex();
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @SINCE_2_2.99
+   * @param[in] motionIndex Handle to an object
+   */
+  MotionIndex(const MotionIndex& motionIndex);
+
+  /**
+   * @brief Move constructor
+   *
+   * @SINCE_2_2.99
+   * @param[in] rhs A reference to the moved handle
+   */
+  MotionIndex(MotionIndex&& rhs) noexcept;
+
+  /**
+   * @brief Assignment operator.
+   *
+   * @SINCE_2_2.99
+   * @param[in] motionIndex Handle to an object
+   * @return reference to this
+   */
+  MotionIndex& operator=(const MotionIndex& motionIndex);
+
+  /**
+   * @brief Move assignment
+   *
+   * @SINCE_2_2.99
+   * @param[in] rhs A reference to the moved handle
+   * @return A reference to this
+   */
+  MotionIndex& operator=(MotionIndex&& rhs) noexcept;
+
+  /**
+   * @brief Downcasts an Object handle to MotionIndex.
+   *
+   * If handle points to a MotionIndex, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   *
+   * @SINCE_2_2.99
+   * @param[in] handle Handle to an object
+   * @return Handle to a MotionIndex or an uninitialized handle
+   */
+  static MotionIndex DownCast(BaseHandle handle);
+
+public: // Public Method
+  /**
+   * @brief Set the id of ModelNode what this motion index looks.
+   *
+   * @SINCE_2_2.99
+   * @param[in] modelNodeId The model node id.
+   */
+  void SetModelNodeId(Property::Key modelNodeId);
+
+  /**
+   * @brief Get the id of ModelNode what this motion index looks.
+   *
+   * @SINCE_2_2.99
+   * @return The model node id.
+   */
+  Property::Key GetModelNodeId() const;
+
+  /**
+   * @brief Get the property name of this MotionIndex from given ModelNode.
+   *
+   * @SINCE_2_2.99
+   * @param[in] node The model node to get the property name.
+   * @return The name of current property.
+   */
+  std::string GetPropertyName(ModelNode node = ModelNode());
+
+  /**
+   * @brief Get the property index of this MotionIndex from given ModelNode.
+   *
+   * @SINCE_2_2.99
+   * @param[in] node The model node to get the property index.
+   * @return The index of current property.
+   */
+  Property::Index GetPropertyIndex(ModelNode node = ModelNode());
+
+public: // Not intended for application developers
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Scene3D::Internal implementation.
+   *
+   * @param[in] implementation The MotionIndex implementation
+   */
+  DALI_INTERNAL MotionIndex(Dali::Scene3D::Internal::MotionIndex* implementation);
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+
+} // namespace Scene3D
+
+} // namespace Dali
+
+#endif // DALI_SCENE3D_MODEL_MOTION_MOTION_INDEX_H
\ No newline at end of file
diff --git a/dali-scene3d/public-api/model-motion/motion-index/motion-property-index.cpp b/dali-scene3d/public-api/model-motion/motion-index/motion-property-index.cpp
new file mode 100644 (file)
index 0000000..3dc7d76
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-property-index.h>
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/internal/model-motion/motion-index/motion-property-index-impl.h>
+
+namespace Dali
+{
+namespace Scene3D
+{
+MotionPropertyIndex MotionPropertyIndex::New()
+{
+  Internal::MotionPropertyIndexPtr internal = Internal::MotionPropertyIndex::New();
+
+  return MotionPropertyIndex(internal.Get());
+}
+
+MotionPropertyIndex MotionPropertyIndex::New(Property::Key modelNodeId, Property::Key propertyId)
+{
+  Internal::MotionPropertyIndexPtr internal = Internal::MotionPropertyIndex::New();
+
+  internal->SetModelNodeId(modelNodeId);
+  internal->SetPropertyId(propertyId);
+
+  return MotionPropertyIndex(internal.Get());
+}
+
+MotionPropertyIndex::MotionPropertyIndex()
+{
+}
+
+MotionPropertyIndex::MotionPropertyIndex(const MotionPropertyIndex& motionPropertyIndex) = default;
+
+MotionPropertyIndex::MotionPropertyIndex(MotionPropertyIndex&& rhs) noexcept = default;
+
+MotionPropertyIndex::~MotionPropertyIndex()
+{
+}
+
+MotionPropertyIndex& MotionPropertyIndex::operator=(const MotionPropertyIndex& handle) = default;
+
+MotionPropertyIndex& MotionPropertyIndex::operator=(MotionPropertyIndex&& rhs) noexcept = default;
+
+MotionPropertyIndex MotionPropertyIndex::DownCast(BaseHandle handle)
+{
+  return MotionPropertyIndex(dynamic_cast<Dali::Scene3D::Internal::MotionPropertyIndex*>(handle.GetObjectPtr()));
+}
+
+MotionPropertyIndex::MotionPropertyIndex(Dali::Scene3D::Internal::MotionPropertyIndex* internal)
+: MotionIndex(internal)
+{
+}
+
+// Public Method
+
+void MotionPropertyIndex::SetPropertyId(Property::Key blendShapeId)
+{
+  GetImplementation(*this).SetPropertyId(blendShapeId);
+}
+
+Property::Key MotionPropertyIndex::GetPropertyId() const
+{
+  return GetImplementation(*this).GetPropertyId();
+}
+
+} // namespace Scene3D
+
+} // namespace Dali
\ No newline at end of file
diff --git a/dali-scene3d/public-api/model-motion/motion-index/motion-property-index.h b/dali-scene3d/public-api/model-motion/motion-index/motion-property-index.h
new file mode 100644 (file)
index 0000000..335fb41
--- /dev/null
@@ -0,0 +1,168 @@
+#ifndef DALI_SCENE3D_MODEL_MOTION_MOTION_PROPERTY_INDEX_H
+#define DALI_SCENE3D_MODEL_MOTION_MOTION_PROPERTY_INDEX_H
+
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-index.h>
+
+namespace Dali
+{
+namespace Scene3D
+{
+//Forward declarations.
+namespace Internal
+{
+class MotionPropertyIndex;
+} // namespace Internal
+
+/**
+ * @addtogroup dali_scene3d_model_motion_motion_property_index
+ * @{
+ */
+
+/**
+ * @brief Basic MotionIndex to control dali property.
+ *
+ * @SINCE_2_2.99
+ */
+class DALI_SCENE3D_API MotionPropertyIndex : public MotionIndex
+{
+public: // Creation & Destruction
+  /**
+   * @brief Create an initialized MotionPropertyIndex.
+   *
+   * @SINCE_2_2.99
+   * @return A handle to a newly allocated Dali resource
+   */
+  static MotionPropertyIndex New();
+
+  /**
+   * @brief Create an initialized MotionPropertyIndex with values.
+   *
+   * @SINCE_2_2.99
+   * @param[in] modelNodeId The id of model node what this motion index looks.
+   * @param[in] propertyId The id of property what this motion index looks.
+   * @return A handle to a newly allocated Dali resource
+   */
+  static MotionPropertyIndex New(Property::Key modelNodeId, Property::Key propertyId);
+
+  /**
+   * @brief Creates an uninitialized MotionPropertyIndex.
+   *
+   * Only derived versions can be instantiated. Calling member
+   * functions with an uninitialized Dali::Object is not allowed.
+   *
+   * @SINCE_2_2.99
+   */
+  MotionPropertyIndex();
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   *
+   * @SINCE_2_2.99
+   */
+  ~MotionPropertyIndex();
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @SINCE_2_2.99
+   * @param[in] motionPropertyIndex Handle to an object
+   */
+  MotionPropertyIndex(const MotionPropertyIndex& motionPropertyIndex);
+
+  /**
+   * @brief Move constructor
+   *
+   * @SINCE_2_2.99
+   * @param[in] rhs A reference to the moved handle
+   */
+  MotionPropertyIndex(MotionPropertyIndex&& rhs) noexcept;
+
+  /**
+   * @brief Assignment operator.
+   *
+   * @SINCE_2_2.99
+   * @param[in] motionPropertyIndex Handle to an object
+   * @return reference to this
+   */
+  MotionPropertyIndex& operator=(const MotionPropertyIndex& motionPropertyIndex);
+
+  /**
+   * @brief Move assignment
+   *
+   * @SINCE_2_2.99
+   * @param[in] rhs A reference to the moved handle
+   * @return A reference to this
+   */
+  MotionPropertyIndex& operator=(MotionPropertyIndex&& rhs) noexcept;
+
+  /**
+   * @brief Downcasts an Object handle to MotionPropertyIndex.
+   *
+   * If handle points to a MotionPropertyIndex, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   *
+   * @SINCE_2_2.99
+   * @param[in] handle Handle to an object
+   * @return Handle to a MotionPropertyIndex or an uninitialized handle
+   */
+  static MotionPropertyIndex DownCast(BaseHandle handle);
+
+public: // Public Method
+  /**
+   * @brief Set the id of property what this motion index looks.
+   *
+   * @SINCE_2_2.99
+   * @param[in] propertyId The property id.
+   */
+  void SetPropertyId(Property::Key propertyId);
+
+  /**
+   * @brief Get the id of property what this motion index looks.
+   *
+   * @SINCE_2_2.99
+   * @return The blend shape id.
+   */
+  Property::Key GetPropertyId() const;
+
+public: // Not intended for application developers
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Scene3D::Internal implementation.
+   *
+   * @param[in] implementation The MotionPropertyIndex implementation
+   */
+  DALI_INTERNAL MotionPropertyIndex(Dali::Scene3D::Internal::MotionPropertyIndex* implementation);
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+
+} // namespace Scene3D
+
+} // namespace Dali
+
+#endif // DALI_SCENE3D_MODEL_MOTION_MOTION_PROPERTY_INDEX_H
\ No newline at end of file
diff --git a/dali-scene3d/public-api/model-motion/motion-index/motion-transform-index.cpp b/dali-scene3d/public-api/model-motion/motion-index/motion-transform-index.cpp
new file mode 100644 (file)
index 0000000..5ea483f
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-transform-index.h>
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/internal/model-motion/motion-index/motion-transform-index-impl.h>
+
+namespace Dali
+{
+namespace Scene3D
+{
+MotionTransformIndex MotionTransformIndex::New()
+{
+  Internal::MotionTransformIndexPtr internal = Internal::MotionTransformIndex::New();
+
+  return MotionTransformIndex(internal.Get());
+}
+
+MotionTransformIndex MotionTransformIndex::New(Property::Key modelNodeId, TransformType type)
+{
+  Internal::MotionTransformIndexPtr internal = Internal::MotionTransformIndex::New();
+
+  internal->SetModelNodeId(modelNodeId);
+  internal->SetTransformType(type);
+
+  return MotionTransformIndex(internal.Get());
+}
+
+MotionTransformIndex::MotionTransformIndex()
+{
+}
+
+MotionTransformIndex::MotionTransformIndex(const MotionTransformIndex& motionTransformIndex) = default;
+
+MotionTransformIndex::MotionTransformIndex(MotionTransformIndex&& rhs) noexcept = default;
+
+MotionTransformIndex::~MotionTransformIndex()
+{
+}
+
+MotionTransformIndex& MotionTransformIndex::operator=(const MotionTransformIndex& handle) = default;
+
+MotionTransformIndex& MotionTransformIndex::operator=(MotionTransformIndex&& rhs) noexcept = default;
+
+MotionTransformIndex MotionTransformIndex::DownCast(BaseHandle handle)
+{
+  return MotionTransformIndex(dynamic_cast<Dali::Scene3D::Internal::MotionTransformIndex*>(handle.GetObjectPtr()));
+}
+
+MotionTransformIndex::MotionTransformIndex(Dali::Scene3D::Internal::MotionTransformIndex* internal)
+: MotionIndex(internal)
+{
+}
+
+// Public Method
+
+void MotionTransformIndex::SetTransformType(MotionTransformIndex::TransformType type)
+{
+  GetImplementation(*this).SetTransformType(type);
+}
+
+MotionTransformIndex::TransformType MotionTransformIndex::GetTransformType() const
+{
+  return GetImplementation(*this).GetTransformType();
+}
+
+} // namespace Scene3D
+
+} // namespace Dali
\ No newline at end of file
diff --git a/dali-scene3d/public-api/model-motion/motion-index/motion-transform-index.h b/dali-scene3d/public-api/model-motion/motion-index/motion-transform-index.h
new file mode 100644 (file)
index 0000000..d90f546
--- /dev/null
@@ -0,0 +1,190 @@
+#ifndef DALI_SCENE3D_MODEL_MOTION_MOTION_TRANSFORM_INDEX_H
+#define DALI_SCENE3D_MODEL_MOTION_MOTION_TRANSFORM_INDEX_H
+
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/public-api/model-motion/motion-index/motion-index.h>
+
+namespace Dali
+{
+namespace Scene3D
+{
+//Forward declarations.
+namespace Internal
+{
+class MotionTransformIndex;
+} // namespace Internal
+
+/**
+ * @addtogroup dali_scene3d_model_motion_motion_transform_index
+ * @{
+ */
+
+/**
+ * @brief Specialized MotionIndex to control transform.
+ *
+ * @SINCE_2_2.99
+ */
+class DALI_SCENE3D_API MotionTransformIndex : public MotionIndex
+{
+public:
+  /**
+   * @brief The type of Transform
+   * @SINCE_2_2.99
+   */
+  enum class TransformType
+  {
+    INVALID = -1,
+
+    POSITION = 0, ///< The position of ModelNode. MotionValue should be Vector3.
+    POSITION_X,   ///< The x position of ModelNode. MotionValue should be float.
+    POSITION_Y,   ///< The y position of ModelNode. MotionValue should be float.
+    POSITION_Z,   ///< The z position of ModelNode. MotionValue should be float.
+
+    ORIENTATION, ///< The orientation of ModelNode. MotionValue should be Quaternion.
+
+    SCALE,   ///< The scale of ModelNode. MotionValue should be Vector3.
+    SCALE_X, ///< The x scale of ModelNode. MotionValue should be float.
+    SCALE_Y, ///< The y scale of ModelNode. MotionValue should be float.
+    SCALE_Z, ///< The z scale of ModelNode. MotionValue should be float.
+  };
+
+public: // Creation & Destruction
+  /**
+   * @brief Create an initialized MotionTransformIndex.
+   *
+   * @SINCE_2_2.99
+   * @return A handle to a newly allocated Dali resource
+   */
+  static MotionTransformIndex New();
+
+  /**
+   * @brief Create an initialized MotionTransformIndex with values.
+   *
+   * @SINCE_2_2.99
+   * @param[in] modelNodeId The id of model node what this motion index looks.
+   * @param[in] type The type of transform what this motion index looks.
+   * @return A handle to a newly allocated Dali resource
+   */
+  static MotionTransformIndex New(Property::Key modelNodeId, TransformType type);
+
+  /**
+   * @brief Creates an uninitialized MotionTransformIndex.
+   *
+   * Only derived versions can be instantiated. Calling member
+   * functions with an uninitialized Dali::Object is not allowed.
+   *
+   * @SINCE_2_2.99
+   */
+  MotionTransformIndex();
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   *
+   * @SINCE_2_2.99
+   */
+  ~MotionTransformIndex();
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @SINCE_2_2.99
+   * @param[in] motionTransformIndex Handle to an object
+   */
+  MotionTransformIndex(const MotionTransformIndex& motionTransformIndex);
+
+  /**
+   * @brief Move constructor
+   *
+   * @SINCE_2_2.99
+   * @param[in] rhs A reference to the moved handle
+   */
+  MotionTransformIndex(MotionTransformIndex&& rhs) noexcept;
+
+  /**
+   * @brief Assignment operator.
+   *
+   * @SINCE_2_2.99
+   * @param[in] motionTransformIndex Handle to an object
+   * @return reference to this
+   */
+  MotionTransformIndex& operator=(const MotionTransformIndex& motionTransformIndex);
+
+  /**
+   * @brief Move assignment
+   *
+   * @SINCE_2_2.99
+   * @param[in] rhs A reference to the moved handle
+   * @return A reference to this
+   */
+  MotionTransformIndex& operator=(MotionTransformIndex&& rhs) noexcept;
+
+  /**
+   * @brief Downcasts an Object handle to MotionTransformIndex.
+   *
+   * If handle points to a MotionTransformIndex, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   *
+   * @SINCE_2_2.99
+   * @param[in] handle Handle to an object
+   * @return Handle to a MotionTransformIndex or an uninitialized handle
+   */
+  static MotionTransformIndex DownCast(BaseHandle handle);
+
+public: // Public Method
+  /**
+   * @brief Set the type of transform what this motion index looks.
+   *
+   * @SINCE_2_2.99
+   * @param[in] type The type of transform.
+   */
+  void SetTransformType(TransformType type);
+
+  /**
+   * @brief Get the type of transform what this motion index looks.
+   *
+   * @SINCE_2_2.99
+   * @return The type of transform.
+   */
+  TransformType GetTransformType() const;
+
+public: // Not intended for application developers
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Scene3D::Internal implementation.
+   *
+   * @param[in] implementation The MotionTransformIndex implementation
+   */
+  DALI_INTERNAL MotionTransformIndex(Dali::Scene3D::Internal::MotionTransformIndex* implementation);
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+
+} // namespace Scene3D
+
+} // namespace Dali
+
+#endif // DALI_SCENE3D_MODEL_MOTION_MOTION_TRANSFORM_INDEX_H
\ No newline at end of file
diff --git a/dali-scene3d/public-api/model-motion/motion-value.cpp b/dali-scene3d/public-api/model-motion/motion-value.cpp
new file mode 100644 (file)
index 0000000..dd5b00a
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali-scene3d/public-api/model-motion/motion-value.h>
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/internal/model-motion/motion-value-impl.h>
+
+namespace Dali
+{
+namespace Scene3D
+{
+MotionValue MotionValue::New()
+{
+  Internal::MotionValuePtr internal = Internal::MotionValue::New();
+
+  return MotionValue(internal.Get());
+}
+
+MotionValue MotionValue::New(Property::Value propertyValue)
+{
+  Internal::MotionValuePtr internal = Internal::MotionValue::New();
+
+  internal->SetValue(propertyValue);
+
+  return MotionValue(internal.Get());
+}
+
+MotionValue MotionValue::New(KeyFrames keyFrames)
+{
+  Internal::MotionValuePtr internal = Internal::MotionValue::New();
+
+  internal->SetValue(keyFrames);
+
+  return MotionValue(internal.Get());
+}
+
+MotionValue::MotionValue()
+{
+}
+
+MotionValue::MotionValue(const MotionValue& motionValue) = default;
+
+MotionValue::MotionValue(MotionValue&& rhs) noexcept = default;
+
+MotionValue::~MotionValue()
+{
+}
+
+MotionValue& MotionValue::operator=(const MotionValue& handle) = default;
+
+MotionValue& MotionValue::operator=(MotionValue&& rhs) noexcept = default;
+
+MotionValue MotionValue::DownCast(BaseHandle handle)
+{
+  return MotionValue(dynamic_cast<Dali::Scene3D::Internal::MotionValue*>(handle.GetObjectPtr()));
+}
+
+MotionValue::MotionValue(Dali::Scene3D::Internal::MotionValue* internal)
+: BaseHandle(internal)
+{
+}
+
+// Public Method
+
+MotionValue::ValueType MotionValue::GetValueType() const
+{
+  return GetImplementation(*this).GetValueType();
+}
+
+void MotionValue::SetValue(Property::Value propertyValue)
+{
+  GetImplementation(*this).SetValue(propertyValue);
+}
+
+void MotionValue::SetValue(KeyFrames keyFrames)
+{
+  GetImplementation(*this).SetValue(keyFrames);
+}
+
+void MotionValue::Clear()
+{
+  GetImplementation(*this).Clear();
+}
+
+Property::Value MotionValue::GetPropertyValue() const
+{
+  return GetImplementation(*this).GetPropertyValue();
+}
+
+KeyFrames MotionValue::GetKeyFrames() const
+{
+  return GetImplementation(*this).GetKeyFrames();
+}
+
+} // namespace Scene3D
+
+} // namespace Dali
\ No newline at end of file
diff --git a/dali-scene3d/public-api/model-motion/motion-value.h b/dali-scene3d/public-api/model-motion/motion-value.h
new file mode 100644 (file)
index 0000000..96bdb5e
--- /dev/null
@@ -0,0 +1,232 @@
+#ifndef DALI_SCENE3D_MODEL_MOTION_MOTION_VALUE_H
+#define DALI_SCENE3D_MODEL_MOTION_MOTION_VALUE_H
+
+/*
+ * Copyright (c) 2023 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/animation/key-frames.h>
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/object/property-value.h>
+
+// INTERNAL INCLUDES
+#include <dali-scene3d/public-api/api.h>
+
+namespace Dali
+{
+namespace Scene3D
+{
+//Forward declarations.
+namespace Internal
+{
+class MotionValue;
+} // namespace Internal
+
+/**
+ * @addtogroup dali_scene3d_model_motion_motion_value
+ * @{
+ */
+
+/**
+ * @brief This MotionValue be used for target value of each MotionIndex.
+ * We can get and set MotionValue as 2 types : Property::Value and KeyFrames.
+ *
+ * Each types will be cross-converted internally.
+ * For example, when we set Property::Value, we can get KeyFrames with 2 frames, and target value is setted.
+ *
+ * @note The type of property should be matched with MotionIndex required.
+ * @SINCE_2_2.99
+ */
+class DALI_SCENE3D_API MotionValue : public Dali::BaseHandle
+{
+public:
+  /**
+   * @brief Determine whether current stored value is PropertyValue, or KeyFrames.
+   * @SINCE_2_2.99
+   */
+  enum class ValueType
+  {
+    INVALID = -1, ///< Value is null, or invalid.
+
+    PROPERTY_VALUE = 0, ///< Value is PropertyValue.
+    KEY_FRAMES,         ///< Value is KeyFrames.
+  };
+
+public: // Creation & Destruction
+  /**
+   * @brief Create an initialized MotionValue.
+   *
+   * @SINCE_2_2.99
+   * @return A handle to a newly allocated Dali resource
+   */
+  static MotionValue New();
+
+  /**
+   * @brief Create an initialized MotionValue with Property::Value.
+   *
+   * @SINCE_2_2.99
+   * @param[in] propertyValue The static value.
+   * @return A handle to a newly allocated Dali resource
+   */
+  static MotionValue New(Property::Value propertyValue);
+
+  /**
+   * @brief Create an initialized MotionValue with KeyFrames.
+   *
+   * @SINCE_2_2.99
+   * @param[in] keyFrames The keyframes value.
+   * @return A handle to a newly allocated Dali resource
+   */
+  static MotionValue New(KeyFrames keyFrames);
+
+  /**
+   * @brief Creates an uninitialized MotionValue.
+   *
+   * Only derived versions can be instantiated. Calling member
+   * functions with an uninitialized Dali::Object is not allowed.
+   *
+   * @SINCE_2_2.99
+   */
+  MotionValue();
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   *
+   * @SINCE_2_2.99
+   */
+  ~MotionValue();
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @SINCE_2_2.99
+   * @param[in] motionValue Handle to an object
+   */
+  MotionValue(const MotionValue& motionValue);
+
+  /**
+   * @brief Move constructor
+   *
+   * @SINCE_2_2.99
+   * @param[in] rhs A reference to the moved handle
+   */
+  MotionValue(MotionValue&& rhs) noexcept;
+
+  /**
+   * @brief Assignment operator.
+   *
+   * @SINCE_2_2.99
+   * @param[in] motionValue Handle to an object
+   * @return reference to this
+   */
+  MotionValue& operator=(const MotionValue& motionValue);
+
+  /**
+   * @brief Move assignment
+   *
+   * @SINCE_2_2.99
+   * @param[in] rhs A reference to the moved handle
+   * @return A reference to this
+   */
+  MotionValue& operator=(MotionValue&& rhs) noexcept;
+
+  /**
+   * @brief Downcasts an Object handle to MotionValue.
+   *
+   * If handle points to a MotionValue, the downcast produces valid handle.
+   * If not, the returned handle is left uninitialized.
+   *
+   * @SINCE_2_2.99
+   * @param[in] handle Handle to an object
+   * @return Handle to a MotionValue or an uninitialized handle
+   */
+  static MotionValue DownCast(BaseHandle handle);
+
+public: // Public Method
+  /**
+   * @brief Get the type of value this MotionValue hold.
+   * The type of value will be changed what we set.
+   *
+   * @SINCE_2_2.99
+   * @return Type of value.
+   */
+  ValueType GetValueType() const;
+
+  /**
+   * @brief Set the value as Property::Value type.
+   *
+   * @SINCE_2_2.99
+   * @param[in] propertyValue The static value.
+   */
+  void SetValue(Property::Value propertyValue);
+
+  /**
+   * @brief Set the value as KeyFrames type.
+   *
+   * @SINCE_2_2.99
+   * @param[in] keyFrames The keyframes value.
+   */
+  void SetValue(KeyFrames keyFrames);
+
+  /**
+   * @brief Make value as Invalid type.
+   *
+   * @SINCE_2_2.99
+   */
+  void Clear();
+
+  /**
+   * @brief Get the value as Property::Value.
+   * If ValueType is KEY_FRAMES, it will return last value of stored KeyFrames.
+   *
+   * @SINCE_2_2.99
+   * @return Property value, or empty if it is invalid.
+   */
+  Property::Value GetPropertyValue() const;
+
+  /**
+   * @brief Get the value as KeyFrames
+   * If ValueType is PROPERTY_VALUE, it will create new KeyFrames by stored Property::Value.
+   *
+   * @SINCE_2_2.99
+   * @return Keyframes handle, or empty if it is invalid.
+   */
+  KeyFrames GetKeyFrames() const;
+
+public: // Not intended for application developers
+  /// @cond internal
+  /**
+   * @brief Creates a handle using the Scene3D::Internal implementation.
+   *
+   * @param[in] implementation The MotionValue implementation
+   */
+  DALI_INTERNAL MotionValue(Dali::Scene3D::Internal::MotionValue* implementation);
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+
+} // namespace Scene3D
+
+} // namespace Dali
+
+#endif // DALI_SCENE3D_MODEL_MOTION_MOTION_VALUE_H
\ No newline at end of file