diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2023-11-27 09:59:46 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2023-11-27 09:59:46 +0100 |
commit | 8171d7f7cbc097c58a2097e14ce814d6a97d54bf (patch) | |
tree | c47d6e8b2dd7af82db0fa7c4cbfd19266986ec38 | |
parent | 5f3d184276f6b4e13642018681cf33d2bc5b7638 (diff) |
a
-rw-r--r-- | serialize/wall-atlas.cpp | 8 | ||||
-rw-r--r-- | src/wall-atlas.cpp | 19 | ||||
-rw-r--r-- | src/wall-atlas.hpp | 2 | ||||
-rw-r--r-- | test/wall-atlas.cpp | 10 | ||||
-rw-r--r-- | wall-tileset-tool/main.cpp | 145 | ||||
-rw-r--r-- | wall-tileset-tool/main.hpp | 20 |
6 files changed, 129 insertions, 75 deletions
diff --git a/serialize/wall-atlas.cpp b/serialize/wall-atlas.cpp index a02dd4e1..ac37e59c 100644 --- a/serialize/wall-atlas.cpp +++ b/serialize/wall-atlas.cpp @@ -237,9 +237,9 @@ Direction read_direction_metadata(const json& jroot, Direction_ dir) Direction val; - for (auto [s_, memfn, tag] : Direction::groups) + for (auto [name, memfn, tag] : Direction::groups) { - std::string_view s = {s_.data(), s_.size()}; + std::string_view s = {name.data(), name.size()}; if (!jdir.contains(s)) continue; val.*memfn = read_group_metadata(jdir[s]); @@ -301,12 +301,12 @@ void write_direction_metadata(json& jdir, const Direction& dir) { jdir["pass-mode"] = dir.passability; - for (auto [s_, memfn, tag] : Direction::groups) + for (auto [name, memfn, tag] : Direction::groups) { const auto& group = dir.*memfn; if (!group.is_defined) continue; - std::string_view s = {s_.data(), s_.size()}; + std::string_view s = {name.data(), name.size()}; write_group_metadata(jdir[s], group); } if (jdir.contains("top")) diff --git a/src/wall-atlas.cpp b/src/wall-atlas.cpp index 721b7906..c8006b1b 100644 --- a/src/wall-atlas.cpp +++ b/src/wall-atlas.cpp @@ -54,27 +54,28 @@ void wall_atlas::validate(const wall_atlas& a, const ImageView2D& img) noexcept( } #endif -Vector2i wall_atlas::expected_size(unsigned depth, Group_ group) +Vector2ui wall_atlas::expected_size(unsigned depth, Group_ group) { - static_assert(iTILE_SIZE2.x() == iTILE_SIZE2.y()); - constexpr int half_tile = iTILE_SIZE2.x()/2; + constexpr auto size = Vector3ui{iTILE_SIZE}; + constexpr auto half_tile = size.x()/2u; + static_assert(size.x() == size.y()); - fm_assert(depth > 0 && depth < 1<<16); + fm_assert(depth > 0 && depth < 1<<15); CORRADE_ASSUME(group < Group_::COUNT); - using enum Group_; switch (group) { + using enum Group_; case overlay: case wall: - return { iTILE_SIZE.x(), iTILE_SIZE.z() }; + return { size.x(), size.z() }; case top: case side: - return { (int)depth, iTILE_SIZE.z() }; + return { depth, size.z() }; case corner_L: - return { half_tile, iTILE_SIZE.z() }; + return { half_tile, size.z() }; case corner_R: - return { iTILE_SIZE2.x() - half_tile, iTILE_SIZE.z() }; + return { size.x() - half_tile, size.z() }; default: fm_assert(false); } diff --git a/src/wall-atlas.hpp b/src/wall-atlas.hpp index 333dd47c..4832047e 100644 --- a/src/wall-atlas.hpp +++ b/src/wall-atlas.hpp @@ -149,7 +149,7 @@ public: 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(unsigned depth, Group_ group); + static Vector2ui expected_size(unsigned depth, Group_ group); struct dir_tuple { diff --git a/test/wall-atlas.cpp b/test/wall-atlas.cpp index 3fa78fc0..2683c1dc 100644 --- a/test/wall-atlas.cpp +++ b/test/wall-atlas.cpp @@ -107,12 +107,12 @@ void test_read_groups(StringView filename) void test_expected_size() { - 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)); + fm_assert_equal(Vector2ui{64, 192}, wall_atlas::expected_size(42, Group_::wall)); + fm_assert_equal(Vector2ui{42, 192}, wall_atlas::expected_size(42, Group_::side)); + fm_assert_equal(Vector2ui{32, 192}, wall_atlas::expected_size(42, Group_::corner_L)); + fm_assert_equal(Vector2ui{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, Group_::top)); + fm_assert_equal(Vector2ui{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 36493c47..4736157a 100644 --- a/wall-tileset-tool/main.cpp +++ b/wall-tileset-tool/main.cpp @@ -9,6 +9,7 @@ //#include "serialize/json-helper.hpp" #include "loader/loader.hpp" #include <utility> +#include <tuple> #include <Corrade/Containers/StringView.h> #include <Corrade/Containers/String.h> #include <Corrade/Containers/StringIterable.h> @@ -29,32 +30,6 @@ using namespace floormat::Wall; namespace { -Vector2i get_buffer_size(const wall_atlas_def& a) -{ - Vector2i size; - - for (auto i = 0uz; i < 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_defined) - 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; -} - const Direction& get_direction(const wall_atlas_def& atlas, size_t i) { fm_assert(atlas.direction_mask[i]); @@ -80,35 +55,116 @@ auto asformat(Fmt&& fmt, Xs&&... args) return ret; } -bool do_group(state st, size_t i, size_t j, Group& new_dir) +struct resolution : Vector2i { using Vector2i::Vector2i; }; + +Debug& operator<<(Debug& dbg, resolution res) +{ + return dbg << res.x() << colon('x') << res.y() << colon(','); +} + +constexpr inline int max_image_dimension = 4096; + +bool convert_to_bgra32(const cv::Mat& src, cv::Mat4b& dest) +{ + fm_assert(dest.empty() || dest.size == src.size); + auto ch = src.channels(), tp = src.type(); + + switch (auto type = src.type()) + { + default: + return false; + case CV_8U: + cv::cvtColor(src, dest, cv::COLOR_GRAY2BGRA); + return true; + case CV_8UC3: + cv::cvtColor(src, dest, cv::COLOR_BGR2BGRA); + return true; + case CV_8UC4: + src.copyTo(dest); + return true; + } +} + +bool do_group(state st, size_t i, size_t j, Group& new_group) { + const auto group_name = Direction::groups[j].name; const wall_atlas_def& old_atlas = st.old_atlas; wall_atlas_def& new_atlas = st.new_atlas; const auto& old_dir = get_direction(old_atlas, (size_t)i); + const auto& old_group = old_dir.group(j); //auto& new_dir = get_direction(new_atlas, (size_t)i); - const auto group_name = Direction::groups[j].name; const auto dir_name = wall_atlas::directions[i].name; + std::vector<frame> frames; frames.reserve(64); - DBG << " group" << quoted2(group_name); - size_t fileno = 1; const auto path = Path::join({ st.opts.input_dir, dir_name, group_name }); + const auto expected_size = wall_atlas::expected_size(new_atlas.header.depth, (Group_)j); - for (;;) + DBG << " group" << quoted2(group_name); + fm_debug_assert(expected_size > Vector2ui{0}); + fm_assert(Math::max(expected_size.x(), expected_size.y()) < max_image_dimension); + + uint32_t count = 0, start = (uint32_t)st.frames.size(); + new_group = old_group; + new_group.is_defined = true; + new_group.pixel_size = Vector2ui(expected_size); + + if (old_group.from_rotation == (uint8_t)-1) { - auto filename = asformat("{}/{:04}.png"_cf, path, fileno++); - auto str = StringView{filename.data(), filename.size(), StringViewFlag::NullTerminated}; - Debug{} << str; - if (!Path::exists(filename)) + for (;;) { - Debug{} << "end"; - break; + auto filename = asformat("{}/{:04}.png"_cf, path, count+1); + if (!Path::exists(filename)) + break; + count++; + if (Path::isDirectory(filename)) [[unlikely]] + { + ERR << "fatal: path" << quoted(filename) << "is a directory!"; + return false; + } + + cv::Mat mat = cv::imread(cv::String{filename.data(), filename.size()}), mat2; + if ((Group_)j == Group_::top) + { + cv::rotate(mat, mat2, cv::ROTATE_90_COUNTERCLOCKWISE); + using std::swap; + swap(mat, mat2); + } + + if (Vector2ui((unsigned)mat.cols, (unsigned)mat.rows) != expected_size) [[unlikely]] + { + ERR << "fatal: wrong image size, expected size" + << resolution{expected_size} << colon(',') + << "actual size" << resolution{} + << "-- file" << filename; + return false; + } + + cv::Mat4b buf; + if (!convert_to_bgra32(mat, buf)) [[unlikely]] + { + ERR << "fatal: unknown image pixel format:" + << "channels" << mat.channels() << colon(',') + << "depth" << cv::depthToString(mat.depth()) << colon(',') + << "type" << cv::typeToString(mat.type()) << colon(',') + << "for" << quoted(filename); + return false; + } } - if (Path::isDirectory(filename)) + + if (count == 0) { - ERR << "fatal: file" << quoted(filename) << "is a directory"; + ERR << "fatal: no files found for" << quoted2(dir_name) << "/" << quoted2(group_name); return false; } - cv::Mat mat = cv::imread(cv::String{filename.data(), filename.size()}); + + fm_assert(start + count == st.frames.size()); + new_group.count = count; + new_group.index = start; + } + else + { + new_group.count = 0; + new_group.index = (uint32_t)-1; } return true; @@ -249,17 +305,16 @@ int main(int argc, char** argv) if (!opts_ok) return usage(args); - auto a = wall_atlas_def::deserialize(opts.input_file); - auto buf_size = get_buffer_size(a); - auto mat = cv::Mat4b{cv::Size{buf_size.x(), buf_size.y()}}; + auto old_atlas = wall_atlas_def::deserialize(opts.input_file); auto new_atlas = wall_atlas_def{}; + auto frames = std::vector<frame>{}; frames.reserve(64); auto error = EX_DATAERR; auto st = state { .opts = opts, - .buffer = mat, - .old_atlas = a, + .old_atlas = old_atlas, .new_atlas = new_atlas, + .frames = frames, .error = error, }; if (!do_input_file(st)) diff --git a/wall-tileset-tool/main.hpp b/wall-tileset-tool/main.hpp index d6403ccf..2dbf25df 100644 --- a/wall-tileset-tool/main.hpp +++ b/wall-tileset-tool/main.hpp @@ -1,15 +1,7 @@ #pragma once #include "src/wall-atlas.hpp" - -namespace cv { -template<typename T> class Mat_; -template<typename T, int cn> class Vec; -typedef Vec<unsigned char, 3> Vec3b; -typedef Vec<unsigned char, 4> Vec4b; -typedef Mat_<unsigned char> Mat1b; -typedef Mat_<Vec3b> Mat3b; -typedef Mat_<Vec4b> Mat4b; -} // namespace cv +#include <vector> +#include <opencv2/core/mat.hpp> namespace floormat::wall_tool { @@ -18,12 +10,18 @@ struct options String input_dir, input_file, output_dir; }; +struct frame +{ + Vector2ui size; + cv::Mat4b mat; +}; + struct state { options& opts; - cv::Mat4b& buffer; const wall_atlas_def& old_atlas; wall_atlas_def& new_atlas; + std::vector<frame>& frames; int& error; }; |