summaryrefslogtreecommitdiffhomepage
path: root/serialize
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2022-10-05 15:47:29 +0200
committerStanislaw Halik <sthalik@misaki.pl>2022-10-05 15:47:29 +0200
commit6731ab0243ba437595062558e56b800d5eca9cf5 (patch)
tree39025a8ca381ff6f71cbe316c7d72b32f506a9bf /serialize
parent2c26d57dc97eb7105a6dca2089fd42847a8c2b37 (diff)
a
Diffstat (limited to 'serialize')
-rw-r--r--serialize/CMakeLists.txt5
-rw-r--r--serialize/anim.cpp36
-rw-r--r--serialize/anim.hpp47
-rw-r--r--serialize/helper.hpp62
-rw-r--r--serialize/vector.hpp41
5 files changed, 191 insertions, 0 deletions
diff --git a/serialize/CMakeLists.txt b/serialize/CMakeLists.txt
new file mode 100644
index 00000000..e695aff2
--- /dev/null
+++ b/serialize/CMakeLists.txt
@@ -0,0 +1,5 @@
+find_package(nlohmann_json QUIET REQUIRED)
+set(self "${PROJECT_NAME}-serialize")
+link_libraries(Magnum::Magnum nlohmann_json::nlohmann_json)
+file(GLOB sources "*.cpp" CONFIGURE_ARGS)
+add_library(${self} STATIC ${sources})
diff --git a/serialize/anim.cpp b/serialize/anim.cpp
new file mode 100644
index 00000000..c65c24a6
--- /dev/null
+++ b/serialize/anim.cpp
@@ -0,0 +1,36 @@
+#include "serialize/vector.hpp"
+#include "serialize/helper.hpp"
+#include "serialize/anim.hpp"
+
+#include <tuple>
+#include <filesystem>
+#include <Corrade/Utility/Debug.h>
+#include <Corrade/Utility/DebugStl.h>
+
+namespace Magnum::Examples::Serialize {
+
+#if defined __clang__ || defined __CLION_IDE__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wweak-vtables"
+# pragma clang diagnostic ignored "-Wcovered-switch-default"
+#endif
+
+NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(anim_frame, ground, offset, size)
+NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(anim_group, name, frames, ground)
+NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(anim, name, nframes, actionframe, fps, groups, width, height)
+
+#if defined __clang__ || defined __CLION_IDE__
+# pragma clang diagnostic pop
+#endif
+
+std::tuple<anim, bool> anim::from_json(const std::filesystem::path& pathname) noexcept
+{
+ return json_helper<anim>::from_json(pathname);
+}
+
+bool anim::to_json(const std::filesystem::path& pathname) const noexcept
+{
+ return json_helper<anim>::to_json(*this, pathname);
+}
+
+} // namespace Magnum::Examples::Serialize
diff --git a/serialize/anim.hpp b/serialize/anim.hpp
new file mode 100644
index 00000000..f03e3c8c
--- /dev/null
+++ b/serialize/anim.hpp
@@ -0,0 +1,47 @@
+#pragma once
+
+#include <tuple>
+#include <array>
+#include <vector>
+#include <string>
+
+#include <Magnum/Magnum.h>
+#include <Magnum/Math/Vector2.h>
+
+namespace std::filesystem { class path; }
+
+namespace Magnum::Examples::Serialize {
+
+struct anim_frame final
+{
+ Magnum::Vector2i ground, offset, size;
+};
+
+enum class anim_direction : unsigned char
+{
+ N, NE, E, SE, S, SW, W, NW,
+ COUNT,
+};
+
+struct anim_group final
+{
+ std::string name;
+ std::vector<anim_frame> frames;
+ Magnum::Vector2i ground;
+};
+
+struct anim final
+{
+ static std::tuple<anim, bool> from_json(const std::filesystem::path& pathname) noexcept;
+ [[nodiscard]] bool to_json(const std::filesystem::path& pathname) const noexcept;
+ static constexpr int default_fps = 24;
+
+ std::string name;
+ std::array<anim_group, (std::size_t)anim_direction::COUNT> groups;
+ int nframes = 0;
+ int width = 0, height = 0;
+ int actionframe = -1, fps = default_fps;
+};
+
+} // namespace Magnum::Examples::Serialize
+
diff --git a/serialize/helper.hpp b/serialize/helper.hpp
new file mode 100644
index 00000000..f16ed60c
--- /dev/null
+++ b/serialize/helper.hpp
@@ -0,0 +1,62 @@
+#pragma once
+#include <tuple>
+#include <fstream>
+#include <exception>
+#include <filesystem>
+#include <nlohmann/json.hpp>
+#include <Corrade/Utility/DebugStl.h>
+
+template<typename t>
+struct json_helper final {
+ [[nodiscard]] static std::tuple<t, bool> from_json(const std::filesystem::path& pathname) noexcept;
+ [[nodiscard]] static bool to_json(const t& self, const std::filesystem::path& pathname) noexcept;
+};
+
+template<typename t>
+std::tuple<t, bool> json_helper<t>::from_json(const std::filesystem::path& pathname) noexcept {
+ using namespace nlohmann;
+ using Corrade::Utility::Error;
+ std::ifstream s;
+ s.exceptions(s.exceptions() | std::ios::failbit | std::ios::badbit);
+ try {
+ s.open(pathname, std::ios_base::in);
+ } catch (const std::ios::failure& e) {
+ Error{Error::Flag::NoSpace} << "failed to open '" << pathname << "': " << e.what();
+ return { {}, false };
+ }
+ t ret;
+ try {
+ json j;
+ s >> j;
+ using nlohmann::from_json;
+ from_json(j, ret);
+ } catch (const std::exception& e) {
+ Error{Error::Flag::NoSpace} << "failed to parse '" << pathname << "': " << e.what();
+ return { {}, false };
+ }
+ return { std::move(ret), true };
+}
+
+template<typename t>
+bool json_helper<t>::to_json(const t& self, const std::filesystem::path& pathname) noexcept {
+ using Corrade::Utility::Error;
+ try {
+ nlohmann::json j = self;
+
+ std::ofstream s;
+ s.exceptions(s.exceptions() | std::ios::failbit | std::ios::badbit);
+ try {
+ s.open(pathname, std::ios_base::out | std::ios_base::trunc);
+ } catch (const std::ios::failure& e) {
+ Error{Error::Flag::NoSpace} << "failed to open '" << pathname << "' for writing: " << e.what();
+ return false;
+ }
+ s << j.dump(4);
+ s.flush();
+ } catch (const std::exception& e) {
+ Error{Error::Flag::NoSpace} << "failed writing to '" << pathname << "': " << e.what();
+ return false;
+ }
+
+ return true;
+}
diff --git a/serialize/vector.hpp b/serialize/vector.hpp
new file mode 100644
index 00000000..39924a9b
--- /dev/null
+++ b/serialize/vector.hpp
@@ -0,0 +1,41 @@
+#include <cstdio>
+#include <string>
+#include <exception>
+#include <Magnum/Magnum.h>
+#include <Magnum/Math/Vector2.h>
+#include <nlohmann/json.hpp>
+
+namespace nlohmann {
+
+template<typename t>
+struct adl_serializer<Magnum::Math::Vector2<t>> final {
+ static void to_json(json& j, const Magnum::Math::Vector2<t>& x);
+ static void from_json(const json& j, Magnum::Math::Vector2<t>& x);
+};
+
+template<typename t>
+void adl_serializer<Magnum::Math::Vector2<t>>::to_json(json& j, const Magnum::Math::Vector2<t>& val)
+{
+ char buf[64];
+ snprintf(buf, sizeof(buf), "%d x %d", val[0], val[1]);
+ j = buf;
+}
+
+template<typename t>
+void adl_serializer<Magnum::Math::Vector2<t>>::from_json(const json& j, Magnum::Math::Vector2<t>& val)
+{
+ std::string str = j;
+ int x = 0, y = 0, n = 0;
+ int ret = std::sscanf(str.c_str(), "%d x %d%n", &x, &y, &n);
+ if (ret != 2 || (std::size_t)n != str.size())
+ {
+ std::string msg; msg.reserve(64 + str.size());
+ msg += "failed to parse string '";
+ msg += str;
+ msg += "' as Magnum::Vector2i";
+ throw std::invalid_argument(msg);
+ }
+ val = { x, y };
+}
+
+} // namespace nlohmann