hylogen-0.1.0.11: src/Hylogen/CSE.hs
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
module Hylogen.CSE where
import qualified Data.Map as Map
import Data.Monoid
import Hylogen.Types
import Control.Monad.State.Lazy
import Data.List
type Id = Int
type Count = Int
-- | Add if in first, variabalize!
newtype GLSL = GLSL (Map.Map Id Expr, Map.Map Hash (Id, Count))
getTopLevel :: GLSL -> Expr
getTopLevel (GLSL (id2expr, _)) = case Map.maxViewWithKey id2expr of
Nothing -> error "must have top level?"
Just ((k, e), _) -> Uniform (getType e) ("_" <> show k)
type GLSLState = State GLSL
addNode:: Hash -> Expr -> GLSLState Id
addNode hashish expr = do
GLSL (id2expr, hash2id) <- get
let newid = case Map.maxViewWithKey id2expr of
Nothing -> 0
Just ((k, _), _) -> k + 1
if Map.member hashish hash2id
then do
modify (\(GLSL (foo, bar)) -> GLSL ( foo
, Map.adjust (\(a, b) -> (a, b+1)) hashish bar
))
return $ fst $ hash2id Map.! hashish
else do
modify (\(GLSL (foo, bar)) -> GLSL ( Map.insert newid expr foo
, Map.insert hashish (newid, 1) bar
))
return $ newid
addTree :: HashTree -> GLSLState ()
addTree ht = case ht of
Leaf h e -> do
-- _ <- addNode h e
return ()
Branch h e subTrees -> do
-- | post-order traversal guarantees topological ordering!
forM_ subTrees addTree
i <- addNode h e
newExpr <- variablize e subTrees
modify (\(GLSL (foo, bar)) -> GLSL ( Map.adjust (const newExpr) i foo
, bar ))
genGLSL :: (Expressible a) => a -> GLSL
genGLSL x = execState (addTree . toHashTree . toExpr $ x ) initialGLSL
where
initialGLSL :: GLSL
initialGLSL = GLSL (Map.empty, Map.empty)
glslToAssignments:: GLSL -> [String]
glslToAssignments glsl = do
let (GLSL (id2expr, _)) = glsl
fmap assign $ Map.toList id2expr
where
assign :: (Id, Expr) -> String
assign (i, e) = show (getType e) <> " " <> "_" <> show i <> " = " <> show e <> ";"
getName :: HashTree -> GLSLState String
getName ht = do
let h = case ht of
Leaf h _ -> h
Branch h _ _ -> h
GLSL (_, hash2id) <- get
return $ "_" <> show (fst $ hash2id Map.! h)
variablize :: Expr -> [HashTree] -> GLSLState Expr
variablize expr subTrees = case expr of
Uniform ty st
-> return $ Uniform ty st
UnaryOp ty st x
-> UnaryOp ty st
<$> f x (subTrees !! 0)
UnaryOpPre ty st x
-> UnaryOpPre ty st
<$> f x (subTrees !! 0)
BinaryOp ty st x y
-> BinaryOp ty st
<$> f x (subTrees !! 0)
<*> f y (subTrees !! 1)
BinaryOpPre ty st x y
-> BinaryOpPre ty st
<$> f x (subTrees !! 0)
<*> f y (subTrees !! 1)
TernaryOpPre ty st x y z
-> TernaryOpPre ty st
<$> f x (subTrees !! 0)
<*> f y (subTrees !! 1)
<*> f z (subTrees !! 2)
QuaternaryOpPre ty st x y z w
-> QuaternaryOpPre ty st
<$> f x (subTrees !! 0)
<*> f y (subTrees !! 1)
<*> f z (subTrees !! 2)
<*> f w (subTrees !! 3)
Select ty x y z
-> Select ty
<$> f x (subTrees !! 0)
<*> f y (subTrees !! 1)
<*> f z (subTrees !! 2)
Access ty st x
-> Access ty st
<$> f x (subTrees !! 0)
where
f :: Expr -> HashTree -> GLSLState Expr
f x ht = do
let h = case ht of
Leaf h _ -> h
Branch h _ _ -> h
(GLSL (_, hash2id)) <- get
if Map.member h hash2id
then Uniform (getType x) <$> (getName ht)
else return x