diff options
-rw-r--r-- | editor/app.cpp | 8 | ||||
-rw-r--r-- | editor/tile-editor.cpp | 10 | ||||
-rw-r--r-- | images/floor.json | 30 | ||||
-rw-r--r-- | images/wall.json | 30 | ||||
-rw-r--r-- | loader/atlas.cpp | 14 | ||||
-rw-r--r-- | loader/impl.hpp | 3 | ||||
-rw-r--r-- | loader/json.cpp | 10 | ||||
-rw-r--r-- | loader/loader.hpp | 6 | ||||
-rw-r--r-- | serialize/tile-atlas.cpp | 37 | ||||
-rw-r--r-- | serialize/world-reader.cpp | 4 | ||||
-rw-r--r-- | src/tile-atlas.cpp | 13 | ||||
-rw-r--r-- | src/tile-atlas.hpp | 9 | ||||
-rw-r--r-- | test/json.cpp | 8 | ||||
-rw-r--r-- | test/serializer.cpp | 6 |
14 files changed, 144 insertions, 44 deletions
diff --git a/editor/app.cpp b/editor/app.cpp index ed374dd8..ed1bac7b 100644 --- a/editor/app.cpp +++ b/editor/app.cpp @@ -12,10 +12,10 @@ namespace floormat { app::app(fm_settings&& opts) : M{floormat_main::create(*this, std::move(opts))}, - _floor1{loader.tile_atlas("floor-tiles", {44, 4})}, - _floor2{loader.tile_atlas("metal1", {2, 2})}, - _wall1{loader.tile_atlas("wood2", {2, 1})}, - _wall2{loader.tile_atlas("wood1", {2, 1})}, + _floor1{loader.tile_atlas("floor-tiles", {44, 4}, pass_mode::pass)}, + _floor2{loader.tile_atlas("metal1", {2, 2}, pass_mode::pass)}, + _wall1{loader.tile_atlas("wood2", {2, 1}, pass_mode::blocked)}, + _wall2{loader.tile_atlas("wood1", {2, 1}, pass_mode::blocked)}, _door{loader.anim_atlas("door-close", loader.SCENERY_PATH)}, _table{loader.anim_atlas("table", loader.SCENERY_PATH)}, _control_panel(loader.anim_atlas("control-panel", loader.SCENERY_PATH)) diff --git a/editor/tile-editor.cpp b/editor/tile-editor.cpp index d5743220..ffee3b66 100644 --- a/editor/tile-editor.cpp +++ b/editor/tile-editor.cpp @@ -16,8 +16,16 @@ tile_editor::tile_editor(editor_mode mode, StringView name) : _name{name}, _mode void tile_editor::load_atlases() { + pass_mode default_pass_mode; + switch (_mode) + { + case editor_mode::floor: default_pass_mode = pass_mode::pass; break; + case editor_mode::walls: default_pass_mode = pass_mode::blocked; break; + default: default_pass_mode = pass_mode::see_through; break; + } + const auto filename = _name + ".json"; - for (const auto& atlas : loader.tile_atlases(filename)) + for (const auto& atlas : loader.tile_atlases(filename, default_pass_mode)) { const auto [name, _ext] = Path::splitExtension(atlas->name()); auto& [_, vec] = _permutation; diff --git a/images/floor.json b/images/floor.json index eff4f153..2fee595f 100644 --- a/images/floor.json +++ b/images/floor.json @@ -1,8 +1,26 @@ [ - ["floor-tiles", "44 x 4"], - ["metal1", "2 x 2"], - ["tiles", "8 x 5"], - ["wood2", "1 x 1"], - ["concrete6", "4 x 4"], - ["texel", "2 x 2"] + { + "name": "floor-tiles", + "size": "44 x 4" + }, + { + "name": "tiles", + "size": "8 x 5" + }, + { + "name": "wood2", + "size": "1 x 1" + }, + { + "name": "concrete6", + "size": "4 x 4" + }, + { + "name": "texel", + "size": "2 x 2" + }, + { + "name": "metal1", + "size": "2 x 2" + } ] diff --git a/images/wall.json b/images/wall.json index 5824513f..12a3d13e 100644 --- a/images/wall.json +++ b/images/wall.json @@ -1,8 +1,26 @@ [ - ["wood2", "2 x 2"], - ["wood1", "2 x 2"], - ["teak1", "2 x 2"], - ["metal2", "2 x 2"], - ["concrete7", "4 x 4"], - ["concrete6", "4 x 4"] + { + "name": "wood2", + "size": "2 x 2" + }, + { + "name": "wood1", + "size": "2 x 2" + }, + { + "name": "teak1", + "size": "2 x 2" + }, + { + "name": "metal2", + "size": "2 x 2" + }, + { + "name": "concrete7", + "size": "4 x 4" + }, + { + "name": "concrete6", + "size": "4 x 4" + } ] diff --git a/loader/atlas.cpp b/loader/atlas.cpp index f285d3b1..1354e922 100644 --- a/loader/atlas.cpp +++ b/loader/atlas.cpp @@ -14,15 +14,25 @@ namespace floormat::loader_detail { -std::shared_ptr<tile_atlas> loader_impl::tile_atlas(StringView name, Vector2ub size) noexcept(false) +std::shared_ptr<tile_atlas> loader_impl::tile_atlas(StringView name, Vector2ub size, Optional<pass_mode> pass) noexcept(false) { fm_soft_assert(check_atlas_name(name)); - const emplacer e{[&] { return std::make_shared<struct tile_atlas>(name, texture(IMAGE_PATH, name), size); }}; + const emplacer e{[&] { return std::make_shared<struct tile_atlas>(name, texture(IMAGE_PATH, name), size, pass); }}; auto atlas = tile_atlas_map.try_emplace(name, e).first->second; + fm_soft_assert(!pass || pass == atlas->pass_mode()); return atlas; } +std::shared_ptr<struct tile_atlas> loader_impl::tile_atlas(StringView filename) noexcept(false) +{ + fm_assert(!tile_atlas_map.empty()); + auto it = tile_atlas_map.find(filename); + if (it == tile_atlas_map.end()) + fm_throw("no such tile atlas '{}'"_cf, filename.data()); + return it->second; +} + ArrayView<String> loader_impl::anim_atlas_list() { if (anim_atlases.empty()) diff --git a/loader/impl.hpp b/loader/impl.hpp index c50cb1d7..673460aa 100644 --- a/loader/impl.hpp +++ b/loader/impl.hpp @@ -30,7 +30,8 @@ struct loader_impl final : loader_ StringView shader(StringView filename) noexcept override; Trade::ImageData2D texture(StringView prefix, StringView filename) noexcept(false); - std::shared_ptr<struct tile_atlas> tile_atlas(StringView filename, Vector2ub size) 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; ArrayView<String> anim_atlas_list() override; std::shared_ptr<struct anim_atlas> anim_atlas(StringView name, StringView dir) noexcept(false) override; const std::vector<serialized_scenery>& sceneries() override; diff --git a/loader/json.cpp b/loader/json.cpp index dbe21d50..7e6aae68 100644 --- a/loader/json.cpp +++ b/loader/json.cpp @@ -1,6 +1,7 @@ #include "impl.hpp" #include "compat/assert.hpp" #include "compat/exception.hpp" +#include "src/tile-atlas.hpp" #include "serialize/json-helper.hpp" #include "serialize/anim.hpp" #include "serialize/tile-atlas.hpp" @@ -52,9 +53,14 @@ 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) +std::vector<std::shared_ptr<struct tile_atlas>> loader_::tile_atlases(StringView filename, pass_mode p) { - return json_helper::from_json<std::vector<std::shared_ptr<struct tile_atlas>>>(Path::join(loader_::IMAGE_PATH, filename)); + auto vec = json_helper::from_json<std::vector<std::shared_ptr<struct tile_atlas>>>( + Path::join(loader_::IMAGE_PATH, filename)); + for (auto& x : vec) + if (!x->pass_mode()) + x->set_pass_mode(p); + return vec; } } // namespace floormat diff --git a/loader/loader.hpp b/loader/loader.hpp index 8883ed8a..1189a02d 100644 --- a/loader/loader.hpp +++ b/loader/loader.hpp @@ -1,4 +1,5 @@ #pragma once +#include "src/pass-mode.hpp" #include <memory> #include <vector> #include <Corrade/Containers/StringView.h> @@ -15,12 +16,13 @@ struct scenery_proto; struct loader_ { virtual StringView shader(StringView filename) noexcept = 0; - virtual std::shared_ptr<struct tile_atlas> tile_atlas(StringView filename, Vector2ub size) noexcept(false) = 0; + 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 ArrayView<String> anim_atlas_list() = 0; virtual std::shared_ptr<struct anim_atlas> anim_atlas(StringView name, StringView dir = ANIM_PATH) noexcept(false) = 0; static void destroy(); static loader_& default_loader() noexcept; - static std::vector<std::shared_ptr<struct tile_atlas>> tile_atlases(StringView filename); + static std::vector<std::shared_ptr<struct 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; diff --git a/serialize/tile-atlas.cpp b/serialize/tile-atlas.cpp index a92dfc28..6a51da4c 100644 --- a/serialize/tile-atlas.cpp +++ b/serialize/tile-atlas.cpp @@ -3,12 +3,25 @@ #include "serialize/corrade-string.hpp" #include "serialize/magnum-vector2i.hpp" #include "loader/loader.hpp" -#include <tuple> - +#include "serialize/pass-mode.hpp" +#include <Corrade/Containers/Optional.h> +#include <Corrade/Containers/String.h> #include <nlohmann/json.hpp> using namespace floormat; +namespace { + +struct proxy { + String name; + Vector2ub size; + Optional<pass_mode> passability; +}; + +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(proxy, name, size) + +} // namespace + namespace nlohmann { void adl_serializer<std::shared_ptr<tile_atlas>>::to_json(json& j, const std::shared_ptr<const tile_atlas>& x) @@ -17,18 +30,26 @@ void adl_serializer<std::shared_ptr<tile_atlas>>::to_json(json& j, const std::sh if (!x) j = nullptr; else - to_json(j, std::tuple<StringView, Vector2ub>{x->name(), x->num_tiles2()}); + { + to_json(j, proxy{x->name(), x->num_tiles2(), NullOpt}); + if (auto p = x->pass_mode()) + j["pass-mode"] = *p; + } } -void adl_serializer<std::shared_ptr<tile_atlas>>::from_json(const json& j, std::shared_ptr<tile_atlas>& x) +void adl_serializer<std::shared_ptr<tile_atlas>>::from_json(const json& j, std::shared_ptr<tile_atlas>& val) { if (j.is_null()) - x = nullptr; + val = nullptr; else { - std::tuple<String, Vector2ub> proxy = j; - const auto& [name, num_tiles] = proxy; - x = loader.tile_atlas(name, num_tiles); + using nlohmann::from_json; + proxy x; + from_json(j, x); + Optional<pass_mode> p; + if (j.contains("pass-mode")) + p = {InPlaceInit, j["pass-mode"]}; + val = loader.tile_atlas(x.name, x.size, p); } } diff --git a/serialize/world-reader.cpp b/serialize/world-reader.cpp index b0e14254..98704599 100644 --- a/serialize/world-reader.cpp +++ b/serialize/world-reader.cpp @@ -45,7 +45,9 @@ void reader_state::read_atlases(reader_t& s) size[0] << s; size[1] << s; const auto& [buf, len] = s.read_asciiz_string<atlas_name_max>(); - atlases.push_back(loader.tile_atlas({buf, len}, size)); + auto atlas = loader.tile_atlas({buf, len}); + fm_soft_assert(size == atlas->num_tiles2()); + atlases.push_back(std::move(atlas)); } } diff --git a/src/tile-atlas.cpp b/src/tile-atlas.cpp index 9b3886da..6f9e832f 100644 --- a/src/tile-atlas.cpp +++ b/src/tile-atlas.cpp @@ -9,9 +9,9 @@ namespace floormat { -tile_atlas::tile_atlas(StringView name, const ImageView2D& image, Vector2ub tile_count) : +tile_atlas::tile_atlas(StringView name, const ImageView2D& image, Vector2ub tile_count, Optional<enum pass_mode> p) : texcoords_{make_texcoords_array(Vector2ui(image.size()), tile_count)}, - name_{name}, size_{image.size()}, dims_{tile_count} + name_{name}, size_{image.size()}, dims_{tile_count}, passability{std::move(p)} { constexpr auto variant_max = std::numeric_limits<variant_t>::max(); fm_assert(num_tiles() <= variant_max); @@ -55,4 +55,13 @@ auto tile_atlas::make_texcoords_array(Vector2ui pixel_size, Vector2ub tile_count return ptr; } +std::size_t tile_atlas::num_tiles() const { return Vector2ui{dims_}.product(); } +Optional<enum pass_mode> tile_atlas::pass_mode() const { return passability; } + +void tile_atlas::set_pass_mode(enum pass_mode p) +{ + fm_assert(!passability || passability == p); + passability = { InPlaceInit, p }; +} + } // namespace floormat diff --git a/src/tile-atlas.hpp b/src/tile-atlas.hpp index 066b1122..61f528ef 100644 --- a/src/tile-atlas.hpp +++ b/src/tile-atlas.hpp @@ -1,6 +1,8 @@ #pragma once +#include "src/pass-mode.hpp" #include <array> #include <memory> +#include <Corrade/Containers/Optional.h> #include <Corrade/Containers/String.h> #include <Magnum/Magnum.h> #include <Magnum/Math/Vector2.h> @@ -13,7 +15,7 @@ struct tile_atlas final using quad = std::array<Vector3, 4>; using texcoords = std::array<Vector2, 4>; - tile_atlas(StringView name, const ImageView2D& img, Vector2ub tile_count); + tile_atlas(StringView name, const ImageView2D& img, Vector2ub tile_count, Optional<enum pass_mode> pass_mode); texcoords texcoords_for_id(std::size_t id) const; static constexpr quad floor_quad(Vector3 center, Vector2 size); @@ -21,10 +23,12 @@ struct tile_atlas final static constexpr quad wall_quad_W(Vector3 center, Vector3 size); static constexpr std::array<UnsignedShort, 6> indices(std::size_t N); [[maybe_unused]] Vector2ui pixel_size() const { return size_; } - std::size_t num_tiles() const { return Vector2ui{dims_}.product(); } + std::size_t num_tiles() const; Vector2ub num_tiles2() const { return dims_; } GL::Texture2D& texture() { return tex_; } StringView name() const { return name_; } + Optional<enum pass_mode> pass_mode() const; + void set_pass_mode(enum pass_mode p); private: static std::unique_ptr<const texcoords[]> make_texcoords_array(Vector2ui pixel_size, Vector2ub tile_count); @@ -35,6 +39,7 @@ private: String name_; Vector2ui size_; Vector2ub dims_; + Optional<enum pass_mode> passability; }; constexpr std::array<UnsignedShort, 6> tile_atlas::indices(std::size_t N) diff --git a/test/json.cpp b/test/json.cpp index 1ef6feb8..60e464f6 100644 --- a/test/json.cpp +++ b/test/json.cpp @@ -16,9 +16,9 @@ namespace floormat { [[maybe_unused]] static chunk make_test_chunk() { - auto metal1 = loader.tile_atlas("metal1", {2, 2}), - metal2 = loader.tile_atlas("metal2", {2, 2}), - tiles = loader.tile_atlas("tiles", {8, 5}); + auto metal1 = loader.tile_atlas("metal1", {2, 2}, pass_mode::pass), + metal2 = loader.tile_atlas("metal2", {2, 2}, pass_mode::blocked), + tiles = loader.tile_atlas("tiles", {8, 5}, pass_mode::pass); constexpr auto N = TILE_MAX_DIM; chunk c; for (auto [x, k, pt] : c) { @@ -37,7 +37,7 @@ void test_app::test_json() // NOLINT(readability-convert-member-functions-to-sta fm_assert(Path::exists("../CMakeCache.txt")); constexpr auto output_dir = "../test/."_s; { - auto atlas = loader.tile_atlas("metal1", {2, 2}); + auto atlas = loader.tile_atlas("metal1", {2, 2}, pass_mode::pass); json_helper::to_json(atlas, Path::join(output_dir, "atlas.json")); } { diff --git a/test/serializer.cpp b/test/serializer.cpp index 8a22d0e5..9f382602 100644 --- a/test/serializer.cpp +++ b/test/serializer.cpp @@ -11,9 +11,9 @@ namespace Path = Corrade::Utility::Path; static chunk make_test_chunk() { - auto metal1 = loader.tile_atlas("metal1", {2, 2}), - metal2 = loader.tile_atlas("metal2", {2, 2}), - tiles = loader.tile_atlas("tiles", {8, 5}); + auto metal1 = loader.tile_atlas("metal1", {2, 2}, pass_mode::pass), + metal2 = loader.tile_atlas("metal2", {2, 2}, pass_mode::blocked), + tiles = loader.tile_atlas("tiles", {8, 5}, pass_mode::pass); constexpr auto N = TILE_MAX_DIM; chunk c; for (auto [x, k, pt] : c) |