lowgl-0.2.1.0: Graphics/GL/Low/BufferObject.hs
{-# LANGUAGE ScopedTypeVariables #-}
-- | VBO and ElementArrays. Both are buffer objects but are used for two
-- different things.
module Graphics.GL.Low.BufferObject (
VBO,
ElementArray,
UsageHint(..),
newVBO,
updateVBO,
bindVBO,
newElementArray,
updateElementArray,
bindElementArray,
deleteBufferObject
) where
import Foreign.Ptr
import Foreign.ForeignPtr
import Foreign.Marshal
import Foreign.Storable
import qualified Data.Vector.Storable as V
import Data.Vector.Storable (Vector)
import Data.Word
import Graphics.GL
import Graphics.GL.Low.Classes
-- | A VBO is a buffer object which has vertex data. Shader programs use VBOs
-- as input to their vertex attributes according to the configuration of the
-- bound VAO.
data VBO = VBO GLuint deriving Show
-- | A buffer object which has a packed sequence of vertex indices. Indexed
-- rendering uses the ElementArray bound to the element array binding target.
data ElementArray = ElementArray GLuint deriving Show
-- | Usage hint for allocation of buffer object storage.
data UsageHint = StaticDraw -- ^ Data will seldomly change.
| DynamicDraw -- ^ Data will change.
| StreamDraw -- ^ Data will change very often.
deriving Show
instance ToGL UsageHint where
toGL StaticDraw = GL_STATIC_DRAW
toGL DynamicDraw = GL_DYNAMIC_DRAW
toGL StreamDraw = GL_STREAM_DRAW
instance GLObject VBO where
glObjectName (VBO n) = fromIntegral n
instance GLObject ElementArray where
glObjectName (ElementArray n) = fromIntegral n
instance BufferObject VBO
instance BufferObject ElementArray
-- | Create a buffer object from a blob of bytes. The usage argument hints
-- at how often you will modify the data.
newVBO :: Storable a => Vector a -> UsageHint -> IO VBO
newVBO = newBufferObject VBO GL_ARRAY_BUFFER
-- | Delete a VBO or ElementArray.
deleteBufferObject :: BufferObject a => a -> IO ()
deleteBufferObject bo = withArray [glObjectName bo] (\ptr -> glDeleteBuffers 1 ptr)
-- | Modify the data in the currently bound VBO starting from the specified
-- index in bytes.
updateVBO :: Storable a => Vector a -> Int -> IO ()
updateVBO = updateBufferObject GL_ARRAY_BUFFER
-- | Bind a VBO to the array buffer binding target. The buffer object bound
-- there will be replaced, if any.
bindVBO :: VBO -> IO ()
bindVBO (VBO n) = glBindBuffer GL_ARRAY_BUFFER n
-- | Create a new ElementArray buffer object from the blob of packed indices.
-- The usage argument hints at how often you plan to modify the data.
newElementArray :: Storable a => Vector a -> UsageHint -> IO ElementArray
newElementArray = newBufferObject ElementArray GL_ELEMENT_ARRAY_BUFFER
-- | Modify contents in the currently bound ElementArray starting at the
-- specified index in bytes.
updateElementArray :: Storable a => Vector a -> Int -> IO ()
updateElementArray = updateBufferObject GL_ELEMENT_ARRAY_BUFFER
-- | Assign an ElementArray to the element array binding target. It will
-- replace the ElementArray already bound there, if any. Note that the state
-- of the element array binding target is a function of the current VAO.
bindElementArray :: ElementArray -> IO ()
bindElementArray (ElementArray n) = glBindBuffer GL_ELEMENT_ARRAY_BUFFER n
newBufferObject :: forall a b . Storable a => (GLuint -> b) -> GLenum -> Vector a -> UsageHint -> IO b
newBufferObject ctor target src usage = do
n <- alloca (\ptr -> glGenBuffers 1 ptr >> peek ptr)
glBindBuffer target n
let (fptr, off, len) = V.unsafeToForeignPtr src
let size = sizeOf (undefined :: a)
withForeignPtr fptr $ \ptr -> glBufferData
target
(fromIntegral (len * size))
(castPtr (ptr `plusPtr` off))
(toGL usage)
return (ctor n)
updateBufferObject :: forall a . Storable a => GLenum -> Vector a -> Int -> IO ()
updateBufferObject target bytes offset = do
let (fptr, off, len) = V.unsafeToForeignPtr bytes
let size = sizeOf (undefined :: a)
withForeignPtr fptr $ \ptr -> glBufferSubData
target
(fromIntegral offset)
(fromIntegral (len * size))
(castPtr (ptr `plusPtr` off))