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/ChunkRegistry.hpp4
-rw-r--r--src/World/VoxelTraversal.hpp60
-rw-r--r--src/World/World.cpp11
-rw-r--r--src/World/World.hpp12
4 files changed, 86 insertions, 1 deletions
diff --git a/src/World/ChunkRegistry.hpp b/src/World/ChunkRegistry.hpp
index ea887e4..2b87a3a 100644
--- a/src/World/ChunkRegistry.hpp
+++ b/src/World/ChunkRegistry.hpp
@@ -34,7 +34,9 @@ public:
         }
 
         void damage() {
-            if (status == Status::Done) chunk.value().damage();
+            // if (status == Status::Done) chunk.value().damage();
+            // TODO: Properly damage the chunk, notifying the nearby chunks, too.
+            status = Status::NeedsReification;
         }
     };
 
diff --git a/src/World/VoxelTraversal.hpp b/src/World/VoxelTraversal.hpp
new file mode 100644
index 0000000..1638901
--- /dev/null
+++ b/src/World/VoxelTraversal.hpp
@@ -0,0 +1,60 @@
+#pragma once
+
+#include "../Common/Casts.hpp"
+#include "../Math/Ray.hpp"
+#include "Position.hpp"
+
+namespace MC::World::VoxelTraversal {
+
+// Amanatides, John, and Andrew Woo. 1987.
+// "A Fast Voxel Traversal Algorithm for Ray Tracing."
+// https://doi.org/10.2312/EGTP.19871000.
+template <typename P>
+Position::BlockWorld traverse(Ray ray, Real max_distance, P&& predicate) {
+    // Find the voxel grid cell containing the origin of the ray.
+    Position::BlockWorld block_pos = Position::World(ray.origin).round_to_block();
+    Position::BlockWorldOffset const step = {
+        Math::sign(ray.direction.x()),
+        Math::sign(ray.direction.y()),
+        Math::sign(ray.direction.z()),
+    };
+
+    Position::WorldOffset t_max = {
+        (TO(Real, block_pos.x()) + TO(Real, step.x() > 0) - ray.origin.x()) / ray.direction.x(),
+        (TO(Real, block_pos.y()) + TO(Real, step.y() > 0) - ray.origin.y()) / ray.direction.y(),
+        (TO(Real, block_pos.z()) + TO(Real, step.z() > 0) - ray.origin.z()) / ray.direction.z()
+    };
+
+    Position::WorldOffset const t_delta = {
+        TO(Real, step.x()) / ray.direction.x(),
+        TO(Real, step.y()) / ray.direction.y(),
+        TO(Real, step.z()) / ray.direction.z()
+    };
+
+    while (!predicate(block_pos)) {
+        // TODO: Calculate distance exactly.
+        if (ray.origin.distance(Vec3(block_pos)) > max_distance) return {};
+
+        if (t_max.x() < t_max.y()) {
+            if (t_max.x() < t_max.z()) {
+                block_pos.x() += step.x();
+                t_max.x() += t_delta.x();
+            } else {
+                block_pos.z() += step.z();
+                t_max.z() += t_delta.z();
+            }
+        } else {
+            if (t_max.y() < t_max.z()) {
+                block_pos.y() += step.y();
+                t_max.y() += t_delta.y();
+            } else {
+                block_pos.z() += step.z();
+                t_max.z() += t_delta.z();
+            }
+        }
+    }
+
+    return block_pos;
+}
+
+}
diff --git a/src/World/World.cpp b/src/World/World.cpp
index ce15ae8..cc5d91f 100644
--- a/src/World/World.cpp
+++ b/src/World/World.cpp
@@ -47,6 +47,17 @@ Chunk::BlockData World::block_at(Position::BlockWorld pos) {
     return {};
 }
 
+void World::break_block(Position::BlockWorld pos) {
+    auto& chunk_data = m_registry.find(pos);
+    if (!chunk_data.chunk.has_value()) return;
+
+    auto& block_data = chunk_data.chunk->at(pos.to_local());
+    if (!block_data.type.is_solid()) return;
+
+    block_data.type = {};
+    chunk_data.damage();
+}
+
 std::vector<ChunkIndex> World::get_visible_chunk_indices(const Position::World position) const {
     ChunkIndex center = ChunkIndex::from_position(position.round_to_block());
 
diff --git a/src/World/World.hpp b/src/World/World.hpp
index 3dbd720..af49378 100644
--- a/src/World/World.hpp
+++ b/src/World/World.hpp
@@ -4,8 +4,10 @@
 #include "ChunkIndex.hpp"
 #include "ChunkRegistry.hpp"
 #include "../Compute/Queue.hpp"
+#include "../Math/Ray.hpp"
 #include "Generation/ChunkMeshing.hpp"
 #include "Generation/Lighting.hpp"
+#include "VoxelTraversal.hpp"
 
 namespace MC::World {
 
@@ -14,6 +16,16 @@ public:
     std::vector<ChunkRegistry::Data*> get_visible_chunks(Position::World position);
 
     Chunk::BlockData block_at(Position::BlockWorld pos);
+    void break_block(Position::BlockWorld pos);
+
+    template <typename F>
+    Position::BlockWorld traverse(Ray ray, Real max_distance, F&& predicate) {
+        return VoxelTraversal::traverse(
+            ray,
+            max_distance,
+            [this, &predicate](Position::BlockWorld pos) { return predicate(block_at(pos)); }
+        );
+    }
 
     Real get_average_chunk_time() const;