summary refs log tree commit diff
path: root/src/World/World.cpp
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2023-07-29 03:31:42 +0200
committerMel <einebeere@gmail.com>2023-07-29 03:31:42 +0200
commit6b69d4b5b648253f894707723af0e2eae9f71445 (patch)
tree0cd0b6c7b18c30abbb2618f553f144d1d06dacba /src/World/World.cpp
parent2eef7cf49b7a15559ee7bb6719411bcf67386213 (diff)
downloadmeowcraft-6b69d4b5b648253f894707723af0e2eae9f71445.tar.zst
meowcraft-6b69d4b5b648253f894707723af0e2eae9f71445.zip
Move chunk reification to worker threads and set stage for chunk-unbound lighting
Diffstat (limited to 'src/World/World.cpp')
-rw-r--r--src/World/World.cpp103
1 files changed, 55 insertions, 48 deletions
diff --git a/src/World/World.cpp b/src/World/World.cpp
index 5548866..3d273bd 100644
--- a/src/World/World.cpp
+++ b/src/World/World.cpp
@@ -5,8 +5,8 @@
 
 namespace MC::World {
 
-std::vector<ChunkRegistry::Data*> World::get_visible_chunks(Vector<3> position) {
-    load_finished_chunks_from_queue();
+std::vector<ChunkRegistry::Data*> World::get_visible_chunks(Position::World position) {
+    process_chunk_updates();
 
     auto visible_chunks = get_visible_chunk_indices(position);
 
@@ -14,24 +14,30 @@ std::vector<ChunkRegistry::Data*> World::get_visible_chunks(Vector<3> position)
     chunks.reserve(visible_chunks.size());
     for (auto index : visible_chunks) {
         auto& data = m_registry.get(index);
-        if (data.status == ChunkRegistry::Status::Empty) {
-            request_generation(index, position.distance(index.middle()));
+
+        if (data.get_status() == ChunkRegistry::Status::Empty) {
+            request_generation(index, calculate_priority(index, position, RequestType::Initial));
             data.status = ChunkRegistry::Status::WaitingForGeneration;
             continue;
         }
 
-        if (data.status == ChunkRegistry::Status::WaitingForReification) {
-            try_to_reify_chunk(data);
-        }
-        if (data.status == ChunkRegistry::Status::Done) {
-            chunks.push_back(&data);
+        if (data.get_status() == ChunkRegistry::Status::NeedsReification || data.get_status() == ChunkRegistry::Status::Damaged) {
+            auto do_all_exist = Generation::find_chunk_neighbors(index, m_registry).all_exist();
+            if (m_reification_queue.size() <= 50 && do_all_exist) {
+                auto request_type = data.get_status() == ChunkRegistry::Status::Damaged ? RequestType::Update : RequestType::Initial;
+                request_reification(index, calculate_priority(index, position, request_type));
+                data.status = ChunkRegistry::Status::WaitingForReification;
+            }
         }
+
+        // TODO: Use a better indicator than `land_mesh.has_value()`.
+        if (data.land_mesh.has_value()) chunks.push_back(&data);
     }
 
     return chunks;
 }
 
-std::vector<ChunkIndex> World::get_visible_chunk_indices(const Vector<3> position) const {
+std::vector<ChunkIndex> World::get_visible_chunk_indices(const Position::World position) const {
     I32 center_x = std::round(position.x() / Chunk::Width);
     I32 center_y = std::round(position.z() / Chunk::Width);
 
@@ -53,61 +59,62 @@ std::vector<ChunkIndex> World::get_visible_chunk_indices(const Vector<3> positio
     return indices;
 }
 
-void World::load_finished_chunks_from_queue() {
-    auto results = m_queue.done();
-    for (auto& [id, res] : results) {
-        m_registry.get(id) = {id, ChunkRegistry::Status::WaitingForReification, {res.chunk}};
+void World::process_chunk_updates() {
+    auto generation_results = m_generation_queue.done();
+    for (auto& [id, res] : generation_results) {
+        m_registry.get(id) = {id, ChunkRegistry::Status::NeedsReification, {res.chunk}};
+
         log_chunk_time(res.generation_duration);
     }
+
+    auto reification_results = m_reification_queue.done();
+    for (auto& [id, res] : reification_results) {
+        m_registry.get(id) = {
+            id, ChunkRegistry::Status::Done,
+            {res.chunk},
+            res.chunk_mesh.land_mesh,
+            res.chunk_mesh.water_mesh
+        };
+
+        // TODO: Damage surrounding chunks.
+    }
 }
 
 void World::request_generation(ChunkIndex index, Real priority) {
-    m_queue.add(index, priority, [=]() -> GenerationResult {
+    m_generation_queue.add(index, priority, [=]() -> GenerationResult {
         auto start = Time::now();
         auto chunk = m_generator.generate(index.x, index.y);
         return {chunk, Time::now() - start};
     });
 }
 
-void World::try_to_reify_chunk(ChunkRegistry::Data& data) {
-    auto index = data.index;
+void World::request_reification(ChunkIndex index, Real priority) {
+    auto& data = m_registry.get(index);
     auto& chunk = data.chunk.value();
 
-    UInt neighbor_index = 0;
-    std::array<Chunk*, 8> neighbors;
-    for (I32 x = -1; x <= 1; x++) {
-        for (I32 y = -1; y <= 1; y++) {
-            if (x == 0 && y == 0) continue;
+    auto neighbors = Generation::find_chunk_neighbors(index, m_registry);
+    auto meshing_context = Generation::ChunkMeshing::create_meshing_context(data.chunk.value(), neighbors);
+    m_reification_queue.add(index, priority, [=]() mutable -> ReificationResult {
+        Generation::Lighting intitial_lighting{};
+        intitial_lighting.add_chunk(chunk);
+        intitial_lighting.illuminate(chunk);
 
-            auto& neighbor_data = m_registry.get({index.x + x, index.y + y});
-            if (!neighbor_data.chunk.has_value()) return; // All neighbors need to be generated first.
-
-            neighbors[neighbor_index++] = &neighbor_data.chunk.value();
-        }
-    }
-
-    // Layout of neighboring chunks in `neighbors` array:
-    // (-1; -1) > (-1;  0) > (-1; 1) > (0; -1)
-    // ( 0;  1) > ( 1; -1) > ( 1; 0) > (1;  1)
-    Generation::ChunkNeighbors chunk_neighbors {
-        neighbors[3], neighbors[6], neighbors[4], neighbors[1],
-        neighbors[5], neighbors[7], neighbors[2], neighbors[0],
-    };
-
-    // Lighting
-    m_lighting.add_chunk(chunk);
-    m_lighting.illuminate(m_registry);
-
-    // Meshing
-    auto meshes = Generation::ChunkMeshing::mesh_chunk(chunk, chunk_neighbors);
+        auto meshes = Generation::ChunkMeshing::mesh_chunk(chunk, meshing_context);
+        return {chunk, meshes};
+    });
+}
 
-    data.land_mesh_data = meshes.land_mesh;
-    data.land_mesh = GFX::Binder::load(data.land_mesh_data.value());
+Real World::calculate_priority(ChunkIndex chunk, Position::World player_position, RequestType request_type) {
+    auto chunk_position = chunk.middle();
+    auto flat_distance = Position::World{player_position.x(), chunk_position.y(), player_position.z()}.distance(chunk_position);
 
-    data.water_mesh_data = meshes.water_mesh;
-    data.water_mesh = GFX::Binder::load(data.water_mesh_data.value());
+    Real request_type_penalty;
+    switch (request_type) {
+    case RequestType::Initial: request_type_penalty = 0; break;
+    case RequestType::Update: request_type_penalty = 500; break;
+    }
 
-    data.status = ChunkRegistry::Status::Done;
+    return flat_distance + request_type_penalty;
 }
 
 void World::log_chunk_time(U64 chunk_time_ms) {