packages feed

TeaHS-0.3: Tea/Display.hs

-- |Includes core Tea monad functions that regulate display and framerate
--  as well as the runTea function that initializes hardware.
module Tea.Display
       ( screen
       , update
       , runTea
       , setFrameRate
       ) where

import qualified Graphics.UI.SDL as SDL
import qualified Graphics.UI.SDL.Mixer as Mixer
import Control.Monad.State
import Control.Monad.Trans
import Control.Applicative((<$>))
import Data.Map (empty)
import Data.Array (listArray)
import Tea.Input (KeyCode)
import Tea.TeaState
import Tea.Screen
import Tea.Tea

-- |Retrieve a buffer handle on the Screen
screen :: Tea s Screen
screen = _screen <$> getT

-- |Sets the frame rate cap. Note that this is merely a cap, and the frame rate may
--  be slower than this if additional processing is required.
setFrameRate :: Int ->  Tea s ()
setFrameRate n = modifyT $ \ts -> ts { _fpsCap = 1000 `div` n }

-- |Flip buffers, causing the hardware display to be updated with changes to
--  the Screen. Note this also waits sufficient time for a frame to have elapsed.
update :: Tea s ()
update = do ts@(TS { _screen = (Screen x), _fpsCap = fps, _lastUpdate = last}) <- getT
            t <- liftIO SDL.getTicks
            liftIO $ do
                     when (fromIntegral t < last + fps) $ SDL.delay $ fromIntegral $ last + fps - fromIntegral t
                     SDL.tryFlip x
            putT $ ts { _lastUpdate = fromIntegral t}

initialEventState = ES { keyCodes    = listArray (minBound :: KeyCode, maxBound :: KeyCode) $ repeat False
                       , keysDown    = 0
                       }

-- |Initialize hardware and run a Tea action with the specified state type.
runTea :: Int      -- ^ Screen Width
       -> Int      -- ^ Screen Height
       -> s        -- ^ State data
       -> Tea s m  -- ^ Tea action
       -> IO ()
runTea w h s m = do
                 SDL.init [SDL.InitEverything]
                 Mixer.openAudio 44100 Mixer.AudioS16Sys 2 1024
                 surf <- SDL.setVideoMode w h 0 [SDL.SWSurface, SDL.DoubleBuf]
                 let initialState = (TS (Screen surf) initialEventState (1000 `div` 60) 0 empty)
                 ((v,s'), st') <- runStateT (runStateT (extractTea m) s) initialState
                 Mixer.closeAudio
                 SDL.quit
                 return ()