packages feed

spice 0.3.3.2 → 0.4.0.0

raw patch · 27 files changed

+1177/−1017 lines, 27 filesdep +JuicyPixelsdep +JuicyPixels-repadep +bytestringsetup-changedPVP ok

version bump matches the API change (PVP)

Dependencies added: JuicyPixels, JuicyPixels-repa, bytestring

API changes (from Hackage documentation)

- FRP.Spice.Graphics: fromElements :: [Element] -> Scene
- FRP.Spice.Graphics: renderScene :: Scene -> IO ()
+ FRP.Spice: Assets :: Map FilePath Sprite -> Assets
+ FRP.Spice: LoadSprite :: FilePath -> LoadAsset
+ FRP.Spice: appendSprite :: Assets -> FilePath -> Sprite -> Assets
+ FRP.Spice: data Assets
+ FRP.Spice: data LoadAsset
+ FRP.Spice: defaultAssets :: Assets
+ FRP.Spice: loadAssets :: Game a => a -> LoadAssets
+ FRP.Spice: loadSpriteAsset :: FilePath -> LoadAssets
+ FRP.Spice: performAssetLoads :: LoadAssets -> IO Assets
+ FRP.Spice: sprites :: Assets -> Map FilePath Sprite
+ FRP.Spice: type LoadAssets = DoList [LoadAsset]
+ FRP.Spice.Graphics: Sprite :: TextureObject -> Vector Float -> Sprite
+ FRP.Spice.Graphics: data Sprite
+ FRP.Spice.Graphics: fromgl :: GLfloat -> Float
+ FRP.Spice.Graphics: loadSprite :: FilePath -> IO Sprite
+ FRP.Spice.Graphics: renderLine :: Vector Float -> Vector Float -> Scene
+ FRP.Spice.Graphics: renderPolygon :: [Vector Float] -> Scene
+ FRP.Spice.Graphics: renderSprite :: Sprite -> Vector Float -> Scene
+ FRP.Spice.Graphics: renderTriangle :: Vector Float -> Vector Float -> Vector Float -> Scene
+ FRP.Spice.Graphics: spriteSize :: Sprite -> Vector Float
+ FRP.Spice.Graphics: spriteTex :: Sprite -> TextureObject
- FRP.Spice: render :: Game a => a -> Scene
+ FRP.Spice: render :: Game a => Assets -> a -> Scene
- FRP.Spice.Graphics: type Scene = DoList [Element]
+ FRP.Spice.Graphics: type Scene = IO ()

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,51 +1,55 @@-name:                spice-version:             0.3.3.2-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-                       FRP.Spice.Utils.DoList--  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.4.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.Assets
+                       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.Scene
+                       FRP.Spice.Graphics.Sprite
+                       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
+                       FRP.Spice.Utils.DoList
+
+  hs-source-dirs:      src/
+
+  build-depends:       base              == 4.7.*
+               ,       elerea            == 2.7.*
+               ,       GLFW              == 0.5.*
+               ,       containers        == 0.5.*
+               ,       data-default      == 0.5.*
+               ,       bytestring        == 0.10.*
+               ,       JuicyPixels       == 3.1.*
+               ,       JuicyPixels-repa  == 0.7.*
+               ,       OpenGL
+
+  default-language:    Haskell2010
src/FRP/Spice.hs view
@@ -1,22 +1,24 @@-{-|-  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.Assets
+                 , 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.Assets
+import FRP.Spice.Config
+import FRP.Spice.Engine
+import FRP.Spice.Input
+import FRP.Spice.Game
+ src/FRP/Spice/Assets.hs view
@@ -0,0 +1,71 @@+{-|
+  This module provides a clean way to load assets that will later be used in
+  the spice-based program.
+-}
+module FRP.Spice.Assets where
+
+--------------------
+-- Global Imports --
+import qualified Data.Map.Strict as Map
+import Control.Monad
+import Data.Default
+
+-------------------
+-- Local Imports --
+import FRP.Spice.Graphics.Sprite
+import FRP.Spice.Utils.DoList
+
+----------
+-- Code --
+
+{-|
+  A single call to load an asset.
+-}
+data LoadAsset = LoadSprite FilePath
+
+{-|
+  A list of @'LoadAssets'@ that may be composed in do-notation.
+-}
+type LoadAssets = DoList [LoadAsset]
+
+{-|
+  The data structure that contains the loaded assets.
+-}
+data Assets = Assets { sprites :: Map.Map FilePath Sprite }
+
+{-|
+  The default state for the @'Assets'@ data type. Used as the initial state for
+  @'performAssetLoads'@.
+-}
+defaultAssets :: Assets
+defaultAssets =
+  Assets { sprites = Map.fromList [] }
+
+{-|
+  A synonym for @'defaultAssets'@ to fit within the data-default library.
+-}
+instance Default Assets where
+  def = defaultAssets
+
+{-|
+  Appending a @'Sprite'@ to an @'Assets'@.
+-}
+appendSprite :: Assets -> FilePath -> Sprite -> Assets
+appendSprite assets path sprite =
+  assets { sprites = Map.insert path sprite $ sprites assets }
+
+{-|
+  Performing the actual loading upon a @'LoadAssets'@.
+-}
+performAssetLoads :: LoadAssets -> IO Assets
+performAssetLoads la =
+  performAssetLoads' (values la) defaultAssets
+  where performAssetLoads' :: [LoadAsset] -> Assets -> IO Assets
+        performAssetLoads' []                   assets = return assets
+        performAssetLoads' (LoadSprite path:xs) assets = (liftM (appendSprite assets path) $ loadSprite path) >>= performAssetLoads' xs
+
+{-|
+  Loading a @'Sprite'@ asset.
+-}
+loadSpriteAsset :: FilePath -> LoadAssets
+loadSpriteAsset = fromValues . return . LoadSprite
src/FRP/Spice/Config.hs view
@@ -1,44 +1,44 @@-{-|-  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-  > getWindowTitle      = "Spice Application"--}-defaultWindowConfig :: WindowConfig-defaultWindowConfig = WindowConfig { getWindowWidth      = 640-                                   , getWindowHeight     = 480-                                   , getWindowFullscreen = False-                                   , getWindowTitle      = "Spice Application"-                                   }--{-|-  A default instance for @'WindowConfig'@. Equivalent to calling-  @'defaultWindowConfig'@.--}-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
+  > getWindowTitle      = "Spice Application"
+-}
+defaultWindowConfig :: WindowConfig
+defaultWindowConfig = WindowConfig { getWindowWidth      = 640
+                                   , getWindowHeight     = 480
+                                   , getWindowFullscreen = False
+                                   , getWindowTitle      = "Spice Application"
+                                   }
+
+{-|
+  A default instance for @'WindowConfig'@. Equivalent to calling
+  @'defaultWindowConfig'@.
+-}
+instance Default WindowConfig where
+  def = defaultWindowConfig
src/FRP/Spice/Engine.hs view
@@ -1,86 +1,90 @@-{-|-  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+{-|
+  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.Assets
+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
+
+  -- Loading the assets
+  assets <- performAssetLoads $ loadAssets game
+
+  -- 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 assets network $ runInput closed
+
+  -- Closing the window, after all is said and done
+  closeWindow
src/FRP/Spice/Engine/Driver.hs view
@@ -1,26 +1,27 @@-{-|-  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 ()+{-|
+  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.Assets
+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 => Assets -> (Float -> IO a) -> IO (Maybe Float) -> IO ()
+driveNetwork assets network iomdriver = do
+  mdriver <- iomdriver
+
+  case mdriver of
+    Just driver -> do state <- network driver
+                      renderWrapper $ render assets state
+                      driveNetwork assets network iomdriver
+    Nothing     -> return ()
src/FRP/Spice/Engine/Network.hs view
@@ -1,31 +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.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+{-|
+  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]
+
+  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+{-|
+  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,29 @@-{-|-  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.Assets
+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 :: Assets -> a -> Scene
+  loadAssets :: a -> LoadAssets
src/FRP/Spice/Graphics.hs view
@@ -1,15 +1,17 @@-{-|-  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+{-|
+  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.Sprite
+                          , 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.Sprite
+import FRP.Spice.Graphics.Color
+import FRP.Spice.Graphics.Scene
+import FRP.Spice.Graphics.Utils
src/FRP/Spice/Graphics/Color.hs view
@@ -1,92 +1,99 @@-{-|-  This module provides an abstraction over the default representations of color-  in the Haskell OpenGL bindings.--}-module FRP.Spice.Graphics.Color where------------------------ Local Imports ---import FRP.Spice.Graphics.Element-import FRP.Spice.Graphics.Scene--------------- 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+{-|
+  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.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) =
+  color $ Color4 (togl r) (togl g) (togl b) (togl 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
@@ -1,41 +0,0 @@-{-|-  This module provides a unified API for specifying every kind of rendering-  datatype and how they get rendered. All of this -- of course -- is only in-  the scope the spice project.--}-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]-             | RenderSprite (Vector Float) (Vector Float) 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 (RenderSprite pos size rot) = return ()-renderElement (SetColor r g b a) =-  color $ Color4 (togl r) (togl g) (togl b) (togl a)
src/FRP/Spice/Graphics/Geometry.hs view
@@ -1,74 +1,76 @@-{-|-  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------------------------ Local Imports ---import FRP.Spice.Graphics.Element-import FRP.Spice.Graphics.Scene-import FRP.Spice.Math.Vector--------------- Code ----{-|-  Rendering a point.--}-renderPoint :: Vector Float -> Scene-renderPoint pos =-  fromElements [RenderPrimitive Points [pos]]--{-|-  Rendering a line between two points.--}-renderLine :: Vector Float -> Vector Float -> Scene-renderLine p1 p2 =-  fromElements [ RenderPrimitive Lines [ p1-                                       , p2-                                       ]-               ]--{-|-  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--{-|-  Rendering a triangle.--}-renderTriangle :: Vector Float -> Vector Float -> Vector Float -> Scene-renderTriangle p1 p2 p3 =-  fromElements [ RenderPrimitive Triangles [ p1-                                           , p2-                                           , p3-                                           ]-               ]--{-|-  Rendering a polygon with 1-N vertecies.--}-renderPolygon :: [Vector Float] -> Scene-renderPolygon l =-  fromElements [RenderPrimitive Polygon l]+{-|
+  This module provides a cleaner API to render a number of shapes in the
+  current OpenGL context.
+-}
+module FRP.Spice.Graphics.Geometry ( renderPoint
+                                   , renderLine
+                                   , renderRectangle
+                                   , renderSquare
+                                   , renderTriangle
+                                   , renderPolygon
+                                   ) where
+
+--------------------
+-- Global Imports --
+import Graphics.Rendering.OpenGL
+import Control.Monad
+
+-------------------
+-- Local Imports --
+import FRP.Spice.Graphics.Scene
+import FRP.Spice.Graphics.Utils
+import FRP.Spice.Math.Vector
+
+----------
+-- Code --
+
+{-|
+  A version of @'renderPrimitive'@ where it takes a list of @'Vector'@
+  @'Float'@s instead of performing @'vertex'@ calls.
+-}
+renderPrimitive' :: PrimitiveMode -> [Vector Float] -> Scene
+renderPrimitive' mode points =
+  renderPrimitive mode $
+    forM_ points $ \(Vector x y) ->
+      vertex $ Vertex2 (togl x) (togl y)
+
+{-|
+  Rendering a point.
+-}
+renderPoint :: Vector Float -> Scene
+renderPoint pos = renderPrimitive' Points [pos]
+
+{-|
+  Rendering a line between two points.
+-}
+renderLine :: Vector Float -> Vector Float -> Scene
+renderLine p1 p2 = renderPrimitive' Lines [p1, p2]
+
+{-|
+  Rendering a rectangle.
+-}
+renderRectangle :: Vector Float -> Vector Float -> Scene
+renderRectangle (Vector x y) (Vector w h) =
+  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
+
+{-|
+  Rendering a triangle.
+-}
+renderTriangle :: Vector Float -> Vector Float -> Vector Float -> Scene
+renderTriangle p1 p2 p3 = renderPrimitive' Triangles [p1, p2, p3]
+
+{-|
+  Rendering a polygon with 1-N vertecies.
+-}
+renderPolygon :: [Vector Float] -> Scene
+renderPolygon l = renderPrimitive' Polygon l
src/FRP/Spice/Graphics/Scene.hs view
@@ -1,24 +1,13 @@-{-|-  This module provides an API to compose @'Scene'@s through do-notation.--}-module FRP.Spice.Graphics.Scene where------------------------ Local Imports ---import FRP.Spice.Graphics.Element-import FRP.Spice.Utils.DoList--------------- Code ----{-|-  A DoList to compose a list of @'Element'@s to render using do-notation.--}-type Scene = DoList [Element]--fromElements :: [Element] -> Scene-fromElements = fromValues--renderScene :: Scene -> IO ()-renderScene scene =-  mapM_ renderElement $ values scene+{-|
+  This module provides an API to compose @'Scene'@s through do-notation.
+-}
+module FRP.Spice.Graphics.Scene where
+
+----------
+-- Code --
+
+{-|
+  A type synonym for a single IO () call to suggest that users should be
+  *rendering* in render calls, and not performing other IO.
+-}
+type Scene = IO ()
+ src/FRP/Spice/Graphics/Sprite.hs view
@@ -0,0 +1,111 @@+{-|
+  This module provides an API for loading and rendering textures in the form
+  of @'Sprite'@s.
+-}
+module FRP.Spice.Graphics.Sprite ( Sprite (..)
+                                 , renderSprite
+                                 , loadSprite
+                                 ) where
+
+--------------------
+-- Global Imports --
+import Graphics.Rendering.OpenGL
+import Data.ByteString.Unsafe
+import Control.Applicative
+import Codec.Picture.Repa
+import Codec.Picture
+import Control.Monad
+import Foreign.Ptr
+
+-------------------
+-- Local Imports --
+import FRP.Spice.Graphics.Color
+import FRP.Spice.Graphics.Scene
+import FRP.Spice.Graphics.Utils
+import FRP.Spice.Math
+
+----------
+-- Code --
+
+{-|
+  Getting the size from a @'DynamicImage'@.
+-}
+getInfo :: DynamicImage -> (Int, Int, PixelInternalFormat)
+getInfo (ImageRGB8   (Image w h _)) = (w, h, RGB8)
+getInfo (ImageRGB16  (Image w h _)) = (w, h, RGB16)
+getInfo (ImageRGBA8  (Image w h _)) = (w, h, RGBA8)
+getInfo (ImageRGBA16 (Image w h _)) = (w, h, RGBA16)
+
+{-|
+  Loading a @'TextureObject'@ and @'Size'@ from any RGB8, RGB16, RGBA8, or
+  RGBA16 images.
+-}
+loadTex :: FilePath -> IO (TextureObject, Size)
+loadTex path = do
+  img <- either error id <$> readImageRGBA path
+
+  let dynimg         = imgToImage img
+      (w, h, format) = getInfo dynimg
+      glSize         = TextureSize2D (fromIntegral w) (fromIntegral h)
+      bs             = toByteString img
+
+  ptr <- unsafeUseAsCString bs $ \cstr ->
+    return $ castPtr cstr
+
+  [t] <- genObjectNames 1
+
+  textureBinding Texture2D $= Just t
+  texImage2D Texture2D NoProxy 0 format glSize 0 (PixelData ABGR UnsignedByte ptr)
+
+  return (t, Size (fromIntegral w) (fromIntegral h))
+
+{-|
+  A datatype to represent a @'TextureObject'@ through a reference to the
+  @'TextureObject'@ itself and its @'Size'@.
+-}
+data Sprite = Sprite { spriteTex   :: TextureObject
+                     , spriteSize  :: Vector Float
+                     }
+
+{-|
+  Performing an OpenGL call to render the @'Sprite'@.
+-}
+renderSprite :: Sprite -> Vector Float -> Scene
+renderSprite sprite pos = do
+  textureWrapMode Texture2D S $= (Repeated, ClampToEdge)
+  textureWrapMode Texture2D T $= (Repeated, ClampToEdge)
+  textureFilter   Texture2D   $= ((Linear', Nothing), Linear')
+  textureFunction             $= Replace
+
+  texture        Texture2D $= Enabled
+  textureBinding Texture2D $= (Just $ spriteTex sprite)
+
+  renderPrimitive Quads $
+    forM_ (generateCoords pos $ spriteSize sprite) $ \(Vector x y, Vector tx ty) -> do
+      texCoord $ TexCoord2 (togl tx) (togl ty)
+      vertex $ Vertex2 (togl x) (togl y)
+
+  texture Texture2D        $= Disabled
+  where generateCoords :: Vector Float -> Vector Float -> [(Vector Float, Vector Float)]
+        generateCoords (Vector x y) (Vector w h) =
+          [ (Vector (x    ) (y    ), Vector 0 0)
+          , (Vector (x + w) (y    ), Vector 1 0)
+          , (Vector (x + w) (y + h), Vector 1 1)
+          , (Vector (x    ) (y + h), Vector 0 1)
+          ]
+
+{-|
+  Creating a @'Sprite'@ from a @'TextureObject'@.
+-}
+makeSprite :: (TextureObject, Size) -> Sprite
+makeSprite (to, (Size w h)) =
+  Sprite { spriteTex   = to
+         , spriteSize  = size
+         }
+  where size = Vector ((fromIntegral w) / 640) ((fromIntegral h) / 480)
+
+{-|
+  Loading a @'Sprite'@ from a file.
+-}
+loadSprite :: FilePath -> IO Sprite
+loadSprite = liftM makeSprite . loadTex
src/FRP/Spice/Graphics/Utils.hs view
@@ -1,18 +1,24 @@-{-|-  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
+
+{-|
+  Converting a @'GLfloat'@ to a @'Float'@.
+-}
+fromgl :: GLfloat -> Float
+fromgl = 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,97 +1,97 @@-{-|-  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.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+{-|
+  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.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,52 +1,52 @@-{-|-  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,64 +1,64 @@-{-|-  This module provides a @'Vector'@ datatype as described below.--}-module FRP.Spice.Math.Vector where------------------------- Global Imports ---import Control.Applicative-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)--{-|-  Applicative instance for @'Vector'@.--}-instance Applicative Vector where-  pure a = Vector a a-  (Vector fn _) <*> (Vector x y) = Vector (fn x) (fn y)--{-|-  Multiplying @'Vector'@ by a scalar value.--}-scalar :: Num a => Vector a -> a -> Vector a-scalar (Vector x y) n = Vector (x * n) (y * n)+{-|
+  This module provides a @'Vector'@ datatype as described below.
+-}
+module FRP.Spice.Math.Vector where
+
+--------------------
+-- Global Imports --
+import Control.Applicative
+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)
+
+{-|
+  Applicative instance for @'Vector'@.
+-}
+instance Applicative Vector where
+  pure a = Vector a a
+  (Vector fn _) <*> (Vector x y) = Vector (fn x) (fn y)
+
+{-|
+  Multiplying @'Vector'@ by a scalar value.
+-}
+scalar :: Num a => Vector a -> a -> Vector a
+scalar (Vector x y) n = Vector (x * n) (y * n)
src/FRP/Spice/Utils/DoList.hs view
@@ -1,63 +1,63 @@-{-|-  This module provides a list that can be composed and concatenated through-  do-notation.----}-module FRP.Spice.Utils.DoList where------------------------- Global Imports ---import Control.Applicative-import Data.Monoid--------------- Code ----{-|-  The datastructure itself. Almost equivalent to a tuple of length 2 without-  and more context.--}-data DoListT a b = DoListT a b--{-|-  A more commonly used synonym for DoListT--}-type DoList a = DoListT a ()--{-|-  Getting the elements from a @'DoListT'@.--}-values :: DoListT a b -> a-values (DoListT a _) = a--{-|-  Constructing a do-list from a @'Monoid'@.--}-fromValues :: Monoid a => a -> DoListT a ()-fromValues a = DoListT a ()--{-|-  A functor instance to satisfy @'Applicative'@'s requirements.--}-instance Functor (DoListT a) where-  fmap fn (DoListT a b) =-    DoListT a $ fn b--{-|-  An applicative instance to satisfy @'Monad'@'s requirements.--}-instance Monoid a => Applicative (DoListT a) where-  pure b = DoListT mempty b-  (DoListT _ fn) <*> dl = fmap fn dl--{-|-  A monad instance to perform the actual composition of the list. List is a-  loose word seeing as the monad instance simply needs an instance of-  @'Monoid'@.--}-instance Monoid a => Monad (DoListT a) where-  return = pure-  (DoListT a b) >>= fn =-    let (DoListT a' b') = fn b in-      DoListT (mappend a a') b'+{-|
+  This module provides a list that can be composed and concatenated through
+  do-notation.
+
+
+-}
+module FRP.Spice.Utils.DoList where
+
+--------------------
+-- Global Imports --
+import Control.Applicative
+import Data.Monoid
+
+----------
+-- Code --
+
+{-|
+  The datastructure itself. Almost equivalent to a tuple of length 2 without
+  and more context.
+-}
+data DoListT a b = DoListT a b
+
+{-|
+  A more commonly used synonym for DoListT
+-}
+type DoList a = DoListT a ()
+
+{-|
+  Getting the elements from a @'DoListT'@.
+-}
+values :: DoListT a b -> a
+values (DoListT a _) = a
+
+{-|
+  Constructing a do-list from a @'Monoid'@.
+-}
+fromValues :: Monoid a => a -> DoListT a ()
+fromValues a = DoListT a ()
+
+{-|
+  A functor instance to satisfy @'Applicative'@'s requirements.
+-}
+instance Functor (DoListT a) where
+  fmap fn (DoListT a b) =
+    DoListT a $ fn b
+
+{-|
+  An applicative instance to satisfy @'Monad'@'s requirements.
+-}
+instance Monoid a => Applicative (DoListT a) where
+  pure b = DoListT mempty b
+  (DoListT _ fn) <*> dl = fmap fn dl
+
+{-|
+  A monad instance to perform the actual composition of the list. List is a
+  loose word seeing as the monad instance simply needs an instance of
+  @'Monoid'@.
+-}
+instance Monoid a => Monad (DoListT a) where
+  return = pure
+  (DoListT a b) >>= fn =
+    let (DoListT a' b') = fn b in
+      DoListT (mappend a a') b'