summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2023-12-23 11:57:25 +0100
committerStanislaw Halik <sthalik@misaki.pl>2023-12-23 11:57:25 +0100
commita737d0cea5ca8bdcd3f9cfc38e29f8a15992ca3e (patch)
treea9eff1385f0b891dc7298477768444a1ce1113fc
parent14cf3a6c5acb51a953ca193289e3eb112542e9ac (diff)
a
-rw-r--r--loader/loader.hpp2
-rw-r--r--loader/wall-atlas.cpp2
-rw-r--r--serialize/wall-atlas.cpp23
-rw-r--r--serialize/wall-atlas.hpp3
-rw-r--r--src/wall-atlas.cpp55
-rw-r--r--src/wall-atlas.hpp8
-rw-r--r--test/json/wall-atlas-02_groups.json9
-rw-r--r--test/wall-atlas.cpp27
8 files changed, 102 insertions, 27 deletions
diff --git a/loader/loader.hpp b/loader/loader.hpp
index 02c5dc67..08881ee7 100644
--- a/loader/loader.hpp
+++ b/loader/loader.hpp
@@ -33,7 +33,7 @@ struct loader_
virtual std::shared_ptr<class tile_atlas> tile_atlas(StringView filename) noexcept(false) = 0;
virtual ArrayView<const String> anim_atlas_list() = 0;
virtual std::shared_ptr<class anim_atlas> anim_atlas(StringView name, StringView dir = ANIM_PATH) noexcept(false) = 0;
- virtual std::shared_ptr<class wall_atlas> wall_atlas(StringView name, bool fail_ok = true) = 0;
+ virtual std::shared_ptr<class wall_atlas> wall_atlas(StringView name, bool fail_ok = true) noexcept(false) = 0;
virtual ArrayView<const wall_info> wall_atlas_list() = 0;
static void destroy();
static loader_& default_loader() noexcept;
diff --git a/loader/wall-atlas.cpp b/loader/wall-atlas.cpp
index 502cfd0c..5b7766a5 100644
--- a/loader/wall-atlas.cpp
+++ b/loader/wall-atlas.cpp
@@ -73,7 +73,7 @@ const wall_info& loader_impl::make_invalid_wall_atlas()
return *invalid_wall_atlas;
}
-std::shared_ptr<class wall_atlas> loader_impl::wall_atlas(StringView name, bool fail_ok)
+std::shared_ptr<class wall_atlas> loader_impl::wall_atlas(StringView name, bool fail_ok) noexcept(false)
{
fm_soft_assert(check_atlas_name(name));
char buf[FILENAME_MAX];
diff --git a/serialize/wall-atlas.cpp b/serialize/wall-atlas.cpp
index 70826e27..ca37a13a 100644
--- a/serialize/wall-atlas.cpp
+++ b/serialize/wall-atlas.cpp
@@ -138,23 +138,6 @@ void wall_atlas::serialize(StringView filename) const
namespace floormat::Wall::detail {
-uint8_t direction_index_from_name(StringView s)
-{
- for (uint8_t i = 0; auto [n, _] : wall_atlas::directions)
- if (n == s)
- return i;
- else
- i++;
-
- fm_throw("bad rotation name '{}'"_cf, s);
-}
-
-StringView direction_index_to_name(size_t i)
-{
- fm_soft_assert(i < arraySize(wall_atlas::directions));
- return wall_atlas::directions[i].name;
-}
-
std::vector<Frame> read_all_frames(const json& jroot)
{
if (!jroot.contains("frames"))
@@ -224,6 +207,8 @@ Group read_group_metadata(const json& jgroup)
val.pixel_size = jgroup["pixel-size"];
if (jgroup.contains("mirrored"))
val.mirrored = !!jgroup["mirrored"];
+ if (jgroup.contains("from-rotation") && !jgroup["from-rotation"].is_null())
+ val.from_rotation = direction_index_from_name(jgroup["from-rotation"]);
val.is_defined = true;
return val;
@@ -278,8 +263,6 @@ void write_all_frames(json& jroot, ArrayView<const Frame> array)
void write_group_metadata(json& jgroup, const Group& val)
{
- constexpr Group group_defaults;
-
fm_assert(jgroup.is_null());
fm_assert(val.is_defined);
@@ -296,6 +279,8 @@ void write_group_metadata(json& jgroup, const Group& val)
jgroup["tint-add"] = val.tint_add;
}
jgroup["mirrored"] = val.mirrored;
+ if (val.from_rotation != (uint8_t )-1)
+ jgroup["from-rotation"] = direction_index_to_name(val.from_rotation);
}
void write_direction_metadata(json& jdir, const Direction& dir)
diff --git a/serialize/wall-atlas.hpp b/serialize/wall-atlas.hpp
index 725204ad..febdf583 100644
--- a/serialize/wall-atlas.hpp
+++ b/serialize/wall-atlas.hpp
@@ -14,9 +14,6 @@ namespace floormat::Wall::detail {
using nlohmann::json;
-uint8_t direction_index_from_name(StringView s);
-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);
diff --git a/src/wall-atlas.cpp b/src/wall-atlas.cpp
index 2486eafd..90d5dfe7 100644
--- a/src/wall-atlas.cpp
+++ b/src/wall-atlas.cpp
@@ -7,6 +7,57 @@
#include <Magnum/ImageView.h>
#include <Magnum/GL/TextureFormat.h>
+namespace floormat::Wall {
+
+uint8_t direction_index_from_name(StringView s) noexcept(false)
+{
+ for (uint8_t i = 0; auto [n, _] : wall_atlas::directions)
+ if (n == s)
+ return i;
+ else
+ i++;
+
+ fm_throw("bad rotation name '{}'"_cf, s);
+}
+
+StringView direction_index_to_name(size_t i) noexcept(false)
+{
+ fm_soft_assert(i < arraySize(wall_atlas::directions));
+ return wall_atlas::directions[i].name;
+}
+
+void resolve_wall_rotations(std::vector<Wall::Direction>& array, const std::array<DirArrayIndex, Direction_COUNT>& map) noexcept(false)
+{
+ for (auto [dir_name, dir] : wall_atlas::directions)
+ {
+ auto DAI = map[(size_t)dir];
+ if (!DAI)
+ continue;
+ auto& D = array[DAI.val];
+ for (auto [group_name, ptr, gr] : Direction::groups)
+ {
+ auto& G = D.*ptr;
+ if (!G.is_defined)
+ continue;
+ if (G.from_rotation != (uint8_t)-1)
+ {
+ const auto& DAI2 = map[G.from_rotation];
+ if (!DAI2)
+ fm_throw("from_rotation for '{}/{}' points to nonexistent rotation {}"_cf,
+ dir_name, group_name, direction_index_to_name(G.from_rotation));
+ const auto& D2 = array[DAI2.val];
+ const auto& G2 = D2.*ptr;
+ if (!G2.is_defined)
+ fm_throw("from_rotation for '{}/{}' points to empty group '{}/{}'"_cf,
+ dir_name, group_name, direction_index_to_name(G.from_rotation), group_name);
+ G.from_rotation = DAI2.val;
+ }
+ }
+ }
+}
+
+} // namespace floormat::Wall
+
namespace floormat {
using namespace floormat::Wall;
@@ -74,7 +125,7 @@ wall_atlas::wall_atlas(wall_atlas_def def, String path, const ImageView2D& img)
for (auto [group_name, gmemb, gr] : Direction::groups)
{
const auto& G = D->*gmemb;
- fm_soft_assert(!G.is_defined == !G.count);
+ fm_soft_assert(G.is_defined == !!G.count);
fm_soft_assert(G.is_defined == (G.index != (uint32_t)-1));
if (!G.is_defined)
continue;
@@ -92,6 +143,8 @@ wall_atlas::wall_atlas(wall_atlas_def def, String path, const ImageView2D& img)
fm_throw("wall_atlas '{}' is empty!"_cf, _path);
}
+ resolve_wall_rotations(_dir_array, _direction_map);
+
_texture.setLabel(_path)
.setWrapping(GL::SamplerWrapping::ClampToEdge)
.setMagnificationFilter(GL::SamplerFilter::Nearest)
diff --git a/src/wall-atlas.hpp b/src/wall-atlas.hpp
index fa3006fc..1f18489a 100644
--- a/src/wall-atlas.hpp
+++ b/src/wall-atlas.hpp
@@ -15,6 +15,9 @@ namespace floormat { class wall_atlas; }
namespace floormat::Wall {
+uint8_t direction_index_from_name(StringView s) noexcept(false);
+StringView direction_index_to_name(size_t i) noexcept(false);
+
struct Frame
{
Vector2ui offset = { (unsigned)-1, (unsigned)-1 }, size;
@@ -28,6 +31,7 @@ struct Group
Vector2ui pixel_size;
Color4 tint_mult{1,1,1,1};
Color3 tint_add{};
+ uint8_t from_rotation = (uint8_t)-1;
bool mirrored : 1 = false,
default_tint : 1 = true,
is_defined : 1 = false;
@@ -73,11 +77,13 @@ struct Info
struct DirArrayIndex {
uint8_t val = (uint8_t)-1;
- operator bool() const { return val != (uint8_t)-1; }
+ explicit operator bool() const { return val != (uint8_t)-1; }
bool operator==(const DirArrayIndex&) const noexcept;
};
+void resolve_wall_rotations(std::vector<Wall::Direction>& dirs, const std::array<DirArrayIndex, Direction_COUNT>& map) noexcept(false);
+
} // namespace floormat::Wall
namespace floormat {
diff --git a/test/json/wall-atlas-02_groups.json b/test/json/wall-atlas-02_groups.json
index c9617d4f..b2d44fc5 100644
--- a/test/json/wall-atlas-02_groups.json
+++ b/test/json/wall-atlas-02_groups.json
@@ -22,6 +22,13 @@
"wall": {
"offset": 0,
"count": 1
+ },
+ "corner-L": {
+ "offset": 0,
+ "count": 11
+ },
+ "top": {
+ "from-rotation": "w"
}
},
"w": {
@@ -40,7 +47,7 @@
"top": {
"pixel-size": "192 x 42",
"offset": 1,
- "count": 2
+ "count": 12
},
"corner-L": { "from-rotation": "n" }
}
diff --git a/test/wall-atlas.cpp b/test/wall-atlas.cpp
index 33b5d1fe..d6b0f564 100644
--- a/test/wall-atlas.cpp
+++ b/test/wall-atlas.cpp
@@ -74,6 +74,31 @@ void test_read_groups(StringView filename)
fm_assert(dir == dir2);
}
+void test_from_rotation(StringView filename)
+{
+ const auto path = Path::join(json_path(), filename);
+ auto atlas = wall_atlas_def::deserialize(path);
+ auto DAI_n = atlas.direction_map[(size_t)Direction_::N];
+ auto DAI_w = atlas.direction_map[(size_t)Direction_::W];
+ fm_assert(DAI_n); fm_assert(DAI_w);
+ const auto& D_n = atlas.direction_array[DAI_n.val];
+ const auto& D_w = atlas.direction_array[DAI_w.val];
+ constexpr auto null = (uint8_t)-1;
+ resolve_wall_rotations(atlas.direction_array, atlas.direction_map);
+ fm_assert(!D_n.corner_R.is_defined && D_n.corner_R.from_rotation == null);
+ fm_assert(D_n.top.is_defined);
+ fm_assert(D_n.top.from_rotation != null);
+ fm_assert(D_n.top.from_rotation != null);
+ fm_assert(D_w.top.from_rotation == null);
+ fm_assert(D_w.top.is_defined);
+ fm_assert(D_n.corner_L.is_defined);
+ fm_assert(D_n.corner_L.from_rotation == null);
+ fm_assert(D_w.corner_L.is_defined);
+ fm_assert(D_w.corner_L.from_rotation == DAI_n.val);
+ fm_assert(atlas.direction_array[D_w.corner_L.from_rotation].corner_L.count == 11);
+ fm_assert(atlas.direction_array[D_n.top.from_rotation].top.count == 12);
+}
+
[[nodiscard]] wall_atlas_def read_and_check(StringView filename)
{
auto atlas = wall_atlas_def::deserialize(filename);
@@ -112,6 +137,7 @@ void test_expected_size()
void floormat::test_app::test_wall_atlas()
{
using namespace floormat::Wall::detail;
+ using namespace floormat::Wall;
{
test_expected_size();
@@ -125,6 +151,7 @@ void floormat::test_app::test_wall_atlas()
{ test_read_header(S_02_groups_json);
test_read_groups(S_02_groups_json);
+ test_from_rotation(S_02_groups_json);
}
{ auto a = read_and_check(Path::join(json_path(), S_02_groups_json));