lowgl 0.2.0.1 → 0.2.1.0
raw patch · 5 files changed
+153/−54 lines, 5 files
Files
- Graphics/GL/Low.hs +107/−10
- Graphics/GL/Low/BufferObject.hs +36/−39
- Graphics/GL/Low/Render.hs +1/−1
- Graphics/GL/Low/VertexAttrib.hs +7/−2
- lowgl.cabal +2/−2
Graphics/GL/Low.hs view
@@ -1,8 +1,6 @@ module Graphics.GL.Low ( - -- * In a Nutshell- --- -- ** Overview+ -- * Overview -- | OpenGL is a graphics rendering interface. This library exposes a vastly -- simplified subset of OpenGL that is hopefully still complete enough for -- many purposes, such as following tutorials, making simple games, and@@ -19,6 +17,105 @@ -- This library uses the `gl' package for raw bindings to OpenGL and the -- `linear' package for matrices. + -- * Example+ --+ -- | The hello world program shows a white triangle on a black background.+ -- It uses the packages `GLFW-b' and `monad-loops'. Note that it forces a+ -- 3.2 core profile when setting up the context through GLFW.+ --+ -- @+ -- module Main where+ --+ -- import Control.Monad.Loops (whileM_)+ -- import Data.Functor ((\<$\>))+ -- import qualified Data.Vector.Storable as V+ -- + -- import qualified Graphics.UI.GLFW as GLFW+ -- import Graphics.GL.Low+ -- + -- -- GLFW will be the shell of the demo+ -- main = do+ -- GLFW.init+ -- GLFW.windowHint (GLFW.WindowHint'ContextVersionMajor 3)+ -- GLFW.windowHint (GLFW.WindowHint'ContextVersionMinor 2)+ -- GLFW.windowHint (GLFW.WindowHint'OpenGLForwardCompat True)+ -- GLFW.windowHint (GLFW.WindowHint'OpenGLProfile GLFW.OpenGLProfile'Core)+ -- mwin <- GLFW.createWindow 640 480 \"Demo\" Nothing Nothing+ -- case mwin of+ -- Nothing -> putStrLn "createWindow failed"+ -- Just win -> do+ -- GLFW.makeContextCurrent (Just win)+ -- GLFW.swapInterval 1+ -- (vao, prog) <- setup -- load and configure objects+ -- whileM_ (not \<$\> GLFW.windowShouldClose win) $ do+ -- GLFW.pollEvents+ -- draw vao prog -- render+ -- GLFW.swapBuffers win+ -- + -- setup = do+ -- -- establish a VAO+ -- vao <- newVAO+ -- bindVAO vao+ -- -- load shader program+ -- vsource <- readFile "hello.vert"+ -- fsource <- readFile "hello.frag"+ -- prog <- newProgram vsource fsource+ -- useProgram prog+ -- -- load vertex data: three 2D vertex positions+ -- let blob = V.fromList+ -- [ -0.5, -0.5+ -- , 0, 0.5+ -- , 0.5, -0.5 ] :: V.Vector Float+ -- vbo <- newVBO blob StaticDraw+ -- bindVBO vbo+ -- -- connect program to vertex data via the VAO+ -- setVertexAttributeLayout [Attrib "position" 2 VFloat]+ -- return (vao, prog)+ -- + -- draw vao prog = do+ -- clearColorBuffer (0,0,0)+ -- bindVAO vao+ -- useProgram prog+ -- drawTriangles 3+ -- @+ --+ -- The vertex shader file looks like+ --+ -- @+ -- #version 150+ --+ -- in vec2 position;+ --+ -- void main()+ -- {+ -- gl_Position = vec4(position, 0.0, 1.0);+ -- }+ -- @+ --+ -- And the corresponding fragment shader file+ --+ -- @+ -- #version 150+ --+ -- out vec4 outColor;+ --+ -- void main()+ -- {+ -- outColor = vec4(1.0, 1.0, 1.0, 1.0);+ -- }+ -- @+ --+ -- And the output should look like+ --+ -- <<demo.png Demo>>++ -- * OpenGL API Basically+ --+ -- | <https://www.opengl.org/registry/doc/glspec32.core.20090803.pdf The spec>+ -- for OpenGL 3.2 is actually quite readable and is worth reviewing.+ -- The following is my synopsis of things which roughly coincide with the+ -- simplified OpenGL ES 2.0.+ -- ** Objects -- | Objects may be created and destroyed by client code. They include: --@@ -159,15 +256,15 @@ -- - The __vertex shader__ takes vertex positions as specified in vertex -- attributes to clip space. This is how the client code specifies a camera, -- movement of objects, and perspective.- -- - The __perspective division__ or ""W-divide"" takes vertices from clip space- -- and maps them to normalized device coordinates (NDC) by dividing all the- -- components of the vertex by that vertex's W component. This allows a+ -- - The __perspective division__ or ""W-divide"" takes vertices from clip+ -- space and maps them to normalized device coordinates (NDC) by dividing all+ -- the components of the vertex by that vertex's W component. This allows a -- perspective effect to be accomplished in the shader by modifying the W -- components. You can't configure this W-division; it just happens. Note- -- that if W = 1 for all vertices this step has no effect. This is useful for- -- orthographic projections. The resulting geometry will be clipped to a- -- 2x2x2 cube centered around the origin. You can think of an XY plane of- -- this cube as the viewport of the final 2D image.+ -- that if W = 1 for all vertices then this step has no effect. This is+ -- useful for orthographic projections. The resulting geometry will be+ -- clipped to a 2x2x2 cube centered around the origin. You can think of an XY+ -- plane of this cube as the viewport of the final 2D image. -- - The configurable __viewport transformation__ ('setViewport') will then -- position the viewport somewhere in the window. This step is necessary -- because your window is probably not a 2x2 square. The viewport
Graphics/GL/Low/BufferObject.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE ScopedTypeVariables #-} -- | VBO and ElementArrays. Both are buffer objects but are used for two -- different things. module Graphics.GL.Low.BufferObject (@@ -14,6 +15,7 @@ ) where import Foreign.Ptr+import Foreign.ForeignPtr import Foreign.Marshal import Foreign.Storable import qualified Data.Vector.Storable as V@@ -57,17 +59,8 @@ -- | 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)+newVBO :: Storable a => Vector a -> UsageHint -> IO VBO+newVBO = newBufferObject VBO GL_ARRAY_BUFFER -- | Delete a VBO or ElementArray. deleteBufferObject :: BufferObject a => a -> IO ()@@ -75,14 +68,8 @@ -- | 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)+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.@@ -92,32 +79,42 @@ -- | 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)+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 :: 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)-+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))++
Graphics/GL/Low/Render.hs view
@@ -87,7 +87,7 @@ drawTriangleFan = drawArrays GL_TRIANGLE_FAN drawArrays :: GLenum -> Int -> IO ()-drawArrays mode n = glDrawArrays mode (fromIntegral n) 0+drawArrays mode n = glDrawArrays mode 0 (fromIntegral n) drawIndexedPoints :: Int -> IndexFormat -> IO () drawIndexedPoints = drawIndexed GL_POINTS
Graphics/GL/Low/VertexAttrib.hs view
@@ -116,12 +116,17 @@ let total = totalLayout layout forM_ layout' $ \(name, size, offset, fmt) -> do attrib <- withCString name $ \ptr -> glGetAttribLocation (fromIntegral p) (castPtr ptr)+ let stride = total - size * sizeOfVertexComponent fmt let norm = isNormalized fmt glVertexAttribPointer (fromIntegral attrib) (fromIntegral size) (toGL fmt)- (fromIntegral . fromEnum $ norm)- (fromIntegral offset)+ (toGL norm)+ (fromIntegral stride) (castPtr (nullPtr `plusPtr` offset)) glEnableVertexAttribArray (fromIntegral attrib)++instance ToGL Bool where+ toGL True = GL_TRUE+ toGL False = GL_FALSE
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.1+version: 0.2.1.0 -- A short (one-line) description of the package. synopsis: Basic gl wrapper and reference@@ -89,4 +89,4 @@ source-repository this type: git location: https://github.com/evanrinehart/lowgl- tag: 0.2.0.1+ tag: 0.2.1.0