module Graphics.GL.Low.VertexAttrib (
setVertexLayout,
VertexLayout(..),
DataType(..)
) where
import Foreign.C.String
import Foreign.Ptr
import Foreign.Marshal
import Foreign.Storable
import Control.Monad (forM_)
import Graphics.GL
import Graphics.GL.Low.Classes
data VertexLayout =
Attrib String Int DataType |
Unused Int
deriving Show
data DataType =
GLFloat |
GLByte |
GLUnsignedByte |
GLShort |
GLUnsignedShort |
GLInt |
GLUnsignedInt
deriving (Eq, Show)
setVertexLayout :: [VertexLayout] -> IO ()
setVertexLayout layout = do
p <- alloca (\ptr -> glGetIntegerv GL_CURRENT_PROGRAM ptr >> peek ptr)
if p == 0
then return ()
else do
let layout' = elaborateLayout 0 layout
let total = totalLayout layout
forM_ layout' $ \(name, size, offset, fmt) -> do
attrib <- withCString name $ \ptr -> glGetAttribLocation (fromIntegral p) (castPtr ptr)
let stride = total
glVertexAttribPointer
(fromIntegral attrib)
(fromIntegral size)
(toGL fmt)
GL_FALSE
(fromIntegral stride)
(castPtr (nullPtr `plusPtr` offset))
glEnableVertexAttribArray (fromIntegral attrib)
instance ToGL DataType where
toGL GLFloat = GL_FLOAT
toGL GLByte = GL_BYTE
toGL GLUnsignedByte = GL_UNSIGNED_BYTE
toGL GLShort = GL_SHORT
toGL GLUnsignedShort = GL_UNSIGNED_SHORT
toGL GLInt = GL_INT
toGL GLUnsignedInt = GL_UNSIGNED_INT
instance ToGL Bool where
toGL True = GL_TRUE
toGL False = GL_FALSE
elaborateLayout :: Int -> [VertexLayout] -> [(String, Int, Int, DataType)]
elaborateLayout here layout = case layout of
[] -> []
(Unused n):xs -> elaborateLayout (here+n) xs
(Attrib name n ty):xs ->
let size = n * sizeOfType ty in
(name, n, here, ty) : elaborateLayout (here+size) xs
totalLayout :: [VertexLayout] -> Int
totalLayout layout = sum (map arraySize layout) where
arraySize (Unused n) = n
arraySize (Attrib _ n ty) = n * sizeOfType ty
sizeOfType :: DataType -> Int
sizeOfType c = case c of
GLFloat -> 4
GLByte -> 1
GLUnsignedByte -> 1
GLShort -> 2
GLUnsignedShort -> 2
GLInt -> 4
GLUnsignedInt -> 4