Load bvh and facial animations from buffer 21/291521/4
authorEunki, Hong <eunkiki.hong@samsung.com>
Tue, 18 Apr 2023 03:50:29 +0000 (12:50 +0900)
committerEunki, Hong <eunkiki.hong@samsung.com>
Wed, 19 Apr 2023 01:54:10 +0000 (10:54 +0900)
Let we allow to load bvh and facial animation from raw buffer stream.

Change-Id: I679539ce10e631101571dab95615404c41b9b2f3
Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
automated-tests/src/dali-scene3d/utc-Dali-BvhLoader.cpp
automated-tests/src/dali-scene3d/utc-Dali-FacialAnimation.cpp
dali-scene3d/public-api/loader/bvh-loader.cpp
dali-scene3d/public-api/loader/bvh-loader.h
dali-scene3d/public-api/loader/facial-animation-loader.cpp
dali-scene3d/public-api/loader/facial-animation-loader.h

index 2315bfd..d642ef4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * 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.
  *
  */
 
-#include <dali-test-suite-utils.h>
 #include <dali-scene3d/public-api/loader/bvh-loader.h>
+#include <dali-test-suite-utils.h>
+
+#include <fstream>
 
 using namespace Dali;
 using namespace Dali::Scene3D::Loader;
 
-int UtcDaliLoadBvh(void)
+namespace
 {
-  TestApplication application;
-
-  AnimationDefinition animDef = LoadBvh(TEST_RESOURCE_DIR "/test.bvh", "testBvh");
-
-  DALI_TEST_EQUAL(animDef.GetName(), "testBvh");
-  DALI_TEST_EQUAL(animDef.GetDuration(), 0.3f);
-
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(0).mNodeName, "root");
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(0).mPropertyName, "position");
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(0).mKeyFrames.GetType(), Property::Type::VECTOR3);
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(0).mTimePeriod.durationSeconds, 0.3f);
-
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(1).mNodeName, "root");
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(1).mPropertyName, "orientation");
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(1).mKeyFrames.GetType(), Property::Type::ROTATION);
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(1).mTimePeriod.durationSeconds, 0.3f);
-
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(2).mNodeName, "first");
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(2).mPropertyName, "position");
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(2).mKeyFrames.GetType(), Property::Type::VECTOR3);
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(2).mTimePeriod.durationSeconds, 0.3f);
-
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(3).mNodeName, "first");
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(3).mPropertyName, "orientation");
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(3).mKeyFrames.GetType(), Property::Type::ROTATION);
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(3).mTimePeriod.durationSeconds, 0.3f);
-
-  Actor root = Actor::New();
-  root.SetProperty(Actor::Property::NAME, "root");
-
-  Actor first = Actor::New();
-  first.SetProperty(Actor::Property::NAME, "first");
-  root.Add(first);
-
-  auto getActor = [&root](const Dali::Scene3D::Loader::AnimatedProperty& property) {
-    return root.FindChildByName(property.mNodeName);
-  };
-
-  Animation animation = animDef.ReAnimate(getActor);
-  DALI_TEST_EQUAL(animation.GetDuration(), animDef.GetDuration());
-
-  application.GetScene().Add(root);
+std::string ReadBufferFromFile(const std::string& url)
+{
+  std::string  rawString;
+  std::fstream fileStream;
 
-  application.SendNotification();
-  application.Render(20);
+  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));
+  }
 
-  DALI_TEST_EQUALS(Vector2(0, 0), root.GetProperty<Vector2>(Actor::Property::POSITION), TEST_LOCATION);
-  DALI_TEST_EQUALS(Vector2(0, 0), first.GetProperty<Vector2>(Actor::Property::POSITION), TEST_LOCATION);
-  Vector3 rootWorldPositionBefore = root.GetProperty<Vector3>(Actor::Property::WORLD_POSITION);
-  Vector3 firstWorldPositionBefore = first.GetProperty<Vector3>(Actor::Property::WORLD_POSITION);
+  // get length of file:
+  fileStream.seekg(0, std::ios::end);
+  auto length = fileStream.tellg();
+  fileStream.seekg(0, std::ios::beg);
 
-  animation.Play();
+  rawString.resize(length);
+  fileStream.read(rawString.data(), length);
 
-  application.SendNotification();
-  application.Render(1000);
+  fileStream.close();
 
-  DALI_TEST_EQUALS(Vector2(0, 10), root.GetProperty<Vector2>(Actor::Property::POSITION), TEST_LOCATION);
-  DALI_TEST_EQUALS(Vector2(10, 0), first.GetProperty<Vector2>(Actor::Property::POSITION), TEST_LOCATION);
+  return rawString;
+}
+} // namespace
 
-  Vector3 rootWorldPositionAfter = root.GetProperty<Vector3>(Actor::Property::WORLD_POSITION);
-  Vector3 firstWorldPositionAfter = first.GetProperty<Vector3>(Actor::Property::WORLD_POSITION);
+int UtcDaliLoadBvh(void)
+{
+  TestApplication application;
 
-  DALI_TEST_EQUALS(Vector3(0, 10, 0), rootWorldPositionAfter - rootWorldPositionBefore, TEST_LOCATION);
-  DALI_TEST_EQUALS(Vector3(10, 10, 0), firstWorldPositionAfter - firstWorldPositionBefore, TEST_LOCATION);
+  for(uint32_t tc = 0; tc < 2; ++tc)
+  {
+    AnimationDefinition animDef;
+    tet_printf("UtcDaliLoadBvh testcase %u\n", tc);
+    switch(tc)
+    {
+      case 0: // Load bvh from url
+      {
+        animDef = LoadBvh(TEST_RESOURCE_DIR "/test.bvh", "testBvh");
+        break;
+      }
+      case 1: // Load bvh from buffer stream.
+      {
+        std::string rawString = ReadBufferFromFile(TEST_RESOURCE_DIR "/test.bvh");
+        animDef               = LoadBvhFromBuffer(reinterpret_cast<uint8_t*>(rawString.data()), static_cast<int>(rawString.length()), "testBvh");
+        break;
+      }
+    }
+
+    DALI_TEST_EQUAL(animDef.GetName(), "testBvh");
+    DALI_TEST_EQUAL(animDef.GetDuration(), 0.3f);
+
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(0).mNodeName, "root");
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(0).mPropertyName, "position");
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(0).mKeyFrames.GetType(), Property::Type::VECTOR3);
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(0).mTimePeriod.durationSeconds, 0.3f);
+
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(1).mNodeName, "root");
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(1).mPropertyName, "orientation");
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(1).mKeyFrames.GetType(), Property::Type::ROTATION);
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(1).mTimePeriod.durationSeconds, 0.3f);
+
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(2).mNodeName, "first");
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(2).mPropertyName, "position");
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(2).mKeyFrames.GetType(), Property::Type::VECTOR3);
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(2).mTimePeriod.durationSeconds, 0.3f);
+
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(3).mNodeName, "first");
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(3).mPropertyName, "orientation");
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(3).mKeyFrames.GetType(), Property::Type::ROTATION);
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(3).mTimePeriod.durationSeconds, 0.3f);
+
+    Actor root = Actor::New();
+    root.SetProperty(Actor::Property::NAME, "root");
+
+    Actor first = Actor::New();
+    first.SetProperty(Actor::Property::NAME, "first");
+    root.Add(first);
+
+    auto getActor = [&root](const Dali::Scene3D::Loader::AnimatedProperty& property) {
+      return root.FindChildByName(property.mNodeName);
+    };
+
+    Animation animation = animDef.ReAnimate(getActor);
+    DALI_TEST_EQUAL(animation.GetDuration(), animDef.GetDuration());
+
+    application.GetScene().Add(root);
+
+    application.SendNotification();
+    application.Render(20);
+
+    DALI_TEST_EQUALS(Vector2(0, 0), root.GetProperty<Vector2>(Actor::Property::POSITION), TEST_LOCATION);
+    DALI_TEST_EQUALS(Vector2(0, 0), first.GetProperty<Vector2>(Actor::Property::POSITION), TEST_LOCATION);
+    Vector3 rootWorldPositionBefore  = root.GetProperty<Vector3>(Actor::Property::WORLD_POSITION);
+    Vector3 firstWorldPositionBefore = first.GetProperty<Vector3>(Actor::Property::WORLD_POSITION);
+
+    animation.Play();
+
+    application.SendNotification();
+    application.Render(1000);
+
+    DALI_TEST_EQUALS(Vector2(0, 10), root.GetProperty<Vector2>(Actor::Property::POSITION), TEST_LOCATION);
+    DALI_TEST_EQUALS(Vector2(10, 0), first.GetProperty<Vector2>(Actor::Property::POSITION), TEST_LOCATION);
+
+    Vector3 rootWorldPositionAfter  = root.GetProperty<Vector3>(Actor::Property::WORLD_POSITION);
+    Vector3 firstWorldPositionAfter = first.GetProperty<Vector3>(Actor::Property::WORLD_POSITION);
+
+    DALI_TEST_EQUALS(Vector3(0, 10, 0), rootWorldPositionAfter - rootWorldPositionBefore, TEST_LOCATION);
+    DALI_TEST_EQUALS(Vector3(10, 10, 0), firstWorldPositionAfter - firstWorldPositionBefore, TEST_LOCATION);
+  }
 
   END_TEST;
 }
 
-
-
-int UtcDaliLoadBvhFailed(void)
+int UtcDaliLoadBvhFailed01(void)
 {
   TestApplication application;
 
@@ -101,3 +146,12 @@ int UtcDaliLoadBvhFailed(void)
   DALI_TEST_EQUALS(0u, animDef.GetPropertyCount(), TEST_LOCATION);
   END_TEST;
 }
+
+int UtcDaliLoadBvhFailed02(void)
+{
+  TestApplication application;
+
+  AnimationDefinition animDef = LoadBvhFromBuffer(nullptr, 0, "testBvh");
+  DALI_TEST_EQUALS(0u, animDef.GetPropertyCount(), TEST_LOCATION);
+  END_TEST;
+}
\ No newline at end of file
index 100cd72..c130b2e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * 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.
  *
  */
 
-#include <dali-test-suite-utils.h>
 #include <dali-scene3d/public-api/loader/animation-definition.h>
 #include <dali-scene3d/public-api/loader/facial-animation-loader.h>
+#include <dali-test-suite-utils.h>
+
+#include <fstream>
 
 using namespace Dali;
 using namespace Dali::Scene3D::Loader;
 
+namespace
+{
+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;
+}
+} // namespace
+
 int UtcDaliLoadFacialAnimation(void)
 {
   TestApplication app;
 
-  AnimationDefinition animDef = LoadFacialAnimation(TEST_RESOURCE_DIR "/facial-blendshape-animation.json");
-
-  std::string name = animDef.GetName();
-  DALI_TEST_EQUAL(name, "Facial_Blendshape_Animation");
-  DALI_TEST_EQUAL(animDef.GetDuration(), 14.966001f);
-  DALI_TEST_EQUAL(animDef.GetEndAction(), Animation::BAKE);
-  DALI_TEST_EQUAL(animDef.GetSpeedFactor(), 1.0f);
-  DALI_TEST_EQUAL(animDef.GetLoopCount(), 1);
-  DALI_TEST_EQUAL(animDef.GetPropertyCount(), 122);
-
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(0).mNodeName, "GEO_1");
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(0).mPropertyName, "uBlendShapeWeight[0]");
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(0).mKeyFrames.GetType(), Property::Type::FLOAT);
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(0).mTimePeriod.delaySeconds, 0.0f);
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(0).mTimePeriod.durationSeconds, 14.966001f);
-
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(69).mNodeName, "GEO_2");
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(69).mPropertyName, "uBlendShapeWeight[1]");
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(69).mKeyFrames.GetType(), Property::Type::FLOAT);
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(69).mTimePeriod.delaySeconds, 0.0f);
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(69).mTimePeriod.durationSeconds, 14.966001f);
-
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(86).mNodeName, "GEO_3");
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(86).mPropertyName, "uBlendShapeWeight[2]");
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(86).mKeyFrames.GetType(), Property::Type::FLOAT);
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(86).mTimePeriod.delaySeconds, 0.0f);
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(86).mTimePeriod.durationSeconds, 14.966001f);
-
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(100).mNodeName, "GEO_4");
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(100).mPropertyName, "uBlendShapeWeight[7]");
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(100).mKeyFrames.GetType(), Property::Type::FLOAT);
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(100).mTimePeriod.delaySeconds, 0.0f);
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(100).mTimePeriod.durationSeconds, 14.966001f);
-
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(121).mNodeName, "GEO_5");
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(121).mPropertyName, "uBlendShapeWeight[19]");
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(121).mKeyFrames.GetType(), Property::Type::FLOAT);
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(121).mTimePeriod.delaySeconds, 0.0f);
-  DALI_TEST_EQUAL(animDef.GetPropertyAt(121).mTimePeriod.durationSeconds, 14.966001f);
-
-  auto actor = Actor::New();
-  actor.SetProperty(Actor::Property::NAME, "GEO_1");
-
-  char        weightNameBuffer[32];
-  char* const pWeightName = weightNameBuffer + snprintf(weightNameBuffer, sizeof(weightNameBuffer), "%s", "uBlendShapeWeight");
-  for(int i = 0; i < 122; i++)
+  for(uint32_t tc = 0; tc < 2; ++tc)
   {
-    snprintf(pWeightName, sizeof(weightNameBuffer) - (pWeightName - weightNameBuffer), "[%d]", i);
-    std::string weightName{weightNameBuffer};
-    actor.RegisterProperty(weightName, 0.0f);
-  }
+    tet_printf("UtcDaliLoadFacialAnimation testcase %u\n", tc);
+    AnimationDefinition animDef;
+    switch(tc)
+    {
+      case 0: // Load bvh from url
+      {
+        animDef = LoadFacialAnimation(TEST_RESOURCE_DIR "/facial-blendshape-animation.json");
+        break;
+      }
+      case 1: // Load bvh from buffer stream.
+      {
+        std::string rawString = ReadBufferFromFile(TEST_RESOURCE_DIR "/facial-blendshape-animation.json");
+        animDef               = LoadFacialAnimationFromBuffer(reinterpret_cast<uint8_t*>(rawString.data()), static_cast<int>(rawString.length()));
+        break;
+      }
+    }
+
+    std::string name = animDef.GetName();
+    DALI_TEST_EQUAL(name, "Facial_Blendshape_Animation");
+    DALI_TEST_EQUAL(animDef.GetDuration(), 14.966001f);
+    DALI_TEST_EQUAL(animDef.GetEndAction(), Animation::BAKE);
+    DALI_TEST_EQUAL(animDef.GetSpeedFactor(), 1.0f);
+    DALI_TEST_EQUAL(animDef.GetLoopCount(), 1);
+    DALI_TEST_EQUAL(animDef.GetPropertyCount(), 122);
+
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(0).mNodeName, "GEO_1");
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(0).mPropertyName, "uBlendShapeWeight[0]");
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(0).mKeyFrames.GetType(), Property::Type::FLOAT);
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(0).mTimePeriod.delaySeconds, 0.0f);
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(0).mTimePeriod.durationSeconds, 14.966001f);
+
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(69).mNodeName, "GEO_2");
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(69).mPropertyName, "uBlendShapeWeight[1]");
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(69).mKeyFrames.GetType(), Property::Type::FLOAT);
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(69).mTimePeriod.delaySeconds, 0.0f);
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(69).mTimePeriod.durationSeconds, 14.966001f);
 
-  auto getActor = [&actor](const Dali::Scene3D::Loader::AnimatedProperty& property) {
-    return actor.FindChildByName(property.mNodeName);
-  };
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(86).mNodeName, "GEO_3");
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(86).mPropertyName, "uBlendShapeWeight[2]");
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(86).mKeyFrames.GetType(), Property::Type::FLOAT);
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(86).mTimePeriod.delaySeconds, 0.0f);
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(86).mTimePeriod.durationSeconds, 14.966001f);
 
-  auto anim = animDef.ReAnimate(getActor);
-  DALI_TEST_EQUAL(anim.GetDuration(), animDef.GetDuration());
-  DALI_TEST_EQUAL(anim.GetEndAction(), animDef.GetEndAction());
-  DALI_TEST_EQUAL(anim.GetSpeedFactor(), animDef.GetSpeedFactor());
-  DALI_TEST_EQUAL(anim.GetLoopCount(), animDef.GetLoopCount());
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(100).mNodeName, "GEO_4");
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(100).mPropertyName, "uBlendShapeWeight[7]");
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(100).mKeyFrames.GetType(), Property::Type::FLOAT);
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(100).mTimePeriod.delaySeconds, 0.0f);
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(100).mTimePeriod.durationSeconds, 14.966001f);
+
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(121).mNodeName, "GEO_5");
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(121).mPropertyName, "uBlendShapeWeight[19]");
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(121).mKeyFrames.GetType(), Property::Type::FLOAT);
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(121).mTimePeriod.delaySeconds, 0.0f);
+    DALI_TEST_EQUAL(animDef.GetPropertyAt(121).mTimePeriod.durationSeconds, 14.966001f);
+
+    auto actor = Actor::New();
+    actor.SetProperty(Actor::Property::NAME, "GEO_1");
+
+    char        weightNameBuffer[32];
+    char* const pWeightName = weightNameBuffer + snprintf(weightNameBuffer, sizeof(weightNameBuffer), "%s", "uBlendShapeWeight");
+    for(int i = 0; i < 122; i++)
+    {
+      snprintf(pWeightName, sizeof(weightNameBuffer) - (pWeightName - weightNameBuffer), "[%d]", i);
+      std::string weightName{weightNameBuffer};
+      actor.RegisterProperty(weightName, 0.0f);
+    }
+
+    auto getActor = [&actor](const Dali::Scene3D::Loader::AnimatedProperty& property) {
+      return actor.FindChildByName(property.mNodeName);
+    };
+
+    auto anim = animDef.ReAnimate(getActor);
+    DALI_TEST_EQUAL(anim.GetDuration(), animDef.GetDuration());
+    DALI_TEST_EQUAL(anim.GetEndAction(), animDef.GetEndAction());
+    DALI_TEST_EQUAL(anim.GetSpeedFactor(), animDef.GetSpeedFactor());
+    DALI_TEST_EQUAL(anim.GetLoopCount(), animDef.GetLoopCount());
+  }
 
   END_TEST;
 }
index 70cb297..3930d33 100644 (file)
@@ -19,6 +19,9 @@
 #include <dali-scene3d/public-api/loader/bvh-loader.h>
 
 // EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/file-stream.h>
+#include <dali/integration-api/debug.h>
+
 #include <fstream>
 #include <iostream>
 #include <memory>
@@ -84,7 +87,7 @@ void trim(std::string& s)
           s.end());
 }
 
-void ParseHierarchy(std::ifstream& file, std::shared_ptr<Joint>& joint)
+void ParseHierarchy(std::istream& file, std::shared_ptr<Joint>& joint)
 {
   std::string line;
   while(std::getline(file, line))
@@ -168,7 +171,7 @@ void MakeList(std::shared_ptr<Joint>& joint, std::vector<std::shared_ptr<Joint>>
   }
 }
 
-void ParseMotion(std::ifstream& file, std::shared_ptr<Joint>& hierarchy, uint32_t& frameCount, float& frameTime)
+void ParseMotion(std::istream& file, std::shared_ptr<Joint>& hierarchy, uint32_t& frameCount, float& frameTime)
 {
   std::vector<std::shared_ptr<Joint>> jointList;
   MakeList(hierarchy, jointList);
@@ -195,7 +198,7 @@ void ParseMotion(std::ifstream& file, std::shared_ptr<Joint>& hierarchy, uint32_
     }
   }
 
-  while(getline(file, line))
+  while(std::getline(file, line))
   {
     trim(line);
     std::istringstream stream(line);
@@ -242,16 +245,10 @@ void ParseMotion(std::ifstream& file, std::shared_ptr<Joint>& hierarchy, uint32_
   }
 }
 
-bool ParseBvh(const std::string& path, uint32_t& frameCount, float& frameTime, std::shared_ptr<Joint>& rootJoint)
+bool ParseBvh(std::istream& file, uint32_t& frameCount, float& frameTime, std::shared_ptr<Joint>& rootJoint)
 {
-  std::ifstream file(path.data());
-  if(!file.is_open())
-  {
-    return false;
-  }
-
   std::string line;
-  while(getline(file, line))
+  while(std::getline(file, line))
   {
     trim(line);
     std::istringstream stream(line);
@@ -260,7 +257,7 @@ bool ParseBvh(const std::string& path, uint32_t& frameCount, float& frameTime, s
     if(token == TOKEN_HIERARCHY.data())
     {
       std::string line;
-      while(getline(file, line))
+      while(std::getline(file, line))
       {
         trim(line);
         std::istringstream stream(line);
@@ -289,7 +286,7 @@ AnimationDefinition GenerateAnimation(const std::string& animationName, std::sha
 
   animationDefinition.SetName(animationName);
   animationDefinition.SetDuration(frameTime * (frameCount - 1));
-  float keyFrameInterval        = (frameCount > 1u) ? 1.0f / static_cast<float>(frameCount - 1u) : Dali::Math::MACHINE_EPSILON_10;
+  float keyFrameInterval = (frameCount > 1u) ? 1.0f / static_cast<float>(frameCount - 1u) : Dali::Math::MACHINE_EPSILON_10;
 
   std::vector<std::shared_ptr<Joint>> jointList;
   MakeList(hierarchy, jointList);
@@ -300,14 +297,14 @@ AnimationDefinition GenerateAnimation(const std::string& animationName, std::sha
     for(uint32_t i = 0; i < jointList.size(); ++i)
     {
       AnimatedProperty translationProperty;
-      translationProperty.mTimePeriod       = Dali::TimePeriod(animationDefinition.GetDuration());
-      translationProperty.mNodeName         = jointList[i]->name;
-      translationProperty.mPropertyName     = PROPERTY_NAME_POSITION.data();
+      translationProperty.mTimePeriod   = Dali::TimePeriod(animationDefinition.GetDuration());
+      translationProperty.mNodeName     = jointList[i]->name;
+      translationProperty.mPropertyName = PROPERTY_NAME_POSITION.data();
 
       AnimatedProperty rotationProperty;
-      rotationProperty.mTimePeriod       = Dali::TimePeriod(animationDefinition.GetDuration());
-      rotationProperty.mNodeName         = jointList[i]->name;
-      rotationProperty.mPropertyName     = PROPERTY_NAME_ORIENTATION.data();
+      rotationProperty.mTimePeriod   = Dali::TimePeriod(animationDefinition.GetDuration());
+      rotationProperty.mNodeName     = jointList[i]->name;
+      rotationProperty.mPropertyName = PROPERTY_NAME_ORIENTATION.data();
 
       translationProperty.mKeyFrames = Dali::KeyFrames::New();
       rotationProperty.mKeyFrames    = Dali::KeyFrames::New();
@@ -323,14 +320,14 @@ AnimationDefinition GenerateAnimation(const std::string& animationName, std::sha
 
   return animationDefinition;
 }
-} // namespace
 
-AnimationDefinition LoadBvh(const std::string& path, const std::string& animationName, const Vector3& scale)
+AnimationDefinition LoadBvhInternal(std::istream& stream, const std::string& animationName, const Vector3& scale)
 {
   uint32_t               frameCount = 0;
   float                  frameTime  = 0.0f;
   std::shared_ptr<Joint> rootJoint(new Joint);
-  if(!ParseBvh(path, frameCount, frameTime, rootJoint))
+
+  if(!ParseBvh(stream, frameCount, frameTime, rootJoint))
   {
     AnimationDefinition animationDefinition;
     return animationDefinition;
@@ -338,4 +335,42 @@ AnimationDefinition LoadBvh(const std::string& path, const std::string& animatio
 
   return GenerateAnimation(animationName, rootJoint, frameCount, frameTime, scale);
 }
+} // namespace
+
+AnimationDefinition LoadBvh(const std::string& path, const std::string& animationName, const Vector3& scale)
+{
+  Dali::FileStream fileStream(path);
+  std::iostream&   stream = fileStream.GetStream();
+
+  if(stream.fail())
+  {
+    DALI_LOG_ERROR("Fail to load bvh file : %s\n", path.c_str());
+    AnimationDefinition animationDefinition;
+    return animationDefinition;
+  }
+
+  return LoadBvhInternal(stream, animationName, scale);
+}
+
+AnimationDefinition LoadBvhFromBuffer(const uint8_t* rawBuffer, int rawBufferLength, const std::string& animationName, const Vector3& scale)
+{
+  if(rawBuffer == nullptr || rawBufferLength == 0)
+  {
+    DALI_LOG_ERROR("Fail to load bvh buffer : buffer is empty!\n");
+    AnimationDefinition animationDefinition;
+    return animationDefinition;
+  }
+
+  Dali::FileStream fileStream(const_cast<uint8_t*>(rawBuffer), static_cast<size_t>(static_cast<uint32_t>(rawBufferLength)));
+  std::iostream&   stream = fileStream.GetStream();
+
+  if(stream.fail())
+  {
+    DALI_LOG_ERROR("Fail to load bvh buffer : buffer length : %d\n", rawBufferLength);
+    AnimationDefinition animationDefinition;
+    return animationDefinition;
+  }
+
+  return LoadBvhInternal(stream, animationName, scale);
+}
 } // namespace Dali::Scene3D::Loader
\ No newline at end of file
index 9830031..950b2ea 100644 (file)
@@ -33,6 +33,17 @@ namespace Dali::Scene3D::Loader
  */
 DALI_SCENE3D_API AnimationDefinition LoadBvh(const std::string& path, const std::string& animationName, const Vector3& scale = Vector3::ONE);
 
+/**
+ * @brief Loads motion capture data from bvh data stream.
+ *
+ * @param[in] rawBuffer The bvh buffer.
+ * @param[in] rawBufferLength The length of buffer.
+ * @param[in] animationName Name of the motion capture animation
+ * @param[in] scale The scale factor to set on the position property manually.
+ * @return AnimationDefinition that includes joint animation information.
+ */
+DALI_SCENE3D_API AnimationDefinition LoadBvhFromBuffer(const uint8_t* rawBuffer, int rawBufferLength, const std::string& animationName, const Vector3& scale = Vector3::ONE);
+
 } // namespace Dali::Scene3D::Loader
 
 #endif // DALI_SCENE3D_LOADER_BVH_LOADER_H
\ No newline at end of file
index 26afb29..36eff86 100644 (file)
@@ -1,5 +1,5 @@
 /*\r
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.\r
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.\r
  *\r
  * Licensed under the Apache License, Version 2.0 (the "License");\r
  * you may not use this file except in compliance with the License.\r
@@ -74,48 +74,29 @@ std::vector<std::vector<float>> ReadBlendShapeKeys(const json_value_s& j)
 const js::Reader<BlendShape>& GetBlendShapeReader()\r
 {\r
   static const auto BLEND_SHAPE_READER = std::move(js::Reader<BlendShape>()\r
-                                                      .Register(*js::MakeProperty("key", ReadBlendShapeKeys, &BlendShape::mKeys))\r
-                                                      .Register(*new js::Property<BlendShape, std::string_view>("name", js::Read::StringView, &BlendShape::mNodeName))\r
-                                                      .Register(*js::MakeProperty("morphtarget", js::Read::Number<uint32_t>, &BlendShape::mNumberOfMorphTarget))\r
-                                                      .Register(*new js::Property<BlendShape, std::string_view>("blendShapeVersion", js::Read::StringView, &BlendShape::mVersion))\r
-                                                      .Register(*new js::Property<BlendShape, std::string_view>("fullName", js::Read::StringView, &BlendShape::mFullName))\r
-                                                      .Register(*js::MakeProperty("morphname", js::Read::Array<std::string_view, js::Read::StringView>, &BlendShape::mMorphNames)));\r
+                                                     .Register(*js::MakeProperty("key", ReadBlendShapeKeys, &BlendShape::mKeys))\r
+                                                     .Register(*new js::Property<BlendShape, std::string_view>("name", js::Read::StringView, &BlendShape::mNodeName))\r
+                                                     .Register(*js::MakeProperty("morphtarget", js::Read::Number<uint32_t>, &BlendShape::mNumberOfMorphTarget))\r
+                                                     .Register(*new js::Property<BlendShape, std::string_view>("blendShapeVersion", js::Read::StringView, &BlendShape::mVersion))\r
+                                                     .Register(*new js::Property<BlendShape, std::string_view>("fullName", js::Read::StringView, &BlendShape::mFullName))\r
+                                                     .Register(*js::MakeProperty("morphname", js::Read::Array<std::string_view, js::Read::StringView>, &BlendShape::mMorphNames)));\r
   return BLEND_SHAPE_READER;\r
 }\r
 \r
 const js::Reader<FacialAnimation>& GetFacialAnimationReader()\r
 {\r
   static const auto FACIAL_ANIMATION_READER = std::move(js::Reader<FacialAnimation>()\r
-                                                           .Register(*new js::Property<FacialAnimation, std::string_view>("name", js::Read::StringView, &FacialAnimation::mName))\r
-                                                           .Register(*js::MakeProperty("blendShapes", js::Read::Array<BlendShape, js::ObjectReader<BlendShape>::Read>, &FacialAnimation::mBlendShapes))\r
-                                                           .Register(*new js::Property<FacialAnimation, std::string_view>("version", js::Read::StringView, &FacialAnimation::mVersion))\r
-                                                           .Register(*js::MakeProperty("shapesAmount", js::Read::Number<uint32_t>, &FacialAnimation::mNumberOfShapes))\r
-                                                           .Register(*js::MakeProperty("time", js::Read::Array<uint32_t, js::Read::Number>, &FacialAnimation::mTime))\r
-                                                           .Register(*js::MakeProperty("frames", js::Read::Number<uint32_t>, &FacialAnimation::mNumberOfFrames)));\r
+                                                          .Register(*new js::Property<FacialAnimation, std::string_view>("name", js::Read::StringView, &FacialAnimation::mName))\r
+                                                          .Register(*js::MakeProperty("blendShapes", js::Read::Array<BlendShape, js::ObjectReader<BlendShape>::Read>, &FacialAnimation::mBlendShapes))\r
+                                                          .Register(*new js::Property<FacialAnimation, std::string_view>("version", js::Read::StringView, &FacialAnimation::mVersion))\r
+                                                          .Register(*js::MakeProperty("shapesAmount", js::Read::Number<uint32_t>, &FacialAnimation::mNumberOfShapes))\r
+                                                          .Register(*js::MakeProperty("time", js::Read::Array<uint32_t, js::Read::Number>, &FacialAnimation::mTime))\r
+                                                          .Register(*js::MakeProperty("frames", js::Read::Number<uint32_t>, &FacialAnimation::mNumberOfFrames)));\r
   return FACIAL_ANIMATION_READER;\r
 }\r
 \r
-} // unnamed namespace\r
-\r
-namespace Scene3D\r
-{\r
-namespace Loader\r
+Dali::Scene3D::Loader::AnimationDefinition LoadFacialAnimationInternal(json::unique_ptr& root)\r
 {\r
-AnimationDefinition LoadFacialAnimation(const std::string& url)\r
-{\r
-  bool failed = false;\r
-  auto js     = LoadTextFile(url.c_str(), &failed);\r
-  if(failed)\r
-  {\r
-    ExceptionFlinger(ASSERT_LOCATION) << "Failed to load " << url << ".";\r
-  }\r
-\r
-  json::unique_ptr root(json_parse(js.c_str(), js.size()));\r
-  if(!root)\r
-  {\r
-    ExceptionFlinger(ASSERT_LOCATION) << "Failed to parse " << url << ".";\r
-  }\r
-\r
   static bool setObjectReaders = true;\r
   if(setObjectReaders)\r
   {\r
@@ -129,7 +110,7 @@ AnimationDefinition LoadFacialAnimation(const std::string& url)
   FacialAnimation facialAnimation;\r
   GetFacialAnimationReader().Read(rootObj, facialAnimation);\r
 \r
-  AnimationDefinition animationDefinition;\r
+  Dali::Scene3D::Loader::AnimationDefinition animationDefinition;\r
   animationDefinition.SetName(facialAnimation.mName.data());\r
   animationDefinition.SetDuration(MILLISECONDS_TO_SECONDS * static_cast<float>(facialAnimation.mTime[facialAnimation.mNumberOfFrames - 1u]));\r
 \r
@@ -146,11 +127,11 @@ AnimationDefinition LoadFacialAnimation(const std::string& url)
   {\r
     for(uint32_t morphTargetIndex = 0u; morphTargetIndex < blendShape.mNumberOfMorphTarget; ++morphTargetIndex)\r
     {\r
-      AnimatedProperty animatedProperty;\r
+      Dali::Scene3D::Loader::AnimatedProperty animatedProperty;\r
       animatedProperty.mTimePeriod = Dali::TimePeriod(animationDefinition.GetDuration());\r
-      animatedProperty.mNodeName = blendShape.mNodeName;\r
+      animatedProperty.mNodeName   = blendShape.mNodeName;\r
       std::stringstream weightPropertyStream;\r
-      weightPropertyStream << BlendShapes::WEIGHTS_UNIFORM << "[" << morphTargetIndex << "]";\r
+      weightPropertyStream << Dali::Scene3D::Loader::BlendShapes::WEIGHTS_UNIFORM << "[" << morphTargetIndex << "]";\r
       animatedProperty.mPropertyName = weightPropertyStream.str();\r
 \r
       animatedProperty.mKeyFrames = Dali::KeyFrames::New();\r
@@ -167,7 +148,40 @@ AnimationDefinition LoadFacialAnimation(const std::string& url)
 \r
   return animationDefinition;\r
 }\r
+} // unnamed namespace\r
+\r
+namespace Scene3D\r
+{\r
+namespace Loader\r
+{\r
+AnimationDefinition LoadFacialAnimation(const std::string& url)\r
+{\r
+  bool failed   = false;\r
+  auto jsonData = LoadTextFile(url.c_str(), &failed);\r
+  if(failed)\r
+  {\r
+    ExceptionFlinger(ASSERT_LOCATION) << "Failed to load " << url << ".";\r
+  }\r
+\r
+  json::unique_ptr root(json_parse(jsonData.c_str(), jsonData.size()));\r
+  if(!root)\r
+  {\r
+    ExceptionFlinger(ASSERT_LOCATION) << "Failed to parse json " << url << ".";\r
+  }\r
+\r
+  return LoadFacialAnimationInternal(root);\r
+}\r
+\r
+AnimationDefinition LoadFacialAnimationFromBuffer(const uint8_t* rawBuffer, int rawBufferLength)\r
+{\r
+  json::unique_ptr root(json_parse(rawBuffer, static_cast<size_t>(static_cast<uint32_t>(rawBufferLength))));\r
+  if(!root)\r
+  {\r
+    ExceptionFlinger(ASSERT_LOCATION) << "Failed to parse json from buffer.";\r
+  }\r
 \r
+  return LoadFacialAnimationInternal(root);\r
+}\r
 } // namespace Loader\r
 } // namespace Scene3D\r
 } // namespace Dali\r
index b61d0a0..a1658fc 100644 (file)
@@ -2,7 +2,7 @@
 #define DALI_SCENE3D_LOADER_FACIAL_ANIMATION_LOADER_H\r
 \r
 /*\r
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.\r
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.\r
  *\r
  * Licensed under the Apache License, Version 2.0 (the "License");\r
  * you may not use this file except in compliance with the License.\r
@@ -33,6 +33,18 @@ namespace Dali::Scene3D::Loader
  * @return An animation definition.\r
  */\r
 DALI_SCENE3D_API AnimationDefinition LoadFacialAnimation(const std::string& url);\r
+\r
+/**\r
+ * @brief Loads a facial animation encoded in a json file in the given data stream.\r
+ *\r
+ * Throws a DaliException on error.\r
+ *\r
+ * @param[in] rawBuffer The raw buffer containing the facial animation.\r
+ * @param[in] rawBufferLength The length of raw buffer.\r
+ *\r
+ * @return An animation definition.\r
+ */\r
+DALI_SCENE3D_API AnimationDefinition LoadFacialAnimationFromBuffer(const uint8_t* rawBuffer, int rawBufferLength);\r
 } // namespace Dali::Scene3D::Loader\r
 \r
 #endif // DALI_SCENE3D_LOADER_FACIAL_ANIMATION_LOADER_H\r