{-# LANGUAGE ForeignFunctionInterface #-}
module Math.Noise.Modules.Perlin where
import Data.Default
import Math.Noise.NoiseGen
import Math.Noise.NoiseModule
import Data.Bits
import Foreign
import Foreign.C.Types
-- import qualified Data.Vector.Unboxed as V

foreign import ccall "perlin.h perlinGen"
  c_perlin :: CDouble -> CDouble -> CDouble 
           -> CDouble -> CDouble -> CInt 
           -> CDouble -> CInt 
           -> CDouble


data Perlin = Perlin { perlinFrequency :: Double 
                     -- ^ Frequency of the first octave
		             , perlinLacunarity :: Double 
                     -- ^ Frequency multiplier between successive octaves
		             , perlinOctaves :: Int 
                     -- ^ Total number of octaves that generate the Perlin noise
		             , perlinPersistence :: Double 
                     -- ^ Persistence of the Perlin noise
		             , perlinSeed :: Int
 		             } deriving (Show, Eq)

perlin :: Perlin 
perlin = Perlin { perlinFrequency = 1.0
		        , perlinLacunarity = 2.0
		        , perlinOctaves = 6
		        , perlinPersistence = 0.5
		        , perlinSeed = 123 
		        }

-- TODO: make sure the number of octaves are within range...
-- getValue :: Perlin -> (Double, Double, Double) -> Double
instance NoiseClass Perlin where
  getNoiseValue (Perlin { perlinFrequency = freq
		                , perlinLacunarity = lac
		   	            , perlinOctaves = octaveCount
		   	            , perlinPersistence = p
		   	            , perlinSeed = seed } ) _ (x,y,z) = 
    Just $ realToFrac $ c_perlin (realToFrac x) (realToFrac y) (realToFrac z) 
                                 (realToFrac freq) (realToFrac lac) 
                                 (fromIntegral octaveCount) (realToFrac p) 
                                 (fromIntegral seed)

{-
    Just $ value $ V.foldr' octaveFunc (0.0, 1.0, x*freq, y*freq, z*freq) (V.generate (octaveCount-1) id)
    where value (v,_,_,_,_) = v
  	  signal sx sy sz octv = gradientCoherentNoise3D sx sy sz (seed + octv) 
	  octaveFunc curOctave (value, curPersistence, ox, oy, oz) = 
	    ( value + ( (signal ox oy oz (curOctave+1)) * curPersistence)
	    , curPersistence * p
	    , ox * lac
	    , oy * lac
	    , oz * lac
	    )
-}