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