    {-# 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 :: IORef State -> DisplayCallback
    animateBegin IORef State
    stateRef IORef a
    backendRef
     = do
            -- write the current time into the display state
            displayTime             <- IORef a -> IO Double
    forall a. Backend a => IORef a -> IO Double
    elapsedTime IORef a
    backendRef
            displayTimeLast         <- stateRef `getsIORef` stateDisplayTime
            let displayTimeElapsed  = Double
    displayTime Double -> Double -> Double
    forall a. Num a => a -> a -> a
    - Double
    displayTimeLast

            modifyIORef' stateRef $ \State
    s -> State
    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)
             $ modifyIORef' stateRef $ \State
    s -> State
    s
                   { stateAnimateTime       = animateTime + displayTimeElapsed }

            when animate
             $ modifyIORef' stateRef $ \State
    s -> State
    s
                   { stateAnimateCount      = animateCount + 1
                   , stateAnimateStart      = False  }

    -- | Handles animation timing details.
    --      Call this function at the end of each frame.
    animateEnd :: IORef State -> DisplayCallback
    animateEnd :: IORef State -> DisplayCallback
    animateEnd IORef State
    stateRef IORef a
    backendRef
     = do
            -- timing gate, limits the maximum frame frequency (FPS)
            timeClamp       <- IORef State
    stateRef IORef State -> (State -> Double) -> IO Double
    forall a r. IORef a -> (a -> r) -> IO r
    `getsIORef` State -> Double
    stateDisplayTimeClamp

            -- the start of this gate
            gateTimeStart   <- elapsedTime backendRef

            -- end of the previous gate
            gateTimeEnd     <- stateRef `getsIORef` stateGateTimeEnd
            let gateTimeElapsed = Double
    gateTimeStart Double -> Double -> Double
    forall a. Num a => a -> a -> a
    - Double
    gateTimeEnd

            when (gateTimeElapsed < timeClamp)
             $ do   sleep backendRef (timeClamp - gateTimeElapsed)

            gateTimeFinal   <- elapsedTime backendRef

            modifyIORef' stateRef $ \State
    s -> State
    s
                    { stateGateTimeEnd      = gateTimeFinal
                    , stateGateTimeElapsed  = gateTimeElapsed }

    getsIORef :: IORef a -> (a -> r) -> IO r
    getsIORef :: forall a r. IORef a -> (a -> r) -> IO r
    getsIORef IORef a
    ref a -> r
    fun
     = (a -> r) -> IO a -> IO r
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
    liftM a -> r
    fun (IO a -> IO r) -> IO a -> IO r
    forall a b. (a -> b) -> a -> b
    $ IORef a -> IO a
    forall a. IORef a -> IO a
    readIORef IORef a
    ref