diff options
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | editor/imgui-inspect.cpp | 3 | ||||
-rw-r--r-- | editor/inspect-types.cpp | 9 | ||||
-rw-r--r-- | editor/update.cpp | 3 | ||||
-rw-r--r-- | serialize/world-reader.cpp | 3 | ||||
-rw-r--r-- | serialize/world-writer.cpp | 7 | ||||
-rw-r--r-- | src/character.cpp | 14 | ||||
-rw-r--r-- | src/character.hpp | 1 | ||||
-rw-r--r-- | src/chunk-collision.cpp | 13 | ||||
-rw-r--r-- | src/chunk.hpp | 14 | ||||
-rw-r--r-- | src/chunk.inl | 37 | ||||
-rw-r--r-- | src/entity.cpp | 44 | ||||
-rw-r--r-- | src/entity.hpp | 15 | ||||
-rw-r--r-- | src/scenery.cpp | 20 | ||||
-rw-r--r-- | src/scenery.hpp | 1 |
15 files changed, 71 insertions, 114 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 89259c58..bf4e4e1a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,6 +153,7 @@ endif() if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_CXX_COMPILER_VERSION GREATER_EQUAL "13.3" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION GREATER_EQUAL "13.0") add_compile_options(-Wno-reserved-macro-identifier) + add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-Wno-ambiguous-reversed-operator>) endif() set_directory_properties(PROPERTIES CORRADE_USE_PEDANTIC_FLAGS OFF) diff --git a/editor/imgui-inspect.cpp b/editor/imgui-inspect.cpp index 3fdbc2af..510fcf32 100644 --- a/editor/imgui-inspect.cpp +++ b/editor/imgui-inspect.cpp @@ -6,7 +6,6 @@ #include "src/world.hpp" #include "src/anim-atlas.hpp" #include "imgui-raii.hpp" -#include "chunk.inl" #include "loader/loader.hpp" namespace floormat { @@ -49,7 +48,7 @@ void app::draw_inspector() if (s.type == entity_type::scenery) { auto& s2 = static_cast<scenery&>(s); - c.with_scenery_update(s, [&] { return entities::inspect_type(s2); }); + entities::inspect_type(s2); } } if (!is_open) diff --git a/editor/inspect-types.cpp b/editor/inspect-types.cpp index dcbd534c..85b77e46 100644 --- a/editor/inspect-types.cpp +++ b/editor/inspect-types.cpp @@ -6,7 +6,6 @@ #include "inspect.hpp" #include "loader/loader.hpp" #include "chunk.hpp" -#include "chunk.inl" #include <Corrade/Containers/ArrayViewStl.h> //#define TEST_STR @@ -40,21 +39,21 @@ struct entity_accessors<scenery> { }, entity::type<Vector2b>::field{"offset"_s, [](const scenery& x) { return x.offset; }, - [](scenery& x, Vector2b value) { x.offset = value; }, + [](scenery& x, Vector2b value) { x.set_bbox(value, x.bbox_offset, x.bbox_size, x.pass); }, constantly(constraints::range{Vector2b(iTILE_SIZE2/-2), Vector2b(iTILE_SIZE2/2)}) }, entity::type<pass_mode>::field{"pass-mode"_s, [](const scenery& x) { return x.pass; }, - [](scenery& x, pass_mode value) { x.chunk().with_scenery_update(x, [&] { x.pass = value; }); }, + [](scenery& x, pass_mode value) { x.set_bbox(x.offset, x.bbox_offset, x.bbox_size, value); } }, entity::type<Vector2b>::field{"bbox-offset"_s, [](const scenery& x) { return x.bbox_offset; }, - [](scenery& x, Vector2b value) { x.chunk().with_scenery_update(x, [&] { x.bbox_offset = value; }); }, + [](scenery& x, Vector2b value) { x.set_bbox(x.offset, value, x.bbox_size, x.pass); }, [](const scenery& x) { return x.pass == pass_mode::pass ? field_status::readonly : field_status::enabled; }, }, entity::type<Vector2ub>::field{"bbox-size"_s, [](const scenery& x) { return x.bbox_size; }, - [](scenery& x, Vector2ub value) { x.chunk().with_scenery_update(x, [&] { x.bbox_size = value; }); }, + [](scenery& x, Vector2ub value) { x.set_bbox(x.offset, x.bbox_offset, value, x.pass); }, [](const scenery& x) { return x.pass == pass_mode::pass ? field_status::readonly : field_status::enabled; }, }, entity::type<bool>::field{"interactive"_s, diff --git a/editor/update.cpp b/editor/update.cpp index 7b3198ee..b16821f8 100644 --- a/editor/update.cpp +++ b/editor/update.cpp @@ -6,7 +6,6 @@ #include "floormat/events.hpp" #include "floormat/main.hpp" #include "character.hpp" -#include "chunk.inl" namespace floormat { @@ -192,7 +191,7 @@ void app::update_world(float dt) for (auto i = size-1; i != (std::size_t)-1; i--) { auto& e = *es[i]; - c.with_scenery_update(e, [&] { return e.update(i, dt); }); + e.update(i, dt); } } } diff --git a/serialize/world-reader.cpp b/serialize/world-reader.cpp index b38c16b4..b79a1122 100644 --- a/serialize/world-reader.cpp +++ b/serialize/world-reader.cpp @@ -274,8 +274,7 @@ void reader_state::read_chunks(reader_t& s) if (sc.active) sc.delta << s; } - global_coords coord{ch, local_coords{i}}; - auto e = _world->make_entity<scenery>(oid, coord, sc); + auto e = _world->make_entity<scenery>(oid, {ch, local}, sc); c.add_entity_unsorted(e); break; } diff --git a/serialize/world-writer.cpp b/serialize/world-writer.cpp index 3bfad5e1..9f724ef1 100644 --- a/serialize/world-writer.cpp +++ b/serialize/world-writer.cpp @@ -69,7 +69,7 @@ private: constexpr auto tile_size = sizeof(tilemeta) + (sizeof(atlasid) + sizeof(variant_t)) * 3 + sizeof(scenery); constexpr auto chunkbuf_size = sizeof(chunk_magic) + sizeof(chunk_coords) + tile_size * TILE_COUNT; -constexpr auto entity_size = std::max(sizeof(character), sizeof(scenery)); +constexpr auto entity_size = std::max(sizeof(character), sizeof(scenery)) + character_name_max; #ifdef __GNUG__ #pragma GCC diagnostic push @@ -302,7 +302,8 @@ const auto def_char_pass = character_proto{}.pass; void writer_state::serialize_chunk(const chunk& c, chunk_coords coord) { fm_assert(chunk_buf.empty()); - chunk_buf.resize(chunkbuf_size + sizeof(std::uint32_t) + entity_size*c.entities().size()); + const auto es_size = sizeof(std::uint32_t) + entity_size*c.entities().size(); + chunk_buf.resize(chunkbuf_size + es_size); auto s = binary_writer{chunk_buf.begin()}; @@ -347,7 +348,7 @@ void writer_state::serialize_chunk(const chunk& c, chunk_coords coord) { const auto& e = *e_; std::uint64_t oid = e.id; - fm_assert((oid & (1ULL << 60)-1) == oid); + fm_assert((oid & ((std::uint64_t)1 << 60)-1) == oid); static_assert(entity_type_BITS == 3); fm_assert(((entity_type_i)e.type & (1 << entity_type_BITS)-1) == (entity_type_i)e.type); oid |= (std::uint64_t)e.type << 64 - entity_type_BITS; diff --git a/src/character.cpp b/src/character.cpp index ed9ce4fa..67b6ca72 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -52,12 +52,13 @@ constexpr auto arrows_to_dir(bool L, bool R, bool U, bool D) } // namespace character::character(std::uint64_t id, struct chunk& c, entity_type type, const character_proto& proto) : - entity{id, c, type}, + entity{id, c, type, proto}, name{proto.name}, playable{proto.playable} { - atlas = loader.anim_atlas("npc-walk", loader.ANIM_PATH); - bbox_size = Vector2ub(iTILE_SIZE2/2); + if (!atlas) + atlas = loader.anim_atlas("npc-walk", loader.ANIM_PATH); + entity::set_bbox_(offset, bbox_offset, Vector2ub(iTILE_SIZE2/2), pass); } character::~character() = default; @@ -88,7 +89,7 @@ void character::set_keys(bool L, bool R, bool U, bool D) bool character::update(std::size_t i, float dt) { - auto [lr, ud, rot] = arrows_to_dir(b_L, b_R, b_U, b_D); + auto [lr, ud, new_r] = arrows_to_dir(b_L, b_R, b_U, b_D); if (!lr & !ud) { @@ -102,18 +103,17 @@ bool character::update(std::size_t i, float dt) return false; const auto vec = move_vec(lr, ud); - r = rot; c->ensure_passability(); for (int k = 0; k < nframes; k++) { constexpr auto frac = Vector2(32767); - constexpr auto inv_frac = Vector2(1.f/32767); + constexpr auto inv_frac = 1.f / frac; auto offset_ = vec + Vector2(offset_frac) * inv_frac; offset_frac = Vector2s(Vector2(std::fmod(offset_[0], 1.f), std::fmod(offset_[1], 1.f)) * frac); auto off_i = Vector2i(offset_); if (can_move_to(off_i)) - i = move(i, off_i); + i = move(i, off_i, new_r); ++frame %= atlas->info().nframes; } //Debug{} << "pos" << Vector2i(pos.local()); diff --git a/src/character.hpp b/src/character.hpp index 9481c4ac..af48b19a 100644 --- a/src/character.hpp +++ b/src/character.hpp @@ -29,7 +29,6 @@ struct character final : entity void set_keys(bool L, bool R, bool U, bool D); bool update(std::size_t i, float dt) override; - void update_bbox(Vector2b bbox_offset, Vector2ub bbox_size) override; String name; Vector2s offset_frac; diff --git a/src/chunk-collision.cpp b/src/chunk-collision.cpp index c64d9a5b..c228c514 100644 --- a/src/chunk-collision.cpp +++ b/src/chunk-collision.cpp @@ -96,9 +96,9 @@ void chunk::ensure_passability() noexcept } } -bool chunk::_bbox_for_scenery(const entity& s, local_coords local, Vector2b offset, bbox& value) noexcept +bool chunk::_bbox_for_scenery(const entity& s, local_coords local, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size, bbox& value) noexcept { - auto [start, end] = scenery_tile(local, offset, s.bbox_offset, s.bbox_size); + auto [start, end] = scenery_tile(local, offset, bbox_offset, bbox_size); auto id = make_id(collision_type::scenery, s.pass, s.id); value = { .id = id, .start = start, .end = end }; return s.atlas && s.pass != pass_mode::pass; @@ -106,27 +106,26 @@ bool chunk::_bbox_for_scenery(const entity& s, local_coords local, Vector2b offs bool chunk::_bbox_for_scenery(const entity& s, bbox& value) noexcept { - return _bbox_for_scenery(s, s.coord.local(), s.offset, value); + return _bbox_for_scenery(s, s.coord.local(), s.offset, s.bbox_offset, s.bbox_size, value); } void chunk::_remove_bbox(const bbox& x) { - if (_scenery_modified) - return; auto start = Vector2(x.start), end = Vector2(x.end); _rtree.Remove(start.data(), end.data(), x.id); } void chunk::_add_bbox(const bbox& x) { - if (_scenery_modified) - return; auto start = Vector2(x.start), end = Vector2(x.end); _rtree.Insert(start.data(), end.data(), x.id); } void chunk::_replace_bbox(const bbox& x0, const bbox& x1, bool b0, bool b1) { + if (_pass_modified) + return; + unsigned i = (unsigned)b1 << 1 | (unsigned)(b0 ? 1 : 0) << 0; CORRADE_ASSUME(i < 4u); diff --git a/src/chunk.hpp b/src/chunk.hpp index 0cd7bcfc..e825ce33 100644 --- a/src/chunk.hpp +++ b/src/chunk.hpp @@ -87,26 +87,18 @@ struct chunk final float depth = -1; }; + using RTree = ::RTree<std::uint64_t, float, 2, float>; + ground_mesh_tuple ensure_ground_mesh() noexcept; tile_atlas* ground_atlas_at(std::size_t i) const noexcept; - wall_mesh_tuple ensure_wall_mesh() noexcept; tile_atlas* wall_atlas_at(std::size_t i) const noexcept; - scenery_mesh_tuple ensure_scenery_mesh() noexcept; void ensure_passability() noexcept; - - using RTree = ::RTree<std::uint64_t, float, 2, float>; - RTree* rtree() noexcept; - struct world& world() noexcept { return *_world; } - template<typename F> - requires requires(F fun) { fun(); } - void with_scenery_update(entity& e, F&& fun); - [[nodiscard]] bool can_place_entity(const entity_proto& proto, local_coords pos); void add_entity(const std::shared_ptr<entity>& e); @@ -147,7 +139,7 @@ private: bool operator==(const bbox& other) const noexcept; }; static bool _bbox_for_scenery(const entity& s, bbox& value) noexcept; - static bool _bbox_for_scenery(const entity& s, local_coords local, Vector2b offset, bbox& value) noexcept; + static bool _bbox_for_scenery(const entity& s, local_coords local, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size, bbox& value) noexcept; void _remove_bbox(const bbox& x); void _add_bbox(const bbox& x); void _replace_bbox(const bbox& x0, const bbox& x, bool b0, bool b); diff --git a/src/chunk.inl b/src/chunk.inl deleted file mode 100644 index 132657ab..00000000 --- a/src/chunk.inl +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once -#include "chunk.hpp" -#include "scenery.hpp" - -namespace floormat { - -template<typename F> -requires requires(F fun) { fun(); } -void chunk::with_scenery_update(entity& s, F&& fun) -{ - static_assert(std::is_convertible_v<decltype(fun()), bool> || std::is_same_v<void, decltype(fun())>); - - // todo handle coord & offset fields - - auto ch = s.coord.chunk(); - entity_proto s0(s); - bbox bb0; bool b0 = _bbox_for_scenery(s, bb0); - - bool modified = true; - if constexpr(!std::is_same_v<void, std::decay_t<decltype(fun())>>) - modified = fun(); - else - fun(); - if (!modified) - return; - - if (s.coord.chunk() != ch) // todo - return; - - if (bbox bb; !is_passability_modified()) - if (bool b = _bbox_for_scenery(s, bb); b != b0 || bb != bb0) - _replace_bbox(bb0, bb, b0, b); - if (!is_scenery_modified() && !s.is_dynamic() && entity_proto(s) != s0) - mark_scenery_modified(false); -} - -} // namespace floormat diff --git a/src/entity.cpp b/src/entity.cpp index c9c1a4ab..390cf18c 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -1,7 +1,6 @@ #include "entity.hpp" #include "world.hpp" #include "rotation.inl" -#include "chunk.inl" #include "anim-atlas.hpp" #include "RTree.hpp" #include <algorithm> @@ -14,11 +13,6 @@ entity_proto::~entity_proto() noexcept = default; entity_proto::entity_proto() = default; entity_proto::entity_proto(const entity_proto&) = default; -entity::entity(std::uint64_t id, struct chunk& c, entity_type type) noexcept : - id{id}, c{&c}, type{type} -{ -} - entity::entity(std::uint64_t id, struct chunk& c, entity_type type, const entity_proto& proto) noexcept : id{id}, c{&c}, atlas{proto.atlas}, offset{proto.offset}, bbox_offset{proto.bbox_offset}, @@ -26,6 +20,8 @@ entity::entity(std::uint64_t id, struct chunk& c, entity_type type, const entity frame{proto.frame}, type{type}, r{proto.r}, pass{proto.pass} { fm_assert(type == proto.type); + fm_assert(atlas->check_rotation(r)); + fm_assert(frame < atlas->info().nframes); } entity::~entity() noexcept @@ -90,12 +86,9 @@ std::size_t entity::index() const void entity::rotate(std::size_t, rotation new_r) { - auto& w = *c->_world; - w[coord.chunk()].with_scenery_update(*this, [&]() { - bbox_offset = rotate_point(bbox_offset, r, new_r); - bbox_size = rotate_size(bbox_size, r, new_r); - r = new_r; - }); + fm_assert(atlas->check_rotation(new_r)); + set_bbox(offset, rotate_point(bbox_offset, r, new_r), rotate_size(bbox_size, r, new_r), pass); + const_cast<rotation&>(r) = new_r; } template <typename T> constexpr T sgn(T val) { return T(T(0) < val) - T(val < T(0)); } @@ -141,7 +134,7 @@ bool entity::can_move_to(Vector2i delta) return ret; } -std::size_t entity::move(std::size_t i, Vector2i delta) +std::size_t entity::move(std::size_t i, Vector2i delta, rotation new_r) { auto& es = c->_entities; fm_debug_assert(i < es.size()); @@ -159,8 +152,10 @@ std::size_t entity::move(std::size_t i, Vector2i delta) c->mark_scenery_modified(false); chunk::bbox bb0, bb1; + const auto bb_offset = rotate_point(bbox_offset, r, new_r); + const auto bb_size = rotate_size(bbox_size, r, new_r); bool b0 = c->_bbox_for_scenery(e, bb0), - b1 = c->_bbox_for_scenery(e, coord_.local(), offset_, bb1); + b1 = c->_bbox_for_scenery(e, coord_.local(), offset_, bb_offset, bb_size, bb1); const auto ord = e.ordinal(coord_.local(), offset_, e.type); if (coord_.chunk() == coord.chunk()) @@ -168,7 +163,7 @@ std::size_t entity::move(std::size_t i, Vector2i delta) c->_replace_bbox(bb0, bb1, b0, b1); auto it_ = std::lower_bound(es.cbegin(), es.cend(), e_, [=](const auto& a, const auto&) { return a->ordinal() < ord; }); e_->coord = coord_; - e_->offset = offset_; + set_bbox_(offset_, bb_offset, bb_size, pass); auto pos1 = std::distance(es.cbegin(), it_); if ((std::size_t)pos1 > i) pos1--; @@ -193,13 +188,30 @@ std::size_t entity::move(std::size_t i, Vector2i delta) auto it = std::lower_bound(es.cbegin(), es.cend(), e_, [=](const auto& a, const auto&) { return a->ordinal() < ord; }); auto ret = (std::size_t)std::distance(es.cbegin(), it); e_->coord = coord_; - e_->offset = offset_; + set_bbox_(offset_, bb_offset, bb_size, pass); const_cast<struct chunk*&>(e_->c) = &c2; es.insert(it, std::move(e_)); return ret; } } +void entity::set_bbox_(Vector2b offset_, Vector2b bbox_offset_, Vector2ub bbox_size_, pass_mode pass_) +{ + const_cast<Vector2b&>(offset) = offset_; + const_cast<Vector2b&>(bbox_offset) = bbox_offset_; + const_cast<Vector2ub&>(bbox_size) = bbox_size_; + const_cast<pass_mode&>(pass) = pass_; +} + +void entity::set_bbox(Vector2b offset_, Vector2b bbox_offset_, Vector2ub bbox_size_, pass_mode pass) +{ + chunk::bbox bb0, bb; + const bool b0 = c->_bbox_for_scenery(*this, bb0); + set_bbox_(offset_, bbox_offset_, bbox_size_, pass); + const bool b = c->_bbox_for_scenery(*this, bb); + c->_replace_bbox(bb0, bb, b0, b); +} + entity::operator entity_proto() const { entity_proto x; diff --git a/src/entity.hpp b/src/entity.hpp index 893c30e9..c6edcf90 100644 --- a/src/entity.hpp +++ b/src/entity.hpp @@ -41,12 +41,12 @@ struct entity struct chunk* const c; std::shared_ptr<anim_atlas> atlas; global_coords coord; - Vector2b offset, bbox_offset; - Vector2ub bbox_size; + const Vector2b offset, bbox_offset; + const Vector2ub bbox_size; std::uint16_t delta = 0, frame = 0; const entity_type type; - rotation r : rotation_BITS = rotation::N; - pass_mode pass : pass_mode_BITS = pass_mode::see_through; + const rotation r = rotation::N; + const pass_mode pass = pass_mode::see_through; virtual ~entity() noexcept; @@ -65,15 +65,16 @@ struct entity static Pair<global_coords, Vector2b> normalize_coords(global_coords coord, Vector2b cur_offset, Vector2i delta); [[nodiscard]] virtual bool can_move_to(Vector2i delta); - std::size_t move(std::size_t i, Vector2i delta); - virtual void update_bbox(Vector2b bbox_offset, Vector2ub bbox_size) = 0; + std::size_t move(std::size_t i, Vector2i delta, rotation new_r); + virtual void set_bbox(Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size, pass_mode pass); bool is_dynamic() const; friend struct world; protected: - entity(std::uint64_t id, struct chunk& c, entity_type type) noexcept; entity(std::uint64_t id, struct chunk& c, entity_type type, const entity_proto& proto) noexcept; + + void set_bbox_(Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size, pass_mode pass); }; } // namespace floormat diff --git a/src/scenery.cpp b/src/scenery.cpp index be0249d2..694090a2 100644 --- a/src/scenery.cpp +++ b/src/scenery.cpp @@ -50,12 +50,14 @@ bool scenery::update(std::size_t, float dt) const std::int8_t dir = s.closing ? 1 : -1; const int fr = s.frame + dir*n; s.active = fr > 0 && fr < nframes-1; + pass_mode p; if (fr <= 0) - s.pass = pass_mode::pass; + p = pass_mode::pass; else if (fr >= nframes-1) - s.pass = pass_mode::blocked; + p = pass_mode::blocked; else - s.pass = pass_mode::see_through; + p = pass_mode::see_through; + set_bbox(offset, bbox_offset, bbox_size, p); s.frame = (std::uint16_t)std::clamp(fr, 0, nframes-1); if (!s.active) s.delta = s.closing = 0; @@ -117,19 +119,11 @@ scenery::operator scenery_proto() const return ret; } -scenery::scenery(std::uint64_t id, struct chunk& c, entity_type type, const scenery_proto& proto) : - entity{id, c, type}, sc_type{proto.sc_type}, active{proto.active}, +scenery::scenery(std::uint64_t id, struct chunk& c, entity_type type_, const scenery_proto& proto) : + entity{id, c, type_, proto}, sc_type{proto.sc_type}, active{proto.active}, closing{proto.closing}, interactive{proto.interactive} { fm_assert(type == proto.type); - atlas = proto.atlas; - offset = proto.offset; - bbox_offset = proto.bbox_offset; - bbox_size = proto.bbox_size; - delta = proto.delta; - frame = proto.frame; - r = proto.r; - pass = proto.pass; } } // namespace floormat diff --git a/src/scenery.hpp b/src/scenery.hpp index 55a13bd0..3fe5fa35 100644 --- a/src/scenery.hpp +++ b/src/scenery.hpp @@ -45,7 +45,6 @@ struct scenery final : entity bool can_activate(std::size_t i) const override; bool activate(std::size_t i) override; bool update(std::size_t i, float dt) override; - void update_bbox(Vector2b bbox_offset, Vector2ub bbox_size) override; explicit operator scenery_proto() const; private: |