diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2022-11-01 16:35:03 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2022-11-01 16:35:03 +0100 |
commit | 704e9bd3ac58484a5209e186798076f1cbd432ef (patch) | |
tree | 511479ebd088d5c9524803c6f3fe4641009b58bc | |
parent | 7ff1f0911e0b0c314d6e639887b705d6fc0d78aa (diff) |
wip
-rw-r--r-- | draw/floor.cpp | 12 | ||||
-rw-r--r-- | draw/floor.hpp | 6 | ||||
-rw-r--r-- | draw/wall.cpp | 11 | ||||
-rw-r--r-- | draw/wall.hpp | 8 | ||||
-rw-r--r-- | editor/editor.cpp | 28 | ||||
-rw-r--r-- | editor/editor.hpp | 12 | ||||
-rw-r--r-- | editor/update.cpp | 10 | ||||
-rw-r--r-- | floormat/events.hpp | 1 | ||||
-rw-r--r-- | serialize/tile.cpp | 10 | ||||
-rw-r--r-- | serialize/tile.hpp | 8 | ||||
-rw-r--r-- | serialize/world-impl.hpp | 8 | ||||
-rw-r--r-- | serialize/world-reader.cpp | 20 | ||||
-rw-r--r-- | serialize/world-writer.cpp | 39 | ||||
-rw-r--r-- | src/chunk.cpp | 6 | ||||
-rw-r--r-- | src/chunk.hpp | 26 | ||||
-rw-r--r-- | src/local-coords.hpp | 2 | ||||
-rw-r--r-- | src/tile-atlas.cpp | 3 | ||||
-rw-r--r-- | src/tile-image.cpp | 17 | ||||
-rw-r--r-- | src/tile-image.hpp | 8 | ||||
-rw-r--r-- | src/tile-iterator.cpp | 8 | ||||
-rw-r--r-- | src/tile-iterator.hpp | 10 | ||||
-rw-r--r-- | src/tile.cpp | 32 | ||||
-rw-r--r-- | src/tile.hpp | 15 | ||||
-rw-r--r-- | src/world.hpp | 2 | ||||
-rw-r--r-- | test/json.cpp | 12 | ||||
-rw-r--r-- | test/serializer.cpp | 12 | ||||
-rw-r--r-- | test/tile-iter.cpp | 10 |
27 files changed, 180 insertions, 156 deletions
diff --git a/draw/floor.cpp b/draw/floor.cpp index 444ee127..861336c7 100644 --- a/draw/floor.cpp +++ b/draw/floor.cpp @@ -17,11 +17,11 @@ floor_mesh::floor_mesh() .setIndexBuffer(_index_buffer, 0, GL::MeshIndexType::UnsignedShort); } -void floor_mesh::set_tile(quad_data& data, tile& x) +void floor_mesh::set_tile(quad_data& data, tile_ref& x) { - if (x.ground) + if (auto ground = x.ground(); ground) { - auto texcoords = x.ground.atlas->texcoords_for_id(x.ground.variant); + auto texcoords = ground.atlas->texcoords_for_id(ground.variant); for (size_t i = 0; i < 4; i++) data[i] = { texcoords[i] }; } @@ -34,7 +34,7 @@ void floor_mesh::draw(tile_shader& shader, chunk& c) { //_vertex_buffer.setData({nullptr, sizeof(quad_data) * TILE_COUNT}, Magnum::GL::BufferUsage::DynamicDraw); // orphan the buffer std::array<quad_data, TILE_COUNT> data; - for (auto& [x, idx, pt] : c) { + for (auto [x, idx, pt] : c) { set_tile(data[idx], x); } _vertex_buffer.setSubData(0, data); @@ -57,8 +57,8 @@ void floor_mesh::draw(tile_shader& shader, chunk& c) last_pos = i; }; - for (auto& [x, i, pt] : c) - do_draw(i, x.ground.atlas.get()); + for (auto [x, i, pt] : c) + do_draw(i, x.ground_atlas().get()); do_draw(TILE_COUNT, nullptr); } diff --git a/draw/floor.hpp b/draw/floor.hpp index 4a273dfc..4ece92eb 100644 --- a/draw/floor.hpp +++ b/draw/floor.hpp @@ -10,10 +10,10 @@ namespace floormat { -struct tile_shader; -struct chunk; struct tile_ref; struct tile_proto; +struct tile_shader; +struct chunk; struct floor_mesh final { @@ -34,7 +34,7 @@ private: GL::Buffer _vertex_buffer{std::array<quad_data, TILE_COUNT>{}, Magnum::GL::BufferUsage::DynamicDraw}, _index_buffer{make_index_array()}, _positions_buffer{make_position_array()}; - static void set_tile(quad_data& data, tile& x); + static void set_tile(quad_data& data, tile_ref& x); }; } // namespace floormat diff --git a/draw/wall.cpp b/draw/wall.cpp index 4602453d..18462e2c 100644 --- a/draw/wall.cpp +++ b/draw/wall.cpp @@ -2,6 +2,7 @@ #include "tile-atlas.hpp" #include "shaders/tile.hpp" #include "chunk.hpp" +#include "tile-image.hpp" #include <Magnum/GL/Texture.h> #include <Magnum/GL/MeshView.h> @@ -18,7 +19,7 @@ wall_mesh::wall_mesh() CORRADE_INTERNAL_ASSERT(_mesh.isIndexed()); } -void wall_mesh::add_wall(vertex_array& data, texture_array& textures, tile_image& img, std::size_t pos) +void wall_mesh::add_wall(vertex_array& data, texture_array& textures, const tile_image_ref& img, std::size_t pos) { CORRADE_INTERNAL_ASSERT(pos < data.size()); auto texcoords = img.atlas->texcoords_for_id(img.variant); @@ -29,11 +30,11 @@ void wall_mesh::add_wall(vertex_array& data, texture_array& textures, tile_image } } -void wall_mesh::maybe_add_tile(vertex_array& data, texture_array& textures, tile& x, std::size_t pos) +void wall_mesh::maybe_add_tile(vertex_array& data, texture_array& textures, tile_ref x, std::size_t pos) { - if (auto& wall = x.wall_north; wall.atlas) + if (auto wall = x.wall_north(); wall.atlas) add_wall(data, textures, wall, pos * 2 + 0); - if (auto& wall = x.wall_west; wall.atlas) + if (auto wall = x.wall_west(); wall.atlas) add_wall(data, textures, wall, pos * 2 + 1); } @@ -43,7 +44,7 @@ void wall_mesh::draw(tile_shader& shader, chunk& c) texture_array textures = {}; { vertex_array data; - for (auto& [x, idx, pt] : c) { + for (auto [x, idx, pt] : c) { maybe_add_tile(data, textures, x, idx); } _vertex_buffer.setSubData(0, data); diff --git a/draw/wall.hpp b/draw/wall.hpp index 06d99842..ad1eafad 100644 --- a/draw/wall.hpp +++ b/draw/wall.hpp @@ -10,10 +10,10 @@ namespace floormat { -struct tile; -struct tile_image; struct tile_shader; struct chunk; +struct tile_ref; +struct tile_image_ref; struct wall_mesh final { @@ -31,8 +31,8 @@ private: using vertex_array = std::array<quad, COUNT>; using texture_array = std::array<GL::Texture2D*, COUNT>; - static void maybe_add_tile(vertex_array& data, texture_array& textures, tile& x, std::size_t pos); - static void add_wall(vertex_array& data, texture_array& textures, tile_image& img, std::size_t pos); + static void maybe_add_tile(vertex_array& data, texture_array& textures, tile_ref x, std::size_t pos); + static void add_wall(vertex_array& data, texture_array& textures, const tile_image_ref& img, std::size_t pos); GL::Mesh _mesh; GL::Buffer _vertex_buffer{vertex_array{}, Magnum::GL::BufferUsage::DynamicDraw}, diff --git a/editor/editor.cpp b/editor/editor.cpp index fc2d1a1f..3d2ee3a6 100644 --- a/editor/editor.cpp +++ b/editor/editor.cpp @@ -68,7 +68,7 @@ void tile_editor::select_tile(const std::shared_ptr<tile_atlas>& atlas, std::siz fm_assert(atlas); clear_selection(); _selection_mode = sel_tile; - _selected_tile = { atlas, decltype(tile_image::variant)(variant % atlas->num_tiles()) }; + _selected_tile = { atlas, variant_t(variant % atlas->num_tiles()) }; } void tile_editor::select_tile_permutation(const std::shared_ptr<tile_atlas>& atlas) @@ -117,10 +117,9 @@ void fisher_yates(T begin, T end) } } -tile_image tile_editor::get_selected_perm() +tile_image_proto tile_editor::get_selected_perm() { auto& [atlas, vec] = _permutation; - using variant_t = decltype(tile_image::variant); const auto N = (variant_t)atlas->num_tiles(); if (N == 0) return {}; @@ -135,7 +134,7 @@ tile_image tile_editor::get_selected_perm() return {atlas, idx}; } -tile_image tile_editor::get_selected() +tile_image_proto tile_editor::get_selected() { switch (_selection_mode) { @@ -151,25 +150,26 @@ tile_image tile_editor::get_selected() } } -void tile_editor::place_tile(world& world, global_coords pos, tile_image& img) +void tile_editor::place_tile(world& world, global_coords pos, const tile_image_proto& img) { - const auto& [c, t] = world[pos]; + auto [c, t] = world[pos]; const auto& [atlas, variant] = img; switch (_mode) { - default: - fm_warn_once("invalid editor mode '%u'", (unsigned)_mode); - break; case editor_mode::none: break; case editor_mode::floor: - t.ground = { atlas, variant }; + t.ground() = img; break; case editor_mode::walls: - switch (tile_image x = { atlas, variant }; _rotation) + switch (_rotation) { - case editor_wall_rotation::N: t.wall_north = x; break; - case editor_wall_rotation::W: t.wall_west = x; break; + case editor_wall_rotation::N: + t.wall_north() = img; + break; + case editor_wall_rotation::W: + t.wall_west() = img; + break; } break; } @@ -307,7 +307,7 @@ void editor::on_click(world& world, global_coords pos, int mods, button b) if (auto opt = mode->get_selected(); opt) { _last_pos = { pos, mode->check_snap(mods), _last_pos ? _last_pos->btn : b }; - switch (tile_image empty; b) + switch (tile_image_proto empty; b) { case button::place: return mode->place_tile(world, pos, opt); case button::remove: return mode->place_tile(world, pos, empty); diff --git a/editor/editor.hpp b/editor/editor.hpp index 460bb8c8..dda13567 100644 --- a/editor/editor.hpp +++ b/editor/editor.hpp @@ -2,7 +2,7 @@ #include "compat/defs.hpp" #include "tile-atlas.hpp" #include "global-coords.hpp" -#include "tile-image.hpp" +#include "tile.hpp" #include <cstdint> #include <tuple> @@ -34,14 +34,14 @@ private: std::string _name; std::map<std::string, std::shared_ptr<tile_atlas>> _atlases; - tile_image _selected_tile; - std::tuple<std::shared_ptr<tile_atlas>, std::vector<decltype(tile_image::variant)>> _permutation; + tile_image_proto _selected_tile; + std::tuple<std::shared_ptr<tile_atlas>, std::vector<decltype(tile_image_proto::variant)>> _permutation; selection_mode _selection_mode = sel_none; editor_mode _mode; editor_wall_rotation _rotation = editor_wall_rotation::W; void load_atlases(); - tile_image get_selected_perm(); + tile_image_proto get_selected_perm(); public: enum class snap_mode : std::uint8_t { @@ -68,8 +68,8 @@ public: bool is_tile_selected(const std::shared_ptr<const tile_atlas>& atlas, std::size_t variant) const; bool is_permutation_selected(const std::shared_ptr<const tile_atlas>& atlas) const; bool is_atlas_selected(const std::shared_ptr<const tile_atlas>& atlas) const; - tile_image get_selected(); - void place_tile(world& world, global_coords pos, tile_image& img); + tile_image_proto get_selected(); + void place_tile(world& world, global_coords pos, const tile_image_proto& img); void toggle_rotation(); void set_rotation(editor_wall_rotation r); snap_mode check_snap(int mods) const; diff --git a/editor/update.cpp b/editor/update.cpp index b96d80fe..adca9492 100644 --- a/editor/update.cpp +++ b/editor/update.cpp @@ -18,16 +18,16 @@ void app::maybe_initialize_chunk_(const chunk_coords& pos, chunk& c) #else const auto& atlas = pt.x == N/2 || pt.y == N/2 ? _floor2 : _floor1; #endif - x.ground = { atlas, decltype(tile_image::variant)(k % atlas->num_tiles()) }; + x.ground() = { atlas, variant_t(k % atlas->num_tiles()) }; } #ifdef FM_NO_BINDINGS const auto& wall1 = floor1, wall2 = floor1; #endif constexpr auto K = N/2; - c[{K, K }].wall_north = { _wall1, 0 }; - c[{K, K }].wall_west = { _wall2, 0 }; - c[{K, K+1}].wall_north = { _wall1, 0 }; - c[{K+1, K }].wall_west = { _wall2, 0 }; + c[{K, K }].wall_north() = { _wall1, 0 }; + c[{K, K }].wall_west() = { _wall2, 0 }; + c[{K, K+1}].wall_north() = { _wall1, 0 }; + c[{K+1, K }].wall_west() = { _wall2, 0 }; } void app::maybe_initialize_chunk([[maybe_unused]] const chunk_coords& pos, [[maybe_unused]] chunk& c) diff --git a/floormat/events.hpp b/floormat/events.hpp index 6ab1b3ae..597c89b2 100644 --- a/floormat/events.hpp +++ b/floormat/events.hpp @@ -47,7 +47,6 @@ struct key_event final { }; union alignas(alignof(void*)) any_event { - std::size_t size[0] = {}; char buf[64]; }; diff --git a/serialize/tile.cpp b/serialize/tile.cpp index 68def2d8..abce91e1 100644 --- a/serialize/tile.cpp +++ b/serialize/tile.cpp @@ -6,7 +6,11 @@ namespace floormat { -NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(tile_image, atlas, variant) +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(tile_image_proto, atlas, variant) + +inline void to_json(nlohmann::json& j, const tile_image_ref& val) { j = tile_image_proto(val); } +inline void from_json(const nlohmann::json& j, tile_image_ref& val) { val = tile_image_proto(j); } + NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(local_coords, x, y) NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(chunk_coords, x, y) @@ -23,8 +27,8 @@ using namespace floormat; namespace nlohmann { -void adl_serializer<tile_image>::to_json(json& j, const tile_image& val) { using nlohmann::to_json; if (val.atlas) to_json(j, val); else j = nullptr; } -void adl_serializer<tile_image>::from_json(const json& j, tile_image& val) { using nlohmann::from_json; if (j.is_null()) val = {}; else from_json(j, val); } +void adl_serializer<tile_image_ref>::to_json(json& j, const tile_image_ref& val) { using nlohmann::to_json; if (val.atlas) to_json(j, val); else j = nullptr; } +void adl_serializer<tile_image_ref>::from_json(const json& j, tile_image_ref& val) { using nlohmann::from_json; if (j.is_null()) val = {}; else from_json(j, val); } void adl_serializer<local_coords>::to_json(json& j, const local_coords& val) { using nlohmann::to_json; to_json(j, val); } void adl_serializer<local_coords>::from_json(const json& j, local_coords& val) { using nlohmann::from_json; from_json(j, val); } diff --git a/serialize/tile.hpp b/serialize/tile.hpp index 1d629fe6..66982682 100644 --- a/serialize/tile.hpp +++ b/serialize/tile.hpp @@ -3,7 +3,7 @@ namespace floormat { -struct tile_image; +struct tile_image_ref; struct local_coords; struct chunk_coords; struct global_coords; @@ -13,9 +13,9 @@ struct global_coords; namespace nlohmann { template<> -struct adl_serializer<floormat::tile_image> { - static void to_json(json& j, const floormat::tile_image& val); - static void from_json(const json& j, floormat::tile_image& val); +struct adl_serializer<floormat::tile_image_ref> { + static void to_json(json& j, const floormat::tile_image_ref& val); + static void from_json(const json& j, floormat::tile_image_ref& val); }; template<> diff --git a/serialize/world-impl.hpp b/serialize/world-impl.hpp index a0414606..caf5e8a7 100644 --- a/serialize/world-impl.hpp +++ b/serialize/world-impl.hpp @@ -12,10 +12,10 @@ namespace floormat::Serialize { namespace { using tilemeta = std::uint8_t; -using varid = decltype(tile_image::variant); +using varid = decltype(tile_image_proto::variant); using atlasid = std::uint16_t; using chunksiz = std::uint16_t; -using enum tile::pass_mode; +using proto_t = std::uint16_t; template<typename T> constexpr inline T int_max = std::numeric_limits<T>::max(); @@ -24,10 +24,10 @@ template<typename T> constexpr inline T int_max = std::numeric_limits<T>::max(); constexpr inline std::size_t atlas_name_max = 128; constexpr inline auto null_atlas = (atlasid)-1LL; -constexpr inline std::uint16_t proto_version = 1; +constexpr inline proto_t proto_version = 1; constexpr inline auto chunk_magic = (std::uint16_t)~0xc0d3; -constexpr inline std::underlying_type_t<tile::pass_mode> pass_mask = pass_blocked | pass_shoot_through | pass_ok; +constexpr inline std::underlying_type_t<pass_mode> pass_mask = pass_blocked | pass_shoot_through | pass_ok; constexpr inline auto pass_bits = std::bit_width(pass_mask); enum : tilemeta { diff --git a/serialize/world-reader.cpp b/serialize/world-reader.cpp index 385d6e39..aa156609 100644 --- a/serialize/world-reader.cpp +++ b/serialize/world-reader.cpp @@ -65,9 +65,9 @@ void reader_state::read_chunks(reader_t& s) for (std::size_t i = 0; i < TILE_COUNT; i++) { const tilemeta flags = s.read<tilemeta>(); - tile& t = chunk[i]; + tile_ref t = chunk[i]; using uchar = std::uint8_t; - const auto make_atlas = [&]() -> tile_image { + const auto make_atlas = [&]() -> tile_image_proto { auto id = flags & meta_short_atlasid ? (atlasid)(s.read<uchar>()) : s.read<atlasid>(); auto v = flags & meta_short_variant ? (varid) (s.read<uchar>()) : s.read<varid>(); auto atlas = lookup_atlas(id); @@ -76,18 +76,18 @@ void reader_state::read_chunks(reader_t& s) }; if (flags & meta_ground) - t.ground = make_atlas(); + t.ground() = make_atlas(); if (flags & meta_wall_n) - t.wall_north = make_atlas(); + t.wall_north() = make_atlas(); if (flags & meta_wall_w) - t.wall_west = make_atlas(); + t.wall_west() = make_atlas(); - switch (auto x = flags & pass_mask) + switch (auto x = pass_mode(flags & pass_mask)) { - case tile::pass_shoot_through: - case tile::pass_blocked: - case tile::pass_ok: - t.passability = (tile::pass_mode)x; + case pass_shoot_through: + case pass_blocked: + case pass_ok: + t.pass_mode() = x; break; default: fm_abort("bad pass mode '%zu' for tile %zu", i, (std::size_t)x); diff --git a/serialize/world-writer.cpp b/serialize/world-writer.cpp index a55e6eb1..c16dc32a 100644 --- a/serialize/world-writer.cpp +++ b/serialize/world-writer.cpp @@ -29,8 +29,8 @@ struct writer_state final { fm_DECLARE_DEPRECATED_COPY_ASSIGNMENT(writer_state); private: - atlasid intern_atlas(const tile_image& img); - atlasid maybe_intern_atlas(const tile_image& img); + atlasid intern_atlas(const tile_image_proto& img); + atlasid maybe_intern_atlas(const tile_image_proto& img); void serialize_chunk(const chunk& c, chunk_coords coord); void serialize_atlases(); @@ -66,7 +66,7 @@ writer_state::writer_state(const struct world& world) : world{&world} #pragma warning(pop) #endif -atlasid writer_state::intern_atlas(const tile_image& img) +atlasid writer_state::intern_atlas(const tile_image_proto& img) { const void* const ptr = img.atlas.get(); fm_debug_assert(ptr != nullptr); @@ -76,7 +76,7 @@ atlasid writer_state::intern_atlas(const tile_image& img) return (tile_images[ptr] = { &*img.atlas, (atlasid)tile_images.size() }).index; } -atlasid writer_state::maybe_intern_atlas(const tile_image& img) +atlasid writer_state::maybe_intern_atlas(const tile_image_proto& img) { return img ? intern_atlas(img) : null_atlas; } @@ -92,13 +92,14 @@ void writer_state::serialize_chunk(const chunk& c, chunk_coords coord) for (std::size_t i = 0; i < TILE_COUNT; i++) { - const tile& x = c[i]; + const tile_proto x = c[i]; + const auto ground = x.ground_image(), wall_north = x.wall_north_image(), wall_west = x.wall_west_image(); fm_debug_assert(s.bytes_written() + tile_size <= chunkbuf_size); - auto img_g = maybe_intern_atlas(x.ground); - auto img_n = maybe_intern_atlas(x.wall_north); - auto img_w = maybe_intern_atlas(x.wall_west); + auto img_g = maybe_intern_atlas(ground); + auto img_n = maybe_intern_atlas(wall_north); + auto img_w = maybe_intern_atlas(wall_west); tilemeta flags = {}; flags |= meta_ground * (img_g != null_atlas); @@ -110,28 +111,28 @@ void writer_state::serialize_chunk(const chunk& c, chunk_coords coord) constexpr auto ashortp = [](atlasid id) { return id == null_atlas || id == (uchar)id; }; - constexpr auto vshortp = [](const tile_image& img) { + constexpr auto vshortp = [](const tile_image_proto& img) { return !img.atlas || img.variant == (uchar)img.variant; }; if (flags != 0 && ashortp(img_g) && ashortp(img_n) && ashortp(img_w)) flags |= meta_short_atlasid; - if (flags != 0 && vshortp(x.ground) && vshortp(x.wall_north) && vshortp(x.wall_west)) + if (flags != 0 && vshortp(ground) && vshortp(wall_north) && vshortp(wall_west)) flags |= meta_short_variant; - fm_debug_assert((x.passability & pass_mask) == x.passability); - flags |= x.passability; + fm_debug_assert((x.pass_mode & pass_mask) == x.pass_mode); + flags |= x.pass_mode; s << flags; #ifndef FM_NO_DEBUG - constexpr auto check_atlas = [](const tile_image& x) { + constexpr auto check_atlas = [](const tile_image_proto& x) { if (x.atlas) fm_assert(x.variant < x.atlas->num_tiles()); }; - check_atlas(x.ground); - check_atlas(x.wall_north); - check_atlas(x.wall_west); + check_atlas(ground); + check_atlas(wall_north); + check_atlas(wall_west); #endif const auto write = [&](atlasid x, varid v) { @@ -140,11 +141,11 @@ void writer_state::serialize_chunk(const chunk& c, chunk_coords coord) }; if (img_g != null_atlas) - write(img_g, x.ground.variant); + write(img_g, ground.variant); if (img_n != null_atlas) - write(img_n, x.wall_north.variant); + write(img_n, wall_north.variant); if (img_w != null_atlas) - write(img_w, x.wall_west.variant); + write(img_w, wall_west.variant); } const auto nbytes = s.bytes_written(); diff --git a/src/chunk.cpp b/src/chunk.cpp index 9eca0138..59e05d73 100644 --- a/src/chunk.cpp +++ b/src/chunk.cpp @@ -7,12 +7,14 @@ bool chunk::empty(bool force) const noexcept if (!force && !_maybe_empty) return false; - for (const tile& x : _tiles) - if (x.ground || x.wall_north || x.wall_west) + for (std::size_t i = 0; i < TILE_COUNT; i++) + { + if (_ground_atlases[i] || _wall_north_atlases[i] || _wall_west_atlases[i]) { _maybe_empty = false; return false; } + } return true; } diff --git a/src/chunk.hpp b/src/chunk.hpp index 6031b913..564f049e 100644 --- a/src/chunk.hpp +++ b/src/chunk.hpp @@ -12,25 +12,15 @@ struct chunk final friend struct tile_ref; friend struct pass_mode_ref; -#if 0 - tile& operator[](local_coords xy) noexcept { return _tiles[xy.to_index()]; } - const tile& operator[](local_coords xy) const noexcept { return _tiles[xy.to_index()]; } - tile& operator[](std::size_t i) noexcept { return _tiles[i]; } - const tile& operator[](std::size_t i) const noexcept { return _tiles[i]; } - const auto& tiles() const noexcept { return _tiles; } - auto& tiles() noexcept { return _tiles; } -#endif + tile_ref operator[](std::size_t idx) noexcept { return { *this, std::uint8_t(idx) }; } + tile_proto operator[](std::size_t idx) const noexcept { return tile_proto(tile_ref { *const_cast<chunk*>(this), std::uint8_t(idx) }); } + tile_ref operator[](local_coords xy) noexcept { return operator[](xy.to_index()); } + tile_proto operator[](local_coords xy) const noexcept { return operator[](xy.to_index()); } using iterator = tile_iterator; -#if 0 - iterator begin() noexcept { return iterator{_tiles.data(), 0}; } - iterator end() noexcept { return iterator{_tiles.data(), _tiles.size()}; } - const_iterator cbegin() const noexcept { return const_iterator{_tiles.data(), 0}; } - const_iterator cend() const noexcept { return const_iterator{_tiles.data(), _tiles.size()}; } - const_iterator begin() const noexcept { return cbegin(); } - const_iterator end() const noexcept { return cend(); } -#endif + iterator begin() noexcept { return iterator { *this, 0 }; } + iterator end() noexcept { return iterator { *this, TILE_COUNT }; } bool empty(bool force = false) const noexcept; @@ -43,8 +33,8 @@ private: static constexpr std::size_t PASS_BITS = 2; std::array<std::shared_ptr<tile_atlas>, TILE_COUNT> _ground_atlases, _wall_north_atlases, _wall_west_atlases; - std::array<std::uint16_t, TILE_COUNT> _ground_variants, _wall_north_variants, _wall_west_variants; - std::bitset<TILE_COUNT*2> _passability; + std::array<std::uint16_t, TILE_COUNT> _ground_variants = {}, _wall_north_variants = {}, _wall_west_variants = {}; + std::bitset<TILE_COUNT*2> _passability = {}; mutable bool _maybe_empty = true; }; diff --git a/src/local-coords.hpp b/src/local-coords.hpp index e0aea1d6..949a90e0 100644 --- a/src/local-coords.hpp +++ b/src/local-coords.hpp @@ -12,7 +12,7 @@ struct local_coords final { template<std::integral T> requires (sizeof(T) <= sizeof(std::size_t)) constexpr local_coords(T x, T y) noexcept; constexpr local_coords(std::uint8_t x, std::uint8_t y) noexcept : x{x}, y{y} {} - constexpr std::size_t to_index() const noexcept { return y*TILE_MAX_DIM + x; } + constexpr std::uint8_t to_index() const noexcept { return y*TILE_MAX_DIM + x; } }; constexpr local_coords::local_coords(std::size_t index) noexcept : diff --git a/src/tile-atlas.cpp b/src/tile-atlas.cpp index e6df942f..624b4694 100644 --- a/src/tile-atlas.cpp +++ b/src/tile-atlas.cpp @@ -13,7 +13,8 @@ tile_atlas::tile_atlas(StringView name, const ImageView2D& image, Vector2ub tile texcoords_{make_texcoords_array(Vector2ui(image.size()), tile_count)}, name_{name}, size_{image.size()}, dims_{tile_count} { - fm_assert(num_tiles() <= std::numeric_limits<decltype(tile_image::variant)>::max()); + constexpr auto variant_max = std::numeric_limits<variant_t>::max(); + fm_assert(num_tiles() <= variant_max); fm_assert(dims_[0] > 0 && dims_[1] > 0); fm_assert(size_ % Vector2ui{tile_count} == Vector2ui()); tex_.setWrapping(GL::SamplerWrapping::ClampToEdge) diff --git a/src/tile-image.cpp b/src/tile-image.cpp index c9dc24f4..5d9d9f11 100644 --- a/src/tile-image.cpp +++ b/src/tile-image.cpp @@ -2,18 +2,16 @@ namespace floormat { -bool operator==(const tile_image_proto& a, const tile_image_proto& b) noexcept = default; - -tile_image_ref::tile_image_ref(std::shared_ptr<tile_atlas>& atlas, std::uint16_t& variant) noexcept : - atlas{atlas}, variant{variant} +bool operator==(const tile_image_proto& a, const tile_image_proto& b) noexcept { + return a.atlas == b.atlas && a.variant == b.variant; } -tile_image_ref& tile_image_ref::operator=(tile_image_ref&& ref) noexcept +tile_image_proto::operator bool() const noexcept { return atlas != nullptr; } + +tile_image_ref::tile_image_ref(std::shared_ptr<tile_atlas>& atlas, std::uint16_t& variant) noexcept : + atlas{atlas}, variant{variant} { - atlas = ref.atlas; - variant = ref.variant; - return *this; } tile_image_ref& tile_image_ref::operator=(const tile_image_proto& proto) noexcept @@ -24,11 +22,12 @@ tile_image_ref& tile_image_ref::operator=(const tile_image_proto& proto) noexcep } tile_image_ref::tile_image_ref(const tile_image_ref&) noexcept = default; -tile_image_ref::tile_image_ref(tile_image_ref&&) noexcept = default; tile_image_ref::operator tile_image_proto() const noexcept { return { atlas, variant }; } +tile_image_ref::operator bool() const noexcept { return atlas != nullptr; } + } // namespace floormat diff --git a/src/tile-image.hpp b/src/tile-image.hpp index 033d3916..5a13e13f 100644 --- a/src/tile-image.hpp +++ b/src/tile-image.hpp @@ -1,16 +1,20 @@ #pragma once #include "compat/integer-types.hpp" +#include <memory> namespace floormat { struct tile_atlas; +using variant_t = std::uint16_t; + struct tile_image_proto final { std::shared_ptr<tile_atlas> atlas; - std::uint16_t variant = (std::uint16_t)-1; + variant_t variant = (std::uint16_t)-1; friend bool operator==(const tile_image_proto& a, const tile_image_proto& b) noexcept; + operator bool() const noexcept; }; struct tile_image_ref final @@ -21,9 +25,9 @@ struct tile_image_ref final tile_image_ref(std::shared_ptr<tile_atlas>& atlas, std::uint16_t& variant) noexcept; tile_image_ref(const tile_image_ref&) noexcept; tile_image_ref(tile_image_ref&&) noexcept; - tile_image_ref& operator=(tile_image_ref&& tile_rvalue_ref) noexcept; tile_image_ref& operator=(const tile_image_proto& tile_proto) noexcept; operator tile_image_proto() const noexcept; + operator bool() const noexcept; }; } // namespace floormat diff --git a/src/tile-iterator.cpp b/src/tile-iterator.cpp index 943bbaf8..6dfc5f6d 100644 --- a/src/tile-iterator.cpp +++ b/src/tile-iterator.cpp @@ -8,12 +8,12 @@ tile_iterator::tile_iterator(const tile_iterator&) noexcept = default; tile_iterator& tile_iterator::operator=(const tile_iterator&) noexcept = default; tile_iterator& tile_iterator::operator++() noexcept { pos++; return *this; } -tile_iterator tile_iterator::operator++() noexcept { auto it = *this; pos++; return it; } +tile_iterator tile_iterator::operator++(int) noexcept { auto it = *this; pos++; return it; } void tile_iterator::swap(tile_iterator& other) noexcept { std::swap(c, other.c); std::swap(pos, other.pos); } -std::strong_ordering tile_iterator::operator<=>(const tile_iterator&) const noexcept = default; +bool operator==(const tile_iterator& a, const tile_iterator& b) noexcept { return a.c == b.c && a.pos == b.pos; } -tile_iterator_tuple tile_iterator::operator->() { return { tile_ref{*c, i}, i, local_coords{i} }; } -tile_iterator_tuple tile_iterator::operator*() { return { tile_ref{*c, i}, i, local_coords{i} }; } +tile_iterator_tuple tile_iterator::operator->() noexcept { return { tile_ref{*c, std::uint8_t(pos)}, pos, local_coords{pos} }; } +tile_iterator_tuple tile_iterator::operator*() noexcept { return { tile_ref{*c, std::uint8_t(pos)}, pos, local_coords{pos} }; } } // namespace floormat diff --git a/src/tile-iterator.hpp b/src/tile-iterator.hpp index 2f860380..5d999716 100644 --- a/src/tile-iterator.hpp +++ b/src/tile-iterator.hpp @@ -3,7 +3,6 @@ #include "compat/integer-types.hpp" #include "local-coords.hpp" #include "tile.hpp" -#include <compare> namespace floormat { @@ -11,21 +10,22 @@ struct tile_iterator_tuple final { // NOLINT(cppcoreguidelines-pro-type-member-i const tile_iterator_tuple* operator->() const noexcept { return this; } tile_iterator_tuple* operator->() noexcept { return this; } - tile_ref tile; - std::size_t i; - local_coords pos; + tile_ref x; + std::size_t k; + local_coords pt; }; class tile_iterator final { chunk* c; std::size_t pos; + friend bool operator==(const tile_iterator&, const tile_iterator&) noexcept; + public: explicit tile_iterator(chunk& c, std::size_t pos) noexcept; tile_iterator(const tile_iterator&) noexcept; tile_iterator& operator=(const tile_iterator&) noexcept; - std::strong_ordering operator<=>(const tile_iterator&) const noexcept; void swap(tile_iterator& other) noexcept; tile_iterator& operator++() noexcept; diff --git a/src/tile.cpp b/src/tile.cpp index 4bf3ae3e..920ee2e5 100644 --- a/src/tile.cpp +++ b/src/tile.cpp @@ -29,27 +29,41 @@ pass_mode_ref::operator pass_mode() const noexcept return pass_mode(ret); } -bool operator==(const tile_proto&, const tile_proto&) noexcept = default; +bool operator==(const tile_proto& a, const tile_proto& b) noexcept { + return a.ground_image() == b.ground_image() && + a.wall_north_image() == b.wall_north_image() && + a.wall_west_image() == b.wall_west_image(); +}; -tile_ref::tile_ref(struct chunk& c, std::uint8_t i) noexcept : _chunk{&c}, i{i} -{ -} +tile_image_proto tile_proto::ground_image() const noexcept { return { ground_atlas, ground_variant }; } +tile_image_proto tile_proto::wall_north_image() const noexcept { return { wall_north_atlas, wall_north_variant }; } +tile_image_proto tile_proto::wall_west_image() const noexcept { return { wall_west_atlas, wall_west_variant }; } + +tile_ref::tile_ref(struct chunk& c, std::uint8_t i) noexcept : _chunk{&c}, i{i} {} + +std::shared_ptr<tile_atlas> tile_ref::ground_atlas() noexcept { return _chunk->_ground_atlases[i]; } +std::shared_ptr<tile_atlas> tile_ref::wall_north_atlas() noexcept { return _chunk->_wall_north_atlases[i]; } +std::shared_ptr<tile_atlas> tile_ref::wall_west_atlas() noexcept { return _chunk->_wall_west_atlases[i]; } + +std::shared_ptr<const tile_atlas> tile_ref::ground_atlas() const noexcept { return _chunk->_ground_atlases[i]; } +std::shared_ptr<const tile_atlas> tile_ref::wall_north_atlas() const noexcept { return _chunk->_wall_north_atlases[i]; } +std::shared_ptr<const tile_atlas> tile_ref::wall_west_atlas() const noexcept { return _chunk->_wall_west_atlases[i]; } tile_image_ref tile_ref::ground() noexcept { return {_chunk->_ground_atlases[i], _chunk->_ground_variants[i] }; } tile_image_ref tile_ref::wall_north() noexcept { return {_chunk->_wall_north_atlases[i], _chunk->_wall_north_variants[i] }; } tile_image_ref tile_ref::wall_west() noexcept { return {_chunk->_wall_west_atlases[i], _chunk->_wall_west_variants[i] }; } -tile_image_proto tile_ref::ground() const noexcept { return {_chunk->_ground_atlases[i], _chunk->_ground_variants[i] }; } -tile_image_proto tile_ref::wall_north() const noexcept { return {_chunk->_wall_north_atlases[i], _chunk->_wall_north_variants[i] }; } -tile_image_proto tile_ref::wall_west() const noexcept { return {_chunk->_wall_west_atlases[i], _chunk->_wall_west_variants[i] }; } +tile_image_proto tile_ref::ground() const noexcept { return { _chunk->_ground_atlases[i], _chunk->_ground_variants[i] }; } +tile_image_proto tile_ref::wall_north() const noexcept { return { _chunk->_wall_north_atlases[i], _chunk->_wall_north_variants[i] }; } +tile_image_proto tile_ref::wall_west() const noexcept { return { _chunk->_wall_west_atlases[i], _chunk->_wall_west_variants[i] }; } pass_mode_ref tile_ref::pass_mode() noexcept { return { *_chunk, i }; } -pass_mode tile_ref::pass_mode() const noexcept { return pass_mode_ref { *const_cast<chunk*>(_chunk), i }; } +pass_mode tile_ref::pass_mode() const noexcept { return pass_mode_ref { *const_cast<struct chunk*>(_chunk), i }; } tile_ref::operator tile_proto() const noexcept { return { - _chunk->_ground_atlases[i], _chunk->_wall_north_atlases[i], _chunk->_wall_west_atlases[i], + _chunk->_ground_atlases[i], _chunk->_wall_north_atlases[i], _chunk->_wall_west_atlases[i], _chunk->_ground_variants[i], _chunk->_wall_north_variants[i], _chunk->_wall_west_variants[i], pass_mode(), }; diff --git a/src/tile.hpp b/src/tile.hpp index 4bfeb84a..8061035f 100644 --- a/src/tile.hpp +++ b/src/tile.hpp @@ -6,7 +6,8 @@ namespace floormat { struct chunk; -enum pass_mode : std::uint8_t { pass_ok, pass_blocked, pass_shoot_through, }; +// zero is the default, see bitset in chunk.hpp +enum pass_mode : std::uint8_t { pass_shoot_through, pass_ok, pass_blocked, }; struct pass_mode_ref final { @@ -26,6 +27,10 @@ struct tile_proto final std::uint16_t ground_variant = 0xffff, wall_north_variant = 0xffff, wall_west_variant = 0xffff; pass_mode pass_mode = pass_mode::pass_shoot_through; + tile_image_proto ground_image() const noexcept; + tile_image_proto wall_north_image() const noexcept; + tile_image_proto wall_west_image() const noexcept; + friend bool operator==(const tile_proto& a, const tile_proto& b) noexcept; }; @@ -41,6 +46,14 @@ struct tile_ref final tile_image_proto wall_north() const noexcept; tile_image_proto wall_west() const noexcept; + std::shared_ptr<tile_atlas> ground_atlas() noexcept; + std::shared_ptr<tile_atlas> wall_north_atlas() noexcept; + std::shared_ptr<tile_atlas> wall_west_atlas() noexcept; + + std::shared_ptr<const tile_atlas> ground_atlas() const noexcept; + std::shared_ptr<const tile_atlas> wall_north_atlas() const noexcept; + std::shared_ptr<const tile_atlas> wall_west_atlas() const noexcept; + pass_mode_ref pass_mode() noexcept; enum pass_mode pass_mode() const noexcept; diff --git a/src/world.hpp b/src/world.hpp index ae7b6240..9b58ff3d 100644 --- a/src/world.hpp +++ b/src/world.hpp @@ -29,7 +29,7 @@ private: public: explicit world(); - struct pair final { chunk& c; tile& t; }; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members) + struct pair final { chunk& c; tile_ref t; }; template<typename Hash, typename Alloc, typename Pred> explicit world(std::unordered_map<chunk_coords, chunk, Hash, Alloc, Pred>&& chunks); diff --git a/test/json.cpp b/test/json.cpp index 927e7355..0cb65278 100644 --- a/test/json.cpp +++ b/test/json.cpp @@ -19,14 +19,14 @@ static chunk make_test_chunk() tiles = loader.tile_atlas("tiles", {8, 5}); constexpr auto N = TILE_MAX_DIM; chunk c; - for (auto& [x, k, pt] : c) { - x.ground = { tiles, decltype(tile_image::variant)(k % tiles->num_tiles()) }; + for (auto [x, k, pt] : c) { + x.ground() = { tiles, variant_t(k % tiles->num_tiles()) }; } constexpr auto K = N/2; - c[{K, K }].wall_north = { metal1, 0 }; - c[{K, K }].wall_west = { metal2, 0 }; - c[{K, K+1}].wall_north = { metal1, 0 }; - c[{K+1, K }].wall_west = { metal2, 0 }; + c[{K, K }].wall_north() = { metal1, 0 }; + c[{K, K }].wall_west() = { metal2, 0 }; + c[{K, K+1}].wall_north() = { metal1, 0 }; + c[{K+1, K }].wall_west() = { metal2, 0 }; return c; } diff --git a/test/serializer.cpp b/test/serializer.cpp index db08a9f8..c1ab5fef 100644 --- a/test/serializer.cpp +++ b/test/serializer.cpp @@ -15,14 +15,14 @@ static chunk make_test_chunk() tiles = loader.tile_atlas("tiles", {8, 5}); constexpr auto N = TILE_MAX_DIM; chunk c; - for (auto& [x, k, pt] : c) { - x.ground = { tiles, decltype(tile_image::variant)(k % tiles->num_tiles()) }; + for (auto [x, k, pt] : c) { + x.ground() = { tiles, variant_t(k % tiles->num_tiles()) }; } constexpr auto K = N/2; - c[{K, K }].wall_north = { metal1, 0 }; - c[{K, K }].wall_west = { metal2, 0 }; - c[{K, K+1}].wall_north = { metal1, 0 }; - c[{K+1, K }].wall_west = { metal2, 0 }; + c[{K, K }].wall_north() = { metal1, 0 }; + c[{K, K }].wall_west() = { metal2, 0 }; + c[{K, K+1}].wall_north() = { metal1, 0 }; + c[{K+1, K }].wall_west() = { metal2, 0 }; return c; } diff --git a/test/tile-iter.cpp b/test/tile-iter.cpp index 9303a764..6bfd1a0b 100644 --- a/test/tile-iter.cpp +++ b/test/tile-iter.cpp @@ -10,6 +10,7 @@ static inline bool always_false() bool floormat::test_tile_iter() // NOLINT(readability-function-size) { +#if 0 if (always_false()) { const chunk c; @@ -22,23 +23,18 @@ bool floormat::test_tile_iter() // NOLINT(readability-function-size) for (auto&& [x, k, pt] : c) static_assert(std::is_same_v<decltype(x), const tile&>); } +#endif if (always_false()) { chunk c; - for (auto& [x, k, pt] : c) - static_assert(std::is_same_v<decltype(x), tile&>); - for (const auto& [x, k, pt] : c) - static_assert(std::is_same_v<decltype(x), const tile&>); for (auto [x, k, pt] : c) - static_assert(std::is_same_v<decltype(x), tile&>); + static_assert(std::is_same_v<decltype(x), tile_ref>); #if 0 // warns for (const auto [x, k, pt] : c) static_assert(std::is_same_v<decltype(x), const tile&>); -#endif for (auto&& [x, k, pt] : c) static_assert(std::is_same_v<decltype(x), tile&>); -#if 0 // fails to compile for (const auto&& [x, k, pt] : c) static_assert(std::is_same_v<decltype(x), const tile&>); |