lowgl 0.2.0.0 → 0.2.0.1
raw patch · 16 files changed
+1416/−2 lines, 16 files
Files
- Graphics/GL/Low/Blending.hs +127/−0
- Graphics/GL/Low/BufferObject.hs +123/−0
- Graphics/GL/Low/Classes.hs +31/−0
- Graphics/GL/Low/Color.hs +19/−0
- Graphics/GL/Low/Cube.hs +41/−0
- Graphics/GL/Low/Depth.hs +17/−0
- Graphics/GL/Low/Error.hs +39/−0
- Graphics/GL/Low/Framebuffer.hs +116/−0
- Graphics/GL/Low/ImageFormat.hs +56/−0
- Graphics/GL/Low/Render.hs +146/−0
- Graphics/GL/Low/Shader.hs +176/−0
- Graphics/GL/Low/Stencil.hs +137/−0
- Graphics/GL/Low/Texture.hs +206/−0
- Graphics/GL/Low/VAO.hs +38/−0
- Graphics/GL/Low/VertexAttrib.hs +127/−0
- lowgl.cabal +17/−2
+ Graphics/GL/Low/Blending.hs view
@@ -0,0 +1,127 @@+-- | When blending is enabled, colors written to the color buffer will be+-- blended using a formula with the color already there. The three options+-- for the formula are:+--+-- - S*s + D*d ('FuncAdd', the default)+-- - S*s - D*d ('FuncSubtract')+-- - D*d - S*s ('FuncReverseSubtract')+--+-- where S and D are source and destination color components respectively. The+-- factors s and d are computed blending factors which can depend on the alpha+-- component of the source pixel, the destination pixel, or a specified+-- constant color. See 'basicBlending' for a common choice.+--+-- The order of rendering matters when using blending. The farther-away+-- primitives should be rendered first to get transparent materials to look+-- right. This means a depth test is unhelpful when using blending. Also+-- blending many layers of transparent primitives can significantly degrade+-- performance. For these reasons transparency effects may be better+-- accomplished with an off-screen rendering pass followed by a suitable+-- shader.+--+-- @+-- blending example program here+-- @++module Graphics.GL.Low.Blending where++import Data.Default+import Graphics.GL++import Graphics.GL.Low.Classes++-- | Enable blending with the specified blending parameters.+enableBlending :: Blending -> IO ()+enableBlending (Blending s d f (r,g,b,a)) = do+ glBlendFunc (toGL s) (toGL d)+ glBlendEquation (toGL f)+ let c = realToFrac+ glBlendColor (c r) (c g) (c b) (c a)+ glEnable GL_BLEND++-- | Disable alpha blending.+disableBlending :: IO ()+disableBlending = glDisable GL_BLEND++-- | This blending configuration is suitable for ordinary alpha blending+-- transparency effects.+--+-- @+-- Blending+-- { sFactor = BlendSourceAlpha+-- , dFactor = BlendOneMinusSourceAlpha+-- , blendFunc = FuncAdd }+-- @+basicBlending :: Blending+basicBlending = def+ { sFactor = BlendSourceAlpha+ , dFactor = BlendOneMinusSourceAlpha }+++-- | Blending parameters.+data Blending = Blending+ { sFactor :: BlendFactor+ , dFactor :: BlendFactor+ , blendFunc :: BlendEquation+ , blendColor :: (Float,Float,Float,Float) }++-- | The default blending parameters have no effect if enabled. The result+-- will be no blending effect.+instance Default Blending where+ def = Blending+ { sFactor = BlendOne+ , dFactor = BlendZero+ , blendFunc = FuncAdd+ , blendColor = (0,0,0,0) }++-- | Blending functions.+data BlendEquation =+ FuncAdd | -- ^ the default+ FuncSubtract |+ FuncReverseSubtract+ deriving Show++instance Default BlendEquation where+ def = FuncAdd++instance ToGL BlendEquation where+ toGL FuncAdd = GL_FUNC_ADD+ toGL FuncSubtract = GL_FUNC_SUBTRACT+ toGL FuncReverseSubtract = GL_FUNC_REVERSE_SUBTRACT+++-- | Blending factors.+data BlendFactor =+ BlendOne |+ BlendZero |+ BlendSourceColor |+ BlendOneMinusSourceColor |+ BlendDestColor |+ BlendOneMinusDestColor |+ BlendSourceAlpha |+ BlendOneMinusSourceAlpha |+ BlendDestAlpha |+ BlendOneMinusDestAlpha |+ BlendConstantColor |+ BlendOneMinusConstantColor |+ BlendConstantAlpha |+ BlendOneMinusConstantAlpha+ deriving Show++instance ToGL BlendFactor where+ toGL BlendOne = GL_ONE+ toGL BlendZero = GL_ZERO+ toGL BlendSourceColor = GL_SRC_COLOR+ toGL BlendOneMinusSourceColor = GL_ONE_MINUS_SRC_COLOR+ toGL BlendDestColor = GL_DST_COLOR+ toGL BlendOneMinusDestColor = GL_ONE_MINUS_DST_COLOR+ toGL BlendSourceAlpha = GL_SRC_ALPHA+ toGL BlendOneMinusSourceAlpha = GL_ONE_MINUS_SRC_ALPHA+ toGL BlendDestAlpha = GL_DST_ALPHA+ toGL BlendOneMinusDestAlpha = GL_ONE_MINUS_DST_ALPHA+ toGL BlendConstantColor = GL_ONE_MINUS_CONSTANT_COLOR+ toGL BlendOneMinusConstantColor = GL_ONE_MINUS_CONSTANT_COLOR+ toGL BlendConstantAlpha = GL_CONSTANT_ALPHA+ toGL BlendOneMinusConstantAlpha = GL_ONE_MINUS_CONSTANT_ALPHA++
+ Graphics/GL/Low/BufferObject.hs view
@@ -0,0 +1,123 @@+-- | 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.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 :: Vector Word8 -> UsageHint -> IO VBO+newVBO src usage = do+ n <- alloca (\ptr -> glGenBuffers 1 ptr >> peek ptr)+ let len = V.length src+ glBindBuffer GL_ARRAY_BUFFER n+ V.unsafeWith src $ \ptr -> glBufferData+ GL_ARRAY_BUFFER+ (fromIntegral len)+ (castPtr ptr)+ (toGL usage)+ return (VBO n)++-- | 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 :: Vector Word8 -> Int -> IO ()+updateVBO src offset = do+ let len = V.length src+ V.unsafeWith src $ \ptr -> glBufferSubData+ GL_ARRAY_BUFFER + (fromIntegral offset)+ (fromIntegral len)+ (castPtr ptr)++-- | 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 :: Vector Word8 -> UsageHint -> IO ElementArray+newElementArray bytes usage = do+ n <- alloca (\ptr -> glGenBuffers 1 ptr >> peek ptr)+ glBindBuffer GL_ELEMENT_ARRAY_BUFFER n+ let len = V.length bytes+ V.unsafeWith bytes $ \ptr -> do+ glBufferData+ GL_ELEMENT_ARRAY_BUFFER+ (fromIntegral len)+ (castPtr ptr)+ (toGL usage)+ return (ElementArray n)++-- | Modify contents in the currently bound ElementArray starting at the+-- specified index in bytes.+updateElementArray :: Vector Word8 -> Int -> IO ()+updateElementArray bytes offset = V.unsafeWith bytes $ \ptr -> do+ glBufferSubData+ GL_ELEMENT_ARRAY_BUFFER+ (fromIntegral offset)+ (fromIntegral (V.length bytes))+ (castPtr ptr)+++-- | 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
+ Graphics/GL/Low/Classes.hs view
@@ -0,0 +1,31 @@+module Graphics.GL.Low.Classes where++import Graphics.GL++-- | OpenGL internal image formats.+class InternalFormat a where+ internalFormat :: (Eq b, Num b) => proxy a -> b++-- | The allowed attachment point for images with an internal format.+class InternalFormat a => Attachable a where+ attachPoint :: (Eq b, Num b) => proxy a -> b++-- | Textures are GL objects.+class GLObject a => Texture a where++-- | Framebuffers can be bound to the framebuffer binding target. There is+-- a default framebuffer and the client may create an arbitrary number of+-- new framebuffer objects.+class Framebuffer a where+ framebufferName :: Num b => a -> b++class GLObject a => BufferObject a where++-- | Mappable to GL enums.+class ToGL a where+ toGL :: (Num b, Eq b) => a -> b++-- | All GL objects have some numeric name.+class GLObject a where+ glObjectName :: Num b => a -> b+
+ Graphics/GL/Low/Color.hs view
@@ -0,0 +1,19 @@+module Graphics.GL.Low.Color where++import Graphics.GL++-- | Allow rendering commands to modify the color buffer of the current+-- framebuffer.+enableColorWriting :: IO ()+enableColorWriting = glColorMask GL_TRUE GL_TRUE GL_TRUE GL_TRUE++-- | Disable rendering to color buffer.+disableColorWriting :: IO ()+disableColorWriting = glColorMask GL_FALSE GL_FALSE GL_FALSE GL_FALSE++-- | Clear the color buffer of the current framebuffer with the specified+-- color. Has no effect if writing to the color buffer is disabled.+clearColorBuffer :: (Float, Float, Float) -> IO ()+clearColorBuffer (r, g, b) = do+ glClearColor (realToFrac r) (realToFrac g) (realToFrac b) 1.0+ glClear GL_COLOR_BUFFER_BIT
+ Graphics/GL/Low/Cube.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE DeriveFoldable #-}+{-# LANGUAGE DeriveTraversable #-}+module Graphics.GL.Low.Cube where++import Data.Functor+import Data.Foldable+import Control.Applicative+import Data.Traversable+import Data.Monoid++-- | Six values, one on each side.+data Cube a = Cube+ { cubeRight :: a+ , cubeLeft :: a+ , cubeTop :: a+ , cubeBottom :: a+ , cubeFront :: a+ , cubeBack :: a }+ deriving (Show, Functor, Foldable, Traversable)++-- | A type to pick one of the sides of a cube. See the accessors of the+-- type 'Cube'.+type Side = forall a . Cube a -> a++instance Applicative Cube where+ pure x = Cube x x x x x x+ (Cube f1 f2 f3 f4 f5 f6) <*> (Cube x1 x2 x3 x4 x5 x6) =+ Cube (f1 x1) (f2 x2) (f3 x3) (f4 x4) (f5 x5) (f6 x6)++instance Monoid a => Monoid (Cube a) where+ mempty = Cube mempty mempty mempty mempty mempty mempty+ (Cube x1 x2 x3 x4 x5 x6) `mappend` (Cube y1 y2 y3 y4 y5 y6) = Cube+ (x1 <> y1)+ (x2 <> y2)+ (x3 <> y3)+ (x4 <> y4)+ (x5 <> y5)+ (x6 <> y6)+
+ Graphics/GL/Low/Depth.hs view
@@ -0,0 +1,17 @@+module Graphics.GL.Low.Depth where++import Graphics.GL++-- | Enable the depth test. Attempting to render pixels with a depth value+-- greater than the depth buffer at those pixels will have no effect. Otherwise+-- the depth in the buffer will get updated to the new pixel's depth.+enableDepthTest :: IO ()+enableDepthTest = glEnable GL_DEPTH_TEST++-- | Disable the depth test and depth buffer updates.+disableDepthTest :: IO ()+disableDepthTest = glDisable GL_DEPTH_TEST++-- | Clear the depth buffer with the maximum depth value.+clearDepthBuffer :: IO ()+clearDepthBuffer = glClear GL_DEPTH_BUFFER_BIT
+ Graphics/GL/Low/Error.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE PatternSynonyms #-}+module Graphics.GL.Low.Error where++import Control.Exception+import Data.Typeable++import Graphics.GL++-- | Detectable errors.+data GLError =+ InvalidEnum | -- ^ Enum argument out of range.+ InvalidValue | -- ^ Integer argument out of range.+ InvalidOperation | -- ^ Operation illegal in current state.+ InvalidFramebufferOperation | -- ^ Framebuffer is not complete.+ OutOfMemory+ deriving Typeable++instance Exception GLError++instance Show GLError where+ show InvalidEnum = "INVALID_ENUM enum argument out of range"+ show InvalidValue = "INVALID_VALUE Numeric argument out of range"+ show InvalidOperation = "INVALID_OPERATION Illegal in current state"+ show InvalidFramebufferOperation = "INVALID_FRAMEBUFFER_OPERATION Framebuffer object is not complete"+ show OutOfMemory = "Not enough memory left to execute command"++-- | Check for a GL Error.+getGLError :: IO (Maybe GLError)+getGLError = do+ n <- glGetError+ return $ case n of+ GL_NO_ERROR -> Nothing+ GL_INVALID_ENUM -> Just InvalidEnum+ GL_INVALID_VALUE -> Just InvalidValue+ GL_INVALID_OPERATION -> Just InvalidOperation+ GL_INVALID_FRAMEBUFFER_OPERATION -> Just InvalidFramebufferOperation+ GL_OUT_OF_MEMORY -> Just OutOfMemory+ _ -> error ("unknown GL error " ++ show n)
+ Graphics/GL/Low/Framebuffer.hs view
@@ -0,0 +1,116 @@+{-# LANGUAGE RankNTypes #-}+module Graphics.GL.Low.Framebuffer (+ FBO,+ RBO,+ DefaultFramebuffer,+ bindFramebuffer,+ newFBO,+ deleteFBO,+ attachTex2D,+ attachCubeMap,+ attachRBO,+ newRBO,+ deleteRBO+) where++import Foreign.Ptr+import Foreign.Marshal+import Foreign.Storable++import Data.Default+import Graphics.GL++import Graphics.GL.Low.Classes+import Graphics.GL.Low.Common+import Graphics.GL.Low.Cube+import Graphics.GL.Low.Texture+++-- | A framebuffer object is an alternative rendering destination. Once an FBO+-- is bound to framebuffer binding target, it is possible to attach images+-- (textures or RBOs) for color, depth, or stencil rendering.+newtype FBO = FBO GLuint deriving Show++-- | An RBO is a kind of image object used for rendering. The only thing+-- you can do with an RBO is attach it to an FBO.+data RBO a = RBO { unRBO :: GLuint } deriving Show++-- | The default framebuffer. Bind this to render to the screen as usual.+-- Use the Default instance method 'def' to construct it.+data DefaultFramebuffer = DefaultFramebuffer deriving Show++instance Default DefaultFramebuffer where+ def = DefaultFramebuffer++instance Framebuffer DefaultFramebuffer where+ framebufferName _ = 0++instance Framebuffer FBO where+ framebufferName = glObjectName++instance GLObject FBO where+ glObjectName (FBO n) = fromIntegral n++instance GLObject (RBO a) where+ glObjectName (RBO n) = fromIntegral n++-- | Binds an FBO or the default framebuffer to the framebuffer binding target.+-- Replaces the framebuffer already bound there.+bindFramebuffer :: Framebuffer a => a -> IO ()+bindFramebuffer x = glBindFramebuffer GL_FRAMEBUFFER (framebufferName x)++-- | Create a new framebuffer object. Before the framebuffer can be used for+-- rendering it must have a color image attachment.+newFBO :: IO FBO+newFBO = do+ n <- alloca (\ptr -> glGenFramebuffers 1 ptr >> peek ptr)+ return (FBO n)++-- | Delete an FBO.+deleteFBO :: FBO -> IO ()+deleteFBO (FBO n) = withArray [n] (\ptr -> glDeleteFramebuffers 1 ptr)++-- | Attach a 2D texture to the FBO currently bound to the+-- framebuffer binding target.+attachTex2D :: Attachable a => Tex2D a -> IO ()+attachTex2D tex =+ glFramebufferTexture2D+ GL_FRAMEBUFFER+ (attachPoint tex)+ GL_TEXTURE_2D+ (glObjectName tex)+ 0++-- | Attach one of the sides of a cubemap texture to the FBO currently bound+-- to the framebuffer binding target.+attachCubeMap :: Attachable a => CubeMap a -> Side -> IO ()+attachCubeMap cm side =+ glFramebufferTexture2D+ GL_FRAMEBUFFER+ (attachPoint cm)+ (side cubeSideCodes)+ (glObjectName cm)+ 0++-- | Attach an RBO to the FBO currently bound to the framebuffer binding+-- target.+attachRBO :: Attachable a => RBO a -> IO ()+attachRBO rbo = glFramebufferRenderbuffer+ GL_FRAMEBUFFER (attachPoint rbo) GL_RENDERBUFFER (unRBO rbo)++-- | Create a new renderbuffer with the specified dimensions.+newRBO :: InternalFormat a => Int -> Int -> IO (RBO a)+newRBO w h = do+ n <- alloca (\ptr -> glGenRenderbuffers 1 ptr >> peek ptr)+ rbo <- return (RBO n)+ glBindRenderbuffer GL_RENDERBUFFER n+ glRenderbufferStorage+ GL_RENDERBUFFER+ (internalFormat rbo)+ (fromIntegral w)+ (fromIntegral h)+ return rbo++-- | Delete an RBO.+deleteRBO :: RBO a -> IO ()+deleteRBO (RBO n) = withArray [n] (\ptr -> glDeleteRenderbuffers 1 ptr)
+ Graphics/GL/Low/ImageFormat.hs view
@@ -0,0 +1,56 @@+module Graphics.GL.Low.ImageFormat where++import Graphics.GL++import Graphics.GL.Low.Classes++-- | 1-byte alpha channel only.+data Alpha = Alpha deriving Show++-- | 1-byte grayscale pixel format.+data Luminance = Luminance deriving Show++-- | 2-byte luminance and alpha channel format.+data LuminanceAlpha = Luminancealpha deriving Show++-- | 3-byte true color pixel format.+data RGB = RGB deriving Show++-- | 4-byte true color plus alpha channel format.+data RGBA = RGBA deriving Show++-- | 24-bit depth format.+data Depth24 = Depth24 deriving Show++-- | Combination depth and stencil format.+data Depth24Stencil8 = Depth24Stencil8 deriving Show++instance InternalFormat RGB where+ internalFormat _ = GL_RGB8+instance InternalFormat RGBA where+ internalFormat _ = GL_RGBA+instance InternalFormat Alpha where+ internalFormat _ = GL_ALPHA+instance InternalFormat Luminance where+ internalFormat _ = GL_LUMINANCE+instance InternalFormat LuminanceAlpha where+ internalFormat _ = GL_LUMINANCE_ALPHA+instance InternalFormat Depth24 where+ internalFormat _ = GL_DEPTH_COMPONENT24+instance InternalFormat Depth24Stencil8 where+ internalFormat _ = GL_DEPTH24_STENCIL8++instance Attachable RGB where+ attachPoint _ = GL_COLOR_ATTACHMENT0+instance Attachable RGBA where+ attachPoint _ = GL_COLOR_ATTACHMENT0+instance Attachable Luminance where+ attachPoint _ = GL_COLOR_ATTACHMENT0+instance Attachable LuminanceAlpha where+ attachPoint _ = GL_COLOR_ATTACHMENT0+instance Attachable Alpha where+ attachPoint _ = GL_COLOR_ATTACHMENT0+instance Attachable Depth24 where+ attachPoint _ = GL_DEPTH_ATTACHMENT+instance Attachable Depth24Stencil8 where+ attachPoint _ = GL_DEPTH_STENCIL_ATTACHMENT
+ Graphics/GL/Low/Render.hs view
@@ -0,0 +1,146 @@+module Graphics.GL.Low.Render (+ Culling(..),+ Viewport(..),+ IndexFormat(..),+ drawPoints,+ drawLines,+ drawLineStrip,+ drawLineLoop,+ drawTriangles,+ drawTriangleStrip,+ drawTriangleFan,+ drawIndexedPoints,+ drawIndexedLines,+ drawIndexedLineStrip,+ drawIndexedLineLoop,+ drawIndexedTriangles,+ drawIndexedTriangleStrip,+ drawIndexedTriangleFan,+ enableScissorTest,+ disableScissorTest,+ enableCulling,+ disableCulling,+ setViewport+) where++import Foreign.Ptr+import Foreign.Marshal+import Foreign.Storable++import Graphics.GL++import Graphics.GL.Low.Classes++-- | Facet culling modes.+data Culling =+ CullFront |+ CullBack |+ CullFrontAndBack+ deriving Show++instance ToGL Culling where+ toGL CullFront = GL_FRONT+ toGL CullBack = GL_BACK+ toGL CullFrontAndBack = GL_FRONT_AND_BACK++-- | A rectangular section of the window.+data Viewport = Viewport+ { viewportX :: Int+ , viewportY :: Int+ , viewportW :: Int+ , viewportH :: Int }+ deriving (Eq, Show)++-- | How indices are packed in an ElementArray buffer object.+data IndexFormat =+ UByteIndices | -- ^ Each index is one unsigned byte.+ UShortIndices | -- ^ Each index is a two byte unsigned int.+ UIntIndices -- ^ Each index is a four byte unsigned int.+ deriving Show++instance ToGL IndexFormat where+ toGL UByteIndices = GL_UNSIGNED_BYTE+ toGL UShortIndices = GL_UNSIGNED_SHORT+ toGL UIntIndices = GL_UNSIGNED_INT++++drawPoints :: Int -> IO ()+drawPoints = drawArrays GL_POINTS++drawLines :: Int -> IO ()+drawLines = drawArrays GL_LINES++drawLineStrip :: Int -> IO ()+drawLineStrip = drawArrays GL_LINE_STRIP++drawLineLoop :: Int -> IO ()+drawLineLoop = drawArrays GL_LINE_LOOP++drawTriangles :: Int -> IO ()+drawTriangles = drawArrays GL_TRIANGLES++drawTriangleStrip :: Int -> IO ()+drawTriangleStrip = drawArrays GL_TRIANGLE_STRIP++drawTriangleFan :: Int -> IO ()+drawTriangleFan = drawArrays GL_TRIANGLE_FAN++drawArrays :: GLenum -> Int -> IO ()+drawArrays mode n = glDrawArrays mode (fromIntegral n) 0++drawIndexedPoints :: Int -> IndexFormat -> IO ()+drawIndexedPoints = drawIndexed GL_POINTS++drawIndexedLines :: Int -> IndexFormat -> IO ()+drawIndexedLines = drawIndexed GL_LINES++drawIndexedLineStrip :: Int -> IndexFormat -> IO ()+drawIndexedLineStrip = drawIndexed GL_LINE_STRIP++drawIndexedLineLoop :: Int -> IndexFormat -> IO ()+drawIndexedLineLoop = drawIndexed GL_LINE_LOOP++drawIndexedTriangles :: Int -> IndexFormat -> IO ()+drawIndexedTriangles = drawIndexed GL_TRIANGLES++drawIndexedTriangleStrip :: Int -> IndexFormat -> IO ()+drawIndexedTriangleStrip = drawIndexed GL_TRIANGLE_STRIP++drawIndexedTriangleFan :: Int -> IndexFormat -> IO ()+drawIndexedTriangleFan = drawIndexed GL_TRIANGLE_FAN++drawIndexed :: GLenum -> Int -> IndexFormat -> IO ()+drawIndexed mode n fmt = glDrawElements mode (fromIntegral n) (toGL fmt) nullPtr++-- | Enable the scissor test. Graphics outside the scissor box will not be+-- rendered.+enableScissorTest :: Viewport -> IO ()+enableScissorTest (Viewport x y w h) = do+ glScissor (fromIntegral x) (fromIntegral y) (fromIntegral w) (fromIntegral h)+ glEnable GL_SCISSOR_TEST++-- | Disable the scissor test.+disableScissorTest :: IO ()+disableScissorTest = glDisable GL_SCISSOR_TEST+++-- | Enable facet culling. The argument specifies whether front faces, back+-- faces, or both will be omitted from rendering. If both front and back+-- faces are culled you can still render points and lines.+enableCulling :: Culling -> IO ()+enableCulling c = do+ case c of+ CullFront -> glCullFace GL_FRONT+ CullBack -> glCullFace GL_BACK+ CullFrontAndBack -> glCullFace GL_FRONT_AND_BACK+ glEnable GL_CULL_FACE++-- | Disable facet culling. Front and back faces will now be rendered.+disableCulling :: IO ()+disableCulling = glDisable GL_CULL_FACE++-- | Set the viewport. The default viewport simply covers the entire window.+setViewport :: Viewport -> IO ()+setViewport (Viewport x y w h) =+ glViewport (fromIntegral x) (fromIntegral y) (fromIntegral w) (fromIntegral h)
+ Graphics/GL/Low/Shader.hs view
@@ -0,0 +1,176 @@+{-# LANGUAGE DeriveDataTypeable #-}+module Graphics.GL.Low.Shader (+ Program,+ ProgramError(..),+ newProgramSafe,+ deleteProgram,+ newProgram,+ useProgram,+ setUniform1f,+ setUniform2f,+ setUniform3f,+ setUniform4f,+ setUniform1i,+ setUniform2i,+ setUniform3i,+ setUniform4i,+ setUniform44,+ setUniform33,+ setUniform22+) where++import Foreign.Ptr+import Foreign.C.String+import Foreign.Marshal+import Foreign.Storable+import Control.Exception+import Control.Monad (when, forM_)+import Data.Typeable++import Graphics.GL+import Linear++import Graphics.GL.Low.Classes+import Graphics.GL.Low.VertexAttrib++-- | A Program object is the combination of a compiled vertex shader and fragment+-- shader. Programs have three kinds of inputs: vertex attributes, uniforms,+-- and samplers. Programs have two outputs: fragment color and fragment depth.+-- At most one program can be "in use" at a time. Same idea as binding targets+-- it's just not called that.+newtype Program = Program GLuint deriving Show++-- | Either a vertex shader or a fragment shader.+data ShaderType = VertexShader | FragmentShader deriving Show++instance ToGL ShaderType where+ toGL VertexShader = GL_VERTEX_SHADER+ toGL FragmentShader = GL_FRAGMENT_SHADER++-- | The error message emitted by the driver when shader compilation or+-- linkage fails.+data ProgramError =+ VertexShaderError String |+ FragmentShaderError String |+ LinkError String+ deriving (Show, Typeable)+ +instance Exception ProgramError++-- | Same as 'newProgram' but does not throw exceptions.+newProgramSafe :: String -> String -> IO (Either ProgramError Program)+newProgramSafe vcode fcode = try $ newProgram vcode fcode++-- | Delete a program.+deleteProgram :: Program -> IO ()+deleteProgram (Program n) = glDeleteProgram n++-- | Compile the code for a vertex shader and a fragment shader, then link+-- them into a new program. If the compiler or linker fails it will throw+-- a ProgramError.+newProgram :: String -- ^ vertex shader source code+ -> String -- ^ fragment shader source code+ -> IO Program+newProgram vcode fcode = do+ vertexShaderId <- compileShader vcode VertexShader+ fragmentShaderId <- compileShader fcode FragmentShader+ programId <- glCreateProgram+ glAttachShader programId vertexShaderId+ glAttachShader programId fragmentShaderId+ glLinkProgram programId+ result <- alloca $ \ptr ->+ glGetProgramiv programId GL_LINK_STATUS ptr >> peek ptr+ when (result == GL_FALSE) $ do+ len <- fmap fromIntegral $ alloca $ \ptr ->+ glGetProgramiv programId GL_INFO_LOG_LENGTH ptr >> peek ptr+ errors <- allocaArray len $ \ptr -> do+ glGetProgramInfoLog programId (fromIntegral len) nullPtr ptr+ peekCString ptr+ throwIO (LinkError errors)+ glDeleteShader vertexShaderId+ glDeleteShader fragmentShaderId+ return (Program programId)++-- | Install a program into the rendering pipeline. Replaces the program+-- already in use, if any.+useProgram :: Program -> IO ()+useProgram (Program n) = glUseProgram n++compileShader :: String -> ShaderType -> IO GLuint+compileShader code vertOrFrag = do+ shaderId <- glCreateShader (toGL vertOrFrag)+ withCString code $ \ptr -> with ptr $ \pptr -> do+ glShaderSource shaderId 1 pptr nullPtr+ glCompileShader shaderId+ result <- with GL_FALSE $ \ptr ->+ glGetShaderiv shaderId GL_COMPILE_STATUS ptr >> peek ptr+ when (result == GL_FALSE) $ do+ len <- fmap fromIntegral $ alloca $ \ptr ->+ glGetShaderiv shaderId GL_INFO_LOG_LENGTH ptr >> peek ptr+ errors <- allocaArray len $ \ptr -> do+ glGetShaderInfoLog shaderId (fromIntegral len) nullPtr ptr+ peekCString ptr+ case vertOrFrag of+ VertexShader -> throwIO (VertexShaderError errors)+ FragmentShader -> throwIO (FragmentShaderError errors)+ return shaderId++setUniform1f :: String -> [Float] -> IO ()+setUniform1f = setUniform glUniform1fv++setUniform2f :: String -> [V2 Float] -> IO ()+setUniform2f = setUniform+ (\loc cnt val -> glUniform2fv loc cnt (castPtr val))++setUniform3f :: String -> [V3 Float] -> IO ()+setUniform3f = setUniform+ (\loc cnt val -> glUniform3fv loc cnt (castPtr val))++setUniform4f :: String -> [V4 Float] -> IO ()+setUniform4f = setUniform+ (\loc cnt val -> glUniform4fv loc cnt (castPtr val))++setUniform1i :: String -> [Int] -> IO ()+setUniform1i = setUniform+ (\loc cnt val -> glUniform1iv loc cnt (castPtr val))++setUniform2i :: String -> [V2 Int] -> IO ()+setUniform2i = setUniform + (\loc cnt val -> glUniform2iv loc cnt (castPtr val))++setUniform3i :: String -> [V3 Int] -> IO ()+setUniform3i = setUniform+ (\loc cnt val -> glUniform3iv loc cnt (castPtr val))++setUniform4i :: String -> [V4 Int] -> IO ()+setUniform4i = setUniform+ (\loc cnt val -> glUniform4iv loc cnt (castPtr val))++setUniform44 :: String -> [M44 Float] -> IO ()+setUniform44 = setUniform+ (\loc cnt val -> glUniformMatrix4fv loc cnt GL_FALSE (castPtr val))++setUniform33 :: String -> [M33 Float] -> IO ()+setUniform33 = setUniform+ (\loc cnt val -> glUniformMatrix3fv loc cnt GL_FALSE (castPtr val))++setUniform22 :: String -> [M22 Float] -> IO ()+setUniform22 = setUniform+ (\loc cnt val -> glUniformMatrix2fv loc cnt GL_FALSE (castPtr val))++setUniform :: Storable a+ => (GLint -> GLsizei -> Ptr a -> IO ())+ -> String+ -> [a]+ -> IO ()+setUniform glAction name xs = withArrayLen xs $ \n bytes -> do+ p <- alloca (\ptr -> glGetIntegerv GL_CURRENT_PROGRAM ptr >> peek ptr)+ if p == 0+ then return ()+ else do+ loc <- withCString name (\ptr -> glGetUniformLocation (fromIntegral p) ptr)+ if loc == -1+ then return ()+ else glAction loc (fromIntegral n) bytes++
+ Graphics/GL/Low/Stencil.hs view
@@ -0,0 +1,137 @@+-- | The stencil test is like a configurable depth test with a dedicated+-- additional buffer. Like the depth test, if the stencil test fails then the+-- pixel being tested will not be rendered. The stencil test happens before the+-- depth test, if it's enabled. For a given pixel, the stencil test passes if+-- the following computation+--+-- > (ref & mask) `stencilOp` (buf & mask)+--+-- computes true. The variables ref and mask are configurable constants, buf is+-- the value in the stencil buffer at the given pixel, and stencilOp is a+-- configurable comparison operation. The stencil op can also be set to pass+-- 'Always' or 'Never'.+--+-- The stencil buffer may be modified in various ways on the following events:+--+-- - When the stencil test fails or+-- - When the stencil test passes then the depth test fails or+-- - When both tests pass.+--+-- An example way of updating the stencil buffer is to write zero, or to write+-- the ref value mentioned above to the location being tested.+--+-- > example program here++module Graphics.GL.Low.Stencil where++import Data.Default+import Data.Bits+import Data.Word++import Graphics.GL+import Graphics.GL.Low.Classes++-- | Enable the stencil test with a set of operating parameters.+enableStencil :: Stencil -> IO ()+enableStencil (Stencil f r m op1 op2 op3) = do+ glStencilFunc (toGL f) (fromIntegral r) (fromIntegral m)+ glStencilOp (toGL op1) (toGL op2) (toGL op2)+ glEnable GL_STENCIL_TEST++-- | Disable the stencil test and updates to the stencil buffer, if one exists.+disableStencil :: IO ()+disableStencil = glDisable GL_STENCIL_TEST++-- | Clear the stencil buffer with all zeros.+clearStencilBuffer :: IO ()+clearStencilBuffer = glClear GL_STENCIL_BUFFER_BIT++-- | In this basic configuration of the stencil, anything rendered will+-- create a silhouette of 1s in the stencil buffer. Attempting to render a+-- second time into the silhouette will have no effect because the stencil+-- test will fail (ref=1 isn't greater than buffer=1).+--+-- @+-- def { func = Greater+-- , ref = 1+-- , onBothPass = Replace }+-- @+basicStencil :: Stencil+basicStencil = def+ { func = Greater+ , ref = 1+ , onBothPass = Replace }++-- | Configuration of the stencil test and associated stencil buffer updating.+data Stencil = Stencil+ { func :: StencilFunc+ , ref :: Int+ , mask :: Word+ , onStencilFail :: StencilOp+ , onDepthFail :: StencilOp+ , onBothPass :: StencilOp }++-- | The default state of the stencil, if it were simply enabled, would be+-- to always pass and update nothing in the buffer. It would have no effect+-- on rendering.+instance Default Stencil where+ def = Stencil+ { func = Always+ , ref = 0+ , mask = complement 0+ , onStencilFail = Keep+ , onDepthFail = Keep+ , onBothPass = Keep }++-- the proper implementation of toList f is the one that for any+-- g :: t a -> [a] you can make a unique k such that g = k . f+-- jle`+ +++-- | The stencil test passes under what condition.+data StencilFunc =+ Never |+ Less |+ LessOrEqual |+ Greater |+ GreaterOrEqual |+ Equal |+ NotEqual |+ Always+ deriving Show++instance ToGL StencilFunc where+ toGL x = case x of+ Never -> GL_NEVER+ Less -> GL_LESS+ LessOrEqual -> GL_LEQUAL+ Greater -> GL_GREATER+ GreaterOrEqual -> GL_GEQUAL+ Equal -> GL_EQUAL+ NotEqual -> GL_NOTEQUAL+ Always -> GL_ALWAYS+++-- | Modification action for the stencil buffer. +data StencilOp =+ Keep | -- ^ Do nothing.+ Zero | -- ^ Set to zero.+ Replace | -- ^ Write the ref value passed to enableStencil.+ Increment |+ Decrement |+ Invert | -- ^ Bitwise complement.+ IncrementWrap |+ DecrementWrap+ deriving Show++instance ToGL StencilOp where+ toGL x = case x of+ Keep -> GL_KEEP+ Zero -> GL_ZERO+ Replace -> GL_REPLACE+ Increment -> GL_INCR+ Decrement -> GL_DECR+ Invert -> GL_INVERT+ IncrementWrap -> GL_INCR_WRAP+ DecrementWrap -> GL_DECR_WRAP
+ Graphics/GL/Low/Texture.hs view
@@ -0,0 +1,206 @@+module Graphics.GL.Low.Texture (+ Tex2D,+ CubeMap,+ Filtering(..),+ Wrapping(..),+ Dimensions(..),+ newTexture2D,+ deleteTexture,+ newCubeMap,+ newEmptyTexture2D,+ newEmptyCubeMap,+ bindTexture2D,+ bindTextureCubeMap,+ setActiveTextureUnit,+ setTex2DFiltering,+ setCubeMapFiltering,+ setTex2DWrapping,+ setCubeMapWrapping+) where++import Foreign.Ptr+import Foreign.Marshal+import Foreign.Storable+import Data.Vector.Storable+import Data.Word+import Control.Applicative+import Data.Traversable++import Graphics.GL++import Graphics.GL.Low.Classes+import Graphics.GL.Low.Common+import Graphics.GL.Low.Cube++-- | A 2D texture. A program can sample a texture if it has been bound to+-- the appropriate texture unit.+newtype Tex2D a = Tex2D GLuint deriving Show++-- | A cubemap texture is just six 2D textures. A program can sample a cubemap+-- texture if it has been bound to the appropriate texture unit.+newtype CubeMap a = CubeMap GLuint deriving Show++-- | Texture filtering modes.+data Filtering =+ Nearest | -- ^ No interpolation.+ Linear -- ^ Linear interpolation.+ deriving Show++instance ToGL Filtering where+ toGL Nearest = GL_NEAREST+ toGL Linear = GL_LINEAR++-- | Texture wrapping modes.+data Wrapping =+ Repeat | -- ^ Tile the texture past the boundary.+ MirroredRepeat | -- ^ Tile the texture but mirror every other tile.+ ClampToEdge -- ^ Use the edge color for anything past the boundary.+ deriving Show++instance ToGL Wrapping where+ toGL Repeat = GL_REPEAT+ toGL MirroredRepeat = GL_MIRRORED_REPEAT+ toGL ClampToEdge = GL_CLAMP_TO_EDGE++-- | The size of an image in pixels.+data Dimensions = Dimensions+ { imageWidth :: Int+ , imageHeight :: Int }+ deriving (Show)++instance Texture (Tex2D a) where++instance Texture (CubeMap a) where++instance GLObject (Tex2D a) where+ glObjectName (Tex2D n) = fromIntegral n++instance GLObject (CubeMap a) where+ glObjectName (CubeMap n) = fromIntegral n++-- | Create a new 2D texture from a blob and its image format.+-- Dimensions should be powers of two.+newTexture2D :: InternalFormat a => Vector Word8 -> Dimensions -> IO (Tex2D a)+newTexture2D bytes (Dimensions w h) = do+ n <- alloca (\ptr -> glGenTextures 1 ptr >> peek ptr)+ glBindTexture GL_TEXTURE_2D n+ tex <- return (Tex2D n)+ unsafeWith bytes $ \ptr -> glTexImage2D+ GL_TEXTURE_2D+ 0+ (internalFormat tex)+ (fromIntegral w)+ (fromIntegral h)+ 0+ (internalFormat tex)+ GL_UNSIGNED_BYTE+ (castPtr ptr)+ return tex++-- | Delete a texture.+deleteTexture :: Texture a => a -> IO ()+deleteTexture x = withArray [glObjectName x] (\ptr -> glDeleteTextures 1 ptr)++-- | Create a new cube map texture from six blobs and their respective formats.+-- Dimensions should be powers of two.+newCubeMap :: InternalFormat a+ => Cube (Vector Word8, Dimensions)+ -> IO (CubeMap a)+newCubeMap images = do+ n <- alloca (\ptr -> glGenTextures 1 ptr >> peek ptr)+ glBindTexture GL_TEXTURE_CUBE_MAP n+ cm <- return (CubeMap n)+ let fmt = internalFormat cm+ sequenceA (liftA2 (loadCubeMapSide fmt) images cubeSideCodes)+ return cm+ +loadCubeMapSide :: GLenum -> (Vector Word8, Dimensions) -> GLenum -> IO ()+loadCubeMapSide fmt (bytes, (Dimensions w h)) side = do+ unsafeWith bytes $ \ptr -> glTexImage2D+ side+ 0+ (fromIntegral fmt)+ (fromIntegral w)+ (fromIntegral h)+ 0+ fmt+ GL_UNSIGNED_BYTE+ (castPtr ptr)++-- | Create an empty texture with the specified dimensions and format.+newEmptyTexture2D :: InternalFormat a => Int -> Int -> IO (Tex2D a)+newEmptyTexture2D w h = do+ let w' = fromIntegral w+ let h' = fromIntegral h+ n <- alloca (\ptr -> glGenTextures 1 ptr >> peek ptr)+ tex <- return (Tex2D n)+ let fmt = internalFormat tex+ let fmt' = internalFormat tex+ glBindTexture GL_TEXTURE_2D n+ glTexImage2D GL_TEXTURE_2D 0 fmt w' h' 0 fmt' GL_UNSIGNED_BYTE nullPtr+ return tex++-- | Create a cubemap texture where each of the six sides has the specified+-- dimensions and format.+newEmptyCubeMap :: InternalFormat a => Int -> Int -> IO (CubeMap a)+newEmptyCubeMap w h = do+ let w' = fromIntegral w+ let h' = fromIntegral h+ n <- alloca (\ptr -> glGenTextures 1 ptr >> peek ptr)+ tex <- return (CubeMap n)+ let fmt = internalFormat tex+ let fmt' = internalFormat tex+ glBindTexture GL_TEXTURE_CUBE_MAP n+ glTexImage2D GL_TEXTURE_CUBE_MAP_POSITIVE_X 0 fmt w' h' 0 fmt' GL_UNSIGNED_BYTE nullPtr+ glTexImage2D GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0 fmt w' h' 0 fmt' GL_UNSIGNED_BYTE nullPtr+ glTexImage2D GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0 fmt w' h' 0 fmt' GL_UNSIGNED_BYTE nullPtr+ glTexImage2D GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0 fmt w' h' 0 fmt' GL_UNSIGNED_BYTE nullPtr+ glTexImage2D GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0 fmt w' h' 0 fmt' GL_UNSIGNED_BYTE nullPtr+ glTexImage2D GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0 fmt w' h' 0 fmt' GL_UNSIGNED_BYTE nullPtr+ return tex+ ++-- | Bind a 2D texture to the 2D texture binding target and the currently+-- active texture unit.+bindTexture2D :: Tex2D a -> IO ()+bindTexture2D (Tex2D n) = glBindTexture GL_TEXTURE_2D n++-- | Bind a cubemap texture to the cubemap texture binding target and+-- the currently active texture unit.+bindTextureCubeMap :: CubeMap a -> IO ()+bindTextureCubeMap (CubeMap n) = glBindTexture GL_TEXTURE_CUBE_MAP n++-- | Set the active texture unit. The default is zero.+setActiveTextureUnit :: Enum a => a -> IO ()+setActiveTextureUnit n =+ (glActiveTexture . fromIntegral) (GL_TEXTURE0 + fromEnum n)++-- | Set the filtering for the 2D texture currently bound to the 2D texture+-- binding target.+setTex2DFiltering :: Filtering -> IO ()+setTex2DFiltering filt = do+ glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER (toGL filt)+ glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER (toGL filt)++-- | Set the filtering for the cubemap texture currently bound to the cubemap+-- texture binding target.+setCubeMapFiltering :: Filtering -> IO ()+setCubeMapFiltering filt = do+ glTexParameteri GL_TEXTURE_CUBE_MAP GL_TEXTURE_MIN_FILTER (toGL filt)+ glTexParameteri GL_TEXTURE_CUBE_MAP GL_TEXTURE_MAG_FILTER (toGL filt)++-- | Set the wrapping mode for the 2D texture currently bound to the 2D+-- texture binding target.+setTex2DWrapping :: Wrapping -> IO ()+setTex2DWrapping wrap = do+ glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_S (toGL wrap)+ glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_T (toGL wrap)++-- | Set the wrapping mode for the cubemap texture currently bound to the+-- cubemap texture binding target. Because no blending occurs between cube+-- faces you probably want ClampToEdge.+setCubeMapWrapping :: Wrapping -> IO ()+setCubeMapWrapping wrap = do+ glTexParameteri GL_TEXTURE_CUBE_MAP GL_TEXTURE_WRAP_S (toGL wrap)+ glTexParameteri GL_TEXTURE_CUBE_MAP GL_TEXTURE_WRAP_T (toGL wrap)+ glTexParameteri GL_TEXTURE_CUBE_MAP GL_TEXTURE_WRAP_R (toGL wrap)
+ Graphics/GL/Low/VAO.hs view
@@ -0,0 +1,38 @@+module Graphics.GL.Low.VAO +(+ VAO,+ newVAO,+ deleteVAO,+ bindVAO+) where++import Foreign.Storable+import Foreign.Marshal++import Graphics.GL++import Graphics.GL.Low.Classes++-- | A VAO stores vertex attribute layouts and the VBO source of vertices+-- for those attributes. It also stores the state of the element array binding+-- target. The vertex array binding target admits one VAO at a time.+newtype VAO = VAO GLuint deriving Show++instance GLObject VAO where+ glObjectName (VAO n) = fromIntegral n++-- | Create a new VAO. The only thing you can do with a VAO is bind it to+-- the vertex array binding target.+newVAO :: IO VAO+newVAO = do+ n <- alloca (\ptr -> glGenVertexArrays 1 ptr >> peek ptr)+ return (VAO n)++-- | Delete a VAO.+deleteVAO :: VAO -> IO ()+deleteVAO (VAO n) = withArray [n] (\ptr -> glDeleteVertexArrays 1 ptr)++-- | Assign the VAO to the vertex array binding target. The VAO already bound+-- will be replaced, if any.+bindVAO :: VAO -> IO ()+bindVAO (VAO n) = glBindVertexArray n
+ Graphics/GL/Low/VertexAttrib.hs view
@@ -0,0 +1,127 @@+-- | Vertex Attribute Array.+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++-- | The name of a vertex input to a program combined with the+-- component format and number of components for that attribute in the+-- vertex data. Alternatively the size of an unused section of the data+-- in bytes.+data LayoutElement =+ Attrib String Int ComponentFormat | -- ^ Name, component count and component format of a vertex attribute.+ Unused Int -- ^ Size in bytes of an unused section of the vertex data.+ deriving Show++-- | The layout of interleaved vertex attribute data.+type VertexAttributeLayout = [LayoutElement]++-- | The size and interpretation of a vertex attribute component. Normalized+-- components will be mapped to floats in the range [0, 1].+data ComponentFormat =+ VFloat | -- ^ 4-byte float+ VByte | + VUByte | + VByteNormalized | + VUByteNormalized |+ VShort | -- ^ 2-byte signed integer+ VUShort | -- ^ 2-byte unsigned integer+ VShortNormalized |+ VUShortNormalized |+ VInt | -- ^ 4-byte signed integer+ VUInt | -- ^ 4-byte unsigned integer+ 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+++-- | This configures the currently bound VAO. It calls glVertexAttribPointer+-- and glEnableVertexAttribArray.+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)
lowgl.cabal view
@@ -10,7 +10,7 @@ -- PVP summary: +-+------- breaking API changes -- | | +----- non-breaking API additions -- | | | +--- code changes with no API change-version: 0.2.0.0+version: 0.2.0.1 -- A short (one-line) description of the package. synopsis: Basic gl wrapper and reference@@ -49,6 +49,21 @@ library -- Modules exported by the library. exposed-modules: Graphics.GL.Low+ Graphics.GL.Low.Blending+ Graphics.GL.Low.BufferObject+ Graphics.GL.Low.Color+ Graphics.GL.Low.Classes+ Graphics.GL.Low.Cube+ Graphics.GL.Low.Depth+ Graphics.GL.Low.Error+ Graphics.GL.Low.Framebuffer+ Graphics.GL.Low.ImageFormat+ Graphics.GL.Low.Render+ Graphics.GL.Low.Shader+ Graphics.GL.Low.Stencil+ Graphics.GL.Low.Texture+ Graphics.GL.Low.VAO+ Graphics.GL.Low.VertexAttrib other-modules: Graphics.GL.Low.Common -- Modules included in this library but not exported.@@ -74,4 +89,4 @@ source-repository this type: git location: https://github.com/evanrinehart/lowgl- tag: 0.2.0.0+ tag: 0.2.0.1