gloss-1.7.7.1: Graphics/Gloss/Internals/Interface/Animate/Timing.hs
{-# LANGUAGE RankNTypes #-}
{-# OPTIONS_HADDOCK hide #-}
-- | Handles timing of animation.
-- The main point is that we want to restrict the framerate to something
-- sensible, instead of just displaying at the machines maximum possible
-- rate and soaking up 100% cpu.
--
-- We also keep track of the elapsed time since the start of the program,
-- so we can pass this to the user's animation function.
--
module Graphics.Gloss.Internals.Interface.Animate.Timing
( animateBegin
, animateEnd )
where
import Graphics.Gloss.Internals.Interface.Backend
import Graphics.Gloss.Internals.Interface.Animate.State
import Control.Monad
import Data.IORef
-- | Handles animation timing details.
-- Call this function at the start of each frame.
animateBegin :: IORef State -> DisplayCallback
animateBegin stateRef backendRef
= do
-- write the current time into the display state
displayTime <- elapsedTime backendRef
displayTimeLast <- stateRef `getsIORef` stateDisplayTime
let displayTimeElapsed = displayTime - displayTimeLast
stateRef `modifyIORef` \s -> s
{ stateDisplayTime = displayTime
, stateDisplayTimeLast = displayTimeLast }
-- increment the animation time
animate <- stateRef `getsIORef` stateAnimate
animateCount <- stateRef `getsIORef` stateAnimateCount
animateTime <- stateRef `getsIORef` stateAnimateTime
animateStart <- stateRef `getsIORef` stateAnimateStart
{- when (animateCount `mod` 5 == 0)
$ putStr $ " displayTime = " ++ show displayTime ++ "\n"
++ " displayTimeLast = " ++ show displayTimeLast ++ "\n"
++ " displayTimeElapsed = " ++ show displayTimeElapsed ++ "\n"
++ " fps = " ++ show (truncate $ 1 / displayTimeElapsed) ++ "\n"
-}
when (animate && not animateStart)
$ stateRef `modifyIORef` \s -> s
{ stateAnimateTime = animateTime + displayTimeElapsed }
when animate
$ stateRef `modifyIORef` \s -> s
{ stateAnimateCount = animateCount + 1
, stateAnimateStart = False }
-- | Handles animation timing details.
-- Call this function at the end of each frame.
animateEnd :: IORef State -> DisplayCallback
animateEnd stateRef backendRef
= do
-- timing gate, limits the maximum frame frequency (FPS)
timeClamp <- stateRef `getsIORef` stateDisplayTimeClamp
gateTimeStart <- elapsedTime backendRef -- the start of this gate
gateTimeEnd <- stateRef `getsIORef` stateGateTimeEnd -- end of the previous gate
let gateTimeElapsed = gateTimeStart - gateTimeEnd
when (gateTimeElapsed < timeClamp)
$ do sleep backendRef (timeClamp - gateTimeElapsed)
gateTimeFinal <- elapsedTime backendRef
stateRef `modifyIORef` \s -> s
{ stateGateTimeEnd = gateTimeFinal
, stateGateTimeElapsed = gateTimeElapsed }
getsIORef :: IORef a -> (a -> r) -> IO r
getsIORef ref fun
= liftM fun $ readIORef ref