diff options
-rw-r--r-- | compat/iota.hpp | 23 | ||||
-rw-r--r-- | doc/cut-rectangle-hole.pdn | bin | 0 -> 239722 bytes | |||
-rw-r--r-- | editor/draw.cpp | 2 | ||||
-rw-r--r-- | serialize/old-savegame.cpp | 2 | ||||
-rw-r--r-- | src/hole.cpp | 45 | ||||
-rw-r--r-- | src/hole.hpp | 33 | ||||
-rw-r--r-- | test/app.cpp | 1 | ||||
-rw-r--r-- | test/app.hpp | 1 | ||||
-rw-r--r-- | test/hole.cpp | 216 |
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 Binary files differnew file mode 100644 index 00000000..d25b6176 --- /dev/null +++ b/doc/cut-rectangle-hole.pdn 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 |