diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/chunk.cpp | 9 | ||||
-rw-r--r-- | src/chunk.hpp | 7 | ||||
-rw-r--r-- | src/global-coords.cpp | 17 | ||||
-rw-r--r-- | src/global-coords.hpp | 42 | ||||
-rw-r--r-- | src/local-coords.hpp | 2 | ||||
-rw-r--r-- | src/world.cpp | 94 | ||||
-rw-r--r-- | src/world.hpp | 58 |
7 files changed, 182 insertions, 47 deletions
diff --git a/src/chunk.cpp b/src/chunk.cpp index 4537acec..95904d81 100644 --- a/src/chunk.cpp +++ b/src/chunk.cpp @@ -2,4 +2,13 @@ namespace floormat { +bool chunk::empty() const +{ + for (const tile& x : _tiles) + if (x.ground_image || x.wall_north || x.wall_west) + return false; + + return true; +} + } // namespace floormat diff --git a/src/chunk.hpp b/src/chunk.hpp index a20a12ce..7ef0bc94 100644 --- a/src/chunk.hpp +++ b/src/chunk.hpp @@ -32,6 +32,13 @@ struct chunk final const_iterator begin() const { return cbegin(); } const_iterator end() const { return cend(); } + bool empty() const; + + chunk() = default; + chunk(chunk&&) = default; + chunk& operator=(chunk&&) = default; + DECLARE_DELETED_COPY_ASSIGNMENT(chunk); + private: std::array<tile, TILE_COUNT> _tiles = {}; }; diff --git a/src/global-coords.cpp b/src/global-coords.cpp new file mode 100644 index 00000000..997f1c11 --- /dev/null +++ b/src/global-coords.cpp @@ -0,0 +1,17 @@ +#include "global-coords.hpp" + +namespace floormat { + +static_assert(sizeof(decltype(local_coords::x))*8 == 8); +static_assert(sizeof(decltype(chunk_coords::x))*8 == 16); +static_assert(std::is_same_v<decltype(local_coords::x), decltype(local_coords::y)>); +static_assert(std::is_same_v<decltype(chunk_coords::x), decltype(chunk_coords::y)>); + +static_assert(std::is_same_v<decltype(chunk_coords::x), decltype(chunk_coords::y)>); + +static_assert(global_coords{{-1, -1}, {2, 3}} == global_coords{((-1 + (1 << 15)) << 4) + 2, ((-1 + (1 << 15)) << 4) + 3}); +static_assert(global_coords{15, 15}.chunk() == global_coords{}.chunk()); +static_assert(global_coords{15, 16}.chunk() != global_coords{}.chunk()); +static_assert(global_coords{(1 + (1<<15)) << 4 | 3, (2 + (1<<15)) << 4 | 4} == global_coords{{1, 2}, {3, 4}}); + +} // namespace floormat diff --git a/src/global-coords.hpp b/src/global-coords.hpp new file mode 100644 index 00000000..e51dc6aa --- /dev/null +++ b/src/global-coords.hpp @@ -0,0 +1,42 @@ +#pragma once +#include "local-coords.hpp" +#include "compat/assert.hpp" + +namespace floormat { + +struct chunk_coords final { + std::int16_t x = 0, y = 0; + + constexpr bool operator==(const chunk_coords& other) const noexcept = default; +}; + +struct global_coords final { + std::uint32_t x = 0, y = 0; + + constexpr global_coords(chunk_coords c, local_coords xy) : + x{ std::uint32_t(c.x + (1 << 15)) << 4 | (xy.x & 0x0f) }, + y{ std::uint32_t(c.y + (1 << 15)) << 4 | (xy.y & 0x0f) } + {} + constexpr global_coords(std::uint32_t x, std::uint32_t y) noexcept : x{x}, y{y} {} + constexpr global_coords() noexcept = default; + + constexpr local_coords local() const noexcept; + constexpr chunk_coords chunk() const noexcept; + + constexpr bool operator==(const global_coords& other) const noexcept = default; +}; + +constexpr local_coords global_coords::local() const noexcept +{ + return { (std::uint8_t)(x % TILE_MAX_DIM), (std::uint8_t)(y % TILE_MAX_DIM) }; +} + +constexpr chunk_coords global_coords::chunk() const noexcept +{ + return { + (std::int16_t)(std::int32_t(x >> 4) - (1 << 15)), + (std::int16_t)(std::int32_t(y >> 4) - (1 << 15)), + }; +} + +} // namespace floormat diff --git a/src/local-coords.hpp b/src/local-coords.hpp index 272c2877..f5615f9a 100644 --- a/src/local-coords.hpp +++ b/src/local-coords.hpp @@ -3,8 +3,6 @@ #include "tile-defs.hpp" #include <cstdint> #include <concepts> -#include <Magnum/Magnum.h> -#include <Magnum/Math/Vector3.h> namespace floormat { diff --git a/src/world.cpp b/src/world.cpp index 63209bf7..56025587 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -1,19 +1,93 @@ #include "world.hpp" +#include "chunk.hpp" namespace floormat { -static_assert(sizeof(decltype(local_coords::x))*8 == 8); -static_assert(sizeof(decltype(chunk_coords::x))*8 == 16); -static_assert(std::is_same_v<decltype(local_coords::x), decltype(local_coords::y)>); -static_assert(std::is_same_v<decltype(chunk_coords::x), decltype(chunk_coords::y)>); +struct chunk_pointer_maker final +{ + operator std::shared_ptr<chunk>() const { return std::make_shared<chunk>(); } +}; -static_assert(std::is_same_v<decltype(chunk_coords::x), decltype(chunk_coords::y)>); +world::world() +{ + _chunks.max_load_factor(max_load_factor); +} -static_assert(global_coords{{-1, -1}, {}} != global_coords{}); -static_assert(global_coords{15, 15}.chunk() == global_coords{}.chunk()); -static_assert(global_coords{15, 16}.chunk() != global_coords{}.chunk()); -static_assert(global_coords{(1 + (1<<15)) << 4 | 3, (2 + (1<<15)) << 4 | 4} == global_coords{{1, 2}, {3, 4}}); +std::shared_ptr<chunk> world::operator[](chunk_coords c) noexcept +{ + auto [it, inserted] = _chunks.try_emplace(c, chunk_pointer_maker{}); + maybe_collect(); return it->second; +} +std::shared_ptr<const chunk> world::maybe_chunk(chunk_coords c) const noexcept +{ + if (const auto it = _chunks.find(c); it != _chunks.cend()) + return it->second; + else + return nullptr; +} -} // namespace floormat +std::shared_ptr<chunk> world::maybe_chunk(chunk_coords c) noexcept +{ + return std::const_pointer_cast<chunk>(const_cast<const world&>(*this).maybe_chunk(c)); +} + +bool world::contains(chunk_coords c) const noexcept +{ + return _chunks.find(c) != _chunks.cend(); +} + +void world::clear() +{ + _last_collection = 0; + _chunks.rehash(initial_capacity); +} + +void world::maybe_collect() +{ + if (_last_collection + collect_every > _chunks.size()) + collect(); +} + +void world::collect() +{ + for (auto it = _chunks.begin(); it != _chunks.end(); (void)0) + { + const auto& [k, c] = *it; + if (c->empty()) + it = _chunks.erase(it); + else + it++; + } + _last_collection = _chunks.size(); +} +std::size_t world::hasher::operator()(chunk_coords c) const noexcept +{ + void _really_unreachable(); + + std::size_t x = (std::size_t)c.y << 16 | (std::size_t)c.x; + if constexpr(sizeof(std::size_t) == 4) + { + // by Chris Wellons <https://nullprogram.com/blog/2018/07/31/> + x ^= x >> 15; + x *= 0x2c1b3c6dU; + x ^= x >> 12; + x *= 0x297a2d39U; + x ^= x >> 15; + } + else if constexpr(sizeof(std::size_t) == 8) + { + x ^= x >> 30; + x *= 0xbf58476d1ce4e5b9U; + x ^= x >> 27; + x *= 0x94d049bb133111ebU; + x ^= x >> 31; + } + else + _really_unreachable(); + + return x; +} + +} // namespace floormat diff --git a/src/world.hpp b/src/world.hpp index 8cbaa710..75e05bd8 100644 --- a/src/world.hpp +++ b/src/world.hpp @@ -1,43 +1,31 @@ #pragma once -#include "src/chunk.hpp" -#include "compat/assert.hpp" +#include "global-coords.hpp" +#include <unordered_map> +#include <memory> namespace floormat { -struct chunk_coords final { - std::int16_t x = 0, y = 0; +struct chunk; - constexpr bool operator==(const chunk_coords& other) const noexcept = default; -}; - -struct global_coords final { - std::uint32_t x = 0, y = 0; - - constexpr global_coords(chunk_coords c, local_coords xy) : - x{ std::uint32_t(c.x + (1 << 15)) << 4 | (xy.x & 0x0f) }, - y{ std::uint32_t(c.y + (1 << 15)) << 4 | (xy.y & 0x0f) } - {} - constexpr global_coords(std::uint32_t x, std::uint32_t y) noexcept : x{x}, y{y} {} - constexpr global_coords() noexcept = default; - - constexpr local_coords local() const noexcept; - constexpr chunk_coords chunk() const noexcept; - - constexpr bool operator==(const global_coords& other) const noexcept = default; -}; - -constexpr local_coords global_coords::local() const noexcept +struct world final { - return { (std::uint8_t)(x % TILE_MAX_DIM), (std::uint8_t)(y % TILE_MAX_DIM) }; -} - - -constexpr chunk_coords global_coords::chunk() const noexcept -{ - return { - (std::int16_t)(std::int32_t(x >> 4) - (1 << 15)), - (std::int16_t)(std::int32_t(y >> 4) - (1 << 15)), - }; -} + world(); + std::shared_ptr<chunk> operator[](chunk_coords c) noexcept; + std::shared_ptr<chunk> maybe_chunk(chunk_coords c) noexcept; + std::shared_ptr<const chunk> maybe_chunk(chunk_coords c) const noexcept; + bool contains(chunk_coords c) const noexcept; + void clear(); + void collect(); + +private: + static constexpr std::size_t initial_capacity = 64, collect_every = 100; + static constexpr float max_load_factor = .5; + std::size_t _last_collection = 0; + + void maybe_collect(); + struct hasher final { std::size_t operator()(chunk_coords c) const noexcept; }; + + std::unordered_map<chunk_coords, std::shared_ptr<chunk>, hasher> _chunks{initial_capacity}; +}; } // namespace floormat |