diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2023-11-23 21:58:32 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2023-11-23 21:58:32 +0100 |
commit | 98a63d0474b79e4e3197fd0c8c34bd8376408bf6 (patch) | |
tree | af865bbb33b6381026d88a457ea09e53d6818580 | |
parent | 37da838ff65b8bd70c80aede9a22b0226eb0f6de (diff) |
wip
-rw-r--r-- | serialize/wall-atlas.cpp | 23 | ||||
-rw-r--r-- | serialize/wall-atlas.hpp | 6 | ||||
-rw-r--r-- | src/wall-atlas.cpp | 44 | ||||
-rw-r--r-- | src/wall-atlas.hpp | 49 | ||||
-rw-r--r-- | test/wall-atlas.cpp | 12 | ||||
-rw-r--r-- | wall-tileset-tool/main.cpp | 72 |
6 files changed, 159 insertions, 47 deletions
diff --git a/serialize/wall-atlas.cpp b/serialize/wall-atlas.cpp index 60c2218d..28d54a0c 100644 --- a/serialize/wall-atlas.cpp +++ b/serialize/wall-atlas.cpp @@ -7,6 +7,7 @@ #include "json-helper.hpp" #include <utility> #include <string_view> +#include <Corrade/Containers/ArrayViewStl.h> #include <Corrade/Containers/PairStl.h> #include <Corrade/Containers/StringStl.h> #include <Magnum/ImageView.h> @@ -55,10 +56,11 @@ wall_atlas_def wall_atlas_def::deserialize(StringView filename) fm_soft_assert(loader.check_atlas_name(atlas.header.name)); atlas.frames = read_all_frames(jroot); auto [dirs, dir_indexes] = read_all_directions(jroot); - fm_soft_assert(!dirs.isEmpty()); + fm_soft_assert(!dirs.empty()); fm_soft_assert(dir_indexes != std::array<Wall::DirArrayIndex, 4>{}); atlas.direction_array = std::move(dirs); atlas.direction_map = dir_indexes; + atlas.direction_mask = get_existing_directions(jroot); return atlas; } @@ -113,16 +115,16 @@ StringView direction_index_to_name(size_t i) return wall_atlas::directions[i].name; } -Array<Frame> read_all_frames(const json& jroot) +std::vector<Frame> read_all_frames(const json& jroot) { fm_assert(jroot.contains("frames")); - Array<Frame> frames; + std::vector<Frame> frames; const auto& jframes = jroot["frames"]; fm_assert(jframes.is_array()); const auto sz = jframes.size(); - frames = Array<Frame>{sz}; + frames = std::vector<Frame>{sz}; for (auto i = 0uz; i < sz; i++) { @@ -199,13 +201,22 @@ Direction read_direction_metadata(const json& jroot, Direction_ dir) return val; } -Pair<Array<Direction>, std::array<DirArrayIndex, 4>> read_all_directions(const json& jroot) +[[nodiscard]] std::bitset<(size_t)Direction_::COUNT> get_existing_directions(const json& jroot) +{ + std::bitset<(size_t)Direction_::COUNT> array{0}; + for (uint8_t i = 0; auto [str, dir] : wall_atlas::directions) + if (jroot.contains(str)) + array[i] = true; + return array; +} + +Pair<std::vector<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::vector<Direction> array{count}; std::array<DirArrayIndex, 4> map = {}; for (uint8_t i = 0; auto [str, dir] : wall_atlas::directions) if (jroot.contains(str)) diff --git a/serialize/wall-atlas.hpp b/serialize/wall-atlas.hpp index b69f7e96..4e96943d 100644 --- a/serialize/wall-atlas.hpp +++ b/serialize/wall-atlas.hpp @@ -1,5 +1,6 @@ #pragma once #include "src/wall-atlas.hpp" +#include <bitset> #include <memory> #include <nlohmann/json_fwd.hpp> @@ -16,10 +17,11 @@ 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]] std::vector<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); +[[nodiscard]] std::bitset<(size_t)Direction_::COUNT> get_existing_directions(const json& jroot); +Pair<std::vector<Direction>, std::array<DirArrayIndex, 4>> read_all_directions(const json& jroot); Info read_info_header(const json& jroot); void write_all_frames(json& jroot, ArrayView<const Frame> array); diff --git a/src/wall-atlas.cpp b/src/wall-atlas.cpp index a8fe168f..a4bf9aa9 100644 --- a/src/wall-atlas.cpp +++ b/src/wall-atlas.cpp @@ -2,6 +2,7 @@ #include "compat/exception.hpp" #include "src/tile-defs.hpp" #include <utility> +#include <Corrade/Containers/ArrayViewStl.h> #include <Corrade/Containers/StridedArrayView.h> #include <Magnum/ImageView.h> #include <Magnum/GL/TextureFormat.h> @@ -11,8 +12,11 @@ namespace floormat { wall_atlas::wall_atlas() noexcept = default; wall_atlas::~wall_atlas() noexcept = default; +#if 0 void wall_atlas::validate(const wall_atlas& a, const ImageView2D& img) noexcept(false) { + // todo + const auto pixels = img.pixels(); const auto size = pixels.size(); const auto width = size[1], height = size[0]; @@ -48,13 +52,17 @@ void wall_atlas::validate(const wall_atlas& a, const ImageView2D& img) noexcept( } fm_soft_assert(got_group); } +#endif -Vector2i wall_atlas::expected_size(int depth, Tag group) +Vector2i wall_atlas::expected_size(unsigned depth, Group_ group) { static_assert(iTILE_SIZE2.x() == iTILE_SIZE2.y()); constexpr int half_tile = iTILE_SIZE2.x()/2; - CORRADE_ASSUME(group < Tag::COUNT); - using enum Tag; + + fm_assert(depth > 0 && depth < 1<<16); + CORRADE_ASSUME(group < Group_::COUNT); + + using enum Group_; switch (group) { case overlay: @@ -62,7 +70,7 @@ Vector2i wall_atlas::expected_size(int depth, Tag group) return { iTILE_SIZE.x(), iTILE_SIZE.z() }; case top: case side: - return { depth, iTILE_SIZE.z() }; + return { (int)depth, iTILE_SIZE.z() }; case corner_L: return { half_tile, iTILE_SIZE.z() }; case corner_R: @@ -93,7 +101,7 @@ auto wall_atlas::get_Direction(Direction_ num) const -> Direction* constexpr DirArrayIndex default_DAI; fm_debug_assert(num < Direction_::COUNT); - if (_dir_array.isEmpty()) [[unlikely]] + if (_dir_array.empty()) [[unlikely]] return {}; else if (auto DAI = _direction_map[(uint8_t)num]; DAI != default_DAI) [[likely]] return const_cast<Direction*>(&_dir_array[DAI.val]); @@ -103,7 +111,7 @@ auto wall_atlas::get_Direction(Direction_ num) const -> Direction* auto wall_atlas::frames(const Group& group) const -> ArrayView<const Frame> { - if (_frame_array.isEmpty()) [[unlikely]] + if (_frame_array.empty()) [[unlikely]] return {}; const auto size = _frame_array.size(); (void)size; const auto index = group.index, count = group.count; @@ -111,9 +119,12 @@ auto wall_atlas::frames(const Group& group) const -> ArrayView<const Frame> return { &_frame_array[index], count }; } -auto wall_atlas::group(size_t dir, Tag tag) const -> const Group* +auto wall_atlas::group(Direction_ d, Group_ tag) const -> const Group* { return group((size_t)d, tag); } +auto wall_atlas::group(size_t d, size_t tag) const -> const Group* { return group(d, (Group_)tag); } + +auto wall_atlas::group(size_t dir, Group_ tag) const -> const Group* { - fm_assert(tag < Tag::COUNT); + fm_assert(tag < Group_::COUNT); const auto* const set_ = direction(dir); if (!set_) return {}; @@ -126,9 +137,9 @@ auto wall_atlas::group(size_t dir, Tag tag) const -> const Group* return &ret; } -auto wall_atlas::group(const Direction& dir, Tag tag) const -> const Group* +auto wall_atlas::group(const Direction& dir, Group_ tag) const -> const Group* { - fm_assert(tag < Tag::COUNT); + fm_assert(tag < Group_::COUNT); const auto memfn = dir.groups[(size_t)tag].member; const Group& ret = dir.*memfn; if (ret.is_empty()) @@ -136,7 +147,7 @@ auto wall_atlas::group(const Direction& dir, Tag tag) const -> const Group* return &ret; } -auto wall_atlas::group(const Direction* dir, Tag tag) const -> const Group* +auto wall_atlas::group(const Direction* dir, Group_ tag) const -> const Group* { fm_debug_assert(dir != nullptr); return group(*dir, tag); @@ -173,6 +184,17 @@ bool Direction::is_empty() const noexcept return true; } +const Group& Direction::group(Group_ i) const { return const_cast<Direction&>(*this).group((size_t)i); } +const Group& Direction::group(size_t i) const { return const_cast<Direction&>(*this).group(i); } +Group& Direction::group(Group_ i) { return group((size_t)i); } + +Group& Direction::group(size_t i) +{ + fm_assert(i < (size_t)Group_::COUNT); + auto ptr = groups[i].member; + return this->*ptr; +} + bool Frame::operator==(const Frame&) const noexcept = default; bool Direction::operator==(const Direction&) const noexcept = default; bool Info::operator==(const floormat::Wall::Info&) const noexcept = default; diff --git a/src/wall-atlas.hpp b/src/wall-atlas.hpp index 1c0a920d..fcad0a8b 100644 --- a/src/wall-atlas.hpp +++ b/src/wall-atlas.hpp @@ -3,7 +3,8 @@ #include "src/rotation.hpp" #include "src/pass-mode.hpp" #include <array> -#include <Corrade/Containers/Array.h> +#include <bitset> +#include <vector> #include <Corrade/Containers/String.h> #include <Magnum/Math/Vector2.h> #include <Magnum/Math/Color.h> @@ -36,14 +37,14 @@ struct Group bool operator==(const Group&) const noexcept; }; -enum class Tag : uint8_t { wall, overlay, side, top, corner_L, corner_R, COUNT }; +enum class Group_ : uint8_t { wall, overlay, side, top, corner_L, corner_R, COUNT }; enum class Direction_ : uint8_t { N, E, S, W, COUNT }; struct Direction { using memfn_ptr = Group Direction::*; - struct member_tuple { StringView str; memfn_ptr member; Tag tag; }; + struct member_tuple { StringView str; memfn_ptr member; Group_ tag; }; explicit operator bool() const noexcept { return !is_empty(); } bool is_empty() const noexcept; @@ -52,15 +53,20 @@ struct Direction Group corner_L, corner_R; pass_mode passability = pass_mode::blocked; + const Group& group(Group_ i) const; + const Group& group(size_t i) const; + Group& group(Group_ i); + Group& group(size_t i); + static constexpr inline member_tuple groups[] = { - { "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, }, + { "wall"_s, &Direction::wall, Group_::wall }, + { "overlay"_s, &Direction::overlay, Group_::overlay }, + { "side"_s, &Direction::side, Group_::side }, + { "top"_s, &Direction::top, Group_::top }, + { "corner-L"_s, &Direction::corner_L, Group_::corner_L, }, + { "corner-R"_s, &Direction::corner_R, Group_::corner_R, }, }; - static_assert(arraySize(groups) == (size_t)Tag::COUNT); + static_assert(std::size(groups) == (size_t)Group_::COUNT); bool operator==(const Direction&) const noexcept; }; @@ -96,9 +102,10 @@ public: bool operator==(const wall_atlas_def&) const noexcept; Info header; - Array<Frame> frames; - Array<Direction> direction_array; + std::vector<Frame> frames; + std::vector<Direction> direction_array; std::array<DirArrayIndex, 4> direction_map; + std::bitset<(size_t)Wall::Direction_::COUNT> direction_mask{0}; static wall_atlas_def deserialize(StringView filename); void serialize(StringView filename) const; @@ -113,11 +120,11 @@ class wall_atlas final using Direction_ = Wall::Direction_; using Direction = Wall::Direction; using Info = Wall::Info; - using Tag = Wall::Tag; + using Group_ = Wall::Group_; using DirArrayIndex = Wall::DirArrayIndex; - Array<Direction> _dir_array; - Array<Frame> _frame_array; + std::vector<Direction> _dir_array; + std::vector<Frame> _frame_array; Info _info; String _path; GL::Texture2D _texture{NoCreate}; @@ -132,9 +139,11 @@ public: wall_atlas(wall_atlas_def def, String path, const ImageView2D& img); void serialize(StringView filename) const; - 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 Group* group(Direction_ d, Group_ tag) const; + const Group* group(size_t dir, size_t group) const; + const Group* group(size_t dir, Group_ tag) const; + const Group* group(const Direction& dir, Group_ tag) const; + const Group* group(const Direction* dir, Group_ tag) const; const Direction* direction(size_t dir) const; uint8_t direction_count() const; ArrayView<const Frame> frames(const Group& a) const; @@ -147,8 +156,8 @@ public: GL::Texture2D& texture(); static size_t enum_to_index(enum rotation x); - static void validate(const wall_atlas& a, const ImageView2D& img) noexcept(false); - static Vector2i expected_size(int depth, Tag group); + //static void validate(const wall_atlas& a, const ImageView2D& img) noexcept(false); + static Vector2i expected_size(unsigned depth, Group_ group); struct dir_tuple { diff --git a/test/wall-atlas.cpp b/test/wall-atlas.cpp index 5f0a1a2c..df17eb14 100644 --- a/test/wall-atlas.cpp +++ b/test/wall-atlas.cpp @@ -91,7 +91,7 @@ void test_read_groups(StringView filename) constexpr Frame frame_defaults; constexpr Group group_defaults; - fm_assert(!atlas.frames.isEmpty()); + fm_assert(!atlas.frames.empty()); fm_assert(atlas.frames[0].offset != frame_defaults.offset); auto dir_index = atlas.direction_map[(size_t)Direction_::W]; fm_assert(dir_index); @@ -106,12 +106,12 @@ void test_read_groups(StringView filename) void test_expected_size() { - fm_assert_equal(Vector2i{64, 192}, wall_atlas::expected_size(42, Tag::wall)); - fm_assert_equal(Vector2i{42, 192}, wall_atlas::expected_size(42, Tag::side)); - fm_assert_equal(Vector2i{32, 192}, wall_atlas::expected_size(42, Tag::corner_L)); - fm_assert_equal(Vector2i{32, 192}, wall_atlas::expected_size(42, Tag::corner_R)); + fm_assert_equal(Vector2i{64, 192}, wall_atlas::expected_size(42, Group_::wall)); + fm_assert_equal(Vector2i{42, 192}, wall_atlas::expected_size(42, Group_::side)); + fm_assert_equal(Vector2i{32, 192}, wall_atlas::expected_size(42, Group_::corner_L)); + fm_assert_equal(Vector2i{32, 192}, wall_atlas::expected_size(42, Group_::corner_R)); // swapped in atlas.json during reading and writing, rotated counter-clockwise in atlas image file - fm_assert_equal(Vector2i{42, 192}, wall_atlas::expected_size(42, Tag::top)); + fm_assert_equal(Vector2i{42, 192}, wall_atlas::expected_size(42, Group_::top)); } } // namespace diff --git a/wall-tileset-tool/main.cpp b/wall-tileset-tool/main.cpp index b61e28ae..ee513bcb 100644 --- a/wall-tileset-tool/main.cpp +++ b/wall-tileset-tool/main.cpp @@ -7,13 +7,14 @@ #include "loader/loader.hpp" #include <utility> #include <tuple> -#include <Corrade/Utility/DebugStl.h> #include <Corrade/Containers/StringView.h> #include <Corrade/Containers/String.h> #include <Corrade/Containers/TripleStl.h> #include <Corrade/Utility/Path.h> +#include <Corrade/Utility/DebugStl.h> #include <Corrade/Utility/Arguments.h> -#include <nlohmann/json.hpp> +#include <Magnum/Math/Functions.h> +//#include <nlohmann/json.hpp> #include <opencv2/core/mat.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/imgcodecs/imgcodecs.hpp> @@ -22,6 +23,7 @@ namespace floormat { using Corrade::Utility::Arguments; using namespace std::string_literals; +using namespace floormat::Wall; namespace { @@ -53,6 +55,60 @@ inline String fixsep(String str) return str; } +#if 0 +bool make_buffer(cv::Mat4b& buf, const wall_atlas& a, Direction_ dir, Group_ group) +{ + if (const auto* p = a.group(dir, group)) + { + auto size = a.expected_size(a.info().depth, group); + fm_assert(size >= Vector2i{0} && size < Vector2i{1<<16}); + if (buf.cols < size.x() || buf.rows < size.y()) + { + auto size_ = Vector2i{std::max(size.x(), buf.cols), std::max(size.y(), buf.rows)}; + buf.create(cv::Size{size_.x(), size_.y()}); + fm_debug_assert(size_ >= Vector2i{0} && size_ < Vector2i{1<<16}); + fm_debug_assert(Vector2i{buf.cols, buf.rows} >= size); + } + return true; + } + return false; +} +#endif + +Vector2i get_buffer_size(const wall_atlas_def& a) +{ + Vector2i size; + + for (auto i = 0uz; i < (size_t)Direction_::COUNT; i++) + { + auto idx = a.direction_map[i]; + if (!idx) + continue; + const auto& dir = a.direction_array[idx.val]; + for (auto j = 0uz; j < (size_t)Group_::COUNT; j++) + { + const auto& group = (dir.*(Direction::groups[j].member)); + if (group.is_empty()) + continue; + auto val = wall_atlas::expected_size(a.header.depth, (Group_)j); + size = Math::max(size, val); + } + } + + if (!(size > Vector2i{0})) + fm_abort("fatal: atlas '%s' has no defined groups", a.header.name.data()); + + return size; +} + +struct state +{ + options opts; + cv::Mat4b buffer; + const wall_atlas_def atlas; + wall_atlas_def new_atlas = atlas; +}; + Triple<options, Arguments, bool> parse_cmdline(int argc, const char* const* argv) noexcept { Corrade::Utility::Arguments args{}; @@ -75,7 +131,12 @@ Triple<options, Arguments, bool> parse_cmdline(int argc, const char* const* argv else if (Path::isDirectory(opts.input_file)) Error{Error::Flag::NoSpace} << "fatal: input file '" << opts.input_file << "' is a directory"; else + { + fm_assert(opts.output_dir); + fm_assert(opts.input_file); + fm_assert(opts.input_dir); return { std::move(opts), std::move(args), true }; + } return {}; } @@ -96,6 +157,13 @@ int main(int argc, char** argv) { argv[0] = fix_argv0(argv[0]); auto [opts, args, opts_ok] = parse_cmdline(argc, argv); + auto a = wall_atlas_def::deserialize(opts.input_file); + auto buf_size = get_buffer_size(a); + auto st = state { + .opts = std::move(opts), + .buffer = cv::Mat4b{cv::Size{buf_size.x(), buf_size.y()}}, + .atlas = std::move(a) + }; return 0; } |