{-# LANGUAGE Arrows, PackageImports #-} import Control.Arrow import Data.Monoid import Data.VectorSpace import "GLFW-b" Graphics.UI.GLFW import Graphics.Rendering.OpenGL import FRP.Yampa.GLFW.Adapter import FRP.Yampa (SF, integral, delay, initially, edge, accumHoldBy, time) import FRP.Yampa.Event import GHC.Float import Text.Printf import Unsafe.Coerce import System.IO.Unsafe import Data.IORef checkError :: String -> IO () checkError functionName = get errors >>= mapM_ reportError where reportError e = putStrLn (showError e ++ " detected in " ++ functionName) showError (Error category message) = "GL error " ++ show category ++ " (" ++ message ++ ")" main = do simpleInit "Simple" cullFace $= Just Back frontFace $= CW shadeModel $= Smooth blend $= Enabled blendFunc $= (SrcAlpha, OneMinusSrcAlpha) lighting $= Enabled ambient (Light 0) $= Color4 0.1 0.1 0.1 (1::GLfloat) diffuse (Light 0) $= Color4 0.9 0.9 0.9 (1::GLfloat) position (Light 0) $= Vertex4 0.5 0.5 (-10) 0 light (Light 0) $= Enabled colorMaterial $= Just (Front, AmbientAndDiffuse) checkError "init" adapt simple simple :: Reaction simple = proc ev -> do pos <- positionSim -< ev disp <- redraw -< ev reshapedAction <- fmap (actionIO . reshape) ^<< resized -< ev returnA -< mconcat [ reshapedAction, disp `tag` actionIO (display pos) ] mkVertex :: Float -> Float -> Float -> IO () mkVertex x y z = vertex $ (Vertex3 :: GLfloat -> GLfloat -> GLfloat -> Vertex3 GLfloat) (realToFrac x) (realToFrac y) (realToFrac z) display (x, y) = do clear [ ColorBuffer, DepthBuffer ] preservingMatrix $ do translate (Vector3 (realToFrac x) (realToFrac y) (0 :: GLfloat)) color $ Color4 0.2 0.8 0 (0.5::GLfloat) renderPrimitive Triangles $ do mkVertex (-0.1) (-0.1) (0) mkVertex (-0.1) ( 0.2) (0) mkVertex ( 0.2) (-0.1) (0) swapBuffers reshape sz@(Size w h) = do let b = fromIntegral (w `min` h) * 2 w' = fromIntegral w / b h' = fromIntegral h / b viewport $= (Position 0 0, sz) matrixMode $= Projection loadIdentity frustum (-w') w' (-h') h' 2 100 matrixMode $= Modelview 0 loadIdentity translate (Vector3 0 0 (-4 :: GLfloat)) pr :: String -> b -> b pr x exp = seq (unsafePerformIO $ putStrLn x) exp oldRef = unsafePerformIO $ newIORef (0 :: Int, 0.0, (0, 0)) v2len :: (Float, Float) -> Float v2len (x, y) = sqrt(x*x + y*y) watcher :: Double -> (Float, Float) -> IO () watcher t pos = do (oldi, oldt, oldp) <- readIORef oldRef writeIORef oldRef (oldi + 1, t, pos) let dt = t - oldt dp = v2len $ pos ^-^ oldp printf "; %d t=%3.3f dt=%3.3f dp=%3.3f es=%3.3f\n" oldi t dt dp (dp / (double2Float dt)) return () positionSim :: SF (Event UI) (Float, Float) positionSim = proc ev -> do d <- moveDirection -< ev (Vector2 tx ty) <- simpleMousePosition -< ev t <- time -< ev rec let mpos = (tx, ty) dpos = mpos ^-^ pos speed = normalized dpos ^* 0.5 ^* d pos <- integral <<< delay 0.1 zeroV -< speed returnA -< -- seq (unsafePerformIO $ watcher t pos) pos moveDirection :: SF (Event UI) Float moveDirection = mouseButtonPressed MouseButton0 >>> edge >>> accumHoldBy (const . negate) 1