geomancy-0.3.0.0: src/Geomancy/Gl/Funs.hs
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
module Geomancy.Gl.Funs
( GlClamp(..)
, glSaturate
, GlStep(..)
, normRange
, smoothstepPoly
, smootherstepPoly
, GlNearest(..)
, glFract
, GlMod(..)
, GlModf(..)
, GlMix(..)
) where
import Geomancy.Elementwise (Element, Elementwise(..))
import Geomancy.Interpolate (linear, linearE)
class GlClamp edge a where
glMin :: a -> edge -> a
glMax :: a -> edge -> a
glClamp :: a -> edge -> edge -> a
glClamp x minVal = glMin (glMax x minVal)
instance {-# OVERLAPS #-} GlClamp Float Float where
glMin = min
glMax = max
instance (Element v ~ Float, Elementwise v) => GlClamp Float v where
{-# INLINE glMin #-}
glMin a b = emap2 glMin a (epoint b)
{-# INLINE glMax #-}
glMax a b = emap2 glMax a (epoint b)
instance (Element v ~ Float, Elementwise v) => GlClamp v v where
{-# INLINE glMin #-}
glMin = emap2 glMin
{-# INLINE glMax #-}
glMax = emap2 glMax
glSaturate :: forall a . (GlClamp a a, Num a) => a -> a
glSaturate x = glClamp @a x 0 1
class GlClamp edge a => GlStep edge a where
glStep :: edge -> a -> a
glSmoothstep :: edge -> edge -> a -> a
glSmootherstep :: edge -> edge -> a -> a
instance (Element v ~ Float, Elementwise v) => GlStep Float v where
glStep edge = emap2 glStep (epoint edge)
glSmoothstep edge0 edge1 = emap3 glSmoothstep (epoint edge0) (epoint edge1)
glSmootherstep edge0 edge1 = emap3 glSmootherstep (epoint edge0) (epoint edge1)
instance (Element v ~ Float, Elementwise v) => GlStep v v where
glStep = emap2 glStep
glSmoothstep = emap3 glSmoothstep
glSmootherstep = emap3 glSmootherstep
instance {-# OVERLAPS #-} GlStep Float Float where
{-# INLINE glStep #-}
glStep edge x =
if x < edge then
0
else
1
glSmoothstep edge0 edge1 x =
smoothstepPoly . glSaturate $
normRange edge0 edge1 x
glSmootherstep edge0 edge1 x =
smootherstepPoly . glSaturate $
normRange edge0 edge1 x
{-# INLINE normRange #-}
normRange :: Fractional a => a -> a -> a -> a
normRange edge0 edge1 x = (x - edge0) / (edge1 - edge0)
{-# INLINE smoothstepPoly #-}
smoothstepPoly :: Num a => a -> a
smoothstepPoly t = t * t * (3 - 2 * t)
{-# INLINE smootherstepPoly #-}
smootherstepPoly :: Num a => a -> a
smootherstepPoly t = t * t * t * (t * (t * 6 - 15) + 10)
class GlNearest a where
glCeil :: a -> a
glFloor :: a -> a
glRound :: a -> a
glTrunc :: a -> a
default glCeil :: (Elementwise a, Element a ~ Float) => a -> a
glCeil = emap glCeil
default glFloor :: (Elementwise a, Element a ~ Float) => a -> a
glFloor = emap glFloor
default glRound :: (Elementwise a, Element a ~ Float) => a -> a
glRound = emap glRound
default glTrunc :: (Elementwise a, Element a ~ Float) => a -> a
glTrunc = emap glTrunc
instance GlNearest Float where
{-# INLINE glCeil #-}
glCeil = fromInteger . ceiling
{-# INLINE glFloor #-}
glFloor = fromInteger . floor
{-# INLINE glRound #-}
glRound = fromInteger . round
{-# INLINE glTrunc #-}
glTrunc = fromInteger . truncate
{-# INLINE glFract #-}
glFract :: (Num a, GlNearest a) => a -> a
glFract x = x - glFloor x
class GlModf i f where
glModf :: f -> (i, f)
instance GlModf Integer Float where
{-# INLINE glModf #-}
glModf x =
let
integral = floor x
in
(integral, x - fromIntegral integral)
instance GlModf Float Float where
{-# INLINE glModf #-}
glModf x = (fromInteger i, f)
where
(i, f) = glModf x
class GlMod x y where
glMod :: x -> y -> x
instance GlMod Float Float where
{-# INLINE glMod #-}
glMod x y = x - y * glFloor (x / y)
class GlMix alpha x where
glMix :: x -> x -> alpha -> x
instance {-# OVERLAPS #-} GlMix Float Float where
{-# INLINE glMix #-}
glMix = linear
instance (Element v ~ Float, Elementwise v) => GlMix Float v where
{-# INLINE glMix #-}
glMix a b t = linearE a b (epoint t)
instance (Element v ~ Float, Elementwise v) => GlMix v v where
{-# INLINE glMix #-}
glMix = linearE