summaryrefslogtreecommitdiffhomepage
path: root/editor/tests/region-test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'editor/tests/region-test.cpp')
-rw-r--r--editor/tests/region-test.cpp256
1 files changed, 256 insertions, 0 deletions
diff --git a/editor/tests/region-test.cpp b/editor/tests/region-test.cpp
new file mode 100644
index 00000000..e4691fc9
--- /dev/null
+++ b/editor/tests/region-test.cpp
@@ -0,0 +1,256 @@
+#include "../tests-private.hpp"
+#include "src/tile-constants.hpp"
+#include "src/chunk.hpp"
+#include "src/path-search.hpp"
+#include "../app.hpp"
+#include "../imgui-raii.hpp"
+#include "floormat/main.hpp"
+#include <bitset>
+#include <Corrade/Containers/Pointer.h>
+#include <Corrade/Containers/GrowableArray.h>
+#include <Magnum/Math/Vector2.h>
+#include <Magnum/Math/Functions.h>
+#include <Magnum/Math/Color.h>
+
+namespace floormat::tests {
+
+namespace {
+
+using namespace floormat::imgui;
+using detail_astar::div_factor;
+using detail_astar::div_size;
+template<typename T> using bbox = typename path_search::bbox<T>;
+
+constexpr auto div_min = -iTILE_SIZE2/2, div_max = TILE_MAX_DIM*iTILE_SIZE2 - iTILE_SIZE2/2;
+
+constexpr uint32_t chunk_dim = TILE_MAX_DIM*uint32_t{div_factor}+1,
+ chunk_nbits = chunk_dim * chunk_dim;
+//constexpr auto bbox_size = Vector2ub(iTILE_SIZE2/2);
+constexpr auto chunk_size = iTILE_SIZE2*Vector2i(TILE_MAX_DIM);
+constexpr auto visited_bits = chunk_dim * chunk_dim *4*4;
+constexpr auto div_count = Vector2i{TILE_MAX_DIM * div_factor};
+
+constexpr bbox<Int> bbox_from_pos1(Vector2i center/*, Vector2ui size*/) // from src/dijkstra.cpp
+{
+ //auto top_left = center - Vector2i(size / 2);
+ //auto bottom_right = top_left + Vector2i(size);
+ auto bottom_right = center + Vector2i(1);
+ //return { top_left, bottom_right };
+ return { center, bottom_right };
+}
+
+constexpr bbox<Int> bbox_from_pos2(Vector2i pt, Vector2i from/*, Vector2ui size*/) // from src/dijkstra.cpp
+{
+ auto bb0 = bbox_from_pos1(from/*, size*/);
+ auto bb = bbox_from_pos1(pt/*, size*/);
+ auto min = Math::min(bb0.min, bb.min);
+ auto max = Math::max(bb0.max, bb.max);
+ return { min, max };
+}
+
+constexpr bbox<Int> make_pos(Vector2i ij, Vector2i from)
+{
+ auto pos = div_min + div_size * ij;
+ auto pos0 = pos + from*div_size;
+ return bbox_from_pos2(pos, pos0/*, Vector2ui(div_size)*/);
+}
+
+bool check_pos(chunk& c, const std::array<chunk*, 8>& nbs, Vector2i ij, Vector2i from)
+{
+ auto pos = make_pos(ij, from);
+ bool ret = path_search::is_passable_(&c, nbs, Vector2(pos.min), Vector2(pos.max), 0);
+ //if (ret) Debug{} << "check" << ij << ij/div_factor << ij % div_factor << pos.min << pos.max << ret;
+ return ret;
+}
+
+struct pending_s
+{
+ chunk_coords_ c;
+ bool exists : 1 = false;
+};
+
+struct result_s
+{
+ std::bitset<chunk_nbits> is_passable;
+ chunk_coords_ c;
+ bool exists : 1 = false;
+};
+
+struct node_s
+{
+ Vector2i pos;
+};
+
+struct tmp_s
+{
+ Array<node_s> stack;
+ std::bitset<visited_bits> visited;
+ std::bitset<chunk_nbits> passable;
+ std::array<chunk*, 8> neighbors = {};
+
+ void append(Vector2i pos, int from);
+ static Pointer<tmp_s> make();
+ void clear();
+};
+
+void tmp_s::append(Vector2i pos, int from)
+{
+ auto i = (uint32_t)pos.y() * chunk_dim + (uint32_t)pos.x();
+ if (i >= passable.size())
+ return;
+ if (passable[i])
+ return;
+ passable[i] = true;
+ auto v = i*4 + (uint32_t)from;
+ fm_debug_assert(v < visited.size());
+ if (visited[v])
+ return;
+ visited[v] = true;
+ arrayAppend(stack, {pos});
+}
+
+Pointer<tmp_s> tmp_s::make()
+{
+ auto ptr = Pointer<tmp_s>{InPlace};
+ arrayResize(ptr->stack, 0);
+ arrayReserve(ptr->stack, TILE_COUNT);
+ ptr->visited = {};
+ ptr->passable = {};
+ ptr->neighbors = {};
+ return ptr;
+}
+
+void tmp_s::clear()
+{
+ arrayResize(stack, 0);
+ visited = {};
+ passable = {};
+ neighbors = {};
+}
+
+struct region_test : base_test
+{
+ result_s result;
+ pending_s pending;
+ Pointer<tmp_s> tmp;
+
+ tmp_s& get_tmp();
+ void do_region_extraction(world& w, chunk_coords_ coord);
+
+ ~region_test() noexcept override = default;
+
+ bool handle_key(app&, const key_event&, bool) override { return {}; }
+ bool handle_mouse_click(app& a, const mouse_button_event& e, bool is_down) override;
+ bool handle_mouse_move(app& a, const mouse_move_event& e) override { return {}; }
+ void draw_overlay(app& a) override;
+ void draw_ui(app&, float) override;
+ void update_pre(app&) override {}
+ void update_post(app& a) override;
+};
+
+tmp_s& region_test::get_tmp()
+{
+ if (tmp)
+ tmp->clear();
+ else
+ tmp = tmp_s::make();
+ return *tmp;
+}
+
+void region_test::do_region_extraction(world& w, chunk_coords_ coord)
+{
+ auto* c = w.at(coord);
+ if (!c)
+ {
+ result.exists = false;
+ pending.exists = false;
+ return;
+ }
+
+ auto& tmp = get_tmp();
+ const auto nbs = w.neighbors(coord);
+
+ static_assert(div_count.x() == div_count.y());
+ constexpr auto last = div_count - Vector2i{1};
+ constexpr Vector2i fours[4] = { {0, 1}, {0, -1}, {1, 0}, {-1, 0} };
+
+ //if (Vector2i from{0, -1}, pos{0, 0}; check_pos(*c, nbs, pos, from)) tmp.append(pos, 0); // bottom
+
+ for (Int i = 0; i < div_count.x(); i++)
+ {
+ if (Vector2i pos{i, last.y()}; check_pos(*c, nbs, pos, fours[0])) tmp.append(pos, 0); // bottom
+ if (Vector2i pos{i, 0}; check_pos(*c, nbs, pos, fours[1])) tmp.append(pos, 1); // top
+ if (Vector2i pos{last.x(), i}; check_pos(*c, nbs, pos, fours[2])) tmp.append(pos, 2); // right
+ if (Vector2i pos{0, i}; check_pos(*c, nbs, pos, fours[3])) tmp.append(pos, 3); // left
+ }
+ while (!tmp.stack.isEmpty())
+ {
+ auto p = tmp.stack.back().pos;
+ arrayRemoveSuffix(tmp.stack);
+ for (int i = 0; i < 4; i++)
+ {
+ Vector2i from = fours[i], pos{p - from};
+ if ((uint32_t)pos.x() < chunk_dim && (uint32_t)pos.y() < chunk_dim)
+ if (check_pos(*c, nbs, pos, from))
+ tmp.append(pos, i);
+ }
+ }
+
+ result = {
+ .is_passable = tmp.passable,
+ .c = coord,
+ .exists = true,
+ };
+
+ Debug{} << "done!" << tmp.passable.count();
+}
+
+void region_test::draw_overlay(app& a)
+{
+
+}
+
+void region_test::draw_ui(app& a, float width)
+{
+
+}
+
+bool region_test::handle_mouse_click(app& a, const mouse_button_event& e, bool is_down)
+{
+ if (e.button == mouse_button_left && is_down)
+ {
+ auto& M = a.main();
+ auto& w = M.world();
+ if (auto pt_ = a.cursor_state().point())
+ {
+ pending = {
+ .c = pt_->chunk3(),
+ .exists = true,
+ };
+ return true;
+ }
+ }
+ else if (e.button == mouse_button_right && is_down)
+ {
+ pending.exists = false;
+ result.exists = false;
+ }
+ return false;
+}
+
+void region_test::update_post(app& a)
+{
+ if (pending.exists)
+ {
+ pending.exists = false;
+ auto& M = a.main();
+ auto& w = M.world();
+ do_region_extraction(w, pending.c);
+ }
+}
+
+} // namespace
+
+Pointer<base_test> tests_data::make_test_region() { return Pointer<region_test>{InPlaceInit}; }
+
+} // namespace floormat::tests