lowgl 0.3.1.0 → 0.3.1.1
raw patch · 12 files changed
+934/−728 lines, 12 filesdep ~basedep ~linear
Dependency ranges changed: base, linear
Files
- Graphics/GL/Low.hs +32/−286
- Graphics/GL/Low/Blending.hs +127/−125
- Graphics/GL/Low/BufferObject.hs +18/−14
- Graphics/GL/Low/EntirePictureUpFront.hs +277/−0
- Graphics/GL/Low/Framebuffer.hs +181/−29
- Graphics/GL/Low/Render.hs +25/−4
- Graphics/GL/Low/Shader.hs +153/−152
- Graphics/GL/Low/Stencil.hs +2/−1
- Graphics/GL/Low/Texture.hs +110/−107
- Graphics/GL/Low/VAO.hs +5/−4
- Graphics/GL/Low/VertexAttrib.hs +1/−4
- lowgl.cabal +3/−2
Graphics/GL/Low.hs view
@@ -14,285 +14,45 @@ -- process of understanding OpenGL. It seems that understanding the entire -- picture up-front is the only way to get started, so this should also serve -- as a quick reference guide to the core commands and concepts.+ -- "Graphics.GL.Low.EntirePictureUpFront" -- -- 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 \"Hello World\" 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- -- setVertexLayout [Attrib "position" 2 GLFloat]- -- 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- --- -- <<hello_world.png Hello World>>-- -- * 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:- --- -- - Vertex Array Object ('VAO')- -- - Buffer Objects ('VBO', 'ElementArray')- -- - Textures ('Tex2D', 'CubeMap')- -- - Shader 'Program's- -- - Framebuffer Objects ('FBO')- -- - Renderbuffer Objects ('RBO')-- -- ** Binding Targets- -- | Objects are referenced with integers (called names in GL), so binding- -- targets can be thought of as global variables to put those references.- -- Many operations implicitly read from these globals to determine what the- -- target object of the operation is. They include:+ -- See specific modules for topic-specific docs and example code --- -- - Vertex array binding target (for VAO)- -- - Buffer binding targets (ARRAY_BUFFER and ELEMENT_ARRAY_BUFFER)- -- - Texture binding targets (TEXTURE_2D and TEXTURE_CUBE_MAP)- -- - Framebuffer binding target (for FBO)+ -- @"Graphics.GL.Low.VAO"@ --- -- (not binding targets but similar)+ -- @"Graphics.GL.Low.BufferObject"@ --- -- - Shader program "in use"- -- - Texture units- -- - Current active texture unit- -- - Image attachment points of an FBO-- -- ** Shader Programs- -- | See "Graphics.GL.Low.Shader"-- -- ** VAO- -- | The VAO is essential. At least one VAO must be created and bound to the- -- vertex array binding target before rendering, before configuring a- -- program's vertex attributes. Here is why: the VAO stores the association- -- between vertex inputs in the program and a VBO from which to pipe input- -- from. It also stores the format of the VBO data, which is otherwise just- -- a big blob. Finally, the VAO stores the state of the element array binding- -- target used for indexed rendering.+ -- @"Graphics.GL.Low.Shader"@ --- -- After installing a program with 'useProgram' and binding a source VBO- -- to the array buffer binding target ('bindVBO') then the bound VAO can be- -- updated ('setVertexLayout') with new vertex attribute information.- -- After this, the VBO can be rebound to configure a different set of inputs- -- with a different source. Many VAOs can be created and swapped out to pipe- -- vertex data in different ways to different programs (or the same program).+ -- @"Graphics.GL.Low.VertexAttrib"@ --- -- When a VAO is bound ('bindVAO') it restores the state of the element array- -- binding target. For this reason you can think of that binding target as- -- simply being a function of the VAO itself rather than a separate global- -- state.-- -- ** Uniforms and Samplers (Textures)- -- | Programs may also have uniform variables and "sampler uniforms" as- -- input. Uniforms are accessible from the vertex or fragment shader part of- -- the program but their values are fixed during the course of a rendering- -- command. They can be set and reset with the setUniform family (ex.- -- 'setUniform1f'), which updates the current program object with new uniform- -- values. Among other things, updating the uniforms each frame is the main- -- way to animate a scene.+ -- @"Graphics.GL.Low.Texture"@ --- -- Samplers are textures that the shader can interpolate to get "in between"- -- values. The texture a sampler uses is determined by the contents of the- -- texture unit that that sampler points to. The sampler is a uniform with- -- an integer type. This integer is the texture unit to use. The word texture- -- should not be construed to mean a color image. Shaders can make use of- -- many kinds of multi-dimensional data that happen to be available through- -- the samplers.-- -- ** Texture Objects and Texture Units- -- | Before a shader can use a texture it must be assigned to a texture unit.- -- First set the active texture unit to the desired unit number- -- ('setActiveTextureUnit') then bind the texture object to one of the- -- two texture binding targets, depending on what kind of texture it is (2D- -- or cubemap). Binding a texture has the side effect of assigning it to the- -- active texture unit.-- -- ** Custom Framebuffers- -- | It is possible (and important in many techniques) to utilize an- -- off-screen render target. To do this create an FBO ('newFBO'), bind it to- -- the framebuffer binding target ('bindFramebuffer') and attach a color- -- /image/ object (texture or renderbuffer object). If necessary a depth- -- image or combination depth-stencil image can be attached as well. If no- -- color image is attached then the FBO is incomplete and rendering will be- -- an error. After rendering to an FBO any textures that were attached can- -- be used in a second pass by assigning them to a texture unit. Watch out- -- for feedback loops accidentally sampling a texture that is also being- -- rendered to at the same time!+ -- @"Graphics.GL.Low.Render"@ --- -- A renderbuffer object is a minor character to be used when you do not- -- expect to use the results of rendering but need an image anyway. For- -- example you may need a depth buffer to do depth testing, or you may want- -- to ignore the (required for rendering to work at all) color buffer.-- -- ** Images and Image Formats- -- | FBOs have attachment points for /images/. A texture serves as an image- -- and a renderbuffer object serves as an image. Images have an "internal- -- format" which describes the size and interpretation of pixel components.- -- There are seven internal formats, five of which are color image formats- -- such as grayscale and RGB. The other two are the depth buffer format and- -- the combination depth-stencil format. RBOs ('newRBO') and empty textures- -- ('newEmptyTexture2D', 'newEmptyCubeMap') can be created with any of these- -- formats.+ -- @"Graphics.GL.Low.Color"@ --- -- (The above is a gross simplification of OpenGL's image formats. I should- -- probably revise, because it may greatly improve performance to use some- -- of the 16-bit color formats rather than 32. Also HDR color format.)-- -- ** Depth Testing and Stencil Testing- -- | The depth test and stencil test use extra buffers in parallel with the- -- color buffer to cause regions of pixels to not show. It does this by- -- making a comparison between the depth each pixel and the value present- -- in those buffers, then updating the buffers as necessary. The stencil- -- test in particular has many configurable options. See the respective- -- modules for the "Graphics.GL.Low.Depth" and "Graphics.GL.Low.Stencil"- -- tests. -- -- ** Scissor Test- -- | The scissor test, if enabled ('enableScissorTest'), disallows all- -- rendering outside of a rectangle region of the window called the scissor- -- box.-- -- ** Coordinate Systems (Mappings)- -- | There are three transformation mechanisms which work together to get raw- -- vertex data from VBOs to rasterized primitives somewhere on the window.- -- You can imagine four coordinate systems between these three transformations- -- if you want to.+ -- @"Graphics.GL.Low.Depth"@+ -- + -- @"Graphics.GL.Low.Stencil"@ --- -- - 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- -- 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 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- -- transformation is configured by specifying a rectangular region of your- -- window where you want the image to map to. The default setting for this is- -- to fill the entire window with the viewport. If you didn't previously- -- account for your aspect ratio then this will have the effect of squishing- -- the scene, so you need to compensate in the vertex shader.-- -- ** Rendering Points, Lines, and Triangles- -- | The draw family (ex. 'drawTriangles') of commands commissions the- -- rendering of a certain number of vertices worth of primitives. The- -- current program will get input from the current VAO, the current texture- -- units, and execute on all the potentially affected pixels in the current- -- framebuffer. Vertexes are consumed in the order they appear in their- -- respective source VBOs. If the VAO is missing, the program is missing, or- -- the current framebuffer has no color attachment, then rendering will not- -- work.+ -- @"Graphics.GL.Low.Blending"@ --- -- The drawIndexed family (ex. 'drawIndexedTriangles') of commands carries- -- out the same effects as the non-indexed rendering commands but traverses- -- vertices in an order determined by the sequence of indexes packed in the- -- ElementArray currently bound to the element array binding target. This- -- mainly allows a huge reuse of vertex data in the case that the object- -- being rendered forms a closed mesh.-+ -- @"Graphics.GL.Low.Framebuffer"@ -- * VAO- -- | See also "Graphics.GL.Low.VAO"+ -- | See also "Graphics.GL.Low.VAO". newVAO, bindVAO, deleteVAO, VAO, -- * Buffer Objects- -- | See also "Graphics.GL.Low.BufferObject"+ -- | See also "Graphics.GL.Low.BufferObject". newVBO, newElementArray, bindVBO,@@ -303,10 +63,9 @@ VBO, ElementArray, UsageHint(..),- IndexFormat(..), -- * Shader Program- -- | See also "Graphics.GL.Low.Shader"+ -- | See also "Graphics.GL.Low.Shader". newProgram, newProgramSafe, useProgram,@@ -326,14 +85,14 @@ ProgramError(..), -- ** Vertex Attributes- -- | See also "Graphics.GL.Low.VertexAttrib"+ -- | See also "Graphics.GL.Low.VertexAttrib". setVertexLayout, VertexLayout(..), DataType(..), -- * Textures- -- | See also "Graphics.GL.Low.Texture"+ -- | See also "Graphics.GL.Low.Texture". newTexture2D, newCubeMap, newEmptyTexture2D,@@ -355,12 +114,9 @@ Wrapping(..), -- * Rendering- -- | See also "Graphics.GL.Low.Render"-+ -- -- ** Primitives- -- | Draw primitives to the framebuffer currently bound to the framebuffer- -- binding target. Each primitive drawing command takes the number of vertices- -- in the VBOs to render. The vertices are traversed in order.+ -- | See also "Graphics.GL.Low.Render". drawPoints, drawLines, drawLineStrip,@@ -368,11 +124,6 @@ drawTriangles, drawTriangleStrip, drawTriangleFan,-- -- ** Primitives by Index- -- | Draw primitives as above, but use the order of vertices defined in- -- the ElementArray currently bound to the element array buffer binding- -- target. drawIndexedPoints, drawIndexedLines, drawIndexedLineStrip,@@ -380,15 +131,23 @@ drawIndexedTriangles, drawIndexedTriangleStrip, drawIndexedTriangleFan,+ setViewport,+ enableScissorTest,+ disableScissorTest,+ enableCulling,+ disableCulling,+ Viewport(..),+ Culling(..),+ IndexFormat(..), -- ** Color Buffer- -- | See also "Graphics.GL.Low.Color"+ -- | See also "Graphics.GL.Low.Color". enableColorWriting, disableColorWriting, clearColorBuffer, -- ** Depth Test- -- | See also "Graphics.GL.Low.Depth"+ -- | See also "Graphics.GL.Low.Depth". enableDepthTest, disableDepthTest, clearDepthBuffer,@@ -403,15 +162,6 @@ StencilFunc(..), StencilOp(..), - -- ** Scissor Test- enableScissorTest,- disableScissorTest,-- -- ** Facet Culling- Culling(..),- enableCulling,- disableCulling,- -- ** Blending -- | See also "Graphics.GL.Low.Blending". @@ -422,12 +172,8 @@ BlendFactor(..), BlendEquation(..), - -- ** Viewport- Viewport(..),- setViewport,- -- * Framebuffers- -- | See also "Graphics.GL.Low.Framebuffer"+ -- | See also "Graphics.GL.Low.Framebuffer". DefaultFramebuffer(..), FBO, bindFramebuffer,
Graphics/GL/Low/Blending.hs view
@@ -1,5 +1,6 @@--- | = Blending--- When blending is enabled, colors written to the color buffer will be+module Graphics.GL.Low.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,136 +12,16 @@ -- 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.------ = Example------ @--- 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--- setVertexLayout [Attrib "position" 2 GLFloat]--- 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 ( enableBlending, disableBlending, basicBlending, Blending(..), BlendFactor(..), BlendEquation(..)++ -- * Example+ -- $example ) where import Data.Default@@ -243,3 +124,124 @@ toGL BlendOneMinusConstantAlpha = GL_ONE_MINUS_CONSTANT_ALPHA +-- $example+--+-- <<blending1.png Blending Before>> <<blending2.png Blending After>>+--+-- 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.+--+-- @+-- 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+-- setVertexLayout [Attrib "position" 2 GLFloat]+-- 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;+-- }+-- @
Graphics/GL/Low/BufferObject.hs view
@@ -2,13 +2,16 @@ -- | 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++module Graphics.GL.Low.BufferObject (++-- * 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/.+-- VAO. VBOs have the data which is used as input to the vertex shader+-- according to the configuration of the VAO/. -- -- Example VBO contents: --@@ -16,10 +19,10 @@ -- -- 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++-- * 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@@ -37,17 +40,18 @@ -- the primitive render commands will simply traverse the vertices in order -- specified in the VBOs. -module Graphics.GL.Low.BufferObject (- VBO,- ElementArray,- UsageHint(..),+-- * Documentation+ newVBO, updateVBO, bindVBO, newElementArray, updateElementArray, bindElementArray,- deleteBufferObject+ deleteBufferObject,+ VBO,+ ElementArray,+ UsageHint(..) ) where import Foreign.Ptr
+ Graphics/GL/Low/EntirePictureUpFront.hs view
@@ -0,0 +1,277 @@+module Graphics.GL.Low.EntirePictureUpFront (++ -- * 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:+ --+ -- - Vertex Array Object ('Graphics.GL.Low.VAO.VAO')+ -- - Buffer Objects ('Graphics.GL.Low.BufferObject.VBO', 'Graphics.GL.Low.BufferObject.ElementArray')+ -- - Textures ('Graphics.GL.Low.Texture.Tex2D', 'Graphics.GL.Low.Texture.CubeMap')+ -- - Shader 'Graphics.GL.Low.Shader.Program's+ -- - Framebuffer Objects ('Graphics.GL.Low.Framebuffer.FBO')+ -- - Renderbuffer Objects ('Graphics.GL.Low.Framebuffer.RBO')++ -- ** Binding Targets+ -- | Objects are referenced with integers (called names in GL), so binding+ -- targets can be thought of as global variables to put those references.+ -- Many operations implicitly read from these globals to determine what the+ -- target object of the operation is. They include:+ --+ -- - Vertex array binding target (for VAO)+ -- - Buffer binding targets (ARRAY_BUFFER and ELEMENT_ARRAY_BUFFER)+ -- - Texture binding targets (TEXTURE_2D and TEXTURE_CUBE_MAP)+ -- - Framebuffer binding target (for FBO)+ --+ -- (not binding targets but similar)+ --+ -- - Shader program "in use"+ -- - Texture units+ -- - Current active texture unit+ -- - Image attachment points of an FBO++ -- ** Shader Programs+ -- | See "Graphics.GL.Low.Shader"++ -- ** VAO+ -- | The VAO is essential. At least one VAO must be created and bound to the+ -- vertex array binding target before rendering, before configuring a+ -- program's vertex attributes. Here is why: the VAO stores the association+ -- between vertex inputs in the program and a VBO from which to pipe input+ -- from. It also stores the format of the VBO data, which is otherwise just+ -- a big blob. Finally, the VAO stores the state of the element array binding+ -- target used for indexed rendering.+ --+ -- After installing a program with 'Graphics.GL.Low.Shader.useProgram' and+ -- binding a source VBO to the array buffer binding target+ -- ('Graphics.GL.Low.BufferObject.bindVBO') then the bound VAO can be updated+ -- ('Graphics.GL.Low.VertexAttrib.setVertexLayout') with new vertex attribute+ -- information. After this, the VBO can be rebound to configure a different+ -- set of inputs with a different source. Many VAOs can be created and+ -- swapped out to pipe vertex data in different ways to different programs+ -- (or the same program).+ --+ -- When a VAO is bound ('Graphics.GL.Low.VAO.bindVAO') it restores the state+ -- of the element array binding target. For this reason you can think of that+ -- binding target as simply being a function of the VAO itself rather than a+ -- separate global state.++ -- ** Uniforms and Samplers (Textures)+ -- | Programs may also have uniform variables and "sampler uniforms" as+ -- input. Uniforms are accessible from the vertex or fragment shader part of+ -- the program but their values are fixed during the course of a rendering+ -- command. They can be set and reset with the setUniform family (ex.+ -- 'Graphics.GL.Low.Shader.setUniform1f'), which updates the current program+ -- object with new uniform values. Among other things, updating the uniforms+ -- each frame is the main way to animate a scene.+ --+ -- Samplers are textures that the shader can interpolate to get "in between"+ -- values. The texture a sampler uses is determined by the contents of the+ -- texture unit that that sampler points to. The sampler is a uniform with+ -- an integer type. This integer is the texture unit to use. The word texture+ -- should not be construed to mean a color image. Shaders can make use of+ -- many kinds of multi-dimensional data that happen to be available through+ -- the samplers.++ -- ** Texture Objects and Texture Units+ -- | Before a shader can use a texture it must be assigned to a texture unit.+ -- First set the active texture unit to the desired unit number+ -- ('Graphics.GL.Texture.setActiveTextureUnit') then bind the texture object+ -- to one of the two texture binding targets, depending on what kind of+ -- texture it is (2D or cubemap). Binding a texture has the side effect of+ -- assigning it to the active texture unit.++ -- ** Custom Framebuffers+ -- | It is possible (and important in many techniques) to utilize an+ -- off-screen render target. To do this create an FBO+ -- ('Graphics.GL.Low.Framebuffer.newFBO'), bind it to the framebuffer binding+ -- target ('Graphics.GL.Low.Framebuffer.bindFramebuffer') and attach a color+ -- /image/ object (texture or renderbuffer object). If necessary a depth+ -- image or combination depth-stencil image can be attached as well. If no+ -- color image is attached then the FBO is incomplete and rendering will be+ -- an error. After rendering to an FBO any textures that were attached can+ -- be used in a second pass by assigning them to a texture unit. Watch out+ -- for feedback loops accidentally sampling a texture that is also being+ -- rendered to at the same time!+ --+ -- A renderbuffer object is a minor character to be used when you do not+ -- expect to use the results of rendering but need an image anyway. For+ -- example you may need a depth buffer to do depth testing, or you may want+ -- to ignore the (required for rendering to work at all) color buffer.++ -- ** Images and Image Formats+ -- | FBOs have attachment points for /images/. A texture serves as an image+ -- and a renderbuffer object serves as an image. Images have an "internal+ -- format" which describes the size and interpretation of pixel components.+ -- There are seven internal formats, five of which are color image formats+ -- such as grayscale and RGB. The other two are the depth buffer format and+ -- the combination depth-stencil format. RBOs+ -- ('Graphics.GL.Low.Framebuffer.newRBO') and empty textures+ -- ('Graphics.GL.Low.Texture.newEmptyTexture2D',+ -- 'Graphics.GL.Low.Texture.newEmptyCubeMap') can be created with any of+ -- these formats.+ --+ -- (The above is a gross simplification of OpenGL's image formats. I should+ -- probably revise, because it may greatly improve performance to use some+ -- of the 16-bit color formats rather than 32. Also HDR color format.)++ -- ** Depth Testing and Stencil Testing+ -- | The depth test and stencil test use extra buffers in parallel with the+ -- color buffer to cause regions of pixels to not show. It does this by+ -- making a comparison between the depth each pixel and the value present+ -- in those buffers, then updating the buffers as necessary. The stencil+ -- test in particular has many configurable options. See the respective+ -- modules for the "Graphics.GL.Low.Depth" and "Graphics.GL.Low.Stencil"+ -- tests. ++ -- ** Scissor Test+ -- | The scissor test, if enabled+ -- ('Graphics.GL.Low.Render.enableScissorTest'), disallows all rendering+ -- outside of a rectangle region of the window called the scissor box.++ -- ** Coordinate Systems (Mappings)+ -- | There are three transformation mechanisms which work together to get raw+ -- vertex data from VBOs to rasterized primitives somewhere on the window.+ -- You can imagine four coordinate systems between these three transformations+ -- if you want to.+ --+ -- - 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+ -- 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 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__+ -- ('Graphics.GL.Low.Render.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 transformation is configured by+ -- specifying a rectangular region of your window where you want the image to+ -- map to. The default setting for this is to fill the entire window with the+ -- viewport. If you didn't previously account for your aspect ratio then+ -- this will have the effect of squishing the scene, so you need to+ -- compensate in the vertex shader.++ -- ** Rendering Points, Lines, and Triangles+ -- | The draw family (ex. 'Graphics.GL.Low.Render.drawTriangles') of commands+ -- commissions the rendering of a certain number of vertices worth of+ -- primitives. The current program will get input from the current VAO, the+ -- current texture units, and execute on all the potentially affected pixels+ -- in the current framebuffer. Vertexes are consumed in the order they appear+ -- in their respective source VBOs. If the VAO is missing, the program is+ -- missing, or the current framebuffer has no color attachment, then+ -- rendering will not work.+ --+ -- The drawIndexed family (ex. 'Graphics.GL.Low.Render.drawIndexedTriangles')+ -- of commands carries out the same effects as the non-indexed rendering+ -- commands but traverses vertices in an order determined by the sequence of+ -- indexes packed in the ElementArray currently bound to the element array+ -- binding target. This mainly allows a huge reuse of vertex data in the case+ -- that the object being rendered forms a closed mesh.++ -- * 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 \"Hello World\" 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+ -- setVertexLayout [Attrib "position" 2 GLFloat]+ -- 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+ --+ -- <<hello_world.png Hello World>>+++) where++
Graphics/GL/Low/Framebuffer.hs view
@@ -1,37 +1,31 @@--- | Framebuffers, FBO, RBO...------ == Example------ This example program renders an animating object to an off-screen--- framebuffer. The resulting texture is then show on a full-screen quad--- with an effect.------ @------ @------ The vertex shader for this program is------ @------ @------ The two fragment shaders, one for the object, one for the effect, are------ @+{-# LANGUAGE RankNTypes #-}+module Graphics.GL.Low.Framebuffer (++-- | By default, rendering commands output graphics to the default framebuffer.+-- This includes the color buffer, the depth buffer, and the stencil buffer. It+-- is possible to render to a texture instead. This is important for many+-- techniques. Rendering to a texture (either color, depth, or depth/stencil)+-- is accomplished by using a framebuffer object (FBO). ----- @+-- The following ritual sets up an FBO with a blank 256x256 color texture for+-- off-screen rendering: -- -- @---+-- do+-- fbo <- newFBO+-- tex <- newEmptyTexture2D 256 256 :: IO (Tex2D RGB)+-- bindFramebuffer fbo+-- attachTex2D tex+-- bindFramebuffer DefaultFramebuffer+-- return (fbo, tex) -- @ ----- And the output looks like------ <<framebuffer.gif Animated screenshot showing post-processing effect>>+-- After binding an FBO to the framebuffer binding target, rendering commands+-- will output to its color attachment and possible depth/stencil attachment+-- if present. An FBO must have a color attachment before rendering. If only+-- the depth results are needed, then you can attach a color RBO instead of+-- a texture to the color attachment point. -{-# LANGUAGE RankNTypes #-}-module Graphics.GL.Low.Framebuffer ( newFBO, bindFramebuffer, deleteFBO,@@ -42,7 +36,11 @@ deleteRBO, FBO, DefaultFramebuffer(..),- RBO,+ RBO++ -- * Example+ -- $example+ ) where import Foreign.Ptr@@ -145,3 +143,157 @@ -- | Delete an RBO. deleteRBO :: RBO a -> IO () deleteRBO (RBO n) = withArray [n] (\ptr -> glDeleteRenderbuffers 1 ptr)+++-- $example+--+-- <<framebuffer.gif Animated screenshot showing post-processing effect>>+--+-- This example program renders an animating object to an off-screen+-- framebuffer. The resulting texture is then shown on a full-screen quad+-- with an effect.+--+-- @+-- module Main where+-- +-- import Control.Monad.Loops (whileM_)+-- import Data.Functor ((\<$\>))+-- import qualified Data.Vector.Storable as V+-- import Data.Maybe (fromJust)+-- import Data.Default+-- import Data.Word+-- +-- 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 \"Framebuffer\" Nothing Nothing+-- case mwin of+-- Nothing -> putStrLn "createWindow failed"+-- Just win -> do+-- GLFW.makeContextCurrent (Just win)+-- GLFW.swapInterval 1+-- (vao1, vao2, prog1, prog2, fbo, texture) <- setup+-- whileM_ (not <$> GLFW.windowShouldClose win) $ do+-- GLFW.pollEvents+-- t <- (realToFrac . fromJust) \<$\> GLFW.getTime+-- draw vao1 vao2 prog1 prog2 fbo texture t+-- GLFW.swapBuffers win+-- +-- setup = do+-- -- primary subject+-- vao1 <- newVAO+-- bindVAO vao1+-- let blob = V.fromList+-- [ -0.5, -0.5, 0, 0+-- , 0, 0.5, 0, 1+-- , 0.5, -0.5, 1, 1] :: V.Vector Float+-- vbo <- newVBO blob StaticDraw+-- bindVBO vbo+-- vsource <- readFile "framebuffer.vert"+-- fsource1 <- readFile "framebuffer1.frag"+-- prog1 <- newProgram vsource fsource1+-- useProgram prog1+-- setVertexLayout+-- [ Attrib "position" 2 GLFloat+-- , Attrib "texcoord" 2 GLFloat ]+-- +-- -- full-screen quad to show the post-processed scene+-- vao2 <- newVAO+-- bindVAO vao2+-- let blob = V.fromList+-- [ -1, -1, 0, 0+-- , -1, 1, 0, 1+-- , 1, -1, 1, 0+-- , 1, 1, 1, 1] :: V.Vector Float+-- vbo <- newVBO blob StaticDraw+-- bindVBO vbo+-- indices <- newElementArray (V.fromList [0,1,2,3,2,1] :: V.Vector Word8) StaticDraw+-- bindElementArray indices+-- fsource2 <- readFile "framebuffer2.frag"+-- prog2 <- newProgram vsource fsource2+-- useProgram prog2+-- setVertexLayout+-- [ Attrib "position" 2 GLFloat+-- , Attrib "texcoord" 2 GLFloat ]+-- +-- -- create an FBO to render the primary scene on+-- fbo <- newFBO+-- bindFramebuffer fbo+-- texture <- newEmptyTexture2D 640 480 :: IO (Tex2D RGB)+-- bindTexture2D texture+-- setTex2DFiltering Linear+-- attachTex2D texture+-- return (vao1, vao2, prog1, prog2, fbo, texture)+-- +-- draw :: VAO -> VAO -> Program -> Program -> FBO -> Tex2D RGB -> Float -> IO ()+-- draw vao1 vao2 prog1 prog2 fbo texture t = do+-- -- render primary scene to fbo+-- bindVAO vao1+-- bindFramebuffer fbo+-- useProgram prog1+-- clearColorBuffer (0,0,0)+-- setUniform1f "time" [t]+-- drawTriangles 3+-- +-- -- render results to quad on main screen+-- bindVAO vao2+-- bindFramebuffer DefaultFramebuffer+-- useProgram prog2+-- bindTexture2D texture+-- clearColorBuffer (0,0,0)+-- setUniform1f "time" [t]+-- drawIndexedTriangles 6 UByteIndices+-- @+--+-- The vertex shader for this program is+--+-- @+-- #version 150+-- in vec2 position;+-- in vec2 texcoord;+-- out vec2 Texcoord;+-- void main()+-- {+-- gl_Position = vec4(position, 0.0, 1.0);+-- Texcoord = texcoord;+-- }+-- @+--+-- The two fragment shaders, one for the object, one for the effect, are+--+-- @+-- #version 150+-- uniform float time;+-- in vec2 Texcoord;+-- out vec4 outColor;+-- void main()+-- {+-- float t = time;+-- outColor = vec4(+-- fract(Texcoord.x*5) < 0.5 ? sin(t*0.145) : cos(t*0.567),+-- fract(Texcoord.y*5) < 0.5 ? cos(t*0.534) : sin(t*0.321),+-- 0.0, 1.0+-- );+-- }+-- @+--+-- @+-- #version 150+-- uniform float time;+-- uniform sampler2D tex;+-- in vec2 Texcoord;+-- out vec4 outColor;+-- +-- void main()+-- {+-- float d = pow(10,(abs(cos(time))+1.5));+-- outColor c = texture(tex, floor(Texcoord*d)/d);+-- }+-- @
Graphics/GL/Low/Render.hs view
@@ -1,7 +1,11 @@ module Graphics.GL.Low.Render (- Culling(..),- Viewport(..),- IndexFormat(..),++ -- * Primitives+ --+ -- | Render various kinds of primitives to the current framebuffer using+ -- the current shader program. The integer argument is the number of+ -- vertices to read from the VBOs via the current VAO.+ -- drawPoints, drawLines, drawLineStrip,@@ -9,6 +13,13 @@ drawTriangles, drawTriangleStrip, drawTriangleFan,++ -- * Primitives (by index)+ --+ -- | Render various kinds of primitives by traversing the vertices in the+ -- order specified in the current ElementArray. The format argument indicates+ -- the size of each index in the ElementArray.+ -- drawIndexedPoints, drawIndexedLines, drawIndexedLineStrip,@@ -16,11 +27,21 @@ drawIndexedTriangles, drawIndexedTriangleStrip, drawIndexedTriangleFan,++ -- * Scissor Test enableScissorTest, disableScissorTest,++ -- * Facet Culling enableCulling, disableCulling,- setViewport++ -- * Viewport+ setViewport,++ Culling(..),+ Viewport(..),+ IndexFormat(..) ) where import Foreign.Ptr
Graphics/GL/Low/Shader.hs view
@@ -1,3 +1,6 @@++{-# LANGUAGE DeriveDataTypeable #-}+module Graphics.GL.Low.Shader ( -- | 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@@ -28,159 +31,10 @@ -- - 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--- setVertexLayout--- [ Attrib "position" 2 GLFloat--- , Attrib "location" 2 GLFloat ]--- 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,- ProgramError(..),- newProgramSafe,- deleteProgram, newProgram,+ newProgramSafe, useProgram,+ deleteProgram, setUniform1f, setUniform2f, setUniform3f,@@ -191,7 +45,12 @@ setUniform4i, setUniform44, setUniform33,- setUniform22+ setUniform22,+ Program,+ ProgramError(..)++ -- * Example+ -- $example ) where import Foreign.Ptr@@ -345,3 +204,145 @@ else glAction loc (fromIntegral n) bytes +-- $example+--+-- <<shaders.gif 3 Different Shaders Animated Demo>>+--+-- This example renders three differently-shaded triangles. The window+-- coordinates, the interpolated location on the triangle, and the elapsed time+-- are used to color the triangles respectively.+--+-- @+-- 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+-- setVertexLayout+-- [ Attrib "position" 2 GLFloat+-- , Attrib "location" 2 GLFloat ]+-- 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+-- );+-- }+-- @
Graphics/GL/Low/Stencil.hs view
@@ -1,3 +1,5 @@+module Graphics.GL.Low.Stencil (+ -- | 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@@ -17,7 +19,6 @@ -- - When the stencil test passes then the depth test fails or -- - When both tests pass. -module Graphics.GL.Low.Stencil ( enableStencil, disableStencil, clearStencilBuffer,
Graphics/GL/Low/Texture.hs view
@@ -1,3 +1,5 @@+module Graphics.GL.Low.Texture (+ -- | Textures are objects that contain image data that can be sampled by -- a shader. While an obvious application of this is texture mapping, there -- are many other uses for textures (the image data doesn't have to be an@@ -11,113 +13,7 @@ -- points to by setting it using the 'Graphics.GL.Low.Shader.setUniform1i' -- command. You can avoid dealing with active texture units if theres only one -- sampler because the default unit is zero.------ == Example------ This example loads a 256x256 PNG file with JuicyPixels and displays the--- image on a square. Of course without a correction for aspect ratio the--- square will only be square if you adjust your window to be square.------ @--- module Main where--- --- import Control.Monad.Loops (whileM_)--- import Data.Functor ((\<$\>))--- import qualified Data.Vector.Storable as V--- import Codec.Picture--- import Data.Word--- --- 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 \"Texture\" Nothing Nothing--- case mwin of--- Nothing -> putStrLn "createWindow failed"--- Just win -> do--- GLFW.makeContextCurrent (Just win)--- GLFW.swapInterval 1--- (vao, prog, texture) <- setup--- whileM_ (not \<$\> GLFW.windowShouldClose win) $ do--- GLFW.pollEvents--- draw vao prog texture--- GLFW.swapBuffers win--- --- setup = do--- -- establish a VAO--- vao <- newVAO--- bindVAO vao--- -- load the shader--- vsource <- readFile "texture.vert"--- fsource <- readFile "texture.frag"--- prog <- newProgram vsource fsource--- useProgram prog--- -- load the vertices--- let blob = V.fromList -- a quad has four vertices--- [ -0.5, -0.5, 0, 1--- , -0.5, 0.5, 0, 0--- , 0.5, -0.5, 1, 1--- , 0.5, 0.5, 1, 0 ] :: V.Vector Float--- vbo <- newVBO blob StaticDraw--- bindVBO vbo--- setVertexLayout [ Attrib "position" 2 GLFloat--- , Attrib "texcoord" 2 GLFloat ]--- -- load the element array to draw a quad with two triangles--- indices <- newElementArray (V.fromList [0,1,2,3,2,1] :: V.Vector Word8) StaticDraw--- bindElementArray indices--- -- load the texture with JuicyPixels--- let fromRight (Right x) = x--- ImageRGBA8 (Image w h image) <- fromRight \<$\> readImage "logo.png"--- texture <- newTexture2D image (Dimensions w h) :: IO (Tex2D RGBA)--- setTex2DFiltering Linear--- return (vao, prog, texture)--- --- draw vao prog texture = do--- clearColorBuffer (0.5, 0.5, 0.5)--- bindVAO vao--- useProgram prog--- bindTexture2D texture--- drawIndexedTriangles 6 UByteIndices--- @------ The vertex shader for this example looks like------ @--- #version 150--- in vec2 position;--- in vec2 texcoord;--- out vec2 Texcoord;--- void main()--- {--- gl_Position = vec4(position, 0.0, 1.0);--- Texcoord = texcoord;--- }--- @------ And the fragment shader looks like------ @--- #version 150--- in vec2 Texcoord;--- out vec4 outColor;--- uniform sampler2D tex;--- void main()--- {--- outColor = texture(tex, Texcoord);--- }--- @------ Should produce output like------ <<texture.png Screenshot of Texture Example>> -module Graphics.GL.Low.Texture ( newTexture2D, newCubeMap, newEmptyTexture2D,@@ -134,7 +30,11 @@ CubeMap, Filtering(..), Wrapping(..),- Dimensions(..),+ Dimensions(..)++ -- * Example+ -- $example+ ) where import Foreign.Ptr@@ -330,3 +230,106 @@ instance GLObject (CubeMap a) where glObjectName (CubeMap n) = fromIntegral n++-- $example+--+-- <<texture.png Screenshot of Texture Example>>+--+-- This example loads a 256x256 PNG file with JuicyPixels and displays the+-- image on a square. Of course without a correction for aspect ratio the+-- square will only be square if you adjust your window to be square.+--+-- @+-- module Main where+-- +-- import Control.Monad.Loops (whileM_)+-- import Data.Functor ((\<$\>))+-- import qualified Data.Vector.Storable as V+-- import Codec.Picture+-- import Data.Word+-- +-- 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 \"Texture\" Nothing Nothing+-- case mwin of+-- Nothing -> putStrLn "createWindow failed"+-- Just win -> do+-- GLFW.makeContextCurrent (Just win)+-- GLFW.swapInterval 1+-- (vao, prog, texture) <- setup+-- whileM_ (not \<$\> GLFW.windowShouldClose win) $ do+-- GLFW.pollEvents+-- draw vao prog texture+-- GLFW.swapBuffers win+-- +-- setup = do+-- -- establish a VAO+-- vao <- newVAO+-- bindVAO vao+-- -- load the shader+-- vsource <- readFile "texture.vert"+-- fsource <- readFile "texture.frag"+-- prog <- newProgram vsource fsource+-- useProgram prog+-- -- load the vertices+-- let blob = V.fromList -- a quad has four vertices+-- [ -0.5, -0.5, 0, 1+-- , -0.5, 0.5, 0, 0+-- , 0.5, -0.5, 1, 1+-- , 0.5, 0.5, 1, 0 ] :: V.Vector Float+-- vbo <- newVBO blob StaticDraw+-- bindVBO vbo+-- setVertexLayout [ Attrib "position" 2 GLFloat+-- , Attrib "texcoord" 2 GLFloat ]+-- -- load the element array to draw a quad with two triangles+-- indices <- newElementArray (V.fromList [0,1,2,3,2,1] :: V.Vector Word8) StaticDraw+-- bindElementArray indices+-- -- load the texture with JuicyPixels+-- let fromRight (Right x) = x+-- ImageRGBA8 (Image w h image) <- fromRight \<$\> readImage "logo.png"+-- texture <- newTexture2D image (Dimensions w h) :: IO (Tex2D RGBA)+-- setTex2DFiltering Linear+-- return (vao, prog, texture)+-- +-- draw vao prog texture = do+-- clearColorBuffer (0.5, 0.5, 0.5)+-- bindVAO vao+-- useProgram prog+-- bindTexture2D texture+-- drawIndexedTriangles 6 UByteIndices+-- @+--+-- The vertex shader for this example looks like+--+-- @+-- #version 150+-- in vec2 position;+-- in vec2 texcoord;+-- out vec2 Texcoord;+-- void main()+-- {+-- gl_Position = vec4(position, 0.0, 1.0);+-- Texcoord = texcoord;+-- }+-- @+--+-- And the fragment shader looks like+--+-- @+-- #version 150+-- in vec2 Texcoord;+-- out vec4 outColor;+-- uniform sampler2D tex;+-- void main()+-- {+-- outColor = texture(tex, Texcoord);+-- }+-- @
Graphics/GL/Low/VAO.hs view
@@ -1,3 +1,6 @@++module Graphics.GL.Low.VAO (+ -- | 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@@ -52,12 +55,10 @@ -- } -- @ -module Graphics.GL.Low.VAO -(- VAO, newVAO, deleteVAO,- bindVAO+ bindVAO,+ VAO ) where import Foreign.Storable
Graphics/GL/Low/VertexAttrib.hs view
@@ -1,9 +1,8 @@+module Graphics.GL.Low.VertexAttrib ( -- | To feed vertices into the vertex shader, the layout of a vertex must be -- specified in the current VAO for the current shader program. Make a list of -- LayoutElements and use 'setVertexLayout' on it as seen below. ----- == Example--- -- @ -- setVertexLayout -- [ Attrib "position" 3 GLFloat -- first 12 bytes maps to: in vec3 position;@@ -17,8 +16,6 @@ -- In this example four mappings from the current VBO to the variables -- in the current Program will be established in the current VAO. --module Graphics.GL.Low.VertexAttrib ( setVertexLayout, VertexLayout(..), DataType(..)
lowgl.cabal view
@@ -10,7 +10,7 @@ -- PVP summary: +-+------- breaking API changes -- | | +----- non-breaking API additions -- | | | +--- code changes with no API change-version: 0.3.1.0+version: 0.3.1.1 -- A short (one-line) description of the package. synopsis: Basic gl wrapper and reference@@ -56,6 +56,7 @@ Graphics.GL.Low.Cube Graphics.GL.Low.Depth Graphics.GL.Low.Error+ Graphics.GL.Low.EntirePictureUpFront Graphics.GL.Low.Framebuffer Graphics.GL.Low.ImageFormat Graphics.GL.Low.Render@@ -89,4 +90,4 @@ source-repository this type: git location: https://github.com/evanrinehart/lowgl- tag: 0.3.1.0+ tag: 0.3.1.1