summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2023-11-23 21:58:32 +0100
committerStanislaw Halik <sthalik@misaki.pl>2023-11-23 21:58:32 +0100
commit98a63d0474b79e4e3197fd0c8c34bd8376408bf6 (patch)
treeaf865bbb33b6381026d88a457ea09e53d6818580
parent37da838ff65b8bd70c80aede9a22b0226eb0f6de (diff)
wip
-rw-r--r--serialize/wall-atlas.cpp23
-rw-r--r--serialize/wall-atlas.hpp6
-rw-r--r--src/wall-atlas.cpp44
-rw-r--r--src/wall-atlas.hpp49
-rw-r--r--test/wall-atlas.cpp12
-rw-r--r--wall-tileset-tool/main.cpp72
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;
}