summary refs log tree commit diff
path: root/src/World/Generation
diff options
context:
space:
mode:
Diffstat (limited to 'src/World/Generation')
-rw-r--r--src/World/Generation/Lighting.cpp54
-rw-r--r--src/World/Generation/Lighting.hpp30
2 files changed, 72 insertions, 12 deletions
diff --git a/src/World/Generation/Lighting.cpp b/src/World/Generation/Lighting.cpp
index 8df6e2a..39d8320 100644
--- a/src/World/Generation/Lighting.cpp
+++ b/src/World/Generation/Lighting.cpp
@@ -1,20 +1,60 @@
 #include "Lighting.hpp"
 
-namespace MC::World::Generation::Lighting {
+namespace MC::World::Generation {
 
-void light_chunk(Chunk& chunk, ChunkNeighbors& _) {
-    for (UInt x = 0; x < Chunk::Width; x++) {
-        for (UInt z = 0; z < Chunk::Width; z++) {
-            U8 current_light_exposure = LightSun;
-            for (UInt y = Chunk::Height - 1; y != 0; y--) {
+void Lighting::add_chunk(Chunk& chunk) {
+    for (U8 x = 0; x < Chunk::Width; x++) {
+        for (U8 z = 0; z < Chunk::Width; z++) {
+            U8 current_light_exposure = SunBrightness;
+            for (U8 y = Chunk::Height - 1; y != 0; y--) {
                 auto& block = chunk.at(x, y, z);
                 if (!block.type.is_translucent()) break;
 
                 current_light_exposure = (Real)current_light_exposure * (1 - block.type.opacity());
-                block.light = current_light_exposure;
+                add_block(chunk, {x, y, z}, current_light_exposure);
             }
         }
     }
 }
 
+void Lighting::add_block(Chunk& chunk, Position::BlockLocal position, U8 light) {
+    auto& block = chunk.at(position);
+    block.light = light;
+    enqueue(chunk.index(), position, light);
+}
+
+void Lighting::illuminate(ChunkRegistry& chunks) {
+    while (!m_queue.empty()) {
+        auto op = m_queue.front();
+        m_queue.pop();
+
+        process(chunks, op);
+    }
+}
+
+void Lighting::enqueue(ChunkIndex chunk, Position::BlockLocal position, U8 origin) {
+    m_queue.push({chunk, position, origin});
+}
+
+void Lighting::process(ChunkRegistry& chunks, Operation op) {
+    auto& chunk_data = chunks.get(op.chunk);
+    auto& chunk = chunk_data.chunk.value();
+
+    for (auto direction : Position::axis_directions) {
+        auto neighbor_pos = op.position.offset(direction);
+        if (!neighbor_pos.fits_within_chunk()) continue;
+
+        auto& neighbor = chunk.at(neighbor_pos);
+        if (!neighbor.type.is_translucent()) continue;
+
+        U8 falloff = (neighbor.type.opacity() + 1) * DefaultFalloff;
+        U8 target = std::max(op.origin - falloff, 0);
+
+        if (neighbor.light < target) {
+            neighbor.light = target;
+            enqueue(op.chunk, neighbor_pos, target);
+        }
+    }
+}
+
 }
diff --git a/src/World/Generation/Lighting.hpp b/src/World/Generation/Lighting.hpp
index 7bb8fcc..72af0e1 100644
--- a/src/World/Generation/Lighting.hpp
+++ b/src/World/Generation/Lighting.hpp
@@ -1,13 +1,33 @@
 #pragma once
 
+#include <queue>
 #include "../Chunk.hpp"
-#include "ChunkNeighbors.hpp"
+#include "../ChunkIndex.hpp"
+#include "../ChunkRegistry.hpp"
+#include "../Position.hpp"
 
-namespace MC::World::Generation::Lighting {
+namespace MC::World::Generation {
 
-constexpr U8 LightSun = 200;
-constexpr U8 LightTorch = 100;
+class Lighting {
+public:
+    void add_chunk(Chunk& chunk);
+    void add_block(Chunk& chunk, Position::BlockLocal position, U8 light);
 
-void light_chunk(Chunk& chunk, ChunkNeighbors& neighbors);
+    void illuminate(ChunkRegistry& chunks);
+private:
+    static constexpr U8 SunBrightness = 200;
+    static constexpr U8 DefaultFalloff = 10;
+
+    struct Operation {
+        ChunkIndex chunk;
+        Position::BlockLocal position;
+        U8 origin;
+    };
+
+    void enqueue(ChunkIndex chunk, Position::BlockLocal position, U8 origin);
+    void process(ChunkRegistry& chunks, Operation op);
+
+    std::queue<Operation> m_queue;
+};
 
 }