opengles-0.8.2: examples/windmill.hs
{-# LANGUAGE RecordWildCards, DeriveDataTypeable #-}
module Main where
import Control.Applicative
import Control.Concurrent
import Control.Monad
import qualified Data.ByteString.Char8 as BS
import Data.Time.Clock
import Graphics.OpenGLES
import qualified Graphics.UI.GLFW as GLFW
import System.Random
import Linear.Graphics
-- ghc examples/windmill.hs -lEGL -lGLESv2 -threaded && examples/windmill
main = do
isOk <- GLFW.init
when (not isOk) $ fail "Initialization Failed!"
win <- initFullscreen 1600 1480 "Window Title"
--win <- initWindow 600 480 "Window Title"
>>= maybe (fail "Failed to create a Window") return
GLFW.setFramebufferSizeCallback win $ Just (const framesize)
forkGL
(GLFW.makeContextCurrent (Just win) >> return False)
(GLFW.makeContextCurrent Nothing)
(GLFW.swapBuffers win)
forkIO $ mapM_ (putStrLn.("# "++)) =<< glLogContents
future <- withGL $ mkWindmill >>= mkSomeObj
obj <- expect future
rand <- getStdGen
t0 <- getCurrentTime
let loop c = do
withGL $ draw win rand t0 obj
endFrameGL
GLFW.pollEvents
closing <- GLFW.windowShouldClose win
when (not closing && c < 1000) $ loop (c + 1)
loop 0
initWindow w h title = do
GLFW.windowHint $ GLFW.WindowHint'Resizable True
GLFW.createWindow w h title Nothing Nothing
initFullscreen w h title = do
monitor <- GLFW.getPrimaryMonitor
GLFW.createWindow w h title monitor Nothing
data Windmill = Windmill
{ windmill :: Program Windmill
, scaleRot :: Uniform Windmill Mat2
, offset :: Uniform Windmill Vec2
, pos :: Attrib Windmill Vec2
, color :: Attrib Windmill Vec3
} deriving Typeable
mkWindmill :: GL Windmill
mkWindmill = do
Finished p <- glCompile NoFeedback
[ vertexShader "windmill.vs" vsSrc
, fragmentShader "windmill.fs" fsSrc ]
$ \prog step msg bin ->
putStrLn $ "> step " ++ show step ++ ", " ++ msg
Windmill p <$> uniform "scaleRot" <*> uniform "offset"
<*> attrib "pos" <*> attrib "color"
vsSrc = BS.pack $
"#version 100\n\
\uniform mat2 scaleRot;\
\uniform vec2 offset;\
\attribute vec2 pos;\
\attribute vec3 color;\
\varying vec4 vColor;\
\void main() {\
\ gl_Position = vec4(scaleRot * pos + offset, 0.0, 1.0);\
\ vColor = vec4(color, 1.0);\
\}"
fsSrc = BS.pack $
"#version 100\n\
\precision mediump float;\
\varying vec4 vColor;\
\void main() {\
\ gl_FragColor = vColor;\
\}"
data SomeObj = SomeObj
{ prog :: Windmill
, vao :: VertexArray Windmill
, posBuf :: Buffer Vec2
, colorBuf :: Buffer (V3 Word8)
}
mkSomeObj :: Windmill -> GL SomeObj
mkSomeObj prog@Windmill{..} = do
posBuf <- glLoad app2gl quadPos
colorBuf <- glLoad app2gl quadCol
vao <- glVA [ pos &= posBuf, normalized color &= colorBuf ]
return SomeObj {..}
-- Square with diagonal < 2 so that it fits in a [-1,1] square
-- regardless of rotation.
quadPos :: [Vec2]
quadPos = [V2 (-0.7) (-0.7), V2 0.7 (-0.7), V2 (-0.7) 0.7, V2 0.7 0.7]
quadCol :: [V3 Word8]
quadCol = [V3 0x00 0xFF 0x00, V3 0x00 0x00 0xFF, V3 0xFF 0x00 0x00, V3 0x30 0x7F 0xFF]
draw :: GLFW.Window -> StdGen -> UTCTime -> SomeObj -> GL ()
draw win seed t0 SomeObj{..} = do
(w, h) <- GLFW.getWindowSize win
let (wx, hx) = (16.0, realToFrac $ h `div` (w `div` 16))
t <- getCurrentTime
let time = realToFrac $ diffUTCTime t t0
let angles = [angl * time | angl <- rollDices seed]
clear [ clearColor 0.2 0.2 0.3 1.0 ] colorBuffer
let Windmill{..} = prog
forM_ [(i, j) | i <- [0..wx-1], j <- [0..hx-1]] $ \(i, j) -> do
let a = angles !! floor (i + wx * j)
glDraw triangleStrip windmill []
[ scaleRot $= cos a *!! scale2 (1/wx) (1/hx) !*! rotate2 a
, offset $= V2 (2/wx*(0.5+i)-1) (2/hx*(0.5+j)-1) ]
vao $ takeFrom 0 4
rollDices :: StdGen -> [Float]
rollDices = randomRs (0.1, 2*3.14)