summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2023-11-27 09:59:46 +0100
committerStanislaw Halik <sthalik@misaki.pl>2023-11-27 09:59:46 +0100
commit8171d7f7cbc097c58a2097e14ce814d6a97d54bf (patch)
treec47d6e8b2dd7af82db0fa7c4cbfd19266986ec38
parent5f3d184276f6b4e13642018681cf33d2bc5b7638 (diff)
a
-rw-r--r--serialize/wall-atlas.cpp8
-rw-r--r--src/wall-atlas.cpp19
-rw-r--r--src/wall-atlas.hpp2
-rw-r--r--test/wall-atlas.cpp10
-rw-r--r--wall-tileset-tool/main.cpp145
-rw-r--r--wall-tileset-tool/main.hpp20
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;
};