ivanperez-keera/yampa-gloss

Reproducing animatons at varying speeds

ivanperez-keera opened this issue · 0 comments

One case I had at some point is that I had to adjust the running speed of an animation.

There are many ways of doing this, one of which is described in the paper Back to the Future: Time Travel in FRP.

An alternative way is the following variation of the main module in this package:

module Graphics.Gloss.Interface.FRP.Yampa
    (playYampa, InputEvent)
  where

import           Control.Monad                    (when, replicateM_)
import           Data.IORef                       (newIORef, readIORef,
                                                   writeIORef)
import           FRP.Yampa                        (Event (..), SF, react,
                                                   reactInit)
import           FRP.Yampa.InternalCore
import           Graphics.Gloss                   (Color, Display, Picture,
                                                   blank)
import qualified Graphics.Gloss
import           Graphics.Gloss.Interface.IO.Game (playIO)
import qualified Graphics.Gloss.Interface.IO.Game as G

type InputEvent = G.Event

-- | Play the game in a window, updating when the value of the provided
playYampa :: Display -- ^ The display method
          -> Color   -- ^ The background color
          -> Int     -- ^ The refresh rate, in Hertz
          -> Int     -- ^ The render to simulation ratio (no unit)
          -> Double  -- ^ The simulation frequency, in Hertz
          -> SF (Event InputEvent) Picture
          -> IO ()
playYampa display color frequencyR ratio frequencyS mainSF = do
  let (sf', p1) = sfTF mainSF NoEvent
  sfR    <- newIORef sf'
  picRef <- newIORef p1

  let delta = 1 / frequencyS

      -- An action to convert the world to a picture
      toPic = (const $ readIORef picRef)

      -- A function to handle input events
      handleInput = (\e t -> stepWorld delta t)
        -- react handle (delta, Just (Event e)) >> return (t + delta))

      -- A function to step the world one  iteration. It is passed the period
      -- of time (in seconds) needing to be  advanced
      stepWorld d t = do
        replicateM_ ratio $ do
          sf' <- readIORef sfR
          let (sf'', b) = sfTF' sf' delta NoEvent
          b `seq` writeIORef picRef b
          writeIORef sfR sf''
        return (t + fromIntegral ratio * delta)

  playIO display color frequencyR 0 toPic handleInput stepWorld

The only issue I see is the need for Yampa's InternalCore, but, otherwise, having this variation was useful. It would be nice to either integrate it or provide an alternative implementation based on that paper.