pure-noise-0.2.2.0: src/Numeric/Noise/OpenSimplex.hs
-- |
-- Maintainer: Jeremy Nuttall <jeremy@jeremy-nuttall.com>
-- Stability: experimental
--
-- This module implements a variation of OpenSimplex2 noise derived from FastNoiseLite.
module Numeric.Noise.OpenSimplex (
-- * 2D Noise
noise2,
noise2Base,
-- * 3D Noise
noise3,
noise3Base,
) where
import Data.Bits (complement, shiftR, (.&.))
import Data.Bool (bool)
import Numeric.Noise.Internal
import Numeric.Noise.Internal.Math
noise2 :: (RealFrac a) => Noise2 a
noise2 = mkNoise2 noise2Base
{-# INLINE noise2 #-}
noise2Base :: (RealFrac a) => Seed -> a -> a -> a
noise2Base seed xo yo =
let !f2 = 0.5 * (sqrt3 - 1)
!to = (xo + yo) * f2
!x = xo + to
!y = yo + to
!fx = floor x
!fy = floor y
!xi = x - fromIntegral fx
!yi = y - fromIntegral fy
!t = (xi + yi) * g2
!x0 = xi - t
!y0 = yi - t
!i = fx * primeX
!j = fy * primeY
!a = 0.5 - x0 * x0 - y0 * y0
n0 = attenuate a seed i j x0 y0
n1 =
let gt = y0 > x0
-- Select the constant-folded addend per branch (g2 or g2 - 1),
-- reproducing FNL's `x0 + (float)G2` / `x0 + ((float)G2 - 1)`
-- rounding. Arithmetic on the selector, e.g.
-- (x0 + g2 - 1) + cond, rounds differently when |x0 + g2| < 1.
x1 = x0 + bool (g2 - 1) g2 gt
y1 = y0 + bool g2 (g2 - 1) gt
i1 = i + bool primeX 0 gt
j1 = j + bool 0 primeY gt
b = 0.5 - x1 * x1 - y1 * y1
in attenuate b seed i1 j1 x1 y1
!n2 =
let g2t = 1 - 2 * g2
c = 2 * g2t * (1 / g2 - 2) * t + (-2 * g2t * g2t + a)
x2 = x0 + (2 * g2 - 1)
y2 = y0 + (2 * g2 - 1)
in attenuate c seed (i + primeX) (j + primeY) x2 y2
in normalize $ n0 + n1 + n2
{-# INLINE [2] noise2Base #-}
attenuate :: (RealFrac a) => a -> Seed -> Hash -> Hash -> a -> a -> a
attenuate !vi seed i j x y =
let !v = max 0 vi
in (v * v) * (v * v) * gradCoord2 seed i j x y
{-# INLINE attenuate #-}
normalize :: (RealFrac a) => a -> a
normalize = (99.83685446303647 *)
{-# INLINE normalize #-}
noise3 :: (RealFrac a) => Noise3 a
noise3 = mkNoise3 noise3Base
{-# INLINE noise3 #-}
noise3Base :: forall a. (RealFrac a) => Seed -> a -> a -> a -> a
noise3Base seed0 xo yo zo =
let !(x, y, z) = rotate3 xo yo zo
!i0 = fastRound x
!j0 = fastRound y
!k0 = fastRound z
!x0 = x - fromIntegral i0
!y0 = y - fromIntegral j0
!z0 = z - fromIntegral k0
-- FNL: (int)(-1.0f - x0) | 1, i.e. -1 when the offset is >= 0
!xns = bool 1 (-1) (x0 >= 0) :: Hash
!yns = bool 1 (-1) (y0 >= 0) :: Hash
!zns = bool 1 (-1) (z0 >= 0) :: Hash
!ax0 = fromIntegral xns * negate x0
!ay0 = fromIntegral yns * negate y0
!az0 = fromIntegral zns * negate z0
!ip = i0 * primeX
!jp = j0 * primeY
!kp = k0 * primeZ
!a0 = (0.6 - x0 * x0) - (y0 * y0 + z0 * z0)
!v0 = iteration seed0 a0 ip jp kp x0 y0 z0 ax0 ay0 az0 xns yns zns
-- second lattice: reflect offsets, flip signs, complement the seed
!ax1 = 0.5 - ax0
!ay1 = 0.5 - ay0
!az1 = 0.5 - az0
!x1 = fromIntegral xns * ax1
!y1 = fromIntegral yns * ay1
!z1 = fromIntegral zns * az1
!a1 = a0 + ((0.75 - ax1) - (ay1 + az1))
!ip' = ip + ((xns `shiftR` 1) .&. primeX)
!jp' = jp + ((yns `shiftR` 1) .&. primeY)
!kp' = kp + ((zns `shiftR` 1) .&. primeZ)
!v1 = iteration (complement seed0) a1 ip' jp' kp' x1 y1 z1 ax1 ay1 az1 (negate xns) (negate yns) (negate zns)
in (v0 + v1) * 32.69428253173828125
where
-- one loop iteration of the FNL reference: the cell contribution plus one
-- step along the dominant axis
iteration
:: Seed -> a -> Hash -> Hash -> Hash -> a -> a -> a -> a -> a -> a -> Hash -> Hash -> Hash -> a
iteration !sd !a !i !j !k !x0 !y0 !z0 !ax !ay !az !xns !yns !zns =
let !va
| a > 0 = (a * a) * (a * a) * gradCoord3 sd i j k x0 y0 z0
| otherwise = 0
!b0 = a + 1
!vb
| ax >= ay && ax >= az =
let !x1 = x0 + fromIntegral xns
!b = b0 - fromIntegral (xns * 2) * x1
in bContrib sd b (i - xns * primeX) j k x1 y0 z0
| ay > ax && ay >= az =
let !y1 = y0 + fromIntegral yns
!b = b0 - fromIntegral (yns * 2) * y1
in bContrib sd b i (j - yns * primeY) k x0 y1 z0
| otherwise =
let !z1 = z0 + fromIntegral zns
!b = b0 - fromIntegral (zns * 2) * z1
in bContrib sd b i j (k - zns * primeZ) x0 y0 z1
in va + vb
{-# INLINE iteration #-}
bContrib :: Seed -> a -> Hash -> Hash -> Hash -> a -> a -> a -> a
bContrib !sd !b !i !j !k !x1 !y1 !z1
| b > 0 = (b * b) * (b * b) * gradCoord3 sd i j k x1 y1 z1
| otherwise = 0
{-# INLINE bContrib #-}
{-# INLINE [2] noise3Base #-}