packages feed

rhine-gloss (empty) → 0.3.0.0

raw patch · 7 files changed

+276/−0 lines, 7 filesdep +basedep +dunaidep +glosssetup-changed

Dependencies added: base, dunai, gloss, rhine, rhine-gloss

Files

+ ChangeLog.md view
@@ -0,0 +1,9 @@+# Revision history for rhine-gloss++## 0.2.0.0  -- 2017-11-29++* First version. Version numbers follow rhine.++## 0.3.0.0  -- 2017-11-30++* Added simple example.
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2017, Manuel Bärenz++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Manuel Bärenz nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Main.hs view
@@ -0,0 +1,20 @@+{- | Example application for the @gloss@ wrapper. -}+++-- rhine-gloss+import FRP.Rhine.Gloss+++-- | Calculate a gear wheel rotated by a certain angle.+gears :: Float -> Picture+gears angle = color green $ pictures+  $ circleSolid 60+  : map (rotate angle) [ rotate (45 * n) $ rectangleSolid 20 150 | n <- [0..3] ]++-- | Rotate the gear with a constant angular velocity.+mainSyncSF :: GlossSyncSF a+mainSyncSF = timeInfoOf sinceStart >>> arr (* 50) >>> arr gears++main :: IO ()+main = flowGloss (InWindow "sonnen" (400, 400) (10, 10)) (greyN 0.3) 30+     $ buildGlossRhine Just mainSyncSF
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ rhine-gloss.cabal view
@@ -0,0 +1,34 @@+-- Initial rhine-gloss.cabal generated by cabal init.  For further+-- documentation, see http://haskell.org/cabal/users-guide/++name:                rhine-gloss+version:             0.3.0.0+-- synopsis:+description:         Wrapper to run reactive programs written in Rhine+                     with Gloss as backend+license:             BSD3+license-file:        LICENSE+author:              Manuel Bärenz+maintainer:          programming@manuelbaerenz.de+-- copyright:+category:            FRP+build-type:          Simple+extra-source-files:  ChangeLog.md+cabal-version:       >=1.18++library+  exposed-modules:     FRP.Rhine.Gloss+  other-modules:       FRP.Rhine.Gloss.Internals+  build-depends:       base  >= 4.7    && < 5+                     , rhine == 0.3.*+                     , dunai == 0.3.*+                     , gloss == 1.11.*+  hs-source-dirs:      src+  default-language:    Haskell2010++executable rhine-gloss-gears+  main-is:             Main.hs+  ghc-options:         -threaded+  build-depends:       base        >= 4.7    && < 5+                     , rhine-gloss+  default-language:    Haskell2010
+ src/FRP/Rhine/Gloss.hs view
@@ -0,0 +1,92 @@+{- | Wrapper library to write Gloss applications in Rhine.+@gloss@ acts as the backend here.++A Rhine app with the Gloss backend must use the 'GlossClock',+since the @gloss@ API only offers callbacks.+In order to run such a reactive program, you have to use 'flowGloss'.+-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE NamedFieldPuns   #-}+{-# LANGUAGE RecordWildCards  #-}+{-# LANGUAGE TypeFamilies     #-}+module FRP.Rhine.Gloss+  ( module FRP.Rhine.Gloss+  , module X+  )+  where++-- base+import Data.Functor.Identity (Identity, runIdentity)++import qualified Control.Arrow as X++-- gloss+import Graphics.Gloss.Interface.Pure.Game++import qualified Graphics.Gloss as X++-- rhine+import FRP.Rhine+import FRP.Rhine.Clock.Select+import FRP.Rhine.Reactimation.Tick+import FRP.Rhine.ResamplingBuffer.Collect+import FRP.Rhine.ResamplingBuffer.KeepLast++import qualified FRP.Rhine        as X+import qualified FRP.Rhine.SyncSF as X++-- rhine-gloss+import FRP.Rhine.Gloss.Internals++-- TODO Consider generalising to IO+++-- | The overall clock of a valid @rhine@ 'SF' that can be run by @gloss@.+--   @a@ is the type of subevents that are selected.+type GlossClock a+  = SequentialClock Identity+      (SelectClock GlossEventClock a)+      GlossSimulationClock_++-- | The type of a valid 'Rhine' that can be run by @gloss@.+--   @a@ is the type of subevents that are selected.+type GlossRhine a = Rhine Identity (GlossClock a) () Picture++-- | The type of a 'SyncSF' that you have to implement to get a @gloss@ app.+type GlossSyncSF a = SyncSF Identity GlossSimulationClock [a] Picture++{- | For most applications, it is sufficient to implement+a single synchronous signal function+that is called with a list of all relevant events+that occurred in the last tick.+-}+buildGlossRhine+  :: (Event -> Maybe a) -- ^ The event selector+  -> GlossSyncSF a      -- ^ The 'SyncSF' representing the game loop.+  -> GlossRhine a+buildGlossRhine select syncsfSim+  =   timeInfoOf tag @@  SelectClock { mainClock = GlossEventClock, .. }+  >-- collect -@- glossSchedule+  --> withProperSimClock syncsfSim @@ GlossSimulationClock_++-- | The main function that will start the @gloss@ backend and run the 'SF'.+flowGloss+  :: Display      -- ^ Display mode (e.g. 'InWindow' or 'FullScreen').+  -> Color        -- ^ Background color.+  -> Int          -- ^ Number of simulation steps per second of real time.+  -> GlossRhine a -- ^ The @gloss@-compatible 'Rhine'.+  -> IO ()+flowGloss display color n Rhine {..}+  = play display color n world getPic handleEvent simStep+  where+    graphicsBuffer+      :: ResamplingBuffer Identity+           GlossSimulationClock_ GlossGraphicsClock+           Picture               Picture+    graphicsBuffer = keepLast Blank+    world = createTickable (trivialResamplingBuffer clock) sf graphicsBuffer ()+    getPic Tickable { buffer2 } = fst $ runIdentity $ get buffer2 $ TimeInfo () () () ()+    handleEvent event tickable = case select (sequentialCl1 clock) event of+      Just a  -> runIdentity $ tick tickable () $ Left a -- Event is relevant+      Nothing -> tickable -- Event is irrelevant, state doesn't change+    simStep diff tickable = runIdentity $ tick tickable () $ Right diff
+ src/FRP/Rhine/Gloss/Internals.hs view
@@ -0,0 +1,89 @@+{- | Internals for 'FRP.Rhine.Gloss'.+You probably won't need this module.+-}+{-# LANGUAGE Arrows                #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE NamedFieldPuns        #-}+{-# LANGUAGE RecordWildCards       #-}+{-# LANGUAGE TypeFamilies          #-}++module FRP.Rhine.Gloss.Internals where++-- base+import qualified Control.Category as Category+import Data.Functor.Identity (Identity)++-- dunai+import Control.Monad.Trans.MSF.Reader (readerS, runReaderS)++-- gloss+import Graphics.Gloss.Interface.Pure.Game++-- rhine+import FRP.Rhine+import FRP.Rhine.Clock.Select+++-- * Clocks++-- | The error message that gets thrown when you try to start a @gloss@ app with 'flow'.+errMsg :: String+errMsg =  "You cannot start gloss apps with FRP.Rhine.flow. "+       ++ "Use FRP.Rhine.Gloss.flowGloss instead."++-- | The clock that ticks whenever a @gloss@ event occurs.+data GlossEventClock = GlossEventClock++instance Clock m GlossEventClock where+  type TimeDomainOf GlossEventClock = ()+  type Tag          GlossEventClock = Event+  startClock _ = error errMsg++-- | The clock that ticks for every @gloss@ simulation step,+--   but only shows the time delta in the tag.+--   Usually, you don't need this clock, but rather 'GlossSimulationClock'.+data GlossSimulationClock_ = GlossSimulationClock_++instance Clock m GlossSimulationClock_ where+  type TimeDomainOf GlossSimulationClock_ = ()+  type Tag          GlossSimulationClock_ = Float+  startClock _ = error errMsg++-- | The clock that ticks for every @gloss@ simulation step.+--   Use 'withProperSimClock' to transform to 'GlossSimulationClock_'.+data GlossSimulationClock = GlossSimulationClock++instance Clock m GlossSimulationClock where+  type TimeDomainOf GlossSimulationClock = Float+  type Tag          GlossSimulationClock = ()+  startClock _ = error errMsg++-- | To use all features of the 'SyncSF' framework,+--   write your synchronous stream function on the 'GlossSimulationClock'+--   and then use this function to transform it.+withProperSimClock+  :: Monad m+  => SyncSF m GlossSimulationClock  a b+  -> SyncSF m GlossSimulationClock_ a b+withProperSimClock syncsf = readerS+  $ (intermingle *** Category.id) >>> runReaderS syncsf+  where+    intermingle :: Monad m => MSF m (TimeInfo GlossSimulationClock_) (TimeInfo GlossSimulationClock)+    intermingle = proc TimeInfo {tag} -> do+      let sinceTick = tag+      absolute <- sumS -< sinceTick+      let sinceStart = absolute+      returnA          -< TimeInfo { tag = (), .. }++-- | The clock that ticks for every @gloss@ graphics output.+data GlossGraphicsClock = GlossGraphicsClock++instance Clock m GlossGraphicsClock where+  type TimeDomainOf GlossGraphicsClock = ()+  type Tag          GlossGraphicsClock = ()+  startClock _ = error errMsg++-- | A schedule you can't actually use, for internal purposes.+glossSchedule :: Schedule Identity (SelectClock GlossEventClock a) GlossSimulationClock_+glossSchedule = error errMsg