From f1fc192ddc4c739fa8b4b376c759b7d3218a34eb Mon Sep 17 00:00:00 2001 From: Mel Date: Fri, 7 Jul 2023 21:39:42 +0200 Subject: Chunk-bound tree decoration --- src/World/Generator.cpp | 321 ------------------------------------------------ 1 file changed, 321 deletions(-) delete mode 100644 src/World/Generator.cpp (limited to 'src/World/Generator.cpp') diff --git a/src/World/Generator.cpp b/src/World/Generator.cpp deleted file mode 100644 index ada2b7b..0000000 --- a/src/World/Generator.cpp +++ /dev/null @@ -1,321 +0,0 @@ -#include "Generator.hpp" -#include "../Math/Interpolation.hpp" -#include "../Math/Sigmoid.hpp" - -namespace MC::World { - -Chunk Generator::generate(int64_t chunk_x, int64_t chunk_y) { - Chunk chunk(chunk_x, chunk_y); - - auto landmass_map = generate_landmass_map(chunk_x, chunk_y); - auto hill_map = generate_hill_map(chunk_x, chunk_y); - auto height_map = generate_height_map(landmass_map, hill_map, chunk_x, chunk_y); - - auto biome_map = generate_biome_map(landmass_map, hill_map, height_map, chunk_x, chunk_y); - auto terrain_map = generate_terrain(height_map, chunk_x, chunk_y); - - decorate_soil(chunk, biome_map, terrain_map); - - chunk.set_details({{landmass_map}, {hill_map}, {biome_map}}); - - return chunk; -} - -Generator::Map2D Generator::generate_landmass_map(int64_t chunk_x, int64_t chunk_y) { - Matrix landmass_map{}; - - for (uint x = 0; x < Chunk::Width; x++) { - for (uint y = 0; y < Chunk::Width; y++) { - auto world_pos = chunk_position_to_world_vector(chunk_x, chunk_y, x, y); - landmass_map(x, y) = get_landmass(world_pos); - } - } - - return landmass_map; -} - -Generator::Map2D Generator::generate_hill_map(int64_t chunk_x, int64_t chunk_y) { - Map2D hill_map{}; - - for (uint x = 0; x < Chunk::Width; x++) { - for (uint y = 0; y < Chunk::Width; y++) { - hill_map(x, y) = get_hill(chunk_position_to_world_vector(chunk_x, chunk_y, x, y)); - } - } - - return hill_map; -} - -Generator::Map2D Generator::generate_height_map(Map2D& landmass_map, Map2D& hill_map, int64_t chunk_x, int64_t chunk_y) { - Map2D height_map{}; - - for (uint x = 0; x < Chunk::Width; x++) { - for (uint y = 0; y < Chunk::Width; y++) { - auto landmass_effect = landmass_map(x, y); - auto hill_effect = hill_map(x, y); - - auto hill = hill_effect * landmass_effect * 1.4 - 0.4; - auto landmass = landmass_effect * 0.6 + 0.4; - - auto height = (hill + landmass) / 2.0f; - - height_map(x, y) = height; - } - } - - return height_map; -} - -Generator::Map2D Generator::generate_biome_map(Map2D& landmass_map, Map2D& hill_map, Map2D& height_map, int64_t chunk_x, int64_t chunk_y) { - Map2D biome_map{}; - - for (uint x = 0; x < Chunk::Width; x++) { - for (uint y = 0; y < Chunk::Width; y++) { - float landmass = landmass_map(x, y); - float hill = hill_map(x, y); - - auto world_pos = chunk_position_to_world_vector(chunk_x, chunk_y, x, y); - float temperature = get_temperature(world_pos); - float humidity = get_humidity(world_pos); - - HillSlice hill_slice; - if (hill > 0.9) { hill_slice = HillSlice::Mountain; } - else if (hill > 0.33) { hill_slice = HillSlice::Middle; } - else { hill_slice = HillSlice::Valley; } - - LandmassSlice landmass_slice; - if (landmass > 0.8) { landmass_slice = LandmassSlice::Land; } - else if (landmass > 0.45) { landmass_slice = LandmassSlice::Beach; } - else { landmass_slice = LandmassSlice::Ocean; } - - TemperatureZone temparature_zone; - if (temperature > 0.66) { temparature_zone = TemperatureZone::Hot; } - else if (temperature > 0.33) { temparature_zone = TemperatureZone::Fair; } - else { temparature_zone = TemperatureZone::Cold; } - - HumidityZone humidity_zone; - if (humidity > 0.66) { humidity_zone = HumidityZone::Wet; } - else if (humidity > 0.33) { humidity_zone = HumidityZone::Temperate; } - else { humidity_zone = HumidityZone::Dry; } - - auto biome = lookup_biome(hill_slice, landmass_slice, temparature_zone, humidity_zone); - biome_map(x, y) = biome; - } - } - - return biome_map; -} - -Generator::Map3D Generator::generate_terrain(Map2D& height_map, int64_t chunk_x, int64_t chunk_y) { - float jaggedness = 0.10f; - - Map3D terrain_map{}; - for (uint x = 0; x < Chunk::Width; x++) { - for (uint z = 0; z < Chunk::Width; z++) { - auto height = height_map(x, z); - - for (uint y = 0; y < Chunk::Height; y++) { - float density = get_density({Chunk::Width * chunk_x + (float)x, (float)y, Chunk::Width * chunk_y + (float)z}); - float threshold = Math::sigmoid(((float)y / (Chunk::Height * height * 2) - 0.5f) / jaggedness); - - if (density > threshold) { - terrain_map(x, y, z) = true; - } - } - } - } - - return terrain_map; -} - -void Generator::decorate_soil(Chunk& chunk, Map2D& biome_map, Map3D& terrain_map) { - constexpr uint dirt_depth = 4; - constexpr uint water_height = 39; - - for (uint x = 0; x < Chunk::Width; x++) { - for (uint z = 0; z < Chunk::Width; z++) { - auto biome = biome_map(x, z); - - BlockType top_block{}; - BlockType soil_block{}; - switch (biome) { - case BiomeType::Beach: - case BiomeType::Desert: - top_block = BlockType::Sand; - soil_block = BlockType::Sand; - break; - case BiomeType::Jungle: - case BiomeType::Forest: - case BiomeType::Plains: - case BiomeType::River: - case BiomeType::Ocean: - top_block = BlockType::Grass; - soil_block = BlockType::Dirt; - break; - case BiomeType::Alpine: - top_block = BlockType::Snow; - soil_block = BlockType::Dirt; - break; - } - - auto column_depth = 0; - for (uint y = Chunk::Height - 1; y > 0; y--) { - auto block = terrain_map(x, y, z); - if (block) { - if (column_depth == 0 && y >= water_height - 1) { - chunk.set(x, y, z, {top_block}); - } else if (column_depth < dirt_depth) { - chunk.set(x, y, z, {soil_block}); - } else { - chunk.set(x, y, z, {BlockType::Stone}); - } - column_depth++; - } else { - if (y < water_height) { - chunk.set(x, y, z, {BlockType::Water}); - } - column_depth = 0; - } - } - } - } -} - -#define CURVE_START(y) constexpr auto lerp = Math::linear_interpolation; float _py = y; float _px = 0.0f; -#define CURVE_POINT(x, y) if (v < x) return lerp({_py, y}, _px, x, v); _py = y; _px = x -#define CURVE_END(y) return lerp({_py, y}, _px, 1.0f, v); - -float Generator::get_landmass(Vector<2> pos) const { - auto v = m_landmass_noise.at(pos); - - CURVE_START(1.0f); - CURVE_POINT(0.1f, 0.8f); - CURVE_POINT(0.3f, 0.8f); - CURVE_POINT(0.37f, 0.125f); - CURVE_POINT(0.4f, 0.4f); - CURVE_POINT(0.46f, 0.45f); - CURVE_POINT(0.47f, 0.875f); - CURVE_POINT(0.48f, 0.9f); - CURVE_POINT(0.55f, 0.95f); - CURVE_END(1.0f); -} - -float Generator::get_hill(Vector<2> pos) const { - auto v = m_hill_noise.at(pos); - - CURVE_START(0.33f); - CURVE_POINT(0.25f, 1.0f); - - CURVE_POINT(0.49f, 0.1f); - CURVE_POINT(0.5f, 0.0f); - CURVE_POINT(0.51f, 0.1f); - - CURVE_POINT(0.75f, 1.0f); - CURVE_END(0.33f); -} - -float Generator::get_humidity(Vector<2> pos) const { - auto v = m_humidity_noise.at(pos); - return v; -} - -float Generator::get_temperature(Vector<2> pos) const { - auto v = m_temperature_noise.at(pos); - return v; -} - -float Generator::get_density(Vector<3> pos) const { - auto v = m_density_noise.at(pos); - return v; -} - -Vector<2> Generator::chunk_position_to_world_vector(int64_t chunk_x, int64_t chunk_y, uint x, uint y) { - return {(float)x + chunk_x * Chunk::Width, (float)y + chunk_y * Chunk::Width}; -} - -std::array Generator::create_biome_lookup_table() { - std::array table{}; - - auto inc = [](auto& x) { x = (std::remove_reference_t)((uint)x + 1); }; - auto cmp = [](auto x, auto s) { return (uint)x < (uint)s; }; - - for (HillSlice hill_slice{}; cmp(hill_slice, HillSliceSize); inc(hill_slice)) { - for (LandmassSlice landmass_slice{}; cmp(landmass_slice, LandmassSliceSize); inc(landmass_slice)) { - for (TemperatureZone temperature_zone{}; cmp(temperature_zone, TemperatureZoneSize); inc(temperature_zone)) { - for (HumidityZone humidity_zone{}; cmp(humidity_zone, HumidityZoneSize); inc(humidity_zone)) { - BiomeType biome{}; - if (landmass_slice == LandmassSlice::Ocean) { - biome = BiomeType::Ocean; - goto set; - } - if (landmass_slice == LandmassSlice::Beach) { - biome = BiomeType::Beach; - goto set; - } - - if (hill_slice == HillSlice::Valley) { - biome = BiomeType::River; - goto set; - } - if (hill_slice == HillSlice::Mountain) { - if (temperature_zone == TemperatureZone::Hot) { - biome = BiomeType::Desert; - } else { - biome = BiomeType::Alpine; - } - goto set; - } - - switch (temperature_zone) { - case TemperatureZone::Hot: - biome = BiomeType::Desert; - break; - case TemperatureZone::Fair: - switch (humidity_zone) { - case HumidityZone::Wet: - biome = BiomeType::Jungle; - break; - case HumidityZone::Lush: - biome = BiomeType::Forest; - break; - case HumidityZone::Temperate: - case HumidityZone::Dry: - biome = BiomeType::Plains; - break; - } - break; - case TemperatureZone::Cold: - switch (humidity_zone) { - case HumidityZone::Wet: - case HumidityZone::Lush: - biome = BiomeType::Alpine; - break; - case HumidityZone::Temperate: - case HumidityZone::Dry: - biome = BiomeType::Plains; - break; - } - break; - } - - set: - table[biome_lookup_table_index(hill_slice, landmass_slice, temperature_zone, humidity_zone)] = biome; - } - } - } - } - - return table; -} - -size_t Generator::biome_lookup_table_index(HillSlice hill_slice, LandmassSlice landmass_slice, TemperatureZone temperature_zone, HumidityZone humidity_zone) { - auto hs = (uint8_t)hill_slice; auto ls = (uint8_t)landmass_slice; auto tz = (uint8_t)temperature_zone; auto hz = (uint8_t)humidity_zone; - auto LS_S = (uint8_t)LandmassSliceSize; auto TZ_S = (uint8_t)TemperatureZoneSize; auto HZ_S = (uint8_t)HumidityZoneSize; - return (hs * LS_S * TZ_S * HZ_S) + (ls * TZ_S * HZ_S) + (tz * HZ_S) + hz; -} - -BiomeType Generator::lookup_biome(HillSlice hill_slice, LandmassSlice landmass_slice, TemperatureZone temperature_zone, HumidityZone humidity_zone) { - return biome_lookup_table.at(biome_lookup_table_index(hill_slice, landmass_slice, temperature_zone, humidity_zone)); -} - -} -- cgit 1.4.1