gore-and-ash-sdl-2.1.0.0: src/Game/GoreAndAsh/SDL/Module.hs
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-|
Module : Game.GoreAndAsh.SDL.Module
Description : Monad transformer of the module
Copyright : (c) Anton Gushcha, 2015-2016
License : BSD3
Maintainer : ncrashed@gmail.com
Stability : experimental
Portability : POSIX
The module contains declaration of monad transformer of the core module and
instance for 'GameModule' class.
-}
module Game.GoreAndAsh.SDL.Module(
SDLT(..)
) where
import Control.Monad.Base
import Control.Monad.Catch
import Control.Monad.Error.Class
import Control.Monad.Fix
import Control.Monad.IO.Class
import Control.Monad.State.Strict
import Control.Monad.Trans.Resource
import Data.Proxy
import qualified Data.Foldable as F
import qualified Data.HashMap.Strict as H
import qualified Data.Sequence as S
import SDL
import Game.GoreAndAsh
import Game.GoreAndAsh.SDL.State
-- | Monad transformer of SDL core module.
--
-- [@s@] - State of next core module in modules chain;
--
-- [@m@] - Next monad in modules monad stack;
--
-- [@a@] - Type of result value;
--
-- How to embed module:
--
-- @
-- type AppStack = ModuleStack [SDLT, ... other modules ... ] IO
--
-- newtype AppMonad a = AppMonad (AppStack a)
-- deriving (Functor, Applicative, Monad, MonadFix, MonadIO, MonadThrow, MonadCatch, MonadSDL)
-- @
--
-- The module is NOT pure within first phase (see 'ModuleStack' docs), therefore currently only 'IO' end monad can handler the module.
newtype SDLT s m a = SDLT { runSDLT :: StateT (SDLState s) m a }
deriving (Functor, Applicative, Monad, MonadState (SDLState s), MonadFix, MonadTrans, MonadIO, MonadThrow, MonadCatch, MonadMask, MonadError e)
instance MonadBase IO m => MonadBase IO (SDLT s m) where
liftBase = SDLT . liftBase
instance MonadResource m => MonadResource (SDLT s m) where
liftResourceT = SDLT . liftResourceT
instance GameModule m s => GameModule (SDLT s m) (SDLState s) where
type ModuleState (SDLT s m) = SDLState s
runModule (SDLT m) s = do
s' <- processEvents s
clearWindows s'
((a, s''), nextState) <- runModule (runStateT m s') (sdlNextState s')
drawWindows s''
return (a, flashSDLState $ s'' {
sdlNextState = nextState
})
newModuleState = emptySDLState <$> newModuleState
withModule _ io = do
initializeAll
liftIO $ putStrLn "SDL initialized"
withModule (Proxy :: Proxy m) io
cleanupModule _ = quit
-- | Takes all window and renderers and update them
drawWindows :: MonadIO m => SDLState s -> m ()
drawWindows SDLState{..} = mapM_ go . H.elems $! sdlWindows
where
go WindowInfo{..} = do
whenJust winfoContext . const . glSwapWindow $! winfoWindow
present winfoRenderer
-- | Clear surface of all windows
clearWindows :: MonadIO m => SDLState s -> m ()
clearWindows SDLState{..} = mapM_ go . H.elems $! sdlWindows
where
go WindowInfo{..} = case winfoColor of
Nothing -> return ()
Just c -> do
rendererDrawColor winfoRenderer $= c
clear winfoRenderer
-- | Catch all SDL events
processEvents :: MonadIO m => SDLState s -> m (SDLState s)
processEvents sdlState = do
es <- pollEvents
return $! F.foldl' process sdlState (eventPayload <$> es)
where
process s e = case e of
WindowShownEvent d -> s { sdlWindowShownEvents = sdlWindowShownEvents s S.|> d }
WindowHiddenEvent d -> s { sdlWindowHiddenEvents = sdlWindowHiddenEvents s S.|> d }
WindowExposedEvent d -> s { sdlWindowExposedEvents = sdlWindowExposedEvents s S.|> d }
WindowMovedEvent d -> s { sdlWindowMovedEvents = sdlWindowMovedEvents s S.|> d }
WindowResizedEvent d -> s { sdlWindowResizedEvents = sdlWindowResizedEvents s S.|> d }
WindowSizeChangedEvent d -> s { sdlWindowSizeChangedEvents = sdlWindowSizeChangedEvents s S.|> d }
WindowMinimizedEvent d -> s { sdlWindowMinimizedEvents = sdlWindowMinimizedEvents s S.|> d }
WindowMaximizedEvent d -> s { sdlWindowMaximizedEvents = sdlWindowMaximizedEvents s S.|> d }
WindowRestoredEvent d -> s { sdlWindowRestoredEvents = sdlWindowRestoredEvents s S.|> d }
WindowGainedMouseFocusEvent d -> s { sdlWindowGainedMouseFocusEvents = sdlWindowGainedMouseFocusEvents s S.|> d }
WindowLostMouseFocusEvent d -> s { sdlWindowLostMouseFocusEvents = sdlWindowLostMouseFocusEvents s S.|> d }
WindowGainedKeyboardFocusEvent d -> s { sdlWindowGainedKeyboardFocusEvents = sdlWindowGainedKeyboardFocusEvents s S.|> d }
WindowLostKeyboardFocusEvent d -> s { sdlWindowLostKeyboardFocusEvents = sdlWindowLostKeyboardFocusEvents s S.|> d }
WindowClosedEvent d -> s { sdlWindowClosedEvents = sdlWindowClosedEvents s S.|> d }
KeyboardEvent d -> s { sdlKeyboardEvents = sdlKeyboardEvents s S.|> d }
TextEditingEvent d -> s { sdlTextEditingEvents = sdlTextEditingEvents s S.|> d }
TextInputEvent d -> s { sdlTextInputEvents = sdlTextInputEvents s S.|> d }
MouseMotionEvent d -> s { sdlMouseMotionEvents = sdlMouseMotionEvents s S.|> d }
MouseButtonEvent d -> s { sdlMouseButtonEvents = sdlMouseButtonEvents s S.|> d }
MouseWheelEvent d -> s { sdlMouseWheelEvents = sdlMouseWheelEvents s S.|> d }
JoyAxisEvent d -> s { sdlJoyAxisEvents = sdlJoyAxisEvents s S.|> d }
JoyBallEvent d -> s { sdlJoyBallEvents = sdlJoyBallEvents s S.|> d }
JoyHatEvent d -> s { sdlJoyHatEvents = sdlJoyHatEvents s S.|> d }
JoyButtonEvent d -> s { sdlJoyButtonEvents = sdlJoyButtonEvents s S.|> d }
JoyDeviceEvent d -> s { sdlJoyDeviceEvents = sdlJoyDeviceEvents s S.|> d }
ControllerAxisEvent d -> s { sdlControllerAxisEvents = sdlControllerAxisEvents s S.|> d }
ControllerButtonEvent d -> s { sdlControllerButtonEvents = sdlControllerButtonEvents s S.|> d }
ControllerDeviceEvent d -> s { sdlControllerDeviceEvents = sdlControllerDeviceEvents s S.|> d }
QuitEvent -> s { sdlQuitEvent = True }
UserEvent d -> s { sdlUserEvents = sdlUserEvents s S.|> d }
SysWMEvent d -> s { sdlSysWMEvents = sdlSysWMEvents s S.|> d }
TouchFingerEvent d -> s { sdlTouchFingerEvents = sdlTouchFingerEvents s S.|> d }
MultiGestureEvent d -> s { sdlMultiGestureEvents = sdlMultiGestureEvents s S.|> d }
DollarGestureEvent d -> s { sdlDollarGestureEvents = sdlDollarGestureEvents s S.|> d }
DropEvent d -> s { sdlDropEvents = sdlDropEvents s S.|> d }
ClipboardUpdateEvent d -> s { sdlClipboardUpdateEvents = sdlClipboardUpdateEvents s S.|> d }
_ -> s