summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--compat/iota.hpp23
-rw-r--r--doc/cut-rectangle-hole.pdnbin0 -> 239722 bytes
-rw-r--r--editor/draw.cpp2
-rw-r--r--serialize/old-savegame.cpp2
-rw-r--r--src/hole.cpp45
-rw-r--r--src/hole.hpp33
-rw-r--r--test/app.cpp1
-rw-r--r--test/app.hpp1
-rw-r--r--test/hole.cpp216
9 files changed, 322 insertions, 1 deletions
diff --git a/compat/iota.hpp b/compat/iota.hpp
new file mode 100644
index 00000000..91ad759c
--- /dev/null
+++ b/compat/iota.hpp
@@ -0,0 +1,23 @@
+#pragma once
+#include <array>
+
+namespace floormat::detail {
+
+template<typename Type, size_t Count>
+std::array<Type, Count> constexpr iota_array_()
+{
+ static_assert( size_t(Type(Count)) == Count );
+ std::array<Type, Count> ret;
+ for (size_t i = 0; i < Count; i++)
+ ret[i] = Type(i);
+ return ret;
+}
+
+} // namespace floormat::detail
+
+namespace floormat {
+
+template<typename Type, size_t Count>
+constexpr inline std::array<Type, Count> iota_array = detail::iota_array_<Type, Count>();
+
+} // namespace floormat
diff --git a/doc/cut-rectangle-hole.pdn b/doc/cut-rectangle-hole.pdn
new file mode 100644
index 00000000..d25b6176
--- /dev/null
+++ b/doc/cut-rectangle-hole.pdn
Binary files differ
diff --git a/editor/draw.cpp b/editor/draw.cpp
index 249bf72c..bae3dffb 100644
--- a/editor/draw.cpp
+++ b/editor/draw.cpp
@@ -134,7 +134,7 @@ void app::draw_collision_boxes()
const auto* rtree = c.rtree();
rtree->Search(min2f, max2f, [&](object_id data, const rect_type& rect) {
[[maybe_unused]] auto x = std::bit_cast<collision_data>(data);
-#if 1
+#if 0
if (x.tag == (uint64_t)collision_type::geometry)
return true;
#else
diff --git a/serialize/old-savegame.cpp b/serialize/old-savegame.cpp
index 4d4aa25a..247462b6 100644
--- a/serialize/old-savegame.cpp
+++ b/serialize/old-savegame.cpp
@@ -395,6 +395,8 @@ void reader_state::read_chunks(reader_t& s)
switch (type)
{
+ case object_type::hole:
+ fm_abort("not implemented");
case object_type::critter: {
critter_proto proto;
proto.offset = offset;
diff --git a/src/hole.cpp b/src/hole.cpp
index f9e6f05c..cdd409d7 100644
--- a/src/hole.cpp
+++ b/src/hole.cpp
@@ -1,7 +1,52 @@
#include "hole.hpp"
+//#include <mg/Functions.h>
namespace floormat {
+using bbox = cut_rectangle_result::bbox;
+
+namespace {
+
+
+} // namespace
+
+cut_rectangle_result cut_rectangle(cut_rectangle_result::bbox input, cut_rectangle_result::bbox hole)
+{
+ const auto ihalf = Vector2i{input.bbox_size/2};
+ const auto istart = input.position - ihalf;
+ const auto iend = input.position + Vector2i{input.bbox_size} - ihalf;
+ const auto hhalf = Vector2i{hole.bbox_size/2};
+ const auto hstart = hole.position - hhalf;
+ const auto hend = hole.position + Vector2i{hole.bbox_size} - hhalf;
+
+ //std::atomic_signal_fence(std::memory_order::relaxed); // compiler-only barrier
+
+ {
+ bool iempty = Vector2ui{input.bbox_size}.product() == 0;
+ bool hempty = Vector2ui{hole.bbox_size}.product() == 0;
+ bool empty_before_x = hend.x() <= istart.x();
+ bool empty_before_y = hend.y() <= istart.y();
+ bool empty_after_x = hstart.x() >= iend.x();
+ bool empty_after_y = hstart.y() >= iend.y();
+ if (iempty | hempty | empty_before_x | empty_before_y | empty_after_x | empty_after_y)
+ return {};
+ }
+
+ const bool sx = hstart.x() <= istart.x();
+ const bool ex = hend.x() >= iend.x();
+ const bool sy = hstart.y() <= istart.y();
+ const bool ey = hend.y() >= iend.y();
+
+ enum : uint8_t { SX, EX, SY, EY };
+ enum : uint8_t { startx = 1 << SX, endx = 1 << EX, starty = 1 << SY, endy = 1 << EY };
+
+ constexpr auto mask = uint8_t(startx | endx | starty | endy);
+ auto val = uint8_t(sx << SX | ex << EX | sy << SY | ey << EY);
+ CORRADE_ASSUME((val & mask) == val);
+ (void)val;
+
+ return {};
+}
} // namespace floormat
diff --git a/src/hole.hpp b/src/hole.hpp
index d97c72f9..bf01ccd2 100644
--- a/src/hole.hpp
+++ b/src/hole.hpp
@@ -1,7 +1,40 @@
#pragma once
+#include "object.hpp"
+#include <array>
namespace floormat {
+struct hole_proto final : object_proto
+{
+ bool affects_render : 1 = true;
+ bool affects_physics : 1 = false;
+};
+struct hole : object
+{
+ bool affects_render : 1 = true;
+ bool affects_physics : 1 = false;
+
+ hole(object_id id, class chunk& c, const hole_proto& proto);
+};
+
+struct cut_rectangle_result
+{
+ struct bbox
+ {
+ Vector2i position;
+ Vector2ub bbox_size;
+ };
+
+ struct rect { Vector2i min, max; };
+
+ uint8_t code = 0;
+ uint8_t size = 0;
+ std::array<rect, 8> ret;
+
+ operator ArrayView<const bbox>() const;
+};
+
+cut_rectangle_result cut_rectangle(cut_rectangle_result::bbox input, cut_rectangle_result::bbox hole);
} // namespace floormat
diff --git a/test/app.cpp b/test/app.cpp
index b6b032eb..4082211e 100644
--- a/test/app.cpp
+++ b/test/app.cpp
@@ -61,6 +61,7 @@ int App::exec()
FM_TEST(test_math),
FM_TEST(test_astar_pool),
FM_TEST(test_coords),
+ FM_TEST(test_hole),
FM_TEST(test_bptr),
FM_TEST(test_iptr),
FM_TEST(test_entity),
diff --git a/test/app.hpp b/test/app.hpp
index fff5a5fa..989b72be 100644
--- a/test/app.hpp
+++ b/test/app.hpp
@@ -24,6 +24,7 @@ void test_critter();
void test_dijkstra();
void test_entity();
void test_hash();
+void test_hole();
void test_iptr();
void test_json();
void test_json2();
diff --git a/test/hole.cpp b/test/hole.cpp
new file mode 100644
index 00000000..fd947137
--- /dev/null
+++ b/test/hole.cpp
@@ -0,0 +1,216 @@
+#include "app.hpp"
+#include "src/hole.hpp"
+#include "compat/array-size.hpp"
+#include "compat/map.hpp"
+#include "compat/iota.hpp"
+
+#ifdef __GNUG__
+#pragma GCC diagnostic ignored "-Wswitch-default"
+//#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#endif
+
+namespace floormat::Hole {
+//namespace {
+
+using bbox = cut_rectangle_result::bbox;
+
+enum class type : uint8_t
+{
+ // see `doc/cut-rectangle-hole'
+ _9 , // all
+ _10, // side-part
+ _11, // corner
+ _12, // full-side
+ _13, // middle
+ _14, // center
+};
+
+enum shift : uint8_t { __ = 0, x0 = 1 << 0, x1 = 1 << 1, y0 = 1 << 2, y1 = 1 << 3, };
+enum class location : uint8_t { R0, R1, H0, H1, };
+
+struct coords
+{
+ location x0 : 2;
+ location x1 : 2;
+ location y0 : 2;
+ location y1 : 2;
+};
+
+struct element
+{
+ uint8_t count;
+ std::array<coords, 8> array;
+};
+
+constexpr element make_element(uint8_t s)
+{
+ switch (s)
+ {
+ using enum type;
+ using enum location;
+ case x0|x1|y0|y1: return element{1, {{ // 9.1
+ {R0, R1, R0, R1},
+ }}};
+ case __|__|__|__: return element{8, {{ // 14.1
+ {R0, H0, R0, H0},
+ {H0, H1, R0, H0},
+ {H1, R1, R0, H0},
+ {R0, H0, H0, H1},
+ {H1, R1, H0, H1},
+ {R0, H0, H1, R1},
+ {H0, H1, H0, R1},
+ {H1, R1, H1, R1},
+ }}};
+
+ case x0|x1|__|__: return element{2, {{ // 13.1
+ {R0, R1, R0, H0},
+ {R0, R1, H1, R1},
+ }}};
+ case __|__|y0|y1: return element{2, {{ // 13.2
+ {R0, H0, H1, R1},
+ {R0, H0, H0, R1},
+ }}};
+
+ case x0|x1|y0|__: return element{1, {{ // 12.1
+ {R0, R1, H1, R1},
+ }}};
+ case x0|x1|__|y1: return element{1, {{ // 12.2
+ {R0, R1, R0, H0},
+ }}};
+ case x0|__|y0|y1: return element{1, {{ // 12.3
+ {H1, R1, R0, R1},
+ }}};
+ case __|x1|y0|y1: return element{1, {{ // 12.4
+ {R0, H0, R0, R1},
+ }}};
+
+ case x0|__|__|__: return element{3, {{ // 10.1
+ {R0, R1, R0, H0},
+ {H1, R1, H0, H1},
+ {R0, R1, H1, R1},
+ }}};
+ case __|x1|__|__: return element{3, {{ // 10.2
+ {R0, R1, R0, H0},
+ {R0, H0, H0, H1},
+ {R0, R1, H1, R1},
+ }}};
+ case __|__|y0|__: return element{3, {{ // 10.3
+ {R0, H0, R0, R1},
+ {H0, H1, H0, R1},
+ {H1, R1, R0, R1},
+ }}};
+ case __|__|__|y1: return element{3, {{ // 10.4
+ {R0, H0, R0, R1},
+ {H0, H1, R0, H0},
+ {H1, R1, R0, R1},
+ }}};
+
+ case x0|__|y0|__: return element{2, {{ // 11.1
+
+ }}};
+ case __|x1|y0|__: return element{2, {{ // 11.1
+
+ }}};
+ case x0|__|__|y1: return element{2, {{ // 11.1
+
+ }}};
+ case __|x1|__|y1: return element{2, {{ // 11.1
+
+ }}};
+ }
+ fm_assert(false);
+}
+constexpr auto elements = map(make_element, iota_array<uint8_t, 16>);
+static_assert(sizeof(elements) == 9 * 16);
+
+constexpr cut_rectangle_result cut(bbox input, bbox hole)
+{
+ auto ihalf = Vector2i{input.bbox_size/2};
+ auto r0 = input.position - ihalf;
+ auto r1 = input.position + Vector2i{input.bbox_size} - ihalf;
+
+ auto hhalf = Vector2i{hole.bbox_size/2};
+ auto h0 = hole.position - hhalf;
+ auto h1 = hole.position + Vector2i{hole.bbox_size} - hhalf;
+
+ {
+ bool iempty = Vector2ui{input.bbox_size}.product() == 0;
+ bool hempty = Vector2ui{hole.bbox_size}.product() == 0;
+ bool empty_before_x = h1.x() <= r0.x();
+ bool empty_after_x = h0.x() >= r1.x();
+ bool empty_before_y = h1.y() <= r0.y();
+ bool empty_after_y = h0.y() >= r1.y();
+
+ if (iempty | hempty | empty_before_x | empty_after_x | empty_before_y | empty_after_y) [[unlikely]]
+ return { 0, 0, {} };
+ }
+
+ const bool sx = h0.x() <= r0.x();
+ const bool ex = h1.x() >= r1.x();
+ const bool sy = h0.y() <= r0.y();
+ const bool ey = h1.y() >= r1.y();
+
+ auto val = uint8_t(sx << 0 | ex << 1 | sy << 2 | ey << 3);
+ CORRADE_ASSUME(val < 16);
+
+ //static_assert(array_size(starts) == 16);
+ fm_assert(false);
+ std::unreachable();
+
+ //return -1;
+}
+
+template<Int x, Int y>
+void test1()
+{
+ static constexpr auto vec = Vector2i{x, y};
+ constexpr auto rect = bbox{{}, {50, 50}};
+ constexpr auto cutʹ = [](bbox rect, bbox hole) {
+ auto rectʹ = bbox { rect.position + vec, rect.bbox_size };
+ auto holeʹ = bbox { hole.position + vec, hole.bbox_size };
+ return cut(rectʹ, holeʹ).code;
+ };
+#if 1
+ fm_assert_not_equal(0, cutʹ(rect, {{ 49, 0}, {50, 50}}));
+ fm_assert_not_equal(0, cutʹ(rect, {{ 0, 49}, {50, 50}}));
+ fm_assert_not_equal(0, cutʹ(rect, {{ 49, 49}, {50, 50}}));
+#endif
+#if 1
+ fm_assert_not_equal(0, cutʹ(rect, {{-49, 0}, {50, 50}}));
+ fm_assert_not_equal(0, cutʹ(rect, {{ 0, -49}, {50, 50}}));
+ fm_assert_not_equal(0, cutʹ(rect, {{ 49, -49}, {50, 50}}));
+#endif
+#if 1
+ fm_assert_equal(0, cutʹ(rect, {{50, 0}, {50, 50}}));
+ fm_assert_equal(0, cutʹ(rect, {{ 0, 50}, {50, 50}}));
+ fm_assert_equal(0, cutʹ(rect, {{50, 50}, {50, 50}}));
+#endif
+#if 1
+ fm_assert_equal(9, cutʹ(rect, {{ 9, 9}, {70, 70}}));
+ fm_assert_equal(9, cutʹ(rect, {{10, 10}, {70, 70}}));
+#endif
+#if 1
+ fm_assert_equal(12, cutʹ(rect, {{1, 0}, {50, 50}}));
+ fm_assert_equal(12, cutʹ(rect, {{0, 1}, {50, 50}}));
+ fm_assert_equal(11, cutʹ(rect, {{1, 1}, {50, 50}}));
+#endif
+#if 1
+ // todo! coverage
+#endif
+}
+
+//} // namespace
+} // namespace floormat::Hole
+
+namespace floormat {
+
+void Test::test_hole()
+{
+ Hole::test1< 0, 0 >();
+ Hole::test1< 110, 105 >();
+ Hole::test1< 15, 110 >();
+ Hole::test1< - 15, -110 >();
+ Hole::test1< -110, -15 >();
+}
+
+} // namespace floormat