packages feed

pure-noise-0.2.2.0: src/Numeric/Noise.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE Strict #-}

-- |
-- Maintainer: Jeremy Nuttall <jeremy@jeremy-nuttall.com>
-- Stability : experimental
--
-- Performant noise generation with composable noise functions.
--
-- Noise functions are built on a unified 'Noise' type that abstracts over
-- the seed and coordinate parameters. 'Noise2' and 'Noise3' are convenient
-- type aliases for 2D and 3D noise. These can be composed algebraically
-- with minimal performance overhead.
--
-- Noise values are generally clamped to @[-1, 1]@, although some noise
-- functions may occasionally produce values slightly outside this range.
--
-- == Basic Usage
--
-- Generate 2D Perlin noise:
--
-- @
-- import Numeric.Noise qualified as Noise
--
-- myNoise :: Noise.Seed -> Float -> Float -> Float
-- myNoise = Noise.noise2At Noise.perlin2
-- @
--
-- Compose multiple noise functions:
--
-- @
-- combined :: (RealFrac a) => Noise.Noise2 a
-- combined = (Noise.perlin2 + Noise.superSimplex2) / 2
--
-- myNoise2 :: Noise.Seed -> Float -> Float -> Float
-- myNoise2 = Noise.noise2At combined
-- @
--
-- Apply fractal Brownian motion:
--
-- @
-- fbm :: (RealFrac a) => Noise.Noise2 a
-- fbm = Noise.fractal2 Noise.defaultFractalConfig Noise.perlin2
-- @
--
-- == Advanced Features
--
-- Generate 1D noise by slicing higher-dimensional noise:
--
-- @
-- noise1d :: Noise.Noise1 Float
-- noise1d = Noise.sliceY2 0.5 Noise.perlin2
--
-- evaluate :: Float -> Float
-- evaluate = Noise.noise1At noise1d 0
-- @
--
-- Transform coordinates with 'warp':
--
-- @
-- scaledAndLayered :: Noise.Noise2 Float
-- scaledAndLayered =
--  Noise.warp (\\(x, y) -> (x * 2, y * 2)) Noise.perlin2
--    + fmap (* 0.5) Noise.perlin2
-- @
--
-- Layer independent noise with 'reseed' or 'next2':
--
-- @
-- layered :: Noise.Noise2 Float
-- layered = (Noise.perlin2 + Noise.next2 Noise.perlin2) \/ 2
-- @
--
-- == Coordinate domain
--
-- Coordinates are supported on the Int32 lattice range (@|x| < 2^31@; in
-- practice 'Float' precision runs out well before that).
--
-- The OpenSimplex2\/2S family first rotates coordinates into its lattice domain,
-- which shrinks its usable range by the rotation factor — up to ~1.73x, so roughly
-- @|x| < 1.2e9@.
--
-- Outside those domains, or for non-finite inputs, results are unspecified.
--
-- This behavior mirrors FastNoiseLite, but may change in a future major version.
module Numeric.Noise (
  -- * Noise

  --

  -- | 'Noise1', 'Noise2', and 'Noise3' are type aliases for 1D, 2D, and 3D noise
  -- functions built on the unified 'Noise' type. They can be evaluated with
  -- 'noise1At', 'noise2At', and 'noise3At' respectively.
  --
  -- 'Seed' is a 'Data.Word.Word64' value used for deterministic noise generation.
  Noise,
  Noise1,
  Noise1',
  Noise2,
  Noise2',
  Noise3,
  Noise3',
  Seed,

  -- * Accessors
  noise1At,
  noise2At,
  noise3At,

  -- * Noise functions

  -- ** Perlin
  perlin2,
  perlin3,

  -- ** OpenSimplex
  openSimplex2,
  openSimplex3,

  -- ** OpenSimplex2S
  superSimplex2,
  superSimplex3,

  -- ** Cellular
  cellular2,
  cellular3,

  -- *** Configuration
  CellularConfig (..),
  defaultCellularConfig,
  CellularDistanceFn (..),
  CellularResult (..),

  -- ** Value
  value2,
  valueCubic2,
  value3,
  valueCubic3,

  -- ** Constant fields
  const2,
  const3,

  -- * Noise alteration

  -- ** Altering values
  remap,

  -- ** Altering parameters
  warp,
  reseed,
  next2,
  next3,

  -- ** Slicing (projecting)
  sliceX2,
  sliceX3,
  sliceY2,
  sliceY3,
  sliceZ3,

  -- * Fractals

  --

  -- | Fractal noise combines multiple octaves at different frequencies and
  -- amplitudes to create natural-looking, multi-scale patterns.
  --
  -- For custom fractal implementations using per-octave modifier functions,
  -- see "Numeric.Noise.Fractal".

  -- ** Fractal Brownian Motion (FBM)
  fractal2,
  fractal3,

  -- ** Fractal variants
  billow2,
  billow3,
  ridged2,
  ridged3,
  pingPong2,
  pingPong3,

  -- ** Configuration
  FractalConfig (..),
  defaultFractalConfig,
  PingPongStrength (..),
  defaultPingPongStrength,

  -- * Custom kernels

  --

  -- | Lift a plain @seed -> coordinates -> value@ function into a composable
  -- 'Noise' value — the inverses of the accessors above.
  --
  -- You may use these to construct custom kernels.
  mkNoise1,
  mkNoise2,
  mkNoise3,

  -- * Math utilities
  clamp,
  clamp2,
  clamp3,
  cubicInterp,
  hermiteInterp,
  lerp,
  quinticInterp,
) where

import Numeric.Noise.Cellular (CellularConfig, CellularDistanceFn (..), CellularResult (..), defaultCellularConfig)
import Numeric.Noise.Cellular qualified as Cellular
import Numeric.Noise.Fractal
import Numeric.Noise.Internal
import Numeric.Noise.OpenSimplex qualified as OpenSimplex
import Numeric.Noise.Perlin qualified as Perlin
import Numeric.Noise.SuperSimplex qualified as SuperSimplex
import Numeric.Noise.Value qualified as Value
import Numeric.Noise.ValueCubic qualified as ValueCubic

-- | 2D Cellular (Worley) noise. Configure with 'CellularConfig' to control
-- distance functions and return values.
--
-- Cellular noise creates patterns based on distances to randomly distributed
-- cell points.
cellular2 :: (RealFrac a, Floating a) => CellularConfig a -> Noise2 a
cellular2 = Cellular.noise2
{-# INLINE cellular2 #-}

-- | 3D Cellular (Worley) noise. See 'cellular2'.
cellular3 :: (RealFrac a, Floating a) => CellularConfig a -> Noise3 a
cellular3 = Cellular.noise3
{-# INLINE cellular3 #-}

-- | 2D OpenSimplex noise. Smooth gradient noise similar to Perlin but without
-- directional artifacts.
openSimplex2 :: (RealFrac a) => Noise2 a
openSimplex2 = OpenSimplex.noise2
{-# INLINE openSimplex2 #-}

-- | 3D OpenSimplex noise (FastNoiseLite's OpenSimplex2, two offset rotated
-- cube grids), including its default coordinate rotation.
openSimplex3 :: (RealFrac a) => Noise3 a
openSimplex3 = OpenSimplex.noise3
{-# INLINE openSimplex3 #-}

-- | 2D SuperSimplex noise. Improved OpenSimplex variant with better visual
-- characteristics.
superSimplex2 :: (RealFrac a) => Noise2 a
superSimplex2 = SuperSimplex.noise2
{-# INLINE superSimplex2 #-}

-- | 3D SuperSimplex noise (FastNoiseLite's OpenSimplex2S, two offset rotated
-- cube grids), including its default coordinate rotation.
superSimplex3 :: (RealFrac a) => Noise3 a
superSimplex3 = SuperSimplex.noise3
{-# INLINE superSimplex3 #-}

-- | 2D Perlin noise. Classic gradient noise algorithm.
perlin2 :: (RealFrac a) => Noise2 a
perlin2 = Perlin.noise2
{-# INLINE perlin2 #-}

-- | 3D Perlin noise. Classic gradient noise algorithm.
perlin3 :: (RealFrac a) => Noise3 a
perlin3 = Perlin.noise3
{-# INLINE perlin3 #-}

-- | 2D Value noise. Simple noise based on interpolated random values at grid points.
value2 :: (RealFrac a) => Noise2 a
value2 = Value.noise2
{-# INLINE value2 #-}

-- | 3D Value noise. Simple noise based on interpolated random values at grid points.
value3 :: (RealFrac a) => Noise3 a
value3 = Value.noise3
{-# INLINE value3 #-}

-- | 2D Value noise with cubic interpolation for smoother results.
valueCubic2 :: (RealFrac a) => Noise2 a
valueCubic2 = ValueCubic.noise2
{-# INLINE valueCubic2 #-}

-- | 3D Value noise with cubic interpolation for smoother results.
valueCubic3 :: (RealFrac a) => Noise3 a
valueCubic3 = ValueCubic.noise3
{-# INLINE valueCubic3 #-}