Packages

Work with different noise functions using Elixir. Fork of isotope, maintained for Elixir 1.18+.

Current section

Files

Jump to
isotope_118 lib noise.ex
Raw

lib/noise.ex

defmodule Isotope.Noise do
@moduledoc """
Create noise generators, sample individual points, and generate noise maps.
## Creating a Noise Generator
All noise operations require a noise reference, created with `new/0` or `new/1`:
{:ok, noise} = Isotope.Noise.new()
{:ok, noise} = Isotope.Noise.new(%Isotope.Options{
seed: 42,
noise_type: :perlin_fractal,
frequency: 0.02,
fractal_options: %Isotope.Options.Fractal{octaves: 6, gain: 0.5}
})
## Generating Noise Maps
`noise_map/2` generates a full map starting at the origin. `chunk/4` generates
a region starting at an arbitrary coordinate, useful for tiling or infinite worlds:
nm = Isotope.Noise.noise_map(noise, {256, 256})
chunk = Isotope.Noise.chunk(noise, {512, 512}, 256, 256)
Both return an `%Isotope.NoiseMap{}` struct. See `Isotope.NoiseMap` for accessors.
## Sampling Individual Points
Use `get_noise/2` with a 2D or 3D coordinate tuple:
value = Isotope.Noise.get_noise(noise, {1.5, 2.5})
value = Isotope.Noise.get_noise(noise, {1.5, 2.5, 3.5})
Coordinates are passed directly to the underlying noise algorithm.
Use the `frequency` option to control the scale of the noise.
## Supported Noise Types
`:perlin`, `:perlin_fractal`, `:simplex`, `:simplex_fractal`, `:value`,
`:value_fractal`, `:cubic`, `:cubic_fractal`, `:cellular`, `:white`
"""
@noise_types [
:perlin,
:perlin_fractal,
:simplex,
:simplex_fractal,
:value,
:value_fractal,
:cubic,
:cubic_fractal,
:cellular,
:white
]
alias Isotope.{NIF, NoiseMap, Options}
@typedoc """
A reference to the noise generator. This is
needed for most of the library functions.
"""
@type noise_ref() :: reference()
@typedoc """
A noise map containing packed f32 noise values with dimensions.
"""
@type noisemap() :: NoiseMap.t()
@typedoc """
A coordinate `{x, y}` in a cartesian plane.
"""
@type coord() :: {integer(), integer()}
@typedoc """
2-element tuple containg x and y values as floats.
"""
@type point2d() :: {float(), float()}
@typedoc """
3-element tuple containg x, y and z values as floats.
"""
@type point3d() :: {float(), float(), float()}
@typedoc """
A tuple containing width and height
"""
@type size() :: {non_neg_integer(), non_neg_integer()}
@typedoc """
Options available when initializing the noise.
"""
@type options() :: Options.t()
@doc """
Returns a new noise reference using the default options.
iex> {:ok, _ref} = Isotope.Noise.new()
"""
@spec new(options()) :: {:ok, noise_ref()} | {:error, :unsupported_noise}
def new(), do: NIF.new(%Options{})
@doc """
Returns a new noise reference using the provided `options`.
iex> {:ok, _ref} = Isotope.Noise.new(%Isotope.Options{seed: 100})
iex> {:error, :unsupported_noise} = Isotope.Noise.new(%Isotope.Options{noise_type: :foobar})
"""
def new(options) when options.noise_type not in @noise_types,
do: {:error, :unsupported_noise}
def new(options), do: NIF.new(options)
@doc """
Returns a 2D noise map from `start_point` which has `width` and `height`
iex> {:ok, noise} = Isotope.Noise.new(%Isotope.Options{seed: 100})
iex> %Isotope.NoiseMap{width: 100, height: 100} = Isotope.Noise.chunk(noise, {0, 0}, 100, 100)
"""
@spec chunk(noise_ref(), coord(), non_neg_integer(), non_neg_integer()) ::
noisemap()
def chunk(noise, start_point, width, height)
def chunk(noise, {start_x, start_y}, width, height) do
{data, w, h} = NIF.chunk(noise, start_x, start_y, width, height)
%NoiseMap{data: data, width: w, height: h}
end
@doc """
Returns the 2D or 3D noise value depending on `axes`.
If `axes` is a 2-float tuple, it will return the 2D noise value for the point.
If `axes` is a 3-float tuple, it will return the 3D noise value for the point.
iex> {:ok, noise} = Isotope.Noise.new()
iex> is_float(Isotope.Noise.get_noise(noise, {10.0, 10.0}))
true
iex> {:ok, noise} = Isotope.Noise.new()
iex> is_float(Isotope.Noise.get_noise(noise, {10.0, 10.0, 10.0}))
true
"""
@spec get_noise(noise_ref(), point2d() | point3d()) :: float()
def get_noise(noise, axes)
def get_noise(noise, {x, y}), do: NIF.get_noise(noise, x, y)
def get_noise(noise, {x, y, z}), do: NIF.get_noise3d(noise, x, y, z)
@doc """
Generates a 2D noise map of `size` and returns it.
iex> {:ok, noise} = Isotope.Noise.new()
iex> %Isotope.NoiseMap{width: 20, height: 20} = Isotope.Noise.noise_map(noise, {20, 20})
"""
@spec noise_map(reference(), size()) :: noisemap()
def noise_map(noise, size)
def noise_map(noise, {w, h}) do
{data, width, height} = NIF.noise_map(noise, w, h)
%NoiseMap{data: data, width: width, height: height}
end
end