defmodule Isotope.Noise do
@moduledoc """
Provide functions to create and work with different types of noises.
"""
@noise_types [
:perlin,
:perlin_fractal,
:simplex,
:simplex_fractal,
:value,
:value_fractal,
:cubic,
:cubic_fractal,
:cellular,
:white
]
alias Isotope.{NIF, 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, represented by a list
containing lists of floats (the noise values).
"""
@type noisemap() :: [[float()]]
@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.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: NIF.chunk(noise, start_x, start_y, width, height)
@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> Isotope.Noise.get_noise(noise, {10.0, 10.0})
-0.6350845098495483
iex> {:ok, noise} = Isotope.Noise.new()
iex> Isotope.Noise.get_noise(noise, {10.0, 10.0, 10.0})
-0.1322503685951233
"""
@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.Noise.noise_map(noise, {20, 20})
"""
@spec noise_map(reference(), size()) :: noisemap()
def noise_map(noise, size)
def noise_map(noise, {w, h}), do: NIF.noise_map(noise, w, h)
end