summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/RTree-fwd.h7
-rw-r--r--src/RTree.cpp3
-rw-r--r--src/RTree.h6
-rw-r--r--src/anim-atlas.cpp8
-rw-r--r--src/anim.cpp1
-rw-r--r--src/chunk-collision.cpp90
-rw-r--r--src/chunk-region.cpp4
-rw-r--r--src/chunk-render.cpp8
-rw-r--r--src/chunk-scenery.cpp21
-rw-r--r--src/chunk-walls.cpp533
-rw-r--r--src/chunk.cpp18
-rw-r--r--src/chunk.hpp19
-rw-r--r--src/collision.hpp6
-rw-r--r--src/critter-script-walk.cpp1
-rw-r--r--src/critter.cpp103
-rw-r--r--src/hole-cut.cpp89
-rw-r--r--src/hole-cut.hpp25
-rw-r--r--src/hole.hpp16
-rw-r--r--src/object.cpp2
-rw-r--r--src/object.hpp1
-rw-r--r--src/point.hpp4
-rw-r--r--src/raycast.cpp6
-rw-r--r--src/script.cpp10
-rw-r--r--src/search.cpp2
-rw-r--r--src/tile-bbox.hpp28
-rw-r--r--src/wall-atlas.hpp10
-rw-r--r--src/wall-defs.hpp2
-rw-r--r--src/world.cpp7
-rw-r--r--src/world.hpp2
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