docs: add developer guide for tilemap library and reduce api doc
Signed-off-by: szdytom <szdytom@qq.com>
This commit is contained in:
parent
10ef94302c
commit
2c9f25256d
@ -1,21 +1,14 @@
|
|||||||
# Tilemap Library API Documentation
|
# Tilemap Library API
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
The tilemap library provides a flexible system for generating and managing tile-based terrain with biome support. The library consists of several main components:
|
The tilemap library provides a system for generating and managing tile-based terrain with biome support.
|
||||||
|
|
||||||
- **TileMap**: The main map container holding chunks of tiles
|
|
||||||
- **Chunk**: 64x64 tile containers with biome information
|
|
||||||
- **Tile**: Individual map tiles with base and surface types
|
|
||||||
- **TerrainGenerator**: Pass-based procedural terrain generation system
|
|
||||||
- **Generation Passes**: Modular generation components (biome, base terrain, hole filling)
|
|
||||||
- **Biome System**: Climate-based terrain variation
|
|
||||||
|
|
||||||
## Core Classes
|
## Core Classes
|
||||||
|
|
||||||
### TileMap
|
### TileMap
|
||||||
|
|
||||||
The main container for the entire map, organized as an n×n grid of chunks.
|
Main container for the map, organized as chunks.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
class TileMap {
|
class TileMap {
|
||||||
@ -24,446 +17,108 @@ public:
|
|||||||
|
|
||||||
std::uint8_t get_size() const;
|
std::uint8_t get_size() const;
|
||||||
Chunk& get_chunk(std::uint8_t chunk_x, std::uint8_t chunk_y);
|
Chunk& get_chunk(std::uint8_t chunk_x, std::uint8_t chunk_y);
|
||||||
const Chunk& get_chunk(std::uint8_t chunk_x, std::uint8_t chunk_y) const;
|
|
||||||
|
|
||||||
Tile& get_tile(TilePos pos);
|
Tile& get_tile(TilePos pos);
|
||||||
const Tile& get_tile(TilePos pos) const;
|
const Tile& get_tile(TilePos pos) const;
|
||||||
void set_tile(TilePos pos, const Tile& tile);
|
void set_tile(TilePos pos, const Tile& tile);
|
||||||
|
|
||||||
bool is_at_boundary(TilePos pos) const;
|
|
||||||
std::vector<TilePos> get_neighbors(TilePos pos, bool chebyshev = false) const;
|
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
**Constructor Parameters:**
|
|
||||||
- `size`: Number of chunks per side (max 100), creating an n×n grid
|
|
||||||
|
|
||||||
**New Methods:**
|
|
||||||
- `is_at_boundary()`: Checks if a tile position is at the map boundary
|
|
||||||
- `get_neighbors()`: Returns neighboring tile positions with optional Chebyshev distance support
|
|
||||||
|
|
||||||
### Chunk
|
### Chunk
|
||||||
|
|
||||||
Each chunk contains 64×64 tiles and sub-chunk biome information.
|
64×64 tile container with biome information.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
struct Chunk {
|
struct Chunk {
|
||||||
static constexpr uint8_t size = 64; // Tiles per side
|
static constexpr uint8_t size = 64;
|
||||||
static constexpr uint8_t subchunk_size = 4; // Tiles per sub-chunk side
|
|
||||||
static constexpr uint8_t subchunk_count = size / subchunk_size; // Sub-chunks per side
|
|
||||||
|
|
||||||
Tile tiles[size][size]; // 64x64 tile grid
|
Tile tiles[size][size];
|
||||||
BiomeType biome[subchunk_count][subchunk_count]; // Sub-chunk biomes
|
BiomeType biome[16][16]; // Sub-chunk biomes
|
||||||
|
|
||||||
// Methods for biome access
|
|
||||||
BiomeType& get_biome(SubChunkPos pos);
|
BiomeType& get_biome(SubChunkPos pos);
|
||||||
const BiomeType& get_biome(SubChunkPos pos) const;
|
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### Tile
|
### Tile
|
||||||
|
|
||||||
Individual map tiles with base terrain and surface features.
|
Individual map tile with terrain types.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
struct Tile {
|
struct Tile {
|
||||||
BaseTileType base : 4; // Base terrain type
|
BaseTileType base : 4; // Base terrain
|
||||||
SurfaceTileType surface : 4; // Surface features
|
SurfaceTileType surface : 4; // Surface features
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
**Base Tile Types:**
|
**Base Tile Types:**
|
||||||
- `Land`: Standard ground terrain
|
- `Land`, `Mountain`, `Sand`, `Water`, `Ice`
|
||||||
- `Mountain`: Rocky elevated terrain
|
|
||||||
- `Sand`: Desert/beach terrain
|
|
||||||
- `Water`: Water bodies
|
|
||||||
- `Ice`: Frozen terrain
|
|
||||||
|
|
||||||
**Surface Tile Types:**
|
**Surface Tile Types:**
|
||||||
- `Empty`: No surface features
|
- `Empty`, `Wood`, `Structure`
|
||||||
- `Wood`: Trees/vegetation
|
|
||||||
- `Structure`: Player-built structures
|
|
||||||
|
|
||||||
### TilePos
|
### Position Types
|
||||||
|
|
||||||
Position structure for locating tiles within the map with enhanced coordinate conversion support.
|
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
struct TilePos {
|
struct TilePos {
|
||||||
uint8_t chunk_x; // Chunk X coordinate
|
uint8_t chunk_x, chunk_y; // Chunk coordinates
|
||||||
uint8_t chunk_y; // Chunk Y coordinate
|
uint8_t local_x, local_y; // Tile within chunk (0-63)
|
||||||
uint8_t local_x; // Tile X within chunk (0-63)
|
|
||||||
uint8_t local_y; // Tile Y within chunk (0-63)
|
|
||||||
|
|
||||||
// Coordinate conversion methods
|
|
||||||
std::pair<std::uint16_t, std::uint16_t> to_global() const;
|
std::pair<std::uint16_t, std::uint16_t> to_global() const;
|
||||||
static TilePos from_global(std::uint16_t global_x, std::uint16_t global_y);
|
static TilePos from_global(std::uint16_t global_x, std::uint16_t global_y);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Three-way comparison operator for ordering
|
|
||||||
std::strong_ordering operator<=>(const TilePos& lhs, const TilePos& rhs);
|
|
||||||
```
|
|
||||||
|
|
||||||
### SubChunkPos
|
|
||||||
|
|
||||||
Position within a chunk's sub-chunk grid.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
struct SubChunkPos {
|
struct SubChunkPos {
|
||||||
std::uint8_t sub_x;
|
std::uint8_t sub_x, sub_y;
|
||||||
std::uint8_t sub_y;
|
|
||||||
|
|
||||||
constexpr SubChunkPos(std::uint8_t x, std::uint8_t y);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::pair<std::uint8_t, std::uint8_t> subchunk_to_tile_start(
|
|
||||||
SubChunkPos pos
|
|
||||||
);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Terrain Generation
|
## Terrain Generation
|
||||||
|
|
||||||
The terrain generation system has been refactored into a modular pass-based architecture, providing better separation of concerns and more flexible generation control.
|
|
||||||
|
|
||||||
### GenerationConfig
|
### GenerationConfig
|
||||||
|
|
||||||
Configuration parameters for terrain generation.
|
Configuration for terrain generation.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
struct GenerationConfig {
|
struct GenerationConfig {
|
||||||
Seed seed; // 128-bit seed for random generation
|
Seed seed;
|
||||||
|
|
||||||
// Temperature noise parameters
|
// Noise parameters
|
||||||
double temperature_scale = 0.05; // Scale for temperature noise
|
double temperature_scale = 0.05;
|
||||||
int temperature_octaves = 3; // Number of octaves for temperature noise
|
double humidity_scale = 0.05;
|
||||||
double temperature_persistence = 0.4; // Persistence for temperature noise
|
double base_scale = 0.08;
|
||||||
|
|
||||||
// Humidity noise parameters
|
int temperature_octaves = 3;
|
||||||
double humidity_scale = 0.05; // Scale for humidity noise
|
int humidity_octaves = 3;
|
||||||
int humidity_octaves = 3; // Number of octaves for humidity noise
|
int base_octaves = 3;
|
||||||
double humidity_persistence = 0.4; // Persistence for humidity noise
|
|
||||||
|
|
||||||
// Base terrain noise parameters
|
|
||||||
double base_scale = 0.08; // Scale 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
|
|
||||||
|
|
||||||
// Mountain smoothing parameters
|
|
||||||
std::uint32_t mountain_remove_threshold = 10; // Remove mountain components smaller than this size
|
|
||||||
|
|
||||||
// Hole filling parameters
|
|
||||||
std::uint32_t fill_threshold = 10; // Fill holes smaller than this size
|
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
**Parameters:**
|
|
||||||
|
|
||||||
- `seed`: 128-bit seed for all noise generators (see Seed structure)
|
|
||||||
- `temperature_scale`: Controls the scale/frequency of temperature variation across the map
|
|
||||||
- `temperature_octaves`: Number of noise octaves for temperature (more octaves = more detail)
|
|
||||||
- `temperature_persistence`: How much each octave contributes to temperature noise (0.0-1.0)
|
|
||||||
- `humidity_scale`: Controls the scale/frequency of humidity variation across the map
|
|
||||||
- `humidity_octaves`: Number of noise octaves for humidity
|
|
||||||
- `humidity_persistence`: How much each octave contributes to humidity noise (0.0-1.0)
|
|
||||||
- `base_scale`: Controls the scale/frequency of base terrain variation across the map
|
|
||||||
- `base_octaves`: Number of noise octaves for base terrain
|
|
||||||
- `base_persistence`: How much each octave contributes to base terrain noise (0.0-1.0)
|
|
||||||
- `mountain_remove_threshold`: Maximum size of mountain components to remove for terrain smoothing
|
|
||||||
- `fill_threshold`: Maximum size of holes to fill with mountains
|
|
||||||
|
|
||||||
### Generation Passes
|
|
||||||
|
|
||||||
The generation system is organized into distinct passes, each responsible for a specific aspect of terrain generation.
|
|
||||||
|
|
||||||
#### BiomeGenerationPass
|
|
||||||
|
|
||||||
Generates biome data for all sub-chunks based on temperature and humidity noise.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
class BiomeGenerationPass {
|
|
||||||
public:
|
|
||||||
BiomeGenerationPass(
|
|
||||||
const GenerationConfig& config,
|
|
||||||
Xoroshiro128PP r1,
|
|
||||||
Xoroshiro128PP r2
|
|
||||||
);
|
|
||||||
|
|
||||||
void operator()(TileMap& tilemap);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::pair<double, double> get_climate(double global_x, double global_y) const;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- **Climate Generation**: Uses separate noise generators for temperature and humidity
|
|
||||||
- **Sub-chunk Resolution**: Assigns biomes to 16×16 sub-chunks for efficient generation
|
|
||||||
- **Climate Mapping**: Maps noise values to temperature/humidity ranges
|
|
||||||
- **Biome Determination**: Uses climate values to determine appropriate biomes
|
|
||||||
|
|
||||||
#### BaseTileTypeGenerationPass
|
|
||||||
|
|
||||||
Generates base terrain types for all tiles based on their sub-chunk biomes.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
class BaseTileTypeGenerationPass {
|
|
||||||
public:
|
|
||||||
BaseTileTypeGenerationPass(const GenerationConfig& config, Xoroshiro128PP rng);
|
|
||||||
|
|
||||||
void operator()(TileMap& tilemap);
|
|
||||||
void generate_chunk(TileMap& tilemap, std::uint8_t chunk_x, std::uint8_t chunk_y);
|
|
||||||
void generate_subchunk(
|
|
||||||
TileMap& tilemap, std::uint8_t chunk_x, std::uint8_t chunk_y,
|
|
||||||
SubChunkPos sub_pos, BiomeType biome
|
|
||||||
);
|
|
||||||
|
|
||||||
private:
|
|
||||||
BaseTileType determine_base_type(
|
|
||||||
double noise_value, const BiomeProperties& properties
|
|
||||||
) const;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- **Biome-aware Generation**: Uses biome properties to control terrain type ratios
|
|
||||||
- **Hierarchical Processing**: Processes chunks, then sub-chunks, then individual tiles
|
|
||||||
- **Noise-based Distribution**: Uses calibrated noise for balanced terrain distribution
|
|
||||||
- **Tile-level Detail**: Generates terrain at individual tile resolution
|
|
||||||
|
|
||||||
#### HoleFillPass
|
|
||||||
|
|
||||||
Fills small holes in the terrain using breadth-first search (BFS) algorithm.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
class HoleFillPass {
|
|
||||||
public:
|
|
||||||
explicit HoleFillPass(const GenerationConfig& config);
|
|
||||||
void operator()(TileMap& tilemap);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool is_passable(BaseTileType type) const;
|
|
||||||
std::uint32_t bfs_component_size(
|
|
||||||
TileMap& tilemap, TilePos start_pos,
|
|
||||||
std::vector<std::vector<bool>>& visited,
|
|
||||||
std::vector<TilePos>& positions
|
|
||||||
);
|
|
||||||
std::vector<TilePos> get_neighbors(TileMap& tilemap, TilePos pos) const;
|
|
||||||
bool is_at_boundary(TileMap& tilemap, TilePos pos) const;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- **BFS Algorithm**: Uses breadth-first search to identify connected components
|
|
||||||
- **Boundary Awareness**: Preserves holes that touch the map boundary
|
|
||||||
- **Size-based Filtering**: Only fills holes smaller than `fill_threshold`
|
|
||||||
- **Mountain-as-Impassable**: Treats mountains as impassable terrain for connectivity
|
|
||||||
- **Hole Filling**: Converts small isolated areas to mountains for cleaner terrain
|
|
||||||
|
|
||||||
#### SmoothenMountainsPass
|
|
||||||
|
|
||||||
Removes small mountain components to create smoother terrain using BFS and replacement strategies.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
class SmoothenMountainsPass {
|
|
||||||
public:
|
|
||||||
SmoothenMountainsPass(const GenerationConfig& config, Xoroshiro128PP rng);
|
|
||||||
void operator()(TileMap& tilemap);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::uint32_t bfs_component_size(
|
|
||||||
TileMap& tilemap, TilePos start_pos,
|
|
||||||
std::vector<std::vector<bool>>& visited,
|
|
||||||
std::vector<TilePos>& positions
|
|
||||||
);
|
|
||||||
void demountainize(TileMap& tilemap, const std::vector<TilePos>& positions);
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- **Mountain Component Detection**: Uses BFS to find connected mountain regions
|
|
||||||
- **Size-based Removal**: Removes mountain components smaller than `mountain_remove_threshold`
|
|
||||||
- **Boundary Preservation**: Preserves mountain components that touch the map boundary
|
|
||||||
- **Intelligent Replacement**: Replaces mountains with terrain types based on neighboring tiles
|
|
||||||
- **Smooth Terrain**: Creates more natural-looking terrain without isolated mountain clusters
|
|
||||||
|
|
||||||
### TerrainGenerator
|
|
||||||
|
|
||||||
Main orchestrator class that manages the generation process using multiple passes.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
class TerrainGenerator {
|
|
||||||
public:
|
|
||||||
explicit TerrainGenerator(const GenerationConfig& config);
|
|
||||||
void operator()(TileMap& tilemap);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void biome_pass(TileMap& tilemap);
|
|
||||||
void base_tile_type_pass(TileMap& tilemap);
|
|
||||||
void smoothen_mountains_pass(TileMap& tilemap);
|
|
||||||
void hole_fill_pass(TileMap& tilemap);
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
**Generation Order:**
|
|
||||||
1. **Biome Pass**: Generates climate-based biome data for sub-chunks
|
|
||||||
2. **Base Tile Type Pass**: Generates base terrain types based on biomes
|
|
||||||
3. **Smoothen Mountains Pass**: Removes small mountain components for smoother terrain
|
|
||||||
4. **Hole Fill Pass**: Fills small holes in the terrain
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- **Multi-pass Architecture**: Separates generation concerns for better control
|
|
||||||
- **RNG Management**: Uses independent RNGs for each pass with proper seeding
|
|
||||||
- **Deterministic Results**: Same seed produces identical terrain across runs
|
|
||||||
- **Configurable**: All passes use parameters from GenerationConfig
|
|
||||||
|
|
||||||
**Generation Flow:**
|
|
||||||
1. **Biome Pass**: Generate climate data and assign biomes to sub-chunks
|
|
||||||
2. **Base Tile Type Pass**: Generate base terrain types based on biomes and noise
|
|
||||||
3. **Hole Fill Pass**: Fill small holes in the terrain using BFS algorithm
|
|
||||||
|
|
||||||
### Generation Function
|
### Generation Function
|
||||||
|
|
||||||
Convenience function for complete map generation.
|
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
void map_generate(TileMap& tilemap, const GenerationConfig& config);
|
void map_generate(TileMap& tilemap, const GenerationConfig& config);
|
||||||
```
|
```
|
||||||
|
|
||||||
## Random Number Generation
|
|
||||||
|
|
||||||
### Seed
|
### Seed
|
||||||
|
|
||||||
128-bit seed structure for random number generation.
|
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
struct Seed {
|
struct Seed {
|
||||||
std::uint64_t s[2]; // 128-bit seed value (two 64-bit components)
|
std::uint64_t s[2];
|
||||||
|
|
||||||
static Seed from_string(const char* str); // Create seed from string
|
static Seed from_string(const char* str);
|
||||||
static Seed device_random(); // Create seed from hardware random device
|
static Seed device_random();
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
**Key Features:**
|
## Biomes
|
||||||
- **128-bit precision**: Uses two 64-bit integers for extended seed space
|
|
||||||
- **String generation**: Deterministic seed creation from text strings
|
|
||||||
- **Hardware random**: True random seed generation using system entropy
|
|
||||||
|
|
||||||
### Xoroshiro128++
|
|
||||||
|
|
||||||
High-performance random number generator using the Xoroshiro128++ algorithm.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
class Xoroshiro128PP {
|
|
||||||
public:
|
|
||||||
Xoroshiro128PP() = default;
|
|
||||||
Xoroshiro128PP(Seed seed);
|
|
||||||
|
|
||||||
// STL RandomEngine interface
|
|
||||||
using result_type = std::uint64_t;
|
|
||||||
static constexpr result_type min();
|
|
||||||
static constexpr result_type max();
|
|
||||||
result_type operator()();
|
|
||||||
|
|
||||||
std::uint64_t next(); // Generate next random number
|
|
||||||
Xoroshiro128PP jump_64() const; // Jump equivalent to 2^64 calls
|
|
||||||
Xoroshiro128PP jump_96() const; // Jump equivalent to 2^96 calls
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- **High Performance**: Optimized for speed with excellent statistical properties
|
|
||||||
- **128-bit State**: Internal state provides long period (2^128 - 1)
|
|
||||||
- **Jump Functions**: Enable parallel random number generation
|
|
||||||
- **STL Compatible**: Implements standard random engine interface
|
|
||||||
|
|
||||||
## Noise System
|
|
||||||
|
|
||||||
### DiscreteRandomNoise
|
|
||||||
|
|
||||||
Discrete random noise generator using Xoroshiro128++ for terrain replacement operations.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
class DiscreteRandomNoise {
|
|
||||||
public:
|
|
||||||
explicit DiscreteRandomNoise(Xoroshiro128PP rng);
|
|
||||||
std::uint64_t noise(std::uint32_t x, std::uint32_t y, std::uint32_t z = 0) const;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- **Discrete Output**: Produces integer values for discrete selections
|
|
||||||
- **High Quality**: Based on Xoroshiro128++ random number generation
|
|
||||||
- **3D Support**: Supports optional Z coordinate for 3D noise
|
|
||||||
- **Fast**: Optimized for performance in terrain processing
|
|
||||||
|
|
||||||
### PerlinNoise
|
|
||||||
|
|
||||||
Standard Perlin noise implementation using Xoroshiro128++ for procedural generation.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
class PerlinNoise {
|
|
||||||
public:
|
|
||||||
explicit PerlinNoise(Xoroshiro128PP rng);
|
|
||||||
double noise(double x, double y) const;
|
|
||||||
double octave_noise(double x, double y, int octaves = 4, double persistence = 0.5) const;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### UniformPerlinNoise
|
|
||||||
|
|
||||||
Advanced noise generator using Xoroshiro128++ that provides uniform distribution mapping.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
class UniformPerlinNoise {
|
|
||||||
public:
|
|
||||||
explicit UniformPerlinNoise(Xoroshiro128PP rng);
|
|
||||||
void calibrate(double scale, int octaves = 1, double persistence = 0.5, int sample_size = 10000);
|
|
||||||
double uniform_noise(double x, double y) const;
|
|
||||||
bool is_calibrated() const;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- **Calibration**: Samples noise distribution to build CDF
|
|
||||||
- **Uniform Mapping**: Maps raw Perlin values to uniform [0,1] distribution
|
|
||||||
- **Balanced Output**: Ensures even distribution across all value ranges
|
|
||||||
- **Automatic Use**: TerrainGenerator uses this internally for balanced terrain
|
|
||||||
- **Xoroshiro128++ Backend**: Uses high-quality random number generation
|
|
||||||
|
|
||||||
## Biome System
|
|
||||||
|
|
||||||
### BiomeType
|
### BiomeType
|
||||||
|
|
||||||
Available biome types based on temperature and humidity.
|
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
enum class BiomeType : std::uint8_t {
|
enum class BiomeType : std::uint8_t {
|
||||||
SnowyPeeks, // Cold & Dry
|
SnowyPeaks, SnowyPlains, FrozenOcean,
|
||||||
SnowyPlains, // Cold & Moderate
|
Plains, Forest, Ocean,
|
||||||
FrozenOcean, // Cold & Wet
|
Desert, Savanna, LukeOcean
|
||||||
Plains, // Temperate & Dry
|
|
||||||
Forest, // Temperate & Moderate
|
|
||||||
Ocean, // Temperate & Wet
|
|
||||||
Desert, // Hot & Dry
|
|
||||||
Savanna, // Hot & Moderate
|
|
||||||
LukeOcean, // Hot & Wet
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### BiomeProperties
|
|
||||||
|
|
||||||
Properties that control terrain generation for each biome.
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
struct BiomeProperties {
|
|
||||||
std::string_view name; // Biome name
|
|
||||||
double water_ratio; // Water generation ratio
|
|
||||||
double ice_ratio; // Ice generation ratio
|
|
||||||
double sand_ratio; // Sand generation ratio
|
|
||||||
double land_ratio; // Land generation ratio
|
|
||||||
int base_octaves = 3; // Noise octaves
|
|
||||||
double base_persistence = 0.5; // Noise persistence
|
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -476,201 +131,32 @@ BiomeType determine_biome(double temperature, double humidity);
|
|||||||
|
|
||||||
## Usage Examples
|
## Usage Examples
|
||||||
|
|
||||||
### Basic Map Generation
|
### Basic Usage
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
#include "tilemap.h"
|
#include "tilemap.h"
|
||||||
#include "generation.h"
|
#include "generation.h"
|
||||||
|
|
||||||
// Create a 4x4 chunk map
|
// Create map
|
||||||
istd::TileMap tilemap(4);
|
istd::TileMap tilemap(4); // 4x4 chunks
|
||||||
|
|
||||||
// Configure generation
|
|
||||||
istd::GenerationConfig config;
|
|
||||||
config.seed = istd::Seed::from_string("hello_world"); // 128-bit seed from string
|
|
||||||
|
|
||||||
// Temperature noise settings
|
|
||||||
config.temperature_scale = 0.05;
|
|
||||||
config.temperature_octaves = 3;
|
|
||||||
config.temperature_persistence = 0.4;
|
|
||||||
|
|
||||||
// Humidity noise settings
|
|
||||||
config.humidity_scale = 0.05;
|
|
||||||
config.humidity_octaves = 3;
|
|
||||||
config.humidity_persistence = 0.4;
|
|
||||||
|
|
||||||
// Base terrain noise settings
|
|
||||||
config.base_scale = 0.08;
|
|
||||||
config.base_octaves = 3;
|
|
||||||
config.base_persistence = 0.5;
|
|
||||||
|
|
||||||
// Mountain smoothing settings
|
|
||||||
config.mountain_remove_threshold = 10; // Remove mountain components smaller than 10 tiles
|
|
||||||
|
|
||||||
// Hole filling settings
|
|
||||||
config.fill_threshold = 10; // Fill holes smaller than 10 tiles
|
|
||||||
|
|
||||||
// Generate terrain
|
// Generate terrain
|
||||||
|
istd::GenerationConfig config;
|
||||||
|
config.seed = istd::Seed::from_string("my_world");
|
||||||
istd::map_generate(tilemap, config);
|
istd::map_generate(tilemap, config);
|
||||||
|
|
||||||
// Access tiles
|
// Access tiles
|
||||||
for (int chunk_y = 0; chunk_y < tilemap.get_size(); ++chunk_y) {
|
istd::TilePos pos{0, 0, 32, 32}; // Chunk (0,0), tile (32,32)
|
||||||
for (int chunk_x = 0; chunk_x < tilemap.get_size(); ++chunk_x) {
|
|
||||||
const auto& chunk = tilemap.get_chunk(chunk_x, chunk_y);
|
|
||||||
// Process chunk tiles...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Advanced Generation with Custom Passes
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#include "tilemap.h"
|
|
||||||
#include "generation.h"
|
|
||||||
|
|
||||||
// Create map and config
|
|
||||||
istd::TileMap tilemap(2);
|
|
||||||
istd::GenerationConfig config;
|
|
||||||
config.seed = istd::Seed::from_string("custom_world");
|
|
||||||
|
|
||||||
// Use TerrainGenerator for step-by-step control
|
|
||||||
istd::TerrainGenerator generator(config);
|
|
||||||
|
|
||||||
// Generate terrain (runs both biome and base tile passes)
|
|
||||||
generator(tilemap);
|
|
||||||
|
|
||||||
// Access biome data
|
|
||||||
const auto& chunk = tilemap.get_chunk(0, 0);
|
|
||||||
for (int sub_y = 0; sub_y < istd::Chunk::subchunk_count; ++sub_y) {
|
|
||||||
for (int sub_x = 0; sub_x < istd::Chunk::subchunk_count; ++sub_x) {
|
|
||||||
istd::SubChunkPos pos(sub_x, sub_y);
|
|
||||||
istd::BiomeType biome = chunk.get_biome(pos);
|
|
||||||
const auto& props = istd::get_biome_properties(biome);
|
|
||||||
// Process biome...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
```
|
|
||||||
|
|
||||||
### Seed Usage Examples
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// Create seed from string (deterministic)
|
|
||||||
istd::Seed seed1 = istd::Seed::from_string("my_world");
|
|
||||||
|
|
||||||
// Create random seed from hardware
|
|
||||||
istd::Seed seed2 = istd::Seed::device_random();
|
|
||||||
|
|
||||||
// Manual seed creation
|
|
||||||
istd::Seed seed3;
|
|
||||||
seed3.s[0] = 0x123456789abcdef0;
|
|
||||||
seed3.s[1] = 0xfedcba9876543210;
|
|
||||||
|
|
||||||
// Use seed in generation
|
|
||||||
istd::GenerationConfig config;
|
|
||||||
config.seed = seed1;
|
|
||||||
```
|
|
||||||
|
|
||||||
### Accessing Individual Tiles
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// Using TilePos
|
|
||||||
istd::TilePos pos{0, 0, 32, 32}; // Chunk (0,0), tile (32,32)
|
|
||||||
const auto& tile = tilemap.get_tile(pos);
|
const auto& tile = tilemap.get_tile(pos);
|
||||||
|
|
||||||
// Direct chunk access
|
|
||||||
const auto& chunk = tilemap.get_chunk(0, 0);
|
|
||||||
const auto& tile2 = chunk.tiles[32][32];
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Working with Biomes
|
### Working with Biomes
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
// Method 1: Direct array access (traditional way)
|
|
||||||
const auto& chunk = tilemap.get_chunk(0, 0);
|
const auto& chunk = tilemap.get_chunk(0, 0);
|
||||||
istd::BiomeType biome = chunk.biome[1][1]; // Sub-chunk (1,1)
|
istd::SubChunkPos sub_pos(1, 1);
|
||||||
|
istd::BiomeType biome = chunk.get_biome(sub_pos);
|
||||||
|
|
||||||
// Method 2: Using SubChunkPos and get_biome method (recommended)
|
|
||||||
istd::SubChunkPos pos(1, 1); // Sub-chunk (1,1)
|
|
||||||
istd::BiomeType biome2 = chunk.get_biome(pos);
|
|
||||||
|
|
||||||
// Modify biome using the new method
|
|
||||||
auto& mutable_chunk = tilemap.get_chunk(0, 0);
|
|
||||||
mutable_chunk.get_biome(pos) = istd::BiomeType::Forest;
|
|
||||||
|
|
||||||
// Get biome properties
|
|
||||||
const auto& props = istd::get_biome_properties(biome);
|
const auto& props = istd::get_biome_properties(biome);
|
||||||
std::cout << "Biome: " << props.name << std::endl;
|
std::cout << "Biome: " << props.name << std::endl;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Performance Notes
|
|
||||||
|
|
||||||
- Each chunk contains 4,096 tiles (64×64)
|
|
||||||
- Sub-chunks provide efficient biome management
|
|
||||||
- Tiles are packed into 1 byte each for memory efficiency
|
|
||||||
- Generation uses Xoroshiro128++ random number generator with uniform distribution mapping for balanced terrain
|
|
||||||
- Noise calibration is performed once during generator construction
|
|
||||||
- 128-bit seeds provide excellent randomness and reproducibility
|
|
||||||
|
|
||||||
## Noise Distribution
|
|
||||||
|
|
||||||
The library uses an advanced noise system based on Xoroshiro128++ random number generation that addresses the non-uniform distribution of Perlin noise:
|
|
||||||
|
|
||||||
### Problem with Raw Perlin Noise
|
|
||||||
|
|
||||||
Raw Perlin noise follows a bell-curve distribution, with most values concentrated around 0.5. This leads to unbalanced terrain generation where certain tile types (like Land) dominate the map.
|
|
||||||
|
|
||||||
### Solution: Xoroshiro128++ + Uniform Distribution Mapping
|
|
||||||
|
|
||||||
The library combines two key improvements:
|
|
||||||
|
|
||||||
1. **Xoroshiro128++ RNG**: High-quality pseudo-random number generator with:
|
|
||||||
- **Long Period**: 2^128 - 1 sequence length before repetition
|
|
||||||
- **High Performance**: Optimized for speed and memory efficiency
|
|
||||||
- **Excellent Statistics**: Passes rigorous randomness tests
|
|
||||||
- **128-bit State**: Two 64-bit values providing extensive seed space
|
|
||||||
|
|
||||||
2. **Uniform Distribution Mapping**: The `UniformPerlinNoise` class:
|
|
||||||
- **Samples** the noise distribution during calibration
|
|
||||||
- **Builds a CDF** (Cumulative Distribution Function) from the samples
|
|
||||||
- **Maps raw noise values** to uniform [0,1] distribution using quantiles
|
|
||||||
- **Ensures balanced** terrain type distribution according to biome properties
|
|
||||||
|
|
||||||
### Usage in Terrain Generation
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
// The terrain generator automatically uses Xoroshiro128++ and uniform noise
|
|
||||||
istd::Seed seed = istd::Seed::from_string("consistent_world");
|
|
||||||
istd::GenerationConfig config;
|
|
||||||
config.seed = seed;
|
|
||||||
|
|
||||||
// TerrainGenerator handles pass coordination and RNG management
|
|
||||||
istd::TerrainGenerator generator(config);
|
|
||||||
generator(tilemap); // Uses calibrated uniform noise with Xoroshiro128++
|
|
||||||
|
|
||||||
// Or use the convenience function
|
|
||||||
istd::map_generate(tilemap, config);
|
|
||||||
```
|
|
||||||
|
|
||||||
### Pass-based Architecture Benefits
|
|
||||||
|
|
||||||
The new pass-based system provides:
|
|
||||||
|
|
||||||
1. **Separation of Concerns**: Each pass handles a specific aspect of generation
|
|
||||||
2. **RNG Independence**: Each pass uses independent random number generators
|
|
||||||
3. **Reproducible Results**: Same seed produces identical results across passes
|
|
||||||
4. **Extensibility**: Easy to add new passes or modify existing ones
|
|
||||||
5. **Performance**: Efficient memory access patterns and reduced redundant calculations
|
|
||||||
6. **Terrain Quality**: SmoothenMountainsPass creates more natural-looking terrain
|
|
||||||
|
|
||||||
### Recent Improvements
|
|
||||||
|
|
||||||
**Mountain Smoothing**: The new `SmoothenMountainsPass` removes small isolated mountain components to create more natural terrain formations. Small mountain clusters that don't connect to the boundary are replaced with terrain types based on their neighboring areas.
|
|
||||||
|
|
||||||
**Enhanced TileMap**: Added utility methods for boundary detection and neighbor finding, supporting both Manhattan and Chebyshev distance calculations.
|
|
||||||
|
|
||||||
**Improved Noise**: Added `DiscreteRandomNoise` for high-quality discrete value generation used in terrain replacement operations.
|
|
||||||
|
|
||||||
## Thread Safety
|
|
||||||
|
|
||||||
The library is not inherently thread-safe. External synchronization is required for concurrent access to TileMap objects.
|
|
||||||
|
209
tilemap/docs/dev.md
Normal file
209
tilemap/docs/dev.md
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
# Tilemap Library Developer Guide
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
The tilemap library is a C++ terrain generation system that creates tile-based worlds with biome support. It uses a multi-pass generation pipeline to create realistic, balanced terrain.
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
tilemap/
|
||||||
|
├── include/ # Public headers
|
||||||
|
│ ├── tilemap.h # Main map container
|
||||||
|
│ ├── chunk.h # 64x64 tile chunks
|
||||||
|
│ ├── tile.h # Individual tile types
|
||||||
|
│ ├── generation.h # Generation system
|
||||||
|
│ ├── biome.h # Biome system
|
||||||
|
│ ├── noise.h # Noise generators
|
||||||
|
│ └── xoroshiro.h # RNG implementation
|
||||||
|
├── src/ # Implementation files
|
||||||
|
│ ├── tilemap.cpp # TileMap implementation
|
||||||
|
│ ├── chunk.cpp # Chunk utilities
|
||||||
|
│ ├── generation.cpp # Main generation orchestrator
|
||||||
|
│ ├── biome.cpp # Biome mapping logic
|
||||||
|
│ ├── noise.cpp # Noise implementations
|
||||||
|
│ ├── xoroshiro.cpp # Xoroshiro128++ RNG
|
||||||
|
│ └── pass/ # Generation passes
|
||||||
|
│ ├── biome.cpp # Climate-based biome generation
|
||||||
|
│ ├── base_tile_type.cpp # Base terrain generation
|
||||||
|
│ ├── smoothen_mountain.cpp # Mountain smoothing
|
||||||
|
│ ├── mountain_hole_fill.cpp # Hole filling
|
||||||
|
│ └── deepwater.cpp # Deep water placement
|
||||||
|
├── examples/ # Usage examples
|
||||||
|
└── docs/ # Documentation
|
||||||
|
```
|
||||||
|
|
||||||
|
## Core Architecture
|
||||||
|
|
||||||
|
### Data Organization
|
||||||
|
|
||||||
|
The system uses a hierarchical structure:
|
||||||
|
- **TileMap**: n×n grid of chunks
|
||||||
|
- **Chunk**: 64×64 tiles with biome metadata
|
||||||
|
- **Tile**: Individual terrain cell (1 byte packed)
|
||||||
|
|
||||||
|
Each chunk also contains a 16×16 grid of sub-chunk biomes, providing efficient biome lookup without per-tile storage.
|
||||||
|
|
||||||
|
### Pass-Based Generation
|
||||||
|
|
||||||
|
Terrain generation uses a multi-pass pipeline for modularity and control:
|
||||||
|
|
||||||
|
1. **Biome Pass**: Generates climate data and assigns biomes to sub-chunks
|
||||||
|
2. **Base Tile Type Pass**: Creates base terrain based on biomes
|
||||||
|
3. **Mountain Smoothing Pass**: Removes isolated mountain clusters
|
||||||
|
4. **Hole Fill Pass**: Fills small terrain holes
|
||||||
|
5. **Deep Water Pass**: Places deep water areas
|
||||||
|
|
||||||
|
Each pass operates independently with its own RNG state, ensuring deterministic results.
|
||||||
|
|
||||||
|
## Terrain Generation Pipeline
|
||||||
|
|
||||||
|
### Climate Generation
|
||||||
|
|
||||||
|
The biome pass uses dual noise generators for temperature and humidity:
|
||||||
|
- Separate Perlin noise for temperature/humidity at sub-chunk resolution
|
||||||
|
- Climate values mapped to 9 biome types in a 3×3 grid
|
||||||
|
- Sub-chunks store biome data for efficient terrain generation
|
||||||
|
|
||||||
|
### Noise System
|
||||||
|
|
||||||
|
The library addresses Perlin noise distribution issues:
|
||||||
|
- **Problem**: Raw Perlin noise has bell-curve distribution
|
||||||
|
- **Solution**: UniformPerlinNoise calibrates distribution to uniform [0,1]
|
||||||
|
- **Result**: Balanced terrain type ratios according to biome properties
|
||||||
|
|
||||||
|
### Terrain Generation Process
|
||||||
|
|
||||||
|
1. **Climate Sampling**: Sample temperature/humidity at sub-chunk centers
|
||||||
|
2. **Biome Assignment**: Map climate values to biome types
|
||||||
|
3. **Terrain Generation**: Generate tiles based on biome properties and noise
|
||||||
|
4. **Post-processing**: Apply smoothing and hole-filling algorithms
|
||||||
|
|
||||||
|
### Connected Component Analysis
|
||||||
|
|
||||||
|
Several passes use BFS (Breadth-First Search) for terrain analysis:
|
||||||
|
- **Mountain Smoothing**: Find and remove small mountain components
|
||||||
|
- **Hole Filling**: Identify and fill isolated terrain holes
|
||||||
|
- Components touching map boundaries are preserved
|
||||||
|
|
||||||
|
## Random Number Generation
|
||||||
|
|
||||||
|
### Xoroshiro128++ Implementation
|
||||||
|
|
||||||
|
High-quality PRNG with excellent statistical properties:
|
||||||
|
- 128-bit internal state
|
||||||
|
- Period of 2^128 - 1
|
||||||
|
- Jump functions for parallel generation
|
||||||
|
- STL-compatible interface
|
||||||
|
|
||||||
|
### Seed Management
|
||||||
|
|
||||||
|
128-bit seeds provide extensive randomness:
|
||||||
|
- String-based deterministic seed creation
|
||||||
|
- Hardware random seed generation
|
||||||
|
- Independent RNG streams for each generation pass
|
||||||
|
|
||||||
|
## Biome System
|
||||||
|
|
||||||
|
### Climate Mapping
|
||||||
|
|
||||||
|
Biomes are determined by temperature/humidity combinations:
|
||||||
|
```
|
||||||
|
Dry Moderate Wet
|
||||||
|
Cold Snowy Snowy Frozen
|
||||||
|
Peaks Plains Ocean
|
||||||
|
Temp Plains Forest Ocean
|
||||||
|
Hot Desert Savanna Luke Ocean
|
||||||
|
```
|
||||||
|
|
||||||
|
### Biome Properties
|
||||||
|
|
||||||
|
Each biome defines terrain generation ratios:
|
||||||
|
- Water/Ice/Sand/Land ratios
|
||||||
|
- Noise parameters (octaves, persistence)
|
||||||
|
- Used by base terrain generation pass
|
||||||
|
|
||||||
|
## Performance Considerations
|
||||||
|
|
||||||
|
### Memory Layout
|
||||||
|
|
||||||
|
- Tiles packed into 1 byte (4 bits base + 4 bits surface)
|
||||||
|
- Chunks use contiguous 64×64 arrays for cache efficiency
|
||||||
|
- Sub-chunk biomes reduce memory overhead vs per-tile storage
|
||||||
|
|
||||||
|
### Generation Efficiency
|
||||||
|
|
||||||
|
- Sub-chunk resolution for biome generation (16×16 vs 64×64)
|
||||||
|
- Single-pass algorithms where possible
|
||||||
|
- Efficient connected component analysis using BFS
|
||||||
|
|
||||||
|
### Determinism
|
||||||
|
|
||||||
|
- Same seed produces identical results
|
||||||
|
- Independent RNG streams prevent cross-pass contamination
|
||||||
|
- Floating-point operations use consistent precision
|
||||||
|
|
||||||
|
## Adding New Generation Passes
|
||||||
|
|
||||||
|
To add a new generation pass:
|
||||||
|
|
||||||
|
1. **Create Pass Implementation**: Add new file in `src/pass/`
|
||||||
|
2. **Add to Pipeline**: Update `TerrainGenerator::operator()`
|
||||||
|
3. **RNG Management**: Use jump functions for independent RNG streams
|
||||||
|
4. **Configuration**: Add parameters to `GenerationConfig` if needed
|
||||||
|
|
||||||
|
Example pass structure:
|
||||||
|
```cpp
|
||||||
|
void TerrainGenerator::my_custom_pass(TileMap &tilemap) {
|
||||||
|
auto rng = master_rng_.jump_96(); // Independent RNG stream
|
||||||
|
|
||||||
|
// Process tilemap...
|
||||||
|
for (auto chunk_y = 0; chunk_y < tilemap.get_size(); ++chunk_y) {
|
||||||
|
for (auto chunk_x = 0; chunk_x < tilemap.get_size(); ++chunk_x) {
|
||||||
|
auto& chunk = tilemap.get_chunk(chunk_x, chunk_y);
|
||||||
|
// Process chunk...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing and Validation
|
||||||
|
|
||||||
|
### Determinism Testing
|
||||||
|
|
||||||
|
Verify same seed produces identical output across runs:
|
||||||
|
```cpp
|
||||||
|
auto seed = Seed::from_string("test");
|
||||||
|
TileMap map1(4), map2(4);
|
||||||
|
map_generate(map1, {seed});
|
||||||
|
map_generate(map2, {seed});
|
||||||
|
// Verify map1 == map2
|
||||||
|
```
|
||||||
|
|
||||||
|
### Distribution Analysis
|
||||||
|
|
||||||
|
Check terrain type distributions match biome properties:
|
||||||
|
- Count tile types per biome
|
||||||
|
- Verify ratios within acceptable tolerance
|
||||||
|
- Test with multiple seeds for statistical significance
|
||||||
|
|
||||||
|
### Visual Validation
|
||||||
|
|
||||||
|
Export maps to image formats for visual inspection:
|
||||||
|
- Check for realistic terrain patterns
|
||||||
|
- Verify biome transitions look natural
|
||||||
|
- Ensure no artifacts from generation passes
|
||||||
|
|
||||||
|
## Future Extensions
|
||||||
|
|
||||||
|
### Potential Improvements
|
||||||
|
|
||||||
|
- **Surface Feature Generation**: Trees, structures, resources
|
||||||
|
- **Elevation System**: Height maps for 3D terrain
|
||||||
|
- **River Generation**: Connected water systems
|
||||||
|
- **Chunk Streaming**: Dynamic loading for large worlds
|
||||||
|
- **Multithreading**: Parallel chunk generation
|
||||||
|
|
||||||
|
### API Stability
|
||||||
|
|
||||||
|
Core interfaces (TileMap, Chunk, Tile) are stable. Generation system is designed for extensibility without breaking existing code.
|
Loading…
x
Reference in New Issue
Block a user