    {-# 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
            Double
    displayTime             <- IORef a -> IO Double
    forall a. Backend a => IORef a -> IO Double
    elapsedTime IORef a
    backendRef
            Double
    displayTimeLast         <- IORef State
    stateRef IORef State -> (State -> Double) -> IO Double
    forall a r. IORef a -> (a -> r) -> IO r
    `getsIORef` State -> Double
    stateDisplayTime
            let displayTimeElapsed :: Double
    displayTimeElapsed  = Double
    displayTime Double -> Double -> Double
    forall a. Num a => a -> a -> a
    - Double
    displayTimeLast

            IORef State -> (State -> State) -> IO ()
    forall a. IORef a -> (a -> a) -> IO ()
    modifyIORef' IORef State
    stateRef ((State -> State) -> IO ()) -> (State -> State) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \State
    s -> State
    s
                    { stateDisplayTime :: Double
    stateDisplayTime      = Double
    displayTime
                    , stateDisplayTimeLast :: Double
    stateDisplayTimeLast  = Double
    displayTimeLast }

            -- increment the animation time
            Bool
    animate        <- IORef State
    stateRef IORef State -> (State -> Bool) -> IO Bool
    forall a r. IORef a -> (a -> r) -> IO r
    `getsIORef` State -> Bool
    stateAnimate
            Integer
    animateCount   <- IORef State
    stateRef IORef State -> (State -> Integer) -> IO Integer
    forall a r. IORef a -> (a -> r) -> IO r
    `getsIORef` State -> Integer
    stateAnimateCount
            Double
    animateTime    <- IORef State
    stateRef IORef State -> (State -> Double) -> IO Double
    forall a r. IORef a -> (a -> r) -> IO r
    `getsIORef` State -> Double
    stateAnimateTime
            Bool
    animateStart   <- IORef State
    stateRef IORef State -> (State -> Bool) -> IO Bool
    forall a r. IORef a -> (a -> r) -> IO r
    `getsIORef` State -> Bool
    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"
    -}
            Bool -> IO () -> IO ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    when (Bool
    animate Bool -> Bool -> Bool
    && Bool -> Bool
    not Bool
    animateStart)
             (IO () -> IO ()) -> IO () -> IO ()
    forall a b. (a -> b) -> a -> b
    $ IORef State -> (State -> State) -> IO ()
    forall a. IORef a -> (a -> a) -> IO ()
    modifyIORef' IORef State
    stateRef ((State -> State) -> IO ()) -> (State -> State) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \State
    s -> State
    s
                   { stateAnimateTime :: Double
    stateAnimateTime       = Double
    animateTime Double -> Double -> Double
    forall a. Num a => a -> a -> a
    + Double
    displayTimeElapsed }

            Bool -> IO () -> IO ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    when Bool
    animate
             (IO () -> IO ()) -> IO () -> IO ()
    forall a b. (a -> b) -> a -> b
    $ IORef State -> (State -> State) -> IO ()
    forall a. IORef a -> (a -> a) -> IO ()
    modifyIORef' IORef State
    stateRef ((State -> State) -> IO ()) -> (State -> State) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \State
    s -> State
    s
                   { stateAnimateCount :: Integer
    stateAnimateCount      = Integer
    animateCount Integer -> Integer -> Integer
    forall a. Num a => a -> a -> a
    + Integer
    1
                   , stateAnimateStart :: Bool
    stateAnimateStart      = Bool
    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)
            Double
    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
            Double
    gateTimeStart   <- IORef a -> IO Double
    forall a. Backend a => IORef a -> IO Double
    elapsedTime IORef a
    backendRef

            -- end of the previous gate
            Double
    gateTimeEnd     <- IORef State
    stateRef IORef State -> (State -> Double) -> IO Double
    forall a r. IORef a -> (a -> r) -> IO r
    `getsIORef` State -> Double
    stateGateTimeEnd
            let gateTimeElapsed :: Double
    gateTimeElapsed = Double
    gateTimeStart Double -> Double -> Double
    forall a. Num a => a -> a -> a
    - Double
    gateTimeEnd

            Bool -> IO () -> IO ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    when (Double
    gateTimeElapsed Double -> Double -> Bool
    forall a. Ord a => a -> a -> Bool
    < Double
    timeClamp)
             (IO () -> IO ()) -> IO () -> IO ()
    forall a b. (a -> b) -> a -> b
    $ do   IORef a -> Double -> IO ()
    forall a. Backend a => IORef a -> Double -> IO ()
    sleep IORef a
    backendRef (Double
    timeClamp Double -> Double -> Double
    forall a. Num a => a -> a -> a
    - Double
    gateTimeElapsed)

            Double
    gateTimeFinal   <- IORef a -> IO Double
    forall a. Backend a => IORef a -> IO Double
    elapsedTime IORef a
    backendRef

            IORef State -> (State -> State) -> IO ()
    forall a. IORef a -> (a -> a) -> IO ()
    modifyIORef' IORef State
    stateRef ((State -> State) -> IO ()) -> (State -> State) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \State
    s -> State
    s
                    { stateGateTimeEnd :: Double
    stateGateTimeEnd      = Double
    gateTimeFinal
                    , stateGateTimeElapsed :: Double
    stateGateTimeElapsed  = Double
    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