diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/RTree-fwd.h | 7 | ||||
| -rw-r--r-- | src/RTree.cpp | 3 | ||||
| -rw-r--r-- | src/RTree.h | 6 | ||||
| -rw-r--r-- | src/anim-atlas.cpp | 8 | ||||
| -rw-r--r-- | src/anim.cpp | 1 | ||||
| -rw-r--r-- | src/chunk-collision.cpp | 90 | ||||
| -rw-r--r-- | src/chunk-region.cpp | 4 | ||||
| -rw-r--r-- | src/chunk-render.cpp | 8 | ||||
| -rw-r--r-- | src/chunk-scenery.cpp | 21 | ||||
| -rw-r--r-- | src/chunk-walls.cpp | 533 | ||||
| -rw-r--r-- | src/chunk.cpp | 18 | ||||
| -rw-r--r-- | src/chunk.hpp | 19 | ||||
| -rw-r--r-- | src/collision.hpp | 6 | ||||
| -rw-r--r-- | src/critter-script-walk.cpp | 1 | ||||
| -rw-r--r-- | src/critter.cpp | 103 | ||||
| -rw-r--r-- | src/hole-cut.cpp | 89 | ||||
| -rw-r--r-- | src/hole-cut.hpp | 25 | ||||
| -rw-r--r-- | src/hole.hpp | 16 | ||||
| -rw-r--r-- | src/object.cpp | 2 | ||||
| -rw-r--r-- | src/object.hpp | 1 | ||||
| -rw-r--r-- | src/point.hpp | 4 | ||||
| -rw-r--r-- | src/raycast.cpp | 6 | ||||
| -rw-r--r-- | src/script.cpp | 10 | ||||
| -rw-r--r-- | src/search.cpp | 2 | ||||
| -rw-r--r-- | src/tile-bbox.hpp | 28 | ||||
| -rw-r--r-- | src/wall-atlas.hpp | 10 | ||||
| -rw-r--r-- | src/wall-defs.hpp | 2 | ||||
| -rw-r--r-- | src/world.cpp | 7 | ||||
| -rw-r--r-- | src/world.hpp | 2 |
29 files changed, 591 insertions, 441 deletions
diff --git a/src/RTree-fwd.h b/src/RTree-fwd.h index a93ec168..e5bcb35e 100644 --- a/src/RTree-fwd.h +++ b/src/RTree-fwd.h @@ -1,5 +1,12 @@ #pragma once +#include "object-id.hpp" template<class DATATYPE, class ELEMTYPE, int NUMDIMS, class ELEMTYPEREAL = ELEMTYPE, int TMAXNODES = 8, int TMINNODES = TMAXNODES / 2> class RTree; + +namespace floormat { + +using Chunk_RTree = ::RTree<object_id, float, 2, float>; + +} // namespace floormat diff --git a/src/RTree.cpp b/src/RTree.cpp index f77d0697..fcefdbcf 100644 --- a/src/RTree.cpp +++ b/src/RTree.cpp @@ -64,8 +64,7 @@ template<typename T> T* rtree_pool<T>::construct() template<typename T> void rtree_pool<T>::free(T* ptr) { ptr->~T(); - node_p p = {.ptr = ptr }; - node_u* n = p.data_ptr; + auto* n = reinterpret_cast<node_u*>(ptr); n->next = free_list; free_list = n; } diff --git a/src/RTree.h b/src/RTree.h index 7b8eeb7c..bbf9a486 100644 --- a/src/RTree.h +++ b/src/RTree.h @@ -37,13 +37,9 @@ template<typename T> struct rtree_pool final void free(T* pool); union node_u { - union { T data; }; + union { T data; char _empty = {}; }; node_u* next; }; - union node_p { - T* ptr; - node_u* data_ptr; - }; private: node_u* free_list = nullptr; diff --git a/src/anim-atlas.cpp b/src/anim-atlas.cpp index 43ba69b2..ee05987f 100644 --- a/src/anim-atlas.cpp +++ b/src/anim-atlas.cpp @@ -11,12 +11,14 @@ namespace floormat { +namespace { +constexpr inline char name_array[][3] = { "n", "ne", "e", "se", "s", "sw", "w", "nw", }; +constexpr inline auto rot_count = size_t(rotation_COUNT); +} // namespace + template class bptr<anim_atlas>; template class bptr<const anim_atlas>; -static constexpr const char name_array[][3] = { "n", "ne", "e", "se", "s", "sw", "w", "nw", }; -static constexpr inline auto rot_count = size_t(rotation_COUNT); - static_assert(array_size(name_array) == rot_count); static_assert(rot_count == 8); diff --git a/src/anim.cpp b/src/anim.cpp index 717b3ee6..db724154 100644 --- a/src/anim.cpp +++ b/src/anim.cpp @@ -1,6 +1,7 @@ #include "anim.hpp" #include "compat/exception.hpp" #include <cmath> +#include <utility> namespace floormat { diff --git a/src/chunk-collision.cpp b/src/chunk-collision.cpp index ec6f4ff2..b0170755 100644 --- a/src/chunk-collision.cpp +++ b/src/chunk-collision.cpp @@ -10,6 +10,7 @@ #include "src/hole.hpp" #include "src/wall-atlas.hpp" #include <bit> +#include <utility> #include <Corrade/Containers/StructuredBindings.h> #include <Corrade/Containers/Pair.h> @@ -17,7 +18,7 @@ namespace floormat { bool collision_data::operator==(const collision_data&) const noexcept = default; bool chunk::bbox::operator==(const floormat::chunk::bbox& other) const noexcept = default; -chunk::RTree* chunk::rtree() noexcept { ensure_passability(); return &*_rtree; } +Chunk_RTree* chunk::rtree() noexcept { ensure_passability(); return &*_rtree; } world& chunk::world() noexcept { return *_world; } namespace { @@ -34,7 +35,7 @@ constexpr object_id make_id(collision_type type, pass_mode p, object_id id) } template<bool IsNeighbor> -bool add_holes_from_chunk(chunk::RTree& rtree, chunk& c, Vector2b chunk_offset) +bool add_holes_from_chunk(Chunk_RTree& rtree, chunk& c, Vector2b chunk_offset) { bool has_holes = false; constexpr auto chunk_size = iTILE_SIZE2 * TILE_MAX_DIM; @@ -65,47 +66,22 @@ bool add_holes_from_chunk(chunk::RTree& rtree, chunk& c, Vector2b chunk_offset) return has_holes; } -#if 1 -CORRADE_NEVER_INLINE -bool find_hole_in_bbox(CutResult<float>::rect& hole, chunk::RTree& rtree, Vector2 min, Vector2 max) -{ - bool ret = true; - rtree.Search(min.data(), max.data(), [&](uint64_t data, const chunk::RTree::Rect& r) { - auto x = std::bit_cast<collision_data>(data); - if (x.pass == (uint64_t)pass_mode::pass && x.tag == (uint64_t)collision_type::none) - { - CutResult<float>::rect holeʹ { - .min = { r.m_min[0], r.m_min[1] }, - .max = { r.m_max[0], r.m_max[1] }, - }; - if (rect_intersects(holeʹ.min, holeʹ.max, min, max)) - { - hole = holeʹ; - return ret = false; - } - } - return true; - }); - return ret; -} - -CORRADE_NEVER_INLINE -void filter_through_holes(chunk::RTree& rtree, object_id id, Vector2 min, Vector2 max, bool has_holes) +void filter_through_holes(Chunk_RTree& rtree, object_id id, Vector2 min, Vector2 max, bool has_holes) { if (!has_holes) return rtree.Insert(min.data(), max.data(), id); start: - fm_assert(min != max); // todo! + fm_assert(min != max); CutResult<float>::rect hole; - bool ret = find_hole_in_bbox(hole, rtree, min, max); + bool ret = chunk::find_hole_in_bbox(hole, rtree, min, max); if (ret) [[likely]] rtree.Insert(min.data(), max.data(), id); else { auto res = CutResult<float>::cut(min, max, hole.min, hole.max); - if (!res.found) + if (!res.found()) { rtree.Insert(min.data(), max.data(), id); } @@ -117,19 +93,40 @@ start: } else { - for (auto i = 0uz; i < res.size; i++) + for (auto i = 0u; i < res.size; i++) filter_through_holes(rtree, id, res.array[i].min, res.array[i].max, has_holes); } } } -#else -void filter_through_holes(chunk::RTree& rtree, object_id id, Vector2 min, Vector2 max, bool) + +} // namespace + +#if 1 +bool chunk::find_hole_in_bbox(CutResult<float>::rect& hole, const Chunk_RTree& rtree, Vector2 min, Vector2 max) { - rtree.Insert(min.data(), max.data(), id); + bool ret = true; + rtree.Search(min.data(), max.data(), [&](uint64_t data, const Chunk_RTree::Rect& r) { + auto x = std::bit_cast<collision_data>(data); + if (x.pass == (uint64_t)pass_mode::pass && x.type == (uint64_t)collision_type::none) + { + CutResult<float>::rect holeʹ { + .min = { r.m_min[0], r.m_min[1] }, + .max = { r.m_max[0], r.m_max[1] }, + }; + if (rect_intersects(holeʹ.min, holeʹ.max, min, max)) + { + hole = holeʹ; + return ret = false; + } + } + return true; + }); + return ret; } +#else +bool chunk::find_hole_in_bbox(CutResult<float>::rect&, Chunk_RTree&, Vector2, Vector2) { return true; } #endif - -} // namespace +bool chunk::find_hole_in_bbox(CutResult<float>::rect& hole, Vector2 min, Vector2 max) { return find_hole_in_bbox(hole, *rtree(), min, max); } void chunk::ensure_passability() noexcept { @@ -143,15 +140,16 @@ void chunk::ensure_passability() noexcept //Debug{} << ".. reset passability" << _coord; bool has_holes = false; + auto& rtree = *_rtree; { - has_holes |= add_holes_from_chunk<false>(*_rtree, *this, {}); + has_holes |= add_holes_from_chunk<false>(rtree, *this, {}); const auto nbs = _world->neighbors(_coord); for (auto i = 0u; i < 8; i++) if (nbs[i]) - has_holes |= add_holes_from_chunk<true>(*_rtree, *nbs[i], world::neighbor_offsets[i]); + has_holes |= add_holes_from_chunk<true>(rtree, *nbs[i], world::neighbor_offsets[i]); } - for (auto i = 0uz; i < TILE_COUNT; i++) + for (auto i = 0u; i < TILE_COUNT; i++) { if (const auto* atlas = ground_atlas_at(i)) { @@ -160,29 +158,29 @@ void chunk::ensure_passability() noexcept if (pass == pass_mode::pass) [[likely]] continue; auto id = make_id(collision_type::geometry, pass, i+1); - filter_through_holes(*_rtree, id, min, max, has_holes); + filter_through_holes(rtree, id, min, max, has_holes); } } - for (auto i = 0uz; i < TILE_COUNT; i++) + for (auto i = 0u; i < TILE_COUNT; i++) { auto tile = operator[](i); if (const auto* atlas = tile.wall_north_atlas().get()) { auto [min, max] = wall_north(i, (float)atlas->info().depth); auto id = make_id(collision_type::geometry, atlas->info().passability, TILE_COUNT+i+1); - filter_through_holes(*_rtree, id, min, max, has_holes); + filter_through_holes(rtree, id, min, max, has_holes); if (tile.wall_west_atlas()) { auto [min, max] = wall_pillar(i, (float)atlas->info().depth); - filter_through_holes(*_rtree, id, min, max, has_holes); + filter_through_holes(rtree, id, min, max, has_holes); } } if (const auto* atlas = tile.wall_west_atlas().get()) { auto [min, max] = wall_west(i, (float)atlas->info().depth); auto id = make_id(collision_type::geometry, atlas->info().passability, TILE_COUNT*2+i+1); - filter_through_holes(*_rtree, id, min, max, has_holes); + filter_through_holes(rtree, id, min, max, has_holes); } } for (const bptr<object>& eʹ : objects()) @@ -193,7 +191,7 @@ void chunk::ensure_passability() noexcept if (_bbox_for_scenery(*eʹ, bb)) { if (!eʹ->is_dynamic()) - filter_through_holes(*_rtree, std::bit_cast<object_id>(bb.data), Vector2(bb.start), Vector2(bb.end), has_holes); + filter_through_holes(rtree, std::bit_cast<object_id>(bb.data), Vector2(bb.start), Vector2(bb.end), has_holes); else _add_bbox_dynamic(bb); } diff --git a/src/chunk-region.cpp b/src/chunk-region.cpp index 3c5a8746..ed978c0f 100644 --- a/src/chunk-region.cpp +++ b/src/chunk-region.cpp @@ -119,10 +119,10 @@ auto default_region_predicate(chunk& c) noexcept return [&c](collision_data data) { auto x = std::bit_cast<collision_data>(data); // XXX 'scenery' is used for all object types - if (x.tag == (uint64_t)collision_type::scenery) + if (x.type == (uint64_t)collision_type::scenery) { auto& w = c.world(); - auto obj = w.find_object(x.data); + auto obj = w.find_object(x.id); if (obj->type() == object_type::critter) return path_search_continue::pass; } diff --git a/src/chunk-render.cpp b/src/chunk-render.cpp index 529d4f64..0c5d5bc6 100644 --- a/src/chunk-render.cpp +++ b/src/chunk-render.cpp @@ -52,9 +52,15 @@ auto chunk::ensure_ground_mesh() noexcept -> ground_mesh_tuple if (_ground->atlases[i]) _ground->indexes[count++] = uint8_t(i); + if (count == 0) + { + ground_mesh = GL::Mesh{NoCreate}; + return { ground_mesh, {}, 0 }; + } + std::sort(_ground->indexes.begin(), _ground->indexes.begin() + count, [this](uint8_t a, uint8_t b) { - return _ground->atlases[a] < _ground->atlases[b]; + return _ground->atlases[a].get() < _ground->atlases[b].get(); }); float hack_offset = _coord.z <= 0 ? -16.f : 0.f; // XXX hack diff --git a/src/chunk-scenery.cpp b/src/chunk-scenery.cpp index 2e491d4d..e928abac 100644 --- a/src/chunk-scenery.cpp +++ b/src/chunk-scenery.cpp @@ -64,6 +64,8 @@ auto make_topo_sort_data(object& e, uint32_t mesh_idx) -> topo_sort_data return data; } +// todo! switch to using a stack as in https://www.geeksforgeeks.org/topological-sorting/ + void topo_dfs(Array<chunk::object_draw_order>& array, size_t& output, size_t i, size_t size) // NOLINT(misc-no-recursion) { using m = typename chunk::topo_sort_data::m; @@ -177,13 +179,18 @@ auto chunk::ensure_scenery_mesh(scenery_scratch_buffers buffers) noexcept -> sce i++; } - GL::Mesh mesh{GL::MeshPrimitive::Triangles}; - auto vert_view = ArrayView<const std::array<vertex, 4>>{scenery_vertexes, count}; - auto index_view = ArrayView<const std::array<UnsignedShort, 6>>{scenery_indexes, count}; - mesh.addVertexBuffer(GL::Buffer{vert_view}, 0, tile_shader::Position{}, tile_shader::TextureCoordinates{}, tile_shader::Depth{}) - .setIndexBuffer(GL::Buffer{index_view}, 0, GL::MeshIndexType::UnsignedShort) - .setCount(int32_t(6 * count)); - scenery_mesh = move(mesh); + if (count == 0) + scenery_mesh = GL::Mesh{NoCreate}; + else + { + GL::Mesh mesh{GL::MeshPrimitive::Triangles}; + auto vert_view = ArrayView<const std::array<vertex, 4>>{scenery_vertexes, count}; + auto index_view = ArrayView<const std::array<UnsignedShort, 6>>{scenery_indexes, count}; + mesh.addVertexBuffer(GL::Buffer{vert_view}, 0, tile_shader::Position{}, tile_shader::TextureCoordinates{}, tile_shader::Depth{}) + .setIndexBuffer(GL::Buffer{index_view}, 0, GL::MeshIndexType::UnsignedShort) + .setCount(int32_t(6 * count)); + scenery_mesh = move(mesh); + } } const auto size = _objects.size(); diff --git a/src/chunk-walls.cpp b/src/chunk-walls.cpp index fb4b6560..39faf0bd 100644 --- a/src/chunk-walls.cpp +++ b/src/chunk-walls.cpp @@ -2,11 +2,15 @@ #include "tile-bbox.hpp" #include "quads.hpp" #include "wall-atlas.hpp" +#include "tile-bbox.hpp" +#include "compat/unroll.hpp" +#include "RTree-search.hpp" #include "shaders/shader.hpp" -#include <Corrade/Containers/ArrayViewStl.h> -#include <Corrade/Containers/Pair.h> -#include <Corrade/Containers/Optional.h> +#include <cr/ArrayViewStl.h> +#include <cr/GrowableArray.h> +#include <cr/Optional.h> #include <utility> +#include <concepts> #include <algorithm> #include <ranges> @@ -30,116 +34,232 @@ wall_atlas* chunk::wall_atlas_at(size_t i) const noexcept namespace { +using Wall::Group; using Wall::Group_; using Wall::Direction_; +using Wall::Frame; + +template<typename T> using Vec2_ = VectorTypeFor<2, T>; +template<typename T> using Vec3_ = VectorTypeFor<3, T>; + +template<typename F, size_t N> +struct minmax_v +{ + VectorTypeFor<N, F> min, max; +}; -constexpr Quads::quad get_quad(Direction_ D, Group_ G, float depth) +struct quad_table_entry { - CORRADE_ASSUME(D < Direction_::COUNT); - CORRADE_ASSUME(G < Group_::COUNT); - constexpr Vector2 half_tile = TILE_SIZE2*.5f; - constexpr float X = half_tile.x(), Y = half_tile.y(), Z = TILE_SIZE.z(); - const bool is_west = D == Wall::Direction_::W; + bool x : 1, y : 1, z : 1, dmx :1 = false, dmy : 1 = false, _fuzz : 3 = false; +}; +static_assert(sizeof(quad_table_entry) == sizeof(uint8_t)); +template<bool IsWest> +constexpr std::array<quad_table_entry, 4> make_quad_table_entry(Group_ G) +{ fm_assert(G < Group_::COUNT); + + constexpr bool x0 = false, x1 = true, + y0 = false, y1 = true, + z0 = false, z1 = true; + constexpr bool t = true, f = false; + switch (G) { using enum Group_; case COUNT: std::unreachable(); case wall: - if (!is_west) + if (!IsWest) return {{ - { X, -Y, 0 }, - { X, -Y, Z }, - {-X, -Y, 0 }, - {-X, -Y, Z }, + { x1, y0, z0 }, + { x1, y0, z1 }, + { x0, y0, z0 }, + { x0, y0, z1 }, }}; else return {{ - {-X, -Y, 0 }, - {-X, -Y, Z }, - {-X, Y, 0 }, - {-X, Y, Z }, + { x0, y0, z0 }, + { x0, y0, z1 }, + { x0, y1, z0 }, + { x0, y1, z1 }, }}; case side: - if (!is_west) + if (!IsWest) return {{ - { X, -Y - depth, 0 }, - { X, -Y - depth, Z }, - { X, -Y, 0 }, - { X, -Y, Z }, + { x1, y0, z0, f, t }, + { x1, y0, z1, f, t }, + { x1, y0, z0 }, + { x1, y0, z1 }, }}; else return {{ - { -X, Y, 0 }, - { -X, Y, Z }, - { -X - depth, Y, 0 }, - { -X - depth, Y, Z }, + { x0, y1, z0 }, + { x0, y1, z1 }, + { x0, y1, z0, t, f }, + { x0, y1, z1, t, f }, }}; case top: - if (!is_west) + if (!IsWest) return {{ - { -X, -Y - depth, Z }, - { X, -Y - depth, Z }, - { -X, -Y, Z }, - { X, -Y, Z }, + { x0, y0, z1, f, t }, + { x1, y0, z1, f, t }, + { x0, y0, z1 }, + { x1, y0, z1 }, }}; else return {{ - { -X, -Y, Z }, - { -X, Y, Z }, - { -X - depth, -Y, Z }, - { -X - depth, Y, Z }, + { x0, y0, z1 }, + { x0, y1, z1 }, + { x0, y0, z1, t, f }, + { x0, y1, z1, t, f }, }}; case corner: - if (!is_west) + if (!IsWest) return {{ - {-X, -Y, 0 }, - {-X, -Y, Z }, - {-X - depth, -Y, 0 }, - {-X - depth, -Y, Z }, + { x0, y0, z0 }, + { x0, y0, z1 }, + { x0, y0, z0, t, f }, + { x0, y0, z1, t, f }, }}; else return {{ - {-X, -Y - depth, 0 }, - {-X, -Y - depth, Z }, - {-X, -Y, 0 }, - {-X, -Y, Z }, + { x0, y0, z0, f, t }, + { x0, y0, z1, f, t }, + { x0, y0, z0 }, + { x0, y0, z1 }, }}; } std::unreachable(); } -Array<Quads::indexes> make_indexes_() +template<Group_ G, bool IsWest, typename F = float> +constexpr auto get_quadʹ(minmax_v<F, 3> bounds, F d) { - auto array = Array<Quads::indexes>{NoInit, chunk::max_wall_quad_count }; - for (auto i = 0uz; i < chunk::max_wall_quad_count; i++) - array[i] = Quads::quad_indexes(i); + F x[2] { bounds.min.x(), bounds.max.x() }, + y[2] { bounds.min.y(), bounds.max.y() }, + z[2] { bounds.min.z(), bounds.max.z() }, + dmx[2] { 0, d }, + dmy[2] { 0, d }; + + std::array<Vec3_<F>, 4> array = {}; + + unroll<static_array_size<decltype(array)>>([&]<typename Index>(Index) { + constexpr size_t i = Index::value; + constexpr auto table = make_quad_table_entry<IsWest>(G); + constexpr auto e = table[i]; + array.data()[i] = { x[e.x] - dmx[e.dmx], y[e.y] - dmy[e.dmy], z[e.z], }; + }); + return array; } -ArrayView<const Quads::indexes> make_indexes(size_t max) +template<Group_ G, bool IsWest, typename F = float> +constexpr CORRADE_ALWAYS_INLINE auto get_quad(F d) +{ + constexpr auto half_tile = Vec2_<F>(TILE_SIZE2*.5f); + constexpr auto X = half_tile.x(), Y = half_tile.y(), Z = F(TILE_SIZE.z()); + + return get_quadʹ<G, IsWest, F>({ { -X, -Y, 0, }, { X, Y, Z, }, }, d); +} + +template<bool IsWest> +CutResult<Int>::rect get_wall_rect(local_coords tile) { - static const auto indexes = make_indexes_(); - fm_assert(max <= chunk::max_wall_quad_count); - return indexes.prefix(max); + constexpr auto nʹ = wall_north<Int>(0, 0), wʹ = wall_west<Int>(0, 0); + constexpr auto t0 = !IsWest ? nʹ.first() : wʹ.first(), + t1 = !IsWest ? nʹ.second() : wʹ.second(); + const auto offset = Vector2i{tile} * iTILE_SIZE2; + const auto min = offset + t0, max = offset + t1; + return { min, max }; } -constexpr float depth_offset_for_group(Group_ G, bool is_west) +template<bool IsWest, std::invocable<Vector2, Vector2> F> +void cut_holes_in_wall(chunk& c, local_coords tile, Vector2i min, Vector2i max, F&& fun) { - CORRADE_ASSUME(G < Group_::COUNT); - float p = is_west ? tile_shader::wall_west_offset : 0; + CutResult<float>::rect hole; + + //constexpr auto eps = Vector2{.125f}; + if (c.find_hole_in_bbox(hole, Vector2(min) /*- eps*/, Vector2(max) /*+ eps*/)) + { + fun(min, max); + } + else + { + fm_assert(Vector2(Vector2i(hole.min)) == hole.min); + fm_assert(Vector2(Vector2i(hole.max)) == hole.max); + auto res = CutResult<Int>::cut(min, max, Vector2i(hole.min), Vector2i(hole.max)); + if (!res.found()) + { + fun(min, max); + } + else + { + for (auto i = 0u; i < res.size; i++) + { + const auto [min, max] = res.array[i]; + cut_holes_in_wall<IsWest>(c, tile, min, max, fun); + } + } + } +} + +struct quad_tuple +{ + Vector2ui tex_pos, tex_size; + Vector2i min, max; +}; + +template<bool IsWest> +quad_tuple get_wall_quad_stuff(const CutResult<Int>::rect& geom, const CutResult<Int>::rect& orig, + Vector2ui orig_tex_pos, Vector2ui orig_tex_size) +{ + return {}; +} + +ArrayView<const Quads::indexes> make_indexes(uint32_t count) +{ + static auto arrayʹ = [] { + auto array = Array<Quads::indexes>{}; + arrayReserve(array, 64); + return array; + }(); + auto& array = arrayʹ; + auto i = (uint32_t)array.size(); + if (count > i) [[unlikely]] + { + arrayResize(array, NoInit, count); + for (; i < count; i++) + array.data()[i] = Quads::quad_indexes(i); + } + return array.prefix(count); +} + +Array<std::array<chunk::vertex, 4>>& make_vertexes() +{ + static auto array = [] { + Array<std::array<chunk::vertex, 4>> array; + arrayReserve(array, 32); + return array; + }(); + return array; +} + +template<Group_ G, bool IsWest> +constexpr float depth_offset_for_group() +{ + static_assert(G < Group_::COUNT); + float p = IsWest ? tile_shader::wall_west_offset : 0; switch (G) { default: return tile_shader::wall_depth_offset + p; - case Wall::Group_::corner: - case Wall::Group_::side: + case Group_::corner: + case Group_::side: return tile_shader::wall_side_offset + p; } } -Wall::Frame variant_from_frame(ArrayView<const Wall::Frame> frames, global_coords coord, variant_t variant, bool is_west) +Frame variant_from_frame(ArrayView<const Frame> frames, global_coords coord, variant_t variant, bool is_west) { auto sz = (unsigned)frames.size(); if (variant == (variant_t)-1) @@ -148,168 +268,183 @@ Wall::Frame variant_from_frame(ArrayView<const Wall::Frame> frames, global_coord return frames[variant]; } -} // namespace +constexpr std::array<chunk::vertex, 4>& alloc_wall_vertexes(uint32_t& N, auto& V, auto& M, uint32_t k) +{ + constexpr uint32_t reserve = 15, mask = ~reserve; + const auto i = N, sz = ++N + reserve & mask; + fm_assert(uint32_t{(UnsignedShort)sz} == sz); + arrayResize(V, NoInit, sz); + arrayResize(M, NoInit, sz); + M[i] = (uint16_t)k; + return V[i]; +}; -GL::Mesh chunk::make_wall_mesh() +template<Group_ G, bool IsWest> +void do_wall_part(const Group& group, wall_atlas& A, chunk& c, chunk::wall_stuff& W, + Array<std::array<chunk::vertex, 4>>& vertexes, + global_coords coord, uint32_t& N, uint32_t tile) { - fm_debug_assert(_walls); - uint32_t N = 0; + if (!group.is_defined) + return; - static auto vertexes = Array<std::array<vertex, 4>>{NoInit, max_wall_quad_count }; + const uint32_t k = tile*2 + IsWest; + constexpr auto D = IsWest ? Direction_::W : Direction_::N; + const auto variant_2 = W.variants[k]; + const auto pos = local_coords{tile}; + const auto center = Vector3(pos) * TILE_SIZE; + const auto& dir = A.calc_direction(D); + const auto Depth = A.info().depth; - for (uint32_t k = 0; k < 2*TILE_COUNT; k++) + if constexpr(G == Group_::side) [[unlikely]] { - const bool is_west = k & 1; - const auto D = is_west ? Wall::Direction_::W : Wall::Direction_::N; - const auto& atlas = _walls->atlases[k]; - if (!atlas) - continue; - const auto variant_2 = _walls->variants[k]; - const auto pos = local_coords{k / 2u}; - const auto center = Vector3(pos) * TILE_SIZE; - const auto& dir = atlas->calc_direction(D); - const auto coord = global_coords{_coord, pos}; - const auto Depth = atlas->info().depth; - - for (auto [s, member, G] : Wall::Direction::groups_for_draw) - { - CORRADE_ASSUME(G < Group_::COUNT); - - bool side_ok = G == Wall::Group_::side; + bool corner_ok = false, pillar_ok = false; - if (!(dir.*member).is_defined) - continue; - - if (G == Wall::Group_::side) [[unlikely]] + if constexpr(!IsWest) + { + if (auto t = c.at_offset(pos, {-1, 0}); !(t && t->wall_north_atlas())) { - bool corner_ok = false, pillar_ok = false; - - if (!is_west) - { - if (auto t = at_offset_(pos, {-1, 0}); !(t && t->wall_north_atlas())) - { - if (_walls->atlases[k+1]) // west on same tile - pillar_ok = true; - if (auto t = at_offset_(pos, {0, -1}); t && t->wall_west_atlas()) - corner_ok = true; - } - if (side_ok) - if (auto t = at_offset_(pos, {1, -1}); t && t->wall_west_atlas()) - side_ok = false; - if (side_ok) - if (auto t = at_offset_(pos, {1, -1}); t && t->wall_west_atlas()) - side_ok = false; - } - else - { - if (auto t = at_offset_(pos, {0, -1}); !(t && t->wall_west_atlas())) - if (auto t = at_offset_(pos, {-1, 0}); t && t->wall_north_atlas()) - corner_ok = true; - if (side_ok) - if (auto t = at_offset_(pos, {-1, 1}); t && t->wall_north_atlas()) - side_ok = false; - } - - if (pillar_ok) [[unlikely]] - { - if (dir.top.is_defined) - { - const auto frames = atlas->frames(dir.top); - const auto frame = variant_from_frame(frames, coord, variant_2, is_west); - constexpr Vector2 half_tile = TILE_SIZE2*.5f; - constexpr float X = half_tile.x(), Y = half_tile.y(), Z = TILE_SIZE.z(); - Quads::quad quad = {{ - { -X - Depth, -Y - Depth, Z }, - { -X, -Y - Depth, Z }, - { -X - Depth, -Y, Z }, - { -X, -Y, Z } - }}; - fm_assert(frame.size.x() == Depth); - fm_assert(frame.size.y() >= Depth); - auto start = frame.offset + Vector2ui{0, frame.size.y()} - Vector2ui{0, Depth}; - const auto texcoords = Quads::texcoords_at(start, Vector2ui{Depth, Depth}, atlas->image_size()); - const auto i = N++; - fm_assert(i < vertexes.size()); - _walls->mesh_indexes[i] = (uint16_t)k; - const auto depth_offset = depth_offset_for_group(Group_::top, is_west); - const auto depth = tile_shader::depth_value(pos, depth_offset); - auto& v = vertexes[i]; - for (auto& v : quad) - v += center; - for (uint8_t j = 0; j < 4; j++) - v[j] = { quad[j], texcoords[j], depth }; - } - } - if (corner_ok) [[unlikely]] - { - if (dir.corner.is_defined) - { - const auto frames = atlas->frames(dir.corner); - const auto depth_offset = depth_offset_for_group(Group_::corner, is_west); - const auto pos_x = !is_west ? (float)pos.x : (float)pos.x - 1; - const auto depth = tile_shader::depth_value(pos_x, pos.y, depth_offset); - const auto& frame = variant_from_frame(frames, coord, variant_2, is_west); - const auto texcoords = Quads::texcoords_at(frame.offset, frame.size, atlas->image_size()); - const auto i = N++; - fm_assert(i < vertexes.size()); - _walls->mesh_indexes[i] = (uint16_t)k; - auto& v = vertexes[i]; - auto quad = get_quad(D, Group_::corner, (float)Depth); - for (auto& v : quad) - v += center; - for (uint8_t j = 0; j < 4; j++) - v[j] = { quad[j], texcoords[j], depth }; - } - else if (dir.wall.is_defined) [[likely]] - { - const auto frames = atlas->frames(dir.wall); - const auto depth_offset = depth_offset_for_group(Group_::corner, is_west); - const auto depth = tile_shader::depth_value(!is_west ? (float)pos.x : (float)pos.x - 1, depth_offset); - const auto frame = variant_from_frame(frames, coord, variant_2, is_west); - fm_assert(frame.size.x() > Depth); - auto start = frame.offset + Vector2ui{frame.size.x(), 0} - Vector2ui{Depth, 0}; - const auto texcoords = Quads::texcoords_at(start, {Depth, frame.size.y()}, atlas->image_size()); - const auto i = N++; - fm_assert(i < vertexes.size()); - _walls->mesh_indexes[i] = (uint16_t)k; - auto& v = vertexes[i]; - auto quad = get_quad(D, Group_::corner, (float)Depth); - for (auto& v : quad) - v += center; - for (uint8_t j = 0; j < 4; j++) - v[j] = { quad[j], texcoords[j], depth }; - } - } + if (W.atlases[k + 1]) // west on same tile + pillar_ok = true; + if (auto t = c.at_offset(pos, {0, -1}); t && t->wall_west_atlas()) + corner_ok = true; } + } + else + { + if (auto t = c.at_offset(pos, {0, -1}); !(t && t->wall_west_atlas())) + if (auto t = c.at_offset(pos, {-1, 0}); t && t->wall_north_atlas()) + corner_ok = true; + } - if (G != Wall::Group_::side || side_ok) [[likely]] + if (pillar_ok) [[unlikely]] + { + if (dir.top.is_defined) { - const auto& group = dir.*member; - const auto frames = atlas->frames(group); - - const auto i = N++; - fm_assert(i < vertexes.size()); - _walls->mesh_indexes[i] = (uint16_t)k; - const auto frame = variant_from_frame(frames, coord, variant_2, is_west); - const auto texcoords = Quads::texcoords_at(frame.offset, frame.size, atlas->image_size()); - const auto depth_offset = depth_offset_for_group(G, is_west); + const auto frames = A.frames(dir.top); + const auto frame = variant_from_frame(frames, coord, variant_2, IsWest); + constexpr Vector2 half_tile = TILE_SIZE2 * .5f; + constexpr float X = half_tile.x(), Y = half_tile.y(), Z = TILE_SIZE.z(); + const auto Depthʹ = (float)(int)Depth; + Quads::quad quad = {{ + {-X - Depthʹ, -Y - Depthʹ, Z}, + {-X, -Y - Depthʹ, Z}, + {-X - Depthʹ, -Y, Z}, + {-X, -Y, Z}, + }}; + fm_assert(frame.size.x() == Depth); + fm_assert(frame.size.y() >= Depth); + auto start = frame.offset + Vector2ui{0, frame.size.y()} - Vector2ui{0, Depth}; + const auto texcoords = Quads::texcoords_at(start, Vector2ui{Depth, Depth}, A.image_size()); + const auto depth_offset = depth_offset_for_group<Group_::top, IsWest>(); const auto depth = tile_shader::depth_value(pos, depth_offset); - auto quad = get_quad(D, G, (float)Depth); for (auto& v : quad) v += center; - auto& v = vertexes[i]; + auto& v = alloc_wall_vertexes(N, vertexes, W.mesh_indexes, k); for (uint8_t j = 0; j < 4; j++) - v[j] = { quad[j], texcoords[j], depth }; + v[j] = {quad[j], texcoords[j], depth}; } } + if (corner_ok) [[unlikely]] + { + if (dir.corner.is_defined) + { + const auto frames = A.frames(dir.corner); + const auto depth_offset = depth_offset_for_group<Group_::corner, IsWest>(); + const auto pos_x = !IsWest ? (float)pos.x : (float)pos.x - 1; + const auto depth = tile_shader::depth_value(pos_x, pos.y, depth_offset); + const auto& frame = variant_from_frame(frames, coord, variant_2, IsWest); + const auto texcoords = Quads::texcoords_at(frame.offset, frame.size, A.image_size()); + auto quad = get_quad<Group_::corner, IsWest>((float)Depth); + for (auto& v : quad) + v += center; + auto& v = alloc_wall_vertexes(N, vertexes, W.mesh_indexes, k); + for (uint8_t j = 0; j < 4; j++) + v[j] = {quad[j], texcoords[j], depth}; + } + else if (dir.wall.is_defined) [[likely]] + { + const auto frames = A.frames(dir.wall); + const auto depth_offset = depth_offset_for_group<Group_::corner, IsWest>(); + const auto depth = tile_shader::depth_value(!IsWest ? (float)pos.x : (float)pos.x - 1, (float)pos.y, depth_offset); + const auto frame = variant_from_frame(frames, coord, variant_2, IsWest); + fm_assert(frame.size.x() > Depth); + auto start = frame.offset + Vector2ui{frame.size.x(), 0} - Vector2ui{Depth, 0}; + const auto texcoords = Quads::texcoords_at(start, {Depth, frame.size.y()}, A.image_size()); + auto quad = get_quad<Group_::corner, IsWest>((float)Depth); + for (auto& v : quad) + v += center; + auto& v = alloc_wall_vertexes(N, vertexes, W.mesh_indexes, k); + for (uint8_t j = 0; j < 4; j++) + v[j] = {quad[j], texcoords[j], depth}; + } + } + } + + { + const auto frames = A.frames(group); + const auto frame = variant_from_frame(frames, coord, variant_2, IsWest); + const auto texcoords = Quads::texcoords_at(frame.offset, frame.size, A.image_size()); + const auto depth_offset = depth_offset_for_group<G, IsWest>(); + const auto depth = tile_shader::depth_value(pos, depth_offset); + auto quad = get_quad<G, IsWest>((float)Depth); + for (auto& v : quad) + v += center; + auto& v = alloc_wall_vertexes(N, vertexes, W.mesh_indexes, k); + for (uint8_t j = 0; j < 4; j++) + v[j] = {quad[j], texcoords[j], depth}; + } +} + +} // namespace + +GL::Mesh chunk::make_wall_mesh() +{ + fm_debug_assert(_walls); + + uint32_t N = 0; +#ifdef __CLION_IDE__ + extern const uint32_t _foo; N = _foo; +#endif + + auto& vertexes = make_vertexes(); + auto& W = *_walls; + + arrayResize(vertexes, 0); + + for (uint32_t k = 0; k < TILE_COUNT; k++) + { + const auto coord = global_coords{_coord, local_coords{k}}; + + static_assert(Wall::Group_COUNT == /* 5 */ 4); + static_assert((int)Direction_::COUNT == 2); + + if (auto* A_nʹ = W.atlases[k*2 + 0].get()) + { + auto& A_n = *A_nʹ; + const auto& dir = A_n.calc_direction(Direction_::N); + do_wall_part<Group_::wall, false>(dir.wall, A_n, *this, W, vertexes, coord, N, k); + do_wall_part<Group_::side, false>(dir.side, A_n, *this, W, vertexes, coord, N, k); + do_wall_part<Group_::top, false>(dir.top, A_n, *this, W, vertexes, coord, N, k); + } + if (auto* A_wʹ = W.atlases[k*2 + 1].get()) + { + auto& A_w = *A_wʹ; + const auto& dir = A_w.calc_direction(Direction_::W); + do_wall_part<Group_::wall, true>(dir.wall, A_w, *this, W, vertexes, coord, N, k); + do_wall_part<Group_::side, true>(dir.side, A_w, *this, W, vertexes, coord, N, k); + do_wall_part<Group_::top, true>(dir.top, A_w, *this, W, vertexes, coord, N, k); + } } + if (N == 0) + return GL::Mesh{NoCreate}; + ranges::sort(ranges::zip_view(vertexes.prefix(N), - ArrayView<uint_fast16_t>{_walls->mesh_indexes.data(), N}), + ArrayView{_walls->mesh_indexes.data(), N}), [&A = _walls->atlases](const auto& a, const auto& b) { const auto& [av, ai] = a; const auto& [bv, bi] = b; - return A[ai] < A[bi]; + return A[ai].get() < A[bi].get(); }); auto vertex_view = std::as_const(vertexes).prefix(N); diff --git a/src/chunk.cpp b/src/chunk.cpp index ac529090..a06d55c3 100644 --- a/src/chunk.cpp +++ b/src/chunk.cpp @@ -41,17 +41,7 @@ tile_proto chunk::operator[](local_coords xy) const noexcept { return operator[] chunk_coords_ chunk::coord() const noexcept { return _coord; } -tile_ref chunk::at_offset(local_coords pos, Vector2i off) -{ - const auto coord = global_coords{_coord, pos}; - const auto coord2 = coord + off; - if (coord.chunk() == coord2.chunk()) [[likely]] - return operator[](coord2.local()); - else - return (*_world)[coord2].t; -} - -Optional<tile_ref> chunk::at_offset_(local_coords pos, Vector2i off) +Optional<tile_ref> chunk::at_offset(local_coords pos, Vector2i off) { const auto coord = global_coords{_coord, pos}; const auto coord2 = coord + off; @@ -66,8 +56,7 @@ Optional<tile_ref> chunk::at_offset_(local_coords pos, Vector2i off) } } -tile_ref chunk::at_offset(tile_ref r, Vector2i off) { return at_offset(local_coords{r.index()}, off); } -Optional<tile_ref> chunk::at_offset_(tile_ref r, Vector2i off) { return at_offset_(local_coords{r.index()}, off); } +Optional<tile_ref> chunk::at_offset(tile_ref r, Vector2i off) { return at_offset(local_coords{r.index()}, off); } void chunk::mark_ground_modified() noexcept { @@ -139,7 +128,6 @@ void chunk::sort_objects() void chunk::add_object_pre(const bptr<object>& e) { - fm_assert(!e->gone); fm_assert(&*e->c == this); const auto dyn = e->is_dynamic(), upd = e->updates_passability(); if (!dyn) @@ -191,7 +179,6 @@ void chunk::remove_object(size_t i) { auto& e = *eʹ; fm_assert(e.c == this); - fm_assert(!e.gone); const auto dyn = e.is_dynamic(), upd = e.updates_passability(); if (!dyn) @@ -207,7 +194,6 @@ void chunk::remove_object(size_t i) } arrayRemove(_objects, i); - //eʹ.destroy(); } ArrayView<const bptr<object>> chunk::objects() const diff --git a/src/chunk.hpp b/src/chunk.hpp index cf41a970..f49a9653 100644 --- a/src/chunk.hpp +++ b/src/chunk.hpp @@ -4,9 +4,8 @@ #include "local-coords.hpp" #include "src/RTree-fwd.h" #include "global-coords.hpp" -#include "wall-defs.hpp" #include "search-pred.hpp" -#include <type_traits> +#include "hole-cut.hpp" #include <array> #include <Corrade/Containers/Array.h> #include <Corrade/Containers/Pointer.h> @@ -34,10 +33,8 @@ public: tile_proto operator[](local_coords xy) const noexcept; chunk_coords_ coord() const noexcept; - tile_ref at_offset(local_coords pos, Vector2i off); - tile_ref at_offset(tile_ref r, Vector2i off); - Optional<tile_ref> at_offset_(local_coords pos, Vector2i off); - Optional<tile_ref> at_offset_(tile_ref r, Vector2i off); + Optional<tile_ref> at_offset(local_coords pos, Vector2i off); + Optional<tile_ref> at_offset(tile_ref r, Vector2i off); using iterator = tile_iterator; using const_iterator = tile_const_iterator; @@ -99,6 +96,8 @@ public: class world& world() noexcept; [[nodiscard]] bool can_place_object(const object_proto& proto, local_coords pos); + [[nodiscard]] bool find_hole_in_bbox(CutResult<float>::rect& hole, Vector2 min, Vector2 max); + [[nodiscard]] static bool find_hole_in_bbox(CutResult<float>::rect& hole, const Chunk_RTree& rtree, Vector2 min, Vector2 max); void on_teardown(); bool is_teardown() const; @@ -107,14 +106,9 @@ public: void remove_object(size_t i); void sort_objects(); - // for drawing only - static constexpr size_t max_wall_quad_count = - TILE_COUNT*Wall::Direction_COUNT*(Wall::Group_COUNT+4); - pass_region make_pass_region(bool debug = false, ArrayView<const Vector2i> positions = {}); pass_region make_pass_region(const Search::pred& f, bool debug = false, ArrayView<const Vector2i> positions = {}); -private: struct ground_stuff { std::array<bptr<ground_atlas>, TILE_COUNT> atlases; @@ -126,9 +120,10 @@ private: { std::array<bptr<wall_atlas>, 2*TILE_COUNT> atlases; std::array<variant_t, 2*TILE_COUNT> variants; - std::array<uint_fast16_t, max_wall_quad_count> mesh_indexes; + Array<uint_fast16_t> mesh_indexes; }; +private: Pointer<ground_stuff> _ground; Pointer<wall_stuff> _walls; Array<bptr<object>> _objects; diff --git a/src/collision.hpp b/src/collision.hpp index 914d6e1a..eef51d88 100644 --- a/src/collision.hpp +++ b/src/collision.hpp @@ -9,9 +9,9 @@ enum class collision_type : unsigned char { constexpr inline size_t collision_data_BITS = 60; struct collision_data final { - uint64_t tag : 2; - uint64_t pass : 2; - uint64_t data : collision_data_BITS; + uint64_t type : 2; + uint64_t pass : 2; + uint64_t id : collision_data_BITS; bool operator==(const collision_data&) const noexcept; }; diff --git a/src/critter-script-walk.cpp b/src/critter-script-walk.cpp index 2402fe74..c0e800e8 100644 --- a/src/critter-script-walk.cpp +++ b/src/critter-script-walk.cpp @@ -7,6 +7,7 @@ #include "search-result.hpp" #include "search-astar.hpp" #include "entity/name-of.hpp" +#include <utility> namespace floormat { diff --git a/src/critter.cpp b/src/critter.cpp index 32d1048b..e99eb3a4 100644 --- a/src/critter.cpp +++ b/src/critter.cpp @@ -55,15 +55,15 @@ constexpr rotation arrows_to_dir_from_mask(unsigned mask) fm_assert(false); } -constexpr auto arrows_to_dir_array = map(arrows_to_dir_from_mask, iota_array<uint8_t, 16>); - constexpr auto arrows_to_dir(bool left, bool right, bool up, bool down) { + constexpr auto table = map(arrows_to_dir_from_mask, iota_array<uint8_t, 16>); constexpr uint8_t L = 1 << 3, R = 1 << 2, U = 1 << 1, D = 1 << 0; - const uint8_t bits = left*L | right*R | up*U | down*D; constexpr uint8_t mask = L|R|U|D; + + const uint8_t bits = left*L | right*R | up*U | down*D; CORRADE_ASSUME((bits & mask) == bits); - return arrows_to_dir_array.data()[bits]; + return table.data()[bits]; } #if 0 @@ -118,26 +118,31 @@ constexpr auto rotation_to_similar_array = map(rotation_to_similar_, iota_array< constexpr std::array<rotation, 3> rotation_to_similar(rotation r) { - CORRADE_ASSUME(r < rotation_COUNT); return rotation_to_similar_array.data()[(uint8_t)r]; } -template<rotation r> constexpr uint8_t get_length_axis() +constexpr uint8_t get_length_axisʹ(rotation r) { - static_assert((int)r % 2 == 0); using enum rotation; - if constexpr(r == N || r == S) + if (r == N || r == S) return 1; - else if constexpr(r == W || r == E) + else if (r == W || r == E) return 0; - fm_assert(false); + else + return 0; // garbage in, garbage out +} + +constexpr uint8_t get_length_axis(rotation r) +{ + constexpr auto table = map(get_length_axisʹ, iota_array<rotation, (size_t)rotation_COUNT>); + return table.data()[(size_t)r]; } -template<rotation new_r, bool MultiStep> -CORRADE_ALWAYS_INLINE -bool update_movement_body(size_t& i, critter& C, const anim_def& info, uint8_t nsteps) +template<bool MultiStep> +CORRADE_NEVER_INLINE +bool update_movement_body(size_t& i, critter& C, const anim_def& info, uint8_t nsteps, rotation new_r, rotation visible_r) { - constexpr auto vec = rotation_to_vec(new_r); + const auto vec = rotation_to_vec(new_r); using Frac = decltype(critter::offset_frac); constexpr auto frac = (float{limits<Frac>::max}+1)/2; constexpr auto inv_frac = 1 / frac; @@ -156,7 +161,7 @@ bool update_movement_body(size_t& i, critter& C, const anim_def& info, uint8_t n C.offset_frac = Frac(rem * frac); if (C.can_move_to(off_i)) { - C.move_to(i, off_i, new_r); + C.move_to(i, off_i, visible_r); if constexpr(MultiStep) (C.frame += nsteps) %= info.nframes; else @@ -173,64 +178,60 @@ bool update_movement_body(size_t& i, critter& C, const anim_def& info, uint8_t n return false; } -template<rotation r> -CORRADE_ALWAYS_INLINE -bool update_movement_3way(size_t& i, critter& C, const anim_def& info) +bool update_movement_3way(size_t& i, critter& C, const anim_def& info, rotation new_r) { - constexpr auto rotations = rotation_to_similar(r); - if (update_movement_body<rotations[0], false>(i, C, info, 0)) + const auto rotations = rotation_to_similar(new_r); + if (update_movement_body<false>(i, C, info, 0, rotations.data()[0], new_r)) return true; - if (update_movement_body<rotations[1], false>(i, C, info, 0)) + if (update_movement_body<false>(i, C, info, 0, rotations.data()[1], new_r)) return true; - if (update_movement_body<rotations[2], false>(i, C, info, 0)) + if (update_movement_body<false>(i, C, info, 0, rotations.data()[2], new_r)) return true; return false; } constexpr bool DoUnroll = true; -template<rotation new_r> -requires ((int)new_r % 2 != 0) -CORRADE_ALWAYS_INLINE -bool update_movement_1(critter& C, size_t& i, const anim_def& info, uint32_t nframes) +template<bool IsEven> +requires (!IsEven) +bool update_movement_1(critter& C, size_t& i, const anim_def& info, uint32_t nframes, rotation new_r) { + //Debug{} << "< nframes" << nframes; if constexpr(DoUnroll) { - //Debug{} << "< nframes" << nframes; while (nframes > 1) { auto len = (uint8_t)Math::min(nframes, (uint32_t)C.bbox_size.min()); if (len <= 1) break; - if (!update_movement_body<new_r, true>(i, C, info, len)) + if (!update_movement_body<true>(i, C, info, len, new_r, new_r)) break; //Debug{} << " " << len; nframes -= len; } - //Debug{} << ">" << nframes; } + //Debug{} << ">" << nframes; for (auto k = 0u; k < nframes; k++) - if (!update_movement_3way<new_r>(i, C, info)) + if (!update_movement_3way(i, C, info, new_r)) return false; return true; } -template<rotation new_r> -requires (((int)new_r & 1) % 2 == 0) -CORRADE_NEVER_INLINE -bool update_movement_1(critter& C, size_t& i, const anim_def& info, uint32_t nframes) +template<bool IsEven> +requires IsEven +bool update_movement_1(critter& C, size_t& i, const anim_def& info, uint32_t nframes, rotation new_r) { if constexpr(DoUnroll) { //Debug{} << "< nframes" << nframes; while (nframes > 1) { - constexpr auto len_axis = get_length_axis<new_r>(); + const auto len_axis = get_length_axis(new_r); auto len = (uint8_t)Math::min(nframes, (uint32_t)C.bbox_size.data()[len_axis]); if (len <= 1) [[unlikely]] break; - if (!update_movement_body<new_r, true>(i, C, info, len)) + if (!update_movement_body<true>(i, C, info, len, new_r, new_r)) break; //Debug{} << " " << len; nframes -= len; @@ -239,20 +240,11 @@ bool update_movement_1(critter& C, size_t& i, const anim_def& info, uint32_t nfr } for (auto k = 0u; k < nframes; k++) - if (!update_movement_body<new_r, false>(i, C, info, 0)) + if (!update_movement_body<false>(i, C, info, 0, new_r, new_r)) return false; return true; } -template bool update_movement_1<(rotation)0>(critter& C, size_t& i, const anim_def& info, uint32_t nframes); -template bool update_movement_1<(rotation)1>(critter& C, size_t& i, const anim_def& info, uint32_t nframes); -template bool update_movement_1<(rotation)2>(critter& C, size_t& i, const anim_def& info, uint32_t nframes); -template bool update_movement_1<(rotation)3>(critter& C, size_t& i, const anim_def& info, uint32_t nframes); -template bool update_movement_1<(rotation)4>(critter& C, size_t& i, const anim_def& info, uint32_t nframes); -template bool update_movement_1<(rotation)5>(critter& C, size_t& i, const anim_def& info, uint32_t nframes); -template bool update_movement_1<(rotation)6>(critter& C, size_t& i, const anim_def& info, uint32_t nframes); -template bool update_movement_1<(rotation)7>(critter& C, size_t& i, const anim_def& info, uint32_t nframes); - struct step_s { uint32_t count; @@ -309,10 +301,10 @@ constexpr rotation dir_from_step_mask(uint8_t val) } } -constexpr auto dir_from_step_array = map(dir_from_step_mask, iota_array<uint8_t, 1 << 4>); - constexpr rotation dir_from_step(step_s step) { + constexpr auto table = map(dir_from_step_mask, iota_array<uint8_t, 1 << 4>); + if (step.direction.isZero()) [[unlikely]] return rotation_COUNT; @@ -320,7 +312,7 @@ constexpr rotation dir_from_step(step_s step) auto y = uint8_t(step.direction.y() + 1); //fm_debug_assert((x & 3) == x && (y & 3) == y); auto val = uint8_t(x << 2 | y); - return dir_from_step_array.data()[val]; + return table.data()[val]; } constexpr step_s next_step(point from, point to) @@ -441,15 +433,12 @@ void critter::update_movement(size_t& i, const Ns& dt, rotation new_r) switch (new_r) { + using enum rotation; default: std::unreachable(); - case (rotation)0: ret = update_movement_1<(rotation)0>(*this, i, info, nframes); break; - case (rotation)1: ret = update_movement_1<(rotation)1>(*this, i, info, nframes); break; - case (rotation)2: ret = update_movement_1<(rotation)2>(*this, i, info, nframes); break; - case (rotation)3: ret = update_movement_1<(rotation)3>(*this, i, info, nframes); break; - case (rotation)4: ret = update_movement_1<(rotation)4>(*this, i, info, nframes); break; - case (rotation)5: ret = update_movement_1<(rotation)5>(*this, i, info, nframes); break; - case (rotation)6: ret = update_movement_1<(rotation)6>(*this, i, info, nframes); break; - case (rotation)7: ret = update_movement_1<(rotation)7>(*this, i, info, nframes); break; + case N: case E: case S: case W: + ret = update_movement_1<true >(*this, i, info, nframes, new_r); break; + case NW: case NE: case SE: case SW: + ret = update_movement_1<false>(*this, i, info, nframes, new_r); break; } if (!ret) [[unlikely]] diff --git a/src/hole-cut.cpp b/src/hole-cut.cpp index 1ecf96ce..a7736762 100644 --- a/src/hole-cut.cpp +++ b/src/hole-cut.cpp @@ -2,6 +2,7 @@ #include "compat/array-size.hpp" #include "compat/iota.hpp" #include "compat/map.hpp" +#include "hole-cut.hpp" //#include <mg/Functions.h> #ifdef __GNUG__ @@ -32,7 +33,7 @@ struct coords struct element { - uint8_t size; + uint8_t s, size; std::array<coords, 8> array; }; @@ -45,9 +46,9 @@ constexpr element make_element(uint8_t s) switch (s) { using enum location; - case x0|x1|y0|y1: return element{0, {{ // 9.1 + case x0|x1|y0|y1: return element{s, 0, {{ // 9.1 }}}; - case __|__|__|__: return element{8, {{ // 14.1 + case __|__|__|__: return element{s, 8, {{ // 14.1 {R0, H0, R0, H0}, {H0, H1, R0, H0}, {H1, R1, R0, H0}, @@ -58,62 +59,62 @@ constexpr element make_element(uint8_t s) {H1, R1, H1, R1}, }}}; - case x0|x1|__|__: return element{2, {{ // 13.1 + case x0|x1|__|__: return element{s, 2, {{ // 13.1 {R0, R1, R0, H0}, {R0, R1, H1, R1}, }}}; - case __|__|y0|y1: return element{2, {{ // 13.2 + case __|__|y0|y1: return element{s, 2, {{ // 13.2 {R0, H0, R0, R1}, {H1, R1, R0, R1}, }}}; - case x0|x1|y0|__: return element{1, {{ // 12.1 + case x0|x1|y0|__: return element{s, 1, {{ // 12.1 {R0, R1, H1, R1}, }}}; - case x0|x1|__|y1: return element{1, {{ // 12.2 + case x0|x1|__|y1: return element{s, 1, {{ // 12.2 {R0, R1, R0, H0}, }}}; - case x0|__|y0|y1: return element{1, {{ // 12.3 + case x0|__|y0|y1: return element{s, 1, {{ // 12.3 {H1, R1, R0, R1}, }}}; - case __|x1|y0|y1: return element{1, {{ // 12.4 + case __|x1|y0|y1: return element{s, 1, {{ // 12.4 {R0, H0, R0, R1}, }}}; - case x0|__|__|__: return element{3, {{ // 10.1 + case x0|__|__|__: return element{s, 3, {{ // 10.1 {R0, R1, R0, H0}, {H1, R1, H0, H1}, {R0, R1, H1, R1}, }}}; - case __|x1|__|__: return element{3, {{ // 10.2 + case __|x1|__|__: return element{s, 3, {{ // 10.2 {R0, R1, R0, H0}, {R0, H0, H0, H1}, {R0, R1, H1, R1}, }}}; - case __|__|y0|__: return element{3, {{ // 10.3 + case __|__|y0|__: return element{s, 3, {{ // 10.3 {R0, H0, R0, R1}, {H0, H1, H1, R1}, {H1, R1, R0, R1}, }}}; - case __|__|__|y1: return element{3, {{ // 10.4 + case __|__|__|y1: return element{s, 3, {{ // 10.4 {R0, H0, R0, R1}, {H0, H1, R0, H0}, {H1, R1, R0, R1}, }}}; - case x0|__|y0|__: return element{2, {{ // 11.1 + case x0|__|y0|__: return element{s, 2, {{ // 11.1 {H1, R1, R0, H1}, {R0, R1, H1, R1}, }}}; - case __|x1|y0|__: return element{2, {{ // 11.2 + case __|x1|y0|__: return element{s, 2, {{ // 11.2 {R0, H0, R0, H1}, {R0, R1, H1, R1}, }}}; - case x0|__|__|y1: return element{2, {{ // 11.3 + case x0|__|__|y1: return element{s, 2, {{ // 11.3 {R0, R1, R0, H0}, {H1, R1, H0, R1}, }}}; - case __|x1|__|y1: return element{2, {{ // 11.4 + case __|x1|__|y1: return element{s, 2, {{ // 11.4 {R0, R1, R0, H0}, {R0, H0, H0, R1}, }}}; @@ -123,8 +124,6 @@ constexpr element make_element(uint8_t s) fm_assert(false); } -constexpr auto elements = map(make_element, iota_array<uint8_t, 16>); - template<typename T> constexpr auto get_value_from_coord(Vec2ʹ<T> r0, Vec2ʹ<T> r1, Vec2ʹ<T> h0, Vec2ʹ<T> h1, coords c) { @@ -141,13 +140,32 @@ template<typename T> [[nodiscard]] constexpr bool check_empty(Vec2ʹ<T> r0, Vec2ʹ<T> r1, Vec2ʹ<T> h0, Vec2ʹ<T> h1) { - bool iempty = r0.x() == r1.x() | r0.y() == r1.y(); + //bool iempty = r0.x() == r1.x() | r0.y() == r1.y(); bool hempty = h0.x() == h1.x() | h0.y() == h1.y(); 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(); - return iempty | hempty | empty_before_x | empty_after_x | empty_before_y | empty_after_y; + return /*iempty |*/ hempty | empty_before_x | empty_after_x | empty_before_y | empty_after_y; +} + +template<typename T> +constexpr Cr<T> cut_rectangleʹ(Vec2ʹ<T> r0, Vec2ʹ<T> r1, Vec2ʹ<T> h0, Vec2ʹ<T> h1, uint8_t val) +{ + constexpr auto table = map(make_element, iota_array<uint8_t, 16>); + + CORRADE_ASSUME(val < 16); + const auto elt = table[val]; + const auto sz = elt.size; + Cr<T> res = { + .s = val, + .size = sz, + .array = {}, + }; + + for (auto i = 0u; i < 8; i++) + res.array[i] = get_value_from_coord<T>(r0, r1, h0, h1, elt.array[i]); + return res; } template<typename T> @@ -155,9 +173,9 @@ constexpr Cr<T> cut_rectangle(Vec2ʹ<T> r0, Vec2ʹ<T> r1, Vec2ʹ<T> h0, Vec2ʹ<T { if (check_empty<T>(r0, r1, h0, h1)) return { - .array = {{ { r0, r1 }, }}, + .s = (uint8_t)-1, .size = 1, - .found = false, + .array = {{ { r0, r1 }, }}, }; const bool sx = h0.x() <= r0.x(); @@ -165,18 +183,9 @@ constexpr Cr<T> cut_rectangle(Vec2ʹ<T> r0, Vec2ʹ<T> r1, Vec2ʹ<T> h0, Vec2ʹ<T 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); + const auto val = uint8_t(sx << 0 | ex << 1 | sy << 2 | ey << 3); CORRADE_ASSUME(val < 16); - const auto elt = elements[val]; - const auto sz = elt.size; - Cr<T> res = { - .array = {}, - .size = sz, - .found = true, - }; - - for (auto i = 0u; i < 8; i++) - res.array[i] = get_value_from_coord<T>(r0, r1, h0, h1, elt.array[i]); + const auto res = cut_rectangleʹ<T>(r0, r1, h0, h1, val); return res; } @@ -199,10 +208,18 @@ constexpr Cr<T> cut_rectangle(bbox<T> input, bbox<T> hole) } // namespace -template<typename T> Cr<T> CutResult<T>::cut(bbox input, bbox hole) { return cut_rectangle<T>(input, hole); } +template<typename T> Cr<T> CutResult<T>::cutʹ(Vec2 r0, Vec2 r1, Vec2 h0, Vec2 h1, uint8_t s) +{ + return cut_rectangleʹ<T>(r0, r1, h0, h1, s); +} + +template<typename T> Cr<T> CutResult<T>::cut(bbox input, bbox hole) requires std::is_signed_v<T> { return cut_rectangle<T>(input, hole); } template<typename T> Cr<T> CutResult<T>::cut(Vec2 r0, Vec2 r1, Vec2 h0, Vec2 h1) { return cut_rectangle<T>(r0, r1, h0, h1); } -template struct CutResult<Int>; +template<typename T> bool CutResult<T>::found() const { return s != (uint8_t)-1; } + +template struct CutResult<uint32_t>; +template struct CutResult<int32_t>; template struct CutResult<float>; } // namespace floormat diff --git a/src/hole-cut.hpp b/src/hole-cut.hpp new file mode 100644 index 00000000..4ec5c168 --- /dev/null +++ b/src/hole-cut.hpp @@ -0,0 +1,25 @@ +#pragma once +#include <array> +#include <mg/Vector2.h> +#include <Magnum/DimensionTraits.h> + +namespace floormat { + +template<typename T> +struct CutResult +{ + using Vec2 = VectorTypeFor<2, T>; + struct bbox { Vec2 position; Vector2ub bbox_size; }; + struct rect { Vec2 min, max; }; + + static CutResult cut(bbox input, bbox hole) requires std::is_signed_v<T>; + static CutResult cut(Vec2 r0, Vec2 r1, Vec2 h0, Vec2 h1); + static CutResult cutʹ(Vec2 r0, Vec2 r1, Vec2 h0, Vec2 h1, uint8_t s); + + uint8_t s = (uint8_t)-1, size = 0; + std::array<rect, 8> array; + + bool found() const; +}; + +} // namespace floormat diff --git a/src/hole.hpp b/src/hole.hpp index 35fd29d9..f70fac15 100644 --- a/src/hole.hpp +++ b/src/hole.hpp @@ -22,7 +22,6 @@ struct hole_proto final : object_proto bool on_render : 1 = true; bool on_physics : 1 = true; bool enabled : 1 = true; - bool is_wall : 1 = false; }; uint8_t height = 0, z_offset = tile_size_z/2; @@ -57,19 +56,4 @@ private: void maybe_mark_neighbor_chunks_modified() override; }; -template<typename T> -struct CutResult -{ - using Vec2 = VectorTypeFor<2, T>; - struct bbox { Vec2 position; Vector2ub bbox_size; }; - struct rect { Vec2 min, max; }; - - static CutResult cut(bbox input, bbox hole); - static CutResult cut(Vec2 r0, Vec2 r1, Vec2 h0, Vec2 h1); - - std::array<rect, 8> array; - uint8_t size = 0; - bool found = false; -}; - } // namespace floormat diff --git a/src/object.cpp b/src/object.cpp index 449a0fcb..1679f5b7 100644 --- a/src/object.cpp +++ b/src/object.cpp @@ -173,7 +173,7 @@ static bool do_search(class chunk* c, chunk_coords_ coord, bool ret = true; c->rtree()->Search(min.data(), max.data(), [&](object_id data, const auto& r) { auto x = std::bit_cast<collision_data>(data); - if (x.data != id && x.pass != (uint64_t)pass_mode::pass && + if (x.id != id && x.pass != (uint64_t)pass_mode::pass && rect_intersects(min, max, {r.m_min[0], r.m_min[1]}, {r.m_max[0], r.m_max[1]})) return ret = false; else diff --git a/src/object.hpp b/src/object.hpp index a73f97b1..e3cbb628 100644 --- a/src/object.hpp +++ b/src/object.hpp @@ -57,7 +57,6 @@ struct object : bptr_base const rotation r = rotation::N; // todo remove bitfield? const pass_mode pass = pass_mode::see_through; bool ephemeral : 1 = false; - bool gone : 1 = false; //char _pad[4]; // got 4 bytes left virtual ~object() noexcept override; diff --git a/src/point.hpp b/src/point.hpp index 8d40992b..f0e39aed 100644 --- a/src/point.hpp +++ b/src/point.hpp @@ -30,7 +30,7 @@ struct point constexpr chunk_coords_ chunk3() const; constexpr local_coords local() const; constexpr Vector2b offset() const; - template<size_t N> std::tuple_element_t<N, point> constexpr get() const; + template<size_t N> typename std::tuple_element<N, point>::type constexpr get() const; friend Debug& operator<<(Debug& dbg, const point& pt); @@ -59,7 +59,7 @@ constexpr chunk_coords point::chunk() const { return {cx, cy}; } constexpr local_coords point::local() const { return tile; } constexpr Vector2b point::offset() const { return _offset; } -template<size_t N> std::tuple_element_t<N, point> constexpr point::get() const +template<size_t N> typename std::tuple_element<N, point>::type constexpr point::get() const { static_assert(N < 2); if constexpr(N == 0) diff --git a/src/raycast.cpp b/src/raycast.cpp index 06cc416e..cb939758 100644 --- a/src/raycast.cpp +++ b/src/raycast.cpp @@ -168,9 +168,9 @@ raycast_result_s do_raycasting(std::conditional_t<EnableDiagnostics, raycast_dia .to = to, .collision = {}, .collider = { - .tag = (uint64_t)collision_type::none, + .type = (uint64_t)collision_type::none, .pass = (uint64_t)pass_mode::pass, - .data = ((uint64_t)1 << collision_data_BITS)-1, + .id = ((uint64_t)1 << collision_data_BITS)-1, }, .has_result = true, .success = false, @@ -234,7 +234,7 @@ raycast_result_s do_raycasting(std::conditional_t<EnableDiagnostics, raycast_dia const auto do_check_collider = [&](uint64_t data, const Rect& r) { auto x = std::bit_cast<collision_data>(data); - if (x.data == self || x.pass == (uint64_t)pass_mode::pass) + if (x.id == self || x.pass == (uint64_t)pass_mode::pass) return; //Debug{} << "item" << x.data << Vector2(r.m_min[0], r.m_min[1]) << Vector2(r.m_max[0], r.m_max[1]); auto ret = ray_aabb_intersection(origin, dir_inv_norm, diff --git a/src/script.cpp b/src/script.cpp index f2b7d30d..23d11e0d 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -5,6 +5,8 @@ namespace floormat { namespace { +namespace fm_debug = floormat::debug::detail; + constexpr StringView names[(size_t)script_lifecycle::COUNT] = { "no-init"_s, "initializing"_s, "created"_s, "destroying"_s, "torn-down"_s, @@ -23,10 +25,10 @@ StringView base_script::state_name(script_lifecycle x) void base_script::_assert_state(script_lifecycle old_state, script_lifecycle s, const char* file, int line) { if (old_state != s) [[unlikely]] - fm_emit_abort(file, line, - "invalid state transition from '%s' to '%s'", - state_name(old_state).data(), - state_name(s).data()); + fm_debug::emit_abort(file, line, + "invalid state transition from '%s' to '%s'", + state_name(old_state).data(), + state_name(s).data()); } base_script::~base_script() noexcept = default; diff --git a/src/search.cpp b/src/search.cpp index 220e3869..424b1743 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -45,7 +45,7 @@ bool path_search::is_passable_1(chunk& c, Vector2 min, Vector2 max, object_id ow rt.Search(min.data(), max.data(), [&](uint64_t data, const auto& r) { auto x = std::bit_cast<collision_data>(data); - if (x.data != own_id && x.pass != (uint64_t)pass_mode::pass) + if (x.id != own_id && x.pass != (uint64_t)pass_mode::pass) { if (rect_intersects(min, max, {r.m_min[0], r.m_min[1]}, {r.m_max[0], r.m_max[1]})) if (p(x) != path_search_continue::pass) diff --git a/src/tile-bbox.hpp b/src/tile-bbox.hpp index 755004d2..6d2228b1 100644 --- a/src/tile-bbox.hpp +++ b/src/tile-bbox.hpp @@ -8,11 +8,12 @@ namespace floormat { template<typename T = float> -constexpr Vector2 tile_start(size_t k) +constexpr VectorTypeFor<2, T> tile_start(size_t k) { - constexpr auto half_tile = VectorTypeFor<2,T>(tile_size_xy/2); + using Vec2 = VectorTypeFor<2,T>; + constexpr auto half_tile = Vec2{tile_size_xy/2}; const local_coords coord{k}; - return TILE_SIZE2 * VectorTypeFor<2,T>(coord) - half_tile; + return Vec2(TILE_SIZE2) * Vec2(coord) - half_tile; } constexpr Pair<Vector2i, Vector2i> scenery_tile(local_coords local, Vector2b offset, Vector2b bbox_offset, Vector2ub bbox_size) @@ -31,24 +32,27 @@ constexpr Pair<VectorTypeFor<2,T>, VectorTypeFor<2,T>> whole_tile(size_t k) } template<typename T = float> -constexpr Pair<VectorTypeFor<2,T>, VectorTypeFor<2,T>> wall_north(size_t k, float wall_depth) +constexpr Pair<VectorTypeFor<2,T>, VectorTypeFor<2,T>> wall_north(size_t k, T wall_depth) { - auto min = tile_start<T>(k) - VectorTypeFor<2,T>{0, wall_depth}; - return { min, min + VectorTypeFor<2,T>{TILE_SIZE2.x(), wall_depth} }; + using Vec2 = VectorTypeFor<2,T>; + auto min = tile_start<T>(k) - Vec2{0, wall_depth}; + return { min, min + Vec2{tile_size_xy, wall_depth} }; } template<typename T = float> -constexpr Pair<VectorTypeFor<2,T>, VectorTypeFor<2,T>> wall_west(size_t k, float wall_depth) +constexpr Pair<VectorTypeFor<2,T>, VectorTypeFor<2,T>> wall_west(size_t k, T wall_depth) { - auto min = tile_start<T>(k) - VectorTypeFor<2,T>{wall_depth, 0}; - return { min, min + VectorTypeFor<2,T>{wall_depth, TILE_SIZE2.y()} }; + using Vec2 = VectorTypeFor<2,T>; + auto min = tile_start<T>(k) - Vec2{wall_depth, 0}; + return { min, min + Vec2{wall_depth, tile_size_xy} }; } template<typename T = float> -constexpr Pair<VectorTypeFor<2,T>, VectorTypeFor<2,T>> wall_pillar(size_t k, float wall_depth) +constexpr Pair<VectorTypeFor<2,T>, VectorTypeFor<2,T>> wall_pillar(size_t k, T wall_depth) { - auto min = tile_start<T>(k) - VectorTypeFor<2,T>{wall_depth, 0}; - return { min - VectorTypeFor<2,T>{0, wall_depth}, min + VectorTypeFor<2,T>{wall_depth, TILE_SIZE2.y()} }; + using Vec2 = VectorTypeFor<2,T>; + auto min = tile_start<T>(k) - Vec2{wall_depth, 0}; + return { min - Vec2{0, wall_depth}, min + Vec2{wall_depth, tile_size_xy} }; } } // namespace floormat diff --git a/src/wall-atlas.hpp b/src/wall-atlas.hpp index e0203165..20dd2a84 100644 --- a/src/wall-atlas.hpp +++ b/src/wall-atlas.hpp @@ -53,19 +53,13 @@ struct Direction bool operator==(const Direction&) const noexcept; - static constexpr inline member_tuple groups[] = { + static constexpr member_tuple groups[] = { { "wall"_s, &Direction::wall, Group_::wall }, { "side"_s, &Direction::side, Group_::side }, { "top"_s, &Direction::top, Group_::top }, { "corner"_s, &Direction::corner, Group_::corner }, }; - static_assert(array_size(groups) == (size_t)Group_::COUNT); - - static constexpr inline member_tuple groups_for_draw[] = { - { "wall"_s, &Direction::wall, Group_::wall }, - { "side"_s, &Direction::side, Group_::side }, - { "top"_s, &Direction::top, Group_::top }, - }; + static_assert(array_size(groups) + /*pillar 1 */ 0 == (size_t)Group_::COUNT); }; struct Info diff --git a/src/wall-defs.hpp b/src/wall-defs.hpp index a19d560b..9f88853c 100644 --- a/src/wall-defs.hpp +++ b/src/wall-defs.hpp @@ -3,7 +3,7 @@ namespace floormat::Wall { -enum class Group_ : uint8_t { wall, side, top, corner, COUNT }; +enum class Group_ : uint8_t { wall, side, top, corner, /*pillar,*/ COUNT }; enum class Direction_ : uint8_t { N, W, COUNT }; diff --git a/src/world.cpp b/src/world.cpp index 89c127cc..1c7c45c9 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -33,9 +33,12 @@ struct world::robin_map_wrapper final : tsl::robin_map<object_id, bptr<object>, world::world(world&& w) noexcept = default; -world::world(std::unordered_map<chunk_coords_, chunk>&& chunks) : - world{std::max(initial_capacity, size_t(1/max_load_factor * 2 * chunks.size()))} +world::world(std::unordered_map<chunk_coords_, chunk, chunk_coords_hasher>&& chunks) { + const auto capʹ = (size_t)(1e-4f + (float)chunks.size() / max_load_factor); + const auto cap = std::max(capʹ, initial_capacity); + _chunks.reserve(cap); + _chunks.max_load_factor(max_load_factor); for (auto&& [coord, c] : chunks) operator[](coord) = move(c); } diff --git a/src/world.hpp b/src/world.hpp index a643de3b..01fc5cc9 100644 --- a/src/world.hpp +++ b/src/world.hpp @@ -67,7 +67,7 @@ private: public: explicit world(); ~world() noexcept; - explicit world(std::unordered_map<chunk_coords_, chunk>&& chunks); + explicit world(std::unordered_map<chunk_coords_, chunk, chunk_coords_hasher>&& chunks); struct pair_chunk_tile final { chunk& c; tile_ref t; }; // NOLINT |
