packages feed

pure-noise-0.2.0.0: src/Numeric/Noise/Internal.hs

-- |
-- Maintainer: Jeremy Nuttall <jeremy@jeremy-nuttall.com>
-- Stability : experimental
module Numeric.Noise.Internal (
  module Math,
  Noise2 (..),
  next2,
  map2,
  clamp2,
  const2,
  Noise3 (..),
  next3,
  map3,
  clamp3,
  const3,
) where

import Numeric.Noise.Internal.Math as Math (
  Hash,
  Seed,
  clamp,
  cubicInterp,
  hermiteInterp,
  lerp,
  quinticInterp,
 )

-- | A 2D noise function parameterized by a seed and two coordinates.
--
-- 'Noise2' wraps a function @Seed -> a -> a -> a@ that takes a seed value
-- and x, y coordinates to produce a noise value.
--
-- This type supports 'Num', 'Fractional', and 'Floating' instances, allowing
-- noise functions to be combined algebraically:
--
-- @
-- combined :: Noise2 Float
-- combined = (perlin2 + superSimplex2) / 2
-- @
--
-- To evaluate a 'Noise2', use 'noise2At' from "Numeric.Noise".
newtype Noise2 a = Noise2
  {unNoise2 :: Seed -> a -> a -> a}

-- | Increment the seed for a 2D noise function.
--
-- This is useful for generating independent noise layers:
--
-- @
-- layer1 = perlin2
-- layer2 = next2 perlin2
-- layer3 = next2 (next2 perlin2)
-- @
next2 :: Noise2 a -> Noise2 a
next2 (Noise2 f) = Noise2 (\s x y -> f (s + 1) x y)
{-# INLINE next2 #-}

map2 :: (a -> a) -> Noise2 a -> Noise2 a
map2 f (Noise2 g) = Noise2 (\s x y -> f (g s x y))
{-# INLINE map2 #-}

-- | Clamp the output of a 2D noise function to the range @[lower, upper]@.
--
-- @
-- clamped :: Noise2 Float
-- clamped = clamp2 0 1 perlin2  -- clamp to [0, 1]
-- @
clamp2 :: (Ord a) => a -> a -> Noise2 a -> Noise2 a
clamp2 l u (Noise2 f) = Noise2 $ \s x y -> clamp l u (f s x y)
{-# INLINE clamp2 #-}

const2 :: a -> Noise2 a
const2 a = Noise2 (\_ _ _ -> a)
{-# INLINE const2 #-}

-- | Arithmetic operations on 'Noise2' are performed point-wise.
--
-- For example, @n1 + n2@ creates a new noise function that adds the
-- results of @n1@ and @n2@ at each coordinate.
instance (Num a) => Num (Noise2 a) where
  Noise2 f + Noise2 g = Noise2 $ \s x y -> f s x y + g s x y
  {-# INLINE (+) #-}
  Noise2 f * Noise2 g = Noise2 $ \s x y -> f s x y * g s x y
  {-# INLINE (*) #-}
  abs (Noise2 f) = Noise2 $ \s x y -> abs (f s x y)
  {-# INLINE abs #-}
  signum (Noise2 f) = Noise2 $ \s x y -> signum (f s x y)
  {-# INLINE signum #-}
  fromInteger i = const2 (fromInteger i)
  {-# INLINE fromInteger #-}
  negate (Noise2 f) = Noise2 $ \s x y -> negate (f s x y)
  {-# INLINE negate #-}

instance (Fractional a) => Fractional (Noise2 a) where
  fromRational r = const2 (fromRational r)
  {-# INLINE fromRational #-}
  recip (Noise2 f) = Noise2 $ \s x y -> recip (f s x y)
  {-# INLINE recip #-}
  Noise2 f / Noise2 g = Noise2 $ \s x y -> f s x y / g s x y
  {-# INLINE (/) #-}

instance (Floating a) => Floating (Noise2 a) where
  pi = const2 pi
  {-# INLINE pi #-}
  exp (Noise2 f) = Noise2 $ \s x y -> exp (f s x y)
  {-# INLINE exp #-}
  log (Noise2 f) = Noise2 $ \s x y -> log (f s x y)
  {-# INLINE log #-}
  sin (Noise2 f) = Noise2 $ \s x y -> sin (f s x y)
  {-# INLINE sin #-}
  cos (Noise2 f) = Noise2 $ \s x y -> cos (f s x y)
  {-# INLINE cos #-}
  asin (Noise2 f) = Noise2 $ \s x y -> asin (f s x y)
  {-# INLINE asin #-}
  acos (Noise2 f) = Noise2 $ \s x y -> acos (f s x y)
  {-# INLINE acos #-}
  atan (Noise2 f) = Noise2 $ \s x y -> atan (f s x y)
  {-# INLINE atan #-}
  sinh (Noise2 f) = Noise2 $ \s x y -> sinh (f s x y)
  {-# INLINE sinh #-}
  cosh (Noise2 f) = Noise2 $ \s x y -> cosh (f s x y)
  {-# INLINE cosh #-}
  asinh (Noise2 f) = Noise2 $ \s x y -> asinh (f s x y)
  {-# INLINE asinh #-}
  acosh (Noise2 f) = Noise2 $ \s x y -> acosh (f s x y)
  {-# INLINE acosh #-}
  atanh (Noise2 f) = Noise2 $ \s x y -> atanh (f s x y)
  {-# INLINE atanh #-}

-- | A 3D noise function parameterized by a seed and three coordinates.
--
-- 'Noise3' wraps a function @Seed -> a -> a -> a -> a@ that takes a seed value
-- and x, y, z coordinates to produce a noise value.
--
-- Like 'Noise2', this type supports 'Num', 'Fractional', and 'Floating' instances
-- for algebraic composition.
--
-- To evaluate a 'Noise3', use 'noise3At' from "Numeric.Noise".
newtype Noise3 a = Noise3
  {unNoise3 :: Seed -> a -> a -> a -> a}

-- | Increment the seed for a 3D noise function.
--
-- Analogous to 'next2', this is useful for generating independent 3D noise layers.
next3 :: Noise3 a -> Noise3 a
next3 (Noise3 f) = Noise3 (\s x y z -> f (s + 1) x y z)
{-# INLINE next3 #-}

map3 :: (a -> a) -> Noise3 a -> Noise3 a
map3 f (Noise3 g) = Noise3 (\s x y z -> f (g s x y z))
{-# INLINE map3 #-}

const3 :: a -> Noise3 a
const3 a = Noise3 (\_ _ _ _ -> a)
{-# INLINE const3 #-}

-- | Clamp the output of a 3D noise function to the range @[lower, upper]@.
--
-- @
-- clamped :: Noise3 Float
-- clamped = clamp3 (-0.5) 0.5 perlin3  -- clamp to [-0.5, 0.5]
-- @
clamp3 :: (Ord a) => a -> a -> Noise3 a -> Noise3 a
clamp3 l u (Noise3 f) = Noise3 $ \s x y z -> clamp l u (f s x y z)
{-# INLINE clamp3 #-}

-- | Arithmetic operations on 'Noise3' are performed point-wise.
--
-- For example, @n1 * n2@ creates a new noise function that multiplies the
-- results of @n1@ and @n2@ at each coordinate.
instance (Num a) => Num (Noise3 a) where
  Noise3 f + Noise3 g = Noise3 $ \s x y z -> f s x y z + g s x y z
  {-# INLINE (+) #-}
  Noise3 f * Noise3 g = Noise3 $ \s x y z -> f s x y z * g s x y z
  {-# INLINE (*) #-}
  abs (Noise3 f) = Noise3 $ \s x y z -> abs (f s x y z)
  {-# INLINE abs #-}
  signum (Noise3 f) = Noise3 $ \s x y z -> signum (f s x y z)
  {-# INLINE signum #-}
  fromInteger i = const3 (fromInteger i)
  {-# INLINE fromInteger #-}
  negate (Noise3 f) = Noise3 $ \s x y z -> negate (f s x y z)
  {-# INLINE negate #-}

instance (Fractional a) => Fractional (Noise3 a) where
  fromRational r = const3 (fromRational r)
  {-# INLINE fromRational #-}
  recip (Noise3 f) = Noise3 $ \s x y z -> recip (f s x y z)
  {-# INLINE recip #-}
  Noise3 f / Noise3 g = Noise3 $ \s x y z -> f s x y z / g s x y z
  {-# INLINE (/) #-}

instance (Floating a) => Floating (Noise3 a) where
  pi = const3 pi
  {-# INLINE pi #-}
  exp (Noise3 f) = Noise3 $ \s x y z -> exp (f s x y z)
  {-# INLINE exp #-}
  log (Noise3 f) = Noise3 $ \s x y z -> log (f s x y z)
  {-# INLINE log #-}
  sin (Noise3 f) = Noise3 $ \s x y z -> sin (f s x y z)
  {-# INLINE sin #-}
  cos (Noise3 f) = Noise3 $ \s x y z -> cos (f s x y z)
  {-# INLINE cos #-}
  asin (Noise3 f) = Noise3 $ \s x y z -> asin (f s x y z)
  {-# INLINE asin #-}
  acos (Noise3 f) = Noise3 $ \s x y z -> acos (f s x y z)
  {-# INLINE acos #-}
  atan (Noise3 f) = Noise3 $ \s x y z -> atan (f s x y z)
  {-# INLINE atan #-}
  sinh (Noise3 f) = Noise3 $ \s x y z -> sinh (f s x y z)
  {-# INLINE sinh #-}
  cosh (Noise3 f) = Noise3 $ \s x y z -> cosh (f s x y z)
  {-# INLINE cosh #-}
  asinh (Noise3 f) = Noise3 $ \s x y z -> asinh (f s x y z)
  {-# INLINE asinh #-}
  acosh (Noise3 f) = Noise3 $ \s x y z -> acosh (f s x y z)
  {-# INLINE acosh #-}
  atanh (Noise3 f) = Noise3 $ \s x y z -> atanh (f s x y z)
  {-# INLINE atanh #-}