module Graphics.Rendering.Ombra.Geometry.Types (
Vertex(..),
Triangle(..),
AttrTable(..),
AttrCol,
AttrVertex(..),
AttrPosition(..),
Geometry(..),
GeometryBuilder,
GeometryBuilderT(..),
Elements(..),
NotTop,
Previous,
Attributes(..)
) where
import Control.Monad.Trans.Class
import Control.Monad.Trans.State
import GHC.Exts (Constraint)
import qualified Data.Hashable as H
import Data.Functor.Identity (Identity)
import Data.Word (Word16)
import Graphics.Rendering.Ombra.Shader.CPU
data Triangle a = Triangle a a a
data Vertex (is :: [*]) where
Attr :: (Eq (CPU S i), H.Hashable (CPU S i), Attribute S i)
=> (a -> i)
-> CPU S i
-> Vertex '[i]
(:~) :: Vertex '[i] -> Vertex is -> Vertex (i ': is)
infixr 5 :~
data Elements is = Triangles Int [Triangle (AttrVertex is)]
data Geometry (is :: [*]) where
Geometry :: Attributes is
=> { topHash :: Int
, geometryHash :: Int
, top :: AttrCol is
, elements :: Elements is
, lastIndex :: Int
}
-> Geometry is
newtype GeometryBuilderT is m a = GeometryBuilderT (StateT (Geometry is) m a)
deriving (Functor, Applicative, Monad, MonadTrans)
type GeometryBuilder is = GeometryBuilderT is Identity
data AttrVertex (is :: [*]) where
AttrVertex :: NotTop p => Word16 -> AttrTable p is -> AttrVertex is
data AttrPosition = Top | Middle | Bottom | End
type family Previous (p :: AttrPosition) :: AttrPosition where
Previous Middle = Middle
Previous Bottom = Middle
Previous End = Bottom
data AttrTable (b :: AttrPosition) (is :: [*]) where
AttrNil :: AttrTable b '[]
AttrEnd :: AttrTable End is
AttrTop :: (NotTop p, Attribute 'S i)
=> Int
-> AttrTable Top is
-> AttrTable p (i ': is)
-> AttrTable Top (i ': is)
AttrCell :: (H.Hashable (CPU S i), Attribute 'S i)
=> CPU 'S i
-> AttrTable (Previous p) is
-> AttrTable p (i ': is)
-> AttrTable (Previous p) (i ': is)
type AttrCol = AttrTable Top
type NotTop p = Previous p ~ Previous p
class Attributes is where
emptyAttrCol :: AttrCol is
cell :: Vertex is -> AttrTable p is -> AttrTable (Previous p) is
addTop :: Vertex is -> AttrCol is -> AttrCol is
foldTop :: (forall i is. b -> AttrCol (i ': is) -> b)
-> b
-> AttrCol is
-> b
rowToVertex :: NotTop p => AttrTable p is -> Vertex is
instance (Attribute 'S i, Eq (CPU 'S i)) => Attributes '[i] where
emptyAttrCol = AttrTop (H.hash (0 :: Int)) AttrNil AttrEnd
cell (Attr _ x) down = AttrCell x AttrNil down
addTop v@(Attr _ x) (AttrTop thash next down) =
AttrTop (H.hashWithSalt (H.hash x + thash) thash)
next
(cell v down)
foldTop f acc top = f acc top
rowToVertex (AttrCell x _ _) = Attr (const undefined) x
instance (Attribute 'S i1, Eq (CPU 'S i1), Attributes (i2 ': is)) =>
Attributes (i1 ': (i2 ': is)) where
emptyAttrCol = AttrTop (H.hash (0 :: Int)) emptyAttrCol AttrEnd
cell (Attr _ x :~ v) down1@(AttrCell _ down2 _) =
AttrCell x (cell v down2) down1
cell (Attr _ x :~ v) AttrEnd = AttrCell x (cell v AttrEnd) AttrEnd
addTop v1@(Attr _ x :~ v2) (AttrTop thash next down) =
AttrTop (H.hashWithSalt (H.hash x + thash) thash)
(addTop v2 next)
(cell v1 down)
foldTop f acc top@(AttrTop _ next _) = foldTop f (f acc top) next
rowToVertex (AttrCell x next _) =
Attr (const undefined) x :~ rowToVertex next
instance Functor Triangle where
fmap f (Triangle x y z) = Triangle (f x) (f y) (f z)
instance H.Hashable (Vertex is) where
hashWithSalt s (Attr _ a) = H.hashWithSalt s a
hashWithSalt s (x :~ y) = H.hashWithSalt (H.hashWithSalt s x) y
instance Eq (Vertex is) where
(Attr _ x) == (Attr _ x') = x == x'
(Attr _ x :~ v) == (Attr _ x' :~ v') = x == x' && v == v'
instance H.Hashable a => H.Hashable (Triangle a) where
hashWithSalt salt (Triangle x y z) = H.hashWithSalt salt (x, y, z)
instance Eq (Geometry is) where
g == g' = geometryHash g == geometryHash g'
instance H.Hashable (Geometry is) where
hashWithSalt salt = H.hashWithSalt salt . geometryHash
instance H.Hashable (Elements is) where
hashWithSalt salt (Triangles h _) = H.hashWithSalt salt h
instance Eq (Elements is) where
(Triangles h _) == (Triangles h' _) = h == h'
instance H.Hashable (AttrVertex is) where
hashWithSalt salt (AttrVertex i _) = H.hashWithSalt salt i
instance Eq (AttrVertex is) where
(AttrVertex i _) == (AttrVertex i' _) = i == i'
instance H.Hashable (AttrCol is) where
hashWithSalt salt AttrNil = salt
hashWithSalt salt (AttrTop thash next _) =
H.hashWithSalt (H.hashWithSalt salt thash) next
instance Eq (AttrCol (i ': is)) where
(AttrTop h _ _) == (AttrTop h' _ _) = h == h'