A generated terrain.
All per-cell buffers are row-major binaries indexed as y * width + x:
:heightmap— 32-bit little-endian floats, elevation in[0, 1]:flow— 32-bit little-endian floats, log-normalised flow accumulation in[0, 1](a useful moisture proxy):flow_accumulation— 32-bit little-endian floats, raw upstream catchment in cells (each cell contributes 1); use this to size channels:rivers— one byte per cell,1where a river runs:lakes— one byte per cell,1where a lake holds standing water:ocean— one byte per cell,1where the cell is sea, meaning at or below sea level and connected to the map border. A basin below sea level that is cut off from the sea is a lake, not ocean.
Binaries are cheap to pass around (they live outside the BEAM heap) and can be consumed wholesale — e.g. uploaded to a GPU or sent over a socket — or queried per cell with the accessors below.
Summary
Functions
Raw upstream catchment at {x, y}, in cells.
Log-normalised flow accumulation at {x, y}, in [0, 1].
Elevation at {x, y}, in [0, 1].
The heightmap as a flat list of floats, row by row.
Whether {x, y} lies in a lake.
Whether {x, y} is ocean: at or below sea level and connected to the map
border. Enclosed low ground is not ocean.
Whether a river runs through {x, y}.
Whether {x, y} is covered by water of any kind: ocean, lake or river.
Types
@type t() :: %TerrainGenerator.Terrain{ flow: binary(), flow_accumulation: binary(), height: pos_integer(), heightmap: binary(), lakes: binary(), ocean: binary(), rivers: binary(), sea_level: float(), width: pos_integer() }
Functions
@spec flow_accumulation_at(t(), non_neg_integer(), non_neg_integer()) :: float()
Raw upstream catchment at {x, y}, in cells.
@spec flow_at(t(), non_neg_integer(), non_neg_integer()) :: float()
Log-normalised flow accumulation at {x, y}, in [0, 1].
@spec height_at(t(), non_neg_integer(), non_neg_integer()) :: float()
Elevation at {x, y}, in [0, 1].
The heightmap as a flat list of floats, row by row.
Convenient for exploration, but for large maps prefer working with the binary directly.
@spec lake?(t(), non_neg_integer(), non_neg_integer()) :: boolean()
Whether {x, y} lies in a lake.
@spec ocean?(t(), non_neg_integer(), non_neg_integer()) :: boolean()
Whether {x, y} is ocean: at or below sea level and connected to the map
border. Enclosed low ground is not ocean.
@spec river?(t(), non_neg_integer(), non_neg_integer()) :: boolean()
Whether a river runs through {x, y}.
@spec water?(t(), non_neg_integer(), non_neg_integer()) :: boolean()
Whether {x, y} is covered by water of any kind: ocean, lake or river.
This is a union of the three masks, not an elevation test — a closed basin below sea level counts as lake, not ocean.