summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--editor/imgui-inspect.cpp2
-rw-r--r--editor/inspect-types.cpp15
-rw-r--r--editor/update.cpp2
-rw-r--r--src/chunk.cpp51
-rw-r--r--src/chunk.hpp11
-rw-r--r--src/chunk.inl51
-rw-r--r--src/scenery.cpp20
-rw-r--r--src/scenery.hpp3
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;
};