spice 0.2.0.0 → 0.3.0.0
raw patch · 10 files changed
+200/−147 lines, 10 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- FRP.Spice: InputContainer :: Sinks -> Signal Input -> InputContainer
- FRP.Spice: Sinks :: (Vector Float -> IO ()) -> Map Key (Bool -> IO ()) -> Map MouseButton (Bool -> IO ()) -> Sinks
- FRP.Spice: data InputContainer
- FRP.Spice: data Sinks
- FRP.Spice: getInput :: InputContainer -> Signal Input
- FRP.Spice: getSinks :: InputContainer -> Sinks
- FRP.Spice: keyboardSinks :: Sinks -> Map Key (Bool -> IO ())
- FRP.Spice: makeInputContainer :: IO InputContainer
- FRP.Spice: makeKeyboardCallback :: InputContainer -> KeyCallback
- FRP.Spice: makeMouseCallback :: InputContainer -> MouseButtonCallback
- FRP.Spice: makeMousePositionCallback :: WindowConfig -> InputContainer -> MousePosCallback
- FRP.Spice: mousePositionSinks :: Sinks -> Vector Float -> IO ()
- FRP.Spice: mouseSinks :: Sinks -> Map MouseButton (Bool -> IO ())
- FRP.Spice.Graphics: Element :: PrimitiveMode -> [Vector Float] -> Element
- FRP.Spice.Graphics: SceneT :: [Element] -> a -> SceneT a
- FRP.Spice.Graphics: bindColor :: Color -> IO ()
- FRP.Spice.Graphics: data Element
- FRP.Spice.Graphics: data SceneT a
- FRP.Spice.Graphics: fromElements :: [Element] -> Scene
- FRP.Spice.Graphics: renderElement :: Element -> IO ()
+ 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: black :: Color
+ FRP.Spice.Graphics: black :: Scene
- FRP.Spice.Graphics: blue :: Color
+ FRP.Spice.Graphics: blue :: Scene
- FRP.Spice.Graphics: color3f :: Float -> Float -> Float -> Color
+ FRP.Spice.Graphics: color3f :: Float -> Float -> Float -> Scene
- FRP.Spice.Graphics: color3i :: Int -> Int -> Int -> Color
+ FRP.Spice.Graphics: color3i :: Int -> Int -> Int -> Scene
- FRP.Spice.Graphics: color4f :: Float -> Float -> Float -> Float -> Color
+ FRP.Spice.Graphics: color4f :: Float -> Float -> Float -> Float -> Scene
- FRP.Spice.Graphics: color4i :: Int -> Int -> Int -> Int -> Color
+ FRP.Spice.Graphics: color4i :: Int -> Int -> Int -> Int -> Scene
- FRP.Spice.Graphics: green :: Color
+ FRP.Spice.Graphics: green :: Scene
- FRP.Spice.Graphics: red :: Color
+ FRP.Spice.Graphics: red :: Scene
- FRP.Spice.Graphics: white :: Color
+ FRP.Spice.Graphics: white :: Scene
Files
- spice.cabal +3/−1
- src/FRP/Spice.hs +7/−1
- src/FRP/Spice/Engine.hs +1/−1
- src/FRP/Spice/Graphics.hs +3/−1
- src/FRP/Spice/Graphics/Color.hs +17/−14
- src/FRP/Spice/Graphics/Geometry.hs +30/−4
- src/FRP/Spice/Graphics/Renderable.hs +22/−0
- src/FRP/Spice/Graphics/Scene.hs +17/−31
- src/FRP/Spice/Input.hs +4/−94
- src/FRP/Spice/Input/Backend.hs +96/−0
spice.cabal view
@@ -1,5 +1,5 @@ name: spice-version: 0.2.0.0+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@@ -28,9 +28,11 @@ 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
src/FRP/Spice.hs view
@@ -2,7 +2,10 @@ 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 FRP.Spice.Config+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@@ -10,6 +13,9 @@ ----------------------- -- 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
src/FRP/Spice/Engine.hs view
@@ -16,8 +16,8 @@ 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.Input import FRP.Spice.Game ----------
src/FRP/Spice/Graphics.hs view
@@ -1,7 +1,8 @@ {-| 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 ( 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@@ -9,6 +10,7 @@ ----------------------- -- Rexported Imports --+import FRP.Spice.Graphics.Renderable import FRP.Spice.Graphics.Geometry import FRP.Spice.Graphics.Color import FRP.Spice.Graphics.Scene
src/FRP/Spice/Graphics/Color.hs view
@@ -10,6 +10,8 @@ ------------------- -- Local Imports --+import FRP.Spice.Graphics.Renderable+import FRP.Spice.Graphics.Scene import FRP.Spice.Graphics.Utils ----------@@ -28,23 +30,24 @@ deriving (Eq, Show, Read) {-|- Changes the current OpenGL context's rendering color to the @'Color'@+ Changing the current OpenGL context's @'Color4'@ to whatever @'Color'@ specified. -}-bindColor :: Color -> IO ()-bindColor (Color r g b a) =- color $ Color4 (togl r) (togl g) (togl b) (togl a)+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 -> Color-color4f = Color+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 -> Color+color3f :: Float -> Float -> Float -> Scene color3f r g b = color4f r g b 1.0 {-|@@ -54,7 +57,7 @@ also equivalent in source code) to calling color4f with each of its arguments divided by 255.) -}-color4i :: Int -> Int -> Int -> Int -> Color+color4i :: Int -> Int -> Int -> Int -> Scene color4i r g b a = color4f (fromIntegral r / 255) (fromIntegral g / 255) (fromIntegral b / 255)@@ -63,35 +66,35 @@ {-| Constructing a @'Color'@ from 3 @'Int'@s, defaulting the alpha mask to 255. -}-color3i :: Int -> Int -> Int -> Color+color3i :: Int -> Int -> Int -> Scene color3i r g b = color4i r g b 255 {-| The color black. -}-black :: Color+black :: Scene black = color3i 0 0 0 {-| The color white. -}-white :: Color+white :: Scene white = color3i 255 255 255 {-| The color red. -}-red :: Color+red :: Scene red = color3i 255 0 0 {-| The color green. -}-green :: Color+green :: Scene green = color3i 0 255 0 {-| The color blue. -}-blue :: Color+blue :: Scene blue = color3i 0 0 255
src/FRP/Spice/Graphics/Geometry.hs view
@@ -2,14 +2,23 @@ This module provides a cleaner API to render a number of shapes in the current OpenGL context. -}-module FRP.Spice.Graphics.Geometry where+module FRP.Spice.Graphics.Geometry ( renderPoint+ , renderRectangle+ , renderSquare+ ) where -------------------- -- Global Imports ---import Graphics.Rendering.OpenGL+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@@ -18,18 +27,35 @@ -- 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 =- fromElements [Element Points [pos]]+ fromRenderables [Primitive Points [pos]] {-| Rendering a rectangle. -} renderRectangle :: Vector Float -> Vector Float -> Scene renderRectangle (Vector x y) (Vector w h) = do- fromElements [ Element Quads [ Vector (x ) (y )+ fromRenderables [ Primitive Quads [ Vector (x ) (y ) , Vector (x + w) (y ) , Vector (x + w) (y + h) , Vector (x ) (y + h)
+ src/FRP/Spice/Graphics/Renderable.hs view
@@ -0,0 +1,22 @@+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,29 +1,24 @@-module FRP.Spice.Graphics.Scene where+module FRP.Spice.Graphics.Scene ( Scene+ , fromRenderables+ , renderScene+ ) where -------------------- -- Global Imports ---import Graphics.Rendering.OpenGL import Control.Applicative import Control.Monad ------------------- -- Local Imports ---import FRP.Spice.Graphics.Utils-import FRP.Spice.Math.Vector+import FRP.Spice.Graphics.Renderable ---------- -- Code -- {-|- Purely specifying the rendering behavior of a single element. To be composed- into @'FRP.Spice.Graphics.Scene'@s for a full rendering effect.--}-data Element = Element PrimitiveMode [Vector Float]--{-|- For composing a scene out of a set of elements.+ For composing a scene out of a set of renderables. -}-data SceneT a = SceneT [Element] a+data SceneT a = SceneT [Render] a {-| The commonly used instance of SceneT@@ -34,7 +29,7 @@ Functor instance to satisfy applicative instance. -} instance Functor SceneT where- fmap fn (SceneT elements v) = SceneT elements $ fn v+ fmap fn (SceneT renderables v) = SceneT renderables $ fn v {-| Applicative instance to satisfy the monad instance. Not advised to use@@ -49,30 +44,21 @@ -} instance Monad SceneT where return a = SceneT [] a- (SceneT elements v) >>= fn =- let (SceneT elements' v') = fn v in- SceneT (elements ++ elements') v'--{-|- Rendering a single @'Element'@.--}-renderElement :: Element -> IO ()-renderElement (Element pm vs) =- renderPrimitive pm $- forM_ vs $ \(Vector x y) ->- vertex $ Vertex2 (togl x) (togl y)+ (SceneT renderables v) >>= fn =+ let (SceneT renderables' v') = fn v in+ SceneT (renderables ++ renderables') v' {-|- Constructing a SceneT from a list of elements.+ Constructing a SceneT from a list of renderables. -}-fromElements :: [Element] -> Scene-fromElements elements =- SceneT elements ()+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 elements _) =- forM_ elements renderElement+renderScene (SceneT renderables _) =+ forM_ renderables runRender
src/FRP/Spice/Input.hs view
@@ -1,49 +1,21 @@ {-| This module provides everything relating to input in the scope of spice. -}-module FRP.Spice.Input ( module Rexport- , Sinks (..)- , Input (..)- , InputContainer (..)- , makeInputContainer- , makeMousePositionCallback- , makeKeyboardCallback- , makeMouseCallback- ) where+module FRP.Spice.Input where -------------------- -- Global Imports ---import Data.Map.Strict hiding (keys, map)-import Graphics.Rendering.OpenGL-import Graphics.UI.GLFW as GLFW-import FRP.Elerea.Param+import Graphics.UI.GLFW+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.Math.Vector-import FRP.Spice.Config---------------------------- Rexported Imports ---import Data.Map.Strict as Rexport ((!))-import Graphics.UI.GLFW as Rexport (Key (..), SpecialKey (..), MouseButton (..))+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 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).@@ -52,65 +24,3 @@ , keyboard :: Map Key Bool , mouse :: Map MouseButton Bool }--{-|- 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
+ src/FRP/Spice/Input/Backend.hs view
@@ -0,0 +1,96 @@+{-|+ 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