feat: add island smoothing pass and update biome properties for improved terrain generation
Signed-off-by: szdytom <szdytom@qq.com>
This commit is contained in:
parent
7f147a1293
commit
e7b9fd856f
@ -7,6 +7,7 @@ set(ISTD_TILEMAP_SRC
|
|||||||
src/pass/deepwater.cpp
|
src/pass/deepwater.cpp
|
||||||
src/pass/mountain_hole_fill.cpp
|
src/pass/mountain_hole_fill.cpp
|
||||||
src/pass/smoothen_mountain.cpp
|
src/pass/smoothen_mountain.cpp
|
||||||
|
src/pass/smoothen_island.cpp
|
||||||
src/generation.cpp
|
src/generation.cpp
|
||||||
src/tilemap.cpp
|
src/tilemap.cpp
|
||||||
src/noise.cpp
|
src/noise.cpp
|
||||||
|
@ -134,7 +134,7 @@ int main(int argc, char *argv[]) {
|
|||||||
istd::Seed seed
|
istd::Seed seed
|
||||||
= istd::Seed::from_string(argc >= 2 ? argv[1] : "hello_world");
|
= istd::Seed::from_string(argc >= 2 ? argv[1] : "hello_world");
|
||||||
std::string output_filename = argc >= 3 ? argv[2] : "output.bmp";
|
std::string output_filename = argc >= 3 ? argv[2] : "output.bmp";
|
||||||
int chunks_per_side = 4; // Default value
|
int chunks_per_side = 8; // Default value
|
||||||
|
|
||||||
// Parse optional chunks_per_side parameter
|
// Parse optional chunks_per_side parameter
|
||||||
if (argc == 4) {
|
if (argc == 4) {
|
||||||
|
@ -5,9 +5,7 @@
|
|||||||
#include "chunk.h"
|
#include "chunk.h"
|
||||||
#include "noise.h"
|
#include "noise.h"
|
||||||
#include "tilemap.h"
|
#include "tilemap.h"
|
||||||
#include <array>
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <queue>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace istd {
|
namespace istd {
|
||||||
@ -28,13 +26,18 @@ struct GenerationConfig {
|
|||||||
double humidity_persistence = 0.4; // Persistence for humidity noise
|
double humidity_persistence = 0.4; // Persistence for humidity noise
|
||||||
|
|
||||||
double base_scale = 0.08; // Scale for base terrain noise
|
double base_scale = 0.08; // Scale for base terrain noise
|
||||||
int base_octaves = 3; // Number of octaves for base terrain noise
|
int base_octaves = 3; // Number of octaves for base terrain noise
|
||||||
double base_persistence = 0.5; // Persistence for base terrain noise
|
double base_persistence = 0.5; // Persistence for base terrain noise
|
||||||
|
|
||||||
|
int mountain_smoothen_steps = 2; // Number of steps for mountain smoothing
|
||||||
|
// cellular automata
|
||||||
|
std::uint32_t mountain_remove_threshold = 10; // Threshold for mountain
|
||||||
|
// removal
|
||||||
|
|
||||||
|
int island_smoothen_steps = 8; // Number of steps for island smoothing
|
||||||
|
// cellular automata
|
||||||
|
std::uint32_t island_remove_threshold = 8; // Threshold for island removal
|
||||||
|
|
||||||
int mountain_smoothen_steps
|
|
||||||
= 2; // Number of steps for mountain smoothing cellular automata
|
|
||||||
std::uint32_t mountain_remove_threshold
|
|
||||||
= 10; // Threshold for mountain removal
|
|
||||||
std::uint32_t fill_threshold = 10; // Fill holes smaller than this size
|
std::uint32_t fill_threshold = 10; // Fill holes smaller than this size
|
||||||
std::uint32_t deepwater_radius = 2; // Radius for deepwater generation
|
std::uint32_t deepwater_radius = 2; // Radius for deepwater generation
|
||||||
};
|
};
|
||||||
@ -222,6 +225,72 @@ public:
|
|||||||
void operator()(TileMap &tilemap);
|
void operator()(TileMap &tilemap);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SmoothenIslandPass {
|
||||||
|
private:
|
||||||
|
const GenerationConfig &config_;
|
||||||
|
DiscreteRandomNoise noise_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Perform BFS to find connected component size for islands
|
||||||
|
* @param tilemap The tilemap to search
|
||||||
|
* @param start_pos Starting position for BFS
|
||||||
|
* @param visited 2D array tracking visited tiles
|
||||||
|
* @param positions Output vector of positions in this component
|
||||||
|
* @return Size of the connected component
|
||||||
|
*/
|
||||||
|
std::uint32_t bfs_component_size(
|
||||||
|
TileMap &tilemap, TilePos start_pos,
|
||||||
|
std::vector<std::vector<bool>> &visited, std::vector<TilePos> &positions
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Remove small island components to create smoother terrain
|
||||||
|
* @param tilemap The tilemap to process
|
||||||
|
*/
|
||||||
|
void remove_small_island(TileMap &tilemap);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Smoothen islands with cellular automata
|
||||||
|
* @param tilemap The tilemap to process
|
||||||
|
*/
|
||||||
|
void smoothen_islands(TileMap &tilemap, std::uint32_t step_i);
|
||||||
|
|
||||||
|
void smoothen_islands_subchunk(
|
||||||
|
TileMap &tilemap, std::uint8_t chunk_x, std::uint8_t chunk_y,
|
||||||
|
SubChunkPos sub_pos, std::uint32_t step_i,
|
||||||
|
std::vector<std::pair<TilePos, Tile>> &replacements
|
||||||
|
);
|
||||||
|
|
||||||
|
struct CACtx {
|
||||||
|
BiomeType biome;
|
||||||
|
std::uint8_t rand;
|
||||||
|
int adj_land, adj_sand, adj_water; // Adjacent tile counts
|
||||||
|
};
|
||||||
|
|
||||||
|
Tile ca_tile(TilePos pos, Tile tile, const CACtx &ctx) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if a tile is part of an island (Land or Sand)
|
||||||
|
* @param tile The tile to check
|
||||||
|
* @return True if the tile is Land or Sand
|
||||||
|
*/
|
||||||
|
bool is_island_tile(const Tile &tile) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct an island smoothing pass
|
||||||
|
* @param config Generation configuration parameters
|
||||||
|
* @param rng Random number generator for terrain replacement
|
||||||
|
*/
|
||||||
|
SmoothenIslandPass(const GenerationConfig &config, Xoroshiro128PP rng);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Smoothen islands in the terrain
|
||||||
|
* @param tilemap The tilemap to process
|
||||||
|
*/
|
||||||
|
void operator()(TileMap &tilemap);
|
||||||
|
};
|
||||||
|
|
||||||
// Terrain generator class that manages the generation process
|
// Terrain generator class that manages the generation process
|
||||||
class TerrainGenerator {
|
class TerrainGenerator {
|
||||||
private:
|
private:
|
||||||
@ -260,6 +329,12 @@ private:
|
|||||||
*/
|
*/
|
||||||
void smoothen_mountains_pass(TileMap &tilemap);
|
void smoothen_mountains_pass(TileMap &tilemap);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Smoothen islands in the terrain
|
||||||
|
* @param tilemap The tilemap to process
|
||||||
|
*/
|
||||||
|
void smoothen_islands_pass(TileMap &tilemap);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Fill small holes in the terrain
|
* @brief Fill small holes in the terrain
|
||||||
* @param tilemap The tilemap to process
|
* @param tilemap The tilemap to process
|
||||||
|
@ -33,6 +33,7 @@ static_assert(surface_tile_count <= 16, "Surface tile don't fit in 4 bits");
|
|||||||
struct Tile {
|
struct Tile {
|
||||||
BaseTileType base : 4;
|
BaseTileType base : 4;
|
||||||
SurfaceTileType surface : 4;
|
SurfaceTileType surface : 4;
|
||||||
|
friend bool operator==(Tile lhs, Tile rhs) = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(Tile) == 1);
|
static_assert(sizeof(Tile) == 1);
|
||||||
|
@ -36,10 +36,10 @@ constexpr BiomeProperties biome_properties[] = {
|
|||||||
.temperature = BiomeTemperature::Cold,
|
.temperature = BiomeTemperature::Cold,
|
||||||
.humidity = BiomeHumidity::Wet,
|
.humidity = BiomeHumidity::Wet,
|
||||||
.is_ocean = true,
|
.is_ocean = true,
|
||||||
.water_ratio = .1,
|
.water_ratio = .15,
|
||||||
.ice_ratio = .7,
|
.ice_ratio = .8,
|
||||||
.sand_ratio = .25,
|
.sand_ratio = .05,
|
||||||
.land_ratio = .05,
|
.land_ratio = .0,
|
||||||
},
|
},
|
||||||
// Plains (Temperate & Dry)
|
// Plains (Temperate & Dry)
|
||||||
{
|
{
|
||||||
@ -69,10 +69,10 @@ constexpr BiomeProperties biome_properties[] = {
|
|||||||
.temperature = BiomeTemperature::Temperate,
|
.temperature = BiomeTemperature::Temperate,
|
||||||
.humidity = BiomeHumidity::Wet,
|
.humidity = BiomeHumidity::Wet,
|
||||||
.is_ocean = true,
|
.is_ocean = true,
|
||||||
.water_ratio = .8,
|
.water_ratio = .95,
|
||||||
.ice_ratio = .0,
|
.ice_ratio = .0,
|
||||||
.sand_ratio = .15,
|
.sand_ratio = .03,
|
||||||
.land_ratio = .05,
|
.land_ratio = .02,
|
||||||
},
|
},
|
||||||
// Desert (Hot & Dry)
|
// Desert (Hot & Dry)
|
||||||
{
|
{
|
||||||
@ -82,7 +82,7 @@ constexpr BiomeProperties biome_properties[] = {
|
|||||||
.is_ocean = false,
|
.is_ocean = false,
|
||||||
.water_ratio = .0,
|
.water_ratio = .0,
|
||||||
.ice_ratio = .0,
|
.ice_ratio = .0,
|
||||||
.sand_ratio = .8,
|
.sand_ratio = .85,
|
||||||
.land_ratio = .0,
|
.land_ratio = .0,
|
||||||
},
|
},
|
||||||
// Savanna (Hot & Moderate)
|
// Savanna (Hot & Moderate)
|
||||||
@ -102,10 +102,10 @@ constexpr BiomeProperties biome_properties[] = {
|
|||||||
.temperature = BiomeTemperature::Hot,
|
.temperature = BiomeTemperature::Hot,
|
||||||
.humidity = BiomeHumidity::Wet,
|
.humidity = BiomeHumidity::Wet,
|
||||||
.is_ocean = true,
|
.is_ocean = true,
|
||||||
.water_ratio = .8,
|
.water_ratio = .95,
|
||||||
.ice_ratio = .0,
|
.ice_ratio = .0,
|
||||||
.sand_ratio = .05,
|
.sand_ratio = .01,
|
||||||
.land_ratio = .15,
|
.land_ratio = .04,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#include "generation.h"
|
#include "generation.h"
|
||||||
#include "biome.h"
|
|
||||||
|
|
||||||
namespace istd {
|
namespace istd {
|
||||||
TerrainGenerator::TerrainGenerator(const GenerationConfig &config)
|
TerrainGenerator::TerrainGenerator(const GenerationConfig &config)
|
||||||
@ -9,6 +8,7 @@ void TerrainGenerator::operator()(TileMap &tilemap) {
|
|||||||
biome_pass(tilemap);
|
biome_pass(tilemap);
|
||||||
base_tile_type_pass(tilemap);
|
base_tile_type_pass(tilemap);
|
||||||
smoothen_mountains_pass(tilemap);
|
smoothen_mountains_pass(tilemap);
|
||||||
|
smoothen_islands_pass(tilemap);
|
||||||
mountain_hole_fill_pass(tilemap);
|
mountain_hole_fill_pass(tilemap);
|
||||||
deepwater_pass(tilemap);
|
deepwater_pass(tilemap);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "biome.h"
|
#include "biome.h"
|
||||||
#include "chunk.h"
|
#include "chunk.h"
|
||||||
#include "generation.h"
|
#include "generation.h"
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace istd {
|
namespace istd {
|
||||||
|
|
||||||
@ -57,12 +58,14 @@ void BaseTileTypeGenerationPass::generate_subchunk(
|
|||||||
double global_y = chunk_y * Chunk::size + local_y;
|
double global_y = chunk_y * Chunk::size + local_y;
|
||||||
|
|
||||||
// Generate base terrain noise value using uniform distribution
|
// Generate base terrain noise value using uniform distribution
|
||||||
double base_noise_value
|
double base_noise_value = base_noise_.uniform_noise(
|
||||||
= base_noise_.uniform_noise(global_x, global_y);
|
global_x, global_y
|
||||||
|
);
|
||||||
|
|
||||||
// Determine base terrain type
|
// Determine base terrain type
|
||||||
BaseTileType base_type
|
BaseTileType base_type = determine_base_type(
|
||||||
= determine_base_type(base_noise_value, properties);
|
base_noise_value, properties
|
||||||
|
);
|
||||||
|
|
||||||
// Create tile with base and surface components
|
// Create tile with base and surface components
|
||||||
Tile tile;
|
Tile tile;
|
||||||
|
274
tilemap/src/pass/smoothen_island.cpp
Normal file
274
tilemap/src/pass/smoothen_island.cpp
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
#include "biome.h"
|
||||||
|
#include "generation.h"
|
||||||
|
#include "tile.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
namespace istd {
|
||||||
|
|
||||||
|
SmoothenIslandPass::SmoothenIslandPass(
|
||||||
|
const GenerationConfig &config, Xoroshiro128PP rng
|
||||||
|
)
|
||||||
|
: config_(config), noise_(rng) {}
|
||||||
|
|
||||||
|
void SmoothenIslandPass::operator()(TileMap &tilemap) {
|
||||||
|
remove_small_island(tilemap);
|
||||||
|
for (int i = 1; i <= config_.island_smoothen_steps; ++i) {
|
||||||
|
smoothen_islands(tilemap, i);
|
||||||
|
}
|
||||||
|
remove_small_island(tilemap);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SmoothenIslandPass::is_island_tile(const Tile &tile) const {
|
||||||
|
return !(
|
||||||
|
tile.base == BaseTileType::Water || tile.base == BaseTileType::Deepwater
|
||||||
|
|| tile.base == BaseTileType::Ice
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmoothenIslandPass::remove_small_island(TileMap &tilemap) {
|
||||||
|
std::uint8_t map_size = tilemap.get_size();
|
||||||
|
std::vector<std::vector<bool>> visited(
|
||||||
|
map_size * Chunk::size, std::vector<bool>(map_size * Chunk::size, false)
|
||||||
|
);
|
||||||
|
|
||||||
|
for (std::uint8_t chunk_x = 0; chunk_x < map_size; ++chunk_x) {
|
||||||
|
for (std::uint8_t chunk_y = 0; chunk_y < map_size; ++chunk_y) {
|
||||||
|
for (std::uint8_t local_x = 0; local_x < Chunk::size; ++local_x) {
|
||||||
|
for (std::uint8_t local_y = 0; local_y < Chunk::size;
|
||||||
|
++local_y) {
|
||||||
|
TilePos pos{chunk_x, chunk_y, local_x, local_y};
|
||||||
|
auto [global_x, global_y] = pos.to_global();
|
||||||
|
|
||||||
|
// Skip if already visited
|
||||||
|
if (visited[global_x][global_y]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Tile &tile = tilemap.get_tile(pos);
|
||||||
|
if (!is_island_tile(tile)) {
|
||||||
|
visited[global_x][global_y] = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find connected component of island tiles
|
||||||
|
std::vector<TilePos> component_positions;
|
||||||
|
std::uint32_t component_size = bfs_component_size(
|
||||||
|
tilemap, pos, visited, component_positions
|
||||||
|
);
|
||||||
|
|
||||||
|
// If the component touches the boundary, skip it
|
||||||
|
bool touches_boundary = false;
|
||||||
|
for (auto component_pos : component_positions) {
|
||||||
|
if (tilemap.is_at_boundary(component_pos)) {
|
||||||
|
touches_boundary = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip if it touches the boundary
|
||||||
|
if (touches_boundary) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the component is too small, convert it to water
|
||||||
|
if (component_size <= config_.island_remove_threshold) {
|
||||||
|
for (const auto &island_pos : component_positions) {
|
||||||
|
Tile tile = tilemap.get_tile(island_pos);
|
||||||
|
tile.base = BaseTileType::Water;
|
||||||
|
tilemap.set_tile(island_pos, tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t SmoothenIslandPass::bfs_component_size(
|
||||||
|
TileMap &tilemap, TilePos start_pos,
|
||||||
|
std::vector<std::vector<bool>> &visited, std::vector<TilePos> &positions
|
||||||
|
) {
|
||||||
|
std::queue<TilePos> queue;
|
||||||
|
queue.push(start_pos);
|
||||||
|
|
||||||
|
auto [start_global_x, start_global_y] = start_pos.to_global();
|
||||||
|
visited[start_global_x][start_global_y] = true;
|
||||||
|
|
||||||
|
std::uint32_t size = 0;
|
||||||
|
positions.clear();
|
||||||
|
|
||||||
|
while (!queue.empty()) {
|
||||||
|
TilePos current = queue.front();
|
||||||
|
queue.pop();
|
||||||
|
positions.push_back(current);
|
||||||
|
++size;
|
||||||
|
|
||||||
|
// Check all neighbors
|
||||||
|
std::vector<TilePos> neighbors = tilemap.get_neighbors(current, true);
|
||||||
|
for (const auto neighbor : neighbors) {
|
||||||
|
auto [neighbor_global_x, neighbor_global_y] = neighbor.to_global();
|
||||||
|
if (visited[neighbor_global_x][neighbor_global_y]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Tile &neighbor_tile = tilemap.get_tile(neighbor);
|
||||||
|
if (is_island_tile(neighbor_tile)) {
|
||||||
|
visited[neighbor_global_x][neighbor_global_y] = true;
|
||||||
|
queue.push(neighbor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tile SmoothenIslandPass::ca_tile(
|
||||||
|
TilePos pos, Tile tile, const CACtx &ctx
|
||||||
|
) const {
|
||||||
|
constexpr std::uint8_t as_water_chance_map[9] = {
|
||||||
|
0, 0, 0, 8, 16, 32, 64, 128, 255
|
||||||
|
};
|
||||||
|
|
||||||
|
// Sand -> Water
|
||||||
|
auto as_water_chance = as_water_chance_map[ctx.adj_water];
|
||||||
|
if (as_water_chance > 0 && tile.base == BaseTileType::Sand) {
|
||||||
|
if (ctx.rand < as_water_chance) {
|
||||||
|
tile.base = BaseTileType::Water;
|
||||||
|
return tile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Water -> Sand
|
||||||
|
if (!is_island_tile(tile)) {
|
||||||
|
int as_sand_chance = std::clamp(
|
||||||
|
ctx.adj_sand * 8 + ctx.adj_land * 32, 0, 255
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ctx.rand < as_sand_chance) {
|
||||||
|
tile.base = BaseTileType::Sand;
|
||||||
|
}
|
||||||
|
return tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sand -> Land
|
||||||
|
if (tile.base == BaseTileType::Sand && ctx.biome == BiomeType::LukeOcean) {
|
||||||
|
int as_land_chance = std::clamp(
|
||||||
|
256 - ctx.adj_water * 32 - ctx.adj_sand * 12, 0, 255
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ctx.rand < as_land_chance) {
|
||||||
|
tile.base = BaseTileType::Land;
|
||||||
|
}
|
||||||
|
return tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Land -> Sand
|
||||||
|
if (tile.base == BaseTileType::Land) {
|
||||||
|
int as_sand_chance = std::clamp(
|
||||||
|
ctx.adj_water * 32 + ctx.adj_sand * 8, 0, 255
|
||||||
|
);
|
||||||
|
|
||||||
|
if (ctx.rand < as_sand_chance) {
|
||||||
|
tile.base = BaseTileType::Sand;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmoothenIslandPass::smoothen_islands_subchunk(
|
||||||
|
TileMap &tilemap, std::uint8_t chunk_x, std::uint8_t chunk_y,
|
||||||
|
SubChunkPos sub_pos, std::uint32_t step_i,
|
||||||
|
std::vector<std::pair<TilePos, Tile>> &replacements
|
||||||
|
) {
|
||||||
|
const auto &chunk = tilemap.get_chunk(chunk_x, chunk_y);
|
||||||
|
auto biome = chunk.get_biome(sub_pos);
|
||||||
|
auto biome_props = get_biome_properties(biome);
|
||||||
|
if (!biome_props.is_ocean) {
|
||||||
|
// Only process ocean biomes
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto [start_x, start_y] = subchunk_to_tile_start(sub_pos);
|
||||||
|
for (std::uint8_t local_x = start_x;
|
||||||
|
local_x < start_x + Chunk::subchunk_size; ++local_x) {
|
||||||
|
for (std::uint8_t local_y = start_y;
|
||||||
|
local_y < start_y + Chunk::subchunk_size; ++local_y) {
|
||||||
|
TilePos pos{chunk_x, chunk_y, local_x, local_y};
|
||||||
|
|
||||||
|
Tile tile = tilemap.get_tile(pos);
|
||||||
|
|
||||||
|
auto neighbors = tilemap.get_neighbors(pos, true);
|
||||||
|
if (neighbors.size() < 8) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int adj_land = 0, adj_sand = 0, adj_water = 0;
|
||||||
|
for (auto neighbor : neighbors) {
|
||||||
|
const Tile &neighbor_tile = tilemap.get_tile(neighbor);
|
||||||
|
switch (neighbor_tile.base) {
|
||||||
|
case BaseTileType::Land:
|
||||||
|
++adj_land;
|
||||||
|
break;
|
||||||
|
case BaseTileType::Sand:
|
||||||
|
++adj_sand;
|
||||||
|
break;
|
||||||
|
case BaseTileType::Water:
|
||||||
|
case BaseTileType::Deepwater:
|
||||||
|
case BaseTileType::Ice:
|
||||||
|
++adj_water;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break; // Ignore other tile types
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto [global_x, global_y] = pos.to_global();
|
||||||
|
std::uint8_t rand = noise_.noise(global_x, global_y, step_i);
|
||||||
|
|
||||||
|
CACtx ctx{
|
||||||
|
biome, rand, adj_land, adj_sand, adj_water,
|
||||||
|
};
|
||||||
|
|
||||||
|
Tile new_tile = ca_tile(pos, tile, ctx);
|
||||||
|
if (new_tile != tile) {
|
||||||
|
replacements.emplace_back(pos, new_tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto [pos, new_tile] : replacements) {
|
||||||
|
tilemap.set_tile(pos, new_tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SmoothenIslandPass::smoothen_islands(
|
||||||
|
TileMap &tilemap, std::uint32_t step_i
|
||||||
|
) {
|
||||||
|
std::vector<std::pair<TilePos, Tile>> replacements;
|
||||||
|
|
||||||
|
for (std::uint8_t chunk_x = 0; chunk_x < tilemap.get_size(); ++chunk_x) {
|
||||||
|
for (std::uint8_t chunk_y = 0; chunk_y < tilemap.get_size();
|
||||||
|
++chunk_y) {
|
||||||
|
for (std::uint8_t sub_x = 0; sub_x < Chunk::subchunk_count;
|
||||||
|
++sub_x) {
|
||||||
|
for (std::uint8_t sub_y = 0; sub_y < Chunk::subchunk_count;
|
||||||
|
++sub_y) {
|
||||||
|
SubChunkPos sub_pos{sub_x, sub_y};
|
||||||
|
smoothen_islands_subchunk(
|
||||||
|
tilemap, chunk_x, chunk_y, sub_pos, step_i, replacements
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TerrainGenerator::smoothen_islands_pass(TileMap &tilemap) {
|
||||||
|
SmoothenIslandPass pass(config_, master_rng_);
|
||||||
|
master_rng_ = master_rng_.jump_96();
|
||||||
|
pass(tilemap);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace istd
|
Loading…
x
Reference in New Issue
Block a user