packages feed

essence-of-live-coding-gloss 0.1.0.3 → 0.2.0.0

raw patch · 5 files changed

+114/−101 lines, 5 filesdep ~essence-of-live-codingdep ~foreign-storedep ~glossPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: essence-of-live-coding, foreign-store, gloss, syb, transformers

API changes (from Hackage documentation)

- LiveCoding.Gloss: glossWrap :: GlossCell -> IO (LiveProgram IO)
- LiveCoding.Gloss: initialWorld :: () => a1 -> (a1, [a2], Picture)
- LiveCoding.Gloss: playCell :: GlossCell -> IO (MVar GlossCell)
- LiveCoding.Gloss: playCellForeground :: GlossCell -> IO ()
- LiveCoding.Gloss: playStep :: Monoid c1 => p -> (Cell (WriterT c1 IO) a1 (), a1, c2) -> IO (Cell (WriterT c1 IO) a1 (), [a2], c1)
- LiveCoding.Gloss: playStepMVar :: Monoid c1 => p -> (MVar (Cell (WriterT c1 IO) a1 ()), a1, c2) -> IO (MVar (Cell (WriterT c1 IO) a1 ()), [a2], c1)
- LiveCoding.Gloss: toPicture :: () => (a, b1, b2) -> IO b2
- LiveCoding.Gloss: type GlossCellWorld = (MVar GlossCell, [Event], Picture)
- LiveCoding.Gloss: type GlossCellWorldForeground = (GlossCell, [Event], Picture)
- LiveCoding.Gloss: updateGloss :: MVar GlossCell -> GlossCell -> IO ()
- LiveCoding.Gloss.GHCi: livegloss :: Monad m => [Char] -> m String
- LiveCoding.Gloss.GHCi: livereloadgloss :: Monad m => [Char] -> m String
- LiveCoding.Gloss.GHCi: loadGloss :: IO (MVar GlossCell)
- LiveCoding.Gloss.GHCi: saveGloss :: MVar GlossCell -> IO ()
- LiveCoding.Gloss.PictureM: massageWriterOutput :: () => (((), b), a) -> (a, b)
- LiveCoding.Gloss.PictureM: runPictureM :: GlossCell -> Cell IO [Event] Picture
- LiveCoding.Gloss.PictureM: type GlossCell = Cell PictureM [Event] ()
+ LiveCoding.Gloss: GlossHandle :: ThreadId -> GlossVars -> GlossHandle
+ LiveCoding.Gloss: GlossSettings :: Display -> Color -> Int -> GlossSettings
+ LiveCoding.Gloss: GlossVars :: IORef [Event] -> IORef Picture -> MVar Float -> IORef Bool -> GlossVars
+ LiveCoding.Gloss: [backgroundColor] :: GlossSettings -> Color
+ LiveCoding.Gloss: [displaySetting] :: GlossSettings -> Display
+ LiveCoding.Gloss: [glossDTimeVar] :: GlossVars -> MVar Float
+ LiveCoding.Gloss: [glossEventsRef] :: GlossVars -> IORef [Event]
+ LiveCoding.Gloss: [glossExitRef] :: GlossVars -> IORef Bool
+ LiveCoding.Gloss: [glossPicRef] :: GlossVars -> IORef Picture
+ LiveCoding.Gloss: [glossThread] :: GlossHandle -> ThreadId
+ LiveCoding.Gloss: [glossVars] :: GlossHandle -> GlossVars
+ LiveCoding.Gloss: [stepsPerSecond] :: GlossSettings -> Int
+ LiveCoding.Gloss: data GlossHandle
+ LiveCoding.Gloss: data GlossSettings
+ LiveCoding.Gloss: data GlossVars
+ LiveCoding.Gloss: defaultSettings :: GlossSettings
+ LiveCoding.Gloss: getPicture :: GlossVars -> IO Picture
+ LiveCoding.Gloss: glossHandle :: GlossSettings -> Handle IO GlossHandle
+ LiveCoding.Gloss: glossWrapC :: GlossSettings -> Cell PictureM a b -> Cell (StateT (HandlingState IO) IO) a b
+ LiveCoding.Gloss: stepGloss :: Float -> GlossVars -> IO GlossVars
+ LiveCoding.Gloss.PictureM: runPictureT :: Monad m => Cell (PictureT m) a b -> Cell m ([Event], a) (Picture, b)
+ LiveCoding.Gloss.PictureM: type PictureT m = ReaderT [Event] (WriterT Picture m)
- LiveCoding.Gloss: handleEvent :: () => a1 -> (a2, [a1], c) -> IO (a2, [a1], c)
+ LiveCoding.Gloss: handleEvent :: Event -> GlossVars -> IO GlossVars
- LiveCoding.Gloss.PictureM: addPicture :: Cell PictureM Picture ()
+ LiveCoding.Gloss.PictureM: addPicture :: Monad m => Cell (PictureT m) Picture ()
- LiveCoding.Gloss.PictureM: type PictureM = WriterT Picture IO
+ LiveCoding.Gloss.PictureM: type PictureM = PictureT IO

Files

essence-of-live-coding-gloss.cabal view
@@ -1,5 +1,5 @@ name:                essence-of-live-coding-gloss-version:             0.1.0.3+version:             0.2.0.0 synopsis: General purpose live coding framework - Gloss backend description:   essence-of-live-coding is a general purpose and type safe live coding framework.@@ -38,14 +38,14 @@   exposed-modules:     LiveCoding.Gloss     LiveCoding.Gloss.Debugger-    LiveCoding.Gloss.GHCi     LiveCoding.Gloss.PictureM   build-depends:       base >= 4.11 && < 5-    , syb-    , transformers-    , essence-of-live-coding-    , foreign-store-    , gloss+    , syb >= 0.7+    , transformers >= 0.5+    , essence-of-live-coding >= 0.2.0.0+    , foreign-store >= 0.2+    , gloss >= 1.13   hs-source-dirs:      src   default-language:    Haskell2010+  default-extensions: StrictData
src/LiveCoding/Gloss.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE Arrows #-}  module LiveCoding.Gloss@@ -7,10 +9,14 @@  -- base import Control.Concurrent+import Control.Monad (when) import Data.IORef+import System.Exit (exitSuccess)  -- transformers+import Control.Arrow (returnA) import Control.Monad.Trans.Writer+import Control.Monad.Trans.State.Strict (StateT)  -- gloss import Graphics.Gloss as X@@ -23,64 +29,85 @@ import LiveCoding.Gloss.Debugger as X import LiveCoding.Gloss.PictureM as X -type GlossCellWorldForeground = (GlossCell, [Event], Picture)+-- | In a 'Handle', store a separate thread where the gloss main loop is executed,+--   and several concurrent variables to communicate with it.+data GlossHandle = GlossHandle+  { glossThread :: ThreadId+  , glossVars   :: GlossVars+  } -playCellForeground :: GlossCell -> IO ()-playCellForeground cell = playIO (InWindow "Gears" (600, 800) (20, 20)) black stepRate (initialWorld cell) toPicture handleEvent playStep+-- | The concurrent variables needed to communicate with the gloss thread.+data GlossVars = GlossVars+  { glossEventsRef :: IORef [Event]+    -- ^ Stores all 'Event's that arrived since the last tick+  , glossPicRef    :: IORef Picture+    -- ^ Stores the next 'Picture' to be painted+  , glossDTimeVar  :: MVar Float+    -- ^ Stores the time passed since the last tick+  , glossExitRef   :: IORef Bool+    -- ^ Write 'True' here to stop the gloss thread+  } -type GlossCellWorld = (MVar GlossCell, [Event], Picture)+-- | Collect all settings that the @gloss@ backend requires.+--   Taken from @rhine-gloss@.+data GlossSettings = GlossSettings+  { displaySetting  :: Display      -- ^ Display mode (e.g. 'InWindow' or 'FullScreen').+  , backgroundColor :: Color        -- ^ Background color.+  , stepsPerSecond  :: Int          -- ^ Number of simulation steps per second of real time.+  } --- TODO Abstract external main loops-playCell :: GlossCell -> IO (MVar GlossCell)-playCell glossCell = do-  var <- newMVar glossCell-  forkIO $ playIO (InWindow "Gears" (600, 800) (20, 20)) black stepRate (initialWorld var) toPicture handleEvent playStepMVar-  return var+defaultSettings :: GlossSettings+defaultSettings = GlossSettings+  { displaySetting  = InWindow "Essence of live coding" (600, 800) (20, 20)+  , backgroundColor = black+  , stepsPerSecond  = 30+  } --- TODO Of course these are general for cells-updateGloss :: MVar GlossCell -> GlossCell -> IO ()-updateGloss var newGlossCell = do-  oldGlossCell <- takeMVar var-  putMVar var $ hotCodeSwapCell newGlossCell oldGlossCell+-- | Will create a handle for communication with the gloss thread,+--   and start gloss.+glossHandle :: GlossSettings -> Handle IO GlossHandle+glossHandle GlossSettings { .. } = Handle+  { create = do+      glossEventsRef <- newIORef []+      glossDTimeVar <- newEmptyMVar+      glossPicRef <- newIORef blank+      glossExitRef <- newIORef False+      let glossVars = GlossVars { .. }+      glossThread <- forkIO+        $ playIO displaySetting backgroundColor stepsPerSecond glossVars getPicture handleEvent stepGloss+      return GlossHandle { .. }+  , destroy = \GlossHandle { glossVars = GlossVars { .. }, .. } -> writeIORef glossExitRef True+  } -initialWorld cell = (cell, [], blank)-toPicture (_, _, picture) = do-  --putStrLn "toPicture"-  threadDelay 10000-  return picture-handleEvent event (cell, events, picture) = do-  --putStrLn "handleEvent"-  threadDelay 10000-  return (cell, event : events, picture)-playStep _ (cell, events, _) = do-  (picture, cell') <- fmap massageWriterOutput $ runWriterT $ step cell events-  threadDelay 10000-  --putStrLn "playStep"-  return (cell', [], picture)-playStepMVar _ (var, events, _) = do-  cell <- takeMVar var-  (picture, cell') <- fmap massageWriterOutput $ runWriterT $ step cell events-  putMVar var cell'-  threadDelay 10000-  --putStrLn "playStepMVar"-  return (var, [], picture)+getPicture :: GlossVars -> IO Picture+getPicture GlossVars { .. } = readIORef glossPicRef -glossWrap :: GlossCell -> IO (LiveProgram IO)-glossWrap cell = do-  pictureVar <- newMVar blank-  eventRef <- newIORef []-  stepVar <- newMVar 0-  let-    getPicture () = takeMVar pictureVar-    putEvent event () = modifyIORef eventRef $ (event :)-    putStep _ () = putMVar stepVar $ 1 / stepRate-  forkIO $ playIO (InWindow "Gears" (600, 800) (20, 20)) black stepRate () getPicture putEvent putStep-  let-    putPicture = putMVar pictureVar-    getEvents = atomicModifyIORef eventRef $ \events -> ([], events)-    getStep = takeMVar stepVar-  return $ liveCell $ proc _ -> do-    _       <- constM getStep            -< ()-    events  <- constM getEvents          -< ()-    picture <- runPictureM cell -< events-    arrM putPicture                            -< picture+handleEvent :: Event -> GlossVars -> IO GlossVars+handleEvent event vars@GlossVars { .. } = do+  modifyIORef glossEventsRef (event :)+  return vars++stepGloss :: Float -> GlossVars -> IO GlossVars+stepGloss dTime vars@GlossVars { .. } = do+  threadDelay $ round $ dTime * 1000+  putMVar glossDTimeVar dTime+  exitNow <- readIORef glossExitRef+  when exitNow exitSuccess+  return vars++-- | Given a cell in the gloss monad 'PictureM',+--   start the gloss backend and connect the cell to it.+--   This introduces 'Handle's, which need to be taken care of by calling 'runHandlingState'+--   or a similar function.+glossWrapC :: GlossSettings -> Cell PictureM a b -> Cell (StateT (HandlingState IO) IO) a b+glossWrapC glossSettings cell = proc a -> do+  GlossHandle { .. } <- handling $ glossHandle glossSettings -< ()+  liftCell pump -< (glossVars, a)+  where+    pump = proc (GlossVars { .. }, a) -> do+      _      <- arrM takeMVar                        -< glossDTimeVar+      events <- arrM $ flip atomicModifyIORef ([], ) -< glossEventsRef+      (picture, b) <- runPictureT cell               -< (events, a)+      arrM (uncurry writeIORef)                      -< (glossPicRef, picture)+      arrM threadDelay                               -< 10000 -- TODO Tweak for better performance+      returnA                                        -< b
src/LiveCoding/Gloss/Debugger.hs view
@@ -8,7 +8,7 @@ -- transformers import Control.Monad.Trans.Writer import Control.Monad.Trans.Class-import Control.Monad.Trans.State+import Control.Monad.Trans.State.Strict  -- syb import Data.Generics.Text@@ -26,7 +26,7 @@ statePicture = translate (-100) 200 . scale 0.2 0.2 . color red . text . stateShow  statePlay :: Debugger PictureM-statePlay = Debugger $ liveCell $ every 2 >>> keep blank >>> arrM (lift . tell)+statePlay = Debugger $ liveCell $ every 2 >>> keep blank >>> arrM (lift . lift . tell)  every :: Data s => Integer -> Cell (StateT s PictureM) () (Maybe Picture) every maxN = proc () -> do
− src/LiveCoding/Gloss/GHCi.hs
@@ -1,29 +0,0 @@-module LiveCoding.Gloss.GHCi where---- base-import Control.Concurrent---- foreign-store-import Foreign.Store---- essence-of-live-coding-import LiveCoding.LiveProgram---- essence-of-live-coding-gloss-import LiveCoding.Gloss--livegloss "" = livegloss "glossCell"-livegloss glossCell = return $ unlines-  [ "var <- playCell " ++ glossCell-  , "saveGloss var"-  ]-livereloadgloss "" = livereloadgloss "glossCell"-livereloadgloss glossCell  = return $ unlines-  [ ":reload"-  , "var <- loadGloss"-  , "updateGloss var " ++ glossCell-  ]-loadGloss :: IO (MVar GlossCell)-loadGloss = readStore (Store 0)-saveGloss :: MVar GlossCell -> IO ()-saveGloss var = writeStore (Store 0) var
src/LiveCoding/Gloss/PictureM.hs view
@@ -1,6 +1,8 @@ module LiveCoding.Gloss.PictureM where  -- transformers+import Control.Monad.Trans.Class+import Control.Monad.Trans.Reader import Control.Monad.Trans.Writer  -- gloss@@ -10,15 +12,28 @@ -- essence-of-live-coding import LiveCoding -type PictureM = WriterT Picture IO+{- | The monad transformer that captures the effects of gloss,+which are reading events and writing pictures. -runPictureM :: GlossCell -> Cell IO [Event] Picture-runPictureM = transformOutput $ fmap massageWriterOutput . runWriterT+You can call these effects for example by... -massageWriterOutput (((), s), pic) = (pic, s)+* ...using 'ask' to read the events that occurred,+* ...composing a cell with 'addPicture' to paint a picture.+-}+type PictureT m = ReaderT [Event] (WriterT Picture m) --- TODO Rhine integration instead of fixed sample size-type GlossCell = Cell PictureM [Event] ()+-- | 'PictureT' specialised to the 'IO' monad.+type PictureM = PictureT IO -addPicture :: Cell PictureM Picture ()-addPicture = arrM tell+-- | Run the effects of the gloss monad stack by explicitly passing events and pictures.+runPictureT+  :: Monad m+  => Cell (PictureT m) a b+  -> Cell m ([Event], a) (Picture, b)+runPictureT = hoistCellOutput (fmap massageWriterOutput . runWriterT) . runReaderC'+  where+    massageWriterOutput :: ((b, s), pic) -> ((pic, b), s)+    massageWriterOutput ((b, s), pic) = ((pic, b), s)++addPicture :: Monad m => Cell (PictureT m) Picture ()+addPicture = arrM $ lift . tell