packages feed

tcod-haskell-0.2.0.0: src/Game/TCOD/Noise.hs

{-# LANGUAGE QuasiQuotes #-}
module Game.TCOD.Noise(
    TCODNoise(..)
  , TCODNoiseType(..)
  , noiseMaxOctaves
  , noiseMaxDimensions
  , noiseDefaultHurst
  , noiseDefaultLacunarity
  , noiseNew
  , noiseDelete
  , noiseSetType
  , noiseGetEx
  , noiseGetFbmEx
  , noiseGetTurbulenceEx
  , noiseGet
  , noiseGetFbm
  , noiseGetTurbulence
  ) where

import Data.Vector.Storable (Vector)
import Foreign
import Foreign.C
import Game.TCOD.Context as C
import Game.TCOD.MersenneTypes
import GHC.Generics

import qualified Data.Vector.Storable as V

context tcodContext
verbatim "#define TCOD_SDL2"
include "libtcod/noise.h"

-- | Reference to TCOD noise object
newtype TCODNoise = TCODNoise { unTCODNoise :: Ptr () }
  deriving (Eq, Ord, Show, Generic)

-- | Supported noise generator types
data TCODNoiseType =
    NoiseDefault
  | NoisePerlin
  | NoiseSimplex
  | NoiseWavelet
  deriving (Eq, Ord, Show, Read, Enum, Bounded, Generic)

noiseMaxOctaves :: Int
noiseMaxOctaves = 128

noiseMaxDimensions :: Int
noiseMaxDimensions = 4

noiseDefaultHurst :: Double
noiseDefaultHurst = 0.5

noiseDefaultLacunarity :: Double
noiseDefaultLacunarity = 2.0

-- | Create a new noise object
noiseNew :: Int -- ^ Dimensions
  -> Double -- ^ hurst
  -> Double -- ^ lacunarity
  -> TCODRandom -- ^ random number generator
  -> IO TCODNoise
noiseNew d h l (TCODRandom r) = do
  let d' = fromIntegral d
      h' = realToFrac h
      l' = realToFrac l
  TCODNoise <$> [C.exp| void* { TCOD_noise_new($(int d'), $(float h'), $(float l'), $(void* r)) } |]

-- | Delete noise object
noiseDelete :: TCODNoise -> IO ()
noiseDelete (TCODNoise n) = [C.exp| void { TCOD_noise_delete($(void* n)) }|]

-- | Choosing a noise type
--
-- Use this function to define the default algorithm used by the noise functions.
-- The default algorithm is simplex. It's much faster than Perlin, especially in 4 dimensions.
-- It has a better contrast too.
noiseSetType :: TCODNoise -> TCODNoiseType -> IO ()
noiseSetType (TCODNoise n) nt = do
  let nt' = fromIntegral . fromEnum $ nt
  [C.exp| void { TCOD_noise_set_type($(void* n), (TCOD_noise_type_t)$(int nt')) } |]

-- | Getting flat noise
--
-- his function returns the noise function value between -1.0 and 1.0 at given coordinates.
noiseGetEx :: TCODNoise -- ^ the generator handler, returned by the initialization function.
  -> Vector Double -- ^ An array of coordinates, depending on the generator dimensions (between 1 and 4). The same array of coordinates will always return the same value.
  -> TCODNoiseType -- ^ The algorithm to use. If not defined, use the default one (set with setType or simplex if not set)
  -> IO Double
noiseGetEx (TCODNoise n) vf nt = V.unsafeWith (V.map realToFrac vf) $ \vf' -> do
  let nt' = fromIntegral . fromEnum $ nt
  realToFrac <$> [C.exp| float { TCOD_noise_get_ex($(void* n), $(float* vf'), (TCOD_noise_type_t)$(int nt')) } |]

-- | This function returns the fbm function value between -1.0 and 1.0 at given
-- coordinates, using fractal hurst and lacunarity defined when the generator has been created.
noiseGetFbmEx :: TCODNoise -- ^ the generator handler, returned by the initialization function.
  -> Vector Double -- ^ An array of coordinates, depending on the generator dimensions (between 1 and 4). The same array of coordinates will always return the same value.
  -> Float -- ^ Number of iterations. Must be < TCOD_NOISE_MAX_OCTAVES = 128
  -> TCODNoiseType -- ^ The algorithm to use
  -> IO Float
noiseGetFbmEx (TCODNoise n) vf o nt = V.unsafeWith (V.map realToFrac vf) $ \vf' -> do
  let nt' = fromIntegral . fromEnum $ nt
      o' = realToFrac o
  realToFrac <$> [C.exp| float { TCOD_noise_get_fbm_ex($(void* n), $(float* vf'), $(float o'), (TCOD_noise_type_t)$(int nt')) } |]

-- | Getting turbulence
--
-- This function returns the turbulence function value between -1.0 and 1.0 at
-- given coordinates, using fractal hurst and lacunarity defined when the
-- generator has been created.
noiseGetTurbulenceEx :: TCODNoise -- ^ the generator handler, returned by the initialization function.
  -> Vector Double -- ^ An array of coordinates, depending on the generator dimensions (between 1 and 4). The same array of coordinates will always return the same value.
  -> Float -- ^ Number of iterations. Must be < TCOD_NOISE_MAX_OCTAVES = 128
  -> TCODNoiseType -- ^ The algorithm to use
  -> IO Float
noiseGetTurbulenceEx (TCODNoise n) vf o nt = V.unsafeWith (V.map realToFrac vf) $ \vf' -> do
  let nt' = fromIntegral . fromEnum $ nt
      o' = realToFrac o
  realToFrac <$> [C.exp| float { TCOD_noise_get_turbulence_ex($(void* n), $(float* vf'), $(float o'), (TCOD_noise_type_t)$(int nt')) } |]

-- | Getting flat noise
--
-- his function returns the noise function value between -1.0 and 1.0 at given coordinates.
noiseGet :: TCODNoise -- ^ the generator handler, returned by the initialization function.
  -> Vector Double -- ^ An array of coordinates, depending on the generator dimensions (between 1 and 4). The same array of coordinates will always return the same value.
  -> IO Double
noiseGet (TCODNoise n) vf = V.unsafeWith (V.map realToFrac vf) $ \vf' ->
  realToFrac <$> [C.exp| float { TCOD_noise_get($(void* n), $(float* vf')) } |]

-- | This function returns the fbm function value between -1.0 and 1.0 at given
-- coordinates, using fractal hurst and lacunarity defined when the generator has been created.
noiseGetFbm :: TCODNoise -- ^ the generator handler, returned by the initialization function.
  -> Vector Double -- ^ An array of coordinates, depending on the generator dimensions (between 1 and 4). The same array of coordinates will always return the same value.
  -> Float -- ^ Number of iterations. Must be < TCOD_NOISE_MAX_OCTAVES = 128
  -> IO Float
noiseGetFbm (TCODNoise n) vf o = V.unsafeWith (V.map realToFrac vf) $ \vf' -> do
  let o' = realToFrac o
  realToFrac <$> [C.exp| float { TCOD_noise_get_fbm($(void* n), $(float* vf'), $(float o')) } |]

-- | Getting turbulence
--
-- This function returns the turbulence function value between -1.0 and 1.0 at
-- given coordinates, using fractal hurst and lacunarity defined when the
-- generator has been created.
noiseGetTurbulence :: TCODNoise -- ^ the generator handler, returned by the initialization function.
  -> Vector Double -- ^ An array of coordinates, depending on the generator dimensions (between 1 and 4). The same array of coordinates will always return the same value.
  -> Float -- ^ Number of iterations. Must be < TCOD_NOISE_MAX_OCTAVES = 128
  -> IO Float
noiseGetTurbulence (TCODNoise n) vf o = V.unsafeWith (V.map realToFrac vf) $ \vf' -> do
  let o' = realToFrac o
  realToFrac <$> [C.exp| float { TCOD_noise_get_turbulence($(void* n), $(float* vf'), $(float o')) } |]