diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2023-03-03 19:40:11 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2023-03-03 20:34:02 +0100 |
commit | 3d7ae4c401d5bd6109a7fd25eb22e5bc77f0a4aa (patch) | |
tree | 7c673746944b85fbafae891ac69594326b15b517 | |
parent | 6d0a594e618f165eb2823bb31eb3cfe21ec1e7c5 (diff) |
src: rework scenery updates
-rw-r--r-- | editor/imgui-inspect.cpp | 2 | ||||
-rw-r--r-- | editor/inspect-types.cpp | 15 | ||||
-rw-r--r-- | editor/update.cpp | 2 | ||||
-rw-r--r-- | src/chunk.cpp | 51 | ||||
-rw-r--r-- | src/chunk.hpp | 11 | ||||
-rw-r--r-- | src/chunk.inl | 51 | ||||
-rw-r--r-- | src/scenery.cpp | 20 | ||||
-rw-r--r-- | src/scenery.hpp | 3 |
8 files changed, 103 insertions, 52 deletions
diff --git a/editor/imgui-inspect.cpp b/editor/imgui-inspect.cpp index f7543788..b673c9d5 100644 --- a/editor/imgui-inspect.cpp +++ b/editor/imgui-inspect.cpp @@ -48,7 +48,7 @@ void app::draw_inspector() snformat(buf, "{} ({}x{} -> {}x{})"_cf, name, ch.x, ch.y, (int)pos.x, (int)pos.y); bool is_open = true; if (auto b2 = begin_window(buf, &is_open)) - c.with_scenery_bbox_update(s.index(), [&] { return entities::inspect_type(s); }); + c.with_scenery_update(s.index(), [&] { return entities::inspect_type(s); }); if (!is_open) inspectors.erase(inspectors.begin() + (int)i); } diff --git a/editor/inspect-types.cpp b/editor/inspect-types.cpp index 8f84ebd7..aa6a2faa 100644 --- a/editor/inspect-types.cpp +++ b/editor/inspect-types.cpp @@ -43,18 +43,12 @@ struct entity_accessors<scenery_ref> { }, entity::type<pass_mode>::field{"pass-mode"_s, [](const scenery_ref& x) { return x.frame.passability; }, - [](scenery_ref& x, pass_mode value) { - x.chunk().with_scenery_bbox_update(x.index(), [&] { - x.frame.passability = value; - }); + [](scenery_ref& x, pass_mode value) { x.chunk().with_scenery_update(x.index(), [&] { x.frame.passability = value; }); }, }, entity::type<Vector2b>::field{"bbox-offset"_s, [](const scenery_ref& x) { return x.frame.bbox_offset; }, - [](scenery_ref& x, Vector2b value) { - x.chunk().with_scenery_bbox_update(x.index(), [&] { - x.frame.bbox_offset = value; - }); + [](scenery_ref& x, Vector2b value) { x.chunk().with_scenery_update(x.index(), [&] { x.frame.bbox_offset = value; }); }, [](const scenery_ref& x) { return x.frame.passability == pass_mode::pass @@ -64,10 +58,7 @@ struct entity_accessors<scenery_ref> { }, entity::type<Vector2ub>::field{"bbox-size"_s, [](const scenery_ref& x) { return x.frame.bbox_size; }, - [](scenery_ref& x, Vector2ub value) { - x.chunk().with_scenery_bbox_update(x.index(), [&] { - x.frame.bbox_size = value; - }); + [](scenery_ref& x, Vector2ub value) { x.chunk().with_scenery_update(x.index(), [&] { x.frame.bbox_size = value; }); }, [](const scenery_ref& x) { return x.frame.passability == pass_mode::pass ? field_status::readonly : field_status::enabled; }, }, diff --git a/editor/update.cpp b/editor/update.cpp index e784ef86..16a155f3 100644 --- a/editor/update.cpp +++ b/editor/update.cpp @@ -205,7 +205,7 @@ void app::update_world(float dt) for (std::int16_t x = minx; x <= maxx; x++) for (auto& c = world[chunk_coords{x, y}]; auto [x, k, pt] : c) if (auto sc = x.scenery(); sc && sc.can_activate()) - c.with_scenery_bbox_update(sc.index(), [&] { return sc.update(dt); }); + c.with_scenery_update(sc.index(), [&] { return sc.update(dt); }); } void app::set_cursor() diff --git a/src/chunk.cpp b/src/chunk.cpp index 8310c756..72b35b84 100644 --- a/src/chunk.cpp +++ b/src/chunk.cpp @@ -31,10 +31,55 @@ auto chunk::cend() const noexcept -> const_iterator { return const_iterator { *t auto chunk::begin() const noexcept -> const_iterator { return cbegin(); } auto chunk::end() const noexcept -> const_iterator { return cend(); } -void chunk::mark_ground_modified() noexcept { _ground_modified = true; _pass_modified = true; } -void chunk::mark_walls_modified() noexcept { _walls_modified = true; _pass_modified = true; } -void chunk::mark_scenery_modified() noexcept { _scenery_modified = true; _pass_modified = true; } +//#define FM_DEBUG_RELOAD + +#ifdef FM_DEBUG_RELOAD +static std::size_t _reloadno_ = 0; +#endif + +void chunk::mark_ground_modified() noexcept +{ +#ifdef FM_DEBUG_RELOAD + if (!_ground_modified) + fm_debug("ground reload %zu", ++_reloadno_); +#endif + _ground_modified = true; + mark_passability_modified(); +} + +// todo this can use _replace_bbox too +void chunk::mark_walls_modified() noexcept +{ +#ifdef FM_DEBUG_RELOAD + if (!_walls_modified) + fm_debug("wall reload %zu", ++_reloadno_); +#endif + _walls_modified = true; + mark_passability_modified(); +} + +void chunk::mark_scenery_modified(bool collision_too) noexcept // todo remove bool +{ +#ifdef FM_DEBUG_RELOAD + if (!_scenery_modified) + fm_debug("scenery reload %zu", ++_reloadno_); +#endif + _scenery_modified = true; + if (collision_too) + mark_passability_modified(); +} + +void chunk::mark_passability_modified() noexcept +{ +#ifdef FM_DEBUG_RELOAD + if (!_pass_modified) + fm_debug("pass reload %zu", ++_reloadno_); +#endif + _pass_modified = true; +} + bool chunk::is_passability_modified() const noexcept { return _pass_modified; } +bool chunk::is_scenery_modified() const noexcept { return _scenery_modified; } void chunk::mark_modified() noexcept { diff --git a/src/chunk.hpp b/src/chunk.hpp index 3ec02130..a2fdf53f 100644 --- a/src/chunk.hpp +++ b/src/chunk.hpp @@ -56,10 +56,13 @@ struct chunk final void mark_ground_modified() noexcept; void mark_walls_modified() noexcept; - void mark_scenery_modified() noexcept; - bool is_passability_modified() const noexcept; + void mark_scenery_modified(bool collision_too = true) noexcept; + void mark_passability_modified() noexcept; void mark_modified() noexcept; + bool is_passability_modified() const noexcept; + bool is_scenery_modified() const noexcept; + struct ground_mesh_tuple final { GL::Mesh& mesh; const ArrayView<const std::uint8_t> ids; @@ -94,7 +97,9 @@ struct chunk final const RTree* rtree() const noexcept; RTree* rtree() noexcept; - template<typename F> void with_scenery_bbox_update(std::size_t idx, F&& fun); + template<typename F> + requires requires(F fun) { fun(); } + void with_scenery_update(std::size_t idx, F&& fun); private: std::array<std::shared_ptr<tile_atlas>, TILE_COUNT> _ground_atlases; diff --git a/src/chunk.inl b/src/chunk.inl index bdb4f8ae..6b01510a 100644 --- a/src/chunk.inl +++ b/src/chunk.inl @@ -3,40 +3,29 @@ namespace floormat { -template<typename F> void chunk::with_scenery_bbox_update(std::size_t i, F&& fun) +template<typename F> +requires requires(F fun) { fun(); } +void chunk::with_scenery_update(std::size_t idx, F&& fun) { - static_assert(std::is_invocable_v<F>); static_assert(std::is_convertible_v<decltype(fun()), bool> || std::is_same_v<void, decltype(fun())>); - if (is_passability_modified()) - { - auto& s = scenery_at(i); - auto r0 = s.r; - bool modified = true; - if constexpr(!std::is_same_v<void, std::decay_t<decltype(fun())>>) - modified = fun(); - else - fun(); - if (r0 != s.r) - { - fm_debug_assert(modified); - mark_scenery_modified(); - } - } + + const auto& s = scenery_at(idx), s0 = s; + bbox bb0; bool b0 = _bbox_for_scenery(idx, bb0); + + bool modified = true; + if constexpr(!std::is_same_v<void, std::decay_t<decltype(fun())>>) + modified = fun(); else - { - bbox x0, x; - bool b0 = _bbox_for_scenery(i, x0); - if constexpr(std::is_same_v<void, std::decay_t<decltype(fun())>>) - { - fun(); - _replace_bbox(x0, x, b0, _bbox_for_scenery(i, x)); - } - else - { - if (fun()) - _replace_bbox(x0, x, b0, _bbox_for_scenery(i, x)); - } - } + fun(); + if (!modified) + return; + + if (bbox bb; !is_passability_modified()) + if (bool b = _bbox_for_scenery(idx, bb); + b != b0 || scenery::is_collision_modified(s0, s)) + _replace_bbox(bb0, bb, b0, b); + if (!is_scenery_modified() && scenery::is_mesh_modified(s0, s)) + mark_scenery_modified(false); } } // namespace floormat diff --git a/src/scenery.cpp b/src/scenery.cpp index fca45411..6b338635 100644 --- a/src/scenery.cpp +++ b/src/scenery.cpp @@ -67,7 +67,7 @@ scenery::scenery(door_tag_t, const anim_atlas& atlas, rotation r, bool is_open, void scenery_ref::rotate(rotation new_r) { - c->with_scenery_bbox_update(idx, [&]() { + c->with_scenery_update(idx, [&]() { auto& s = frame; s.bbox_offset = rotate_point(s.bbox_offset, s.r, new_r); s.bbox_size = rotate_size(s.bbox_size, s.r, new_r); @@ -143,6 +143,24 @@ bool scenery_ref::activate() return false; } +bool scenery::is_mesh_modified(const scenery& s0, const scenery& s) +{ + if (s.interactive != s0.interactive || s.type != s0.type) + return true; + if (!s.interactive) + return s.r != s0.r || s.offset != s0.offset || s0.frame != s.frame || s.type != s0.type; + return false; +} + +bool scenery::is_collision_modified(const scenery& s0, const scenery& s) +{ + // passability value is stored as object's id + // so don't optimize into (s.pass == pass) != (s0.pass == pass) + return s.r != s0.r || s.passability != s0.passability || + s.offset != s0.offset || + s.bbox_offset != s0.bbox_offset || s.bbox_size != s0.bbox_size; +} + #ifdef __GNUG__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wfloat-equal" diff --git a/src/scenery.hpp b/src/scenery.hpp index 1db631fb..439a83fc 100644 --- a/src/scenery.hpp +++ b/src/scenery.hpp @@ -48,6 +48,9 @@ struct scenery final scenery(door_tag_t, const anim_atlas& atlas, rotation r, bool is_open, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size); + static bool is_mesh_modified(const scenery& s1, const scenery& s2); + static bool is_collision_modified(const scenery& s1, const scenery& s2); + bool operator==(const scenery&) const noexcept; }; |