From 9d200f31beba8fbf0986847191a80b8cda5716c5 Mon Sep 17 00:00:00 2001 From: zhenyan121 <104683324+zhenyan121@users.noreply.github.com> Date: Sun, 3 May 2026 16:02:01 +0800 Subject: [PATCH] refactor: chunk interpolate (#6) * refactor: rewrite blend_heightmap_boundaries * refactor: init_world * fix: unnatural biome boundary transition --- CMakeLists.txt | 4 +- include/Cubed/constants.hpp | 13 +- include/Cubed/dev_panel.hpp | 1 + include/Cubed/gameplay/biome.hpp | 8 +- .../Cubed/gameplay/builders/biome_builder.hpp | 1 + include/Cubed/gameplay/chunk.hpp | 10 +- include/Cubed/gameplay/chunk_generator.hpp | 15 +- include/Cubed/gameplay/world.hpp | 11 +- src/dev_panel.cpp | 8 + src/gameplay/builders/biome_builder.cpp | 27 +- src/gameplay/builders/desert_builder.cpp | 23 +- src/gameplay/builders/forest_builder.cpp | 19 +- src/gameplay/builders/mountain_builder.cpp | 27 +- src/gameplay/builders/plain_builder.cpp | 23 +- src/gameplay/builders/river_builder.cpp | 4 +- src/gameplay/chunk.cpp | 31 +- src/gameplay/chunk_generator.cpp | 334 +++++++++++++----- src/gameplay/tree.cpp | 4 +- src/gameplay/world.cpp | 309 ++++++++++------ 19 files changed, 553 insertions(+), 319 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index faa26af..0b7ab7d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,14 +123,14 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug") message(STATUS "Building with AddressSanitizer enabled for target: ${PROJECT_NAME}") target_compile_options(${PROJECT_NAME} PRIVATE - -fsanitize=address + #-fsanitize=address #-fsanitize=thread -fno-omit-frame-pointer -g ) target_link_options(${PROJECT_NAME} PRIVATE - -fsanitize=address + #-fsanitize=address #-fsanitize=thread ) diff --git a/include/Cubed/constants.hpp b/include/Cubed/constants.hpp index 60f32ce..324f66d 100644 --- a/include/Cubed/constants.hpp +++ b/include/Cubed/constants.hpp @@ -1,9 +1,11 @@ #pragma once +#include "Cubed/gameplay/chunk_pos.hpp" + #include namespace Cubed { constexpr int WORLD_SIZE_Y = 256; -constexpr int CHUCK_SIZE = 16; +constexpr int CHUNK_SIZE = 16; constexpr int SEA_LEVEL = 64; constexpr int MAX_BLOCK_NUM = 8; @@ -22,10 +24,13 @@ constexpr float DEFAULT_MAX_RUN_SPEED = 7.0f; constexpr float DEFAULT_ACCELERATION = 10.0f; constexpr float DEFAULT_DECELERATION = 15.0f; constexpr float DEFAULT_G = 22.5f; -static constexpr int SIZE_X = CHUCK_SIZE; +static constexpr int SIZE_X = CHUNK_SIZE; static constexpr int SIZE_Y = WORLD_SIZE_Y; -static constexpr int SIZE_Z = CHUCK_SIZE; +static constexpr int SIZE_Z = CHUNK_SIZE; -using HeightMapArray = std::array, CHUCK_SIZE>; +constexpr ChunkPos CHUNK_DIR[]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}, + {1, 1}, {-1, 1}, {1, -1}, {-1, -1}}; + +using HeightMapArray = std::array, CHUNK_SIZE>; } // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/dev_panel.hpp b/include/Cubed/dev_panel.hpp index 7168d64..6e0f56e 100644 --- a/include/Cubed/dev_panel.hpp +++ b/include/Cubed/dev_panel.hpp @@ -42,6 +42,7 @@ private: PlayerProfile m_player_profile; TextEditing m_text_editing; bool m_need_save_config = false; + bool m_gen_thread_running = true; int m_theme = 0; void show_about_table_bar(); void show_biome_table_bar(); diff --git a/include/Cubed/gameplay/biome.hpp b/include/Cubed/gameplay/biome.hpp index 100d6d8..604ba94 100644 --- a/include/Cubed/gameplay/biome.hpp +++ b/include/Cubed/gameplay/biome.hpp @@ -23,12 +23,8 @@ struct BiomeNonAdjacent { static inline const std::vector NON_ADJACENT{ {{BiomeType::PLAIN, {BiomeType::DESERT}, BiomeType::RIVER}, {BiomeType::FOREST, {BiomeType::DESERT}, BiomeType::RIVER}, - {BiomeType::DESERT, - {BiomeType::MOUNTAIN, BiomeType::FOREST}, - BiomeType::RIVER}, - {BiomeType::MOUNTAIN, - {BiomeType::DESERT, BiomeType::FOREST}, - BiomeType::RIVER}}}; + {BiomeType::DESERT, {BiomeType::FOREST}, BiomeType::RIVER}, + {BiomeType::MOUNTAIN, {BiomeType::NONE}, BiomeType::RIVER}}}; struct BaseBiomeParams { BiomeType biome; diff --git a/include/Cubed/gameplay/builders/biome_builder.hpp b/include/Cubed/gameplay/builders/biome_builder.hpp index 694572f..7df2309 100644 --- a/include/Cubed/gameplay/builders/biome_builder.hpp +++ b/include/Cubed/gameplay/builders/biome_builder.hpp @@ -12,5 +12,6 @@ public: protected: void build_bottom(); + void fill_water(); }; } // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/gameplay/chunk.hpp b/include/Cubed/gameplay/chunk.hpp index 4a39aee..9bd93d0 100644 --- a/include/Cubed/gameplay/chunk.hpp +++ b/include/Cubed/gameplay/chunk.hpp @@ -15,11 +15,10 @@ class World; // if want to use, do init_chunk(), gen_vertex_data() and class Chunk { private: - static constexpr int SIZE_X = CHUCK_SIZE; + static constexpr int SIZE_X = CHUNK_SIZE; static constexpr int SIZE_Y = WORLD_SIZE_Y; - static constexpr int SIZE_Z = CHUCK_SIZE; + static constexpr int SIZE_Z = CHUNK_SIZE; - using HeightMapArray = std::array, SIZE_X>; std::atomic m_dirty{false}; std::atomic m_need_upload{true}; std::atomic m_is_on_gen_vertex_data{false}; @@ -60,12 +59,13 @@ public: // Determine biome from temperature and humidity noise void gen_phase_one(); // Resolve biome adjacency conflicts with neighbor chunks - void gen_phase_two(const std::array& adj_chunks); + void gen_phase_two(const std::array& adj_chunks); // Generate heightmap using biome-specific noise void gen_phase_three(); // Blend heightmap with neighbors for smooth transitions void gen_phase_four( - const std::array, 4>& neighbor_heightmap); + const std::array, 8>& neighbor_heightmap, + const std::array& neighbor_biome); // Generate terrain blocks from heightmap and biome void gen_phase_five(); // Blend surface blocks at chunk borders with neighbors diff --git a/include/Cubed/gameplay/chunk_generator.hpp b/include/Cubed/gameplay/chunk_generator.hpp index c9f33c1..0cfc93d 100644 --- a/include/Cubed/gameplay/chunk_generator.hpp +++ b/include/Cubed/gameplay/chunk_generator.hpp @@ -25,12 +25,13 @@ public: void assign_chunk_biome(); // Adjust Biome void resolve_biome_adjacency_conflict( - const std::array& adj_chunks); + const std::array& adj_chunks); // Generate Heightmap void generate_heightmap(); // Adjust Height void blend_heightmap_boundaries( - const std::array, 4>& neighbor_heightmap); + const std::array, 8>& neighbor_heightmap, + const std::array& neighbor_biome); // Generate Block void generate_terrain_blocks(); // Adjust Block; @@ -39,10 +40,10 @@ public: neighbor_block); // Generate Structure void generate_vegetation(); - + BiomeType get_biome_at(float world_x, float world_z); Chunk& chunk(); Random& random(); - bool neighbor_river() const; + const std::array& neighbor_biome() const; private: static inline std::atomic is_init{false}; @@ -50,11 +51,9 @@ private: static inline std::atomic is_seed_change{false}; Chunk& m_chunk; Random m_random; - std::array neighbor_biome{BiomeType::NONE, BiomeType::NONE, - BiomeType::NONE, BiomeType::NONE}; std::unique_ptr m_biome_builder{nullptr}; - bool is_neighbor_river = false; - + bool is_cur_chunk_ins = false; + std::array m_neighbor_biome; void make_biome_builder(); }; diff --git a/include/Cubed/gameplay/world.hpp b/include/Cubed/gameplay/world.hpp index 5fef3e0..b338389 100644 --- a/include/Cubed/gameplay/world.hpp +++ b/include/Cubed/gameplay/world.hpp @@ -28,9 +28,9 @@ private: using ConstChunkMap = std::unordered_map; using ChunkPosSet = std::unordered_set; - + using ChunkHashMap = std::unordered_map; glm::vec3 m_gen_player_pos{0.0f, 0.0f, 0.0f}; - std::unordered_map m_chunks; + ChunkHashMap m_chunks; std::unordered_map m_players; std::vector m_planes; @@ -63,11 +63,10 @@ private: void build_neighbor_context_for_new_chunks(ConstChunkMap& new_chunks_neighbor, ChunkPtrUpdateList& affected_neighbor, - const ChunkUpdateList& new_chunks); + const ChunkUpdateList& new_chunks, + ChunkHashMap& temp_neighbor); void build_neighbor_context_for_affected_neighbors(ChunkPtrUpdateList&, ConstChunkMap&); - void start_gen_thread(); - void stop_gen_thread(); public: World(); @@ -105,6 +104,8 @@ public: float chunk_gen_fraction() const; int rendering_distance() const; void rendering_distance(int rendering_distance); + void start_gen_thread(); + void stop_gen_thread(); }; } // namespace Cubed diff --git a/src/dev_panel.cpp b/src/dev_panel.cpp index 44d4d41..ed6283b 100644 --- a/src/dev_panel.cpp +++ b/src/dev_panel.cpp @@ -387,6 +387,14 @@ void DevPanel::show_world_tab_item() { if (ImGui::Button("Spawn Point")) { m_player->set_player_pos({0.0f, 255.0f, 0.0f}); } + ImGui::SameLine(); + if (ImGui::Checkbox("Gen Thread", &m_gen_thread_running)) { + if (m_gen_thread_running) { + m_app.world().start_gen_thread(); + } else { + m_app.world().stop_gen_thread(); + } + } ImGui::Text("Chunk Build Progress\n"); ImGui::ProgressBar(m_app.world().chunk_gen_fraction()); show_biome_table_bar(); diff --git a/src/gameplay/builders/biome_builder.cpp b/src/gameplay/builders/biome_builder.cpp index 3314569..e9772ea 100644 --- a/src/gameplay/builders/biome_builder.cpp +++ b/src/gameplay/builders/biome_builder.cpp @@ -7,12 +7,35 @@ void BiomeBuilder::build_bottom() { ChunkGenerator& chunk_generator = get_chunk_generator(); Chunk& chunk = chunk_generator.chunk(); auto& m_blocks = chunk.blocks(); - for (int x = 0; x < CHUCK_SIZE; x++) { + for (int x = 0; x < CHUNK_SIZE; x++) { for (int y = 0; y < 5; y++) { - for (int z = 0; z < CHUCK_SIZE; z++) { + for (int z = 0; z < CHUNK_SIZE; z++) { m_blocks[Chunk::get_index(x, y, z)] = 3; } } } } +void BiomeBuilder::fill_water() { + ChunkGenerator& chunk_generator = get_chunk_generator(); + Chunk& chunk = chunk_generator.chunk(); + auto& m_blocks = chunk.blocks(); + auto& neighbor = chunk_generator.neighbor_biome(); + auto& heightmap = chunk.heightmap(); + for (int i = 0; i < 8; i++) { + if (neighbor[i] == BiomeType::RIVER) { + for (int x = 0; x < SIZE_X; x++) { + for (int z = 0; z < SIZE_Z; z++) { + if (heightmap[x][z] >= SEA_LEVEL) { + continue; + } + int height = heightmap[x][z]; + for (int y = height; y < SEA_LEVEL; y++) { + m_blocks[Chunk::get_index(x, y, z)] = 7; + } + } + } + return; + } + } +} } // namespace Cubed \ No newline at end of file diff --git a/src/gameplay/builders/desert_builder.cpp b/src/gameplay/builders/desert_builder.cpp index bc1a511..bb33e9f 100644 --- a/src/gameplay/builders/desert_builder.cpp +++ b/src/gameplay/builders/desert_builder.cpp @@ -15,8 +15,8 @@ void DesertBuilder::build_blocks() { auto& m_chunk = m_chunk_generator.chunk(); auto& m_blocks = m_chunk.blocks(); auto& m_heightmap = m_chunk.heightmap(); - for (int x = 0; x < CHUCK_SIZE; x++) { - for (int z = 0; z < CHUCK_SIZE; z++) { + for (int x = 0; x < CHUNK_SIZE; x++) { + for (int z = 0; z < CHUNK_SIZE; z++) { int height = static_cast(m_heightmap[x][z]); for (int y = 5; y < height - 5; y++) { m_blocks[Chunk::get_index(x, y, z)] = 3; @@ -29,24 +29,7 @@ void DesertBuilder::build_blocks() { } } -void DesertBuilder::build_vegetation() { - auto& m_chunk = m_chunk_generator.chunk(); - auto& m_blocks = m_chunk.blocks(); - auto& m_heightmap = m_chunk.heightmap(); - if (m_chunk_generator.neighbor_river()) { - for (int x = 0; x < SIZE_X; x++) { - for (int z = 0; z < SIZE_Z; z++) { - int height = static_cast(m_heightmap[x][z]); - if (height >= SEA_LEVEL) { - continue; - } - for (int y = height + 1; y < SEA_LEVEL; y++) { - m_blocks[Chunk::get_index(x, y, z)] = 7; - } - } - } - } -} +void DesertBuilder::build_vegetation() { fill_water(); } ChunkGenerator& DesertBuilder::get_chunk_generator() { return m_chunk_generator; diff --git a/src/gameplay/builders/forest_builder.cpp b/src/gameplay/builders/forest_builder.cpp index 5cdf9a7..e5538ca 100644 --- a/src/gameplay/builders/forest_builder.cpp +++ b/src/gameplay/builders/forest_builder.cpp @@ -16,8 +16,8 @@ void ForestBuilder::build_blocks() { auto& m_chunk = m_chunk_generator.chunk(); auto& m_blocks = m_chunk.blocks(); auto& m_heightmap = m_chunk.heightmap(); - for (int x = 0; x < CHUCK_SIZE; x++) { - for (int z = 0; z < CHUCK_SIZE; z++) { + for (int x = 0; x < CHUNK_SIZE; x++) { + for (int z = 0; z < CHUNK_SIZE; z++) { int height = static_cast(m_heightmap[x][z]); for (int y = 5; y < height - 5; y++) { m_blocks[Chunk::get_index(x, y, z)] = 3; @@ -49,20 +49,7 @@ void ForestBuilder::build_vegetation() { } } } - auto& m_blocks = m_chunk.blocks(); - if (m_chunk_generator.neighbor_river()) { - for (int x = 0; x < SIZE_X; x++) { - for (int z = 0; z < SIZE_Z; z++) { - int height = static_cast(m_heightmap[x][z]); - if (height >= SEA_LEVEL) { - continue; - } - for (int y = height + 1; y < SEA_LEVEL; y++) { - m_blocks[Chunk::get_index(x, y, z)] = 7; - } - } - } - } + fill_water(); } ChunkGenerator& ForestBuilder::get_chunk_generator() { diff --git a/src/gameplay/builders/mountain_builder.cpp b/src/gameplay/builders/mountain_builder.cpp index 68ba103..22f06b0 100644 --- a/src/gameplay/builders/mountain_builder.cpp +++ b/src/gameplay/builders/mountain_builder.cpp @@ -15,8 +15,8 @@ void MountainBuilder::build_blocks() { auto& m_chunk = m_chunk_generator.chunk(); auto& m_blocks = m_chunk.blocks(); auto& m_heightmap = m_chunk.heightmap(); - for (int x = 0; x < CHUCK_SIZE; x++) { - for (int z = 0; z < CHUCK_SIZE; z++) { + for (int x = 0; x < CHUNK_SIZE; x++) { + for (int z = 0; z < CHUNK_SIZE; z++) { int height = static_cast(m_heightmap[x][z]); for (int y = 5; y < height - 5; y++) { m_blocks[Chunk::get_index(x, y, z)] = 3; @@ -29,32 +29,15 @@ void MountainBuilder::build_blocks() { } } if (height > 110) { - m_blocks[Chunk::get_index(x, height - 1, z)] = 3; + m_blocks[Chunk::get_index(x, height, z)] = 3; } else { - m_blocks[Chunk::get_index(x, height - 1, z)] = 1; + m_blocks[Chunk::get_index(x, height, z)] = 1; } } } } -void MountainBuilder::build_vegetation() { - auto& m_chunk = m_chunk_generator.chunk(); - auto& m_blocks = m_chunk.blocks(); - auto& m_heightmap = m_chunk.heightmap(); - if (m_chunk_generator.neighbor_river()) { - for (int x = 0; x < SIZE_X; x++) { - for (int z = 0; z < SIZE_Z; z++) { - int height = static_cast(m_heightmap[x][z]); - if (height >= SEA_LEVEL) { - continue; - } - for (int y = height + 1; y < SEA_LEVEL; y++) { - m_blocks[Chunk::get_index(x, y, z)] = 7; - } - } - } - } -} +void MountainBuilder::build_vegetation() { fill_water(); } ChunkGenerator& MountainBuilder::get_chunk_generator() { return m_chunk_generator; diff --git a/src/gameplay/builders/plain_builder.cpp b/src/gameplay/builders/plain_builder.cpp index 147980d..4cc6186 100644 --- a/src/gameplay/builders/plain_builder.cpp +++ b/src/gameplay/builders/plain_builder.cpp @@ -15,8 +15,8 @@ void PlainBuilder::build_blocks() { auto& m_chunk = m_chunk_generator.chunk(); auto& m_blocks = m_chunk.blocks(); auto& m_heightmap = m_chunk.heightmap(); - for (int x = 0; x < CHUCK_SIZE; x++) { - for (int z = 0; z < CHUCK_SIZE; z++) { + for (int x = 0; x < CHUNK_SIZE; x++) { + for (int z = 0; z < CHUNK_SIZE; z++) { int height = static_cast(m_heightmap[x][z]); for (int y = 5; y < height - 5; y++) { m_blocks[Chunk::get_index(x, y, z)] = 3; @@ -29,24 +29,7 @@ void PlainBuilder::build_blocks() { } } -void PlainBuilder::build_vegetation() { - auto& m_chunk = m_chunk_generator.chunk(); - auto& m_blocks = m_chunk.blocks(); - auto& m_heightmap = m_chunk.heightmap(); - if (m_chunk_generator.neighbor_river()) { - for (int x = 0; x < SIZE_X; x++) { - for (int z = 0; z < SIZE_Z; z++) { - int height = static_cast(m_heightmap[x][z]); - if (height >= SEA_LEVEL) { - continue; - } - for (int y = height + 1; y < SEA_LEVEL; y++) { - m_blocks[Chunk::get_index(x, y, z)] = 7; - } - } - } - } -} +void PlainBuilder::build_vegetation() { fill_water(); } ChunkGenerator& PlainBuilder::get_chunk_generator() { return m_chunk_generator; diff --git a/src/gameplay/builders/river_builder.cpp b/src/gameplay/builders/river_builder.cpp index 15b92d4..9d9a807 100644 --- a/src/gameplay/builders/river_builder.cpp +++ b/src/gameplay/builders/river_builder.cpp @@ -15,8 +15,8 @@ void RiverBuilder::build_blocks() { auto& m_chunk = m_chunk_generator.chunk(); auto& m_blocks = m_chunk.blocks(); auto& m_heightmap = m_chunk.heightmap(); - for (int x = 0; x < CHUCK_SIZE; x++) { - for (int z = 0; z < CHUCK_SIZE; z++) { + for (int x = 0; x < CHUNK_SIZE; x++) { + for (int z = 0; z < CHUNK_SIZE; z++) { int height = static_cast(m_heightmap[x][z]); for (int y = 5; y < height - 5; y++) { m_blocks[Chunk::get_index(x, y, z)] = 3; diff --git a/src/gameplay/chunk.cpp b/src/gameplay/chunk.cpp index 8da69d9..0fdfd0d 100644 --- a/src/gameplay/chunk.cpp +++ b/src/gameplay/chunk.cpp @@ -59,15 +59,15 @@ HeightMapArray Chunk::get_heightmap() const { } int Chunk::get_index(int x, int y, int z) { - ASSERT(!(x < 0 || y < 0 || z < 0 || x >= CHUCK_SIZE || y >= WORLD_SIZE_Y || - z >= CHUCK_SIZE)); - if ((x * WORLD_SIZE_Y + y) * CHUCK_SIZE + z < 0 || - (x * WORLD_SIZE_Y + y) * CHUCK_SIZE + z >= - CHUCK_SIZE * CHUCK_SIZE * WORLD_SIZE_Y) { + ASSERT(!(x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_SIZE_Y || + z >= CHUNK_SIZE)); + if ((x * WORLD_SIZE_Y + y) * CHUNK_SIZE + z < 0 || + (x * WORLD_SIZE_Y + y) * CHUNK_SIZE + z >= + CHUNK_SIZE * CHUNK_SIZE * WORLD_SIZE_Y) { Logger::error("block pos x {} y {} z {} range error", x, y, z); ASSERT(0); } - return (x * WORLD_SIZE_Y + y) * CHUCK_SIZE + z; + return (x * WORLD_SIZE_Y + y) * CHUNK_SIZE + z; } int Chunk::get_index(const glm::vec3& pos) { @@ -89,8 +89,8 @@ void Chunk::gen_vertex_data( for (int x = 0; x < SIZE_X; x++) { for (int y = 0; y < SIZE_Y; y++) { for (int z = 0; z < SIZE_Z; z++) { - int world_x = x + m_chunk_pos.x * CHUCK_SIZE; - int world_z = z + m_chunk_pos.z * CHUCK_SIZE; + int world_x = x + m_chunk_pos.x * CHUNK_SIZE; + int world_z = z + m_chunk_pos.z * CHUNK_SIZE; int world_y = y; int cur_id = m_blocks[get_index(x, y, z)]; // air @@ -121,11 +121,11 @@ void Chunk::gen_vertex_data( } int x, y, z; y = world_ny; - x = world_nx - neighbor_x * CHUCK_SIZE; - z = world_nz - neighbor_z * CHUCK_SIZE; + x = world_nx - neighbor_x * CHUNK_SIZE; + z = world_nz - neighbor_z * CHUNK_SIZE; if (x < 0 || y < 0 || z < 0 || - x >= CHUCK_SIZE || y >= WORLD_SIZE_Y || - z >= CHUCK_SIZE) { + x >= CHUNK_SIZE || y >= WORLD_SIZE_Y || + z >= CHUNK_SIZE) { return false; } @@ -215,7 +215,7 @@ void Chunk::gen_phase_one() { m_generator->assign_chunk_biome(); } -void Chunk::gen_phase_two(const std::array& adj_chunks) { +void Chunk::gen_phase_two(const std::array& adj_chunks) { if (!m_generator) { Logger::error("ChunkGenerator is Nullptr"); return; @@ -232,12 +232,13 @@ void Chunk::gen_phase_three() { } void Chunk::gen_phase_four( - const std::array, 4>& neighbor_heightmap) { + const std::array, 8>& neighbor_heightmap, + const std::array& neighbor_biome) { if (!m_generator) { Logger::error("ChunkGenerator is Nullptr"); return; } - m_generator->blend_heightmap_boundaries(neighbor_heightmap); + m_generator->blend_heightmap_boundaries(neighbor_heightmap, neighbor_biome); } void Chunk::gen_phase_five() { diff --git a/src/gameplay/chunk_generator.cpp b/src/gameplay/chunk_generator.cpp index 2345f28..855207e 100644 --- a/src/gameplay/chunk_generator.cpp +++ b/src/gameplay/chunk_generator.cpp @@ -57,18 +57,14 @@ void ChunkGenerator::assign_chunk_biome() { } void ChunkGenerator::resolve_biome_adjacency_conflict( - const std::array& adj_chunks) { + const std::array& adj_chunks) { auto m_biome = m_chunk.biome(); - for (int i = 0; i < 4; i++) { + for (int i = 0; i < 8; i++) { auto& chunk = adj_chunks[i]; if (chunk == nullptr) { continue; } BiomeType biome = chunk->get_biome(); - neighbor_biome[i] = biome; - if (biome == BiomeType::RIVER) { - is_neighbor_river = true; - } for (const auto& non : NON_ADJACENT) { if (m_biome != non.first) { continue; @@ -90,13 +86,13 @@ void ChunkGenerator::generate_heightmap() { auto& m_heightmap = m_chunk.heightmap(); auto m_biome = m_chunk.biome(); - for (int x = 0; x < CHUCK_SIZE; x++) { - for (int z = 0; z < CHUCK_SIZE; z++) { + for (int x = 0; x < CHUNK_SIZE; x++) { + for (int z = 0; z < CHUNK_SIZE; z++) { - float world_x = static_cast(x + m_chunk_pos.x * CHUCK_SIZE); - float world_z = static_cast(z + m_chunk_pos.z * CHUCK_SIZE); + float world_x = static_cast(x + m_chunk_pos.x * CHUNK_SIZE); + float world_z = static_cast(z + m_chunk_pos.z * CHUNK_SIZE); - auto sample_height = [&](BiomeType b) -> float { + auto sample_height = [&](BiomeType b) -> int { auto range = get_biome_height_range(b); auto [f1, f2, f3] = get_noise_frequencies_for_biome(b); float n = 1.00f * PerlinNoise::noise(world_x * f1, 0.5f, @@ -106,7 +102,7 @@ void ChunkGenerator::generate_heightmap() { 0.25f * PerlinNoise::noise(world_x * f3, 0.5f, world_z * f3); n /= 1.75f; - return range.base_y + n * range.amplitude; + return range.base_y + std::round(n * range.amplitude); }; m_heightmap[x][z] = sample_height(m_biome); } @@ -114,79 +110,240 @@ void ChunkGenerator::generate_heightmap() { } void ChunkGenerator::blend_heightmap_boundaries( - const std::array, 4>& neighbor_heightmap) { + const std::array, 8>& neighbor_heightmap, + const std::array& neighbor_biome) { auto& m_heightmap = m_chunk.heightmap(); auto m_biome = m_chunk.biome(); - // Width of interpolation influence (in number of cells) + m_neighbor_biome = neighbor_biome; + // --- Right neighbor neighbor[0]: (1, 0) --- + for (int z = 0; z < SIZE_Z; z++) { + if (neighbor_heightmap[0] != std::nullopt && + neighbor_biome[0] != m_biome) { + is_cur_chunk_ins = true; + int edge_x = CHUNK_SIZE - 1; + int h = m_heightmap[edge_x][z]; + int neighbor_h = (*neighbor_heightmap[0])[0][z]; + if (h <= neighbor_h) { + continue; + } + const int DIR = (edge_x == 0) ? 1 : -1; + for (int i = 0; i < BLEND_RADIUS; i++) { + int x = edge_x + DIR * i; + float t = static_cast(i) / BLEND_RADIUS; + // float smooth_t = t * t * (3.0f - 2.0f * t); + float smooth_t = t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f); + m_heightmap[x][z] = static_cast( + std::round(neighbor_h + (h - neighbor_h) * smooth_t)); + } + } + } + // --- Left neighbor neighbor[1]: (-1, 0) --- + for (int z = 0; z < SIZE_Z; z++) { + if (neighbor_heightmap[1] != std::nullopt && + neighbor_biome[1] != m_biome) { + is_cur_chunk_ins = true; + int edge_x = 0; + int h = m_heightmap[edge_x][z]; + int neighbor_h = (*neighbor_heightmap[1])[CHUNK_SIZE - 1][z]; + if (h <= neighbor_h) { + continue; + } + + const int DIR = (edge_x == 0) ? 1 : -1; + for (int i = 0; i < BLEND_RADIUS; i++) { + int x = edge_x + DIR * i; + float t = static_cast(i) / BLEND_RADIUS; + + // float smooth_t = t * t * (3.0f - 2.0f * t); + float smooth_t = t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f); + m_heightmap[x][z] = static_cast( + std::round(neighbor_h + (h - neighbor_h) * smooth_t)); + } + } + } + // --- Front neighbor neighbor[2]: (0, 1) --- for (int x = 0; x < SIZE_X; x++) { - for (int z = 0; z < SIZE_Z; z++) { - float h = static_cast(m_heightmap[x][z]); - float total_weight = 1.0f; - float blended = h; + if (neighbor_heightmap[2] != std::nullopt && + neighbor_biome[2] != m_biome) { + is_cur_chunk_ins = true; + int edge_z = CHUNK_SIZE - 1; + int h = m_heightmap[x][edge_z]; + int neighbor_h = (*neighbor_heightmap[2])[x][0]; + if (h <= neighbor_h) { + continue; + } + const int DIR = (edge_z == 0) ? 1 : -1; + for (int i = 0; i < BLEND_RADIUS; i++) { + int z = edge_z + DIR * i; + float t = static_cast(i) / BLEND_RADIUS; - // --- Right neighbor neighbor[0]: (1, 0) --- - // Blend when x is close to SIZE_X-1 - if (neighbor_heightmap[0] != std::nullopt && - neighbor_biome[0] != m_biome) { - int dist = (SIZE_X - 1) - x; // distance from right border - if (dist < BLEND_RADIUS) { - // Neighbor's boundary row is its x=0 column - float neighbor_h = - static_cast((*neighbor_heightmap[0])[0][z]); - float t = - 1.0f - static_cast(dist) / - BLEND_RADIUS; // larger weight when closer - // Use smoothstep for a more natural transition - t = t * t * (3.0f - 2.0f * t); - blended += t * neighbor_h; - total_weight += t; - } + // float smooth_t = t * t * (3.0f - 2.0f * t); + float smooth_t = t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f); + m_heightmap[x][z] = static_cast( + std::round(neighbor_h + (h - neighbor_h) * smooth_t)); + } + } + } + + // --- Back neighbor neighbor[3]: (0, -1) --- + for (int x = 0; x < SIZE_X; x++) { + if (neighbor_heightmap[3] != std::nullopt && + neighbor_biome[3] != m_biome) { + is_cur_chunk_ins = true; + int edge_z = 0; + int h = m_heightmap[x][edge_z]; + int neighbor_h = (*neighbor_heightmap[3])[x][CHUNK_SIZE - 1]; + if (h <= neighbor_h) { + continue; } - // --- Left neighbor neighbor[1]: (-1, 0) --- - if (neighbor_heightmap[1] != std::nullopt && - neighbor_biome[1] != m_biome) { - int dist = x; // distance from left border - if (dist < BLEND_RADIUS) { - float neighbor_h = static_cast( - (*neighbor_heightmap[1])[SIZE_X - 1][z]); - float t = 1.0f - static_cast(dist) / BLEND_RADIUS; - t = t * t * (3.0f - 2.0f * t); - blended += t * neighbor_h; - total_weight += t; - } - } + const int DIR = (edge_z == 0) ? 1 : -1; + for (int i = 0; i < BLEND_RADIUS; i++) { + int z = edge_z + DIR * i; + float t = static_cast(i) / BLEND_RADIUS; - // --- Front neighbor neighbor[2]: (0, 1) --- - if (neighbor_heightmap[2] != std::nullopt && - neighbor_biome[2] != m_biome) { - int dist = (SIZE_Z - 1) - z; - if (dist < BLEND_RADIUS) { - float neighbor_h = - static_cast((*neighbor_heightmap[2])[x][0]); - float t = 1.0f - static_cast(dist) / BLEND_RADIUS; - t = t * t * (3.0f - 2.0f * t); - blended += t * neighbor_h; - total_weight += t; - } + // float smooth_t = t * t * (3.0f - 2.0f * t); + float smooth_t = t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f); + m_heightmap[x][z] = static_cast( + std::round(neighbor_h + (h - neighbor_h) * smooth_t)); } + } + } - // --- Back neighbor neighbor[3]: (0, -1) --- - if (neighbor_heightmap[3] != std::nullopt && - neighbor_biome[3] != m_biome) { - int dist = z; - if (dist < BLEND_RADIUS) { - float neighbor_h = static_cast( - (*neighbor_heightmap[3])[x][SIZE_Z - 1]); - float t = 1.0f - static_cast(dist) / BLEND_RADIUS; - t = t * t * (3.0f - 2.0f * t); - blended += t * neighbor_h; - total_weight += t; - } + if (is_cur_chunk_ins) { + return; + } + // --- Right-Front corner neighbor[4]: (1, 1) --- + if (neighbor_heightmap[4] != std::nullopt && neighbor_biome[4] != m_biome) { + for (int i = 0; i < BLEND_RADIUS; i++) { + for (int j = 0; j < BLEND_RADIUS; j++) { + int x = (CHUNK_SIZE - 1) - i; + int z = (CHUNK_SIZE - 1) - j; + int h = m_heightmap[x][z]; + + int h_right = (neighbor_heightmap[0] != std::nullopt) + ? (*neighbor_heightmap[0])[0][z] + : h; + + int h_front = (neighbor_heightmap[2] != std::nullopt) + ? (*neighbor_heightmap[2])[x][0] + : h; + + int h_corner = (*neighbor_heightmap[4])[0][0]; + + float tx = static_cast(i) / BLEND_RADIUS; + float tz = static_cast(j) / BLEND_RADIUS; + + float target_h = h_corner * (1 - tx) * (1 - tz) + + h_front * tx * (1 - tz) + + h_right * (1 - tx) * tz + h * tx * tz; + + if (h <= static_cast(std::round(target_h))) + continue; + + float t = static_cast(std::max(i, j)) / BLEND_RADIUS; + float smooth_t = t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f); + m_heightmap[x][z] = static_cast( + std::round(target_h + (h - target_h) * smooth_t)); } + } + } - m_heightmap[x][z] = static_cast(blended / total_weight); + // --- Left-Front corner neighbor[5]: (-1, 1) --- + if (neighbor_heightmap[5] != std::nullopt && neighbor_biome[5] != m_biome) { + for (int i = 0; i < BLEND_RADIUS; i++) { + for (int j = 0; j < BLEND_RADIUS; j++) { + int x = i; + int z = (CHUNK_SIZE - 1) - j; + int h = m_heightmap[x][z]; + int h_left = (neighbor_heightmap[1] != std::nullopt) + ? (*neighbor_heightmap[1])[CHUNK_SIZE - 1][z] + : h; + int h_front = (neighbor_heightmap[2] != std::nullopt) + ? (*neighbor_heightmap[2])[x][0] + : h; + int h_corner = (*neighbor_heightmap[5])[CHUNK_SIZE - 1][0]; + + float tx = static_cast(i) / BLEND_RADIUS; + float tz = static_cast(j) / BLEND_RADIUS; + float target_h = h_corner * (1 - tx) * (1 - tz) + + h_front * tx * (1 - tz) + + h_left * (1 - tx) * tz + h * tx * tz; + + if (h <= static_cast(std::round(target_h))) + continue; + + float t = static_cast(std::max(i, j)) / BLEND_RADIUS; + float smooth_t = t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f); + m_heightmap[x][z] = static_cast( + std::round(target_h + (h - target_h) * smooth_t)); + } + } + } + + // --- Right-Back corner neighbor[6]: (1, -1) --- + if (neighbor_heightmap[6] != std::nullopt && neighbor_biome[6] != m_biome) { + for (int i = 0; i < BLEND_RADIUS; i++) { + for (int j = 0; j < BLEND_RADIUS; j++) { + int x = (CHUNK_SIZE - 1) - i; + int z = j; + int h = m_heightmap[x][z]; + int h_right = (neighbor_heightmap[0] != std::nullopt) + ? (*neighbor_heightmap[0])[0][z] + : h; + int h_back = (neighbor_heightmap[3] != std::nullopt) + ? (*neighbor_heightmap[3])[x][CHUNK_SIZE - 1] + : h; + int h_corner = (*neighbor_heightmap[6])[0][CHUNK_SIZE - 1]; + + float tx = static_cast(i) / BLEND_RADIUS; + float tz = static_cast(j) / BLEND_RADIUS; + float target_h = h_corner * (1 - tx) * (1 - tz) + + h_back * tx * (1 - tz) + + h_right * (1 - tx) * tz + h * tx * tz; + + if (h <= static_cast(std::round(target_h))) + continue; + + float t = static_cast(std::max(i, j)) / BLEND_RADIUS; + float smooth_t = t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f); + m_heightmap[x][z] = static_cast( + std::round(target_h + (h - target_h) * smooth_t)); + } + } + } + + // --- Left-Back corner neighbor[7]: (-1, -1) --- + if (neighbor_heightmap[7] != std::nullopt && neighbor_biome[7] != m_biome) { + for (int i = 0; i < BLEND_RADIUS; i++) { + for (int j = 0; j < BLEND_RADIUS; j++) { + int x = i; + int z = j; + int h = m_heightmap[x][z]; + int h_left = (neighbor_heightmap[1] != std::nullopt) + ? (*neighbor_heightmap[1])[CHUNK_SIZE - 1][z] + : h; + int h_back = (neighbor_heightmap[3] != std::nullopt) + ? (*neighbor_heightmap[3])[x][CHUNK_SIZE - 1] + : h; + int h_corner = + (*neighbor_heightmap[7])[CHUNK_SIZE - 1][CHUNK_SIZE - 1]; + + float tx = static_cast(i) / BLEND_RADIUS; + float tz = static_cast(j) / BLEND_RADIUS; + float target_h = h_corner * (1 - tx) * (1 - tz) + + h_back * tx * (1 - tz) + + h_left * (1 - tx) * tz + h * tx * tz; + + if (h <= static_cast(std::round(target_h))) + continue; + + float t = static_cast(std::max(i, j)) / BLEND_RADIUS; + float smooth_t = t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f); + m_heightmap[x][z] = static_cast( + std::round(target_h + (h - target_h) * smooth_t)); + } } } } @@ -197,7 +354,7 @@ void ChunkGenerator::generate_terrain_blocks() { Logger::error("BiomeBuilder is nullptr"); return; } - m_chunk.blocks().assign(CHUCK_SIZE * CHUCK_SIZE * WORLD_SIZE_Y, 0); + m_chunk.blocks().assign(CHUNK_SIZE * CHUNK_SIZE * WORLD_SIZE_Y, 0); m_biome_builder->build_biome(); } @@ -225,8 +382,8 @@ void ChunkGenerator::blend_surface_blocks_borders( }; // For each column (x, z) - for (int x = 0; x < CHUCK_SIZE; ++x) { - for (int z = 0; z < CHUCK_SIZE; ++z) { + for (int x = 0; x < CHUNK_SIZE; ++x) { + for (int z = 0; z < CHUNK_SIZE; ++z) { // Get the current top block type of this column from m_blocks uint8_t type_self = 0; int top_y = -1; @@ -241,8 +398,8 @@ void ChunkGenerator::blend_surface_blocks_borders( weights[type_self] = 1.0f; // self weight // --- Right neighbor (index 0) --- - if (neighbor_block[0] && x >= CHUCK_SIZE - BLEND_RADIUS) { - int dist = (CHUCK_SIZE - 1) - x; + if (neighbor_block[0] && x >= CHUNK_SIZE - BLEND_RADIUS) { + int dist = (CHUNK_SIZE - 1) - x; float t = 1.0f - static_cast(dist) / BLEND_RADIUS; t = t * t * (3.0f - 2.0f * t); // smoothstep if (t > 0.0f) { @@ -259,14 +416,14 @@ void ChunkGenerator::blend_surface_blocks_borders( t = t * t * (3.0f - 2.0f * t); if (t > 0.0f) { uint8_t type_neighbor = get_top_block_from_neighbor( - *neighbor_block[1], CHUCK_SIZE - 1, z); + *neighbor_block[1], CHUNK_SIZE - 1, z); weights[type_neighbor] += t; } } // --- Front neighbor (index 2) --- - if (neighbor_block[2] && z >= CHUCK_SIZE - BLEND_RADIUS) { - int dist = (CHUCK_SIZE - 1) - z; + if (neighbor_block[2] && z >= CHUNK_SIZE - BLEND_RADIUS) { + int dist = (CHUNK_SIZE - 1) - z; float t = 1.0f - static_cast(dist) / BLEND_RADIUS; t = t * t * (3.0f - 2.0f * t); if (t > 0.0f) { @@ -283,7 +440,7 @@ void ChunkGenerator::blend_surface_blocks_borders( t = t * t * (3.0f - 2.0f * t); if (t > 0.0f) { uint8_t type_neighbor = get_top_block_from_neighbor( - *neighbor_block[3], x, CHUCK_SIZE - 1); + *neighbor_block[3], x, CHUNK_SIZE - 1); weights[type_neighbor] += t; } } @@ -304,13 +461,7 @@ void ChunkGenerator::blend_surface_blocks_borders( if (m_chunk.biome() == BiomeType::RIVER && final_type == 1) { final_type = 2; } - if (is_neighbor_river && final_type == 1) { - if (top_y < SEA_LEVEL) { - final_type = 2; - } else { - final_type = 1; - } - } + m_blocks[Chunk::get_index(x, top_y, z)] = final_type; // bottom block unsigned fill_type = 2; @@ -363,6 +514,7 @@ void ChunkGenerator::make_biome_builder() { Chunk& ChunkGenerator::chunk() { return m_chunk; } Random& ChunkGenerator::random() { return m_random; } -bool ChunkGenerator::neighbor_river() const { return is_neighbor_river; } - +const std::array& ChunkGenerator::neighbor_biome() const { + return m_neighbor_biome; +} } // namespace Cubed \ No newline at end of file diff --git a/src/gameplay/tree.cpp b/src/gameplay/tree.cpp index af2f4c6..3aae5be 100644 --- a/src/gameplay/tree.cpp +++ b/src/gameplay/tree.cpp @@ -39,8 +39,8 @@ bool build_tree(Chunk& chunk, const glm::ivec3& pos) { int x = tree_node.x; int y = tree_node.y; int z = tree_node.z; - if (x < 0 || y < 0 || z < 0 || x >= CHUCK_SIZE || y >= WORLD_SIZE_Y || - z >= CHUCK_SIZE) { + if (x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_SIZE_Y || + z >= CHUNK_SIZE) { return false; } if (block[Chunk::get_index(tree_node)] != 0) { diff --git a/src/gameplay/world.cpp b/src/gameplay/world.cpp index 62a8ecc..e40fa2b 100644 --- a/src/gameplay/world.cpp +++ b/src/gameplay/world.cpp @@ -11,8 +11,6 @@ namespace Cubed { -static constexpr ChunkPos CHUNK_DIR[]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; - struct ChunkRenderData { std::array*, 4> neighbor_block; Chunk* chunk; @@ -67,18 +65,8 @@ Player& World::get_player(const std::string& name) { } void World::init_world() { - m_chunks.reserve(MAX_DISTANCE * MAX_DISTANCE); + m_chunks.reserve(MAX_DISTANCE * MAX_DISTANCE * 4); auto t1 = std::chrono::system_clock::now(); - for (int s = 0; s < PRE_LOAD_DISTANCE; s++) { - for (int t = 0; t < PRE_LOAD_DISTANCE; t++) { - int ns = s - PRE_LOAD_DISTANCE / 2; - int nt = t - PRE_LOAD_DISTANCE / 2; - - ChunkPos pos{ns, nt}; - - m_chunks.emplace(pos, Chunk(*this, pos)); - } - } Logger::info("Max Support Thread is {}", std::thread::hardware_concurrency()); @@ -93,95 +81,162 @@ void World::init_world() { start_gen_thread(); hot_reload(); } -/* + void World::init_chunks() { - std::vector chunk_ptrs; - chunk_ptrs.reserve(m_chunks.size()); - for (auto& [pos, chunk] : m_chunks) { - chunk_ptrs.push_back(&chunk); - } - std::for_each(std::execution::par, chunk_ptrs.begin(), chunk_ptrs.end(), -[](auto& chunk){ chunk->init_chunk(); - }); - - std::atomic sync{0}; - sync.store(1, std::memory_order_release); - sync.load(std::memory_order_acquire); - - std::vector pending_gen_data; - pending_gen_data.reserve(m_chunks.size()); - for (auto& [pos, chunk] : m_chunks) { - ChunkRenderData data; - data.chunk = &chunk; - for (int i = 0; i < 4; i++) { - auto it = m_chunks.find(pos + CHUNK_DIR[i]); - if (it != m_chunks.end()) { - data.neighbor_block[i] = &(it->second.get_chunk_blocks()); - } else { - data.neighbor_block[i] = nullptr; + int dis_x = PRE_LOAD_DISTANCE; + int dis_z = PRE_LOAD_DISTANCE; + for (int x = 0; x < dis_x; x++) { + for (int z = 0; z < dis_z; z++) { + int nx = x - dis_x / 2; + int nz = z - dis_z / 2; + ChunkPos pos{nx, nz}; + auto it = m_chunks.find(pos); + if (it == m_chunks.end()) { + m_chunks.emplace(pos, Chunk(*this, pos)); } } - pending_gen_data.emplace_back(std::move(data)); } - std::for_each(std::execution::par, pending_gen_data.begin(), -pending_gen_data.end(), [](ChunkRenderData& data){ if(!data.chunk) { return ; + ChunkHashMap temp_neighbor; + for (int x = 0; x < dis_x + 2; x++) { + for (int z = 0; z < dis_z + 2; z++) { + int nx = x - (dis_x + 2) / 2; + int nz = z - (dis_z + 2) / 2; + ChunkPos pos{nx, nz}; + auto it = m_chunks.find(pos); + if (it == m_chunks.end()) { + auto it = temp_neighbor.find(pos); + if (it == temp_neighbor.end()) { + temp_neighbor.emplace(pos, Chunk(*this, pos)); + } + } } - data.chunk->gen_vertex_data(data.neighbor_block); - }); - for (auto& chunk_map : m_chunks) { - auto& [chunk_pos, chunk] = chunk_map; - chunk.upload_to_gpu(); - } -} -*/ - -void World::init_chunks() { for (auto& [pos, chunks] : m_chunks) { chunks.gen_phase_one(); } - std::array neighbor_chunks; + for (auto& [pos, chunks] : temp_neighbor) { + chunks.gen_phase_one(); + } + + std::array neighbor_chunks; for (auto& [pos, chunks] : m_chunks) { - for (int i = 0; i < 4; i++) { + for (int i = 0; i < 8; i++) { auto neighbor_pos = pos + CHUNK_DIR[i]; auto it = m_chunks.find(neighbor_pos); if (it == m_chunks.end()) { - neighbor_chunks[i] = nullptr; + auto it = temp_neighbor.find(neighbor_pos); + if (it == temp_neighbor.end()) { + neighbor_chunks[i] = nullptr; + ASSERT_MSG(false, "Neighbor Chunk is nullptr"); + } else { + neighbor_chunks[i] = &it->second; + } continue; } neighbor_chunks[i] = &it->second; } chunks.gen_phase_two(neighbor_chunks); } - - for (auto& [pos, chunks] : m_chunks) { - chunks.gen_phase_three(); - } - std::array, 4> neighbor_chunk_heightmap; - for (auto& [pos, chunks] : m_chunks) { - for (int i = 0; i < 4; i++) { + for (auto& [pos, chunks] : temp_neighbor) { + for (int i = 0; i < 8; i++) { auto neighbor_pos = pos + CHUNK_DIR[i]; auto it = m_chunks.find(neighbor_pos); if (it == m_chunks.end()) { - neighbor_chunk_heightmap[i] = std::nullopt; + auto it = temp_neighbor.find(neighbor_pos); + if (it == temp_neighbor.end()) { + neighbor_chunks[i] = nullptr; + } else { + neighbor_chunks[i] = &it->second; + } continue; } - neighbor_chunk_heightmap[i] = it->second.get_heightmap(); + neighbor_chunks[i] = &it->second; + } + chunks.gen_phase_two(neighbor_chunks); + } + for (auto& [pos, chunks] : m_chunks) { + chunks.gen_phase_three(); + } + for (auto& [pos, chunks] : temp_neighbor) { + chunks.gen_phase_three(); + } + + for (int i = 0; i < 4; i++) { + for (auto& [pos, chunks] : temp_neighbor) { + std::array, 8> + neighbor_chunk_heightmap; + std::array neighbor_biome; + for (int i = 0; i < 4; i++) { + auto neighbor_pos = pos + CHUNK_DIR[i]; + auto it = m_chunks.find(neighbor_pos); + if (it == m_chunks.end()) { + auto it = temp_neighbor.find(neighbor_pos); + if (it == temp_neighbor.end()) { + neighbor_chunk_heightmap[i] = std::nullopt; + neighbor_biome[i] = BiomeType::NONE; + } else { + neighbor_chunk_heightmap[i] = + it->second.get_heightmap(); + neighbor_biome[i] = it->second.biome(); + } + + continue; + } + neighbor_chunk_heightmap[i] = it->second.get_heightmap(); + neighbor_biome[i] = it->second.biome(); + } + chunks.gen_phase_four(neighbor_chunk_heightmap, neighbor_biome); + } + for (auto& [pos, chunks] : m_chunks) { + std::array, 8> + neighbor_chunk_heightmap; + std::array neighbor_biome; + for (int i = 0; i < 8; i++) { + + auto neighbor_pos = pos + CHUNK_DIR[i]; + auto it = m_chunks.find(neighbor_pos); + if (it == m_chunks.end()) { + auto it = temp_neighbor.find(neighbor_pos); + if (it == temp_neighbor.end()) { + neighbor_chunk_heightmap[i] = std::nullopt; + neighbor_biome[i] = BiomeType::NONE; + ASSERT_MSG(false, "Neighbor Chunk is nullptr"); + } else { + neighbor_chunk_heightmap[i] = + it->second.get_heightmap(); + neighbor_biome[i] = it->second.biome(); + } + + continue; + } + neighbor_chunk_heightmap[i] = it->second.get_heightmap(); + neighbor_biome[i] = it->second.biome(); + } + chunks.gen_phase_four(neighbor_chunk_heightmap, neighbor_biome); } - chunks.gen_phase_four(neighbor_chunk_heightmap); } for (auto& [pos, chunks] : m_chunks) { chunks.gen_phase_five(); } + for (auto& [pos, chunks] : temp_neighbor) { + chunks.gen_phase_five(); + } std::array>, 4> neighbor_block; for (auto& [pos, chunks] : m_chunks) { for (int i = 0; i < 4; i++) { auto neighbor_pos = pos + CHUNK_DIR[i]; auto it = m_chunks.find(neighbor_pos); if (it == m_chunks.end()) { - neighbor_block[i] = std::nullopt; + auto it = temp_neighbor.find(neighbor_pos); + if (it == temp_neighbor.end()) { + neighbor_block[i] = std::nullopt; + ASSERT_MSG(false, "Neighbor Chunk is nullptr"); + } else { + neighbor_block[i] = it->second.get_chunk_blocks(); + } + continue; } neighbor_block[i] = it->second.get_chunk_blocks(); @@ -191,6 +246,7 @@ void World::init_chunks() { for (auto& [pos, chunks] : m_chunks) { chunks.gen_phase_seven(); } + std::atomic sync{0}; sync.store(1, std::memory_order_release); sync.load(std::memory_order_acquire); @@ -253,16 +309,16 @@ void World::render(const glm::mat4& mvp_matrix) { ChunkPos World::chunk_pos(int world_x, int world_z) { int chunk_x, chunk_z; if (world_x < 0) { - chunk_x = (world_x + 1) / CHUCK_SIZE - 1; + chunk_x = (world_x + 1) / CHUNK_SIZE - 1; } if (world_x >= 0) { - chunk_x = world_x / CHUCK_SIZE; + chunk_x = world_x / CHUNK_SIZE; } if (world_z < 0) { - chunk_z = (world_z + 1) / CHUCK_SIZE - 1; + chunk_z = (world_z + 1) / CHUNK_SIZE - 1; } if (world_z >= 0) { - chunk_z = world_z / CHUCK_SIZE; + chunk_z = world_z / CHUNK_SIZE; } return {chunk_x, chunk_z}; } @@ -292,19 +348,35 @@ void World::gen_chunks_internal() { ConstChunkMap new_chunks_neighbor; // affected neighbor ChunkPtrUpdateList affected_neighbor; - build_neighbor_context_for_new_chunks(new_chunks_neighbor, - affected_neighbor, new_chunks); - - std::array*, 4> neighbor_block; + ChunkHashMap temp_neighbor; + build_neighbor_context_for_new_chunks( + new_chunks_neighbor, affected_neighbor, new_chunks, temp_neighbor); + Logger::info("Temp neighbor sum {}", temp_neighbor.size()); // build new chunk, but the neighbor in m_chunks also need to re-build for (auto& [pos, chunk] : new_chunks) { chunk.gen_phase_one(); } + for (auto& [pos, chunk] : temp_neighbor) { + chunk.gen_phase_one(); + } m_chunk_gen_fraction = 0.2f; - std::array neighbor_chunks; + std::array neighbor_chunks; for (auto& [pos, chunks] : new_chunks) { - for (int i = 0; i < 4; i++) { + for (int i = 0; i < 8; i++) { + auto neighbor_pos = pos + CHUNK_DIR[i]; + auto it = new_chunks_neighbor.find(neighbor_pos); + if (it == new_chunks_neighbor.end()) { + neighbor_chunks[i] = nullptr; + ASSERT_MSG(false, "Cant Find Neighbot"); + continue; + } + neighbor_chunks[i] = it->second; + } + chunks.gen_phase_two(neighbor_chunks); + } + for (auto& [pos, chunks] : temp_neighbor) { + for (int i = 0; i < 8; i++) { auto neighbor_pos = pos + CHUNK_DIR[i]; auto it = new_chunks_neighbor.find(neighbor_pos); if (it == new_chunks_neighbor.end()) { @@ -319,27 +391,59 @@ void World::gen_chunks_internal() { for (auto& [pos, chunks] : new_chunks) { chunks.gen_phase_three(); } + for (auto& [pos, chunks] : temp_neighbor) { + chunks.gen_phase_three(); + } m_chunk_gen_fraction = 0.4f; - std::array, 4> neighbor_chunk_heightmap; - for (auto& [pos, chunks] : new_chunks) { - { + for (int i = 0; i < 4; i++) { + for (auto& [pos, chunks] : temp_neighbor) { + std::array, 8> + neighbor_chunk_heightmap; // std::lock_guard lk(m_chunks_mutex); - for (int i = 0; i < 4; i++) { + std::array neighbor_biome; + for (int i = 0; i < 8; i++) { auto neighbor_pos = pos + CHUNK_DIR[i]; auto it = new_chunks_neighbor.find(neighbor_pos); if (it == new_chunks_neighbor.end()) { neighbor_chunk_heightmap[i] = std::nullopt; + neighbor_biome[i] = BiomeType::NONE; continue; } neighbor_chunk_heightmap[i] = it->second->get_heightmap(); + neighbor_biome[i] = it->second->biome(); } + + chunks.gen_phase_four(neighbor_chunk_heightmap, neighbor_biome); + } + for (auto& [pos, chunks] : new_chunks) { + std::array, 8> + neighbor_chunk_heightmap; + // std::lock_guard lk(m_chunks_mutex); + std::array neighbor_biome; + for (int i = 0; i < 8; i++) { + auto neighbor_pos = pos + CHUNK_DIR[i]; + auto it = new_chunks_neighbor.find(neighbor_pos); + if (it == new_chunks_neighbor.end()) { + neighbor_chunk_heightmap[i] = std::nullopt; + neighbor_biome[i] = BiomeType::NONE; + ASSERT_MSG(false, "Cant Find Neighbot"); + continue; + } + neighbor_chunk_heightmap[i] = it->second->get_heightmap(); + neighbor_biome[i] = it->second->biome(); + } + + chunks.gen_phase_four(neighbor_chunk_heightmap, neighbor_biome); } - chunks.gen_phase_four(neighbor_chunk_heightmap); } + m_chunk_gen_fraction = 0.5f; for (auto& [pos, chunks] : new_chunks) { chunks.gen_phase_five(); } + for (auto& [pos, chunks] : temp_neighbor) { + chunks.gen_phase_five(); + } std::array>, 4> neighbor_blocks_data; for (auto& [pos, chunks] : new_chunks) { { @@ -359,7 +463,9 @@ void World::gen_chunks_internal() { for (auto& [pos, chunks] : new_chunks) { chunks.gen_phase_seven(); } + m_chunk_gen_fraction = 0.6f; + std::array*, 4> neighbor_block; for (auto& [pos, chunk] : new_chunks) { for (int i = 0; i < 4; i++) { auto it = new_chunks_neighbor.find(pos + CHUNK_DIR[i]); @@ -441,7 +547,7 @@ void World::sync_and_collect_missing_chunks( void World::build_neighbor_context_for_new_chunks( ConstChunkMap& new_chunks_neighbor, ChunkPtrUpdateList& affected_neighbor, - const ChunkUpdateList& new_chunks) { + const ChunkUpdateList& new_chunks, ChunkHashMap& temp_neighbor) { { std::lock_guard lk(m_chunks_mutex); for (auto& [pos, chunk] : new_chunks) { @@ -450,6 +556,8 @@ void World::build_neighbor_context_for_new_chunks( if (it != m_chunks.end()) { new_chunks_neighbor.insert({it->first, &(it->second)}); affected_neighbor.push_back({it->first, &(it->second)}); + } else { + temp_neighbor.emplace(pos + dir, Chunk(*this, pos + dir)); } } } @@ -457,6 +565,9 @@ void World::build_neighbor_context_for_new_chunks( for (auto& [pos, chunk] : new_chunks) { new_chunks_neighbor.insert({pos, &chunk}); } + for (auto& [pos, chunk] : temp_neighbor) { + new_chunks_neighbor.insert({pos, &chunk}); + } } void World::build_neighbor_context_for_affected_neighbors( @@ -544,10 +655,10 @@ int World::get_block(const glm::ivec3& block_pos) const { const auto& chunk_blocks = it->second.get_chunk_blocks(); int x, y, z; y = block_pos.y; - x = block_pos.x - chunk_x * CHUCK_SIZE; - z = block_pos.z - chunk_z * CHUCK_SIZE; - if (x < 0 || y < 0 || z < 0 || x >= CHUCK_SIZE || y >= WORLD_SIZE_Y || - z >= CHUCK_SIZE) { + x = block_pos.x - chunk_x * CHUNK_SIZE; + z = block_pos.z - chunk_z * CHUNK_SIZE; + if (x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_SIZE_Y || + z >= CHUNK_SIZE) { return 0; } return chunk_blocks[Chunk::get_index(x, y, z)]; @@ -564,10 +675,10 @@ bool World::is_block(const glm::ivec3& block_pos) const { const auto& chunk_blocks = it->second.get_chunk_blocks(); int x, y, z; y = block_pos.y; - x = block_pos.x - chunk_x * CHUCK_SIZE; - z = block_pos.z - chunk_z * CHUCK_SIZE; - if (x < 0 || y < 0 || z < 0 || x >= CHUCK_SIZE || y >= WORLD_SIZE_Y || - z >= CHUCK_SIZE) { + x = block_pos.x - chunk_x * CHUNK_SIZE; + z = block_pos.z - chunk_z * CHUNK_SIZE; + if (x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_SIZE_Y || + z >= CHUNK_SIZE) { return false; } auto id = chunk_blocks[Chunk::get_index(x, y, z)]; @@ -595,10 +706,10 @@ void World::set_block(const glm::ivec3& block_pos, unsigned id) { int x, y, z; y = world_y; - x = world_x - chunk_x * CHUCK_SIZE; - z = world_z - chunk_z * CHUCK_SIZE; - if (x < 0 || y < 0 || z < 0 || x >= CHUCK_SIZE || y >= WORLD_SIZE_Y || - z >= CHUCK_SIZE) { + x = world_x - chunk_x * CHUNK_SIZE; + z = world_z - chunk_z * CHUNK_SIZE; + if (x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_SIZE_Y || + z >= CHUNK_SIZE) { return; } @@ -677,14 +788,14 @@ void World::update(float delta_time) { } m_render_snapshots.push_back( {chunk.get_vbo(), chunk.get_vertex_sum(), - glm::vec3(static_cast(pos.x * CHUCK_SIZE) + - static_cast(CHUCK_SIZE / 2), + glm::vec3(static_cast(pos.x * CHUNK_SIZE) + + static_cast(CHUNK_SIZE / 2), static_cast(WORLD_SIZE_Y / 2), - static_cast(pos.z * CHUCK_SIZE) + - static_cast(CHUCK_SIZE / 2)), - glm::vec3(static_cast(CHUCK_SIZE / 2), + static_cast(pos.z * CHUNK_SIZE) + + static_cast(CHUNK_SIZE / 2)), + glm::vec3(static_cast(CHUNK_SIZE / 2), static_cast(WORLD_SIZE_Y / 2), - static_cast(CHUCK_SIZE / 2))}); + static_cast(CHUNK_SIZE / 2))}); } } }