summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--src/GFX/Image/PPMParser.cpp2
-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
-rw-r--r--src/main.cpp24
10 files changed, 162 insertions, 20 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f1834cf..ecbf6b8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,7 +10,7 @@ if (LINUX)
     find_package(OpenGL REQUIRED)
 endif (LINUX)
 
-add_executable(meowcraft src/main.cpp src/GFX/Window.cpp src/GFX/Window.hpp src/GFX/Mesh.cpp src/GFX/Mesh.hpp src/Math/Vector.hpp src/Math/Math.hpp src/GFX/Binder.cpp src/GFX/Binder.hpp src/GFX/Shading/Shader.cpp src/GFX/Shading/Shader.hpp src/GFX/Shading/Program.cpp src/GFX/Shading/Program.hpp src/Math/Matrix.hpp src/Math/MVP.cpp src/Math/MVP.hpp src/GFX/Camera.cpp src/GFX/Camera.hpp src/Math/Rotation.hpp src/GFX/Shading/Uniform.cpp src/GFX/Shading/Uniform.hpp src/GFX/Mouse.cpp src/GFX/Mouse.hpp src/Math/Trig.hpp src/GFX/Texture.cpp src/GFX/Texture.hpp src/Assets.cpp src/Assets.hpp src/GFX/Image/RawImage.cpp src/GFX/Image/RawImage.hpp src/GFX/Image/PPMParser.cpp src/GFX/Image/PPMParser.hpp src/World/Chunk.cpp src/World/Chunk.hpp src/World/BlockType.hpp src/World/Generator.cpp src/World/Generator.hpp src/World/BlockSide.hpp)
+add_executable(meowcraft src/main.cpp src/GFX/Window.cpp src/GFX/Window.hpp src/GFX/Mesh.cpp src/GFX/Mesh.hpp src/Math/Vector.hpp src/Math/Math.hpp src/GFX/Binder.cpp src/GFX/Binder.hpp src/GFX/Shading/Shader.cpp src/GFX/Shading/Shader.hpp src/GFX/Shading/Program.cpp src/GFX/Shading/Program.hpp src/Math/Matrix.hpp src/Math/MVP.cpp src/Math/MVP.hpp src/GFX/Camera.cpp src/GFX/Camera.hpp src/Math/Rotation.hpp src/GFX/Shading/Uniform.cpp src/GFX/Shading/Uniform.hpp src/GFX/Mouse.cpp src/GFX/Mouse.hpp src/Math/Trig.hpp src/GFX/Texture.cpp src/GFX/Texture.hpp src/Assets.cpp src/Assets.hpp src/GFX/Image/RawImage.cpp src/GFX/Image/RawImage.hpp src/GFX/Image/PPMParser.cpp src/GFX/Image/PPMParser.hpp src/World/Chunk.cpp src/World/Chunk.hpp src/World/BlockType.hpp src/World/Generator.cpp src/World/Generator.hpp src/World/BlockSide.hpp src/World/World.cpp src/World/World.hpp src/World/ChunkIndex.hpp)
 target_link_libraries(meowcraft glfw GLEW::GLEW)
 
 if (LINUX)
diff --git a/src/GFX/Image/PPMParser.cpp b/src/GFX/Image/PPMParser.cpp
index 7fc2359..b809ef1 100644
--- a/src/GFX/Image/PPMParser.cpp
+++ b/src/GFX/Image/PPMParser.cpp
@@ -1,5 +1,5 @@
 #include <cctype>
-#include <string>
+#include <stdexcept>
 #include "PPMParser.hpp"
 
 namespace MC::GFX::Image {
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;
+};
+
+}
diff --git a/src/main.cpp b/src/main.cpp
index 3a8b55d..960112e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,7 +1,6 @@
 #include <iostream>
 #include <GL/glew.h>
 #include <GLFW/glfw3.h>
-#include <cstdint>
 
 #include "GFX/Window.hpp"
 #include "GFX/Camera.hpp"
@@ -10,7 +9,7 @@
 #include "GFX/Shading/Program.hpp"
 #include "GFX/Texture.hpp"
 #include "GFX/Image/PPMParser.hpp"
-#include "World/Generator.hpp"
+#include "World/World.hpp"
 
 #define APP_NAME "Meowcraft"
 
@@ -18,7 +17,7 @@
 #define WINDOW_HEIGHT 800
 #define ASPECT static_cast<float>(WINDOW_WIDTH) / WINDOW_HEIGHT
 
-#define FOV 45
+#define FOV 90
 
 void run();
 void render(MC::GFX::BindableMesh&, MC::GFX::Texture&);
@@ -53,11 +52,7 @@ void run() {
     auto image = MC::GFX::Image::PPMParser(MC::Assets::Images::atlas).parse();
     auto texture = MC::GFX::Texture(image);
 
-    MC::World::Generator generator;
-    auto chunk = generator.generate(0, 0);
-    auto chunk_mesh = chunk.mesh();
-
-    auto mesh = MC::GFX::Binder::load(chunk_mesh);
+    MC::World::World world;
 
     MC::GFX::Camera camera{};
     camera.set_position({0.0f, 0.0f, 3.0f});
@@ -72,7 +67,7 @@ void run() {
     auto projection_uniform = program.uniform("projection_matrix");
 
     program.bind();
-    auto projection = Math::MVP::projection(ASPECT, FOV, 0.1f, 100.0f);
+    auto projection = Math::MVP::projection(ASPECT, FOV, 0.1f, 1000.0f);
     projection_uniform.set(projection);
 
     glEnable(GL_DEPTH_TEST);
@@ -94,13 +89,14 @@ void run() {
 
         program.bind();
 
-        auto model = Math::MVP::model({}, {});
-        model_uniform.set(model);
-
         auto view = Math::MVP::view(camera.position(), camera.angles());
         view_uniform.set(view);
 
-        render(mesh, texture);
+        for (auto& chunk : world.get_visible_chunks(camera.position())) {
+            auto model = Math::MVP::model(chunk.chunk->position(), {});
+            model_uniform.set(model);
+            render(chunk.mesh.value(), texture);
+        }
         time++;
     }
 }
@@ -129,7 +125,7 @@ void process_input(MC::GFX::Window& window, MC::GFX::Camera& camera) {
     float y = key(GLFW_KEY_SPACE) - key(GLFW_KEY_LEFT_SHIFT);
     float z = key(GLFW_KEY_S) - key(GLFW_KEY_W);
 
-    auto move_speed = 0.05f;
+    auto move_speed = 0.5f;
     auto rotation_speed = 0.1f;
 
     camera.move_relative({x * move_speed, y * move_speed, z * move_speed});