diff options
-rw-r--r-- | loader/loader.cpp | 1 | ||||
-rw-r--r-- | loader/loader.hpp | 1 | ||||
-rw-r--r-- | serialize/wall-atlas.cpp | 95 | ||||
-rw-r--r-- | serialize/wall-atlas.hpp | 10 | ||||
-rw-r--r-- | src/wall-atlas.cpp | 18 | ||||
-rw-r--r-- | src/wall-atlas.hpp | 4 |
6 files changed, 116 insertions, 13 deletions
diff --git a/loader/loader.cpp b/loader/loader.cpp index 19e07bc4..7d95da0e 100644 --- a/loader/loader.cpp +++ b/loader/loader.cpp @@ -40,5 +40,6 @@ const StringView loader_::ANIM_PATH = "anim/"_s; const StringView loader_::SCENERY_PATH = "scenery/"_s; const StringView loader_::TEMP_PATH = "../../../"_s; const StringView loader_::VOBJ_PATH = "vobj/"_s; +const StringView loader_::WALL_TILESET_PATH = "wall-tilesets/"_s; } // namespace floormat diff --git a/loader/loader.hpp b/loader/loader.hpp index f94b530e..19d93021 100644 --- a/loader/loader.hpp +++ b/loader/loader.hpp @@ -52,6 +52,7 @@ struct loader_ static const StringView SCENERY_PATH; static const StringView TEMP_PATH; static const StringView VOBJ_PATH; + static const StringView WALL_TILESET_PATH; protected: loader_(); diff --git a/serialize/wall-atlas.cpp b/serialize/wall-atlas.cpp index 5db79e05..3749be64 100644 --- a/serialize/wall-atlas.cpp +++ b/serialize/wall-atlas.cpp @@ -1,11 +1,16 @@ #include "wall-atlas.hpp" #include "magnum-vector2i.hpp" #include "magnum-vector.hpp" +#include "corrade-string.hpp" #include "compat/exception.hpp" +#include "loader/loader.hpp" #include <utility> #include <string_view> +#include <Corrade/Containers/PairStl.h> #include <Corrade/Containers/StringStl.h> #include <Corrade/Containers/StringStlView.h> +#include <Magnum/ImageView.h> +#include <Magnum/Trade/ImageData.h> #include <nlohmann/json.hpp> // todo add test on dummy files that generates 100% coverage on the j.contains() blocks! @@ -31,6 +36,27 @@ StringView direction_index_to_name(size_t i) return wall_atlas::directions[i].name; } +Array<Frame> read_all_frames(const json& jroot) +{ + fm_assert(jroot.contains("frames"sv)); + + Array<Frame> frames; + const auto& jframes = jroot["frames"sv]; + + fm_assert(jframes.is_array()); + const auto sz = jframes.size(); + frames = Array<Frame>{sz}; + + for (auto i = 0uz; i < sz; i++) + { + const auto& jframe = jframes[i]; + fm_assert(jframe.is_object()); + frames[i] = jframe; + } + + return frames; +} + Group read_group_metadata(const json& jgroup) { fm_assert(jgroup.is_object()); @@ -40,11 +66,10 @@ Group read_group_metadata(const json& jgroup) { int count = 0, index = -1; bool has_count = jgroup.contains("count"sv) && (count = jgroup["count"sv]) != 0, - has_index = jgroup.contains("offset"sv); - if (has_index) - index = jgroup["offset"sv]; + has_index = jgroup.contains("offset"sv) && (index = jgroup["offset"sv]) != -1; fm_soft_assert(has_count == has_index); fm_soft_assert(!has_index || index >= 0 && index < 1 << 20); + fm_soft_assert(count >= 0); // todo check index within range } @@ -86,6 +111,23 @@ Direction read_direction_metadata(const json& jroot, Direction_ dir) return val; } +Pair<Array<Direction>, std::array<DirArrayIndex, 4>> read_all_directions(const json& jroot) +{ + size_t count = 0; + for (auto [str, _] : wall_atlas::directions) + if (jroot.contains(str)) + count++; + Array<Direction> array{count}; + std::array<DirArrayIndex, 4> map = {}; + for (uint8_t i = 0; auto [str, dir] : wall_atlas::directions) + if (jroot.contains(str)) + { + map[(size_t)dir] = {.val = i}; + array[i++] = read_direction_metadata(jroot, dir); + } + return { std::move(array), std::move(map) }; +} + Info read_info_header(const json& jroot) { fm_soft_assert(jroot.contains(("name"sv))); @@ -97,12 +139,26 @@ Info read_info_header(const json& jroot) return val; } +void write_all_frames(json& jroot, ArrayView<const Frame> array) +{ + auto jframes = json{json::value_t::array}; + for (const Frame& frame : array) + { + json jframe = frame; + jframes.push_back(std::move(jframe)); + } + jroot["frames"sv] = std::move(jframes); +} + void write_group_metadata(json& jgroup, const Group& val) { fm_assert(jgroup.is_object()); - fm_assert(jgroup.empty()); - jgroup["offset"sv] = val.index; + if (val.index != (uint32_t)-1) + jgroup["offset"sv] = val.index; + else + jgroup["offset"sv] = -1; + jgroup["count"sv] = val.count; jgroup["pixel-size"sv] = val.pixel_size; jgroup["tint-mult"sv] = Vector4(val.tint_mult); @@ -114,8 +170,6 @@ void write_group_metadata(json& jgroup, const Group& val) void write_direction_metadata(json& jdir, const Direction& dir) { - //auto name = std::string_view{direction_index_to_name((size_t)i)}; - for (auto [s_, memfn, tag] : Direction::members) { std::string_view s = s_; @@ -138,14 +192,13 @@ void write_all_directions(json& jroot, const wall_atlas& a) { auto jdir = json{json::value_t::object}; write_direction_metadata(jdir, *dir); - jroot[name] = jdir; + jroot[name] = std::move(jdir); } } } void write_info_header(json& jroot, const Info& info) -{ - jroot["name"sv] = info.name; +{ jroot["name"sv] = info.name; if (info.description) jroot["description"sv] = info.description; jroot["depth"sv] = info.depth; @@ -153,21 +206,41 @@ void write_info_header(json& jroot, const Info& info) } // namespace floormat::Wall::detail +namespace floormat::Wall { + +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Frame, offset) +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Info, name, description, depth) + +} // namespace floormat::Wall + namespace nlohmann { using namespace floormat; +using namespace floormat::Wall; using namespace floormat::Wall::detail; +void adl_serializer<Frame>::to_json(nlohmann::json& j, const Frame& x) { using nlohmann::to_json; to_json(j, x); } +void adl_serializer<Frame>::from_json(const json& j, Frame& x) { using nlohmann::from_json; from_json(j, x); } + void adl_serializer<std::shared_ptr<wall_atlas>>::to_json(json& j, const std::shared_ptr<const wall_atlas>& x) { fm_assert(x != nullptr); write_info_header(j, x->info()); write_all_directions(j, *x); + write_all_frames(j, x->raw_frame_array()); } void adl_serializer<std::shared_ptr<wall_atlas>>::from_json(const json& j, std::shared_ptr<wall_atlas>& x) { - + auto info = read_info_header(j); + fm_assert(loader.check_atlas_name(info.name)); + auto [dirs, map] = read_all_directions(j); + Array<Frame> frames; + auto img = loader.texture(loader.WALL_TILESET_PATH, info.name); + if (j.contains("frames"sv)) + frames = read_all_frames(j); + + x = std::make_shared<wall_atlas>(std::move(info), img, std::move(frames), std::move(dirs), map); } } // namespace nlohmann diff --git a/serialize/wall-atlas.hpp b/serialize/wall-atlas.hpp index edb8b29b..7f578a5d 100644 --- a/serialize/wall-atlas.hpp +++ b/serialize/wall-atlas.hpp @@ -6,6 +6,13 @@ namespace nlohmann { template<> +struct adl_serializer<floormat::Wall::Frame> +{ + static void to_json(json& j, const floormat::Wall::Frame& x); + static void from_json(const json& j, floormat::Wall::Frame& x); +}; + +template<> struct adl_serializer<std::shared_ptr<floormat::wall_atlas>> { static void to_json(json& j, const std::shared_ptr<const floormat::wall_atlas>& x); @@ -21,10 +28,13 @@ using nlohmann::json; uint8_t direction_index_from_name(StringView s); StringView direction_index_to_name(size_t i); +[[nodiscard]] Array<Frame> read_all_frames(const json& jroot); [[nodiscard]] Group read_group_metadata(const json& jgroup); [[nodiscard]] Direction read_direction_metadata(const json& jroot, Direction_ dir); +Pair<Array<Direction>, std::array<DirArrayIndex, 4>> read_all_directions(const json& jroot); Info read_info_header(const json& jroot); +void write_all_frames(json& jframes, ArrayView<const Frame> array); void write_group_metadata(json& jgroup, const Group& val); void write_direction_metadata(json& jdir, const Direction& dir); void write_all_directions(json& jroot, const wall_atlas& a); diff --git a/src/wall-atlas.cpp b/src/wall-atlas.cpp index 96758983..402d5d66 100644 --- a/src/wall-atlas.cpp +++ b/src/wall-atlas.cpp @@ -21,6 +21,23 @@ wall_atlas::wall_atlas(Info info, const ImageView2D& image, _info{ std::move(info) }, _direction_to_Direction_array_index{ direction_to_DirArrayIndex } { + const auto frame_count = frames.size(); + for (const Direction& dir : directions) + { + for (auto [_str, _group, tag] : Direction::members) + { + const auto* g = group(dir, tag); + if (!g) + continue; + fm_assert(g->count > 0 == g->index < (uint32_t)-1); + if (g->count > 0) + { + fm_assert(g->index < frame_count); + fm_assert(g->index + g->count <= frame_count); + } + } + } + _texture.setLabel(_info.name) .setWrapping(GL::SamplerWrapping::ClampToEdge) .setMagnificationFilter(GL::SamplerFilter::Nearest) @@ -91,6 +108,7 @@ auto wall_atlas::direction(size_t dir) const -> const Direction* uint8_t wall_atlas::direction_count() const { return (uint8_t)_dir_array.size(); } auto wall_atlas::raw_frame_array() const -> ArrayView<const Frame> { return _frame_array; } auto wall_atlas::info() const -> const Info& { return _info; } +GL::Texture2D& wall_atlas::texture() { fm_debug_assert(_texture.id()); return _texture; } StringView wall_atlas::name() const { return _info.name; } size_t wall_atlas::enum_to_index(enum rotation r) diff --git a/src/wall-atlas.hpp b/src/wall-atlas.hpp index 3d97c0e7..65b15183 100644 --- a/src/wall-atlas.hpp +++ b/src/wall-atlas.hpp @@ -95,7 +95,7 @@ class wall_atlas final Array<Direction> _dir_array; Array<Frame> _frame_array; Info _info; - GL::Texture2D _texture; + GL::Texture2D _texture{NoCreate}; std::array<DirArrayIndex, 4> _direction_to_Direction_array_index; Direction* get_Direction(Direction_ num) const; @@ -104,7 +104,6 @@ public: fm_DECLARE_DELETED_MOVE_ASSIGNMENT(wall_atlas); wall_atlas() noexcept; ~wall_atlas() noexcept; - wall_atlas(Info info, const ImageView2D& image, Array<Frame> frames, Array<Direction> directions, std::array<DirArrayIndex, 4> direction_to_DirArrayIndex); @@ -118,6 +117,7 @@ public: ArrayView<const Frame> frames(const Group& a) const; ArrayView<const Frame> raw_frame_array() const; const Info& info() const; + GL::Texture2D& texture(); static size_t enum_to_index(enum rotation x); |