diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2022-10-01 19:35:43 +0200 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2022-10-01 19:35:43 +0200 |
commit | 9436414c5002e86e64f90be3f10933fdba63943e (patch) | |
tree | 96dde7340044d2088d6948dada1b0da0f34d4c43 /chunk.hpp | |
parent | 85a8bd54726fe4edc70676b797ed90f519dbbf7d (diff) |
a
Diffstat (limited to 'chunk.hpp')
-rw-r--r-- | chunk.hpp | 162 |
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 |