summaryrefslogtreecommitdiffhomepage
path: root/chunk.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'chunk.hpp')
-rw-r--r--chunk.hpp162
1 files changed, 162 insertions, 0 deletions
diff --git a/chunk.hpp b/chunk.hpp
new file mode 100644
index 00000000..99ad1778
--- /dev/null
+++ b/chunk.hpp
@@ -0,0 +1,162 @@
+#pragma once
+#include "tile.hpp"
+#include <type_traits>
+#include <vector>
+
+namespace Magnum::Examples {
+
+static constexpr std::size_t TILE_MAX_DIM = 16;
+static constexpr std::size_t TILE_COUNT = TILE_MAX_DIM*TILE_MAX_DIM;
+
+struct local_coords final {
+ std::uint8_t x = 0, y = 0;
+ constexpr std::size_t to_index() const noexcept;
+};
+
+constexpr std::size_t local_coords::to_index() const noexcept {
+ return y*TILE_MAX_DIM + x;
+}
+
+struct chunk_coords final {
+ std::int16_t x = 0, y = 0;
+ constexpr std::size_t to_index() const noexcept;
+
+ static constexpr std::size_t max_bits = sizeof(chunk_coords::x)*8 * 3 / 4;
+ static_assert(max_bits*4/3/8 == sizeof(decltype(chunk_coords::x)));
+};
+
+struct chunk_sampler_array final {
+ using shared_sampler = std::shared_ptr<tile_atlas>;
+ using sampler_tuple = std::pair<shared_sampler, int>;
+
+ static constexpr inline int MAX_SAMPLERS = 16;
+ std::vector<std::shared_ptr<tile_atlas>> samplers;
+ std::array<UnsignedInt, TILE_COUNT> sampler_map = {};
+
+ chunk_sampler_array();
+ void ensure_sampler(std::size_t tile_id, const shared_sampler& x);
+ std::shared_ptr<tile_atlas> operator[](std::size_t tile_id) const;
+ void clear();
+ void bind();
+
+ static_assert(MAX_SAMPLERS <= 0xff);
+};
+
+struct global_coords final {
+ std::uint32_t x = 0, y = 0;
+ constexpr global_coords() noexcept = default;
+ constexpr global_coords(decltype(x) x, decltype(y) y) noexcept : x{x}, y{y} {}
+ constexpr global_coords(chunk_coords c, local_coords tile) noexcept;
+};
+
+static_assert(std::is_same_v<decltype(chunk_coords::x), decltype(chunk_coords::y)>);
+static_assert(std::is_same_v<decltype(global_coords::x), decltype(global_coords::y)>);
+
+struct chunk final
+{
+ using index_type = decltype(local_coords::x);
+ using tile_index_array_type = std::array<index_type, TILE_COUNT>;
+ //static constexpr inline local_coords center = { (index_type)(N/2), (index_type)(N/2) };
+
+ constexpr tile& operator[](local_coords xy);
+ constexpr const tile& operator[](local_coords xy) const;
+ constexpr tile& operator[](std::size_t i);
+ constexpr const tile& operator[](std::size_t i) const;
+
+ template<typename F>
+ requires std::invocable<F, tile&, int, int>
+ constexpr inline void foreach_tile(F&& fun) { foreach_tile_<F, chunk&>(std::forward<F>(fun)); }
+
+ template<typename F>
+ requires std::invocable<F, const tile&, int, int>
+ constexpr inline void foreach_tile(F&& fun) const { foreach_tile_<F, const chunk&>(std::forward<F>(fun)); }
+
+private:
+ template<typename F, typename Self> constexpr void foreach_tile_(F&& fun);
+
+ std::array<tile, TILE_COUNT> tiles = {};
+ chunk_sampler_array samplers;
+};
+
+constexpr tile& chunk::operator[](std::size_t i) {
+ if (i >= TILE_COUNT)
+ throw OUT_OF_RANGE(i, 0, TILE_COUNT);
+ return tiles[i];
+}
+
+constexpr const tile& chunk::operator[](std::size_t i) const {
+ return const_cast<chunk&>(*this).operator[](i);
+}
+
+constexpr const tile& chunk::operator[](local_coords xy) const {
+ return const_cast<chunk&>(*this).operator[](xy);
+}
+
+constexpr tile& chunk::operator[](local_coords xy)
+{
+ auto idx = xy.to_index();
+ return operator[](idx);
+}
+
+template<typename F, typename Self>
+constexpr void chunk::foreach_tile_(F&& fun)
+{
+ constexpr auto N = TILE_MAX_DIM;
+ for (unsigned j = 0; j < N; j++)
+ for (unsigned i = 0; i < N; i++)
+ {
+ unsigned idx = j*N + i;
+ fun(const_cast<Self>(*this).tiles[idx], i, j);
+ }
+}
+
+constexpr std::size_t chunk_coords::to_index() const noexcept
+{
+ using unsigned_type = std::make_unsigned_t<decltype(x)>;
+ using limits = std::numeric_limits<unsigned_type>;
+ constexpr auto N = limits::max() + std::size_t{1};
+ static_assert(sizeof(unsigned_type) <= sizeof(UnsignedInt)/2);
+ return (std::size_t)(unsigned_type)y * N + (std::size_t)(unsigned_type)x;
+}
+
+struct hash_chunk final {
+ constexpr std::size_t operator()(chunk_coords xy) const noexcept {
+ return hash<sizeof(std::size_t)*8>{}(xy.to_index());
+ }
+};
+
+struct world final
+{
+ static_assert(sizeof(chunk_coords::x) <= sizeof(std::size_t)/2);
+
+ explicit world() = default;
+ template<typename F> std::shared_ptr<chunk> ensure_chunk(chunk_coords xy, F&& fun);
+
+private:
+ std::unordered_map<chunk_coords, std::shared_ptr<chunk>, hash_chunk> chunks;
+};
+
+template<typename F>
+std::shared_ptr<chunk> world::ensure_chunk(chunk_coords xy, F&& fun)
+{
+ ASSERT(xy.x < 1 << chunk_coords::max_bits);
+ ASSERT(xy.y < 1 << chunk_coords::max_bits);
+
+ auto it = chunks.find(xy);
+ if (it != chunks.end())
+ return it->second;
+ else
+ {
+ std::shared_ptr<chunk> ptr{fun()};
+ ASSERT(ptr);
+ return chunks[xy] = std::move(ptr);
+ }
+}
+
+constexpr global_coords::global_coords(chunk_coords c, local_coords tile) noexcept :
+ x{tile.x + ((std::uint32_t)(std::make_unsigned_t<decltype(c.x)>)c.x << chunk_coords::max_bits)},
+ y{tile.y + ((std::uint32_t)(std::make_unsigned_t<decltype(c.y)>)c.y << chunk_coords::max_bits)}
+{
+}
+
+} // namespace Magnum::Examples