summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2023-11-22 09:47:25 +0100
committerStanislaw Halik <sthalik@misaki.pl>2023-11-22 09:47:25 +0100
commit28ba97727326c05c9347b50b0114f01c0ec8b1df (patch)
tree223712106e660dec018f7dfc3329ca48e5c8fb11
parentb7006b670843f692bc14aa9932bffd44f6a629f7 (diff)
a
-rw-r--r--draw/anim.hpp2
-rw-r--r--editor/app.hpp4
-rw-r--r--editor/editor.hpp4
-rw-r--r--editor/scenery-editor.hpp2
-rw-r--r--editor/vobj-editor.hpp2
-rw-r--r--floormat/main.hpp2
-rw-r--r--loader/atlas.cpp10
-rw-r--r--loader/impl.cpp1
-rw-r--r--loader/impl.hpp42
-rw-r--r--loader/json.cpp5
-rw-r--r--loader/loader.cpp2
-rw-r--r--loader/loader.hpp17
-rw-r--r--loader/vobj-info.hpp2
-rw-r--r--loader/vobj.cpp6
-rw-r--r--loader/wall-atlas.cpp99
-rw-r--r--loader/wall-info.hpp15
-rw-r--r--main/main-impl.hpp2
-rw-r--r--serialize/wall-atlas.cpp110
-rw-r--r--serialize/wall-atlas.hpp18
-rw-r--r--src/anim-atlas.hpp31
-rw-r--r--src/chunk.hpp2
-rw-r--r--src/critter.hpp2
-rw-r--r--src/object.hpp2
-rw-r--r--src/scenery.hpp2
-rw-r--r--src/tile-atlas.hpp25
-rw-r--r--src/tile-image.hpp2
-rw-r--r--src/tile.hpp2
-rw-r--r--src/wall-atlas.cpp16
-rw-r--r--src/wall-atlas.hpp32
-rw-r--r--test/json/wall-atlas-01_header.json4
-rw-r--r--test/json/wall-atlas-02_groups.json4
-rw-r--r--test/wall-atlas.cpp123
32 files changed, 359 insertions, 233 deletions
diff --git a/draw/anim.hpp b/draw/anim.hpp
index dcfbfe68..03bb10c4 100644
--- a/draw/anim.hpp
+++ b/draw/anim.hpp
@@ -17,7 +17,7 @@
namespace floormat {
struct tile_shader;
-struct anim_atlas;
+class anim_atlas;
struct chunk;
struct clickable;
struct object;
diff --git a/editor/app.hpp b/editor/app.hpp
index 7cf983bc..04857771 100644
--- a/editor/app.hpp
+++ b/editor/app.hpp
@@ -21,10 +21,10 @@ namespace floormat {
struct chunk;
struct floormat_main;
-struct tile_atlas;
+class tile_atlas;
struct tile_editor;
struct fm_settings;
-struct anim_atlas;
+class anim_atlas;
struct critter;
struct point;
diff --git a/editor/editor.hpp b/editor/editor.hpp
index 1ae983de..d877288d 100644
--- a/editor/editor.hpp
+++ b/editor/editor.hpp
@@ -15,8 +15,8 @@
namespace floormat {
struct world;
-struct anim_atlas;
-struct tile_atlas;
+class anim_atlas;
+class tile_atlas;
struct app;
struct editor final
diff --git a/editor/scenery-editor.hpp b/editor/scenery-editor.hpp
index f3c3780b..cf2a1681 100644
--- a/editor/scenery-editor.hpp
+++ b/editor/scenery-editor.hpp
@@ -6,7 +6,7 @@
namespace floormat {
-struct anim_atlas;
+class anim_atlas;
struct global_coords;
struct world;
struct app;
diff --git a/editor/vobj-editor.hpp b/editor/vobj-editor.hpp
index e26289d4..e92c6abe 100644
--- a/editor/vobj-editor.hpp
+++ b/editor/vobj-editor.hpp
@@ -10,7 +10,7 @@ namespace floormat {
struct world;
struct global_coords;
struct object;
-struct anim_atlas;
+class anim_atlas;
struct vobj_info;
struct app;
diff --git a/floormat/main.hpp b/floormat/main.hpp
index 11a42bd7..1604ad22 100644
--- a/floormat/main.hpp
+++ b/floormat/main.hpp
@@ -15,7 +15,7 @@ struct tile_shader;
struct lightmap_shader;
struct world;
struct scenery;
-struct anim_atlas;
+class anim_atlas;
struct clickable;
struct floor_mesh;
struct wall_mesh;
diff --git a/loader/atlas.cpp b/loader/atlas.cpp
index 2afd4d2e..3fd30e80 100644
--- a/loader/atlas.cpp
+++ b/loader/atlas.cpp
@@ -55,12 +55,12 @@ std::shared_ptr<tile_atlas> loader_impl::tile_atlas(StringView name, Vector2ub s
char buf[FILENAME_MAX];
auto path = make_atlas_path(buf, IMAGE_PATH, name);
- auto atlas = std::make_shared<struct tile_atlas>(path, name, texture(""_s, path), size, pass);
+ auto atlas = std::make_shared<class tile_atlas>(path, name, texture(""_s, path), size, pass);
tile_atlas_map[atlas->name()] = atlas;
return atlas;
}
-std::shared_ptr<struct tile_atlas> loader_impl::tile_atlas(StringView filename) noexcept(false)
+std::shared_ptr<class tile_atlas> loader_impl::tile_atlas(StringView filename) noexcept(false)
{
fm_assert(!tile_atlas_map.empty());
auto it = tile_atlas_map.find(filename);
@@ -120,7 +120,7 @@ std::shared_ptr<anim_atlas> loader_impl::anim_atlas(StringView name, StringView
const auto width = size[1], height = size[0];
fm_soft_assert(anim_info.pixel_size[0] == width && anim_info.pixel_size[1] == height);
- auto atlas = std::make_shared<struct anim_atlas>(path, tex, std::move(anim_info));
+ auto atlas = std::make_shared<class anim_atlas>(path, tex, std::move(anim_info));
return anim_atlas_map[atlas->name()] = atlas;
}
}
@@ -132,11 +132,13 @@ void loader_impl::get_anim_atlas_list()
constexpr auto flags = f::SkipDirectories | f::SkipDotAndDotDot | f::SkipSpecial | f::SortAscending;
if (const auto list = Path::list(ANIM_PATH, flags); list)
{
- anim_atlases.reserve(list->size()*2);
+ anim_atlases.reserve(list->size());
for (StringView str : *list)
if (str.hasSuffix(".json"))
anim_atlases.emplace_back(str.exceptSuffix(std::size(".json")-1));
}
+ anim_atlases.shrink_to_fit();
+ fm_assert(!anim_atlases.empty());
}
} // namespace floormat::loader_detail
diff --git a/loader/impl.cpp b/loader/impl.cpp
index 02493089..029f96a6 100644
--- a/loader/impl.cpp
+++ b/loader/impl.cpp
@@ -2,6 +2,7 @@
#include "compat/assert.hpp"
#include "loader/scenery.hpp"
#include "loader/vobj-info.hpp"
+#include "loader/wall-info.hpp"
#include <Corrade/Containers/Pair.h>
#include <Magnum/Trade/ImageData.h>
diff --git a/loader/impl.hpp b/loader/impl.hpp
index f5975d0e..525a5ecc 100644
--- a/loader/impl.hpp
+++ b/loader/impl.hpp
@@ -10,22 +10,36 @@
#include <Corrade/PluginManager/PluginManager.h>
#include <Magnum/Trade/AbstractImporter.h>
-namespace floormat { struct anim_def; }
+namespace floormat {
+struct anim_def;
+struct wall_info;
+}
namespace floormat::loader_detail {
struct loader_impl final : loader_
{
+// <-----< resources <-----<
Optional<Utility::Resource> shader_res;
Optional<PluginManager::Manager<Trade::AbstractImporter>> importer_plugins;
Containers::Pointer<Trade::AbstractImporter> image_importer;
Containers::Pointer<Trade::AbstractImporter> tga_importer;
+// >-----> resources >----->
- tsl::robin_map<StringView, std::shared_ptr<struct tile_atlas>> tile_atlas_map;
- tsl::robin_map<StringView, std::shared_ptr<struct anim_atlas>> anim_atlas_map;
- tsl::robin_map<StringView, const struct vobj_info*> vobj_atlas_map;
+// <-----< walls <-----<
+ struct wall_index { uint32_t val = (uint32_t)-1; };
+ tsl::robin_map<StringView, const wall_info*> wall_atlas_map;
+ std::vector<wall_info> wall_atlas_array;
+
+ const wall_info& wall_atlas(StringView name, StringView dir) override;
+ ArrayView<const wall_info> wall_atlas_list() override;
+ void get_wall_atlas_list();
+ std::shared_ptr<class wall_atlas> get_wall_atlas(StringView pathname);
+// >-----> walls >----->
+
+ tsl::robin_map<StringView, std::shared_ptr<class tile_atlas>> tile_atlas_map;
+ tsl::robin_map<StringView, std::shared_ptr<class anim_atlas>> anim_atlas_map;
std::vector<String> anim_atlases;
- std::vector<struct vobj_info> vobjs;
std::vector<serialized_scenery> sceneries_array;
tsl::robin_map<StringView, const serialized_scenery*> sceneries_map;
@@ -34,21 +48,27 @@ struct loader_impl final : loader_
StringView shader(StringView filename) noexcept override;
Trade::ImageData2D texture(StringView prefix, StringView filename) noexcept(false) override;
- std::shared_ptr<struct tile_atlas> tile_atlas(StringView filename, Vector2ub size, Optional<pass_mode> pass) noexcept(false) override;
- std::shared_ptr<struct tile_atlas> tile_atlas(StringView filename) noexcept(false) override;
+ std::shared_ptr<class tile_atlas> tile_atlas(StringView filename, Vector2ub size, Optional<pass_mode> pass) noexcept(false) override;
+ std::shared_ptr<class tile_atlas> tile_atlas(StringView filename) noexcept(false) override;
ArrayView<const String> anim_atlas_list() override;
- std::shared_ptr<struct anim_atlas> anim_atlas(StringView name, StringView dir) noexcept(false) override;
+ std::shared_ptr<class anim_atlas> anim_atlas(StringView name, StringView dir) noexcept(false) override;
const std::vector<serialized_scenery>& sceneries() override;
const scenery_proto& scenery(StringView name) noexcept(false) override;
void get_anim_atlas_list();
void get_scenery_list();
- static anim_def deserialize_anim(StringView filename);
- void get_vobj_list();
- std::shared_ptr<struct anim_atlas> make_vobj_anim_atlas(StringView name, StringView image_filename);
+// <-----< vobjs <-----<
+ tsl::robin_map<StringView, const struct vobj_info*> vobj_atlas_map;
+ std::vector<struct vobj_info> vobjs;
+
+ std::shared_ptr<class anim_atlas> make_vobj_anim_atlas(StringView name, StringView image_filename);
const struct vobj_info& vobj(StringView name) override;
ArrayView<const struct vobj_info> vobj_list() override;
+ void get_vobj_list();
+// >-----> vobjs >----->
+
+ static anim_def deserialize_anim(StringView filename);
void set_application_working_directory();
StringView startup_directory() noexcept override;
diff --git a/loader/json.cpp b/loader/json.cpp
index 7e6aae68..007bafeb 100644
--- a/loader/json.cpp
+++ b/loader/json.cpp
@@ -29,6 +29,7 @@ void loader_impl::get_scenery_list()
fm_abort("duplicate scenery name '%s'", s.name.data());
sceneries_map[s.name] = &s;
}
+ fm_assert(!sceneries_map.empty());
}
const std::vector<serialized_scenery>& loader_impl::sceneries()
@@ -53,9 +54,9 @@ const scenery_proto& loader_impl::scenery(StringView name) noexcept(false)
namespace floormat {
-std::vector<std::shared_ptr<struct tile_atlas>> loader_::tile_atlases(StringView filename, pass_mode p)
+std::vector<std::shared_ptr<class tile_atlas>> loader_::tile_atlases(StringView filename, pass_mode p)
{
- auto vec = json_helper::from_json<std::vector<std::shared_ptr<struct tile_atlas>>>(
+ auto vec = json_helper::from_json<std::vector<std::shared_ptr<class tile_atlas>>>(
Path::join(loader_::IMAGE_PATH, filename));
for (auto& x : vec)
if (!x->pass_mode())
diff --git a/loader/loader.cpp b/loader/loader.cpp
index 7d95da0e..a89cadab 100644
--- a/loader/loader.cpp
+++ b/loader/loader.cpp
@@ -32,6 +32,8 @@ StringView loader_::strip_prefix(StringView name)
return name.exceptPrefix(SCENERY_PATH.size());
if (name.hasPrefix(VOBJ_PATH))
return name.exceptPrefix(VOBJ_PATH.size());
+ if (name.hasPrefix(WALL_TILESET_PATH))
+ return name.exceptPrefix(WALL_TILESET_PATH.size());
return name;
}
diff --git a/loader/loader.hpp b/loader/loader.hpp
index 181688fc..390f020c 100644
--- a/loader/loader.hpp
+++ b/loader/loader.hpp
@@ -17,23 +17,28 @@ using ImageData2D = ImageData<2>;
namespace floormat {
-struct tile_atlas;
-struct anim_atlas;
+class tile_atlas;
+class anim_atlas;
+class wall_atlas;
struct scenery_proto;
struct vobj_info;
+struct wall_info;
struct loader_
{
virtual StringView shader(StringView filename) noexcept = 0;
virtual Trade::ImageData2D texture(StringView prefix, StringView filename) noexcept(false) = 0;
// todo remove Optional when wall_atlas is fully implemented -sh 20231122
- virtual std::shared_ptr<struct tile_atlas> tile_atlas(StringView filename, Vector2ub size, Optional<pass_mode> pass) noexcept(false) = 0;
- virtual std::shared_ptr<struct tile_atlas> tile_atlas(StringView filename) noexcept(false) = 0;
+ virtual std::shared_ptr<class tile_atlas> tile_atlas(StringView filename, Vector2ub size, Optional<pass_mode> pass) noexcept(false) = 0;
+ 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<struct anim_atlas> anim_atlas(StringView name, StringView dir = ANIM_PATH) noexcept(false) = 0;
+ virtual std::shared_ptr<class anim_atlas> anim_atlas(StringView name, StringView dir = ANIM_PATH) noexcept(false) = 0;
+ virtual const wall_info& wall_atlas(StringView name, StringView dir = WALL_TILESET_PATH) = 0;
+ virtual ArrayView<const wall_info> wall_atlas_list() = 0;
static void destroy();
static loader_& default_loader() noexcept;
- static std::vector<std::shared_ptr<struct tile_atlas>> tile_atlases(StringView filename, pass_mode p);
+ // todo move to ArrayView later, make non-static, and remove pass_mode
+ static std::vector<std::shared_ptr<class tile_atlas>> tile_atlases(StringView filename, pass_mode p);
virtual const std::vector<serialized_scenery>& sceneries() = 0;
virtual const scenery_proto& scenery(StringView name) noexcept(false) = 0;
virtual StringView startup_directory() noexcept = 0;
diff --git a/loader/vobj-info.hpp b/loader/vobj-info.hpp
index 8bc7d189..75ace811 100644
--- a/loader/vobj-info.hpp
+++ b/loader/vobj-info.hpp
@@ -4,7 +4,7 @@
namespace floormat {
-struct anim_atlas;
+class anim_atlas;
struct vobj_info final
{
diff --git a/loader/vobj.cpp b/loader/vobj.cpp
index 1f8f5207..aa3be207 100644
--- a/loader/vobj.cpp
+++ b/loader/vobj.cpp
@@ -48,7 +48,7 @@ namespace floormat::loader_detail {
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#endif
-std::shared_ptr<struct anim_atlas> loader_impl::make_vobj_anim_atlas(StringView name, StringView image_filename)
+std::shared_ptr<class anim_atlas> loader_impl::make_vobj_anim_atlas(StringView name, StringView image_filename)
{
auto tex = texture(VOBJ_PATH, image_filename);
anim_def def;
@@ -65,7 +65,7 @@ std::shared_ptr<struct anim_atlas> loader_impl::make_vobj_anim_atlas(StringView
.size = def.pixel_size
}}
}};
- auto atlas = std::make_shared<struct anim_atlas>(name, tex, std::move(def));
+ auto atlas = std::make_shared<class anim_atlas>(name, tex, std::move(def));
return atlas;
}
@@ -87,6 +87,8 @@ void loader_impl::get_vobj_list()
const auto& x = vobjs.back();
vobj_atlas_map[x.atlas->name()] = &x;
}
+
+ fm_assert(!vobjs.empty());
}
ArrayView<const vobj_info> loader_impl::vobj_list()
diff --git a/loader/wall-atlas.cpp b/loader/wall-atlas.cpp
new file mode 100644
index 00000000..10f3524d
--- /dev/null
+++ b/loader/wall-atlas.cpp
@@ -0,0 +1,99 @@
+#include "loader/impl.hpp"
+#include "wall-info.hpp"
+#include "compat/assert.hpp"
+#include "compat/exception.hpp"
+#include "src/wall-atlas.hpp"
+#include "serialize/wall-atlas.hpp"
+#include "wall-info.hpp"
+#include "serialize/json-helper.hpp"
+#include "serialize/corrade-string.hpp"
+#include <Corrade/Containers/Array.h>
+#include <Corrade/Containers/ArrayViewStl.h>
+#include <Corrade/Utility/Path.h>
+#include <Magnum/Trade/ImageData.h>
+#include <vector>
+
+namespace floormat {
+NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(wall_info, name, descr)
+} // namespace floormat
+
+namespace floormat::loader_detail {
+
+std::shared_ptr<wall_atlas> loader_impl::get_wall_atlas(StringView filename)
+{
+ using namespace floormat::Wall;
+ using namespace floormat::Wall::detail;
+
+ const auto jroot = json_helper::from_json_(filename);
+ auto header = read_info_header(jroot);
+ auto frames = read_all_frames(jroot);
+
+ size_t direction_count = 0;
+ for (const auto& [str, curdir] : wall_atlas::directions)
+ if (jroot.contains(std::string_view{str.data(), str.size()}))
+ direction_count++;
+ fm_soft_assert(direction_count > 0);
+ fm_debug_assert(direction_count <= (size_t)Direction_::COUNT);
+
+ auto directions = Array<Direction>{direction_count};
+ std::array<DirArrayIndex, 4> dir_array_indexes{};
+
+ uint8_t dir_idx = 0;
+ for (const auto& [str, curdir] : wall_atlas::directions)
+ {
+ if (!jroot.contains(std::string_view{str.data(), str.size()}))
+ continue;
+ auto i = (size_t)curdir;
+ fm_debug_assert(dir_idx < direction_count);
+ dir_array_indexes[i] = { .val = dir_idx };
+ directions[dir_idx++] = read_direction_metadata(jroot, curdir);
+ }
+ fm_debug_assert(dir_idx == direction_count);
+
+ auto atlas = std::make_shared<class wall_atlas>();
+ return atlas;
+}
+
+const wall_info& loader_impl::wall_atlas(StringView name, StringView dir)
+{
+ fm_soft_assert(check_atlas_name(name));
+ char buf[FILENAME_MAX];
+ auto path = make_atlas_path(buf, dir, name);
+
+ auto it = wall_atlas_map.find(path);
+ if (it == wall_atlas_map.end())
+ fm_throw("no such wall atlas '{}'"_cf, fmt::string_view{path.data(), path.size()});
+ fm_assert(it->second != nullptr);
+ if (!it->second->atlas)
+ {
+ const_cast<wall_info*>(it->second)->atlas = get_wall_atlas(path);
+ }
+ return *it->second;
+}
+
+void loader_impl::get_wall_atlas_list()
+{
+ wall_atlas_array = json_helper::from_json<std::vector<wall_info>>(Path::join(WALL_TILESET_PATH, "walls.json"_s));
+ wall_atlas_array.shrink_to_fit();
+ wall_atlas_map.clear();
+ wall_atlas_map.reserve(wall_atlas_array.size()*2);
+
+ for (const auto& x : wall_atlas_array)
+ {
+ fm_soft_assert(check_atlas_name(x.name));
+ StringView name = x.name;
+ wall_atlas_map[name] = &x;
+ fm_debug_assert(name.data() == wall_atlas_map[name]->name.data());
+ }
+
+ fm_assert(!wall_atlas_map.empty());
+}
+
+ArrayView<const wall_info> loader_impl::wall_atlas_list()
+{
+ if (wall_atlas_map.empty())
+ get_wall_atlas_list();
+ return wall_atlas_array;
+}
+
+} // namespace floormat::loader_detail
diff --git a/loader/wall-info.hpp b/loader/wall-info.hpp
new file mode 100644
index 00000000..570f436d
--- /dev/null
+++ b/loader/wall-info.hpp
@@ -0,0 +1,15 @@
+#pragma once
+#include <memory>
+#include <Corrade/Containers/String.h>
+
+namespace floormat {
+
+class wall_atlas;
+
+struct wall_info
+{
+ String name, descr;
+ std::shared_ptr<wall_atlas> atlas;
+};
+
+} // namespace floormat
diff --git a/main/main-impl.hpp b/main/main-impl.hpp
index 5619dda6..f66b0248 100644
--- a/main/main-impl.hpp
+++ b/main/main-impl.hpp
@@ -29,7 +29,7 @@ namespace floormat {
struct floormat_app;
struct scenery;
-struct anim_atlas;
+class anim_atlas;
struct clickable;
struct main_impl final : Platform::Sdl2Application, floormat_main
diff --git a/serialize/wall-atlas.cpp b/serialize/wall-atlas.cpp
index 6d711d6b..79abe6fa 100644
--- a/serialize/wall-atlas.cpp
+++ b/serialize/wall-atlas.cpp
@@ -5,6 +5,7 @@
#include "compat/exception.hpp"
#include "loader/loader.hpp"
#include "pass-mode.hpp"
+#include "json-helper.hpp"
#include <utility>
#include <string_view>
#include <Corrade/Containers/PairStl.h>
@@ -15,6 +16,79 @@
// todo add test on dummy files that generates 100% coverage on the j.contains() blocks!
+namespace floormat {
+
+using namespace floormat::Wall::detail;
+
+bool wall_atlas_def::operator==(const wall_atlas_def& other) const noexcept
+{
+ if (header != other.header)
+ return false;
+ if (direction_array.size() != other.direction_array.size())
+ return false;
+ for (uint8_t i = 0; i < std::size(direction_to_Direction_array_index); i++)
+ {
+ auto i1 = direction_to_Direction_array_index[i],
+ i2 = other.direction_to_Direction_array_index[i];
+ if (!i1 != !i2)
+ return false;
+ if (i1)
+ {
+ fm_assert(i1.val < direction_array.size());
+ fm_assert(i2.val < other.direction_array.size());
+ if (direction_array[i1.val] != other.direction_array[i2.val])
+ return false;
+ }
+ }
+ if (frames.size() != other.frames.size())
+ return false;
+ for (auto i = 0uz; i < frames.size(); i++)
+ if (frames[i] != other.frames[i])
+ return false;
+ return true;
+}
+
+wall_atlas_def wall_atlas_def::deserialize(StringView filename)
+{
+ wall_atlas_def atlas;
+
+ const auto jroot = json_helper::from_json_(filename);
+ atlas.header = read_info_header(jroot);
+ atlas.frames = read_all_frames(jroot);
+ auto [dirs, dir_indexes] = read_all_directions(jroot);
+ fm_soft_assert(!dirs.isEmpty());
+ fm_soft_assert(dir_indexes != std::array<Wall::DirArrayIndex, 4>{});
+ atlas.direction_array = std::move(dirs);
+ atlas.direction_to_Direction_array_index = dir_indexes;
+
+ return atlas;
+}
+
+void wall_atlas_def::serialize(StringView filename) const
+{
+ auto jroot = json{};
+
+ write_info_header(jroot, header);
+ write_all_frames(jroot, frames);
+
+ for (const auto [name_, dir] : wall_atlas::directions)
+ {
+ if (auto idx = direction_to_Direction_array_index[(size_t)dir])
+ {
+ const auto& dir = direction_array[idx.val];
+ if (!dir.is_empty())
+ {
+ std::string_view name = {name_.data(), name_.size()};
+ write_direction_metadata(jroot[name], dir);
+ }
+ }
+ }
+
+ json_helper::to_json_(jroot, filename);
+}
+
+} // namespace floormat
+
namespace floormat::Wall::detail {
uint8_t direction_index_from_name(StringView s)
@@ -141,10 +215,8 @@ Info read_info_header(const json& jroot)
{
fm_soft_assert(jroot.contains(("name")));
fm_soft_assert(jroot.contains(("depth")));
- Info val = {std::string{jroot["name"]}, {}, jroot["depth"]};
+ Info val = {std::string{jroot["name"]}, jroot["depth"]};
fm_soft_assert(val.depth > 0);
- if (jroot.contains("description"))
- val.description = std::string{jroot["description"]};
return val;
}
@@ -214,9 +286,8 @@ void write_all_directions(json& jroot, const wall_atlas& a)
}
void write_info_header(json& jroot, const Info& info)
-{ jroot["name"] = info.name;
- if (info.description)
- jroot["description"] = info.description;
+{
+ jroot["name"] = info.name;
jroot["depth"] = info.depth;
}
@@ -225,38 +296,15 @@ void write_info_header(json& jroot, const Info& info)
namespace floormat::Wall {
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Frame, offset)
-NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Info, name, description, depth)
+NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Info, name, depth)
} // namespace floormat::Wall
namespace nlohmann {
-using namespace floormat;
-using namespace floormat::Wall;
-using namespace floormat::Wall::detail;
+using floormat::Wall::Frame;
void adl_serializer<Frame>::to_json(nlohmann::json& j, const Frame& x) { using nlohmann::to_json; to_json(j, x); }
void adl_serializer<Frame>::from_json(const json& j, Frame& x) { using nlohmann::from_json; from_json(j, x); }
-void adl_serializer<std::shared_ptr<wall_atlas>>::to_json(json& j, const std::shared_ptr<const wall_atlas>& x)
-{
- fm_assert(x != nullptr);
- write_info_header(j, x->info());
- write_all_directions(j, *x);
- write_all_frames(j, x->raw_frame_array());
-}
-
-void adl_serializer<std::shared_ptr<wall_atlas>>::from_json(const json& j, std::shared_ptr<wall_atlas>& x)
-{
- auto info = read_info_header(j);
- fm_assert(loader.check_atlas_name(info.name));
- auto [dirs, map] = read_all_directions(j);
- Array<Frame> frames;
- auto img = loader.texture(loader.WALL_TILESET_PATH, info.name);
- if (j.contains("frames"))
- frames = read_all_frames(j);
-
- x = std::make_shared<wall_atlas>(std::move(info), img, std::move(frames), std::move(dirs), map);
-}
-
} // namespace nlohmann
diff --git a/serialize/wall-atlas.hpp b/serialize/wall-atlas.hpp
index f531a48e..b69f7e96 100644
--- a/serialize/wall-atlas.hpp
+++ b/serialize/wall-atlas.hpp
@@ -3,24 +3,12 @@
#include <memory>
#include <nlohmann/json_fwd.hpp>
-namespace nlohmann {
-
template<>
-struct adl_serializer<floormat::Wall::Frame>
-{
- static void to_json(json& j, const floormat::Wall::Frame& x);
- static void from_json(const json& j, floormat::Wall::Frame& x);
+struct nlohmann::adl_serializer<floormat::Wall::Frame> {
+ static void to_json(json& j, const floormat::Wall::Frame& val);
+ static void from_json(const json& j, floormat::Wall::Frame& val);
};
-template<>
-struct adl_serializer<std::shared_ptr<floormat::wall_atlas>>
-{
- static void to_json(json& j, const std::shared_ptr<const floormat::wall_atlas>& x);
- static void from_json(const json& j, std::shared_ptr<floormat::wall_atlas>& x);
-};
-
-} // namespace nlohmann
-
namespace floormat::Wall::detail {
using nlohmann::json;
diff --git a/src/anim-atlas.hpp b/src/anim-atlas.hpp
index 22df30eb..2803566f 100644
--- a/src/anim-atlas.hpp
+++ b/src/anim-atlas.hpp
@@ -2,6 +2,7 @@
#include "compat/defs.hpp"
#include "rotation.hpp"
#include "anim.hpp"
+#include "src/quads.hpp"
#include <array>
#include <Corrade/Containers/BitArray.h>
#include <Corrade/Containers/String.h>
@@ -11,11 +12,23 @@
namespace floormat {
-struct anim_atlas final
+class anim_atlas final
{
- using texcoords = std::array<Vector2, 4>;
- using quad = std::array<Vector3, 4>;
+ using texcoords = Quads::texcoords;
+ using quad = Quads::quad;
+ String _name;
+ BitArray _bitmask;
+ anim_def _info;
+ std::array<uint8_t, (size_t)rotation_COUNT> _group_indices = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ };
+ GL::Texture2D _tex;
+
+ static decltype(_group_indices) make_group_indices(const anim_def& anim) noexcept;
+ static uint8_t rotation_to_index(StringView name);
+
+public:
anim_atlas() noexcept;
anim_atlas(String name, const ImageView2D& tex, anim_def info);
~anim_atlas() noexcept;
@@ -43,18 +56,6 @@ struct anim_atlas final
static void make_bitmask_(const ImageView2D& tex, BitArray& array);
static BitArray make_bitmask(const ImageView2D& tex);
-
-private:
- String _name;
- BitArray _bitmask;
- anim_def _info;
- std::array<uint8_t, (size_t)rotation_COUNT> _group_indices = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- };
- GL::Texture2D _tex;
-
- static decltype(_group_indices) make_group_indices(const anim_def& anim) noexcept;
- static uint8_t rotation_to_index(StringView name);
};
} // namespace floormat
diff --git a/src/chunk.hpp b/src/chunk.hpp
index e964fca0..a24957b1 100644
--- a/src/chunk.hpp
+++ b/src/chunk.hpp
@@ -11,7 +11,7 @@
namespace floormat {
-struct anim_atlas;
+class anim_atlas;
struct object;
struct object_proto;
class tile_iterator;
diff --git a/src/critter.hpp b/src/critter.hpp
index 81c8b601..724e2b28 100644
--- a/src/critter.hpp
+++ b/src/critter.hpp
@@ -6,7 +6,7 @@
namespace floormat {
-struct anim_atlas;
+class anim_atlas;
struct world;
struct critter_proto : object_proto
diff --git a/src/object.hpp b/src/object.hpp
index c02e4d07..50512419 100644
--- a/src/object.hpp
+++ b/src/object.hpp
@@ -12,7 +12,7 @@
namespace floormat {
template<typename T> struct object_type_;
-struct anim_atlas;
+class anim_atlas;
struct world;
struct chunk;
diff --git a/src/scenery.hpp b/src/scenery.hpp
index 70b7733c..9135b548 100644
--- a/src/scenery.hpp
+++ b/src/scenery.hpp
@@ -10,7 +10,7 @@
namespace floormat {
struct chunk;
-struct anim_atlas;
+class anim_atlas;
struct world;
enum class scenery_type : unsigned char {
diff --git a/src/tile-atlas.hpp b/src/tile-atlas.hpp
index 45251c6d..1a06db4a 100644
--- a/src/tile-atlas.hpp
+++ b/src/tile-atlas.hpp
@@ -1,5 +1,6 @@
#pragma once
#include "src/pass-mode.hpp"
+#include "src/quads.hpp"
#include <array>
#include <memory>
#include <Corrade/Containers/Optional.h>
@@ -10,11 +11,22 @@
namespace floormat {
-struct tile_atlas final
+class tile_atlas final
{
using quad = std::array<Vector3, 4>;
using texcoords = std::array<Vector2, 4>;
+ static std::unique_ptr<const texcoords[]> make_texcoords_array(Vector2ui pixel_size, Vector2ub tile_count);
+ static texcoords make_texcoords(Vector2ui pixel_size, Vector2ub tile_count, size_t i);
+
+ std::unique_ptr<const texcoords[]> texcoords_;
+ GL::Texture2D tex_;
+ String path_, name_;
+ Vector2ui size_;
+ Vector2ub dims_;
+ Optional<enum pass_mode> passability;
+
+public:
// todo remove Optional when wall atlases are fully implemented -sh 20231122
tile_atlas(StringView path, StringView name, const ImageView2D& img, Vector2ub tile_count, Optional<enum pass_mode> pass_mode);
@@ -28,17 +40,6 @@ struct tile_atlas final
Optional<enum pass_mode> pass_mode() const; // todo remove later
enum pass_mode pass_mode(enum pass_mode p) const;
void set_pass_mode(enum pass_mode p); // todo remove later
-
-private:
- static std::unique_ptr<const texcoords[]> make_texcoords_array(Vector2ui pixel_size, Vector2ub tile_count);
- static texcoords make_texcoords(Vector2ui pixel_size, Vector2ub tile_count, size_t i);
-
- std::unique_ptr<const texcoords[]> texcoords_;
- GL::Texture2D tex_;
- String path_, name_;
- Vector2ui size_;
- Vector2ub dims_;
- Optional<enum pass_mode> passability;
};
diff --git a/src/tile-image.hpp b/src/tile-image.hpp
index 907a465c..c93cc778 100644
--- a/src/tile-image.hpp
+++ b/src/tile-image.hpp
@@ -3,7 +3,7 @@
namespace floormat {
-struct tile_atlas;
+class tile_atlas;
using variant_t = uint8_t;
diff --git a/src/tile.hpp b/src/tile.hpp
index f9d6adc8..fbe2e93d 100644
--- a/src/tile.hpp
+++ b/src/tile.hpp
@@ -4,7 +4,7 @@
namespace floormat {
struct chunk;
-struct anim_atlas;
+class anim_atlas;
struct tile_proto final
{
diff --git a/src/wall-atlas.cpp b/src/wall-atlas.cpp
index 31659cca..3c2ac3cf 100644
--- a/src/wall-atlas.cpp
+++ b/src/wall-atlas.cpp
@@ -70,15 +70,13 @@ Vector2i wall_atlas::expected_size(int depth, Tag group)
}
}
-wall_atlas::wall_atlas(Info info, const ImageView2D& img,
- Array<Frame> frames,
- Array<Direction> directions,
- std::array<DirArrayIndex, 4> direction_to_DirArrayIndex)
- : _dir_array{ std::move(directions) }, _frame_array{ std::move(frames) },
- _info{ std::move(info) },
- _direction_to_Direction_array_index{ direction_to_DirArrayIndex }
+wall_atlas::wall_atlas(wall_atlas_def def, String path, const ImageView2D& img)
+ : _dir_array{std::move(def.direction_array)},
+ _frame_array{std::move(def.frames)},
+ _info{std::move(def.header)}, _path{std::move(path)},
+ _direction_to_Direction_array_index{def.direction_to_Direction_array_index}
{
- _texture.setLabel(_info.name)
+ _texture.setLabel(_path)
.setWrapping(GL::SamplerWrapping::ClampToEdge)
.setMagnificationFilter(GL::SamplerFilter::Nearest)
.setMinificationFilter(GL::SamplerFilter::Linear)
@@ -149,9 +147,7 @@ auto wall_atlas::direction(size_t dir) const -> const Direction*
uint8_t wall_atlas::direction_count() const { return (uint8_t)_dir_array.size(); }
auto wall_atlas::raw_frame_array() const -> ArrayView<const Frame> { return _frame_array; }
-auto wall_atlas::info() const -> const Info& { return _info; }
GL::Texture2D& wall_atlas::texture() { fm_debug_assert(_texture.id()); return _texture; }
-StringView wall_atlas::name() const { return _info.name; }
size_t wall_atlas::enum_to_index(enum rotation r)
{
diff --git a/src/wall-atlas.hpp b/src/wall-atlas.hpp
index 6a0abf15..e3470a56 100644
--- a/src/wall-atlas.hpp
+++ b/src/wall-atlas.hpp
@@ -67,7 +67,7 @@ struct Direction
struct Info
{
- String name = "(unnamed)"_s, description = {};
+ String name;
unsigned depth = 0;
bool operator==(const Info&) const noexcept;
@@ -75,7 +75,7 @@ struct Info
struct DirArrayIndex {
std::uint8_t val = (uint8_t)-1;
- operator bool() const { return val == (uint8_t)-1; }
+ operator bool() const { return val != (uint8_t)-1; }
bool operator==(const DirArrayIndex&) const noexcept;
};
@@ -84,6 +84,19 @@ struct DirArrayIndex {
namespace floormat {
+struct wall_atlas_def final
+{
+ bool operator==(const wall_atlas_def&) const noexcept;
+
+ Wall::Info header;
+ Array<Wall::Frame> frames;
+ Array<Wall::Direction> direction_array;
+ std::array<Wall::DirArrayIndex, 4> direction_to_Direction_array_index;
+
+ static wall_atlas_def deserialize(StringView filename);
+ void serialize(StringView filename) const;
+};
+
class wall_atlas final
{
using Frame = Wall::Frame;
@@ -97,6 +110,7 @@ class wall_atlas final
Array<Direction> _dir_array;
Array<Frame> _frame_array;
Info _info;
+ String _path;
GL::Texture2D _texture{NoCreate};
std::array<DirArrayIndex, 4> _direction_to_Direction_array_index;
@@ -106,19 +120,21 @@ public:
fm_DECLARE_DELETED_MOVE_ASSIGNMENT(wall_atlas);
wall_atlas() noexcept;
~wall_atlas() noexcept;
- wall_atlas(Info info, const ImageView2D& img,
- Array<Frame> frames, Array<Direction> directions,
- std::array<DirArrayIndex, 4> direction_to_DirArrayIndex);
- StringView name() const;
- uint8_t direction_count() const;
+ 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 Direction* direction(size_t dir) const;
+ uint8_t direction_count() const;
ArrayView<const Frame> frames(const Group& a) const;
ArrayView<const Frame> raw_frame_array() const;
- const Info& info() const;
+
+ const Info& info() const { return _info; }
+ StringView name() const { return _info.name; }
+ //StringView path() const { return _path; }
+
GL::Texture2D& texture();
static size_t enum_to_index(enum rotation x);
diff --git a/test/json/wall-atlas-01_header.json b/test/json/wall-atlas-01_header.json
index 6859c6da..7d0bb3b4 100644
--- a/test/json/wall-atlas-01_header.json
+++ b/test/json/wall-atlas-01_header.json
@@ -1,7 +1,5 @@
{
"name": "foo",
"depth": 42,
- "frames": [],
- "n": {},
- "w": {}
+ "frames": []
}
diff --git a/test/json/wall-atlas-02_groups.json b/test/json/wall-atlas-02_groups.json
index e3ff3fb3..196085bd 100644
--- a/test/json/wall-atlas-02_groups.json
+++ b/test/json/wall-atlas-02_groups.json
@@ -18,6 +18,10 @@
}
],
"n": {
+ "wall": {
+ "offset": 0,
+ "count": 1
+ }
},
"w": {
"pass-mode": "shoot-through",
diff --git a/test/wall-atlas.cpp b/test/wall-atlas.cpp
index 7cd922ae..5bf143d8 100644
--- a/test/wall-atlas.cpp
+++ b/test/wall-atlas.cpp
@@ -3,6 +3,7 @@
#include "serialize/wall-atlas.hpp"
#include "serialize/json-helper.hpp"
#include "loader/loader.hpp"
+#include "compat/exception.hpp"
#include <Corrade/Containers/StringStl.h>
#include <Corrade/Utility/Path.h>
@@ -37,21 +38,6 @@ void test_read_header(StringView filename)
fm_assert(info.depth == 42);
}
-void test_read_empty_directions(StringView filename)
-{
- const auto jroot = json_helper::from_json_(Path::join(json_path(), filename));
- test_read_header(filename);
- fm_assert(!jroot.empty());
-
- fm_assert( jroot.contains("n") );
- fm_assert(!jroot.contains("e") );
- fm_assert(!jroot.contains("s") );
- fm_assert( jroot.contains("w") );
-
- fm_assert(jroot["n"].is_object() && jroot["n"].empty());
- fm_assert(jroot["w"].is_object() && jroot["w"].empty());
-}
-
void test_read_groups(StringView filename)
{
constexpr Group group_defaults;
@@ -60,16 +46,15 @@ void test_read_groups(StringView filename)
auto info = read_info_header(jroot);
fm_assert(info.name == "foo"_s);
fm_assert(info.depth == 42);
- fm_assert(info.description == ""_s);
fm_assert(jroot["depth"] == 42);
fm_assert( jroot.contains("n") );
fm_assert(!jroot.contains("e") );
fm_assert(!jroot.contains("s") );
fm_assert( jroot.contains("w") );
- fm_assert(jroot["n"].is_object() && jroot["n"].empty());
+ fm_assert(jroot["n"].is_object() && !jroot["n"].empty());
fm_assert(jroot["w"].is_object() && !jroot["w"].empty());
- fm_assert(read_direction_metadata(jroot, Direction_::N).is_empty());
+ fm_assert(!read_direction_metadata(jroot, Direction_::N).is_empty());
fm_assert(read_direction_metadata(jroot, Direction_::E).is_empty());
fm_assert(read_direction_metadata(jroot, Direction_::S).is_empty());
@@ -87,89 +72,33 @@ void test_read_groups(StringView filename)
fm_assert(dir.overlay.mirrored == true );
}
-struct wall_atlas_
-{
- bool operator==(const wall_atlas_&) const noexcept;
-
- Info header;
- std::array<Direction, 4> directions = {};
- Array<Frame> frames;
-};
-
-[[nodiscard]] wall_atlas_ read_from_file(StringView filename, bool do_checks = true)
+[[nodiscard]] wall_atlas_def read_and_check(StringView filename)
{
- wall_atlas_ atlas;
+ auto atlas = wall_atlas_def::deserialize(filename);
- const auto jroot = json_helper::from_json_(filename);
- atlas.header = read_info_header(jroot);
+ const Info header_defaults;
+ fm_assert(atlas.header.name != header_defaults.name);
+ fm_assert(atlas.header.depth != header_defaults.depth);
- if (do_checks)
- {
- const Info header_defaults;
- fm_assert(atlas.header.name != header_defaults.name);
- fm_assert(atlas.header.depth != header_defaults.depth);
- }
+ constexpr Frame frame_defaults;
+ constexpr Group group_defaults;
- bool got_any_directions = false;
- for (const auto& [_, curdir] : wall_atlas::directions)
- {
- auto i = (size_t)curdir;
- atlas.directions[i] = read_direction_metadata(jroot, curdir);
- got_any_directions = got_any_directions || atlas.directions[i];
- }
- if (do_checks)
- fm_assert(got_any_directions);
-
- atlas.frames = read_all_frames(jroot);
-
- if (do_checks)
- {
- constexpr Frame frame_defaults;
- constexpr Group group_defaults;
-
- fm_assert(!atlas.frames.isEmpty());
- fm_assert(atlas.frames[0].offset != frame_defaults.offset);
- const auto& dir = atlas.directions[(size_t)Direction_::W];
- fm_assert(dir.side.pixel_size != group_defaults.pixel_size);
- fm_assert(dir.side.from_rotation == group_defaults.from_rotation);
- fm_assert(dir.corner_L.from_rotation != group_defaults.from_rotation);
- fm_assert(dir.corner_L.from_rotation == (uint8_t)Direction_::N);
- }
+ fm_assert(!atlas.frames.isEmpty());
+ fm_assert(atlas.frames[0].offset != frame_defaults.offset);
+ auto dir_index = atlas.direction_to_Direction_array_index[(size_t)Direction_::W];
+ fm_assert(dir_index);
+ const auto& dir = atlas.direction_array[dir_index.val];
+ fm_assert(dir.side.pixel_size != group_defaults.pixel_size);
+ fm_assert(dir.side.from_rotation == group_defaults.from_rotation);
+ fm_assert(dir.corner_L.from_rotation != group_defaults.from_rotation);
+ fm_assert(dir.corner_L.from_rotation == (uint8_t)Direction_::N);
return atlas;
}
-void write_to_temp_file(const wall_atlas_& atlas)
+void write_to_temp_file(const wall_atlas_def& atlas)
{
- auto jroot = json{};
-
- write_info_header(jroot, atlas.header);
- write_all_frames(jroot, atlas.frames);
-
- for (const auto [name_, dir] : wall_atlas::directions)
- {
- std::string_view name = {name_.data(), name_.size()};
- auto i = (size_t)dir;
- if (atlas.directions[i])
- write_direction_metadata(jroot[name], atlas.directions[i]);
- }
-
- const auto filename = temp_filename();
- json_helper::to_json_(jroot, filename);
-}
-
-bool wall_atlas_::operator==(const wall_atlas_& other) const noexcept
-{
- if (header != other.header)
- return false;
- if (directions != other.directions)
- return false;
- if (frames.size() != other.frames.size())
- return false;
- for (auto i = 0uz; i < frames.size(); i++)
- if (frames[i] != other.frames[i])
- return false;
- return true;
+ atlas.serialize(temp_filename());
}
} // namespace
@@ -182,17 +111,15 @@ void floormat::test_app::test_wall_atlas()
constexpr auto S_01_header_json = "wall-atlas-01_header.json"_s,
S_02_groups_json = "wall-atlas-02_groups.json"_s;
- { test_read_header(S_01_header_json);
- test_read_empty_directions(S_01_header_json);
- }
+ test_read_header(S_01_header_json);
{ test_read_header(S_02_groups_json);
test_read_groups(S_02_groups_json);
}
- { auto a = read_from_file(Path::join(json_path(), S_02_groups_json));
- write_to_temp_file(a);
- auto b = read_from_file(temp_filename());
+ { auto a = read_and_check(Path::join(json_path(), S_02_groups_json));
+ a.serialize(temp_filename());
+ auto b = read_and_check(temp_filename());
fm_assert(a == b);
}
}