summary refs log tree commit diff
path: root/src/World
diff options
context:
space:
mode:
Diffstat (limited to 'src/World')
-rw-r--r--src/World/Chunk.cpp4
-rw-r--r--src/World/Chunk.hpp6
-rw-r--r--src/World/ChunkIndex.hpp33
-rw-r--r--src/World/Generator.cpp4
-rw-r--r--src/World/Generator.hpp2
-rw-r--r--src/World/World.cpp67
-rw-r--r--src/World/World.hpp38
7 files changed, 150 insertions, 4 deletions
diff --git a/src/World/Chunk.cpp b/src/World/Chunk.cpp
index 0d86ddb..d02e5e5 100644
--- a/src/World/Chunk.cpp
+++ b/src/World/Chunk.cpp
@@ -45,6 +45,10 @@ GFX::Mesh Chunk::mesh() {
     return {positions, tex_coords, indices};
 }
 
+Vector<3> Chunk::position() {
+    return m_position;
+}
+
 bool Chunk::is_face_visible(uint32_t x, uint32_t y, uint32_t z, BlockSide side) {
     Vector<3, int32_t> offset{};
     switch (side) {
diff --git a/src/World/Chunk.hpp b/src/World/Chunk.hpp
index 7a93f5a..797a757 100644
--- a/src/World/Chunk.hpp
+++ b/src/World/Chunk.hpp
@@ -14,9 +14,12 @@ namespace MC::World {
 
 class Chunk {
 public:
-    Chunk() : m_blocks{} {};
+    Chunk(int64_t x, int64_t y)
+        : m_blocks{}, m_position{(float)x * CHUNK_WIDTH, 0.0f, (float)y * CHUNK_WIDTH} {};
 
     void set(uint32_t x, uint32_t y, uint32_t z, BlockType type);
+
+    Vector<3> position();
     GFX::Mesh mesh();
 private:
     bool is_face_visible(uint32_t x, uint32_t y, uint32_t z, BlockSide side);
@@ -27,6 +30,7 @@ private:
         BlockType type;
     };
 
+    Vector<3> m_position;
     BlockData m_blocks[CHUNK_WIDTH][CHUNK_HEIGHT][CHUNK_WIDTH];
 };
 
diff --git a/src/World/ChunkIndex.hpp b/src/World/ChunkIndex.hpp
new file mode 100644
index 0000000..330d202
--- /dev/null
+++ b/src/World/ChunkIndex.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <cstdint>
+#include <cstdlib>
+#include <functional>
+
+namespace MC::World {
+
+struct ChunkIndex {
+    ChunkIndex(int64_t x, int64_t y) : x(x), y(x) {}
+
+    bool operator==(ChunkIndex& other) const {
+        return x == other.x && y == other.y;
+    }
+
+    int64_t x, y;
+};
+
+}
+
+template<> struct std::equal_to<MC::World::ChunkIndex> {
+    bool operator()(const MC::World::ChunkIndex& i1, const MC::World::ChunkIndex& i2) const noexcept {
+        return i1.x == i2.x && i1.y == i2.y;
+    }
+};
+
+template<> struct std::hash<MC::World::ChunkIndex> {
+    std::size_t operator()(const MC::World::ChunkIndex& i) const noexcept {
+        std::size_t xh = std::hash<int64_t>{}(i.x);
+        std::size_t yh = std::hash<int64_t>{}(i.y);
+        return xh ^ (yh << 1);
+    }
+};
\ No newline at end of file
diff --git a/src/World/Generator.cpp b/src/World/Generator.cpp
index d7bb038..757abf2 100644
--- a/src/World/Generator.cpp
+++ b/src/World/Generator.cpp
@@ -2,8 +2,8 @@
 
 namespace MC::World {
 
-Chunk Generator::generate(uint32_t _x, uint32_t _y) {
-    Chunk chunk;
+Chunk Generator::generate(int64_t chunk_x, int64_t chunk_y) {
+    Chunk chunk(chunk_x, chunk_y);
 
     for (int y = 0; y < CHUNK_HEIGHT; y++) {
         BlockType type = BlockType::Air;
diff --git a/src/World/Generator.hpp b/src/World/Generator.hpp
index 9ddac66..479089f 100644
--- a/src/World/Generator.hpp
+++ b/src/World/Generator.hpp
@@ -9,7 +9,7 @@ class Generator {
 public:
     Generator() = default;
 
-    Chunk generate(uint32_t x, uint32_t y);
+    Chunk generate(int64_t chunk_x, int64_t chunk_y);
 };
 
 }
diff --git a/src/World/World.cpp b/src/World/World.cpp
new file mode 100644
index 0000000..5a0d729
--- /dev/null
+++ b/src/World/World.cpp
@@ -0,0 +1,67 @@
+#include "World.hpp"
+
+namespace MC::World {
+
+std::vector<World::ChunkData> World::get_visible_chunks(Vector<3> position) {
+    auto visible_chunks = get_visible_chunk_indices(position);
+
+    auto difference = visible_chunks;
+    for (auto index : m_visible_chunks) {
+        difference.erase(index);
+    }
+
+    if (!difference.empty()) {
+        for (auto new_index: difference) {
+            auto& data = get_or_generate(new_index);
+            if (!data.mesh.has_value()) {
+                auto mesh = data.chunk->mesh();
+                data.mesh = GFX::Binder::load(mesh);
+            }
+        }
+        m_visible_chunks = visible_chunks;
+    }
+
+    std::vector<World::ChunkData> chunks{};
+    chunks.reserve(visible_chunks.size());
+    for (auto index : visible_chunks) {
+        chunks.push_back(get_or_generate(index));
+    }
+
+    return chunks;
+}
+
+std::unordered_set<ChunkIndex> World::get_visible_chunk_indices(Vector<3> position) const {
+    int64_t center_x = std::round(position.x() / CHUNK_WIDTH);
+    int64_t center_y = std::round(position.z() / CHUNK_HEIGHT);
+
+    auto upper_x_bound = center_x + m_view_distance_radius;
+    auto lower_x_bound = center_x - m_view_distance_radius;
+    auto upper_y_bound = center_y + m_view_distance_radius;
+    auto lower_y_bound = center_y - m_view_distance_radius;
+
+    std::unordered_set<ChunkIndex> indices{};
+    indices.reserve(m_view_distance_radius * m_view_distance_radius * 4);
+    for (int64_t x = lower_x_bound; x < upper_x_bound; x++) {
+        for (int64_t y = lower_y_bound; y < upper_y_bound; y++) {
+            indices.emplace(x, y);
+        }
+    }
+
+    return indices;
+}
+
+World::ChunkData& World::get_or_generate(ChunkIndex index) {
+    auto entry = m_chunks.find(index);
+    if (entry == m_chunks.end()) {
+        auto chunk = m_generator.generate(index.x, index.y);
+        ChunkData data{index, std::make_shared<Chunk>(chunk)};
+
+        m_chunks.insert({index, data});
+        return m_chunks.at(index);
+    }
+
+    return entry->second;
+}
+
+
+}
\ No newline at end of file
diff --git a/src/World/World.hpp b/src/World/World.hpp
new file mode 100644
index 0000000..3453b18
--- /dev/null
+++ b/src/World/World.hpp
@@ -0,0 +1,38 @@
+#pragma once
+
+#include <memory>
+#include <unordered_set>
+#include <utility>
+#include "Generator.hpp"
+#include "ChunkIndex.hpp"
+
+namespace MC::World {
+
+class World {
+public:
+    World() : m_generator(), m_chunks(), m_visible_chunks() {}
+
+    struct ChunkData {
+        ChunkData(ChunkIndex index, std::shared_ptr<Chunk> chunk)
+            : index(index), chunk(std::move(chunk)), mesh() {}
+
+        ChunkIndex index;
+        std::shared_ptr<Chunk> chunk;
+        std::optional<GFX::BindableMesh> mesh;
+    };
+
+    std::vector<ChunkData> get_visible_chunks(Vector<3> position);
+
+private:
+    std::unordered_set<ChunkIndex> get_visible_chunk_indices(Vector<3> position) const;
+    ChunkData& get_or_generate(ChunkIndex index);
+
+    uint8_t m_view_distance_radius = 6;
+
+    Generator m_generator;
+
+    std::unordered_map<ChunkIndex, ChunkData> m_chunks;
+    std::unordered_set<ChunkIndex> m_visible_chunks;
+};
+
+}