module Common where import Control.Concurrent import Control.Monad import Control.Monad.IO.Class import Control.Monad.Trans.Except import Control.Monad.Trans.Resource import Data.IORef ( IORef, newIORef, readIORef, writeIORef ) import Graphics.Luminance.Framebuffer import Graphics.Luminance.Shader.Program import Graphics.Luminance.Shader.Stage import Graphics.UI.GLFW import Prelude hiding ( init ) import System.IO ( hPutStrLn, stderr ) type App = ExceptT AppError (ResourceT IO) data AppError = AppIncompleteFramebuffer String | AppStageCompilationFailed String | AppUnsupportedStage StageType | AppProgramLinkFailed String | AppInactiveUniform SomeUniformName | TextureLoadFailed String | CLIUsage String deriving (Eq,Show) instance HasFramebufferError AppError where fromFramebufferError (IncompleteFramebuffer s) = AppIncompleteFramebuffer s instance HasStageError AppError where fromStageError e = case e of CompilationFailed s -> AppStageCompilationFailed s UnsupportedStage s -> AppUnsupportedStage s instance HasProgramError AppError where fromProgramError e = case e of LinkFailed s -> AppProgramLinkFailed s InactiveUniform name -> AppInactiveUniform name windowW,windowH :: (Num a) => a windowW = 800 windowH = 600 windowTitle :: String windowTitle = "luminance-sample" startup :: (Window -> (App a -> App ()) -> App ()) -> IO () startup app = do _ <- init windowHint (WindowHint'Resizable False) windowHint (WindowHint'ContextVersionMajor 3) windowHint (WindowHint'ContextVersionMinor 3) windowHint (WindowHint'OpenGLProfile OpenGLProfile'Core) window <- createWindow windowW windowH windowTitle Nothing Nothing escapeKey <- newIORef False makeContextCurrent window case window of Just window' -> do swapInterval 1 setKeyCallback window' . Just $ \_ k _ ks _ -> case (k,ks) of (Key'Escape,KeyState'Released) -> writeIORef escapeKey True _ -> pure () (runResourceT . runExceptT $ app window' (mainLoop window' escapeKey)) >>= either print (const $ pure ()) destroyWindow window' Nothing -> hPutStrLn stderr "unable to create window; please check your hardware support OpenGL4.5" terminate endFrame :: (MonadIO m) => Window -> m () endFrame window = liftIO $ do pollEvents swapBuffers window threadDelay 50000 mainLoop :: Window -> IORef Bool -> App a -> App () mainLoop window escapeKey = untilM $ liftIO $ do escaped <- readIORef escapeKey if escaped then setWindowShouldClose window True >> pure True else windowShouldClose window untilM :: (Monad m) => m Bool -> m b -> m () untilM predicate a = go where go = do p <- predicate if p then pure () else a >> go