packages feed

spice 0.3.0.0 → 0.3.2.0

raw patch · 26 files changed

+1040/−962 lines, 26 filesdep +spicedep ~data-defaultsetup-changednew-component:exe:spicePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: spice

Dependency ranges changed: data-default

API changes (from Hackage documentation)

- FRP.Spice.Graphics: Render :: (IO ()) -> Render
- FRP.Spice.Graphics: class Renderable a
- FRP.Spice.Graphics: fromRenderables :: Renderable a => [a] -> Scene
- FRP.Spice.Graphics: newtype Render
- FRP.Spice.Graphics: runRender :: Render -> IO ()
- FRP.Spice.Graphics: toRender :: Renderable a => a -> Render
+ FRP.Spice.Graphics: bindColor :: Color -> Scene
+ FRP.Spice.Graphics: fromElements :: [Element] -> Scene
- FRP.Spice.Graphics: black :: Scene
+ FRP.Spice.Graphics: black :: Color
- FRP.Spice.Graphics: blue :: Scene
+ FRP.Spice.Graphics: blue :: Color
- FRP.Spice.Graphics: color3f :: Float -> Float -> Float -> Scene
+ FRP.Spice.Graphics: color3f :: Float -> Float -> Float -> Color
- FRP.Spice.Graphics: color3i :: Int -> Int -> Int -> Scene
+ FRP.Spice.Graphics: color3i :: Int -> Int -> Int -> Color
- FRP.Spice.Graphics: color4f :: Float -> Float -> Float -> Float -> Scene
+ FRP.Spice.Graphics: color4f :: Float -> Float -> Float -> Float -> Color
- FRP.Spice.Graphics: color4i :: Int -> Int -> Int -> Int -> Scene
+ FRP.Spice.Graphics: color4i :: Int -> Int -> Int -> Int -> Color
- FRP.Spice.Graphics: green :: Scene
+ FRP.Spice.Graphics: green :: Color
- FRP.Spice.Graphics: red :: Scene
+ FRP.Spice.Graphics: red :: Color
- FRP.Spice.Graphics: white :: Scene
+ FRP.Spice.Graphics: white :: Color

Files

LICENSE view
@@ -1,20 +1,20 @@-Copyright (c) 2014 Cerek Hillen--Permission is hereby granted, free of charge, to any person obtaining-a copy of this software and associated documentation files (the-"Software"), to deal in the Software without restriction, including-without limitation the rights to use, copy, modify, merge, publish,-distribute, sublicense, and/or sell copies of the Software, and to-permit persons to whom the Software is furnished to do so, subject to-the following conditions:--The above copyright notice and this permission notice shall be included-in all copies or substantial portions of the Software.--THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY-CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE-SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.+Copyright (c) 2014 Cerek Hillen
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Setup.hs view
@@ -1,2 +1,2 @@-import Distribution.Simple-main = defaultMain+import Distribution.Simple
+main = defaultMain
spice.cabal view
@@ -1,50 +1,59 @@-name:                spice-version:             0.3.0.0-synopsis:            An FRP-based game engine written in Haskell.-description:         An FRP-based game engine written in Haskell. - See the homepage for more information.-homepage:            http://github.com/crockeo/spice-license:             MIT-license-file:        LICENSE-author:              Cerek Hillen-maintainer:          Cerek Hillen <cerekh@gmail.com>-copyright:           (c) 2014, Cerek Hillen-category:            FRP-build-type:          Simple-cabal-version:       >=1.10--library-  ghc-options:         -Wall -fno-warn-unused-do-bind--  exposed-modules:     FRP.Spice-                       FRP.Spice.Graphics-                       FRP.Spice.Math--  other-modules:       FRP.Spice.Config-                       FRP.Spice.Engine-                       FRP.Spice.Engine.Driver-                       FRP.Spice.Engine.Network-                       FRP.Spice.Engine.RenderWrapper-                       FRP.Spice.Engine.RunInput-                       FRP.Spice.Game-                       FRP.Spice.Graphics.Color-                       FRP.Spice.Graphics.Geometry-                       FRP.Spice.Graphics.Renderable-                       FRP.Spice.Graphics.Scene-                       FRP.Spice.Graphics.Utils-                       FRP.Spice.Input-                       FRP.Spice.Input.Backend-                       FRP.Spice.Input.Keyboard-                       FRP.Spice.Input.Mouse-                       FRP.Spice.Input.MousePosition-                       FRP.Spice.Math.Vector--  hs-source-dirs:      src/--  build-depends:       base         == 4.7.*-               ,       elerea       == 2.7.*-               ,       GLFW         == 0.5.*-               ,       containers   == 0.5.*-               ,       data-default == 0.5.*-               ,       OpenGL--  default-language:    Haskell2010+name:                spice
+version:             0.3.2.0
+synopsis:            An FRP-based game engine written in Haskell.
+description:         An FRP-based game engine written in Haskell. - See the homepage for more information.
+homepage:            http://github.com/crockeo/spice
+license:             MIT
+license-file:        LICENSE
+author:              Cerek Hillen
+maintainer:          Cerek Hillen <cerekh@gmail.com>
+copyright:           (c) 2014, Cerek Hillen
+category:            FRP
+build-type:          Simple
+cabal-version:       >=1.10
+
+library
+  ghc-options:         -Wall -fno-warn-unused-do-bind
+
+  exposed-modules:     FRP.Spice
+                       FRP.Spice.Graphics
+                       FRP.Spice.Math
+
+  other-modules:       FRP.Spice.Config
+                       FRP.Spice.Engine
+                       FRP.Spice.Engine.Driver
+                       FRP.Spice.Engine.Network
+                       FRP.Spice.Engine.RenderWrapper
+                       FRP.Spice.Engine.RunInput
+                       FRP.Spice.Game
+                       FRP.Spice.Graphics.Color
+                       FRP.Spice.Graphics.Element
+                       FRP.Spice.Graphics.Geometry
+                       FRP.Spice.Graphics.Scene
+                       FRP.Spice.Graphics.Utils
+                       FRP.Spice.Input
+                       FRP.Spice.Input.Backend
+                       FRP.Spice.Input.Keyboard
+                       FRP.Spice.Input.Mouse
+                       FRP.Spice.Input.MousePosition
+                       FRP.Spice.Math.Vector
+
+  hs-source-dirs:      src/
+
+  build-depends:       base         == 4.7.*
+               ,       elerea       == 2.7.*
+               ,       GLFW         == 0.5.*
+               ,       containers   == 0.5.*
+               ,       data-default == 0.5.*
+               ,       OpenGL
+
+  default-language:    Haskell2010
+
+executable spice
+  ghc-options: -rtsopts
+  main-is: Main.hs
+  hs-source-dirs: src/test/
+  build-depends: base == 4.7.*
+               , spice
+               , data-default
+  default-language: Haskell2010
src/FRP/Spice.hs view
@@ -1,22 +1,22 @@-{-|-  This module re-exports some other modules in the spice library so that you-  needn't import all of them explicitly.--}-module FRP.Spice ( module Graphics.UI.GLFW-                 , module Data.Map.Strict--                 , module FRP.Spice.Config-                 , module FRP.Spice.Engine-                 , module FRP.Spice.Input-                 , module FRP.Spice.Game-                 ) where---------------------------- Rexported Imports ---import Graphics.UI.GLFW (Key (..), SpecialKey (..), MouseButton (..))-import Data.Map.Strict ((!))--import FRP.Spice.Config-import FRP.Spice.Engine-import FRP.Spice.Input-import FRP.Spice.Game+{-|
+  This module re-exports some other modules in the spice library so that you
+  needn't import all of them explicitly.
+-}
+module FRP.Spice ( module Graphics.UI.GLFW
+                 , module Data.Map.Strict
+
+                 , module FRP.Spice.Config
+                 , module FRP.Spice.Engine
+                 , module FRP.Spice.Input
+                 , module FRP.Spice.Game
+                 ) where
+
+-----------------------
+-- Rexported Imports --
+import Graphics.UI.GLFW (Key (..), SpecialKey (..), MouseButton (..))
+import Data.Map.Strict ((!))
+
+import FRP.Spice.Config
+import FRP.Spice.Engine
+import FRP.Spice.Input
+import FRP.Spice.Game
src/FRP/Spice/Config.hs view
@@ -1,41 +1,41 @@-{-|-  This module handles the configuration for the project.--}-module FRP.Spice.Config where------------------------- Global Imports ---import Data.Default--------------- Code ----{-|-  A datatype to configure the window settings when creating an OpenGL context-  using @'FRP.Spice.Engine.startEngine'@ in the engine.--}-data WindowConfig = WindowConfig { getWindowWidth      :: Int-                                 , getWindowHeight     :: Int-                                 , getWindowFullscreen :: Bool-                                 , getWindowTitle      :: String-                                 }-  deriving (Eq, Show, Read)--{-|-  The default for @'WindowConfig'@--  > getWindowWidth      = 640-  > getWindowHeight     = 480-  > getWindowFullscreen = False-  > getWindowResizeable = False-  > getWindowTitle      = "Spice Application"--}-defaultWindowConfig :: WindowConfig-defaultWindowConfig = WindowConfig { getWindowWidth      = 640-                                   , getWindowHeight     = 480-                                   , getWindowFullscreen = False-                                   , getWindowTitle      = "Spice Application"-                                   }--instance Default WindowConfig where-  def = defaultWindowConfig+{-|
+  This module handles the configuration for the project.
+-}
+module FRP.Spice.Config where
+
+--------------------
+-- Global Imports --
+import Data.Default
+
+----------
+-- Code --
+
+{-|
+  A datatype to configure the window settings when creating an OpenGL context
+  using @'FRP.Spice.Engine.startEngine'@ in the engine.
+-}
+data WindowConfig = WindowConfig { getWindowWidth      :: Int
+                                 , getWindowHeight     :: Int
+                                 , getWindowFullscreen :: Bool
+                                 , getWindowTitle      :: String
+                                 }
+  deriving (Eq, Show, Read)
+
+{-|
+  The default for @'WindowConfig'@
+
+  > getWindowWidth      = 640
+  > getWindowHeight     = 480
+  > getWindowFullscreen = False
+  > getWindowResizeable = False
+  > getWindowTitle      = "Spice Application"
+-}
+defaultWindowConfig :: WindowConfig
+defaultWindowConfig = WindowConfig { getWindowWidth      = 640
+                                   , getWindowHeight     = 480
+                                   , getWindowFullscreen = False
+                                   , getWindowTitle      = "Spice Application"
+                                   }
+
+instance Default WindowConfig where
+  def = defaultWindowConfig
src/FRP/Spice/Engine.hs view
@@ -1,90 +1,86 @@-{-|-  This module handles starting the engine. This is done via the use of the-  @'startEngine'@ function.--}-module FRP.Spice.Engine (startEngine) where------------------------- Global Imports ---import Graphics.Rendering.OpenGL-import Graphics.UI.GLFW as GLFW-import FRP.Elerea.Param-import Data.IORef------------------------ Local Imports ---import FRP.Spice.Engine.RunInput-import FRP.Spice.Engine.Network-import FRP.Spice.Engine.Driver-import FRP.Spice.Input.Backend-import FRP.Spice.Config-import FRP.Spice.Game--------------- Code ------ Containing if the engine has been made before-madeRef :: IO (IORef Bool)-madeRef = newIORef False---- Making the size from a WindowConfig-makeSize :: WindowConfig -> Size-makeSize wc = Size (fromIntegral $ getWindowWidth wc) (fromIntegral $ getWindowHeight wc)---- Making the displaybits from a WindowConfig-makeDisplayBits :: [DisplayBits]-makeDisplayBits = [DisplayRGBBits 8 8 8, DisplayAlphaBits 8, DisplayDepthBits 24]---- Making the window mode from a WindowConfig-makeWindowMode :: WindowConfig -> WindowMode-makeWindowMode wc =-  if getWindowFullscreen wc-    then FullScreen-    else Window--{-|-  Starting the spice engine with the parameters prescribed in the-  @'WindowConfig'@. It updates and renders the @'Game'@ automatically so all-  you need to to is set up the @'WindowConfig'@ and make a datatype with an-  instance of @'Game'@.--}-startEngine :: Game a => WindowConfig -> a -> IO ()-startEngine wc game = do-  made   <- madeRef-  isMade <- readIORef made-  if isMade-    then error "You cannot run 'startEngine' more than once per program."-    else do-      writeIORef made True--      -- Opening the window-      initialize-      openWindow (makeSize wc) makeDisplayBits (makeWindowMode wc)-      windowTitle $= getWindowTitle wc--      -- Checking for the window being closed-      closed <- newIORef False-      windowCloseCallback $= do-        writeIORef closed True-        return True--      -- Getting an external of the game-      (gameSignal, gameSink) <- external game--      -- Getting the input container-      ic <- makeInputContainer--      -- Updating the input-      mousePosCallback    $= makeMousePositionCallback wc ic-      keyCallback         $= makeKeyboardCallback ic-      mouseButtonCallback $= makeMouseCallback ic--      -- Creating the network-      network <- makeNetwork (getInput ic) gameSignal gameSink--      -- Driving the network-      GLFW.time $= 0-      driveNetwork network $ runInput closed--      -- Closing the window, after all is said and done-      closeWindow+{-|
+  This module handles starting the engine. This is done via the use of the
+  @'startEngine'@ function.
+-}
+module FRP.Spice.Engine (startEngine) where
+
+--------------------
+-- Global Imports --
+import Graphics.Rendering.OpenGL
+import Graphics.UI.GLFW as GLFW
+import Data.IORef
+
+-------------------
+-- Local Imports --
+import FRP.Spice.Engine.RunInput
+import FRP.Spice.Engine.Network
+import FRP.Spice.Engine.Driver
+import FRP.Spice.Input.Backend
+import FRP.Spice.Config
+import FRP.Spice.Game
+import FRP.Spice.Math
+
+----------
+-- Code --
+
+-- Making the size from a WindowConfig
+makeSize :: WindowConfig -> Size
+makeSize wc = Size (fromIntegral $ getWindowWidth wc) (fromIntegral $ getWindowHeight wc)
+
+-- Making the displaybits from a WindowConfig
+makeDisplayBits :: [DisplayBits]
+makeDisplayBits = [DisplayRGBBits 8 8 8, DisplayAlphaBits 8, DisplayDepthBits 24]
+
+-- Making the window mode from a WindowConfig
+makeWindowMode :: WindowConfig -> WindowMode
+makeWindowMode wc =
+  if getWindowFullscreen wc
+    then FullScreen
+    else Window
+
+-- Resizing the window
+resizeCallback :: IORef (Vector Int) -> WindowSizeCallback
+resizeCallback wSize size@(Size w h) = do
+  writeIORef wSize $ Vector (fromIntegral w) (fromIntegral h)
+  viewport $= (Position 0 0, size)
+
+{-|
+  Starting the spice engine with the parameters prescribed in the
+  @'WindowConfig'@. It updates and renders the @'Game'@ automatically so all
+  you need to to is set up the @'WindowConfig'@ and make a datatype with an
+  instance of @'Game'@.
+-}
+startEngine :: Game a => WindowConfig -> a -> IO ()
+startEngine wc game = do
+  -- Opening the window
+  initialize
+  openWindow (makeSize wc) makeDisplayBits (makeWindowMode wc)
+  windowTitle $= getWindowTitle wc
+
+  -- Checking for the window being closed
+  closed <- newIORef False
+  windowCloseCallback $= do
+    writeIORef closed True
+    return True
+
+  -- Function to run on window resize
+  wSizeRef <- newIORef $ Vector (getWindowWidth wc) (getWindowHeight wc)
+  windowSizeCallback $= resizeCallback wSizeRef
+
+  -- Getting the input container
+  ic <- makeInputContainer
+
+  -- Updating the input
+  mousePosCallback    $= makeMousePositionCallback ic wSizeRef
+  keyCallback         $= makeKeyboardCallback ic
+  mouseButtonCallback $= makeMouseCallback ic
+
+  -- Creating the network
+  network <- makeNetwork (getInput ic) game
+
+  -- Driving the network
+  GLFW.time $= 0
+  driveNetwork network $ runInput closed
+
+  -- Closing the window, after all is said and done
+  closeWindow
src/FRP/Spice/Engine/Driver.hs view
@@ -1,24 +1,26 @@-{-|-  This module need not be used directly. Refer to @'FRP.Spice.Engine'@ instead.--}-module FRP.Spice.Engine.Driver where------------------------- Global Imports ---import Control.Monad--------------- Code ----{-|-  Driving a network created with the @'FRP.Spice.Engine.Network.makeNetwork'@-  function and a function such as @'FRP.Spice.Engine.RunInput.runInput'@.--}-driveNetwork :: (a -> IO (IO ())) -> IO (Maybe a) -> IO ()-driveNetwork network iomdriver = do-  mdriver <- iomdriver--  case mdriver of-    Just driver -> do join $ network driver-                      driveNetwork network iomdriver-    Nothing     -> return ()+{-|
+  This module need not be used directly. Refer to @'FRP.Spice.Engine'@ instead.
+-}
+module FRP.Spice.Engine.Driver where
+
+--------------------
+-- Global Imports --
+import FRP.Spice.Engine.RenderWrapper
+import FRP.Spice.Game
+
+----------
+-- Code --
+
+{-|
+  Driving a network created with the @'FRP.Spice.Engine.Network.makeNetwork'@
+  function and a function such as @'FRP.Spice.Engine.RunInput.runInput'@.
+-}
+driveNetwork :: Game a => (Float -> IO a) -> IO (Maybe Float) -> IO ()
+driveNetwork network iomdriver = do
+  mdriver <- iomdriver
+
+  case mdriver of
+    Just driver -> do state <- network driver
+                      renderWrapper $ render state
+                      driveNetwork network iomdriver
+    Nothing     -> return ()
src/FRP/Spice/Engine/Network.hs view
@@ -1,32 +1,31 @@-{-|-  This module need not be used directly. Refer to-  @'FRP.Spice.Engine.startEngine'@ instead.--}-module FRP.Spice.Engine.Network where------------------------- Global Imports ---import FRP.Elerea.Param------------------------ Local Imports ---import FRP.Spice.Engine.RenderWrapper-import FRP.Spice.Input-import FRP.Spice.Game--------------- Code ----{-|-  Creating a network to be used with the-  @'FRP.Spice.Engine.Driver.driveNetwork'@ function.--}-makeNetwork :: Game a => Signal Input -> Signal a -> (a -> IO ()) -> IO (Float -> IO (IO ()))-makeNetwork inputSignal gameSignal gameSink =-  start $ memo $ do-    input <- inputSignal-    game  <- gameSignal--    return $ do-      gameSink $ update 0.01 input game-      renderWrapper $ render game+{-|
+  This module need not be used directly. Refer to
+  @'FRP.Spice.Engine.startEngine'@ instead.
+-}
+module FRP.Spice.Engine.Network where
+
+--------------------
+-- Global Imports --
+import FRP.Elerea.Param
+
+-------------------
+-- Local Imports --
+import FRP.Spice.Input
+import FRP.Spice.Game
+
+----------
+-- Code --
+
+{-|
+  The raw update function that @'makeNetwork'@ calls.
+-}
+updateFn :: Game a => Float -> Input -> a -> a
+updateFn = update
+
+{-|
+  Creating a network to be used with the
+  @'FRP.Spice.Engine.Driver.driveNetwork'@ function.
+-}
+makeNetwork :: Game a => Signal Input -> a -> IO (Float -> IO a)
+makeNetwork inputSignal game =
+  start $ transfer game updateFn inputSignal
src/FRP/Spice/Engine/RenderWrapper.hs view
@@ -1,31 +1,31 @@-{-|-  This module provides a wrapper to use with a given @'FRP.Spice.Game.Game'@'s-  render function.--}-module FRP.Spice.Engine.RenderWrapper where------------------------- Global Imports ---import Graphics.Rendering.OpenGL-import Graphics.UI.GLFW------------------------- Global Imports ---import FRP.Spice.Graphics.Scene--------------- Code ----{-|-  A function to be ran on a @'FRP.Spice.Game.Game'@'s render function to-  provide a bit of a framework around it. It runs @'clear'@ before the render-  function, and @'flush'@ / @'swapBuffers'@ afterwards.--}-renderWrapper :: Scene -> IO ()-renderWrapper scene = do-  clear [ColorBuffer]--  renderScene scene--  flush-  swapBuffers+{-|
+  This module provides a wrapper to use with a given @'FRP.Spice.Game.Game'@'s
+  render function.
+-}
+module FRP.Spice.Engine.RenderWrapper where
+
+--------------------
+-- Global Imports --
+import Graphics.Rendering.OpenGL
+import Graphics.UI.GLFW
+
+--------------------
+-- Global Imports --
+import FRP.Spice.Graphics.Scene
+
+----------
+-- Code --
+
+{-|
+  A function to be ran on a @'FRP.Spice.Game.Game'@'s render function to
+  provide a bit of a framework around it. It runs @'clear'@ before the render
+  function, and @'flush'@ / @'swapBuffers'@ afterwards.
+-}
+renderWrapper :: Scene -> IO ()
+renderWrapper scene = do
+  clear [ColorBuffer]
+
+  renderScene scene
+
+  flush
+  swapBuffers
src/FRP/Spice/Engine/RunInput.hs view
@@ -1,31 +1,31 @@-{-|-  This module need not be used directly. Refer to @'FRP.Spice.Engine'@ instead.--}-module FRP.Spice.Engine.RunInput where------------------------- Global Imports ---import Graphics.Rendering.OpenGL-import Graphics.UI.GLFW as GLFW-import Data.IORef-import GHC.Float--------------- Code ----{-|-  Given an @'IORef'@ indicating whether or not the program should close, it-  either returns the delta time since the last call, or a @'Nothing'@,-  indicating that the program should close.--}-runInput :: IORef Bool -> IO (Maybe Float)-runInput closed = do-  pollEvents-  c <- readIORef closed--  if c-    then return Nothing-    else do-      dt <- get GLFW.time-      GLFW.time $= 0-      return $ Just $ double2Float (dt / 1000)+{-|
+  This module need not be used directly. Refer to @'FRP.Spice.Engine'@ instead.
+-}
+module FRP.Spice.Engine.RunInput where
+
+--------------------
+-- Global Imports --
+import Graphics.Rendering.OpenGL
+import Graphics.UI.GLFW as GLFW
+import Data.IORef
+import GHC.Float
+
+----------
+-- Code --
+
+{-|
+  Given an @'IORef'@ indicating whether or not the program should close, it
+  either returns the delta time since the last call, or a @'Nothing'@,
+  indicating that the program should close.
+-}
+runInput :: IORef Bool -> IO (Maybe Float)
+runInput closed = do
+  pollEvents
+  c <- readIORef closed
+
+  if c
+    then return Nothing
+    else do
+      dt <- get GLFW.time
+      GLFW.time $= 0
+      return $ Just $ double2Float dt
src/FRP/Spice/Game.hs view
@@ -1,27 +1,27 @@-{-|-  This module provides the API which people must use to define a game within-  the scope of Spice.--}-module FRP.Spice.Game where------------------------ Local Imports ---import FRP.Spice.Graphics.Scene-import FRP.Spice.Input--------------- Code ----{-|-  A synonym to make the update function more self-documenting.--}-type DeltaTime = Float--{-|-  The class which is to be used in the @'FRP.Spice.Engine.startEngine'@-  function. @'update'@ provides the API to update on every tick (purely), an-   @'render'@ provides the API to render every frame.--}-class Game a where-  update :: DeltaTime -> Input -> a -> a-  render :: a -> Scene+{-|
+  This module provides the API which people must use to define a game within
+  the scope of Spice.
+-}
+module FRP.Spice.Game where
+
+-------------------
+-- Local Imports --
+import FRP.Spice.Graphics.Scene
+import FRP.Spice.Input
+
+----------
+-- Code --
+
+{-|
+  A synonym to make the update function more self-documenting.
+-}
+type DeltaTime = Float
+
+{-|
+  The class which is to be used in the @'FRP.Spice.Engine.startEngine'@
+  function. @'update'@ provides the API to update on every tick (purely), an
+   @'render'@ provides the API to render every frame.
+-}
+class Game a where
+  update :: DeltaTime -> Input -> a -> a
+  render :: a -> Scene
src/FRP/Spice/Graphics.hs view
@@ -1,17 +1,15 @@-{-|-  This module re-exports a number of modules having to do with graphics.--}-module FRP.Spice.Graphics ( module FRP.Spice.Graphics.Renderable-                          , module FRP.Spice.Graphics.Geometry-                          , module FRP.Spice.Graphics.Color-                          , module FRP.Spice.Graphics.Scene-                          , module FRP.Spice.Graphics.Utils-                          ) where---------------------------- Rexported Imports ---import FRP.Spice.Graphics.Renderable-import FRP.Spice.Graphics.Geometry-import FRP.Spice.Graphics.Color-import FRP.Spice.Graphics.Scene-import FRP.Spice.Graphics.Utils+{-|
+  This module re-exports a number of modules having to do with graphics.
+-}
+module FRP.Spice.Graphics ( module FRP.Spice.Graphics.Geometry
+                          , module FRP.Spice.Graphics.Color
+                          , module FRP.Spice.Graphics.Scene
+                          , module FRP.Spice.Graphics.Utils
+                          ) where
+
+-----------------------
+-- Rexported Imports --
+import FRP.Spice.Graphics.Geometry
+import FRP.Spice.Graphics.Color
+import FRP.Spice.Graphics.Scene
+import FRP.Spice.Graphics.Utils
src/FRP/Spice/Graphics/Color.hs view
@@ -1,100 +1,97 @@-{-|-  This module provides an abstraction over the default representations of color-  in the Haskell OpenGL bindings.--}-module FRP.Spice.Graphics.Color where------------------------- Global Imports ---import Graphics.Rendering.OpenGL (Color4 (..), color)------------------------ Local Imports ---import FRP.Spice.Graphics.Renderable-import FRP.Spice.Graphics.Scene-import FRP.Spice.Graphics.Utils--------------- Code ----{-|-  Representing a Color using four @'Float'@ representing reg, green, blue, and-  the alpha mask respectively. The @'Float'@s are in a range from 0-1,-  representing @'Int'@s from 0-255.--}-data Color = Color { getRed   :: Float-                   , getGreen :: Float-                   , getBlue  :: Float-                   , getAlpha :: Float-                   }-  deriving (Eq, Show, Read)--{-|-  Changing the current OpenGL context's @'Color4'@ to whatever @'Color'@-  specified.--}-instance Renderable Color where-  toRender (Color r g b a) =-    Render $-      color $ Color4 (togl r) (togl g) (togl b) (togl a)--{-|-  A synonym for the @'Color'@ constructor.--}-color4f :: Float -> Float -> Float -> Float -> Scene-color4f r g b a = fromRenderables [Color r g b a]--{-|-  Constructing a @'Color'@ from 3 @'Float'@s, defaulting the alpha mask to 1.0.--}-color3f :: Float -> Float -> Float -> Scene-color3f r g b = color4f r g b 1.0--{-|-  Creating a @'Color'@ from 4 @'Int'@s. The ints, similarly to @'color4f'@-  represent red, green, blue, and the alpha mask respectively. The ints should-  be in the range of 0-255. (Note: @'color4i'@ is functionally equivalent (and-  also equivalent in source code) to calling color4f with each of its arguments-  divided by 255.)--}-color4i :: Int -> Int -> Int -> Int -> Scene-color4i r g b a = color4f (fromIntegral r / 255)-                          (fromIntegral g / 255)-                          (fromIntegral b / 255)-                          (fromIntegral a / 255)--{-|-  Constructing a @'Color'@ from 3 @'Int'@s, defaulting the alpha mask to 255.--}-color3i :: Int -> Int -> Int -> Scene-color3i r g b = color4i r g b 255--{-|-  The color black.--}-black :: Scene-black = color3i 0 0 0--{-|-  The color white.--}-white :: Scene-white = color3i 255 255 255--{-|-  The color red.--}-red :: Scene-red = color3i 255 0 0--{-|-  The color green.--}-green :: Scene-green = color3i 0 255 0--{-|-  The color blue.--}-blue :: Scene-blue = color3i 0 0 255+{-|
+  This module provides an abstraction over the default representations of color
+  in the Haskell OpenGL bindings.
+-}
+module FRP.Spice.Graphics.Color where
+
+--------------------
+-- Global Imports --
+import Graphics.Rendering.OpenGL (Color4 (..), color)
+
+-------------------
+-- Local Imports --
+import FRP.Spice.Graphics.Element
+import FRP.Spice.Graphics.Scene
+import FRP.Spice.Graphics.Utils
+
+----------
+-- Code --
+
+{-|
+  Representing a Color using four @'Float'@ representing reg, green, blue, and
+  the alpha mask respectively. The @'Float'@s are in a range from 0-1,
+  representing @'Int'@s from 0-255.
+-}
+data Color = Color { getRed   :: Float
+                   , getGreen :: Float
+                   , getBlue  :: Float
+                   , getAlpha :: Float
+                   }
+  deriving (Eq, Show, Read)
+
+{-|
+  Converting a color to an action in a @'Scene'@.
+-}
+bindColor :: Color -> Scene
+bindColor (Color r g b a) = fromElements [SetColor r g b a]
+
+{-|
+  A synonym for the @'Color'@ constructor.
+-}
+color4f :: Float -> Float -> Float -> Float -> Color
+color4f = Color
+
+{-|
+  Constructing a @'Color'@ from 3 @'Float'@s, defaulting the alpha mask to 1.0.
+-}
+color3f :: Float -> Float -> Float -> Color
+color3f r g b = color4f r g b 1.0
+
+{-|
+  Creating a @'Color'@ from 4 @'Int'@s. The ints, similarly to @'color4f'@
+  represent red, green, blue, and the alpha mask respectively. The ints should
+  be in the range of 0-255. (Note: @'color4i'@ is functionally equivalent (and
+  also equivalent in source code) to calling color4f with each of its arguments
+  divided by 255.)
+-}
+color4i :: Int -> Int -> Int -> Int -> Color
+color4i r g b a = color4f (fromIntegral r / 255)
+                          (fromIntegral g / 255)
+                          (fromIntegral b / 255)
+                          (fromIntegral a / 255)
+
+{-|
+  Constructing a @'Color'@ from 3 @'Int'@s, defaulting the alpha mask to 255.
+-}
+color3i :: Int -> Int -> Int -> Color
+color3i r g b = color4i r g b 255
+
+{-|
+  The color black.
+-}
+black :: Color
+black = color3i 0 0 0
+
+{-|
+  The color white.
+-}
+white :: Color
+white = color3i 255 255 255
+
+{-|
+  The color red.
+-}
+red :: Color
+red = color3i 255 0 0
+
+{-|
+  The color green.
+-}
+green :: Color
+green = color3i 0 255 0
+
+{-|
+  The color blue.
+-}
+blue :: Color
+blue = color3i 0 0 255
+ src/FRP/Spice/Graphics/Element.hs view
@@ -0,0 +1,36 @@+module FRP.Spice.Graphics.Element ( Element (..)
+                                  , renderElement
+                                  ) where
+
+--------------------
+-- Global Imports --
+import Graphics.Rendering.OpenGL
+import Control.Monad
+
+-------------------
+-- Local Imports --
+import FRP.Spice.Graphics.Utils
+import FRP.Spice.Math
+
+----------
+-- Code --
+
+{-|
+  A type to purely contain the information for any kind of render call (that
+  has been implemented so far.)
+-}
+data Element = RenderPrimitive PrimitiveMode [Vector Float]
+             | SetColor Float Float Float Float
+
+{-|
+  Converting an @'Element'@ into its matching OpenGL call.
+-}
+renderElement :: Element -> IO ()
+
+renderElement (RenderPrimitive mode vertecies) =
+  renderPrimitive mode $
+    forM_ vertecies $ \(Vector x y) ->
+      vertex $ Vertex2 (togl x) (togl y)
+
+renderElement (SetColor r g b a) =
+  color $ Color4 (togl r) (togl g) (togl b) (togl a)
src/FRP/Spice/Graphics/Geometry.hs view
@@ -1,69 +1,52 @@-{-|-  This module provides a cleaner API to render a number of shapes in the-  current OpenGL context.--}-module FRP.Spice.Graphics.Geometry ( renderPoint-                                   , renderRectangle-                                   , renderSquare-                                   ) where------------------------- Global Imports ---import Graphics.Rendering.OpenGL ( PrimitiveMode (..)-                                 , Vertex2 (..)-                                 , renderPrimitive-                                 , vertex-                                 )-import Control.Monad------------------------ Local Imports ---import FRP.Spice.Graphics.Renderable-import FRP.Spice.Graphics.Scene-import FRP.Spice.Graphics.Utils-import FRP.Spice.Math.Vector--------------- Code ----{-|-  The information necessary to construct any given OpenGL primitive. The-  @'PrimitiveMode'@ represents -- of course -- the kind of GL primitive to-  render. The list of @'Vector'@s directly represents the vertecies to bind.--}-data Primitive = Primitive PrimitiveMode [Vector Float]--{-|-  Rendering whatever OpenGL primitive is specified.--}-instance Renderable Primitive where-  toRender (Primitive mode vertecies) =-    Render $-      renderPrimitive mode $-        forM_ vertecies $ \(Vector x y) ->-          vertex $ Vertex2 (togl x) (togl y)--{-|-  Rendering a point.--}-renderPoint :: Vector Float -> Scene-renderPoint pos =-  fromRenderables [Primitive Points [pos]]--{-|-  Rendering a rectangle.--}-renderRectangle :: Vector Float -> Vector Float -> Scene-renderRectangle (Vector x y) (Vector w h) = do-  fromRenderables [ Primitive Quads [ Vector (x    ) (y    )-                               , Vector (x + w) (y    )-                               , Vector (x + w) (y + h)-                               , Vector (x    ) (y + h)-                               ]-               ]--{-|-  Rendering a square.--}-renderSquare :: Vector Float -> Float -> Scene-renderSquare pos size = renderRectangle pos $ Vector size size+{-|
+  This module provides a cleaner API to render a number of shapes in the
+  current OpenGL context.
+-}
+module FRP.Spice.Graphics.Geometry ( renderPoint
+                                   , renderRectangle
+                                   , renderSquare
+                                   ) where
+
+--------------------
+-- Global Imports --
+import Graphics.Rendering.OpenGL ( PrimitiveMode (..)
+                                 , Vertex2 (..)
+                                 , renderPrimitive
+                                 , vertex
+                                 )
+import Control.Monad
+
+-------------------
+-- Local Imports --
+import FRP.Spice.Graphics.Element
+import FRP.Spice.Graphics.Scene
+import FRP.Spice.Graphics.Utils
+import FRP.Spice.Math.Vector
+
+----------
+-- Code --
+
+{-|
+  Rendering a point.
+-}
+renderPoint :: Vector Float -> Scene
+renderPoint pos =
+  fromElements [RenderPrimitive Points [pos]]
+
+{-|
+  Rendering a rectangle.
+-}
+renderRectangle :: Vector Float -> Vector Float -> Scene
+renderRectangle (Vector x y) (Vector w h) = do
+  fromElements [ RenderPrimitive Quads [ Vector (x    ) (y    )
+                                       , Vector (x + w) (y    )
+                                       , Vector (x + w) (y + h)
+                                       , Vector (x    ) (y + h)
+                                       ]
+               ]
+
+{-|
+  Rendering a square.
+-}
+renderSquare :: Vector Float -> Float -> Scene
+renderSquare pos size = renderRectangle pos $ Vector size size
− src/FRP/Spice/Graphics/Renderable.hs
@@ -1,22 +0,0 @@-module FRP.Spice.Graphics.Renderable where--------------- Code ----{-|-  A container around IO to suggest that one should perform rendering in a-  rendering function.--}-newtype Render = Render (IO ())--{-|-  Performing the IO contained in a @'Render'@.--}-runRender :: Render -> IO ()-runRender (Render action) = action--{-|-  A class that provides an API to convert a datatype into a @'Render'@.--}-class Renderable a where-  toRender :: a -> Render
src/FRP/Spice/Graphics/Scene.hs view
@@ -1,64 +1,64 @@-module FRP.Spice.Graphics.Scene ( Scene-                                , fromRenderables-                                , renderScene-                                ) where------------------------- Global Imports ---import Control.Applicative-import Control.Monad------------------------ Local Imports ---import FRP.Spice.Graphics.Renderable--------------- Code ----{-|-  For composing a scene out of a set of renderables.--}-data SceneT a = SceneT [Render] a--{-|-  The commonly used instance of SceneT--}-type Scene = SceneT ()--{-|-  Functor instance to satisfy applicative instance.--}-instance Functor SceneT where-  fmap fn (SceneT renderables v) = SceneT renderables $ fn v--{-|-  Applicative instance to satisfy the monad instance. Not advised to use--}-instance Applicative SceneT where-  pure  = return-  (<*>) = ap--{-|-  Used for being able to compose Scenes in a do-notation. Not very useful-  outside of that.--}-instance Monad SceneT where-  return a = SceneT [] a-  (SceneT renderables v) >>= fn =-    let (SceneT renderables' v') = fn v in-      SceneT (renderables ++ renderables') v'--{-|-  Constructing a SceneT from a list of renderables.--}-fromRenderables :: Renderable a => [a] -> Scene-fromRenderables renderables =-  SceneT (map toRender renderables) ()--{-|-  Rendering a whole @'Scene'@ (renders each @'Element'@ from first in list to last in-  list.)--}-renderScene :: Scene -> IO ()-renderScene (SceneT renderables _) =-  forM_ renderables runRender+module FRP.Spice.Graphics.Scene ( Scene
+                                , fromElements
+                                , renderScene
+                                ) where
+
+--------------------
+-- Global Imports --
+import Control.Applicative
+import Control.Monad
+
+-------------------
+-- Local Imports --
+import FRP.Spice.Graphics.Element
+
+----------
+-- Code --
+
+{-|
+  For composing a scene out of a set of elements.
+-}
+data SceneT a = SceneT [Element] a
+
+{-|
+  The commonly used instance of SceneT
+-}
+type Scene = SceneT ()
+
+{-|
+  Functor instance to satisfy applicative instance.
+-}
+instance Functor SceneT where
+  fmap fn (SceneT elements v) = SceneT elements $ fn v
+
+{-|
+  Applicative instance to satisfy the monad instance. Not advised to use
+-}
+instance Applicative SceneT where
+  pure  = return
+  (<*>) = ap
+
+{-|
+  Used for being able to compose Scenes in a do-notation. Not very useful
+  outside of that.
+-}
+instance Monad SceneT where
+  return a = SceneT [] a
+  (SceneT elements v) >>= fn =
+    let (SceneT elements' v') = fn v in
+      SceneT (elements ++ elements') v'
+
+{-|
+  Constructing a SceneT from a list of elements.
+-}
+fromElements :: [Element] -> Scene
+fromElements elements =
+  SceneT elements ()
+
+{-|
+  Rendering a whole @'Scene'@ (renders each @'Element'@ from first in list to last in
+  list.)
+-}
+renderScene :: Scene -> IO ()
+renderScene (SceneT elements _) =
+  forM_ elements renderElement
src/FRP/Spice/Graphics/Utils.hs view
@@ -1,18 +1,18 @@-{-|-  This module provides a set of utilities to ease the burden of writing OpenGL-  rendering functions.--}-module FRP.Spice.Graphics.Utils where------------------------- Global Imports ---import Graphics.Rendering.OpenGL--------------- Code ----{-|-  Converting a @'Float'@ to a @'GLfloat'@--}-togl :: Float -> GLfloat-togl = realToFrac+{-|
+  This module provides a set of utilities to ease the burden of writing OpenGL
+  rendering functions.
+-}
+module FRP.Spice.Graphics.Utils where
+
+--------------------
+-- Global Imports --
+import Graphics.Rendering.OpenGL
+
+----------
+-- Code --
+
+{-|
+  Converting a @'Float'@ to a @'GLfloat'@
+-}
+togl :: Float -> GLfloat
+togl = realToFrac
src/FRP/Spice/Input.hs view
@@ -1,26 +1,26 @@-{-|-  This module provides everything relating to input in the scope of spice.--}-module FRP.Spice.Input where------------------------- Global Imports ---import Graphics.UI.GLFW-import Data.Map.Strict------------------------ Local Imports ---import FRP.Spice.Math--------------- Code ----{-|-  A container for all of the states themselves. It is used as a @'Signal'@-  @'Input'@ in the @'InputContainer'@ (which is necessary to use it within-  Elerea's FRP network).--}-data Input = Input { mousePosition :: Vector Float-                   , keyboard      :: Map Key Bool-                   , mouse         :: Map MouseButton Bool-                   }+{-|
+  This module provides everything relating to input in the scope of spice.
+-}
+module FRP.Spice.Input where
+
+--------------------
+-- Global Imports --
+import Graphics.UI.GLFW
+import Data.Map.Strict
+
+-------------------
+-- Local Imports --
+import FRP.Spice.Math
+
+----------
+-- Code --
+
+{-|
+  A container for all of the states themselves. It is used as a @'Signal'@
+  @'Input'@ in the @'InputContainer'@ (which is necessary to use it within
+  Elerea's FRP network).
+-}
+data Input = Input { mousePosition :: Vector Float
+                   , keyboard      :: Map Key Bool
+                   , mouse         :: Map MouseButton Bool
+                   }
src/FRP/Spice/Input/Backend.hs view
@@ -1,96 +1,98 @@-{-|-  The backend to be used with the input.--}-module FRP.Spice.Input.Backend where------------------------- Global Imports ---import Graphics.Rendering.OpenGL-import Graphics.UI.GLFW as GLFW-import FRP.Elerea.Param-import Data.Map.Strict------------------------ Local Imports ---import qualified FRP.Spice.Input.MousePosition as MousePosition-import qualified FRP.Spice.Input.Keyboard      as Keyboard-import qualified FRP.Spice.Input.Mouse         as Mouse-import FRP.Spice.Config-import FRP.Spice.Input-import FRP.Spice.Math--------------- Code ----{-|-  A wrapper around the sinks for the mouse position, the key states, and the-  mouse button states.--}-data Sinks = Sinks { mousePositionSinks :: Vector Float -> IO ()-                   , keyboardSinks      :: Map Key (Bool -> IO ())-                   , mouseSinks         :: Map MouseButton (Bool -> IO ())-                   }----{-|-  A container around @'Sinks'@ and @'Signal'@ @'Input'@ so that one needn't-  pass around a tuple.--}-data InputContainer = InputContainer { getSinks :: Sinks-                                     , getInput :: Signal Input-                                     }--{-|-  Making an @'InputContainer'@ filled with all necessary externals.--}-makeInputContainer :: IO InputContainer-makeInputContainer = do-  mousePositionExternals <- MousePosition.externals-  keyboardExternals      <- Keyboard.externals-  mouseExternals         <- Mouse.externals--  let sinks = Sinks { mousePositionSinks = MousePosition.sinks mousePositionExternals-                    , keyboardSinks      = Keyboard.sinks keyboardExternals-                    , mouseSinks         = Mouse.sinks mouseExternals-                    }--  let input = do mps <- fst mousePositionExternals-                 kbs <- Keyboard.signals keyboardExternals-                 ms  <- Mouse.signals mouseExternals--                 return Input { mousePosition = mps-                              , keyboard      = kbs-                              , mouse         = ms-                              }--  return InputContainer { getSinks = sinks-                        , getInput = input-                        }--{-|-  Creating a callback to update the mouse position's state.--}-makeMousePositionCallback :: WindowConfig -> InputContainer -> MousePosCallback-makeMousePositionCallback wc ic (Position x y) =-  mousePositionSinks (getSinks ic) $-    Vector (  fromIntegral x  / ((fromIntegral $ getWindowWidth  wc) / 2) - 1)-           ((-fromIntegral y) / ((fromIntegral $ getWindowHeight wc) / 2) + 1)--{-|-  Creating a callback to update the keyboard's states.--}-makeKeyboardCallback :: InputContainer -> KeyCallback-makeKeyboardCallback ic key state =-  keyboardSinks (getSinks ic) ! key $ case state of-    Press   -> True-    Release -> False--{-|-  Creating a callback to update the mouse buttons' states.--}-makeMouseCallback :: InputContainer -> MouseButtonCallback-makeMouseCallback ic button state =-  mouseSinks (getSinks ic) ! button $ case state of-    Press   -> True-    Release -> False+{-|
+  The backend to be used with the input.
+-}
+module FRP.Spice.Input.Backend where
+
+--------------------
+-- Global Imports --
+import Graphics.Rendering.OpenGL
+import Graphics.UI.GLFW as GLFW
+import FRP.Elerea.Param
+import Data.Map.Strict
+import Data.IORef
+
+-------------------
+-- Local Imports --
+import qualified FRP.Spice.Input.MousePosition as MousePosition
+import qualified FRP.Spice.Input.Keyboard      as Keyboard
+import qualified FRP.Spice.Input.Mouse         as Mouse
+import FRP.Spice.Config
+import FRP.Spice.Input
+import FRP.Spice.Math
+
+----------
+-- Code --
+
+{-|
+  A wrapper around the sinks for the mouse position, the key states, and the
+  mouse button states.
+-}
+data Sinks = Sinks { mousePositionSinks :: Vector Float -> IO ()
+                   , keyboardSinks      :: Map Key (Bool -> IO ())
+                   , mouseSinks         :: Map MouseButton (Bool -> IO ())
+                   }
+
+
+
+{-|
+  A container around @'Sinks'@ and @'Signal'@ @'Input'@ so that one needn't
+  pass around a tuple.
+-}
+data InputContainer = InputContainer { getSinks :: Sinks
+                                     , getInput :: Signal Input
+                                     }
+
+{-|
+  Making an @'InputContainer'@ filled with all necessary externals.
+-}
+makeInputContainer :: IO InputContainer
+makeInputContainer = do
+  mousePositionExternals <- MousePosition.externals
+  keyboardExternals      <- Keyboard.externals
+  mouseExternals         <- Mouse.externals
+
+  let sinks = Sinks { mousePositionSinks = MousePosition.sinks mousePositionExternals
+                    , keyboardSinks      = Keyboard.sinks keyboardExternals
+                    , mouseSinks         = Mouse.sinks mouseExternals
+                    }
+
+  let input = do mps <- fst mousePositionExternals
+                 kbs <- Keyboard.signals keyboardExternals
+                 ms  <- Mouse.signals mouseExternals
+
+                 return Input { mousePosition = mps
+                              , keyboard      = kbs
+                              , mouse         = ms
+                              }
+
+  return InputContainer { getSinks = sinks
+                        , getInput = input
+                        }
+
+{-|
+  Creating a callback to update the mouse position's state.
+-}
+makeMousePositionCallback :: InputContainer -> IORef (Vector Int) -> MousePosCallback
+makeMousePositionCallback ic wSizeRef (Position x y) = do
+  (Vector w h) <- readIORef wSizeRef
+  mousePositionSinks (getSinks ic) $
+    Vector (  fromIntegral x  / ((fromIntegral $ w) / 2) - 1)
+           ((-fromIntegral y) / ((fromIntegral $ h) / 2) + 1)
+
+{-|
+  Creating a callback to update the keyboard's states.
+-}
+makeKeyboardCallback :: InputContainer -> KeyCallback
+makeKeyboardCallback ic key state =
+  keyboardSinks (getSinks ic) ! key $ case state of
+    Press   -> True
+    Release -> False
+
+{-|
+  Creating a callback to update the mouse buttons' states.
+-}
+makeMouseCallback :: InputContainer -> MouseButtonCallback
+makeMouseCallback ic button state =
+  mouseSinks (getSinks ic) ! button $ case state of
+    Press   -> True
+    Release -> False
src/FRP/Spice/Input/Keyboard.hs view
@@ -1,40 +1,40 @@-{-|-  The keyboard specific section of input.--}-module FRP.Spice.Input.Keyboard where------------------------- Global Imports ---import qualified Data.Traversable as T-import Data.Map.Strict hiding (keys, map)-import Graphics.UI.GLFW as GLFW-import FRP.Elerea.Param-import Control.Monad--------------- Code ----{-|-  A list of all possible keys used in the GLFW API.--}-keys :: [Key]-keys = map toEnum [0 .. 318]--{-|-  A Map from @'Key'@ to the externals created for every single key.--}-externals :: IO (Map Key (Signal Bool, Bool -> IO ()))-externals = liftM fromList $ mapM (\k -> liftM ((,) k) $ external False) keys--{-|-  Creating the @'Signal'@ of a @'Map'@ from @'Key'@ to @'Bool'@ from a @'Map'@-  of @'externals'@.--}-signals :: Map Key (Signal Bool, Bool -> IO ()) -> Signal (Map Key Bool)-signals = T.sequence . fmap fst--{-|-  Making a @'Map'@ from @'Key'@ to sink from a @'Map'@ of @'externals'@.--}-sinks :: Map Key (Signal Bool, Bool -> IO ()) -> Map Key (Bool -> IO ())-sinks = fmap snd+{-|
+  The keyboard specific section of input.
+-}
+module FRP.Spice.Input.Keyboard where
+
+--------------------
+-- Global Imports --
+import qualified Data.Traversable as T
+import Data.Map.Strict hiding (keys, map)
+import Graphics.UI.GLFW as GLFW
+import FRP.Elerea.Param
+import Control.Monad
+
+----------
+-- Code --
+
+{-|
+  A list of all possible keys used in the GLFW API.
+-}
+keys :: [Key]
+keys = map toEnum [0 .. 318]
+
+{-|
+  A Map from @'Key'@ to the externals created for every single key.
+-}
+externals :: IO (Map Key (Signal Bool, Bool -> IO ()))
+externals = liftM fromList $ mapM (\k -> liftM ((,) k) $ external False) keys
+
+{-|
+  Creating the @'Signal'@ of a @'Map'@ from @'Key'@ to @'Bool'@ from a @'Map'@
+  of @'externals'@.
+-}
+signals :: Map Key (Signal Bool, Bool -> IO ()) -> Signal (Map Key Bool)
+signals = T.sequence . fmap fst
+
+{-|
+  Making a @'Map'@ from @'Key'@ to sink from a @'Map'@ of @'externals'@.
+-}
+sinks :: Map Key (Signal Bool, Bool -> IO ()) -> Map Key (Bool -> IO ())
+sinks = fmap snd
src/FRP/Spice/Input/Mouse.hs view
@@ -1,50 +1,50 @@-{-|-  The mouse (button) specific section of input.--}-module FRP.Spice.Input.Mouse where------------------------- Global Imports ---import qualified Data.Traversable as T (sequence)-import Data.Map.Strict hiding (keys, map)-import Graphics.UI.GLFW as GLFW-import FRP.Elerea.Param-import Control.Monad--------------- Code ------ Adding an instance of Ord to MouseButton so it can be used with the map-instance Ord MouseButton where-  mb1 <= mb2 = fromEnum mb1 < fromEnum mb2--{-|-  A list of all mouse buttons available via the GLFW api.--}-buttons :: [MouseButton]-buttons = [ ButtonLeft-          , ButtonRight-          , ButtonMiddle-          ]-          ++-          map ButtonNo [0 .. 7]--{-|-  A map from @'MouseButton'@ to externals created for every button.--}-externals :: IO (Map MouseButton (Signal Bool, Bool -> IO ()))-externals = liftM fromList $ mapM (\b -> liftM ((,) b) $ external False) buttons--{-|-  Creating the @'Signal'@ of a @'Map'@ from @'MouseButton'@ to @'Bool'@ from a-  @'Map'@ of @'externals'@.--}-signals :: Map MouseButton (Signal Bool, Bool -> IO ()) -> Signal (Map MouseButton Bool)-signals = T.sequence . fmap fst--{-|-  Making a @'Map'@ from @'MouseButton'@ to sink from a @'Map'@ of-  @'externals'@.--}-sinks :: Map MouseButton (Signal Bool, Bool -> IO ()) -> Map MouseButton (Bool -> IO ())-sinks = fmap snd+{-|
+  The mouse (button) specific section of input.
+-}
+module FRP.Spice.Input.Mouse where
+
+--------------------
+-- Global Imports --
+import qualified Data.Traversable as T (sequence)
+import Data.Map.Strict hiding (keys, map)
+import Graphics.UI.GLFW as GLFW
+import FRP.Elerea.Param
+import Control.Monad
+
+----------
+-- Code --
+
+-- Adding an instance of Ord to MouseButton so it can be used with the map
+instance Ord MouseButton where
+  mb1 <= mb2 = fromEnum mb1 < fromEnum mb2
+
+{-|
+  A list of all mouse buttons available via the GLFW api.
+-}
+buttons :: [MouseButton]
+buttons = [ ButtonLeft
+          , ButtonRight
+          , ButtonMiddle
+          ]
+          ++
+          map ButtonNo [0 .. 7]
+
+{-|
+  A map from @'MouseButton'@ to externals created for every button.
+-}
+externals :: IO (Map MouseButton (Signal Bool, Bool -> IO ()))
+externals = liftM fromList $ mapM (\b -> liftM ((,) b) $ external False) buttons
+
+{-|
+  Creating the @'Signal'@ of a @'Map'@ from @'MouseButton'@ to @'Bool'@ from a
+  @'Map'@ of @'externals'@.
+-}
+signals :: Map MouseButton (Signal Bool, Bool -> IO ()) -> Signal (Map MouseButton Bool)
+signals = T.sequence . fmap fst
+
+{-|
+  Making a @'Map'@ from @'MouseButton'@ to sink from a @'Map'@ of
+  @'externals'@.
+-}
+sinks :: Map MouseButton (Signal Bool, Bool -> IO ()) -> Map MouseButton (Bool -> IO ())
+sinks = fmap snd
src/FRP/Spice/Input/MousePosition.hs view
@@ -1,31 +1,31 @@-{-|-  The mouse (position) specific section of input.--}-module FRP.Spice.Input.MousePosition where------------------------- Global Imports ---import FRP.Elerea.Param-import Data.Default------------------------ Local Imports ---import FRP.Spice.Math.Vector--{-|-  Creating the external for the mouse position.--}-externals :: IO (Signal (Vector Float), Vector Float -> IO ())-externals = external def--{-|-  Getting the signal from the mouse position external.--}-signals :: (Signal (Vector Float), Vector Float -> IO ()) -> Signal (Vector Float)-signals = fst--{-|-  Getting the sink from the mouse position external.--}-sinks :: (Signal (Vector Float), Vector Float -> IO ()) -> Vector Float -> IO ()-sinks = snd+{-|
+  The mouse (position) specific section of input.
+-}
+module FRP.Spice.Input.MousePosition where
+
+--------------------
+-- Global Imports --
+import FRP.Elerea.Param
+import Data.Default
+
+-------------------
+-- Local Imports --
+import FRP.Spice.Math.Vector
+
+{-|
+  Creating the external for the mouse position.
+-}
+externals :: IO (Signal (Vector Float), Vector Float -> IO ())
+externals = external def
+
+{-|
+  Getting the signal from the mouse position external.
+-}
+signals :: (Signal (Vector Float), Vector Float -> IO ()) -> Signal (Vector Float)
+signals = fst
+
+{-|
+  Getting the sink from the mouse position external.
+-}
+sinks :: (Signal (Vector Float), Vector Float -> IO ()) -> Vector Float -> IO ()
+sinks = snd
src/FRP/Spice/Math.hs view
@@ -1,9 +1,9 @@-{-|-  This module re-exports a number of modules having to do with math.--}-module FRP.Spice.Math ( module FRP.Spice.Math.Vector-                      ) where---------------------------- Rexported Imports ---import FRP.Spice.Math.Vector+{-|
+  This module re-exports a number of modules having to do with math.
+-}
+module FRP.Spice.Math ( module FRP.Spice.Math.Vector
+                      ) where
+
+-----------------------
+-- Rexported Imports --
+import FRP.Spice.Math.Vector
src/FRP/Spice/Math/Vector.hs view
@@ -1,50 +1,50 @@-{-|-  This module provides a @'Vector'@ datatype as described below.--}-module FRP.Spice.Math.Vector where------------------------- Global Imports ---import Data.Default-import Data.Monoid--------------- Code ----{-|-  A datatype that houses two values of a given type. It is provided with a-  @'Num'@ instance so that, when used with number types it can function-  similarly (though not exactly) to a mathematical vector.--}-data Vector a = Vector a a--{-|-  The default for the @'Vector'@.--}-instance Default a => Default (Vector a) where-  def = Vector def def--{-|-  Displaying the @'Vector'@.--}-instance Show a => Show (Vector a) where-  show (Vector x y) = mconcat ["Vector ", show x, " ", show y]--{-|-  Performs operations on the matching fields of the other @'Vector'@.--}-instance Num a => Num (Vector a) where-  (Vector x1 y1) + (Vector x2 y2) = Vector (x1 + x2) (y1 + y2)-  (Vector x1 y1) * (Vector x2 y2) = Vector (x1 * x2) (y1 * y2)--  fromInteger n = Vector (fromInteger n) (fromInteger n)--  abs    (Vector x y) = Vector (abs    x) (abs    y)-  signum (Vector x y) = Vector (signum x) (signum y)-  negate (Vector x y) = Vector (negate x) (negate y)--{-|-  Maps over both values in the @'Vector'@--}-instance Functor Vector where-  fmap fn (Vector x y) = Vector (fn x) (fn y)+{-|
+  This module provides a @'Vector'@ datatype as described below.
+-}
+module FRP.Spice.Math.Vector where
+
+--------------------
+-- Global Imports --
+import Data.Default
+import Data.Monoid
+
+----------
+-- Code --
+
+{-|
+  A datatype that houses two values of a given type. It is provided with a
+  @'Num'@ instance so that, when used with number types it can function
+  similarly (though not exactly) to a mathematical vector.
+-}
+data Vector a = Vector a a
+
+{-|
+  The default for the @'Vector'@.
+-}
+instance Default a => Default (Vector a) where
+  def = Vector def def
+
+{-|
+  Displaying the @'Vector'@.
+-}
+instance Show a => Show (Vector a) where
+  show (Vector x y) = mconcat ["Vector ", show x, " ", show y]
+
+{-|
+  Performs operations on the matching fields of the other @'Vector'@.
+-}
+instance Num a => Num (Vector a) where
+  (Vector x1 y1) + (Vector x2 y2) = Vector (x1 + x2) (y1 + y2)
+  (Vector x1 y1) * (Vector x2 y2) = Vector (x1 * x2) (y1 * y2)
+
+  fromInteger n = Vector (fromInteger n) (fromInteger n)
+
+  abs    (Vector x y) = Vector (abs    x) (abs    y)
+  signum (Vector x y) = Vector (signum x) (signum y)
+  negate (Vector x y) = Vector (negate x) (negate y)
+
+{-|
+  Maps over both values in the @'Vector'@
+-}
+instance Functor Vector where
+  fmap fn (Vector x y) = Vector (fn x) (fn y)
+ src/test/Main.hs view
@@ -0,0 +1,78 @@+module Main where
+
+-------------
+-- Imports --
+import FRP.Spice.Graphics
+import FRP.Spice.Math
+import FRP.Spice
+
+import Data.Default
+
+----------
+-- Code --
+
+-- Some directions
+up, down, left, right :: Vector Float
+up    = Vector ( 0) ( 1)
+down  = Vector ( 0) (-1)
+left  = Vector (-1) ( 0)
+right = Vector ( 1) ( 0)
+
+-- The speed in which pos should move
+speedCfg :: Float
+speedCfg = 0.5
+
+-- The size rendered squares should take
+size :: Float
+size = 0.05
+
+-- Applying the speed to a vector
+speed :: DeltaTime -> Vector Float -> Vector Float
+speed dt vec = vec * Vector (speedCfg * dt) (speedCfg * dt)
+
+-- A basic game type
+data BasicGame = BasicGame { pos      :: Vector Float
+                           , mousePos :: Vector Float
+                           }
+
+-- Updating the game
+updatePos :: DeltaTime -> Input -> BasicGame -> BasicGame
+updatePos dt input game =
+  move dt game [ (keyboard input ! CharKey 'W', speed dt up   )
+               , (keyboard input ! CharKey 'S', speed dt down )
+               , (keyboard input ! CharKey 'A', speed dt left )
+               , (keyboard input ! CharKey 'D', speed dt right)
+               ]
+  where move :: DeltaTime -> BasicGame -> [(Bool, Vector Float)] -> BasicGame
+        move dt game                   []              = game
+        move dt game@(BasicGame pos _) ((True , d):xs) = move dt (game { pos = pos + d }) xs
+        move dt game                   ((False, _):xs) = move dt game xs
+
+-- Updating the mouse position
+updateMousePosition :: Input -> BasicGame -> BasicGame
+updateMousePosition input game@(BasicGame _ mousePos) =
+  game { mousePos = mousePosition input }
+
+updateGame :: DeltaTime -> Input -> BasicGame -> BasicGame
+updateGame dt input game = updateMousePosition input $ updatePos dt input game
+
+-- Rendering the game
+renderGame :: BasicGame -> Scene
+renderGame (BasicGame pos mousePos) = do
+  bindColor $ color3i 0 0 255
+  renderRectangle ((mousePos * Vector 0 1) - (Vector 1 0)) $ Vector 2 2
+
+  bindColor $ color3i 255 0 0
+  renderSquare pos      size
+
+  bindColor $ color3i 0 255 0
+  renderSquare mousePos size
+
+-- Giving BasicGame a Game instance.
+instance Game BasicGame where
+  update dt input game = updateGame dt input game
+  render          game = renderGame game
+
+-- Starting the game
+main :: IO ()
+main = startEngine defaultWindowConfig $ BasicGame def def