1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
//! Procedural terrain generation with fractal noise, hydraulic erosion and
//! river extraction.
//!
//! The pipeline runs in five stages; everything after the first is
//! optional:
//!
//! 1. **Base heightmap** — fractal (fBm) OpenSimplex noise via the
//! [`noise`] crate.
//! 2. **Land mask** — either a single radial island
//! ([`IslandParams`]) or an archipelago of several
//! ([`ArchipelagoParams`]), both with noise-perturbed coastlines.
//! 3. **Hydraulic erosion** — a particle/droplet simulation that carves
//! valleys and drainage networks into the terrain.
//! 4. **Basin breaching** *(opt-in)* — cuts outlets through the rims of
//! oversized closed basins so they drain instead of becoming inland
//! seas. See [`TerrainBuilder::breach_basins`].
//! 5. **Hydrology** — depressions are filled (priority-flood), then D8
//! flow routing; cells with enough upstream catchment become rivers,
//! filled depressions become lakes, and border-connected sea becomes
//! the [`ocean`](Terrain::ocean) mask.
//!
//! # Quick start
//!
//! ```no_run
//! use terrain_generator::{RenderStyle, Terrain};
//!
//! let terrain = Terrain::builder()
//! .size(512, 512)
//! .seed(42)
//! .generate();
//!
//! terrain.save_png("map.png", RenderStyle::Shaded).unwrap();
//!
//! // raw data access for games/simulations:
//! let h = terrain.heightmap[(100, 100)]; // elevation in [0, 1]
//! let wet = terrain.flow_at(100, 100); // moisture proxy in [0, 1]
//! let catchment = terrain.flow_accumulation_at(100, 100); // cells upstream
//! let river = terrain.is_river(100, 100);
//! # let _ = (h, wet, catchment, river);
//! ```
//!
//! # What this crate does and does not decide
//!
//! The output is a set of raw, independent layers: elevation, flow
//! accumulation, and river/lake/ocean masks. It deliberately stops short
//! of gameplay or domain semantics — there is no "drinkable", no biome
//! enum, no navigability. Anything that is a judgement call is either a
//! parameter (how dense are rivers? how big may a lake be?) or derivable
//! from the raw layers, so a consumer can substitute its own rules.
//!
//! Consumers that bring their own hydrology should use
//! [`TerrainBuilder::no_rivers`], which skips flow routing entirely and
//! leaves [`Terrain::heightmap`] as the single source of truth.
//!
//! # Data model
//!
//! All per-cell outputs are [`Grid`]s: dense row-major buffers indexed as
//! `grid[(x, y)]`, with the flat storage available via [`Grid::as_slice`]
//! for zero-copy hand-off to FFI, GPUs or file formats.
//!
//! # Determinism
//!
//! The same seed and parameters produce the same terrain, run after run.
//! Ordering that could otherwise vary — the flow-routing sort and both
//! priority queues — is broken by cell index, so no result depends on
//! sort or heap internals.
//!
//! Two caveats worth knowing before you persist a world as a seed:
//!
//! * **Pin the version.** The base noise comes from the [`noise`] crate,
//! and tuning inside this crate also changes output. If you regenerate
//! terrain from a stored seed, depend on an exact tag or revision and
//! commit your `Cargo.lock`; treat any change to the generated output as
//! a breaking change on your side.
//! * **`flow` uses a transcendental.** [`Terrain::flow`] is log-normalised
//! with `f32::ln`, whose last-bit rounding is not guaranteed identical
//! across platforms and libm implementations. Every other layer —
//! heightmap, [`flow_accumulation`](Terrain::flow_accumulation), rivers,
//! lakes, ocean — is computed with IEEE-exact operations only
//! (`+ - * /`, `sqrt`, comparisons), so those are reproducible
//! bit-for-bit everywhere. If you need cross-platform exactness for
//! moisture, derive it from `flow_accumulation` yourself.
//!
//! # Cargo features
//!
//! * `png` *(default)* — PNG output ([`Terrain::save_png`],
//! [`Terrain::save_layer_png`]); pulls in the
//! [`png`](https://crates.io/crates/png) crate. [`Terrain::to_rgb`]
//! works without it.
//! * `cli` *(default)* — the `terrain-generator` command-line binary;
//! pulls in `clap` and implies `png`. Library consumers should use
//! `default-features = false`, which leaves `noise` as the only
//! dependency.
pub use Grid;
pub use ocean_mask;
pub use RenderError;
pub use ;
pub use ;