lowgl 0.2.1.0 → 0.2.1.1
raw patch · 9 files changed
+430/−43 lines, 9 files
Files
- Graphics/GL/Low.hs +4/−12
- Graphics/GL/Low/Blending.hs +128/−10
- Graphics/GL/Low/BufferObject.hs +40/−7
- Graphics/GL/Low/Error.hs +22/−2
- Graphics/GL/Low/Shader.hs +176/−5
- Graphics/GL/Low/Texture.hs +1/−1
- Graphics/GL/Low/VAO.hs +55/−3
- Graphics/GL/Low/VertexAttrib.hs +2/−1
- lowgl.cabal +2/−2
Graphics/GL/Low.hs view
@@ -1,3 +1,4 @@+-- | Basic low-level GL wrapper and reference. module Graphics.GL.Low ( -- * Overview@@ -40,7 +41,7 @@ -- 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+ -- mwin <- GLFW.createWindow 640 480 \"Hello World\" Nothing Nothing -- case mwin of -- Nothing -> putStrLn "createWindow failed" -- Just win -> do@@ -107,7 +108,7 @@ -- -- And the output should look like --- -- <<demo.png Demo>>+ -- <<hello_world.png Hello World>> -- * OpenGL API Basically --@@ -145,16 +146,7 @@ -- - Image attachment points of an FBO -- ** Shader Programs- -- | The role of the second half of a shader program, the fragment shader, is- -- to compute the color and depth of pixels covered by rasterized primitives- -- (points, lines, and triangles) in the process of rendering. The role of- -- the /first/ half of the program (vertex program) is to arrange the- -- vertices of those primitives somewhere in clip space. Where these vertices- -- and their attributes come from in the first place is determined by the VAO- -- bound to the vertex array binding target. The program may also make use of- -- uniform variables and texture units assigned by client code before- -- rendering (but in a process completely separate from configuring the VAO).- -- At most one Program can be "in use" at a time.+ -- | See "Graphics.GL.Low.Shader" -- ** VAO -- | The VAO is essential. At least one VAO must be created and bound to the
Graphics/GL/Low/Blending.hs view
@@ -1,4 +1,5 @@--- | When blending is enabled, colors written to the color buffer will be+-- | = Blending+-- 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: --@@ -11,19 +12,136 @@ -- 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.+-- = Example -- -- @--- blending example program here+-- module Main where+-- +-- import Control.Monad.Loops (whileM_)+-- import Data.Functor ((\<$\>))+-- import qualified Data.Vector.Storable as V+-- import Control.Concurrent.STM+-- +-- import qualified Graphics.UI.GLFW as GLFW+-- import Linear+-- import Graphics.GL.Low+-- +-- 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 \"Blending\" Nothing Nothing+-- case mwin of+-- Nothing -> putStrLn "createWindow failed"+-- Just win -> do+-- GLFW.makeContextCurrent (Just win)+-- GLFW.swapInterval 1+-- shouldSwap <- newTVarIO False+-- (GLFW.setKeyCallback win . Just)+-- (\_ _ _ _ _ -> atomically (modifyTVar shouldSwap not))+-- (vao, prog) <- setup+-- whileM_ (not \<$\> GLFW.windowShouldClose win) $ do+-- GLFW.pollEvents+-- draw vao prog shouldSwap+-- GLFW.swapBuffers win+-- +-- setup = do+-- vao <- newVAO+-- bindVAO vao+-- vsource <- readFile "blending.vert"+-- fsource <- readFile "blending.frag"+-- prog <- newProgram vsource fsource+-- useProgram prog+-- let blob = V.fromList+-- [ -0.5, 0.5+-- , 0.5, 0+-- , -0.5, -0.5 ] :: V.Vector Float+-- vbo <- newVBO blob StaticDraw+-- bindVBO vbo+-- setVertexAttributeLayout [Attrib "position" 2 VFloat]+-- enableBlending basicBlending+-- return (vao, prog)+-- +-- draw vao prog shouldSwap = do+-- clearColorBuffer (0,0,0)+-- yes <- readTVarIO shouldSwap+-- if yes+-- then sequence [drawRed, drawGreen]+-- else sequence [drawGreen, drawRed]+-- +-- drawGreen = do+-- setUniform3f "color" [V3 0 1 0]+-- setUniform1f "alpha" [0.5]+-- setUniform44 "move" [eye4]+-- drawTriangles 3+-- +-- drawRed = do+-- let ninety = pi/2+-- let move = mkTransformation (axisAngle (V3 0 0 1) ninety) (V3 0.25 0.5 0)+-- setUniform3f "color" [V3 1 0 0]+-- setUniform1f "alpha" [0.5]+-- setUniform44 "move" [transpose move]+-- drawTriangles 3 -- @+-- +-- blending.vert+--+-- @+-- #version 150+-- +-- in vec3 Color;+-- in float Alpha;+-- out vec4 outColor;+-- +-- void main()+-- {+-- outColor = vec4(Color, Alpha);+-- }+-- @+--+-- blending.frag+--+-- @+-- #version 150+-- +-- uniform vec3 color;+-- uniform float alpha;+-- uniform mat4 move;+-- +-- in vec2 position;+-- out vec3 Color;+-- out float Alpha;+-- +-- void main()+-- {+-- gl_Position = move * vec4(position, 0.0, 1.0);+-- Color = color;+-- Alpha = alpha;+-- }+-- @+--+-- This program draws two half-transparent shapes. When you press a key they+-- are rendered in the opposite order. This makes one appear as if it were in+-- front of the other. Because the depth test (see "Graphics.GL.Low.Depth")+-- must be disabled while using this kind of blending, there may be significant+-- overdraw in areas with many blending layers. This can harm performance.+-- Also the order-dependency can make using alpha blending in a 3D scene+-- complex or impossible. It may make more sense to use an off-screen render+-- pass (see "Graphics.GL.Low.Framebuffer") and an appropriate shader to+-- simulate transparency effects.+--+-- <<blending1.png Blending Before>> <<blending2.png Blending After>> -module Graphics.GL.Low.Blending where+module Graphics.GL.Low.Blending (+ enableBlending,+ disableBlending,+ basicBlending,+ Blending(..),+ BlendFactor(..),+ BlendEquation(..)+) where import Data.Default import Graphics.GL
Graphics/GL/Low/BufferObject.hs view
@@ -1,6 +1,42 @@ {-# LANGUAGE ScopedTypeVariables #-}--- | VBO and ElementArrays. Both are buffer objects but are used for two--- different things.++-- | Buffer Objects are objects for holding arbitrary blobs of bytes. This+-- library exposes two types of buffer objects: VBOs and ElementArrays.+--+-- = VBO+--+-- Vertex Buffer Objects (VBO) contain data for a sequence of vertices. A+-- vertex shader interprets the data for each vertex by mapping the attributes+-- of the vertex (position, normal vector, etc) to input variables using the+-- VAO. /VBOs have the data which is used as input to the vertex shader according to the configuration of the VAO/.+--+-- Example VBO contents:+--+-- <<vbo.png VBO diagram>>+--+-- The shader will interpret those parts of the VBO as illustrated only after+-- appropiately configuring a VAO. See "Graphics.GL.Low.VAO".+--+-- = ElementArray+--+-- Element arrays are buffer objects that contain a sequence of indices. When+-- using indexed rendering, the bound element array determines the order that+-- the vertices in the VBOs are visited to construct primitives. This allows+-- sharing vertices in cases that many vertices overlap with each other. OpenGL+-- accepts element array objects whose indices are encoded as unsigned bytes,+-- unsigned 16-bit ints, and unsigned 32-bit ints.+--+-- Example ElementArray contents appropriate for render triangles and lines+-- respectively:+--+-- <<element_array.png Element array diagram>>+--+-- See 'Graphics.GL.Low.Render.drawIndexedTriangles' and friends to see which+-- primitives are possible to construct with element arrays. It is not+-- necessary to use element arrays to render. The non-indexed versions of+-- the primitive render commands will simply traverse the vertices in order+-- specified in the VBOs.+ module Graphics.GL.Low.BufferObject ( VBO, ElementArray,@@ -26,13 +62,10 @@ 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.+-- | Handle to a VBO. 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.+-- | Handle to an element array buffer object. data ElementArray = ElementArray GLuint deriving Show -- | Usage hint for allocation of buffer object storage.
Graphics/GL/Low/Error.hs view
@@ -1,7 +1,18 @@ {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE PatternSynonyms #-}-module Graphics.GL.Low.Error where +-- | If you issue an invalid GL command or run out of memory, the GL+-- implementation may set an internal flag indicating that an error has+-- occurred. You can query this flag ('getGLError') to see if something went+-- wrong with a previous command. If you ignore errors, chances are nothing+-- will happen except perhaps some rendering weirdness. However checking this+-- periodically is a good idea, perhaps once per frame, because it might+-- indicate a bug in your code.+module Graphics.GL.Low.Error (+ GLError(..),+ getGLError,+) where+ import Control.Exception import Data.Typeable @@ -25,7 +36,16 @@ show InvalidFramebufferOperation = "INVALID_FRAMEBUFFER_OPERATION Framebuffer object is not complete" show OutOfMemory = "Not enough memory left to execute command" --- | Check for a GL Error.+-- | Check for a GL Error. This call has the semantics of a dequeue. If an+-- error is returned, then calling getGLError again may return more errors that+-- have "stacked up." When it returns Nothing then there are no more errors to+-- report. An error indicates that a bug in your code caused incorrect ussage+-- of the API or that the implementation has run out of memory.+--+-- It has been suggested that using this after every single GL command may+-- adversely affect performance (not to mention be very tedious). Since there+-- is no reasonable way to recover from a GL error, a good idea might be to+-- check this once per frame or even less often, and respond with a core dump. getGLError :: IO (Maybe GLError) getGLError = do n <- glGetError
Graphics/GL/Low/Shader.hs view
@@ -1,3 +1,178 @@+-- | A shader program is composed of two cooperating parts: the vertex program+-- and the fragment program. The vertex program is executed once for each+-- vertex. The fragment program is executed once for each pixel covered by+-- a rasterized primitive (actually this is more complicated but close enough).+--+-- The inputs to the vertex program are:+--+-- - a vertex (see "Graphics.GL.Low.VAO")+-- - uniforms+--+-- The outputs of the vertex program are:+--+-- - clip space position of the vertex, gl_Position+-- - any number of variables matching inputs to the fragment program+-- - (if rendering a point, then you can set gl_PointSize)+--+-- The inputs to the fragment program are:+--+-- - the previously mentioned outputs of the vertex program (interpolated)+-- - the window position of the pixel, gl_FragCoord+-- - samplers (see "Graphics.GL.Low.Texture")+-- - uniforms+-- - gl_FrontFacing, true if pixel is part of a front facing triangle+-- - (if rendering a point, then you can use gl_PointCoord)+--+-- The outputs of the fragment program are:+--+-- - a color (this is more complicated in reality but close enough)+-- - the depth of the pixel, gl_FragDepth, which will default to the pixel's Z.+--+-- = Example+--+-- @+-- module Main where+-- +-- import Control.Monad.Loops (whileM_)+-- import Data.Functor ((\<$\>))+-- import qualified Data.Vector.Storable as V+-- import Data.Maybe (fromJust)+-- +-- import qualified Graphics.UI.GLFW as GLFW+-- import Linear+-- import Graphics.GL.Low+-- +-- 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 \"Shaders\" Nothing Nothing+-- case mwin of+-- Nothing -> putStrLn "createWindow failed"+-- Just win -> do+-- GLFW.makeContextCurrent (Just win)+-- GLFW.swapInterval 1+-- (vao, prog1, prog2, prog3) <- setup+-- whileM_ (not \<$\> GLFW.windowShouldClose win) $ do+-- GLFW.pollEvents+-- t <- (realToFrac . fromJust) \<$\> GLFW.getTime+-- draw vao prog1 prog2 prog3 t+-- GLFW.swapBuffers win+-- +-- setup = do+-- vao <- newVAO+-- bindVAO vao+-- vsource <- readFile "shader.vert"+-- fsource1 <- readFile "shader1.frag"+-- fsource2 <- readFile "shader2.frag"+-- fsource3 <- readFile "shader3.frag"+-- prog1 <- newProgram vsource fsource1+-- prog2 <- newProgram vsource fsource2+-- prog3 <- newProgram vsource fsource3+-- useProgram prog1+-- let blob = V.fromList+-- [ -0.4, -0.4, 0, 0+-- , 0, 0.4, 0, 1+-- , 0.4, -0.4, 1, 1] :: V.Vector Float+-- vbo <- newVBO blob StaticDraw+-- bindVBO vbo+-- setVertexAttributeLayout+-- [ Attrib "position" 2 VFloat+-- , Attrib "location" 2 VFloat ]+-- return (vao, prog1, prog2, prog3)+-- +-- draw vao prog1 prog2 prog3 t = do+-- clearColorBuffer (0,0,0)+-- bindVAO vao+-- drawThing prog1 t (V3 (-0.5) 0.5 0.0)+-- drawThing prog2 t (V3 0.5 0.5 0.0)+-- drawThing prog3 t (V3 0.0 (-0.5) (-0.0))+-- +-- drawThing :: Program -> Float -> V3 Float -> IO ()+-- drawThing prog t shift = do+-- let angle = t / 5+-- let move = mkTransformation (axisAngle (V3 0 0 1) angle) shift+-- useProgram prog+-- setUniform1f "time" [t]+-- setUniform44 "move" [transpose move]+-- drawTriangles 3+-- @+--+-- Where the vertex shader is+--+-- @+-- #version 150+-- uniform mat4 move;+-- in vec2 position;+-- in vec2 location;+-- out vec2 Location;+-- void main()+-- {+-- gl_Position = move * vec4(position, 0.0, 1.0);+-- Location = location;+-- }+-- @+--+-- And the three fragment shaders are+--+-- @+-- #version 150+-- uniform float time;+-- in vec2 Location;+-- out vec4 outColor;+-- void main()+-- {+-- float x = gl_FragCoord.x / 640;+-- float y = gl_FragCoord.y / 480;+-- outColor = vec4(+-- fract(x*25) < 0.5 ? 1.0 : 0.0,+-- fract(y*25) < 0.5 ? 1.0 : 0.0,+-- 0.0, 1.0+-- );+-- }+-- @+--+-- @+-- #version 150+-- uniform float time;+-- in vec2 Location;+-- out vec4 outColor;+-- void main()+-- {+-- outColor = vec4(+-- fract(Location.x*10) < 0.5 ? 1.0 : 0.0,+-- fract(Location.y*10) < 0.5 ? 1.0 : 0.0,+-- 0.0, 1.0+-- );+-- }+-- @+--+-- @+-- #version 150+-- uniform float time;+-- in vec2 Location;+-- out vec4 outColor;+-- void main()+-- {+-- float t = time;+-- outColor = vec4(+-- fract(Location.x*5) < 0.5 ? sin(t*3.145) : cos(t*4.567),+-- fract(Location.y*5) < 0.5 ? cos(t*6.534) : sin(t*4.321),+-- 0.0, 1.0+-- );+-- }+-- @+--+-- The output should look like+--+-- <<shaders.gif 3 Different Shaders Animated Demo>>+--+-- Where the window coordinates, the interpolated location on the triangle,+-- and the elapsed time are used to color the triangle respectively.+--+ {-# LANGUAGE DeriveDataTypeable #-} module Graphics.GL.Low.Shader ( Program,@@ -33,11 +208,7 @@ 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.+-- | Handle to a shader program. newtype Program = Program GLuint deriving Show -- | Either a vertex shader or a fragment shader.
Graphics/GL/Low/Texture.hs view
@@ -24,7 +24,7 @@ import Data.Vector.Storable import Data.Word import Control.Applicative-import Data.Traversable+import Data.Traversable (sequenceA) import Graphics.GL
Graphics/GL/Low/VAO.hs view
@@ -1,3 +1,57 @@+-- | Vertex Array Objects (VAO). Despite having almost no operations of its+-- own, the VAO mechanism is one of the most complex pieces of OpenGL. A VAO+-- has mutable state which associates vertex shader input variables (actually+-- the integer location of the variable) with three things:+--+-- - The VBO to read from.+-- - The position in the each vertex array (in the VBO) to read from.+-- - The interpretation of the bytes found there (32-bit float, 16-bit int, etc).+--+-- You set these VAO parameters with the following dance:+--+-- - Bind a VAO+-- - Bind a VBO+-- - Use a Program+-- - call 'Graphics.GL.Low.VertexAttrib.setVertexAttributeLayout' which will+-- lookup the position of the input variables and issue the appropriate+-- glVertexAttribPointer calls.+--+-- After a VAO is configured against a Program, either can be swapped in or+-- out freely and they will still work when both are swapped in again together.+--+-- An "in-use" program will use whatever VAO is bound for getting its vertex+-- inputs. It is up to the programmer to ensure that the VAO has been+-- configured with the right variable positions for the current program. Two+-- ways to do this are to use a consistent set of variables for all shaders or+-- restrict a set of VAOs to only be allowed with specific Program objects.+--+-- The currently bound VBO is not remembered or restored by binding a VAO, but+-- the currently bound ElementArray is. This detail won't affect you if you+-- always explicitly bind an ElementArray after binding a VAO. Alternatively+-- you can exploit this to bundle particular models and their element arrays+-- as a VAO.+--+-- Diagram of possible VAO contents:+--+-- <<vao.png VAO Diagram>>+--+-- The above VAO would be compatible with the following vertex program:+--+-- @+-- #version 150+-- +-- in vec2 position;+-- in vec3 color;+--+-- out vec3 Color;+-- +-- void main()+-- {+-- gl_Position = vec4(position, 0.0, 1.0);+-- Color = color;+-- }+-- @+ module Graphics.GL.Low.VAO ( VAO,@@ -13,9 +67,7 @@ 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.+-- | Handle to a VAO. newtype VAO = VAO GLuint deriving Show instance GLObject VAO where
Graphics/GL/Low/VertexAttrib.hs view
@@ -116,7 +116,8 @@ 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 stride = total - size * sizeOfVertexComponent fmt+ let stride = total let norm = isNormalized fmt glVertexAttribPointer (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.1.0+version: 0.2.1.1 -- 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.1.0+ tag: 0.2.1.1