packages feed

rhine-gloss 0.9 → 1.0

raw patch · 6 files changed

+85/−82 lines, 6 filesdep +monad-scheduledep ~rhinePVP ok

version bump matches the API change (PVP)

Dependencies added: monad-schedule

Dependency ranges changed: rhine

API changes (from Hackage documentation)

- FRP.Rhine.Gloss.IO: glossConcurrently :: (Clock (GlossConcT IO) cl1, Clock (GlossConcT IO) cl2, Time cl1 ~ Time cl2) => Schedule (GlossConcT IO) cl1 cl2
- FRP.Rhine.Gloss.Pure: flowGlossWithWorldMSF :: Clock GlossM cl => GlossSettings -> cl -> MSF GlossM (Time cl, Tag cl) b -> IO ()
- FRP.Rhine.Gloss.Pure.Combined: flowGlossCombined :: GlossSettings -> GlossRhine a -> IO ()
- FRP.Rhine.Gloss.Pure.Combined: glossSchedule :: Schedule GlossM (GlossEventClock a) GlossSimulationClock
+ FRP.Rhine.Gloss.IO: instance (GHC.Base.Monad m, Control.Monad.Schedule.Class.MonadSchedule m) => Control.Monad.Schedule.Class.MonadSchedule (FRP.Rhine.Gloss.IO.GlossConcT m)
+ FRP.Rhine.Gloss.IO: launchInGlossThread :: MonadIO m => GlossSettings -> GlossConcT m a -> m a
+ FRP.Rhine.Gloss.IO: runGlossEnvClock :: GlossEnv -> cl -> RunGlossEnvClock m cl
+ FRP.Rhine.Gloss.IO: type RunGlossEnvClock m cl = HoistClock (GlossConcT m) m cl
+ FRP.Rhine.Gloss.Pure: flowGlossClSF :: GlossSettings -> GlossClSF -> IO ()
+ FRP.Rhine.Gloss.Pure: instance Control.Monad.Schedule.Class.MonadSchedule FRP.Rhine.Gloss.Pure.GlossM
- FRP.Rhine.Gloss.IO: launchGlossThread :: MonadIO m => GlossSettings -> GlossConcT m a -> m a
+ FRP.Rhine.Gloss.IO: launchGlossThread :: MonadIO m => GlossSettings -> m GlossEnv
- FRP.Rhine.Gloss.Pure: flowGloss :: GlossSettings -> GlossClSF -> IO ()
+ FRP.Rhine.Gloss.Pure: flowGloss :: (Clock GlossM cl, GetClockProxy cl) => GlossSettings -> Rhine GlossM cl () () -> IO ()
- FRP.Rhine.Gloss.Pure.Combined: type GlossCombinedClock a = SequentialClock GlossM (GlossEventClock a) GlossSimulationClock
+ FRP.Rhine.Gloss.Pure.Combined: type GlossCombinedClock a = SequentialClock (GlossEventClock a) GlossSimulationClock

Files

ChangeLog.md view
@@ -1,5 +1,10 @@ # Revision history for rhine-gloss +## 1.0++* Removed schedules. See the [page about changes in version 1](/version1.md).+* Simplified `gloss` backends. Renamed `launchGlossThread` to `launchInGlossThread`.+ ## 0.7.0  * Reworked `gloss` backends.
Main.hs view
@@ -28,8 +28,8 @@   putStrLn "Please choose between the pure (1), the pure combined (2), and the IO backend (3):"   n <- readLn   case n of-    1 -> flowGloss defaultSettings pureClSF-    2 -> flowGlossCombined defaultSettings pureRhine+    1 -> flowGlossClSF defaultSettings pureClSF+    2 -> flowGloss defaultSettings pureRhine     3 -> flowGlossIO defaultSettings ioRhine     _ -> error "Invalid input" @@ -39,7 +39,7 @@ {- | Run the gears simulation with the pure backend with two subsystems,    one at the rate of events, one at the rate of simulation. -}-pureRhine = tagS @@ glossEventClock >-- collect -@- glossSchedule --> sim >-> arrMCl paintAll @@ glossSimulationClock+pureRhine = tagS @@ glossEventClock >-- collect --> sim >-> arrMCl paintAll @@ glossSimulationClock  -- | Run the gears simulation with the 'IO' backend.-ioRhine = tagS @@ GlossEventClockIO >-- collect -@- glossConcurrently --> sim >-> arrMCl paintAllIO @@ GlossSimClockIO+ioRhine = tagS @@ GlossEventClockIO >-- collect --> sim >-> arrMCl paintAllIO @@ GlossSimClockIO
rhine-gloss.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/  name:                rhine-gloss-version:             0.9+version:             1.0 synopsis:            Gloss backend for Rhine description:   This package provides a simple wrapper for the `gloss` library,@@ -26,7 +26,7 @@ source-repository this   type:     git   location: https://github.com/turion/rhine.git-  tag:      v0.9+  tag:      v1.0   library@@ -38,10 +38,11 @@     FRP.Rhine.Gloss.Pure.Combined   build-depends:       base         >= 4.14 && < 4.18                      , transformers >= 0.5-                     , rhine        == 0.9+                     , rhine        == 1.0                      , dunai        ^>= 0.9                      , gloss        >= 1.12                      , mmorph       >= 1.1+                     , monad-schedule >= 0.1   hs-source-dirs:      src   default-language:    Haskell2010   default-extensions:
src/FRP/Rhine/Gloss/IO.hs view
@@ -14,9 +14,11 @@   paintAllIO,   GlossEventClockIO (..),   GlossSimClockIO (..),+  launchInGlossThread,   launchGlossThread,   flowGlossIO,-  glossConcurrently,+  runGlossEnvClock,+  RunGlossEnvClock, ) where @@ -35,6 +37,9 @@ -- gloss import Graphics.Gloss.Interface.IO.Game +-- monad-schedule+import Control.Monad.Schedule.Class+ -- rhine import FRP.Rhine @@ -55,6 +60,9 @@   {unGlossConcT :: ReaderT GlossEnv m a}   deriving (Functor, Applicative, Monad, MonadTrans, MonadIO, MFunctor, MMonad) +instance (Monad m, MonadSchedule m) => MonadSchedule (GlossConcT m) where+  schedule actions = GlossConcT $ fmap (second $ map GlossConcT) $ schedule $ unGlossConcT <$> actions+ withPicRef ::   MonadIO m =>   (IORef Picture -> IO a) ->@@ -121,9 +129,8 @@ launchGlossThread ::   MonadIO m =>   GlossSettings ->-  GlossConcT m a ->-  m a-launchGlossThread GlossSettings {..} glossLoop = do+  m GlossEnv+launchGlossThread GlossSettings {..} = do   vars <- liftIO $ GlossEnv <$> newEmptyMVar <*> newEmptyMVar <*> newIORef Blank <*> pure 0   let     getPic GlossEnv {picRef} = readIORef picRef@@ -136,6 +143,24 @@       void $ tryPutMVar timeVar time'       return vars {time = time'}   void $ liftIO $ forkIO $ playIO display backgroundColor stepsPerSecond vars getPic handleEvent simStep+  return vars++{- | Apply this to supply the 'GlossConcT' effect.+   Creates a new thread in which @gloss@ is run,+   and feeds the clocks 'GlossEventClockIO' and 'GlossSimClockIO'.++   Usually, this function is applied to the result of 'flow',+   so you can handle all occurring effects as needed.+   If you only use @gloss@ in your whole signal network,+   you can use 'flowGlossIO' instead.+-}+launchInGlossThread ::+  MonadIO m =>+  GlossSettings ->+  GlossConcT m a ->+  m a+launchInGlossThread settings glossLoop = do+  vars <- launchGlossThread settings   runReaderT (unGlossConcT glossLoop) vars  {- | Run a 'Rhine' in the 'GlossConcT' monad by launching a separate thread for the @gloss@ backend,@@ -151,37 +176,23 @@   GlossSettings ->   Rhine (GlossConcT m) cl () () ->   m ()-flowGlossIO settings = launchGlossThread settings . flow+flowGlossIO settings = launchInGlossThread settings . flow -{- | A schedule in the 'GlossConcT' transformer,-   supplying the same backend connection to its scheduled clocks.+{- | Apply this wrapper to your clock type @cl@ in order to escape the 'GlossConcT' transformer.+  The resulting clock will be in @m@, not 'GlossConcT m' anymore.+  Typically, @m@ will have the 'MonadIO' constraint. -}-glossConcurrently ::-  ( Clock (GlossConcT IO) cl1-  , Clock (GlossConcT IO) cl2-  , Time cl1 ~ Time cl2-  ) =>-  Schedule (GlossConcT IO) cl1 cl2-glossConcurrently = Schedule $-  \cl1 cl2 -> GlossConcT $-    ReaderT $-      \vars ->-        first liftTransS-          <$> initSchedule-            concurrently-            (runGlossEnvClock vars cl1)-            (runGlossEnvClock vars cl2)--type RunGlossEnvClock cl = HoistClock (GlossConcT IO) IO cl+type RunGlossEnvClock m cl = HoistClock (GlossConcT m) m cl +{- | Apply to a gloss clock to remove a 'GlossConcT' layer.+  You will have to have initialized a 'GlossEnv', for example by calling 'launchGlossThread'.+-} runGlossEnvClock ::   GlossEnv ->   cl ->-  RunGlossEnvClock cl+  RunGlossEnvClock m cl runGlossEnvClock env unhoistedClock =   HoistClock     { monadMorphism = flip runReaderT env . unGlossConcT     , ..     }---- FIXME And a schedule for gloss clocks and other clocks
src/FRP/Rhine/Gloss/Pure.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE Arrows #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-}@@ -19,39 +18,47 @@   GlossClSF,   currentEvent,   flowGloss,-  flowGlossWithWorldMSF,+  flowGlossClSF, ) where  -- base import qualified Control.Category as Category+import Data.Functor.Identity  -- transformers import Control.Monad.Trans.Class import Control.Monad.Trans.Reader-import Control.Monad.Trans.Writer+import Control.Monad.Trans.Writer.Strict  -- dunai+import Control.Monad.Trans.MSF (performOnFirstSample) import qualified Control.Monad.Trans.MSF.Reader as MSFReader+import qualified Control.Monad.Trans.MSF.Writer as MSFWriter import Data.MonadicStreamFunction.InternalCore +-- monad-schedule+import Control.Monad.Schedule.Class+import Control.Monad.Schedule.Yield+ -- rhine import FRP.Rhine-import FRP.Rhine.Reactimation.ClockErasure  -- rhine-gloss import FRP.Rhine.Gloss.Common  -- * @gloss@ effects --- FIXME How about a Reader (MSF () (Either Float Event))? That might unify the two backends and make the pure one more flexible.- -- | A pure monad in which all effects caused by the @gloss@ backend take place.-newtype GlossM a = GlossM {unGlossM :: (ReaderT (Float, Maybe Event)) (Writer Picture) a}+newtype GlossM a = GlossM {unGlossM :: YieldT (ReaderT (Float, Maybe Event) (Writer Picture)) a}   deriving (Functor, Applicative, Monad) +-- Would have liked to make this a derived instance, but for some reason deriving gets thrown off by the newtype+instance MonadSchedule GlossM where+  schedule actions = fmap (fmap (fmap GlossM)) $ GlossM $ schedule $ fmap unGlossM actions+ -- | Add a picture to the canvas. paint :: Picture -> GlossM ()-paint = GlossM . lift . tell+paint = GlossM . lift . lift . tell  -- FIXME This doesn't what you think it does @@ -76,7 +83,7 @@ instance Clock GlossM GlossClock where   type Time GlossClock = Float   type Tag GlossClock = Maybe Event-  initClock _ = return (constM (GlossM ask) >>> (sumS *** Category.id), 0)+  initClock _ = return (constM (GlossM $ yield >> lift ask) >>> (sumS *** Category.id), 0)  instance GetClockProxy GlossClock @@ -99,29 +106,29 @@  -- * Reactimation -{- | The main function that will start the @gloss@ backend and run the 'SN'-   (in the case of the combined clock).--}-flowGloss ::+-- | Specialisation of 'flowGloss' to a 'GlossClSF'+flowGlossClSF ::   GlossSettings ->-  -- | The @gloss@-compatible 'Rhine'.+  -- | The @gloss@-compatible 'ClSF'.   GlossClSF ->   IO ()-flowGloss settings clsf = flowGlossWithWorldMSF settings GlossClock $ proc (time, tag) -> do-  arrM (const clear) -< ()-  pic <- eraseClockClSF getClockProxy 0 clsf -< (time, tag, ())-  arrM paint -< pic+flowGlossClSF settings clsf = flowGloss settings $ clsf >-> arrMCl paintAll @@ GlossClock --- FIXME Hide?+type WorldMSF = MSF Identity ((Float, Maybe Event), ()) (Picture, Maybe ()) --- | Helper function-flowGlossWithWorldMSF GlossSettings {..} clock msf =+-- | The main function that will start the @gloss@ backend and run the 'Rhine'+flowGloss ::+  (Clock GlossM cl, GetClockProxy cl) =>+  GlossSettings ->+  Rhine GlossM cl () () ->+  IO ()+flowGloss GlossSettings {..} rhine =   play display backgroundColor stepsPerSecond (worldMSF, Blank) getPic handleEvent simStep   where-    worldMSF = MSFReader.runReaderS $ morphS unGlossM $ proc () -> do-      (time, tag) <- fst $ fst $ runWriter $ flip runReaderT (0, Nothing) $ unGlossM $ initClock clock -< ()-      msf -< (time, tag)+    worldMSF :: WorldMSF+    worldMSF = MSFWriter.runWriterS $ MSFReader.runReaderS $ morphS (runYieldT . unGlossM) $ performOnFirstSample $ eraseClock rhine+    stepWith :: (Float, Maybe Event) -> (WorldMSF, Picture) -> (WorldMSF, Picture)+    stepWith (diff, eventMaybe) (msf, _) = let ((picture, _), msf') = runIdentity $ unMSF msf ((diff, eventMaybe), ()) in (msf', picture)     getPic (_, pic) = pic-    stepWith (diff, maybeEvent) (msf, _) = first snd $ runWriter $ unMSF msf ((diff, maybeEvent), ())     handleEvent event = stepWith (0, Just event)     simStep diff = stepWith (diff, Nothing)
src/FRP/Rhine/Gloss/Pure/Combined.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE Arrows #-} {-# LANGUAGE RecordWildCards #-}  {- | A pure @gloss@ backend for Rhine,@@ -12,7 +11,6 @@  -- rhine import FRP.Rhine-import FRP.Rhine.Reactimation.ClockErasure  -- rhine-gloss import FRP.Rhine.Gloss.Common@@ -24,14 +22,9 @@ -} type GlossCombinedClock a =   SequentialClock-    GlossM     (GlossEventClock a)     GlossSimulationClock --- | Schedule the subclocks of the 'GlossCombinedClock'.-glossSchedule :: Schedule GlossM (GlossEventClock a) GlossSimulationClock-glossSchedule = schedSelectClocks- -- ** Events  -- | The clock that ticks whenever a specific @gloss@ event occurs.@@ -92,7 +85,7 @@  myGlossRhine :: GlossRhine a myGlossRhine-  = myEventSubsystem @@ myEventClock >-- collect -@- glossSchedule --> mySim @@ glossSimulationClock+  = myEventSubsystem @@ myEventClock >-- collect --> mySim @@ glossSimulationClock @ -} type GlossRhine a = Rhine GlossM (GlossCombinedClock a) () ()@@ -110,19 +103,5 @@   GlossRhine a buildGlossRhine selector clsfSim =   timeInfoOf tag @@ glossEventSelectClock selector-    >-- collect -@- glossSchedule+    >-- collect     --> clsfSim @@ glossSimulationClock---- * Reactimation---- | The main function that will start the @gloss@ backend and run the 'SN'.-flowGlossCombined ::-  GlossSettings ->-  -- | The @gloss@-compatible 'Rhine'.-  GlossRhine a ->-  IO ()-flowGlossCombined settings Rhine {..} = flowGlossWithWorldMSF settings clock $ proc tick -> do-  eraseClockSN 0 sn-    -< case tick of-      (_, Left event) -> (0, Left event, Just ())-      (diffTime, Right ()) -> (diffTime, Right (), Nothing)