From 225395606938c9e98fa895a4a5fd23b575c9df77 Mon Sep 17 00:00:00 2001 From: "Eunki, Hong" Date: Tue, 18 Apr 2023 12:50:29 +0900 Subject: [PATCH] Load bvh and facial animations from buffer Let we allow to load bvh and facial animation from raw buffer stream. Change-Id: I679539ce10e631101571dab95615404c41b9b2f3 Signed-off-by: Eunki, Hong --- .../src/dali-scene3d/utc-Dali-BvhLoader.cpp | 180 +++++++++++++-------- .../src/dali-scene3d/utc-Dali-FacialAnimation.cpp | 167 ++++++++++++------- dali-scene3d/public-api/loader/bvh-loader.cpp | 79 ++++++--- dali-scene3d/public-api/loader/bvh-loader.h | 11 ++ .../public-api/loader/facial-animation-loader.cpp | 88 +++++----- .../public-api/loader/facial-animation-loader.h | 14 +- 6 files changed, 356 insertions(+), 183 deletions(-) diff --git a/automated-tests/src/dali-scene3d/utc-Dali-BvhLoader.cpp b/automated-tests/src/dali-scene3d/utc-Dali-BvhLoader.cpp index 2315bfd..d642ef4 100644 --- a/automated-tests/src/dali-scene3d/utc-Dali-BvhLoader.cpp +++ b/automated-tests/src/dali-scene3d/utc-Dali-BvhLoader.cpp @@ -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. @@ -15,85 +15,130 @@ * */ -#include #include +#include + +#include 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(std::ios::in | std::ios::binary)); + } - DALI_TEST_EQUALS(Vector2(0, 0), root.GetProperty(Actor::Property::POSITION), TEST_LOCATION); - DALI_TEST_EQUALS(Vector2(0, 0), first.GetProperty(Actor::Property::POSITION), TEST_LOCATION); - Vector3 rootWorldPositionBefore = root.GetProperty(Actor::Property::WORLD_POSITION); - Vector3 firstWorldPositionBefore = first.GetProperty(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(Actor::Property::POSITION), TEST_LOCATION); - DALI_TEST_EQUALS(Vector2(10, 0), first.GetProperty(Actor::Property::POSITION), TEST_LOCATION); + return rawString; +} +} // namespace - Vector3 rootWorldPositionAfter = root.GetProperty(Actor::Property::WORLD_POSITION); - Vector3 firstWorldPositionAfter = first.GetProperty(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(rawString.data()), static_cast(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(Actor::Property::POSITION), TEST_LOCATION); + DALI_TEST_EQUALS(Vector2(0, 0), first.GetProperty(Actor::Property::POSITION), TEST_LOCATION); + Vector3 rootWorldPositionBefore = root.GetProperty(Actor::Property::WORLD_POSITION); + Vector3 firstWorldPositionBefore = first.GetProperty(Actor::Property::WORLD_POSITION); + + animation.Play(); + + application.SendNotification(); + application.Render(1000); + + DALI_TEST_EQUALS(Vector2(0, 10), root.GetProperty(Actor::Property::POSITION), TEST_LOCATION); + DALI_TEST_EQUALS(Vector2(10, 0), first.GetProperty(Actor::Property::POSITION), TEST_LOCATION); + + Vector3 rootWorldPositionAfter = root.GetProperty(Actor::Property::WORLD_POSITION); + Vector3 firstWorldPositionAfter = first.GetProperty(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 diff --git a/automated-tests/src/dali-scene3d/utc-Dali-FacialAnimation.cpp b/automated-tests/src/dali-scene3d/utc-Dali-FacialAnimation.cpp index 100cd72..c130b2e 100644 --- a/automated-tests/src/dali-scene3d/utc-Dali-FacialAnimation.cpp +++ b/automated-tests/src/dali-scene3d/utc-Dali-FacialAnimation.cpp @@ -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. @@ -15,78 +15,125 @@ * */ -#include #include #include +#include + +#include 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(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(rawString.data()), static_cast(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; } diff --git a/dali-scene3d/public-api/loader/bvh-loader.cpp b/dali-scene3d/public-api/loader/bvh-loader.cpp index 70cb297..3930d33 100644 --- a/dali-scene3d/public-api/loader/bvh-loader.cpp +++ b/dali-scene3d/public-api/loader/bvh-loader.cpp @@ -19,6 +19,9 @@ #include // EXTERNAL INCLUDES +#include +#include + #include #include #include @@ -84,7 +87,7 @@ void trim(std::string& s) s.end()); } -void ParseHierarchy(std::ifstream& file, std::shared_ptr& joint) +void ParseHierarchy(std::istream& file, std::shared_ptr& joint) { std::string line; while(std::getline(file, line)) @@ -168,7 +171,7 @@ void MakeList(std::shared_ptr& joint, std::vector> } } -void ParseMotion(std::ifstream& file, std::shared_ptr& hierarchy, uint32_t& frameCount, float& frameTime) +void ParseMotion(std::istream& file, std::shared_ptr& hierarchy, uint32_t& frameCount, float& frameTime) { std::vector> jointList; MakeList(hierarchy, jointList); @@ -195,7 +198,7 @@ void ParseMotion(std::ifstream& file, std::shared_ptr& 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& hierarchy, uint32_ } } -bool ParseBvh(const std::string& path, uint32_t& frameCount, float& frameTime, std::shared_ptr& rootJoint) +bool ParseBvh(std::istream& file, uint32_t& frameCount, float& frameTime, std::shared_ptr& 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(frameCount - 1u) : Dali::Math::MACHINE_EPSILON_10; + float keyFrameInterval = (frameCount > 1u) ? 1.0f / static_cast(frameCount - 1u) : Dali::Math::MACHINE_EPSILON_10; std::vector> 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 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(rawBuffer), static_cast(static_cast(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 diff --git a/dali-scene3d/public-api/loader/bvh-loader.h b/dali-scene3d/public-api/loader/bvh-loader.h index 9830031..950b2ea 100644 --- a/dali-scene3d/public-api/loader/bvh-loader.h +++ b/dali-scene3d/public-api/loader/bvh-loader.h @@ -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 diff --git a/dali-scene3d/public-api/loader/facial-animation-loader.cpp b/dali-scene3d/public-api/loader/facial-animation-loader.cpp index 26afb29..36eff86 100644 --- a/dali-scene3d/public-api/loader/facial-animation-loader.cpp +++ b/dali-scene3d/public-api/loader/facial-animation-loader.cpp @@ -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. @@ -74,48 +74,29 @@ std::vector> ReadBlendShapeKeys(const json_value_s& j) const js::Reader& GetBlendShapeReader() { static const auto BLEND_SHAPE_READER = std::move(js::Reader() - .Register(*js::MakeProperty("key", ReadBlendShapeKeys, &BlendShape::mKeys)) - .Register(*new js::Property("name", js::Read::StringView, &BlendShape::mNodeName)) - .Register(*js::MakeProperty("morphtarget", js::Read::Number, &BlendShape::mNumberOfMorphTarget)) - .Register(*new js::Property("blendShapeVersion", js::Read::StringView, &BlendShape::mVersion)) - .Register(*new js::Property("fullName", js::Read::StringView, &BlendShape::mFullName)) - .Register(*js::MakeProperty("morphname", js::Read::Array, &BlendShape::mMorphNames))); + .Register(*js::MakeProperty("key", ReadBlendShapeKeys, &BlendShape::mKeys)) + .Register(*new js::Property("name", js::Read::StringView, &BlendShape::mNodeName)) + .Register(*js::MakeProperty("morphtarget", js::Read::Number, &BlendShape::mNumberOfMorphTarget)) + .Register(*new js::Property("blendShapeVersion", js::Read::StringView, &BlendShape::mVersion)) + .Register(*new js::Property("fullName", js::Read::StringView, &BlendShape::mFullName)) + .Register(*js::MakeProperty("morphname", js::Read::Array, &BlendShape::mMorphNames))); return BLEND_SHAPE_READER; } const js::Reader& GetFacialAnimationReader() { static const auto FACIAL_ANIMATION_READER = std::move(js::Reader() - .Register(*new js::Property("name", js::Read::StringView, &FacialAnimation::mName)) - .Register(*js::MakeProperty("blendShapes", js::Read::Array::Read>, &FacialAnimation::mBlendShapes)) - .Register(*new js::Property("version", js::Read::StringView, &FacialAnimation::mVersion)) - .Register(*js::MakeProperty("shapesAmount", js::Read::Number, &FacialAnimation::mNumberOfShapes)) - .Register(*js::MakeProperty("time", js::Read::Array, &FacialAnimation::mTime)) - .Register(*js::MakeProperty("frames", js::Read::Number, &FacialAnimation::mNumberOfFrames))); + .Register(*new js::Property("name", js::Read::StringView, &FacialAnimation::mName)) + .Register(*js::MakeProperty("blendShapes", js::Read::Array::Read>, &FacialAnimation::mBlendShapes)) + .Register(*new js::Property("version", js::Read::StringView, &FacialAnimation::mVersion)) + .Register(*js::MakeProperty("shapesAmount", js::Read::Number, &FacialAnimation::mNumberOfShapes)) + .Register(*js::MakeProperty("time", js::Read::Array, &FacialAnimation::mTime)) + .Register(*js::MakeProperty("frames", js::Read::Number, &FacialAnimation::mNumberOfFrames))); return FACIAL_ANIMATION_READER; } -} // unnamed namespace - -namespace Scene3D -{ -namespace Loader +Dali::Scene3D::Loader::AnimationDefinition LoadFacialAnimationInternal(json::unique_ptr& root) { -AnimationDefinition LoadFacialAnimation(const std::string& url) -{ - bool failed = false; - auto js = LoadTextFile(url.c_str(), &failed); - if(failed) - { - ExceptionFlinger(ASSERT_LOCATION) << "Failed to load " << url << "."; - } - - json::unique_ptr root(json_parse(js.c_str(), js.size())); - if(!root) - { - ExceptionFlinger(ASSERT_LOCATION) << "Failed to parse " << url << "."; - } - static bool setObjectReaders = true; if(setObjectReaders) { @@ -129,7 +110,7 @@ AnimationDefinition LoadFacialAnimation(const std::string& url) FacialAnimation facialAnimation; GetFacialAnimationReader().Read(rootObj, facialAnimation); - AnimationDefinition animationDefinition; + Dali::Scene3D::Loader::AnimationDefinition animationDefinition; animationDefinition.SetName(facialAnimation.mName.data()); animationDefinition.SetDuration(MILLISECONDS_TO_SECONDS * static_cast(facialAnimation.mTime[facialAnimation.mNumberOfFrames - 1u])); @@ -146,11 +127,11 @@ AnimationDefinition LoadFacialAnimation(const std::string& url) { for(uint32_t morphTargetIndex = 0u; morphTargetIndex < blendShape.mNumberOfMorphTarget; ++morphTargetIndex) { - AnimatedProperty animatedProperty; + Dali::Scene3D::Loader::AnimatedProperty animatedProperty; animatedProperty.mTimePeriod = Dali::TimePeriod(animationDefinition.GetDuration()); - animatedProperty.mNodeName = blendShape.mNodeName; + animatedProperty.mNodeName = blendShape.mNodeName; std::stringstream weightPropertyStream; - weightPropertyStream << BlendShapes::WEIGHTS_UNIFORM << "[" << morphTargetIndex << "]"; + weightPropertyStream << Dali::Scene3D::Loader::BlendShapes::WEIGHTS_UNIFORM << "[" << morphTargetIndex << "]"; animatedProperty.mPropertyName = weightPropertyStream.str(); animatedProperty.mKeyFrames = Dali::KeyFrames::New(); @@ -167,7 +148,40 @@ AnimationDefinition LoadFacialAnimation(const std::string& url) return animationDefinition; } +} // unnamed namespace + +namespace Scene3D +{ +namespace Loader +{ +AnimationDefinition LoadFacialAnimation(const std::string& url) +{ + bool failed = false; + auto jsonData = LoadTextFile(url.c_str(), &failed); + if(failed) + { + ExceptionFlinger(ASSERT_LOCATION) << "Failed to load " << url << "."; + } + + json::unique_ptr root(json_parse(jsonData.c_str(), jsonData.size())); + if(!root) + { + ExceptionFlinger(ASSERT_LOCATION) << "Failed to parse json " << url << "."; + } + + return LoadFacialAnimationInternal(root); +} + +AnimationDefinition LoadFacialAnimationFromBuffer(const uint8_t* rawBuffer, int rawBufferLength) +{ + json::unique_ptr root(json_parse(rawBuffer, static_cast(static_cast(rawBufferLength)))); + if(!root) + { + ExceptionFlinger(ASSERT_LOCATION) << "Failed to parse json from buffer."; + } + return LoadFacialAnimationInternal(root); +} } // namespace Loader } // namespace Scene3D } // namespace Dali diff --git a/dali-scene3d/public-api/loader/facial-animation-loader.h b/dali-scene3d/public-api/loader/facial-animation-loader.h index b61d0a0..a1658fc 100644 --- a/dali-scene3d/public-api/loader/facial-animation-loader.h +++ b/dali-scene3d/public-api/loader/facial-animation-loader.h @@ -2,7 +2,7 @@ #define DALI_SCENE3D_LOADER_FACIAL_ANIMATION_LOADER_H /* - * 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. @@ -33,6 +33,18 @@ namespace Dali::Scene3D::Loader * @return An animation definition. */ DALI_SCENE3D_API AnimationDefinition LoadFacialAnimation(const std::string& url); + +/** + * @brief Loads a facial animation encoded in a json file in the given data stream. + * + * Throws a DaliException on error. + * + * @param[in] rawBuffer The raw buffer containing the facial animation. + * @param[in] rawBufferLength The length of raw buffer. + * + * @return An animation definition. + */ +DALI_SCENE3D_API AnimationDefinition LoadFacialAnimationFromBuffer(const uint8_t* rawBuffer, int rawBufferLength); } // namespace Dali::Scene3D::Loader #endif // DALI_SCENE3D_LOADER_FACIAL_ANIMATION_LOADER_H -- 2.7.4