glsl-0.0.1.0: src/Language/GLSL/Runtime/Value.hs
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE StrictData #-}
module Language.GLSL.Runtime.Value where
import Control.Monad.Trans.State.Strict (StateT)
import qualified Data.IntMap as M
import Language.GLSL.AST (BinaryOp (..), ParamDecl,
StmtAnnot, Type (..),
UnaryOp (..))
import Language.GLSL.Decls (Decls)
import Language.GLSL.PrettyPrint (pp, ppType)
import Linear (M44, V2, V3, V4, (!*!), (!*))
data Proc
= Proc [ParamDecl] [StmtAnnot ()]
data EvalState = EvalState
{ stProcs :: M.IntMap Proc
, stMainProc :: Maybe Proc
, globals :: Decls Value
, gl_Position :: Maybe Value
}
newtype EvalResult a = EvalResult { fromResult :: Either String a }
deriving (Functor, Applicative, Monad)
instance MonadFail EvalResult where
fail = EvalResult . Left
type Eval = StateT EvalState EvalResult
data Value
= FloatValue Float
| IntValue Int
| BoolValue Bool
| Vec2Value (V2 Float)
| Vec3Value (V3 Float)
| Vec4Value (V4 Float)
| Mat4x4Value (M44 Float)
deriving (Show, Eq)
defaultValue :: Type -> Value
defaultValue TyFloat = FloatValue 0
defaultValue (TyVec 2) = Vec2Value 0
defaultValue (TyVec 3) = Vec3Value 0
defaultValue (TyVec 4) = Vec4Value 0
defaultValue ty = error $ "defaultValue not implemented: " <> pp ppType ty
isNaNValue :: Value -> Bool
isNaNValue (FloatValue v) = isNaN v
isNaNValue _ = False
roundValue :: Value -> Value
roundValue (FloatValue v) =
FloatValue $ fromIntegral (round (v * 100000) :: Integer) / 100000
roundValue v = v
evalCoerce :: Type -> Value -> Eval Value
evalCoerce TyFloat v@FloatValue{} = return v
evalCoerce TyBool v@BoolValue{} = return v
evalCoerce TyFloat (IntValue i) = return $ FloatValue (fromIntegral i)
evalCoerce (TyVec 2) v@Vec2Value{} = return v
evalCoerce (TyVec 3) v@Vec3Value{} = return v
evalCoerce (TyVec 4) v@Vec4Value{} = return v
evalCoerce (TyMat 4 4) v@Mat4x4Value{} = return v
evalCoerce ty v = fail $ "coerce failed: " <> show (ty, v)
evalBinaryOp :: Value -> BinaryOp -> Value -> Value
evalBinaryOp (FloatValue l) BOpPlus (FloatValue r) = FloatValue (l + r)
evalBinaryOp (FloatValue l) BOpMinus (FloatValue r) = FloatValue (l - r)
evalBinaryOp (FloatValue l) BOpMul (FloatValue r) = FloatValue (l + r)
evalBinaryOp (FloatValue l) BOpDiv (FloatValue r) = FloatValue (l / r)
evalBinaryOp (FloatValue l) BOpLE (FloatValue r) = BoolValue (l <= r)
evalBinaryOp (FloatValue l) BOpGE (FloatValue r) = BoolValue (l >= r)
evalBinaryOp (FloatValue l) BOpLT (FloatValue r) = BoolValue (l < r)
evalBinaryOp (FloatValue l) BOpGT (FloatValue r) = BoolValue (l > r)
evalBinaryOp (IntValue l) BOpPlus (IntValue r) = IntValue (l + r)
evalBinaryOp (IntValue l) BOpMinus (IntValue r) = IntValue (l - r)
evalBinaryOp (IntValue l) BOpMul (IntValue r) = IntValue (l * r)
evalBinaryOp (Vec4Value l) BOpMul (Mat4x4Value r) = Vec4Value (r !* l)
evalBinaryOp (Mat4x4Value l) BOpMul (Mat4x4Value r) = Mat4x4Value (r !*! l)
evalBinaryOp l@FloatValue{} o (IntValue r) = evalBinaryOp l o (FloatValue $ fromIntegral r)
evalBinaryOp (IntValue l) o r@FloatValue{} = evalBinaryOp (FloatValue $ fromIntegral l) o r
evalBinaryOp l o r =
error $ "not implemented: " <> show (l, o, r)
evalUnaryOp :: UnaryOp -> Value -> Value
evalUnaryOp UOpMinus (FloatValue v) = FloatValue (-v)
evalUnaryOp UOpMinus (IntValue v) = IntValue (-v)
evalUnaryOp o e =
error $ "not implemented: " <> show (o, e)