diff options
-rw-r--r-- | compat/assert.hpp | 16 | ||||
-rw-r--r-- | compat/prelude.hpp | 7 | ||||
-rw-r--r-- | serialize/wall-atlas.cpp | 17 | ||||
-rw-r--r-- | serialize/wall-atlas.hpp | 4 | ||||
-rw-r--r-- | src/wall-atlas.hpp | 24 | ||||
-rw-r--r-- | wall-tileset-tool/main.cpp | 143 |
6 files changed, 123 insertions, 88 deletions
diff --git a/compat/assert.hpp b/compat/assert.hpp index 73e1d376..550933fa 100644 --- a/compat/assert.hpp +++ b/compat/assert.hpp @@ -92,14 +92,14 @@ { \ if (a != b) [[unlikely]] \ { \ - DBG_nospace << Debug::color(Debug::Color::Magenta) \ - << "fatal:" \ - << Debug::resetColor << " " \ - << "Equality assertion failed at " \ - << __FILE__ << ":" << __LINE__; \ - DBG_nospace << #__VA_ARGS__; \ - DBG_nospace << " expected: " << a; \ - DBG_nospace << " actual: " << b; \ + FATAL_nospace << Debug::color(Debug::Color::Magenta) \ + << "fatal:" \ + << Debug::resetColor << " " \ + << "Equality assertion failed at " \ + << __FILE__ << ":" << __LINE__; \ + FATAL_nospace << #__VA_ARGS__; \ + FATAL_nospace << " expected: " << a; \ + FATAL_nospace << " actual: " << b; \ fm_EMIT_ABORT(); \ } \ })(__VA_ARGS__) diff --git a/compat/prelude.hpp b/compat/prelude.hpp index 443ab382..973e99d7 100644 --- a/compat/prelude.hpp +++ b/compat/prelude.hpp @@ -6,7 +6,14 @@ #include <Magnum/Magnum.h> #define DBG_nospace (::Corrade::Utility::Debug{::Corrade::Utility::Debug::Flag::NoSpace}) +#define WARNING_nospace (::Corrade::Utility::Warning{::Corrade::Utility::Debug::Flag::NoSpace}) +#define ERROR_nospace (::Corrade::Utility::Error{::Corrade::Utility::Debug::Flag::NoSpace}) +#define FATAL_nospace (::Corrade::Utility::Fatal{::Corrade::Utility::Debug::Flag::NoSpace}) + #define DBG (::Corrade::Utility::Debug{}) +#define WARNING (::Corrade::Utility::Warning{}) +#define ERROR (::Corrade::Utility::Error{}) +#define FATAL (::Corrade::Utility::Fatal{}) #if !(defined __cpp_size_t_suffix || defined _MSC_VER && _MSVC_LANG < 202004) #ifdef _MSC_VER diff --git a/serialize/wall-atlas.cpp b/serialize/wall-atlas.cpp index 28d54a0c..d2f4fa77 100644 --- a/serialize/wall-atlas.cpp +++ b/serialize/wall-atlas.cpp @@ -18,6 +18,7 @@ namespace floormat { +using namespace floormat::Wall; using namespace floormat::Wall::detail; bool wall_atlas_def::operator==(const wall_atlas_def& other) const noexcept @@ -57,7 +58,7 @@ wall_atlas_def wall_atlas_def::deserialize(StringView filename) atlas.frames = read_all_frames(jroot); auto [dirs, dir_indexes] = read_all_directions(jroot); fm_soft_assert(!dirs.empty()); - fm_soft_assert(dir_indexes != std::array<Wall::DirArrayIndex, 4>{}); + fm_soft_assert(dir_indexes != std::array<Wall::DirArrayIndex, Direction_COUNT>{}); atlas.direction_array = std::move(dirs); atlas.direction_map = dir_indexes; atlas.direction_mask = get_existing_directions(jroot); @@ -66,7 +67,8 @@ wall_atlas_def wall_atlas_def::deserialize(StringView filename) } void wall_atlas_def::serialize(StringView filename, const Info& header, ArrayView<const Frame> frames, - ArrayView<const Direction> dir_array, std::array<DirArrayIndex, 4> dir_map) + ArrayView<const Direction> dir_array, + std::array<DirArrayIndex, Direction_COUNT> dir_map) { auto jroot = json{}; @@ -201,23 +203,23 @@ Direction read_direction_metadata(const json& jroot, Direction_ dir) return val; } -[[nodiscard]] std::bitset<(size_t)Direction_::COUNT> get_existing_directions(const json& jroot) +[[nodiscard]] std::bitset<Direction_COUNT> get_existing_directions(const json& jroot) { - std::bitset<(size_t)Direction_::COUNT> array{0}; + std::bitset<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) +Pair<std::vector<Direction>, std::array<DirArrayIndex, Direction_COUNT>> read_all_directions(const json& jroot) { size_t count = 0; for (auto [str, _] : wall_atlas::directions) if (jroot.contains(str)) count++; std::vector<Direction> array{count}; - std::array<DirArrayIndex, 4> map = {}; + std::array<DirArrayIndex, Direction_COUNT> map = {}; for (uint8_t i = 0; auto [str, dir] : wall_atlas::directions) if (jroot.contains(str)) { @@ -283,7 +285,8 @@ void write_direction_metadata(json& jdir, const Direction& dir) if (jdir.contains("top")) { json& top = jdir["top"]; - top["pixel-size"] = Math::Vector<2, Int>(top["pixel-size"]).flipped(); + Vector2i vec = top["pixel-size"]; + top["pixel-size"] = vec.flipped(); } } diff --git a/serialize/wall-atlas.hpp b/serialize/wall-atlas.hpp index 4e96943d..0d1f80b2 100644 --- a/serialize/wall-atlas.hpp +++ b/serialize/wall-atlas.hpp @@ -20,8 +20,8 @@ StringView direction_index_to_name(size_t i); [[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); -[[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); +[[nodiscard]] std::bitset<Direction_COUNT> get_existing_directions(const json& jroot); +Pair<std::vector<Direction>, std::array<DirArrayIndex, Direction_COUNT>> 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.hpp b/src/wall-atlas.hpp index fcad0a8b..60e87286 100644 --- a/src/wall-atlas.hpp +++ b/src/wall-atlas.hpp @@ -90,27 +90,23 @@ struct DirArrayIndex { namespace floormat { +constexpr inline auto Direction_COUNT = (size_t)Wall::Direction_::COUNT; + struct wall_atlas_def final { -private: - using Frame = Wall::Frame; - using Direction = Wall::Direction; - using Info = Wall::Info; - using DirArrayIndex = Wall::DirArrayIndex; - -public: bool operator==(const wall_atlas_def&) const noexcept; - Info header; - 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}; + Wall::Info header; + std::vector<Wall::Frame> frames; + std::vector<Wall::Direction> direction_array; + std::array<Wall::DirArrayIndex, Direction_COUNT> direction_map; + std::bitset<Direction_COUNT> direction_mask{0}; static wall_atlas_def deserialize(StringView filename); void serialize(StringView filename) const; - static void serialize(StringView filename, const Info& header, ArrayView<const Frame> frames, - ArrayView<const Direction> dir_array, std::array<DirArrayIndex, 4> dir_map); + static void serialize(StringView filename, const Wall::Info& header, ArrayView<const Wall::Frame> frames, + ArrayView<const Wall::Direction> dir_array, + std::array<Wall::DirArrayIndex, Direction_COUNT> dir_map); }; class wall_atlas final diff --git a/wall-tileset-tool/main.cpp b/wall-tileset-tool/main.cpp index ee513bcb..f7c92772 100644 --- a/wall-tileset-tool/main.cpp +++ b/wall-tileset-tool/main.cpp @@ -1,6 +1,7 @@ #include "compat/assert.hpp" #include "compat/sysexits.hpp" #include "compat/fix-argv0.hpp" +#include "compat/strerror.hpp" #include "src/wall-atlas.hpp" #include "serialize/wall-atlas.hpp" #include "serialize/json-helper.hpp" @@ -27,59 +28,11 @@ using namespace floormat::Wall; namespace { -struct options -{ - String input_dir, input_file, output_dir; -}; - -std::shared_ptr<wall_atlas> read_from_file(StringView filename) -{ - using namespace floormat::Wall::detail; - auto def = wall_atlas_def::deserialize(filename); - - const auto jroot = json_helper::from_json_(filename); - auto header = read_info_header(jroot); - if (!loader.check_atlas_name(header.name)) - fm_abort("bad atlas name '%s'!", header.name.data()); - - return {}; -} - -inline String fixsep(String str) -{ -#ifdef _WIN32 - for (char& c : str) - if (c == '\\') - c = '/'; -#endif - 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++) + for (auto i = 0uz; i < Direction_COUNT; i++) { auto idx = a.direction_map[i]; if (!idx) @@ -101,14 +54,73 @@ Vector2i get_buffer_size(const wall_atlas_def& a) return size; } +struct options +{ + String input_dir, input_file, output_dir; +}; + struct state { - options opts; - cv::Mat4b buffer; - const wall_atlas_def atlas; - wall_atlas_def new_atlas = atlas; + options& opts; + cv::Mat4b& buffer; + const wall_atlas_def& old_atlas; + wall_atlas_def& new_atlas; + int& error; }; +bool do_direction(state& st, Direction_ i) +{ + const auto& name = wall_atlas::directions[(size_t)i].name; + DBG_nospace << " direction '" << name << "'"; + auto dir = Path::join(st.opts.input_dir, name); + if (!Path::isDirectory(dir)) + { + char errbuf[128]; + auto error = get_error_string(errbuf); + Fatal{Fatal::Flag::NoSpace} << "fatal: direction '" << name + << "' has missing directory '" << dir + << "': " << error; + return false; + } + + auto dir_count = st.old_atlas.direction_mask.count(); + st.new_atlas.direction_array = std::vector<Direction>{dir_count}; + + + return true; +} + +bool do_input_file(state& st) +{ + DBG_nospace << "input-file '" << st.old_atlas.header.name << "'"; + + fm_assert(!st.buffer.empty()); + fm_assert(loader.check_atlas_name(st.old_atlas.header.name)); + fm_assert(st.old_atlas.direction_mask.any()); + + st.new_atlas.header = std::move(const_cast<wall_atlas_def&>(st.old_atlas).header); + + for (auto i = 0uz; i < Direction_COUNT; i++) + { + if (!st.old_atlas.direction_mask[i]) + continue; + if (!do_direction(st, (Direction_)i)) + return false; + } + + return true; +} + +inline String fixsep(String str) +{ +#ifdef _WIN32 + for (char& c : str) + if (c == '\\') + c = '/'; +#endif + return str; +} + Triple<options, Arguments, bool> parse_cmdline(int argc, const char* const* argv) noexcept { Corrade::Utility::Arguments args{}; @@ -124,6 +136,9 @@ Triple<options, Arguments, bool> parse_cmdline(int argc, const char* const* argv if (opts.output_dir.isEmpty()) opts.output_dir = opts.input_dir; + DBG_nospace << "input-dir" << opts.input_dir; + DBG_nospace << "output-dir" << opts.output_dir; + if (!Path::exists(opts.input_file)) Error{Error::Flag::NoSpace} << "fatal: input file '" << opts.input_file << "' doesn't exist"; else if (!Path::isDirectory(opts.output_dir)) @@ -141,7 +156,7 @@ Triple<options, Arguments, bool> parse_cmdline(int argc, const char* const* argv return {}; } -[[nodiscard]] static int usage(const Arguments& args) noexcept +[[nodiscard]] int usage(const Arguments& args) noexcept { Error{Error::Flag::NoNewlineAtTheEnd} << args.usage(); return EX_USAGE; @@ -157,13 +172,27 @@ int main(int argc, char** argv) { argv[0] = fix_argv0(argv[0]); auto [opts, args, opts_ok] = parse_cmdline(argc, 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 new_atlas = wall_atlas_def{}; + auto error = EX_DATAERR; + auto st = state { - .opts = std::move(opts), - .buffer = cv::Mat4b{cv::Size{buf_size.x(), buf_size.y()}}, - .atlas = std::move(a) + .opts = opts, + .buffer = mat, + .old_atlas = a, + .new_atlas = new_atlas, + .error = error, }; + if (!do_input_file(st)) + { + fm_assert(error); + return error; + } return 0; } |