module Graphics.Rendering.Ombra.Geometry.Internal (
AttrList(..),
AttrData(..),
Geometry(..),
ElemData(..),
LoadedBuffer,
LoadedAttribute,
LoadedGeometry(..),
Attributes(..),
geometry,
removeAttribute,
loadGeometry,
deleteGeometry
) where
import Control.Monad.Trans.Class
import Control.Monad.Trans.State
import qualified Data.Hashable as H
import Data.Typeable
import Data.Word (Word16)
import Unsafe.Coerce
import Graphics.Rendering.Ombra.Internal.GL
import Graphics.Rendering.Ombra.Internal.Resource
import Graphics.Rendering.Ombra.Shader.CPU
import Graphics.Rendering.Ombra.Shader.Default2D (Position2)
import Graphics.Rendering.Ombra.Shader.Default3D (Position3, Normal3)
import qualified Graphics.Rendering.Ombra.Shader.Default2D as D2
import qualified Graphics.Rendering.Ombra.Shader.Default3D as D3
import Graphics.Rendering.Ombra.Shader.Language.Types (ShaderType(size))
import Graphics.Rendering.Ombra.Vector
data AttrList (is :: [*]) where
AttrListNil :: AttrList '[]
AttrListCons :: (H.Hashable (CPU S i), Attribute S i)
=> AttrData i
-> AttrList is
-> AttrList (i ': is)
data AttrData i = AttrData [CPU S i] Int
data Geometry (is :: [*]) = Geometry (AttrList is) ElemData Int
data LoadedGeometry = LoadedGeometry {
elementCount :: Int,
vao :: VertexArrayObject
}
newtype LoadedBuffer = LoadedBuffer Buffer
data ElemData = ElemData [Word16] Int
data LoadedAttribute = LoadedAttribute GLUInt [(Buffer, GLUInt -> GL ())]
instance Eq (Geometry is) where
(Geometry _ _ h) == (Geometry _ _ h') = h == h'
instance H.Hashable (Geometry is) where
hashWithSalt salt (Geometry _ _ h) = H.hashWithSalt salt h
instance H.Hashable ElemData where
hashWithSalt salt (ElemData _ h) = H.hashWithSalt salt h
instance Eq ElemData where
(ElemData _ h) == (ElemData _ h') = h == h'
instance H.Hashable (AttrData i) where
hashWithSalt salt (AttrData _ h) = H.hashWithSalt salt h
instance Eq (AttrData i) where
(AttrData _ h) == (AttrData _ h') = h == h'
instance H.Hashable (AttrList is) where
hashWithSalt salt AttrListNil = salt
hashWithSalt salt (AttrListCons (AttrData _ h) al) =
H.hashWithSalt (H.hashWithSalt salt h) al
class Attributes (is :: [*]) where
emptyAttrList :: Proxy (is :: [*]) -> AttrList is
instance Attributes '[] where
emptyAttrList _ = AttrListNil
instance (H.Hashable (CPU S i), Attribute S i, Attributes is) =>
Attributes (i ': is) where
emptyAttrList (_ :: Proxy (i ': is)) =
AttrListCons (AttrData [] (H.hash (0 :: Int)) :: AttrData i) $
emptyAttrList (Proxy :: Proxy is)
geometry :: AttrList is -> ElemData -> Geometry is
geometry al es = Geometry al es $ H.hashWithSalt (H.hash al) es
removeAttribute :: (RemoveAttr i is is', GLES)
=> (a -> i)
-> Geometry is -> Geometry is'
removeAttribute g (Geometry al es _) = geometry (removeAttr g al) es
class RemoveAttr i is is' where
removeAttr :: (a -> i) -> AttrList is -> AttrList is'
instance RemoveAttr i (i ': is) is where
removeAttr _ (AttrListCons _ al) = al
instance RemoveAttr i is is' =>
RemoveAttr i (i1 ': is) (i1 ': is') where
removeAttr g (AttrListCons c al) =
AttrListCons c $ removeAttr g al
instance (GLES, Attribute 'S i) => Resource (AttrData i) LoadedAttribute GL where
loadResource (AttrData vs _ :: AttrData i) =
fmap (Right . uncurry LoadedAttribute) .
flip execStateT (0, []) $
withAttributes (Proxy :: Proxy 'S) (undefined :: i) vs $
\_ (g :: Proxy g) c ->
do (i, as) <- get
arr <- lift $ encodeAttribute g c
buf <- lift $
loadBuffer gl_ARRAY_BUFFER
arr
let sz = fromIntegral . size $
(undefined :: g)
set = setAttribute g . (+ i)
put (i + sz, (buf, set) : as)
unloadResource _ (LoadedAttribute _ as) =
mapM_ (\(buf, _) -> deleteBuffer buf) as
instance GLES => Resource ElemData LoadedBuffer GL where
loadResource (ElemData elems _) =
liftIO (encodeUShorts elems) >>=
fmap (Right . LoadedBuffer) .
loadBuffer gl_ELEMENT_ARRAY_BUFFER
. fromUInt16Array
unloadResource _ (LoadedBuffer buf) = deleteBuffer buf
loadGeometry :: (GLES, Monad m)
=> (forall i. Attribute 'S i => AttrData i -> m LoadedAttribute)
-> (ElemData -> m LoadedBuffer)
-> (forall a. GL a -> m a)
-> Geometry is
-> m LoadedGeometry
loadGeometry getAttr getElems gl (Geometry attrList elems@(ElemData es _) _) =
do vao <- gl createVertexArray
gl $ bindVertexArray vao
setAttrList getAttr gl (0 :: GLUInt) attrList
LoadedBuffer eb <- getElems elems
gl $ do bindBuffer gl_ELEMENT_ARRAY_BUFFER eb
bindVertexArray noVAO
bindBuffer gl_ELEMENT_ARRAY_BUFFER noBuffer
bindBuffer gl_ARRAY_BUFFER noBuffer
return $ LoadedGeometry (length es) vao
setAttrList :: (GLES, Monad m)
=> (forall i. Attribute 'S i => AttrData i -> m LoadedAttribute)
-> (forall a. GL a -> m a)
-> GLUInt
-> AttrList is
-> m ()
setAttrList getAttr gl i (AttrListCons attrData rest) =
do (LoadedAttribute sz as) <- getAttr attrData
gl $ mapM_ (\(buf, set) -> do bindBuffer gl_ARRAY_BUFFER buf
enableVertexAttribArray i
set i
) as
setAttrList getAttr gl (i + sz) rest
setAttrList _ _ _ AttrListNil = return ()
deleteGeometry :: GLES => LoadedGeometry -> GL ()
deleteGeometry (LoadedGeometry _ vao) = deleteVertexArray vao
loadBuffer :: GLES => GLEnum -> AnyArray -> GL Buffer
loadBuffer ty bufData =
do buffer <- createBuffer
bindBuffer ty buffer
bufferData ty bufData gl_STATIC_DRAW
bindBuffer ty noBuffer
return buffer