summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/chunk.cpp9
-rw-r--r--src/chunk.hpp7
-rw-r--r--src/global-coords.cpp17
-rw-r--r--src/global-coords.hpp42
-rw-r--r--src/local-coords.hpp2
-rw-r--r--src/world.cpp94
-rw-r--r--src/world.hpp58
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