There are some really clever and productive people on the #haskell-game IRC channel. Among them is Brian Lewis, who maintains a binding to the GLFW library, which lets you create windows with OpenGL contexts in them and manage inputs and events. His binding is called GLFW-b and is just a cabal install
away from you.
Recently, Brian updated his package to match GLFW 3.0, so I thought it could be a good opportunity to see how it felt to use his package. I decided to port the official “quick example” in Haskell using GLFW-b, and here’s the reulting code. I tried to keep the same spirit as in the original code, just introducing some utility functions to make that code smoother to read.
module Main where
import Control.Monad (unless, when)
import Graphics.Rendering.OpenGL
import qualified Graphics.UI.GLFW as G
import System.Exit
import System.IO
-- tiny utility functions, in the same spirit as 'maybe' or 'either'
-- makes the code a wee bit easier to read
bool :: Bool -> a -> a -> a
= if b then trueRes else falseRes
bool b falseRes trueRes
unless' :: Monad m => m Bool -> m () -> m ()
= do
unless' action falseAction <- action
b
unless b falseAction
maybe' :: Maybe a -> b -> (a -> b) -> b
= case m of
maybe' m nothingRes f Nothing -> nothingRes
Just x -> f x
-- type ErrorCallback = Error -> String -> IO ()
errorCallback :: G.ErrorCallback
= hPutStrLn stderr description
errorCallback err description
keyCallback :: G.KeyCallback
= when (key == G.Key'Escape && action == G.KeyState'Pressed) $
keyCallback window key scancode action mods True
G.setWindowShouldClose window
main :: IO ()
= do
main Just errorCallback)
G.setErrorCallback (<- G.init
successfulInit -- if init failed, we exit the program
$ do
bool successfulInit exitFailure <- G.createWindow 640 480 "Simple example, haskell style" Nothing Nothing
mw >> exitFailure) $ \window -> do
maybe' mw (G.terminate
G.makeContextCurrent mwJust keyCallback)
G.setKeyCallback window (
mainLoop window
G.destroyWindow window
G.terminate
exitSuccess
mainLoop :: G.Window -> IO ()
= unless' (G.windowShouldClose w) $ do
mainLoop w <- G.getFramebufferSize w
(width, height) let ratio = fromIntegral width / fromIntegral height
$= (Position 0 0, Size (fromIntegral width) (fromIntegral height))
viewport ColorBuffer]
clear [
$= Projection
matrixMode
loadIdentitynegate ratio) ratio (negate 1.0) 1.0 1.0 (negate 1.0)
ortho ($= Modelview 0
matrixMode
loadIdentity-- this is bad, but keeps the logic of the original example I guess
Just t <- G.getTime
realToFrac t) * 50) $ (Vector3 0 0 1 :: Vector3 GLdouble)
rotate ((
Triangles $ do
renderPrimitive Color3 1 0 0 :: Color3 GLdouble)
color (Vertex3 (negate 0.6) (negate 0.4) 0 :: Vertex3 GLdouble)
vertex (Color3 0 1 0 :: Color3 GLdouble)
color (Vertex3 0.6 (negate 0.4) 0 :: Vertex3 GLdouble)
vertex (Color3 0 0 1 :: Color3 GLdouble)
color (Vertex3 0 0.6 0 :: Vertex3 GLdouble)
vertex (
G.swapBuffers w
G.pollEvents mainLoop w
The code sits in a github repo for your viewing/forking pleasure.
Powered by Hakyll - RSS feed - servant paper