packages feed

hylogen-0.1.0.11: src/Hylogen/Types.hs

{-# LANGUAGE GADTs #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ExtendedDefaultRules #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}

module Hylogen.Types where


import Data.Monoid
import Data.VectorSpace
import GHC.Exts (Constraint)
import Data.Hashable
import GHC.Generics

class (ConstructFrom' tuple hprim, Show tuple, Vec hprim) => ConstructFrom tuple hprim where
  exprFormFromTuple :: tuple -> hprim -> Expr

instance ConstructFrom Float Vec1 where
  exprFormFromTuple x _ = Uniform GLSLFloat (show x) -- TODO: this is a hack!
instance ConstructFrom (Vec1, Vec1) Vec2 where
  exprFormFromTuple (x, y) _  = BinaryOpPre GLSLVec2 "vec2" (toExpr x) (toExpr y)
instance ConstructFrom (Vec1, Vec1, Vec1) Vec3 where
  exprFormFromTuple (x, y, z) _  = TernaryOpPre GLSLVec3 "vec3" (toExpr x) (toExpr y) (toExpr z)
instance ConstructFrom (Vec2, Vec1) Vec3 where
  exprFormFromTuple (x, y) _  = BinaryOpPre  GLSLVec3 "vec3" (toExpr x) (toExpr y)
instance ConstructFrom (Vec1, Vec2) Vec3 where
  exprFormFromTuple (x, y) _  = BinaryOpPre  GLSLVec3 "vec3" (toExpr x) (toExpr y)
instance ConstructFrom (Vec1, Vec1, Vec1, Vec1) Vec4 where
  exprFormFromTuple (x, y, z, w) _  = QuaternaryOpPre GLSLVec4 "vec4" (toExpr x) (toExpr y) (toExpr z) (toExpr w)
instance ConstructFrom (Vec2, Vec1, Vec1) Vec4 where
  exprFormFromTuple (x, y, z) _  = TernaryOpPre GLSLVec4 "vec4" (toExpr x) (toExpr y) (toExpr z)
instance ConstructFrom (Vec1, Vec2, Vec1) Vec4 where
  exprFormFromTuple (x, y, z) _  = TernaryOpPre GLSLVec4 "vec4" (toExpr x) (toExpr y) (toExpr z)
instance (a ~ Vec1, b ~ Vec1) => ConstructFrom (a, b, Vec2) Vec4 where
  exprFormFromTuple (x, y, z) _  = TernaryOpPre GLSLVec4 "vec4" (toExpr x) (toExpr y) (toExpr z)
instance ConstructFrom (Vec3, Vec1) Vec4 where
  exprFormFromTuple (x, y) _  = BinaryOpPre GLSLVec4 "vec4" (toExpr x) (toExpr y)
instance (a ~ Vec1) => ConstructFrom (a, Vec3) Vec4 where
  exprFormFromTuple (x, y) _  = BinaryOpPre GLSLVec4 "vec4" (toExpr x) (toExpr y)
instance (a ~ Vec2) => ConstructFrom (a, Vec2) Vec4 where
  exprFormFromTuple (x, y) _  = BinaryOpPre GLSLVec4 "vec4" (toExpr x) (toExpr y)

type family (ConstructFrom' tuple hprim) :: Constraint where
  ConstructFrom' a Vec1 = a ~ Float
  ConstructFrom' (a, b) Vec2 = (a ~ Vec1, b ~ Vec1)

  ConstructFrom' (a, b, c) Vec3 = (a ~ Vec1, b ~ Vec1, c ~ Vec1)
  ConstructFrom' (Vec2, b) Vec3 = (b ~ Vec1)
  ConstructFrom' (a, Vec2) Vec3 = (a ~ Vec1)

  ConstructFrom' (a, b, c, d) Vec4 = (a ~ Vec1, b ~ Vec1, c ~ Vec1, d ~ Vec1)
  ConstructFrom' (Vec3, b) Vec4 = (b ~ Vec1)
  ConstructFrom' (Vec2, b) Vec4 = (b ~ Vec2)
  ConstructFrom' (a, Vec3) Vec4 = (a ~ Vec1)


  -- ConstructFrom' (Vec1, Vec1, Vec2) Vec4 = ()
  -- ConstructFrom' (Vec1, Vec2, Vec1) Vec4 = ()
  -- ConstructFrom' (Vec2, Vec1, Vec1) Vec4 = ()

  ConstructFrom' (Vec2, b, c) Vec4 = (b ~ Vec1, c ~ Vec1)
  ConstructFrom' (a, Vec2, c) Vec4 = (a ~ Vec1, c ~ Vec1) -- works
  ConstructFrom' (a, b, Vec2) Vec4 = (a ~ Vec1, b ~ Vec1)





class (Expressible v, Show v) => Vec v where
  vec :: (ConstructFrom tuple v) => tuple -> v
  vu :: String -> v
  vuop :: String -> v -> v
  vuoppre :: String -> v -> v
  vbop :: String -> v -> v -> v
  vboppre :: String -> v -> v -> v
  select :: Booly -> v -> v -> v
  fromVec1 :: Vec1 -> v
  toList :: v -> [Vec1]



class (Expressible a, Show a) => HasX a
class HasX a => HasY a
class HasY a => HasZ a
class HasZ a => HasW a


data Vec1 where
  Vec1 :: Float -> Vec1
  V1u :: String -> Vec1
  V1uop :: String -> Vec1 -> Vec1
  V1uoppre :: String -> Vec1 -> Vec1
  V1bop :: String -> Vec1 -> Vec1 -> Vec1
  V1boppre :: String -> Vec1 -> Vec1 -> Vec1
  V1select :: Booly -> Vec1 -> Vec1 -> Vec1
  Dot :: (Vec a) => a -> a -> Vec1
  X :: (HasX a) => a -> Vec1
  Y :: (HasY a) => a -> Vec1
  Z :: (HasZ a) => a -> Vec1
  W :: (HasW a) => a -> Vec1



instance Show Vec1 where
  show expr = case expr of
    Vec1 x -> show x
    V1u x -> x
    V1uop u x -> u <> "(" <> show x <> ")"
    V1uoppre u x -> "(" <> u <> show x <> ")"
    V1bop b x y -> "(" <> show x <> " " <> b <> " " <> show y <> ")"
    V1boppre b x y -> b <> "(" <> show x <> ", " <> show y <> ")"
    V1select b x y -> "( " <> show b <> " ? " <> show x <> " : " <> show y <> ")"
    Dot x y -> "dot(" <> show x <> ", " <> show y <> ")"
    X x ->  show x <> ".x"
    Y x ->  show x <> ".y"
    Z x ->  show x <> ".z"
    W x ->  show x <> ".w"


instance Vec Vec1 where
  vec = Vec1
  vu = V1u
  vuop = V1uop
  vuoppre = V1uoppre
  vbop = V1bop
  vboppre = V1boppre
  select = V1select
  fromVec1 = id
  toList x = [x]

instance Num Vec1 where
  (+) = vbop "+"
  (*) = vbop "*"
  negate = vuoppre "-"
  abs = vuop "abs"
  signum = vuop "sign"
  fromInteger = Vec1 . fromInteger

instance Fractional Vec1 where
  (/) = vbop "/"
  recip = vbop "/" 1
  fromRational = Vec1 . fromRational


instance Floating Vec1 where
  pi = vu "pi"
  exp = vuop "exp"
  log = vuop "log"
  sqrt = vuop "sqrt"
  (**) = vboppre "pow"
  sin = vuop "sin"
  cos = vuop "cos"
  tan = vuop "tan"
  asin = vuop "asin"
  acos = vuop "acos"
  atan = vuop "atan"
  sinh x = (exp x - exp (negate x))/2
  cosh x = (exp x + exp (negate x))/2
  tanh x = sinh x / cosh x
  asinh x = log $ x + sqrt(x**2 + 1)
  acosh x = log $ x + sqrt(x**2 - 1)
  atanh x = 0.5 * log ((1 + x)/(1 - x))

instance AdditiveGroup Vec1 where
  zeroV = 0
  (^+^) = (+)
  negateV = negate
  (^-^) = (-)

instance VectorSpace Vec1 where
  type Scalar Vec1 = Vec1
  a *^ b = a * b

instance InnerSpace Vec1 where
  (<.>) = Dot

-- | Vec2:

data Vec2 where
  Vec2 :: (ConstructFrom tuple Vec2) => tuple -> Vec2
  V2u :: String -> Vec2
  V2uop :: String -> Vec2 -> Vec2
  V2uoppre :: String -> Vec2 -> Vec2
  V2bop :: String -> Vec2 -> Vec2 -> Vec2
  V2boppre :: String -> Vec2 -> Vec2 -> Vec2
  V2bops :: String -> Vec1 -> Vec2 -> Vec2
  V2select :: Booly -> Vec2 -> Vec2 -> Vec2


instance Vec Vec2 where
  vec = Vec2
  vu = V2u
  vuop = V2uop
  vuoppre = V2uoppre
  vbop = V2bop
  vboppre = V2boppre
  select = V2select
  fromVec1 x = Vec2 (x, x)
  toList x = [X x, Y x]


instance Show Vec2 where
  show expr = case expr of
    Vec2 tuple -> "vec2" <> show tuple
    V2u x -> x
    V2uop u x -> u <> "(" <> show x <> ")"
    V2uoppre u x -> "(" <> u <> show x <> ")"
    V2bop b x y -> "(" <> show x <> " " <> b <> " " <> show y <> ")"
    V2boppre b x y -> b <> "(" <> show x <> ", " <> show y <> ")"
    V2bops b x y -> "(" <> show x <> " " <> b <> " " <> show y <> ")"
    V2select b x y -> "( " <> show b <> " ? " <> show x <> " : " <> show y <> ")"

instance Num Vec2 where
  (+) = vbop "+"
  (*) = vbop "*"
  negate = vuoppre "-"
  abs = vuop "abs"
  signum = vuop "sign"
  fromInteger = fromVec1 . fromInteger

instance Fractional Vec2 where
  (/) = vbop "/"
  recip = vbop "/" 1
  fromRational = fromVec1 . fromRational


instance Floating Vec2 where
  pi = vu "pi"
  exp = vuop "exp"
  log = vuop "log"
  sqrt = vuop "sqrt"
  (**) = vboppre "pow"
  sin = vuop "sin"
  cos = vuop "cos"
  tan = vuop "tan"
  asin = vuop "asin"
  acos = vuop "acos"
  atan = vuop "atan"
  sinh x = (exp x - exp (negate x))/2
  cosh x = (exp x + exp (negate x))/2
  tanh x = sinh x / cosh x
  asinh x = log $ x + sqrt(x**2 + 1)
  acosh x = log $ x + sqrt(x**2 - 1)
  atanh x = 0.5 * log ((1 + x)/(1 - x))

instance AdditiveGroup Vec2 where
  zeroV = 0
  (^+^) = (+)
  negateV = negate
  (^-^) = (-)

instance VectorSpace Vec2 where
  type Scalar Vec2 = Vec1
  a *^ b = V2bops "*" a b

instance InnerSpace Vec2 where
  (<.>) = Dot

instance HasX Vec2
instance HasY Vec2


-- | Vec3:

data Vec3 where
  Vec3 :: (ConstructFrom tuple Vec3) => tuple -> Vec3
  V3u :: String -> Vec3
  V3uop :: String -> Vec3 -> Vec3
  V3uoppre :: String -> Vec3 -> Vec3
  V3bop :: String -> Vec3 -> Vec3 -> Vec3
  V3boppre :: String -> Vec3 -> Vec3 -> Vec3
  V3bops :: String -> Vec1 -> Vec3 -> Vec3
  V3select :: Booly -> Vec3 -> Vec3 -> Vec3

instance Vec Vec3 where
  vec = Vec3
  vu = V3u
  vuop = V3uop
  vuoppre = V3uoppre
  vbop = V3bop
  vboppre = V3boppre
  select = V3select
  fromVec1 x = Vec3 (x, x, x)
  toList x = [X x, Y x, Z x]

instance Show Vec3 where
  show expr = case expr of
    Vec3 tuple -> "vec3" <> show tuple
    V3u x -> x
    V3uop u x -> u <> "(" <> show x <> ")"
    V3uoppre u x -> "(" <> u <> show x <> ")"
    V3bop b x y -> "(" <> show x <> " " <> b <> " " <> show y <> ")"
    V3boppre b x y -> b <> "(" <> show x <> ", " <> show y <> ")"
    V3bops b x y -> "(" <> show x <> " " <> b <> " " <> show y <> ")"
    V3select b x y -> "( " <> show b <> " ? " <> show x <> " : " <> show y <> ")"

instance Num Vec3 where
  (+) = vbop "+"
  (*) = vbop "*"
  negate = vuoppre "-"
  abs = vuop "abs"
  signum = vuop "sign"
  fromInteger = fromVec1 . fromInteger

instance Fractional Vec3 where
  (/) = vbop "/"
  recip = vbop "/" 1
  fromRational = fromVec1 . fromRational


instance Floating Vec3 where
  pi = vu "pi"
  exp = vuop "exp"
  log = vuop "log"
  sqrt = vuop "sqrt"
  (**) = vboppre "pow"
  sin = vuop "sin"
  cos = vuop "cos"
  tan = vuop "tan"
  asin = vuop "asin"
  acos = vuop "acos"
  atan = vuop "atan"
  sinh x = (exp x - exp (negate x))/2
  cosh x = (exp x + exp (negate x))/2
  tanh x = sinh x / cosh x
  asinh x = log $ x + sqrt(x**2 + 1)
  acosh x = log $ x + sqrt(x**2 - 1)
  atanh x = 0.5 * log ((1 + x)/(1 - x))

instance AdditiveGroup Vec3 where
  zeroV = 0
  (^+^) = (+)
  negateV = negate
  (^-^) = (-)

instance VectorSpace Vec3 where
  type Scalar Vec3 = Vec1
  a *^ b = V3bops "*" a b

instance InnerSpace Vec3 where
  (<.>) = Dot

instance HasX Vec3
instance HasY Vec3
instance HasZ Vec3



-- | Vec4:

data Vec4 where
  Vec4 :: (ConstructFrom tuple Vec4) => tuple -> Vec4
  V4u :: String -> Vec4
  V4uop :: String -> Vec4 -> Vec4
  V4uoppre :: String -> Vec4 -> Vec4
  V4bop :: String -> Vec4 -> Vec4 -> Vec4
  V4boppre :: String -> Vec4 -> Vec4 -> Vec4
  V4bops :: String -> Vec1 -> Vec4 -> Vec4
  V4select :: Booly -> Vec4 -> Vec4 -> Vec4
  Texture2D :: Texture -> Vec2 -> Vec4


instance Vec Vec4 where
  vec = Vec4
  vu = V4u
  vuop = V4uop
  vuoppre = V4uoppre
  vbop = V4bop
  vboppre = V4boppre
  select = V4select
  fromVec1 x = Vec4 (x, x, x, x)
  toList x = [X x, Y x, Z x, W x]

instance Show Vec4 where
  show expr = case expr of
    Vec4 tuple -> "vec4" <> show tuple
    V4u x -> x
    V4uop u x -> u <> "(" <> show x <> ")"
    V4uoppre u x -> "(" <> u <> show x <> ")"
    V4bop b x y -> "(" <> show x <> " " <> b <> " " <> show y <> ")"
    V4boppre b x y -> b <> "(" <> show x <> ", " <> show y <> ")"
    V4bops b x y -> "(" <> show x <> " " <> b <> " " <> show y <> ")"
    V4select b x y -> "( " <> show b <> " ? " <> show x <> " : " <> show y <> ")"
    Texture2D t v -> "texture2D(" <> show t <> ", " <> show v <> ")"

instance Num Vec4 where
  (+) = vbop "+"
  (*) = vbop "*"
  negate = vuoppre "-"
  abs = vuop "abs"
  signum = vuop "sign"
  fromInteger = fromVec1 . fromInteger

instance Fractional Vec4 where
  (/) = vbop "/"
  recip = vbop "/" 1
  fromRational = fromVec1 . fromRational


instance Floating Vec4 where
  pi = vu "pi"
  exp = vuop "exp"
  log = vuop "log"
  sqrt = vuop "sqrt"
  (**) = vboppre "pow"
  sin = vuop "sin"
  cos = vuop "cos"
  tan = vuop "tan"
  asin = vuop "asin"
  acos = vuop "acos"
  atan = vuop "atan"
  sinh x = (exp x - exp (negate x))/2
  cosh x = (exp x + exp (negate x))/2
  tanh x = sinh x / cosh x
  asinh x = log $ x + sqrt(x**2 + 1)
  acosh x = log $ x + sqrt(x**2 - 1)
  atanh x = 0.5 * log ((1 + x)/(1 - x))

instance AdditiveGroup Vec4 where
  zeroV = 0
  (^+^) = (+)
  negateV = negate
  (^-^) = (-)

instance VectorSpace Vec4 where
  type Scalar Vec4 = Vec1
  a *^ b = V4bops "*" a b

instance InnerSpace Vec4 where
  (<.>) = Dot

instance HasX Vec4
instance HasY Vec4
instance HasZ Vec4
instance HasW Vec4


data Texture where
  Tu :: String -> Texture

instance Show Texture where
  show (Tu xs) = xs

-- | We implement Bool as a Num

data Booly where
  Bu:: String -> Booly
  Buop :: String -> Booly -> Booly
  Buoppre :: String -> Booly -> Booly
  Bbop :: String -> Booly -> Booly -> Booly
  Bcomp :: (Vec a) => String -> a -> a -> Booly
  Bcomp_ :: String -> Vec1 -> Vec1 -> Booly

instance Show Booly where
  show expr = case expr of
    Bu x -> x
    Buop u x -> u <> "(" <> show x <> ")"
    Buoppre u x -> "(" <> u <> show x <> ")"
    Bbop u x y -> "(" <> show x <> " " <> u <> " " <>  show y <> ")"
    Bcomp u x y -> show . product $ zipWith (Bcomp_ u) (toList x) (toList y)
    Bcomp_ u x y -> "(" <> show x <> " " <> u <> " " <>  show y <> ")"

instance Num Booly where
  (+) = Bbop "||"
  (*) = Bbop "&&"
  negate = Buoppre "!"
  abs = id
  signum = id
  fromInteger x
    | x > 0 = Bu "true"
    | otherwise = Bu "false"




instance Hashable Vec1 where
  hashWithSalt salt x = hashWithSalt salt $ ("vec1", show x)
instance Hashable Vec2 where
  hashWithSalt salt x = hashWithSalt salt $ ("vec2", show x)
instance Hashable Vec3 where
  hashWithSalt salt x = hashWithSalt salt $ ("vec3", show x)
instance Hashable Vec4 where
  hashWithSalt salt x = hashWithSalt salt $ ("vec4", show x)
instance Hashable Booly where
  hashWithSalt salt x = hashWithSalt salt $ ("booly", show x)

instance Hashable Texture where
  hashWithSalt salt x = hashWithSalt salt $ ("texture2D", show x)

-- TODO: textures cannot be saved as variable!



data GLSLType = GLSLFloat
              | GLSLVec2
              | GLSLVec3
              | GLSLVec4
              | GLSLBool
              | GLSLTexture
              deriving (Generic, Hashable, Eq, Ord)

instance Show GLSLType where
  show x = case x of
    GLSLFloat -> "float"
    GLSLVec2 -> "vec2"
    GLSLVec3 -> "vec3"
    GLSLVec4 -> "vec4"
    GLSLBool -> "bool"
    GLSLTexture -> "(texture)" -- this should never be variablized

newtype Hash = Hash Int
  deriving (Generic, Hashable, Eq, Ord)
instance Show Hash where
  show (Hash i) = "h_" <> show i

data HashTree = Leaf Hash Expr | Branch Hash Expr [HashTree]
  deriving (Generic, Hashable, Show, Eq, Ord)

class (Show a) => Expressible a where
  toExpr :: a -> Expr



-- TODO: get rid of Vec?, replace with Expr? at least get rid of all the duplicate show statements in my primitives!

data Expr = Uniform GLSLType String
          | UnaryOp  GLSLType String Expr
          | UnaryOpPre GLSLType String Expr
          | BinaryOp GLSLType String Expr Expr
          | BinaryOpPre GLSLType String Expr Expr
          | TernaryOpPre GLSLType String Expr Expr Expr
          | QuaternaryOpPre GLSLType String Expr Expr Expr Expr
          | Select GLSLType Expr Expr Expr -- for ternary selection
          | Access GLSLType String Expr -- field accessor
          deriving (Generic, Hashable, Eq, Ord)

-- TODO: is there any way to do this automatically?
getType :: Expr -> GLSLType
getType x = case x of
  Uniform ty _ -> ty
  UnaryOp ty _ _ -> ty
  UnaryOpPre ty _ _ -> ty
  BinaryOp ty _ _ _ -> ty
  BinaryOpPre ty _ _ _ -> ty
  TernaryOpPre ty _ _ _ _ -> ty
  QuaternaryOpPre ty _ _ _ _ _ -> ty
  Select ty _ _ _ -> ty
  Access ty _ _ -> ty

instance Show Expr where
  show foo = case foo of
    Uniform _ x                  -> x
    UnaryOp _  u x               -> u <> "(" <> show x <> ")"
    UnaryOpPre _  u x            -> "(" <> u <> show x <> ")"
    BinaryOp _  b x y            -> "(" <> show x <> " " <> b <> " " <> show y <> ")"
    BinaryOpPre _  b x y         -> b <> "(" <> show x <> ", " <> show y <> ")"
    TernaryOpPre _  b x y z      -> b <> "(" <> show x <> ", " <> show y <> ", " <> show z <> ")"
    QuaternaryOpPre _  b x y z w -> b <> "(" <> show x <> ", " <> show y <> ", " <> show z <> ", " <> show w <> ")"
    Select _  b x y              -> "( " <> show b <> " ? " <> show x <> " : " <> show y <> ")"
    Access _  field x            ->  show x <> "." <> field

-- Type information?
-- STring information?
toHashTree :: Expr -> HashTree
toHashTree exprForm = case exprForm of
  a@(Uniform ty str)              -> mkLeaf (ty, str) a
  UnaryOp ty  str x               -> mkBranch1 (ty, str) exprForm x
  UnaryOpPre ty  str x            -> mkBranch1 (ty, str) exprForm x
  BinaryOp ty  str x y            -> mkBranch2 (ty, str) exprForm x y
  BinaryOpPre ty  str x y         -> mkBranch2 (ty, str) exprForm x y
  TernaryOpPre ty  str x y z      -> mkBranch3 (ty, str) exprForm x y z
  QuaternaryOpPre ty  str x y z w -> mkBranch4 (ty, str) exprForm x y z w
  Select ty b x y                 -> mkBranch3 (ty, "?:") exprForm b x y
  Access ty str x                 -> mkBranch1 (ty, "." <> str) exprForm x

type HashContext = (GLSLType, String)

mkLeaf :: HashContext -> Expr -> HashTree
mkLeaf hc expr = Leaf (Hash $ hash (expr, hc)) expr

mkBranch1 :: HashContext -> Expr -> Expr -> HashTree
mkBranch1 hc expr x = Branch (Hash $ hash (expr, hc, subTrees)) expr subTrees
  where
    subTrees = [toHashTree x]

mkBranch2 :: HashContext -> Expr -> Expr -> Expr -> HashTree
mkBranch2 hc expr x y = Branch (Hash $ hash (expr, hc, subTrees)) expr subTrees
  where
    subTrees = [toHashTree x, toHashTree y]

mkBranch3 :: HashContext -> Expr -> Expr -> Expr -> Expr -> HashTree
mkBranch3 hc expr x y z = Branch (Hash $ hash (expr, hc, subTrees)) expr subTrees
  where
    subTrees = [toHashTree x, toHashTree y, toHashTree z]

mkBranch4 :: HashContext -> Expr -> Expr -> Expr -> Expr -> Expr -> HashTree
mkBranch4 hc expr x y z w = Branch (Hash $ hash (expr, hc, subTrees)) expr subTrees
  where
    subTrees = [toHashTree x, toHashTree y, toHashTree z, toHashTree w]

-- TODO: tag strings so hash is correct

instance Expressible Vec1 where
  toExpr foo = case foo of
    Vec1 x           -> exprFormFromTuple x foo
    V1u str          -> Uniform ty str
    V1uop str x      -> UnaryOp ty str (toExpr x)
    V1uoppre str x   -> UnaryOpPre ty str (toExpr x)
    V1bop str x y    -> BinaryOp ty str (toExpr x) (toExpr y)
    V1boppre str x y -> BinaryOpPre ty str (toExpr x) (toExpr y)
    V1select b x y   -> Select ty (toExpr b) (toExpr x) (toExpr y)
    Dot x y          -> BinaryOpPre ty "dot" (toExpr x) (toExpr y)
    X x              -> Access ty "x" (toExpr x)
    Y x              -> Access ty "y" (toExpr x)
    Z x              -> Access ty "z" (toExpr x)
    W x              -> Access ty "w" (toExpr x)
    where
      ty = GLSLFloat

instance Expressible Vec2 where
  toExpr foo = case foo of
    Vec2 x           -> exprFormFromTuple x foo
    V2u str          -> Uniform ty str
    V2uop str x      -> UnaryOp ty str (toExpr x)
    V2uoppre str x   -> UnaryOpPre ty str (toExpr x)
    V2bop str x y    -> BinaryOp ty str (toExpr x) (toExpr y)
    V2boppre str x y -> BinaryOpPre ty str (toExpr x) (toExpr y)
    V2bops str x y   -> BinaryOp ty str (toExpr x) (toExpr y)
    V2select b x y   -> Select ty (toExpr b) (toExpr x) (toExpr y)
    where
      ty = GLSLVec2

instance Expressible Vec3 where
  toExpr foo = case foo of
    Vec3 x           -> exprFormFromTuple x foo
    V3u str          -> Uniform ty str
    V3uop str x      -> UnaryOp ty str (toExpr x)
    V3uoppre str x   -> UnaryOpPre ty str (toExpr x)
    V3bop str x y    -> BinaryOp ty str (toExpr x) (toExpr y)
    V3boppre str x y -> BinaryOpPre ty str (toExpr x) (toExpr y)
    V3bops str x y   -> BinaryOp ty str (toExpr x) (toExpr y)
    V3select b x y   -> Select ty (toExpr b) (toExpr x) (toExpr y)
    where
      ty = GLSLVec3

instance Expressible Vec4 where
  toExpr foo = case foo of
    Vec4 x           -> exprFormFromTuple x foo
    V4u str          -> Uniform ty str
    V4uop str x      -> UnaryOp ty str (toExpr x)
    V4uoppre str x   -> UnaryOpPre ty str (toExpr x)
    V4bop str x y    -> BinaryOp ty str (toExpr x) (toExpr y)
    V4boppre str x y -> BinaryOpPre ty str (toExpr x) (toExpr y)
    V4bops str x y   -> BinaryOp ty str (toExpr x) (toExpr y)
    V4select b x y   -> Select ty (toExpr b) (toExpr x) (toExpr y)
    Texture2D t x    -> BinaryOpPre ty "texture2D" (toExpr t) (toExpr x)
    where
      ty = GLSLVec4

instance Expressible Booly where
  toExpr foo = case foo of
    Bu str -> Uniform ty str
    Buop str x -> UnaryOp ty str (toExpr x)
    Buoppre str x -> UnaryOpPre ty str (toExpr x)
    Bbop str x y -> BinaryOp ty str (toExpr x) (toExpr y)
    Bcomp_ str x y -> BinaryOp ty str (toExpr x) (toExpr y)
    Bcomp str x y -> toExpr . product $ zipWith (Bcomp_ str) (toList x) (toList y)
    where
      ty = GLSLBool

instance Expressible Texture where
  toExpr (Tu str) = Uniform ty str
    where
      ty = GLSLTexture

-- | Existential
-- data Expr where
--   ToExpr :: (Expressible a) => a -> Expr

-- instance Show Expr where
--   show (ToExpr a) = show (getType a) <> " blah = " <> show a <> ";"


  -- TODO: implement Variable as a contructor for Expression
-- data Variable where
--   VVec1 :: Vec1 -> Variable
--   VVec2 :: Vec2 -> Variable
--   VVec3 :: Vec3 -> Variable
--   VBooly :: Booly -> Variable

-- instance Num (Context Vec1) where