Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gfx-replay and JSON serialization fixes #1758

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/esp/bindings/GfxReplayBindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.)");
}
Expand Down
19 changes: 16 additions & 3 deletions src/esp/gfx/replay/Recorder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -54,7 +55,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
Expand Down Expand Up @@ -175,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();
}
Expand Down
1 change: 1 addition & 0 deletions src/esp/io/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ add_library(
JsonEspTypes.h
JsonMagnumTypes.cpp
JsonMagnumTypes.h
JsonStlTypes.cpp
JsonStlTypes.h
JsonUtils.h
URDFParser.cpp
Expand Down
3 changes: 3 additions & 0 deletions src/esp/io/JsonBuiltinTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ void addMember(JsonGenericValue& value,
template <typename T>
bool readMember(const JsonGenericValue& value, const char* name, T& x);

#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.
Expand Down Expand Up @@ -70,6 +72,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.
Expand Down
56 changes: 56 additions & 0 deletions src/esp/io/JsonEspTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
59 changes: 7 additions & 52 deletions src/esp/io/JsonEspTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moving these implementations to the cpp to avoid compile errors

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,
Expand Down
26 changes: 26 additions & 0 deletions src/esp/io/JsonStlTypes.cpp
Original file line number Diff line number Diff line change
@@ -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
32 changes: 19 additions & 13 deletions src/esp/io/JsonStlTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -30,13 +25,24 @@ 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);

template <typename T_first, typename T_second>
inline JsonGenericValue toJsonValue(const std::pair<T_first, T_second>& 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 <typename T_first, typename T_second>
inline bool fromJsonValue(const JsonGenericValue& obj,
std::pair<T_first, T_second>& 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
Expand Down
6 changes: 6 additions & 0 deletions src/tests/IOTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,12 @@ void IOTest::testJsonStlTypes() {
std::string s{"hello world"};
_testJsonReadWrite(s, "s", d);

std::pair<float, std::string> pair(1.5f, "second");
esp::io::addMember(d, "pair", pair, allocator);
std::pair<float, std::string> pair2;
CORRADE_VERIFY(esp::io::readMember(d, "pair", pair2));
CORRADE_COMPARE(pair2, pair);

// test a vector of ints
std::vector<int> vec{3, 4, 5, 6};
_testJsonReadWrite(vec, "vec", d);
Expand Down