packages feed

GLUtil-0.1.4: examples/example1.hs

-- | A port of the code presented at [Modern OpenGL with
-- Haskell](http://www.arcadianvisions.com/blog/?p=224) to use the
-- GLFW-b package.
import Control.Applicative
import Control.Monad (when)
import Graphics.Rendering.OpenGL
import Graphics.UI.GLFW
import Foreign.Storable (sizeOf)
import System.FilePath ((</>))
import TGA -- Small library for TGA file handling
import Graphics.GLUtil

-- | A value to carry around a shader program and its parameters.
data Shaders = Shaders { program        :: Program
                       , fadeFactorU    :: UniformLocation
                       , texturesU      :: [UniformLocation] 
                       , positionA      :: AttribLocation }

-- | The resources used for drawing our scene.
data Resources = Resources { vertexBuffer  :: BufferObject
                           , elementBuffer :: BufferObject
                           , textures      :: [TextureObject]
                           , shaders       :: Shaders
                           , fadeFactor    :: GLfloat }

-- | Geometry data is a list of four 2D vertices.
vertexBufferData :: [GLfloat]
vertexBufferData = [-1, -1, 1, -1, -1, 1, 1, 1]

-- | Load a texture and set some texturing parameters.
makeTexture :: FilePath -> IO TextureObject
makeTexture filename = 
    do (width,height,pixels) <- readTGA filename
       tex <- loadTexture $ texInfo width height TexBGR pixels
       textureFilter   Texture2D   $= ((Linear', Nothing), Linear')
       textureWrapMode Texture2D S $= (Mirrored, ClampToEdge)
       textureWrapMode Texture2D T $= (Mirrored, ClampToEdge)
       return tex

-- | Load and compile our GLSL program, and pull out the parameters we
-- want.
initShaders :: IO Shaders
initShaders = do vs <- loadShader $ "shaders" </> "hello-gl.vert"
                 fs <- loadShader $ "shaders" </> "hello-gl.frag"
                 p <- linkShaderProgram [vs] [fs]
                 Shaders p
                   <$> get (uniformLocation p "fade_factor")
                   <*> mapM (get . uniformLocation p)
                         ["textures[0]", "textures[1]"]
                   <*> get (attribLocation p "position")

-- | Load our geometry and textures into OpenGL.
makeResources :: IO Resources
makeResources =  Resources
             <$> makeBuffer ArrayBuffer vertexBufferData
             <*> makeBuffer ElementArrayBuffer [0..3::GLuint]
             <*> mapM (makeTexture . ("images" </>)) 
                      ["hello1.tga", "hello2.tga"]
             <*> initShaders
             <*> pure 0.0

-- | Bind textures to GLSL samplers.
setupTexturing :: Resources -> IO ()
setupTexturing r = let [t1, t2] = textures r
                       [tu1, tu2] = texturesU (shaders r)
                   in do activeTexture $= TextureUnit 0
                         textureBinding Texture2D $= Just t1
                         uniform tu1 $= Index1 (0::GLint)
                         activeTexture $= TextureUnit 1
                         textureBinding Texture2D $= Just t2
                         uniform tu2 $= Index1 (1::GLint)

-- | Bind the geometry array and element buffers.
setupGeometry :: Resources -> IO ()
setupGeometry r = let posn = positionA (shaders r)
                      stride = fromIntegral $ sizeOf (undefined::GLfloat) * 2
                      vad = VertexArrayDescriptor 2 Float stride offset0
                  in do bindBuffer ArrayBuffer   $= Just (vertexBuffer r)
                        vertexAttribPointer posn $= (ToFloat, vad)
                        vertexAttribArray posn   $= Enabled
                        bindBuffer ElementArrayBuffer $= Just (elementBuffer r)

-- | Set drawing parameters that won't change during execution.
drawInit :: Resources -> IO ()
drawInit r = do clearColor $= Color4 1 1 1 1
                clear [ColorBuffer]
                currentProgram $= Just (program (shaders r))
                setupTexturing r
                setupGeometry r

draw :: Resources -> IO ()
draw r = do uniform (fadeFactorU (shaders r)) $= Index1 (fadeFactor r)
            drawElements TriangleStrip 4 UnsignedInt offset0

animate :: Resources -> IO Resources
animate r = do seconds <- getTime
               let fade = sin seconds * 0.5 + 0.5
               return r { fadeFactor = realToFrac fade }

main :: IO ()
main = do _ <- initialize
          _ <- openWindow opts
          setWindowTitle "Chapter 2"
          makeResources >>= (>>) <$> drawInit <*> go
  where opts = defaultDisplayOptions { displayOptions_width = 500
                                     , displayOptions_height = 500
                                     , displayOptions_refreshRate = Just 100 }
        go r = do draw r
                  swapBuffers
                  pollEvents
                  keyIsPressed KeyEsc >>= flip when (animate r >>= go) . not