summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2023-03-01 17:23:27 +0100
committerStanislaw Halik <sthalik@misaki.pl>2023-03-01 17:23:27 +0100
commit257c2420545eb632a53c0fe3cd317be613dcb272 (patch)
tree95dfb97898f84ea60b293e60453bef1c57088fa4 /src
parentf6aed5a3ae2e6b2b2eb822deee0a579ca66cd13f (diff)
editor: update bboxes from a central place
Diffstat (limited to 'src')
-rw-r--r--src/chunk-collision.cpp92
-rw-r--r--src/chunk.cpp3
-rw-r--r--src/chunk.hpp49
-rw-r--r--src/scenery.cpp12
-rw-r--r--src/scenery.hpp3
5 files changed, 128 insertions, 31 deletions
diff --git a/src/chunk-collision.cpp b/src/chunk-collision.cpp
index 5b85de1e..bd761b03 100644
--- a/src/chunk-collision.cpp
+++ b/src/chunk-collision.cpp
@@ -18,36 +18,36 @@ constexpr Vector2 tile_start(std::size_t k)
return TILE_SIZE2 * Vector2(coord) - half_tile;
}
-constexpr Pair<Vector2, Vector2> scenery_tile(std::size_t k, const scenery& sc)
+constexpr Pair<Vector2i, Vector2i> scenery_tile(std::size_t k, const scenery& sc)
{
const local_coords coord{k};
- auto center = TILE_SIZE2 * Vector2(coord) + Vector2(sc.offset) + Vector2(sc.bbox_offset);
- auto start = center - Vector2(sc.bbox_size);
- auto size = Vector2(sc.bbox_size)*2;
+ auto center = iTILE_SIZE2 * Vector2i(coord) + Vector2i(sc.offset) + Vector2i(sc.bbox_offset);
+ auto start = center - Vector2i(sc.bbox_size);
+ auto size = Vector2i(sc.bbox_size)*2;
return { start, start + size, };
-};
+}
constexpr Pair<Vector2, Vector2> whole_tile(std::size_t k)
{
auto start = tile_start(k);
return { start, start + TILE_SIZE2, };
-};
+}
constexpr Pair<Vector2, Vector2> wall_north(std::size_t k)
{
auto start = tile_start(k) - Vector2(0, 1);
return { start, start + Vector2(TILE_SIZE2[0], 2), };
-};
+}
constexpr Pair<Vector2, Vector2> wall_west(std::size_t k)
{
auto start = tile_start(k) - Vector2(1, 0);
return { start, start + Vector2(2, TILE_SIZE2[1]), };
-};
+}
-constexpr std::uint64_t make_id(collision_type type, std::uint64_t id)
+constexpr std::uint64_t make_id(collision_type type, pass_mode p, std::uint64_t id)
{
- return std::bit_cast<std::uint64_t>(collision_data { (std::uint64_t)type, id });
+ return std::bit_cast<std::uint64_t>(collision_data { (std::uint64_t)type, (std::uint64_t)p, id });
}
} // namespace
@@ -62,22 +62,20 @@ void chunk::ensure_passability() noexcept
for (auto i = 0_uz; i < TILE_COUNT; i++)
{
- auto tile = operator[](i);
- if (auto s = tile.scenery())
- if (s.frame.passability != pass_mode::pass && Vector2ui(s.frame.bbox_size).product() > 0)
- {
- auto [start, end] = scenery_tile(i, s.frame);
- auto id = make_id(collision_type::scenery, i);
- _rtree.Insert(start.data(), end.data(), id);
- }
+ if (auto s = operator[](i).scenery())
+ {
+ bbox box;
+ if (_bbox_for_scenery(i, box))
+ _add_bbox(box);
+ }
}
for (auto i = 0_uz; i < TILE_COUNT; i++)
{
if (const auto* atlas = ground_atlas_at(i))
- if (atlas->pass_mode(pass_mode::pass) != pass_mode::pass)
+ if (auto p = atlas->pass_mode(pass_mode::pass); p != pass_mode::pass)
{
auto [start, end] = whole_tile(i);
- auto id = make_id(collision_type::geometry, i);
+ auto id = make_id(collision_type::geometry, p, i);
_rtree.Insert(start.data(), end.data(), id);
}
}
@@ -85,20 +83,66 @@ void chunk::ensure_passability() noexcept
{
auto tile = operator[](i);
if (const auto* atlas = tile.wall_north_atlas().get())
- if (atlas->pass_mode(pass_mode::blocked) != pass_mode::pass)
+ if (auto p = atlas->pass_mode(pass_mode::blocked); p != pass_mode::pass)
{
auto [start, end] = wall_north(i);
- auto id = make_id(collision_type::geometry, i);
+ auto id = make_id(collision_type::geometry, p, i);
_rtree.Insert(start.data(), end.data(), id);
}
if (const auto* atlas = tile.wall_west_atlas().get())
- if (atlas->pass_mode(pass_mode::blocked) != pass_mode::pass)
+ if (auto p = atlas->pass_mode(pass_mode::blocked); p != pass_mode::pass)
{
auto [start, end] = wall_west(i);
- auto id = make_id(collision_type::geometry, i);
+ auto id = make_id(collision_type::geometry, p, i);
_rtree.Insert(start.data(), end.data(), id);
}
}
}
+bool chunk::_bbox_for_scenery(std::size_t i, bbox& value) noexcept
+{
+ fm_debug_assert(i < TILE_COUNT);
+ auto [atlas, s] = operator[](i).scenery();
+ auto [start, end] = scenery_tile(i, s);
+ auto id = make_id(collision_type::scenery, s.passability, i);
+ value = { .id = id, .start = start, .end = end };
+ return atlas && s.passability != pass_mode::pass && Vector2i(s.bbox_size).product() > 0;
+}
+
+void chunk::_remove_bbox(const bbox& x)
+{
+ auto start = Vector2(x.start), end = Vector2(x.end);
+ fm_assert(_rtree.Remove(start.data(), end.data(), x.id));
+}
+
+void chunk::_add_bbox(const bbox& x)
+{
+ 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)
+{
+ unsigned i = (unsigned)b1 << 1 | (unsigned)(b0 ? 1 : 0) << 0;
+ CORRADE_ASSUME(i < 4u);
+
+ switch (i) // NOLINT(hicpp-multiway-paths-covered)
+ {
+ case 1 << 1 | 1 << 0:
+ if (x1 == x0)
+ return;
+ _remove_bbox(x0);
+ [[fallthrough]];
+ case 1 << 1 | 0 << 0:
+ _add_bbox(x1);
+ return;
+ case 0 << 1 | 1 << 0:
+ _remove_bbox(x0);
+ return;
+ case 0 << 1 | 0 << 0:
+ return;
+ }
+ CORRADE_ASSUME(false);
+}
+
} // namespace floormat
diff --git a/src/chunk.cpp b/src/chunk.cpp
index b7f54e4d..8310c756 100644
--- a/src/chunk.cpp
+++ b/src/chunk.cpp
@@ -34,6 +34,7 @@ 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; }
+bool chunk::is_passability_modified() const noexcept { return _pass_modified; }
void chunk::mark_modified() noexcept
{
@@ -48,4 +49,6 @@ chunk::~chunk() noexcept = default;
chunk::chunk(chunk&&) noexcept = default;
chunk& chunk::operator=(chunk&&) noexcept = default;
+bool chunk::bbox::operator==(const bbox& other) const noexcept = default;
+
} // namespace floormat
diff --git a/src/chunk.hpp b/src/chunk.hpp
index 8d6f5a6b..54f59e2d 100644
--- a/src/chunk.hpp
+++ b/src/chunk.hpp
@@ -2,6 +2,7 @@
#include "tile.hpp"
#include "tile-iterator.hpp"
#include "scenery.hpp"
+#include <concepts>
#include <type_traits>
#include <array>
#include <memory>
@@ -22,7 +23,8 @@ enum class collision_type : std::uint8_t {
struct collision_data final {
std::uint64_t tag : 2;
- std::uint64_t data : 62;
+ std::uint64_t pass : 2;
+ std::uint64_t data : 60;
};
struct chunk final
@@ -56,6 +58,7 @@ 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_modified() noexcept;
struct ground_mesh_tuple final {
@@ -92,6 +95,9 @@ struct chunk final
const RTree* rtree() const noexcept;
RTree* rtree() noexcept;
+ template<std::invocable<tile_ref&> F> void with_scenery_bbox_update(tile_ref t, F&& fun);
+ template<std::invocable<> F> void with_scenery_bbox_update(std::size_t i, F&& fun);
+
private:
std::array<std::shared_ptr<tile_atlas>, TILE_COUNT> _ground_atlases;
std::array<std::uint8_t, TILE_COUNT> ground_indexes = {};
@@ -112,6 +118,47 @@ private:
_walls_modified : 1 = true,
_scenery_modified : 1 = true,
_pass_modified : 1 = true;
+
+ struct bbox final // NOLINT(cppcoreguidelines-pro-type-member-init)
+ {
+ std::uint64_t id;
+ Vector2i start, end;
+
+ bool operator==(const bbox& other) const noexcept;
+ };
+ bool _bbox_for_scenery(std::size_t i, 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);
};
+template<std::invocable<tile_ref&> F>
+void chunk::with_scenery_bbox_update(tile_ref t, F&& fun)
+{
+ if (is_passability_modified())
+ return fun(t);
+ else
+ {
+ bbox x0, x;
+ std::size_t i = t.index();
+ bool b0 = _bbox_for_scenery(i, x0);
+ fun(t);
+ _replace_bbox(x0, x, b0, _bbox_for_scenery(i, x));
+ }
+}
+
+template<std::invocable<> F>
+void chunk::with_scenery_bbox_update(std::size_t i, F&& fun)
+{
+ if (is_passability_modified())
+ return fun();
+ else
+ {
+ bbox x0, x;
+ bool b0 = _bbox_for_scenery(i, x0);
+ fun();
+ _replace_bbox(x0, x, b0, _bbox_for_scenery(i, x));
+ }
+}
+
} // namespace floormat
diff --git a/src/scenery.cpp b/src/scenery.cpp
index 86ebea73..f21f95c2 100644
--- a/src/scenery.cpp
+++ b/src/scenery.cpp
@@ -66,13 +66,15 @@ scenery::scenery(door_tag_t, const anim_atlas& atlas, rotation r, bool is_open,
void scenery_ref::rotate(rotation new_r)
{
- 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);
- s.r = new_r;
+ c->with_scenery_bbox_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);
+ s.r = new_r;
+ });
}
-bool scenery_ref::can_activate() noexcept
+bool scenery_ref::can_activate() const noexcept
{
return frame.interactive;
}
diff --git a/src/scenery.hpp b/src/scenery.hpp
index 7d2cb502..3a8fb241 100644
--- a/src/scenery.hpp
+++ b/src/scenery.hpp
@@ -81,6 +81,7 @@ struct scenery_ref final {
scenery_ref(struct chunk& c, std::size_t i) noexcept;
scenery_ref(const scenery_ref&) noexcept;
scenery_ref(scenery_ref&&) noexcept;
+ scenery_ref& operator=(const scenery_ref&) = delete;
scenery_ref& operator=(const scenery_proto& proto) noexcept;
operator scenery_proto() const noexcept;
@@ -95,7 +96,7 @@ struct scenery_ref final {
std::shared_ptr<anim_atlas>& atlas;
scenery& frame;
- bool can_activate() noexcept;
+ bool can_activate() const noexcept;
bool activate();
void update(float dt);
void rotate(rotation r);