module Graphics.GL.Low.VertexAttrib 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 LayoutElement =
Attrib String Int ComponentFormat |
Unused Int
deriving Show
type VertexAttributeLayout = [LayoutElement]
data ComponentFormat =
VFloat |
VByte |
VUByte |
VByteNormalized |
VUByteNormalized |
VShort |
VUShort |
VShortNormalized |
VUShortNormalized |
VInt |
VUInt |
VIntNormalized |
VUIntNormalized
deriving (Eq, Show)
instance ToGL ComponentFormat where
toGL VFloat = GL_FLOAT
toGL VByte = GL_BYTE
toGL VUByte = GL_UNSIGNED_BYTE
toGL VByteNormalized = GL_BYTE
toGL VUByteNormalized = GL_UNSIGNED_BYTE
toGL VShort = GL_SHORT
toGL VUShort = GL_UNSIGNED_SHORT
toGL VShortNormalized = GL_SHORT
toGL VUShortNormalized = GL_UNSIGNED_SHORT
toGL VInt = GL_INT
toGL VUInt = GL_UNSIGNED_INT
toGL VIntNormalized = GL_INT
toGL VUIntNormalized = GL_UNSIGNED_INT
elaborateLayout :: Int -> VertexAttributeLayout -> [(String, Int, Int, ComponentFormat)]
elaborateLayout here layout = case layout of
[] -> []
(Unused n):xs -> elaborateLayout (here+n) xs
(Attrib name n fmt):xs ->
let size = n * sizeOfVertexComponent fmt in
(name, n, here, fmt) : elaborateLayout (here+size) xs
totalLayout :: VertexAttributeLayout -> Int
totalLayout layout = sum (map arraySize layout) where
arraySize (Unused n) = n
arraySize (Attrib _ n fmt) = n * sizeOfVertexComponent fmt
sizeOfVertexComponent :: ComponentFormat -> Int
sizeOfVertexComponent c = case c of
VByte -> 1
VUByte -> 1
VByteNormalized -> 1
VUByteNormalized -> 1
VShort -> 2
VUShort -> 2
VShortNormalized -> 2
VUShortNormalized -> 2
VInt -> 4
VUInt -> 4
VIntNormalized -> 4
VUIntNormalized -> 4
VFloat -> 4
isNormalized :: ComponentFormat -> Bool
isNormalized c = case c of
VByte -> False
VUByte -> False
VByteNormalized -> True
VUByteNormalized -> True
VShort -> False
VUShort -> False
VShortNormalized -> True
VUShortNormalized -> True
VInt -> False
VUInt -> False
VIntNormalized -> True
VUIntNormalized -> True
VFloat -> False
setVertexAttributeLayout :: VertexAttributeLayout -> IO ()
setVertexAttributeLayout 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 norm = isNormalized fmt
glVertexAttribPointer
(fromIntegral attrib)
(fromIntegral size)
(toGL fmt)
(fromIntegral . fromEnum $ norm)
(fromIntegral offset)
(castPtr (nullPtr `plusPtr` offset))
glEnableVertexAttribArray (fromIntegral attrib)