module Graphics.GPipe.Context.GLFW
( newContext,
GLFWWindow(),
getCursorPos, getMouseButton, getKey, windowShouldClose,
MouseButtonState(..), MouseButton(..), KeyState(..), Key(..),
) where
import qualified Control.Concurrent as C
import qualified Control.Monad as M
import qualified Graphics.GPipe.Context.GLFW.Format as Format
import qualified Graphics.GPipe.Context.GLFW.Resource as Resource
import qualified Graphics.GPipe.Context.GLFW.Util as Util
import qualified Graphics.UI.GLFW as GLFW (getCursorPos, getMouseButton, getKey, windowShouldClose, makeContextCurrent, destroyWindow)
import Control.Monad.IO.Class (MonadIO)
import Data.Maybe (isNothing)
import Graphics.GPipe.Context (ContextFactory, ContextHandle(..),ContextT,withContextWindow)
import Graphics.GPipe.Format (ContextFormat)
import Graphics.UI.GLFW (MouseButtonState(..), MouseButton(..), KeyState(..), Key(..))
type Message = Maybe Request
data Request where
ReqExecute :: forall a. IO a -> Maybe (C.MVar a) -> Request
newtype GLFWWindow = GLFWWindow { unGLFWWindow :: Resource.Window }
newContext :: ContextFactory c ds GLFWWindow
newContext fmt = do
chReply <- C.newEmptyMVar
_ <- C.forkOS $ begin chReply fmt
C.takeMVar chReply
createContext :: C.Chan Message -> Maybe Resource.Window -> ContextFactory c ds GLFWWindow
createContext msgC share fmt = do
w <- makeContext share
return ContextHandle
{ newSharedContext = contextDoSyncImpl w msgC . createContext msgC (Just w)
, contextDoSync = contextDoSyncImpl w msgC
, contextDoAsync = contextDoAsyncImpl w msgC
, contextSwap = Util.swapBuffers w
, contextFrameBufferSize = Util.getFramebufferSize w
, contextDelete = do
contextDoSyncImpl w msgC (GLFW.destroyWindow w)
M.when (isNothing share) $ contextDeleteImpl msgC
, contextWindow = GLFWWindow w
}
where
hints = Format.toHints fmt
makeContext :: Maybe Resource.Window -> IO Resource.Window
makeContext Nothing = Resource.newContext Nothing hints Nothing
makeContext (Just s) = Resource.newSharedContext s hints Nothing
begin :: C.MVar (ContextHandle GLFWWindow) -> ContextFormat c ds -> IO ()
begin chReply fmt = do
msgC <- C.newChan
handle <- createContext msgC Nothing fmt
C.putMVar chReply handle
loop msgC
loop :: C.Chan Message -> IO ()
loop msgC = do
msg <- C.readChan msgC
case msg of
Nothing -> return ()
Just req -> doRequest req >> loop msgC
doRequest :: Request -> IO ()
doRequest (ReqExecute action Nothing) = M.void action
doRequest (ReqExecute action (Just reply)) = action >>= C.putMVar reply
contextDoSyncImpl :: Resource.Window -> C.Chan Message -> IO a -> IO a
contextDoSyncImpl w msgC action = do
reply <- C.newEmptyMVar
C.writeChan msgC . Just $ ReqExecute (GLFW.makeContextCurrent (Just w) >> action) (Just reply)
C.takeMVar reply
contextDoAsyncImpl :: Resource.Window -> C.Chan Message -> IO () -> IO ()
contextDoAsyncImpl w msgC action =
C.writeChan msgC . Just $ ReqExecute (GLFW.makeContextCurrent (Just w) >> action) Nothing
contextDeleteImpl :: C.Chan Message -> IO ()
contextDeleteImpl msgC =
C.writeChan msgC Nothing
getCursorPos :: MonadIO m => ContextT GLFWWindow os f m (Double, Double)
getCursorPos = withContextWindow (GLFW.getCursorPos . unGLFWWindow)
getMouseButton :: MonadIO m => MouseButton -> ContextT GLFWWindow os f m MouseButtonState
getMouseButton mb = withContextWindow (\(GLFWWindow w) -> GLFW.getMouseButton w mb)
getKey :: MonadIO m => Key -> ContextT GLFWWindow os f m KeyState
getKey k = withContextWindow (\(GLFWWindow w) -> GLFW.getKey w k)
windowShouldClose :: MonadIO m => ContextT GLFWWindow os f m Bool
windowShouldClose = withContextWindow (GLFW.windowShouldClose . unGLFWWindow)