diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2023-11-05 21:23:07 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2023-11-05 21:23:07 +0100 |
commit | 7f82a729ae5074beafb6b4fd50d2f025dd05dfbe (patch) | |
tree | 28f2d5b968d75ff9e6f4eb6f03174d46359a0dc0 | |
parent | 0c9e57bfdc2ac5bead6c5f4984d3ae26eaeb5769 (diff) |
wip broken
-rw-r--r-- | serialize/wall-atlas.cpp | 132 | ||||
-rw-r--r-- | serialize/wall-atlas.hpp | 10 | ||||
-rw-r--r-- | src/wall-atlas.cpp | 157 | ||||
-rw-r--r-- | src/wall-atlas.hpp | 114 | ||||
-rw-r--r-- | test/wall-atlas.cpp | 22 | ||||
-rw-r--r-- | wall-tileset-tool/main.cpp | 12 |
6 files changed, 217 insertions, 230 deletions
diff --git a/serialize/wall-atlas.cpp b/serialize/wall-atlas.cpp index 31090e45..8ebe106a 100644 --- a/serialize/wall-atlas.cpp +++ b/serialize/wall-atlas.cpp @@ -9,138 +9,94 @@ // todo add test on dummy files that generates 100% coverage on the j.contains() blocks! -namespace floormat { +namespace floormat::Wall::detail { + +using nlohmann::json; +using namespace std::string_literals; namespace { -using nlohmann::json; constexpr auto none = (uint8_t)-1; -using namespace std::string_literals; -constexpr StringView rotation_names[] = { "n"_s, "e"_s, "s"_s, "w"_s, }; +constexpr StringView direction_names[] = { "n"_s, "e"_s, "s"_s, "w"_s, }; + +} // namespace -size_t rotation_from_name(StringView s) +uint8_t direction_index_from_name(StringView s) { - for (auto i = 0uz; auto n : rotation_names) - { + for (uint8_t i = 0; auto n : direction_names) if (n == s) return i; - i++; - } - fm_throw("bad rotation name '{}'"_cf, fmt::string_view{s.data(), s.size()}); -} + else + i++; -StringView rotation_to_name(size_t i) -{ - fm_soft_assert(i < std::size(rotation_names)); - return rotation_names[i]; + fm_throw("bad rotation name '{}'"_cf, fmt::string_view{s.data(), s.size()}); } -[[nodiscard]] wall_frames read_frames_metadata(const json& jfs) +StringView direction_index_to_name(size_t i) { - wall_frames val; - - if (jfs.contains("pixel-size"s)) - val.pixel_size = jfs["pixel-size"s]; - if (jfs.contains("tint"s)) - { - std::tie(val.tint_mult, val.tint_add) = std::pair<Vector4, Vector3>{ jfs["tint"s]}; - fm_soft_assert(val.tint_mult >= Color4{0}); - } - if (jfs.contains("from-rotation"s)) - val.from_rotation = (uint8_t)rotation_from_name(std::string{jfs["from-rotation"s]}); - if (jfs.contains("mirrored"s)) - val.mirrored = jfs["mirrored"s]; - if (jfs.contains("use-default-tint"s)) - val.use_default_tint = jfs["use-default-tint"s]; - - return val; + fm_soft_assert(i < arraySize(direction_names)); + return direction_names[i]; } -[[nodiscard]] wall_frame_set read_frameset_metadata(const json& j) +[[nodiscard]] Group read_group_metadata(const json& jgroup) { - return {}; -} + fm_assert(jgroup.is_object()); -void read_framesets(const json& jf, wall_atlas_def& val) -{ - fm_soft_assert(jf.is_object()); - fm_soft_assert(val.framesets == nullptr && val.frameset_count == 0); - uint8_t count = 0; + Group val; - static_assert(std::size(rotation_names) == 4); - for (auto i = 0uz; i < 4; i++) - { - const auto& r = rotation_names[i]; - auto key = std::string_view{r.data(), r.size()}; - if (jf.contains(key)) - { - fm_soft_assert(jf[key].is_object()); - auto& index = val.frameset_indexes[i]; - fm_soft_assert(index == none); - index = count++; - } - } - fm_soft_assert(count > 0); - fm_soft_assert(count == jf.size()); + if (jgroup.contains("pixel-size"s)) + val.pixel_size = jgroup["pixel-size"s]; + if (jgroup.contains("tint"s)) + std::tie(val.tint_mult, val.tint_add) = std::pair<Vector4, Vector3>{ jgroup["tint"s] }; + if (jgroup.contains("from-rotation"s)) + val.from_rotation = (uint8_t)direction_index_from_name(std::string{ jgroup["from-rotation"s] }); + if (jgroup.contains("mirrored"s)) + val.mirrored = jgroup["mirrored"s]; + if (jgroup.contains("use-default-tint"s)) + val.use_default_tint = jgroup["use-default-tint"s]; - val.framesets = std::make_unique<wall_frame_set[]>(count); - val.frameset_count = count; + fm_soft_assert(val.tint_mult >= Color4{0}); - for (auto i = 0uz; i < 4; i++) - { - auto index = val.frameset_indexes[i]; - if (index == none) - continue; - auto r = rotation_to_name(i); - auto key = std::string_view{r.data(), r.size()}; - - fm_debug_assert(index < val.frameset_count); - val.framesets[index] = read_frameset_metadata(jf[key]); - } + return val; } -void write_frameset_metadata(json& j, const wall_atlas& a, const wall_frames& val, size_t rot) +void write_group_metadata(json& jgroup, const Group& val) { - constexpr wall_frames default_value; + constexpr Group default_value; - fm_soft_assert(val.count != (uint32_t)-1); - fm_soft_assert(val.index == (uint32_t)-1 || val.index < a.frame_array().size()); - fm_soft_assert((val.index == (uint32_t)-1) == (val.count == 0)); + fm_soft_assert(jgroup.is_object()); + fm_soft_assert(jgroup.empty()); - j["name"s] = rotation_to_name(rot); - j["pixel-size"s] = val.pixel_size; + jgroup["pixel-size"s] = val.pixel_size; if (val.tint_mult != default_value.tint_mult || val.tint_add != default_value.tint_add) { auto tint = std::pair<Vector4, Vector3>{{val.tint_mult}, {val.tint_add}}; - j["tint"s] = tint; + jgroup["tint"s] = tint; } if (val.from_rotation != default_value.from_rotation) { fm_soft_assert(val.from_rotation != none && val.from_rotation < 4); - j["from-rotation"s] = val.from_rotation; + jgroup["from-rotation"s] = val.from_rotation; } if (val.mirrored != default_value.mirrored) - j["mirrored"s] = val.mirrored; + jgroup["mirrored"s] = val.mirrored; if (val.use_default_tint) if (val.tint_mult != default_value.tint_mult || val.tint_add != default_value.tint_add) - j["use-default-tint"s] = true; + jgroup["use-default-tint"s] = true; } -} // namespace - -void Serialize::wall_test::read_atlas_header(const json& j, wall_atlas_def& val) +Info read_info_header(const json& jroot) { - val = {}; - val.info = { std::string(j["name"s]), j["depth"], }; - val.frame_count = (uint32_t)j["frames"s].size(); - read_framesets(j["framesets"s], val); + Info val { std::string(jroot["name"s]), jroot["depth"] }; + return val; } -} // namespace floormat +} // namespace floormat::Wall::detail namespace nlohmann { using namespace floormat; +using namespace floormat::Wall::detail; void adl_serializer<std::shared_ptr<wall_atlas>>::to_json(json& j, const std::shared_ptr<const wall_atlas>& x) { diff --git a/serialize/wall-atlas.hpp b/serialize/wall-atlas.hpp index f8f3110b..9f1ba71c 100644 --- a/serialize/wall-atlas.hpp +++ b/serialize/wall-atlas.hpp @@ -14,8 +14,12 @@ struct adl_serializer<std::shared_ptr<floormat::wall_atlas>> } // namespace nlohmann -namespace floormat::Serialize::wall_test { +namespace floormat::Wall::detail { -void read_atlas_header(const nlohmann::json& j, wall_atlas_def& val); +uint8_t direction_index_from_name(StringView s); +StringView direction_index_to_name(size_t i); +[[nodiscard]] Group read_group_metadata(const nlohmann::json& jgroup); +void write_group_metadata(nlohmann::json& jgroup, const Group& val); +Info read_info_header(const nlohmann::json& jroot); -} // namespace floormat::Serialize::wall_test +} // namespace floormat::Wall::detail diff --git a/src/wall-atlas.cpp b/src/wall-atlas.cpp index d73510bb..24910549 100644 --- a/src/wall-atlas.cpp +++ b/src/wall-atlas.cpp @@ -1,6 +1,5 @@ #include "wall-atlas.hpp" #include "compat/assert.hpp" -#include "compat/function2.hpp" #include <utility> #include <Magnum/ImageView.h> #include <Magnum/GL/TextureFormat.h> @@ -9,103 +8,123 @@ namespace floormat { namespace { -#define FM_FRAMESET_ITER(Name) do { if (fun( #Name ## _s, const_cast<Self>(frameset.Name), wall_frame_set::type::Name)) return; } while(false) -#define FM_FRAMESET_ITER2(Str, Name) do { if (fun( Str, const_cast<Self>(frameset.Name), wall_frame_set::type::Name )) return; } while(false) - -template<typename Self> -CORRADE_ALWAYS_INLINE void visit_frameset_impl(const wall_frame_set& frameset, auto&& fun) +inline uint8_t direction_count_(std::array<uint8_t, 4> rot_to_direction) { - FM_FRAMESET_ITER(wall); - FM_FRAMESET_ITER(overlay); - FM_FRAMESET_ITER(side); - FM_FRAMESET_ITER(top); - FM_FRAMESET_ITER2("corner-L"_s, corner_L); - FM_FRAMESET_ITER2("corner-R"_s, corner_R); + uint8_t total = 0; + for (uint8_t x : rot_to_direction) + if (x != (uint8_t)-1) + total++; + return total; } -#undef FM_FRAMESET_ITER - } // namespace -size_t wall_atlas::enum_to_index(enum rotation r) -{ - static_assert(rotation_COUNT == rotation{8}); - fm_debug_assert(r < rotation_COUNT); +namespace Wall { - auto x = uint8_t(r); - x >>= 1; - return x; -} +} // namespace Wall -bool wall_frames::is_empty() const noexcept -{ - return count == 0; -} - -bool wall_frame_set::is_empty() const noexcept -{ - return !wall.is_empty() && !overlay.is_empty() && !side.is_empty() && !top.is_empty() && - !corner_L.is_empty() && !corner_R.is_empty(); -} +wall_atlas::wall_atlas() noexcept = default; +wall_atlas::~wall_atlas() noexcept = default; -wall_atlas::wall_atlas(wall_info info, const ImageView2D& image, - Array<wall_frame> frames, - std::unique_ptr<wall_frame_set[]> framesets, - uint8_t frameset_count, - std::array<uint8_t, 4> frameset_indexes) : - _framesets{std::move(framesets)}, _frame_array{std::move(frames)}, _info(std::move(info)), - _frameset_indexes{frameset_indexes}, - _frameset_count{(uint8_t)frameset_count} +wall_atlas::wall_atlas(Info info, const ImageView2D& image, + Array<Frame> frames, + Array<Direction> directions, + std::array<DirArrayIndex, 4> direction_to_DirArrayIndex) + : _dir_array{ std::move(directions) }, _frame_array{ std::move(frames) }, + _info{ std::move(info) }, + _direction_to_Direction_array_index{ direction_to_DirArrayIndex } { - { fm_assert(frameset_count <= 4); - uint8_t counts[4] = {}, total = 0; - - for (auto i = 0uz; i < frameset_count; i++) - if (frameset_indexes[i] != (uint8_t)-1) - { - fm_assert(++counts[i] == 1); - total++; - } - fm_assert(total == frameset_count); - } - _texture.setLabel(_info.name) .setWrapping(GL::SamplerWrapping::ClampToEdge) .setMagnificationFilter(GL::SamplerFilter::Nearest) .setMinificationFilter(GL::SamplerFilter::Linear) - .setMaxAnisotropy(1) + .setMaxAnisotropy(1) // todo? .setBorderColor(Color4{1, 0, 0, 1}) .setStorage(1, GL::textureFormat(image.format()), image.size()) .setSubImage(0, {}, image); } -wall_atlas::wall_atlas() = default; -wall_atlas::~wall_atlas() noexcept = default; -ArrayView<const wall_frame> wall_atlas::frame_array() const { return _frame_array; } -StringView wall_atlas::name() const { return _info.name; } -const wall_frame_set& wall_atlas::frameset(enum rotation r) const { return frameset(enum_to_index(r)); } +auto wall_atlas::get_Direction(Direction_ num) const -> Direction* +{ + fm_debug_assert(num < Direction_::COUNT); + + if (_dir_array.isEmpty()) [[unlikely]] + return {}; + if (auto idx = _direction_to_Direction_array_index[(uint8_t)num]) + return const_cast<Direction*>(&_dir_array[idx.val]); + return {}; +} + +auto wall_atlas::frames(const Group& group) const -> ArrayView<const Frame> +{ + if (_frame_array.isEmpty()) [[unlikely]] + return {}; + const auto size = _frame_array.size(); (void)size; + const auto index = group.index, count = group.count; + fm_assert(index < size && index <= index + count && index + count <= size); + return { &_frame_array[index], count }; +} -void wall_frame_set::visit(const fu2::function_view<bool(StringView name, const wall_frames& frames, type tag) const>& fun) const& +auto wall_atlas::group(size_t dir, Tag tag) const -> const Group* { - visit_frameset_impl<const wall_frames&>(*this, fun); + fm_assert(tag < Tag::COUNT); + const auto* const set_ = direction(dir); + if (!set_) + return {}; + const auto& set = *set_; + + const auto memfn = set.members[(size_t)tag].member; + const Group& ret = set.*memfn; + if (ret.is_empty()) + return {}; + return &ret; } -void wall_frame_set::visit(const fu2::function_view<bool(StringView name, wall_frames& frames, type tag) const>& fun) & +auto wall_atlas::group(const Direction& dir, Tag tag) const -> const Group* { - visit_frameset_impl<wall_frames&>(*this, fun); + fm_assert(tag < Tag::COUNT); + const auto memfn = dir.members[(size_t)tag].member; + const Group& ret = dir.*memfn; + if (ret.is_empty()) + return {}; + return &ret; } -const wall_frame_set& wall_atlas::frameset(size_t i) const +auto wall_atlas::group(const Direction* dir, Tag tag) const -> const Group* { - fm_assert(i < 4 && _frameset_indexes[i] != (uint8_t)-1); - return _framesets[i]; + fm_debug_assert(dir != nullptr); + return group(*dir, tag); } -ArrayView<const wall_frame> wall_frames::items(const wall_atlas& a) const +auto wall_atlas::direction(size_t dir) const -> const Direction* { - auto sz = a.frame_array().size(); (void)sz; - fm_assert(index < sz && index + count <= sz); - return { a.frame_array() + index, count }; + return get_Direction(Direction_(dir)); +} + +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; } +StringView wall_atlas::name() const { return _info.name; } + +size_t wall_atlas::enum_to_index(enum rotation r) +{ + static_assert(rotation_COUNT == rotation{8}); + fm_debug_assert(r < rotation_COUNT); + + auto x = uint8_t(r); + x >>= 1; + return x; } } // namespace floormat + +namespace floormat::Wall { + +bool Direction::is_empty() const noexcept +{ + for (auto [str, member, tag] : Direction::members) + if (const auto& val = this->*member; !val.is_empty()) + return false; + return true; +} + +} // namespace floormat::Wall diff --git a/src/wall-atlas.hpp b/src/wall-atlas.hpp index 544bc5b7..6a94b34f 100644 --- a/src/wall-atlas.hpp +++ b/src/wall-atlas.hpp @@ -1,93 +1,115 @@ #pragma once #include "compat/defs.hpp" -#include "compat/function2.fwd.hpp" #include "src/rotation.hpp" #include <array> -#include <memory> #include <Corrade/Containers/Array.h> #include <Corrade/Containers/String.h> #include <Magnum/Math/Vector2.h> #include <Magnum/Math/Color.h> #include <Magnum/GL/Texture.h> -namespace floormat { +namespace floormat { class wall_atlas; } -struct wall_atlas; +namespace floormat::Wall { -struct wall_frame +struct Frame { Vector2ui offset = { (unsigned)-1, (unsigned)-1 }; }; -struct wall_frames +struct Group { - bool is_empty() const noexcept; - ArrayView<const wall_frame> items(const wall_atlas& a) const; - uint32_t index = (uint32_t)-1, count = 0; - Vector2ui pixel_size; Color4 tint_mult{1,1,1,1}; Color3 tint_add; uint8_t from_rotation = (uint8_t)-1; bool mirrored : 1 = false, use_default_tint : 1 = true; + + explicit operator bool() const noexcept { return !is_empty(); } + bool is_empty() const noexcept { return count == 0; } }; -struct wall_frame_set +enum class Tag : uint8_t { wall, overlay, side, top, corner_L, corner_R, COUNT }; + +enum class Direction_ : uint8_t { N, E, S, W, COUNT }; + +struct Direction { - enum class type : uint8_t { wall = 1, overlay, side, top, corner_L, corner_R, }; + using memfn_ptr = Group Direction::*; + struct member_tuple { StringView str; memfn_ptr member; Tag tag; }; + explicit operator bool() const noexcept { return !is_empty(); } bool is_empty() const noexcept; - void visit(const fu2::function_view<bool(StringView, const wall_frames&, type) const>& fun) const&; - void visit(const fu2::function_view<bool(StringView, wall_frames&, type) const>& fun) &; - - wall_frames wall, overlay, side, top; - wall_frames corner_L, corner_R; + Group wall, overlay, side, top; + Group corner_L, corner_R; + + static constexpr inline member_tuple members[] = { + { "wall"_s, &Direction::wall, Tag::wall }, + { "overlay"_s, &Direction::overlay, Tag::overlay }, + { "side"_s, &Direction::side, Tag::side }, + { "top"_s, &Direction::top, Tag::top }, + { "corner-L"_s, &Direction::corner_L, Tag::corner_L, }, + { "corner-R"_s, &Direction::corner_R, Tag::corner_R, }, + }; + static_assert(arraySize(members) == (size_t)Tag::COUNT); }; -struct wall_info +struct Info { String name = "(unnamed)"_s; unsigned depth = 0; }; -struct wall_atlas_def -{ - wall_info info; - std::unique_ptr<wall_frame_set[]> framesets; - std::array<uint8_t, 4> frameset_indexes = {255, 255, 255, 255}; - uint8_t frameset_count = 0; - - Array<wall_frame> array; - uint32_t frame_count = 0; +struct DirArrayIndex { + std::uint8_t val = (uint8_t)-1; + operator bool() const { return val == (uint8_t)-1; } }; -struct wall_atlas final +} // namespace floormat::Wall + +namespace floormat { + +class wall_atlas final { - fm_DECLARE_DEFAULT_MOVE_ASSIGNMENT_(wall_atlas); - wall_atlas(); + using Frame = Wall::Frame; + using Group = Wall::Group; + using Direction_ = Wall::Direction_; + using Direction = Wall::Direction; + using Info = Wall::Info; + using Tag = Wall::Tag; + using DirArrayIndex = Wall::DirArrayIndex; + + Array<Direction> _dir_array; + Array<Frame> _frame_array; + Info _info; + GL::Texture2D _texture; + std::array<DirArrayIndex, 4> _direction_to_Direction_array_index; + + Direction* get_Direction(Direction_ num) const; + +public: + fm_DECLARE_DELETED_MOVE_ASSIGNMENT(wall_atlas); + wall_atlas() noexcept; ~wall_atlas() noexcept; - wall_atlas(wall_info info, const ImageView2D& image, - Array<wall_frame> frames, - std::unique_ptr<wall_frame_set[]> framesets, - uint8_t frameset_count, - std::array<uint8_t, 4> frameset_indexes); - static size_t enum_to_index(enum rotation x); - const wall_frame_set& frameset(size_t i) const; - const wall_frame_set& frameset(enum rotation r) const; - ArrayView<const wall_frame> frame_array() const; + wall_atlas(Info info, const ImageView2D& image, + Array<Frame> frames, Array<Direction> directions, + std::array<DirArrayIndex, 4> direction_to_DirArrayIndex); StringView name() const; + uint8_t direction_count() const; -private: - std::unique_ptr<wall_frame_set[]> _framesets; - Array<wall_frame> _frame_array; - wall_info _info; - GL::Texture2D _texture; - std::array<uint8_t, 4> _frameset_indexes; - uint8_t _frameset_count = 0; + const Group* group(size_t dir, Tag tag) const; + const Group* group(const Direction& dir, Tag tag) const; + const Group* group(const Direction* dir, Tag tag) const; + const Direction* direction(size_t dir) const; + ArrayView<const Frame> frames(const Group& a) const; + ArrayView<const Frame> raw_frame_array() const; + + static size_t enum_to_index(enum rotation x); }; + } // namespace floormat diff --git a/test/wall-atlas.cpp b/test/wall-atlas.cpp index 720c118f..b9ba2aec 100644 --- a/test/wall-atlas.cpp +++ b/test/wall-atlas.cpp @@ -9,13 +9,11 @@ namespace floormat { -namespace ranges = std::ranges; -namespace test = floormat::Serialize::wall_test; using nlohmann::json; namespace { -Pair<wall_atlas_def, json> test_atlas_header(StringView path, StringView filename) +[[nodiscard]] Pair<wall_atlas_def, json> test_atlas_header(StringView path, StringView filename) { auto j = json_helper::from_json_(Path::join(path, filename)); wall_atlas_def def; @@ -23,19 +21,19 @@ Pair<wall_atlas_def, json> test_atlas_header(StringView path, StringView filenam fm_assert(def.info.name == "foo"_s); fm_assert(def.info.depth == 42); - fm_assert(def.frameset_count == 2); + fm_assert(def.dir_count == 2); constexpr auto none = (uint8_t)-1; enum : uint8_t { N, E, S, W, }; - fm_assert(def.frameset_indexes[N] == 0 || def.frameset_indexes[N] == 1); - fm_assert(def.frameset_indexes[E] == none); - fm_assert(def.frameset_indexes[S] == none); + fm_assert(def.dir_indexes[N] == 0 || def.dir_indexes[N] == 1); + fm_assert(def.dir_indexes[E] == none); + fm_assert(def.dir_indexes[S] == none); - if (def.frameset_indexes[N] == 0) - fm_assert(def.frameset_indexes[W] == 1); - else if (def.frameset_indexes[N] == 1) - fm_assert(def.frameset_indexes[W] == 0); + if (def.dir_indexes[N] == 0) + fm_assert(def.dir_indexes[W] == 1); + else if (def.dir_indexes[N] == 1) + fm_assert(def.dir_indexes[W] == 0); else fm_assert(false); @@ -50,7 +48,7 @@ void test_app::test_wall_atlas() const auto path = Path::join(loader.TEMP_PATH, "test/json"_s); fm_assert(Path::isDirectory(path)); - test_atlas_header(path, "frameset-header.json"_s); + (void)test_atlas_header(path, "frame_direction-header.json"_s); } diff --git a/wall-tileset-tool/main.cpp b/wall-tileset-tool/main.cpp index 5863bdf4..eab78c16 100644 --- a/wall-tileset-tool/main.cpp +++ b/wall-tileset-tool/main.cpp @@ -23,18 +23,6 @@ using namespace std::string_literals; namespace { -wall_atlas_def read_atlas_def(const nlohmann::json& j) -{ - auto val = wall_atlas_def{}; - auto& info = val.info; - info.name = std::string(j["name"s]); - info.depth = j["depth"s]; - - fm_assert(loader.check_atlas_name(info.name)); - - return val; -} - struct options { String input_dir, input_file, output_dir; |