TerrainGenerator.Terrain (terrain_generator v0.3.1)

Copy Markdown View Source

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, 1 where a river runs
  • :lakes — one byte per cell, 1 where a lake holds standing water
  • :ocean — one byte per cell, 1 where 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

t()

@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

flow_accumulation_at(t, x, y)

@spec flow_accumulation_at(t(), non_neg_integer(), non_neg_integer()) :: float()

Raw upstream catchment at {x, y}, in cells.

flow_at(t, x, y)

@spec flow_at(t(), non_neg_integer(), non_neg_integer()) :: float()

Log-normalised flow accumulation at {x, y}, in [0, 1].

height_at(t, x, y)

@spec height_at(t(), non_neg_integer(), non_neg_integer()) :: float()

Elevation at {x, y}, in [0, 1].

heightmap_list(t)

@spec heightmap_list(t()) :: [float()]

The heightmap as a flat list of floats, row by row.

Convenient for exploration, but for large maps prefer working with the binary directly.

lake?(t, x, y)

@spec lake?(t(), non_neg_integer(), non_neg_integer()) :: boolean()

Whether {x, y} lies in a lake.

ocean?(t, x, y)

@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.

river?(t, x, y)

@spec river?(t(), non_neg_integer(), non_neg_integer()) :: boolean()

Whether a river runs through {x, y}.

water?(t, 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.