diff options
| author | Mel <einebeere@gmail.com> | 2023-07-29 03:31:42 +0200 |
|---|---|---|
| committer | Mel <einebeere@gmail.com> | 2023-07-29 03:31:42 +0200 |
| commit | 6b69d4b5b648253f894707723af0e2eae9f71445 (patch) | |
| tree | 0cd0b6c7b18c30abbb2618f553f144d1d06dacba /src/World/World.cpp | |
| parent | 2eef7cf49b7a15559ee7bb6719411bcf67386213 (diff) | |
| download | meowcraft-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.cpp | 103 |
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) { |
