{-# 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 using algebraically
-- with minimal performance overhead.
--
-- Noise values are generally clamped to @[-1, 1]@, though some 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 (logBase 2) Noise.perlin2
-- @
--
-- Layer independent noise with 'reseed' or 'next2':
--
-- @
-- layered :: Noise.Noise2 Float
-- layered = Noise.perlin2 + Noise.next2 Noise.perlin2 \/ 2
-- @
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,

  -- ** OpenSimplex2S
  superSimplex2,

  -- ** Cellular
  cellular2,

  -- *** 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 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,

  -- * 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 :: forall a. (RealFrac a, Floating a) => CellularConfig a -> Noise2 a
cellular2 = CellularConfig a -> Noise2 a
forall a. (RealFrac a, Floating a) => CellularConfig a -> Noise2 a
Cellular.noise2
{-# INLINE cellular2 #-}

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

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

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

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

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

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

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

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