From 9bd4a8581836e2c4217e18e41afefbafe9d9f89b Mon Sep 17 00:00:00 2001 From: Eric Undersander Date: Fri, 13 May 2022 15:46:48 -0400 Subject: [PATCH 1/8] gfx-replay scaling fix (relevant for URDF scaling) --- src/esp/gfx/replay/Recorder.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/esp/gfx/replay/Recorder.cpp b/src/esp/gfx/replay/Recorder.cpp index 387501456a..e172d41f80 100644 --- a/src/esp/gfx/replay/Recorder.cpp +++ b/src/esp/gfx/replay/Recorder.cpp @@ -54,7 +54,18 @@ void Recorder::onCreateRenderAssetInstance( RenderAssetInstanceKey instanceKey = getNewInstanceKey(); - getKeyframe().creations.emplace_back(std::make_pair(instanceKey, creation)); + auto adjustedCreation = creation; + + // bake node scale into creation + auto nodeScale = node->absoluteTransformation().scaling(); + if (nodeScale != Mn::Vector3(1.f, 1.f, 1.f)) { + adjustedCreation.scale = adjustedCreation.scale + ? *adjustedCreation.scale * nodeScale + : nodeScale; + } + + getKeyframe().creations.emplace_back( + std::make_pair(instanceKey, adjustedCreation)); // Constructing NodeDeletionHelper here is equivalent to calling // node->addFeature. We keep a pointer to deletionHelper so we can delete it From 7ccb54082850592eef4c13abae5f77ceaba87129 Mon Sep 17 00:00:00 2001 From: Eric Undersander Date: Mon, 16 May 2022 20:35:34 -0400 Subject: [PATCH 2/8] add file-write error-checking to Recorder::writeSavedKeyframesToFile --- src/esp/gfx/replay/Recorder.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/esp/gfx/replay/Recorder.cpp b/src/esp/gfx/replay/Recorder.cpp index e172d41f80..01885f8218 100644 --- a/src/esp/gfx/replay/Recorder.cpp +++ b/src/esp/gfx/replay/Recorder.cpp @@ -5,6 +5,7 @@ #include "Recorder.h" #include "esp/assets/RenderAssetInstanceCreationInfo.h" +#include "esp/core/Check.h" #include "esp/io/Json.h" #include "esp/io/JsonAllTypes.h" #include "esp/scene/SceneNode.h" @@ -186,8 +187,9 @@ void Recorder::writeSavedKeyframesToFile(const std::string& filepath, auto document = writeKeyframesToJsonDocument(); // replay::Keyframes use floats (not doubles) so this is plenty of precision const float maxDecimalPlaces = 7; - esp::io::writeJsonToFile(document, filepath, usePrettyWriter, - maxDecimalPlaces); + auto ok = esp::io::writeJsonToFile(document, filepath, usePrettyWriter, + maxDecimalPlaces); + ESP_CHECK(ok, "writeSavedKeyframesToFile: unable to write to " << filepath); consolidateSavedKeyframes(); } From 293a90e1481753aed61fed28f61402ea1ef58928 Mon Sep 17 00:00:00 2001 From: Eric Undersander Date: Mon, 4 Apr 2022 05:55:30 -0400 Subject: [PATCH 3/8] force compile errors for missing JSON serialization functions --- src/esp/io/JsonBuiltinTypes.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/esp/io/JsonBuiltinTypes.h b/src/esp/io/JsonBuiltinTypes.h index 1b60b2e439..b2d0ebf6e2 100644 --- a/src/esp/io/JsonBuiltinTypes.h +++ b/src/esp/io/JsonBuiltinTypes.h @@ -39,6 +39,7 @@ void addMember(JsonGenericValue& value, template bool readMember(const JsonGenericValue& value, const char* name, T& x); +#if 0 // temp disable so we get compile errors /** * @brief Fallback implementation for fromJsonValue to produce a runtime error * for types that haven't implemented fromJsonValue. @@ -70,6 +71,7 @@ JsonGenericValue toJsonValue(const T&, JsonAllocator&) { << typeid(T).name() << "."; return JsonGenericValue(rapidjson::kObjectType); } +#endif // toJsonValue wrappers for the 7 rapidjson builtin types. A JsonGenericValue // can be directly constructed from the builtin types. From 713184c695ae7810f5665cf6d352ca428193e50f Mon Sep 17 00:00:00 2001 From: Eric Undersander Date: Wed, 18 May 2022 13:54:39 -0400 Subject: [PATCH 4/8] fix JSON serialize compile issues --- src/esp/io/CMakeLists.txt | 1 + src/esp/io/JsonEspTypes.cpp | 56 +++++++++++++++++++++++++++++++++++ src/esp/io/JsonEspTypes.h | 59 +++++-------------------------------- src/esp/io/JsonStlTypes.cpp | 26 ++++++++++++++++ src/esp/io/JsonStlTypes.h | 16 ++-------- 5 files changed, 92 insertions(+), 66 deletions(-) create mode 100644 src/esp/io/JsonStlTypes.cpp diff --git a/src/esp/io/CMakeLists.txt b/src/esp/io/CMakeLists.txt index 293b994c85..5b8448ed4a 100644 --- a/src/esp/io/CMakeLists.txt +++ b/src/esp/io/CMakeLists.txt @@ -10,6 +10,7 @@ add_library( JsonEspTypes.h JsonMagnumTypes.cpp JsonMagnumTypes.h + JsonStlTypes.cpp JsonStlTypes.h JsonUtils.h URDFParser.cpp diff --git a/src/esp/io/JsonEspTypes.cpp b/src/esp/io/JsonEspTypes.cpp index e887d2f670..eb79ae6945 100644 --- a/src/esp/io/JsonEspTypes.cpp +++ b/src/esp/io/JsonEspTypes.cpp @@ -101,5 +101,61 @@ bool fromJsonValue(const JsonGenericValue& obj, return true; } +JsonGenericValue toJsonValue(const esp::assets::AssetInfo& x, + JsonAllocator& allocator) { + JsonGenericValue obj(rapidjson::kObjectType); + addMemberAsUint32(obj, "type", x.type, allocator); + addMember(obj, "filepath", x.filepath, allocator); + addMember(obj, "frame", x.frame, allocator); + addMember(obj, "virtualUnitToMeters", x.virtualUnitToMeters, allocator); + addMember(obj, "forceFlatShading", x.forceFlatShading, allocator); + addMember(obj, "splitInstanceMesh", x.splitInstanceMesh, allocator); + addMember(obj, "shaderTypeToUse", x.shaderTypeToUse, allocator); + addMember(obj, "overridePhongMaterial", x.overridePhongMaterial, allocator); + addMember(obj, "hasSemanticTextures", x.hasSemanticTextures, allocator); + + return obj; +} + +bool fromJsonValue(const JsonGenericValue& obj, esp::assets::AssetInfo& x) { + readMemberAsUint32(obj, "type", x.type); + readMember(obj, "filepath", x.filepath); + readMember(obj, "frame", x.frame); + readMember(obj, "virtualUnitToMeters", x.virtualUnitToMeters); + readMember(obj, "forceFlatShading", x.forceFlatShading); + readMember(obj, "splitInstanceMesh", x.splitInstanceMesh); + readMember(obj, "shaderTypeToUse", x.shaderTypeToUse); + readMember(obj, "overridePhongMaterial", x.overridePhongMaterial); + readMember(obj, "hasSemanticTextures", x.hasSemanticTextures); + return true; +} + +JsonGenericValue toJsonValue( + const metadata::attributes::ObjectInstanceShaderType& x, + JsonAllocator& allocator) { + return toJsonValue(metadata::attributes::getShaderTypeName(x), allocator); +} + +bool fromJsonValue(const JsonGenericValue& obj, + metadata::attributes::ObjectInstanceShaderType& x) { + std::string shaderTypeToUseString; + // read as string + bool shaderTypeSucceess = fromJsonValue(obj, shaderTypeToUseString); + // convert to enum + if (shaderTypeSucceess) { + const std::string shaderTypeLC = + Cr::Utility::String::lowercase(shaderTypeToUseString); + auto mapIter = metadata::attributes::ShaderTypeNamesMap.find(shaderTypeLC); + ESP_CHECK( + mapIter != metadata::attributes::ShaderTypeNamesMap.end(), + "Illegal shader_type value" + << shaderTypeToUseString + << "specified in JSON to be used to set AssetInfo.shaderTypeToUse. " + "Aborting."); + x = mapIter->second; + } + return shaderTypeSucceess; +} + } // namespace io } // namespace esp diff --git a/src/esp/io/JsonEspTypes.h b/src/esp/io/JsonEspTypes.h index 85c202bbde..731ff6229b 100644 --- a/src/esp/io/JsonEspTypes.h +++ b/src/esp/io/JsonEspTypes.h @@ -81,62 +81,17 @@ inline bool fromJsonValue(const JsonGenericValue& obj, return success; } -inline JsonGenericValue toJsonValue(const esp::assets::AssetInfo& x, - JsonAllocator& allocator) { - JsonGenericValue obj(rapidjson::kObjectType); - addMemberAsUint32(obj, "type", x.type, allocator); - addMember(obj, "filepath", x.filepath, allocator); - addMember(obj, "frame", x.frame, allocator); - addMember(obj, "virtualUnitToMeters", x.virtualUnitToMeters, allocator); - addMember(obj, "forceFlatShading", x.forceFlatShading, allocator); - addMember(obj, "splitInstanceMesh", x.splitInstanceMesh, allocator); - addMember(obj, "shaderTypeToUse", x.shaderTypeToUse, allocator); - addMember(obj, "overridePhongMaterial", x.overridePhongMaterial, allocator); - addMember(obj, "hasSemanticTextures", x.hasSemanticTextures, allocator); +JsonGenericValue toJsonValue(const esp::assets::AssetInfo& x, + JsonAllocator& allocator); - return obj; -} +bool fromJsonValue(const JsonGenericValue& obj, esp::assets::AssetInfo& x); -inline bool fromJsonValue(const JsonGenericValue& obj, - esp::assets::AssetInfo& x) { - readMemberAsUint32(obj, "type", x.type); - readMember(obj, "filepath", x.filepath); - readMember(obj, "frame", x.frame); - readMember(obj, "virtualUnitToMeters", x.virtualUnitToMeters); - readMember(obj, "forceFlatShading", x.forceFlatShading); - readMember(obj, "splitInstanceMesh", x.splitInstanceMesh); - readMember(obj, "shaderTypeToUse", x.shaderTypeToUse); - readMember(obj, "overridePhongMaterial", x.overridePhongMaterial); - readMember(obj, "hasSemanticTextures", x.hasSemanticTextures); - return true; -} - -inline JsonGenericValue toJsonValue( +JsonGenericValue toJsonValue( const metadata::attributes::ObjectInstanceShaderType& x, - JsonAllocator& allocator) { - return toJsonValue(metadata::attributes::getShaderTypeName(x), allocator); -} + JsonAllocator& allocator); -inline bool fromJsonValue(const JsonGenericValue& obj, - metadata::attributes::ObjectInstanceShaderType& x) { - std::string shaderTypeToUseString; - // read as string - bool shaderTypeSucceess = fromJsonValue(obj, shaderTypeToUseString); - // convert to enum - if (shaderTypeSucceess) { - const std::string shaderTypeLC = - Cr::Utility::String::lowercase(shaderTypeToUseString); - auto mapIter = metadata::attributes::ShaderTypeNamesMap.find(shaderTypeLC); - ESP_CHECK( - mapIter != metadata::attributes::ShaderTypeNamesMap.end(), - "Illegal shader_type value" - << shaderTypeToUseString - << "specified in JSON to be used to set AssetInfo.shaderTypeToUse. " - "Aborting."); - x = mapIter->second; - } - return shaderTypeSucceess; -} +bool fromJsonValue(const JsonGenericValue& obj, + metadata::attributes::ObjectInstanceShaderType& x); inline JsonGenericValue toJsonValue( const esp::assets::RenderAssetInstanceCreationInfo& x, diff --git a/src/esp/io/JsonStlTypes.cpp b/src/esp/io/JsonStlTypes.cpp new file mode 100644 index 0000000000..5cd7246862 --- /dev/null +++ b/src/esp/io/JsonStlTypes.cpp @@ -0,0 +1,26 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#include "JsonAllTypes.h" + +namespace esp { +namespace io { + +JsonGenericValue toJsonValue(const std::string& str, JsonAllocator& allocator) { + JsonGenericValue strObj; + strObj.SetString(str.c_str(), allocator); + return strObj; +} + +bool fromJsonValue(const JsonGenericValue& obj, std::string& val) { + if (obj.IsString()) { + val = obj.GetString(); + return true; + } + ESP_ERROR() << "Invalid string value"; + return false; +} + +} // namespace io +} // namespace esp diff --git a/src/esp/io/JsonStlTypes.h b/src/esp/io/JsonStlTypes.h index 420d038322..ab4a104a8e 100644 --- a/src/esp/io/JsonStlTypes.h +++ b/src/esp/io/JsonStlTypes.h @@ -15,12 +15,7 @@ namespace esp { namespace io { -inline JsonGenericValue toJsonValue(const std::string& str, - JsonAllocator& allocator) { - JsonGenericValue strObj; - strObj.SetString(str.c_str(), allocator); - return strObj; -} +JsonGenericValue toJsonValue(const std::string& str, JsonAllocator& allocator); /** * @brief Populate passed @p val with value. Returns whether successfully @@ -30,14 +25,7 @@ inline JsonGenericValue toJsonValue(const std::string& str, * @param val destination value to be populated * @return whether successful or not */ -inline bool fromJsonValue(const JsonGenericValue& obj, std::string& val) { - if (obj.IsString()) { - val = obj.GetString(); - return true; - } - ESP_ERROR() << "Invalid string value"; - return false; -} +bool fromJsonValue(const JsonGenericValue& obj, std::string& val); // For std::vector, we use rapidjson::kArrayType. For an empty vector, we // omit the member altogether rather than add an empty array. From c1c356db60823ca77d103623fc4c43759553dab9 Mon Sep 17 00:00:00 2001 From: Eric Undersander Date: Wed, 18 May 2022 13:55:44 -0400 Subject: [PATCH 5/8] add python binding for gfx-replay writeSavedKeyframesToString --- src/esp/bindings/GfxReplayBindings.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/esp/bindings/GfxReplayBindings.cpp b/src/esp/bindings/GfxReplayBindings.cpp index dd3fba59bd..ede5a722c5 100644 --- a/src/esp/bindings/GfxReplayBindings.cpp +++ b/src/esp/bindings/GfxReplayBindings.cpp @@ -85,6 +85,18 @@ void initGfxReplayBindings(py::module& m) { }, R"(Write all saved keyframes to a file, then discard the keyframes.)") + .def( + "write_saved_keyframes_to_string", + [](ReplayManager& self) { + if (!self.getRecorder()) { + throw std::runtime_error( + "replay save not enabled. See " + "SimulatorConfiguration.enable_gfx_replay_save."); + } + return self.getRecorder()->writeSavedKeyframesToString(); + }, + R"(Write all saved keyframes to a string, then discard the keyframes.)") + .def("read_keyframes_from_file", &ReplayManager::readKeyframesFromFile, R"(Create a Player object from a replay file.)"); } From 50cf6e7003dae9552182d3fe748ab6b24e136bd5 Mon Sep 17 00:00:00 2001 From: Eric Undersander Date: Mon, 4 Apr 2022 05:56:32 -0400 Subject: [PATCH 6/8] add JSON serialization for std::pair --- src/esp/io/JsonStlTypes.h | 17 +++++++++++++++++ src/tests/IOTest.cpp | 6 ++++++ 2 files changed, 23 insertions(+) diff --git a/src/esp/io/JsonStlTypes.h b/src/esp/io/JsonStlTypes.h index ab4a104a8e..5861898711 100644 --- a/src/esp/io/JsonStlTypes.h +++ b/src/esp/io/JsonStlTypes.h @@ -27,6 +27,23 @@ JsonGenericValue toJsonValue(const std::string& str, JsonAllocator& allocator); */ bool fromJsonValue(const JsonGenericValue& obj, std::string& val); +template +inline JsonGenericValue toJsonValue(const std::pair& val, + JsonAllocator& allocator) { + esp::io::JsonGenericValue obj(rapidjson::kObjectType); + esp::io::addMember(obj, "first", val.first, allocator); + esp::io::addMember(obj, "second", val.second, allocator); + return obj; +} + +template +inline bool fromJsonValue(const JsonGenericValue& obj, std::pair& val) { + bool success = true; + success &= readMember(obj, "first", val.first); + success &= readMember(obj, "second", val.second); + return success; +} + // For std::vector, we use rapidjson::kArrayType. For an empty vector, we // omit the member altogether rather than add an empty array. diff --git a/src/tests/IOTest.cpp b/src/tests/IOTest.cpp index 245146cb96..dd757f2632 100644 --- a/src/tests/IOTest.cpp +++ b/src/tests/IOTest.cpp @@ -262,6 +262,12 @@ void IOTest::testJsonStlTypes() { std::string s{"hello world"}; _testJsonReadWrite(s, "s", d); + std::pair pair(1.5f, "second"); + esp::io::addMember(d, "pair", pair, allocator); + std::pair pair2; + CORRADE_VERIFY(esp::io::readMember(d, "pair", pair2)); + CORRADE_COMPARE(pair2, pair); + // test a vector of ints std::vector vec{3, 4, 5, 6}; _testJsonReadWrite(vec, "vec", d); From 9bca3d61df414bd7bd27c79be910d16ff1ee8a71 Mon Sep 17 00:00:00 2001 From: Eric Undersander Date: Wed, 18 May 2022 14:40:48 -0400 Subject: [PATCH 7/8] update comment --- src/esp/io/JsonBuiltinTypes.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/esp/io/JsonBuiltinTypes.h b/src/esp/io/JsonBuiltinTypes.h index b2d0ebf6e2..2efb178246 100644 --- a/src/esp/io/JsonBuiltinTypes.h +++ b/src/esp/io/JsonBuiltinTypes.h @@ -39,7 +39,8 @@ void addMember(JsonGenericValue& value, template bool readMember(const JsonGenericValue& value, const char* name, T& x); -#if 0 // temp disable so we get compile errors +#if 0 // reference code to produce runtime errors for missing implementations + // (instead of compile errors) /** * @brief Fallback implementation for fromJsonValue to produce a runtime error * for types that haven't implemented fromJsonValue. From cbec4b96d2ac6b79e4424a405aa979593ced39bc Mon Sep 17 00:00:00 2001 From: Eric Undersander Date: Wed, 18 May 2022 17:24:36 -0400 Subject: [PATCH 8/8] formatting fix --- src/esp/io/JsonStlTypes.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/esp/io/JsonStlTypes.h b/src/esp/io/JsonStlTypes.h index 5861898711..3bfe8c4fb9 100644 --- a/src/esp/io/JsonStlTypes.h +++ b/src/esp/io/JsonStlTypes.h @@ -37,7 +37,8 @@ inline JsonGenericValue toJsonValue(const std::pair& val, } template -inline bool fromJsonValue(const JsonGenericValue& obj, std::pair& val) { +inline bool fromJsonValue(const JsonGenericValue& obj, + std::pair& val) { bool success = true; success &= readMember(obj, "first", val.first); success &= readMember(obj, "second", val.second);