aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2024-12-30 19:14:12 -0800
committer3gg <3gg@shellblade.net>2024-12-30 19:14:12 -0800
commitf1939232bec72fffede16a55119bc7c4fb3057cf (patch)
tree379a8268ff765023527bbf0a4e2088396dba5f84
parent34cac097d15cdd7ef0a0de8b9024db9acfe8618d (diff)
Simplify Game monad.
-rw-r--r--Demos/Pong/Main.hs18
-rw-r--r--Spear/App.hs26
-rw-r--r--Spear/Assets/Image.hsc18
-rw-r--r--Spear/Assets/Model.hsc60
-rw-r--r--Spear/GL.hs42
-rw-r--r--Spear/Game.hs172
-rw-r--r--Spear/Render/AnimatedModel.hs13
-rw-r--r--Spear/Render/Core/Buffer.hs10
-rw-r--r--Spear/Render/Core/Geometry.hs12
-rw-r--r--Spear/Render/Core/Shader.hs32
-rw-r--r--Spear/Render/Core/State.hs8
-rw-r--r--Spear/Render/Immediate.hs38
-rw-r--r--Spear/Render/StaticModel.hs13
-rw-r--r--Spear/Scene/Loader.hs14
-rw-r--r--Spear/Window.hs6
15 files changed, 238 insertions, 244 deletions
diff --git a/Demos/Pong/Main.hs b/Demos/Pong/Main.hs
index de8e6f2..df90020 100644
--- a/Demos/Pong/Main.hs
+++ b/Demos/Pong/Main.hs
@@ -41,16 +41,16 @@ initGame window = do
41 41
42endGame :: Game GameState () 42endGame :: Game GameState ()
43endGame = do 43endGame = do
44 game <- getGameState 44 game <- get
45 runSubGame' (deleteImmRenderer $ immRenderState game) (renderCoreState game) 45 runSubGame' (deleteImmRenderer $ immRenderState game) (renderCoreState game)
46 46
47 47
48step :: Elapsed -> Dt -> [InputEvent] -> Game GameState Bool 48step :: Elapsed -> Dt -> [InputEvent] -> Game GameState Bool
49step elapsed dt inputEvents = do 49step elapsed dt inputEvents = do
50 gs <- getGameState 50 gs <- get
51 events <- processInput (window gs) 51 events <- processInput (window gs)
52 --when (events /= []) $ gameIO . putStrLn $ show events 52 --when (events /= []) $ liftIO . putStrLn $ show events
53 modifyGameState $ \gs -> 53 modify $ \gs ->
54 gs 54 gs
55 { world = stepWorld (realToFrac elapsed) (realToFrac dt) events (world gs) 55 { world = stepWorld (realToFrac elapsed) (realToFrac dt) events (world gs)
56 } 56 }
@@ -67,18 +67,18 @@ exitRequested = elem (KeyDown KEY_ESC)
67 67
68render :: Game GameState () 68render :: Game GameState ()
69render = do 69render = do
70 gameState <- getGameState 70 gameState <- get
71 immRenderState' <- flip execSubGame (immRenderState gameState) $ do 71 immRenderState' <- flip execSubGame (immRenderState gameState) $ do
72 immStart 72 immStart
73 immSetViewProjectionMatrix (viewProjection gameState) 73 immSetViewProjectionMatrix (viewProjection gameState)
74 -- Clear the background to a different colour than the playable area to make 74 -- Clear the background to a different colour than the playable area to make
75 -- the latter distinguishable. 75 -- the latter distinguishable.
76 gameIO $ do 76 liftIO $ do
77 setClearColour (0.2, 0.2, 0.2, 0.0) 77 setClearColour (0.2, 0.2, 0.2, 0.0)
78 clearBuffers [ColourBuffer] 78 clearBuffers [ColourBuffer]
79 render' $ world gameState 79 render' $ world gameState
80 immEnd 80 immEnd
81 saveGameState $ gameState { immRenderState = immRenderState' } 81 put $ gameState { immRenderState = immRenderState' }
82 82
83render' :: [GameObject] -> Game ImmRenderState () 83render' :: [GameObject] -> Game ImmRenderState ()
84render' world = do 84render' world = do
@@ -122,7 +122,7 @@ resize (ResizeEvent w h) =
122 bottom = if r > 1 then 0 else -pad 122 bottom = if r > 1 then 0 else -pad
123 top = if r > 1 then 1 else 1 + pad 123 top = if r > 1 then 1 else 1 + pad
124 in do 124 in do
125 gameIO $ setViewport 0 0 w h 125 liftIO $ setViewport 0 0 w h
126 modifyGameState $ \state -> state { 126 modify $ \state -> state {
127 viewProjection = Matrix4.ortho left right bottom top (-1) 1 127 viewProjection = Matrix4.ortho left right bottom top (-1) 1
128 } 128 }
diff --git a/Spear/App.hs b/Spear/App.hs
index 61ea3b1..1520eee 100644
--- a/Spear/App.hs
+++ b/Spear/App.hs
@@ -76,15 +76,15 @@ loop :: App s -> Window -> Game s ()
76loop app window = do 76loop app window = do
77 -- For convenience, trigger an initial resize followed by a render of the 77 -- For convenience, trigger an initial resize followed by a render of the
78 -- application's initial state. 78 -- application's initial state.
79 (width, height) <- gameIO $ getWindowSize window 79 (width, height) <- liftIO $ getWindowSize window
80 resizeApp app (ResizeEvent width height) 80 resizeApp app (ResizeEvent width height)
81 renderApp app 81 renderApp app
82 82
83 let ddt = fpsToDdt . maxFPS . appOptions $ app -- Desired render time step. 83 let ddt = fpsToDdt . maxFPS . appOptions $ app -- Desired render time step.
84 let animationDdt = fpsToDdt . animationFPS . appOptions $ app -- Desired animation time step. 84 let animationDdt = fpsToDdt . animationFPS . appOptions $ app -- Desired animation time step.
85 85
86 timer <- gameIO newTimer 86 timer <- liftIO newTimer
87 gameIO $ Timer.start timer 87 liftIO $ Timer.start timer
88 let lastAnimationTime = lastTick timer 88 let lastAnimationTime = lastTick timer
89 loop' window ddt animationDdt lastAnimationTime timer app 89 loop' window ddt animationDdt lastAnimationTime timer app
90 90
@@ -97,16 +97,16 @@ loop' ::
97 App s -> 97 App s ->
98 Game s () 98 Game s ()
99loop' window renderDdt animationDdt lastAnimationTime inputTimer app = do 99loop' window renderDdt animationDdt lastAnimationTime inputTimer app = do
100 timer <- gameIO $ tick inputTimer 100 timer <- liftIO $ tick inputTimer
101 windowEvents <- gameIO $ pollWindowEvents window 101 windowEvents <- liftIO $ pollWindowEvents window
102 close <- gameIO $ shouldWindowClose window 102 close <- liftIO $ shouldWindowClose window
103 103
104 (continue, lastAnimationTimeNextFrame) <- case animationDdt of 104 (continue, lastAnimationTimeNextFrame) <- case animationDdt of
105 0 -> do 105 0 -> do
106 -- Variable time step game animation. 106 -- Variable time step game animation.
107 let t = timeDeltaToSec $ runningTime timer 107 let t = timeDeltaToSec $ runningTime timer
108 let dt = timeDeltaToSec $ deltaTime timer 108 let dt = timeDeltaToSec $ deltaTime timer
109 inputEvents <- gameIO $ pollInputEvents window 109 inputEvents <- liftIO $ pollInputEvents window
110 continue <- stepApp app t dt inputEvents 110 continue <- stepApp app t dt inputEvents
111 return (continue, lastAnimationTime) 111 return (continue, lastAnimationTime)
112 112
@@ -118,15 +118,15 @@ loop' window renderDdt animationDdt lastAnimationTime inputTimer app = do
118 let timeBudgetThisFrame = timeBudget + deltaTime timer 118 let timeBudgetThisFrame = timeBudget + deltaTime timer
119 let timeBudgetNextFrame = timeBudgetThisFrame `mod` ddt 119 let timeBudgetNextFrame = timeBudgetThisFrame `mod` ddt
120 let steps = timeBudgetThisFrame `div` ddt -} 120 let steps = timeBudgetThisFrame `div` ddt -}
121 --gameIO . print $ "Steps: " ++ show steps ++ ", Budget: " ++ show timeBudgetThisFrame ++ ", ddt: " ++ show ddt 121 --liftIO . print $ "Steps: " ++ show steps ++ ", Budget: " ++ show timeBudgetThisFrame ++ ", ddt: " ++ show ddt
122 let elapsed = runningTime timer 122 let elapsed = runningTime timer
123 let dt = timeDeltaToSec ddt 123 let dt = timeDeltaToSec ddt
124 let timeBudgetThisFrame = timeDiff lastAnimationTime (lastTick timer) 124 let timeBudgetThisFrame = timeDiff lastAnimationTime (lastTick timer)
125 let steps = timeBudgetThisFrame `div` ddt 125 let steps = timeBudgetThisFrame `div` ddt
126 let lastAnimationTimeNextFrame = timeAdd lastAnimationTime (steps * ddt) 126 let lastAnimationTimeNextFrame = timeAdd lastAnimationTime (steps * ddt)
127 --gameIO . print $ "Steps: " ++ show steps ++ ", Budget: " ++ show timeBudgetThisFrame ++ ", ddt: " ++ show ddt 127 --liftIO . print $ "Steps: " ++ show steps ++ ", Budget: " ++ show timeBudgetThisFrame ++ ", ddt: " ++ show ddt
128 continue <- and <$> forM [1..steps] (\i -> do 128 continue <- and <$> forM [1..steps] (\i -> do
129 inputEvents <- gameIO $ pollInputEvents window 129 inputEvents <- liftIO $ pollInputEvents window
130 let t = timeDeltaToSec $ elapsed + i * ddt 130 let t = timeDeltaToSec $ elapsed + i * ddt
131 stepApp app t dt inputEvents) 131 stepApp app t dt inputEvents)
132 return (continue, lastAnimationTimeNextFrame) 132 return (continue, lastAnimationTimeNextFrame)
@@ -138,16 +138,16 @@ loop' window renderDdt animationDdt lastAnimationTime inputTimer app = do
138 -- For smoother resizing, render only while not resizing. 138 -- For smoother resizing, render only while not resizing.
139 unless resized $ do 139 unless resized $ do
140 renderApp app 140 renderApp app
141 gameIO $ swapBuffers window 141 liftIO $ swapBuffers window
142 142
143 -- Limit frame rate if so requested by the application. 143 -- Limit frame rate if so requested by the application.
144 -- This currently makes the rendering stutter and is not very desirable. 144 -- This currently makes the rendering stutter and is not very desirable.
145 when ((maxFPS . appOptions $ app) > 0) $ do 145 when ((maxFPS . appOptions $ app) > 0) $ do
146 frameEnd <- gameIO now 146 frameEnd <- liftIO now
147 let ddt = renderDdt 147 let ddt = renderDdt
148 let frameTime = timeDiff (lastTick timer) frameEnd 148 let frameTime = timeDiff (lastTick timer) frameEnd
149 when (frameTime < ddt) $ do 149 when (frameTime < ddt) $ do
150 gameIO $ Timer.sleep (ddt - frameTime) 150 liftIO $ Timer.sleep (ddt - frameTime)
151 151
152 when (continue && not close) $ do 152 when (continue && not close) $ do
153 loop' window renderDdt animationDdt lastAnimationTimeNextFrame timer app 153 loop' window renderDdt animationDdt lastAnimationTimeNextFrame timer app
diff --git a/Spear/Assets/Image.hsc b/Spear/Assets/Image.hsc
index f9fc025..db90afe 100644
--- a/Spear/Assets/Image.hsc
+++ b/Spear/Assets/Image.hsc
@@ -46,24 +46,24 @@ data CImage = CImage
46instance Storable CImage where 46instance Storable CImage where
47 sizeOf _ = #{size Image} 47 sizeOf _ = #{size Image}
48 alignment _ = alignment (undefined :: CInt) 48 alignment _ = alignment (undefined :: CInt)
49 49
50 peek ptr = do 50 peek ptr = do
51 width <- #{peek Image, width} ptr 51 width <- #{peek Image, width} ptr
52 height <- #{peek Image, height} ptr 52 height <- #{peek Image, height} ptr
53 bpp <- #{peek Image, bpp} ptr 53 bpp <- #{peek Image, bpp} ptr
54 pixels <- #{peek Image, pixels} ptr 54 pixels <- #{peek Image, pixels} ptr
55 return $ CImage width height bpp pixels 55 return $ CImage width height bpp pixels
56 56
57 poke ptr (CImage width height bpp pixels) = do 57 poke ptr (CImage width height bpp pixels) = do
58 #{poke Image, width} ptr width 58 #{poke Image, width} ptr width
59 #{poke Image, height} ptr height 59 #{poke Image, height} ptr height
60 #{poke Image, bpp} ptr bpp 60 #{poke Image, bpp} ptr bpp
61 #{poke Image, pixels} ptr pixels 61 #{poke Image, pixels} ptr pixels
62 62
63-- | Represents an image 'Resource'. 63-- | An image resource.
64data Image = Image 64data Image = Image
65 { imageData :: CImage 65 { imageData :: CImage
66 , rkey :: Resource 66 , rkey :: ReleaseKey
67 } 67 }
68 68
69instance ResourceClass Image where 69instance ResourceClass Image where
@@ -84,15 +84,15 @@ loadImage file = do
84 dotPos <- case elemIndex '.' file of 84 dotPos <- case elemIndex '.' file of
85 Nothing -> gameError $ "file name has no extension: " ++ file 85 Nothing -> gameError $ "file name has no extension: " ++ file
86 Just p -> return p 86 Just p -> return p
87 87
88 let ext = map toLower . tail . snd $ splitAt dotPos file 88 let ext = map toLower . tail . snd $ splitAt dotPos file
89 89
90 result <- gameIO . alloca $ \ptr -> do 90 result <- liftIO . alloca $ \ptr -> do
91 status <- withCString file $ \fileCstr -> do 91 status <- withCString file $ \fileCstr -> do
92 case ext of 92 case ext of
93 "bmp" -> bmp_load fileCstr ptr 93 "bmp" -> bmp_load fileCstr ptr
94 _ -> return ImageNoSuitableLoader 94 _ -> return ImageNoSuitableLoader
95 95
96 case status of 96 case status of
97 ImageSuccess -> peek ptr >>= return . Right 97 ImageSuccess -> peek ptr >>= return . Right
98 ImageReadError -> return . Left $ "read error" 98 ImageReadError -> return . Left $ "read error"
@@ -100,7 +100,7 @@ loadImage file = do
100 ImageFileNotFound -> return . Left $ "file not found" 100 ImageFileNotFound -> return . Left $ "file not found"
101 ImageInvalidFormat -> return . Left $ "invalid format" 101 ImageInvalidFormat -> return . Left $ "invalid format"
102 ImageNoSuitableLoader -> return . Left $ "no suitable loader for extension " ++ ext 102 ImageNoSuitableLoader -> return . Left $ "no suitable loader for extension " ++ ext
103 103
104 case result of 104 case result of
105 Right image -> register (freeImage image) >>= return . Image image 105 Right image -> register (freeImage image) >>= return . Image image
106 Left err -> gameError $ "loadImage: " ++ err 106 Left err -> gameError $ "loadImage: " ++ err
diff --git a/Spear/Assets/Model.hsc b/Spear/Assets/Model.hsc
index 74666f2..02e1edf 100644
--- a/Spear/Assets/Model.hsc
+++ b/Spear/Assets/Model.hsc
@@ -65,12 +65,12 @@ data Vec2 = Vec2 {-# UNPACK #-} !Float {-# UNPACK #-} !Float
65instance Storable Vec2 where 65instance Storable Vec2 where
66 sizeOf _ = 2*sizeFloat 66 sizeOf _ = 2*sizeFloat
67 alignment _ = alignment (undefined :: CFloat) 67 alignment _ = alignment (undefined :: CFloat)
68 68
69 peek ptr = do 69 peek ptr = do
70 f0 <- peekByteOff ptr 0 70 f0 <- peekByteOff ptr 0
71 f1 <- peekByteOff ptr sizeFloat 71 f1 <- peekByteOff ptr sizeFloat
72 return $ Vec2 f0 f1 72 return $ Vec2 f0 f1
73 73
74 poke ptr (Vec2 f0 f1) = do 74 poke ptr (Vec2 f0 f1) = do
75 pokeByteOff ptr 0 f0 75 pokeByteOff ptr 0 f0
76 pokeByteOff ptr sizeFloat f1 76 pokeByteOff ptr sizeFloat f1
@@ -81,13 +81,13 @@ data Vec3 = Vec3 {-# UNPACK #-} !Float {-# UNPACK #-} !Float {-# UNPACK #-} !Flo
81instance Storable Vec3 where 81instance Storable Vec3 where
82 sizeOf _ = 3*sizeFloat 82 sizeOf _ = 3*sizeFloat
83 alignment _ = alignment (undefined :: CFloat) 83 alignment _ = alignment (undefined :: CFloat)
84 84
85 peek ptr = do 85 peek ptr = do
86 f0 <- peekByteOff ptr 0 86 f0 <- peekByteOff ptr 0
87 f1 <- peekByteOff ptr sizeFloat 87 f1 <- peekByteOff ptr sizeFloat
88 f2 <- peekByteOff ptr (2*sizeFloat) 88 f2 <- peekByteOff ptr (2*sizeFloat)
89 return $ Vec3 f0 f1 f2 89 return $ Vec3 f0 f1 f2
90 90
91 poke ptr (Vec3 f0 f1 f2) = do 91 poke ptr (Vec3 f0 f1 f2) = do
92 pokeByteOff ptr 0 f0 92 pokeByteOff ptr 0 f0
93 pokeByteOff ptr sizeFloat f1 93 pokeByteOff ptr sizeFloat f1
@@ -99,12 +99,12 @@ data TexCoord = TexCoord {-# UNPACK #-} !Float {-# UNPACK #-} !Float
99instance Storable TexCoord where 99instance Storable TexCoord where
100 sizeOf _ = 2*sizeFloat 100 sizeOf _ = 2*sizeFloat
101 alignment _ = alignment (undefined :: CFloat) 101 alignment _ = alignment (undefined :: CFloat)
102 102
103 peek ptr = do 103 peek ptr = do
104 f0 <- peekByteOff ptr 0 104 f0 <- peekByteOff ptr 0
105 f1 <- peekByteOff ptr sizeFloat 105 f1 <- peekByteOff ptr sizeFloat
106 return $ TexCoord f0 f1 106 return $ TexCoord f0 f1
107 107
108 poke ptr (TexCoord f0 f1) = do 108 poke ptr (TexCoord f0 f1) = do
109 pokeByteOff ptr 0 f0 109 pokeByteOff ptr 0 f0
110 pokeByteOff ptr sizeFloat f1 110 pokeByteOff ptr sizeFloat f1
@@ -122,23 +122,23 @@ data CTriangle = CTriangle
122instance Storable CTriangle where 122instance Storable CTriangle where
123 sizeOf _ = #{size triangle} 123 sizeOf _ = #{size triangle}
124 alignment _ = alignment (undefined :: CUShort) 124 alignment _ = alignment (undefined :: CUShort)
125 125
126 peek ptr = do 126 peek ptr = do
127 v0 <- #{peek triangle, vertexIndices[0]} ptr 127 v0 <- #{peek triangle, vertexIndices[0]} ptr
128 v1 <- #{peek triangle, vertexIndices[1]} ptr 128 v1 <- #{peek triangle, vertexIndices[1]} ptr
129 v2 <- #{peek triangle, vertexIndices[2]} ptr 129 v2 <- #{peek triangle, vertexIndices[2]} ptr
130 130
131 t0 <- #{peek triangle, textureIndices[0]} ptr 131 t0 <- #{peek triangle, textureIndices[0]} ptr
132 t1 <- #{peek triangle, textureIndices[1]} ptr 132 t1 <- #{peek triangle, textureIndices[1]} ptr
133 t2 <- #{peek triangle, textureIndices[2]} ptr 133 t2 <- #{peek triangle, textureIndices[2]} ptr
134 134
135 return $ CTriangle v0 v1 v2 t0 t1 t2 135 return $ CTriangle v0 v1 v2 t0 t1 t2
136 136
137 poke ptr (CTriangle v0 v1 v2 t0 t1 t2) = do 137 poke ptr (CTriangle v0 v1 v2 t0 t1 t2) = do
138 #{poke triangle, vertexIndices[0]} ptr v0 138 #{poke triangle, vertexIndices[0]} ptr v0
139 #{poke triangle, vertexIndices[1]} ptr v1 139 #{poke triangle, vertexIndices[1]} ptr v1
140 #{poke triangle, vertexIndices[2]} ptr v2 140 #{poke triangle, vertexIndices[2]} ptr v2
141 141
142 #{poke triangle, textureIndices[0]} ptr t0 142 #{poke triangle, textureIndices[0]} ptr t0
143 #{poke triangle, textureIndices[1]} ptr t1 143 #{poke triangle, textureIndices[1]} ptr t1
144 #{poke triangle, textureIndices[2]} ptr t2 144 #{poke triangle, textureIndices[2]} ptr t2
@@ -149,7 +149,7 @@ data Box = Box {-# UNPACK #-} !Vec3 {-# UNPACK #-} !Vec3
149instance Storable Box where 149instance Storable Box where
150 sizeOf _ = 6 * sizeFloat 150 sizeOf _ = 6 * sizeFloat
151 alignment _ = alignment (undefined :: CFloat) 151 alignment _ = alignment (undefined :: CFloat)
152 152
153 peek ptr = do 153 peek ptr = do
154 xmin <- peekByteOff ptr 0 154 xmin <- peekByteOff ptr 0
155 ymin <- peekByteOff ptr sizeFloat 155 ymin <- peekByteOff ptr sizeFloat
@@ -158,7 +158,7 @@ instance Storable Box where
158 ymax <- peekByteOff ptr $ 4*sizeFloat 158 ymax <- peekByteOff ptr $ 4*sizeFloat
159 zmax <- peekByteOff ptr $ 5*sizeFloat 159 zmax <- peekByteOff ptr $ 5*sizeFloat
160 return $ Box (Vec3 xmin ymin zmin) (Vec3 xmax ymax zmax) 160 return $ Box (Vec3 xmin ymin zmin) (Vec3 xmax ymax zmax)
161 161
162 poke ptr (Box (Vec3 xmin ymin zmin) (Vec3 xmax ymax zmax)) = do 162 poke ptr (Box (Vec3 xmin ymin zmin) (Vec3 xmax ymax zmax)) = do
163 pokeByteOff ptr 0 xmin 163 pokeByteOff ptr 0 xmin
164 pokeByteOff ptr sizeFloat ymin 164 pokeByteOff ptr sizeFloat ymin
@@ -173,11 +173,11 @@ newtype Skin = Skin { skinName :: B.ByteString }
173instance Storable Skin where 173instance Storable Skin where
174 sizeOf (Skin s) = 64 174 sizeOf (Skin s) = 64
175 alignment _ = 1 175 alignment _ = 1
176 176
177 peek ptr = do 177 peek ptr = do
178 s <- B.packCString $ unsafeCoerce ptr 178 s <- B.packCString $ unsafeCoerce ptr
179 return $ Skin s 179 return $ Skin s
180 180
181 poke ptr (Skin s) = do 181 poke ptr (Skin s) = do
182 B.useAsCStringLen s $ \(sptr, len) -> copyArray (unsafeCoerce ptr) sptr len 182 B.useAsCStringLen s $ \(sptr, len) -> copyArray (unsafeCoerce ptr) sptr len
183 183
@@ -193,13 +193,13 @@ data Animation = Animation
193instance Storable Animation where 193instance Storable Animation where
194 sizeOf _ = #{size animation} 194 sizeOf _ = #{size animation}
195 alignment _ = alignment (undefined :: CUInt) 195 alignment _ = alignment (undefined :: CUInt)
196 196
197 peek ptr = do 197 peek ptr = do
198 name <- B.packCString (unsafeCoerce ptr) 198 name <- B.packCString (unsafeCoerce ptr)
199 start <- #{peek animation, start} ptr 199 start <- #{peek animation, start} ptr
200 end <- #{peek animation, end} ptr 200 end <- #{peek animation, end} ptr
201 return $ Animation name start end 201 return $ Animation name start end
202 202
203 poke ptr (Animation name start end) = do 203 poke ptr (Animation name start end) = do
204 B.useAsCStringLen name $ \(sptr, len) -> copyArray (unsafeCoerce ptr) sptr len 204 B.useAsCStringLen name $ \(sptr, len) -> copyArray (unsafeCoerce ptr) sptr len
205 #{poke animation, start} ptr start 205 #{poke animation, start} ptr start
@@ -224,7 +224,7 @@ data Model = Model
224instance Storable Model where 224instance Storable Model where
225 sizeOf _ = #{size Model} 225 sizeOf _ = #{size Model}
226 alignment _ = alignment (undefined :: CUInt) 226 alignment _ = alignment (undefined :: CUInt)
227 227
228 peek ptr = do 228 peek ptr = do
229 numFrames <- #{peek Model, numFrames} ptr 229 numFrames <- #{peek Model, numFrames} ptr
230 numVertices <- #{peek Model, numVertices} ptr 230 numVertices <- #{peek Model, numVertices} ptr
@@ -232,7 +232,7 @@ instance Storable Model where
232 numTexCoords <- #{peek Model, numTexCoords} ptr 232 numTexCoords <- #{peek Model, numTexCoords} ptr
233 numSkins <- #{peek Model, numSkins} ptr 233 numSkins <- #{peek Model, numSkins} ptr
234 numAnimations <- #{peek Model, numAnimations} ptr 234 numAnimations <- #{peek Model, numAnimations} ptr
235 pVerts <- peek (unsafeCoerce ptr) 235 pVerts <- peek (unsafeCoerce ptr)
236 pNormals <- peekByteOff ptr sizePtr 236 pNormals <- peekByteOff ptr sizePtr
237 pTexCoords <- peekByteOff ptr (2*sizePtr) 237 pTexCoords <- peekByteOff ptr (2*sizePtr)
238 pTriangles <- peekByteOff ptr (3*sizePtr) 238 pTriangles <- peekByteOff ptr (3*sizePtr)
@@ -247,7 +247,7 @@ instance Storable Model where
247 return $ 247 return $
248 Model vertices normals texCoords triangles skins animations 248 Model vertices normals texCoords triangles skins animations
249 numFrames numVertices numTriangles numTexCoords numSkins numAnimations 249 numFrames numVertices numTriangles numTexCoords numSkins numAnimations
250 250
251 poke ptr 251 poke ptr
252 (Model verts normals texCoords tris skins animations 252 (Model verts normals texCoords tris skins animations
253 numFrames numVerts numTris numTex numSkins numAnimations) = 253 numFrames numVerts numTris numTex numSkins numAnimations) =
@@ -288,7 +288,7 @@ data Triangle = Triangle
288instance Storable Triangle where 288instance Storable Triangle where
289 sizeOf _ = #{size model_triangle} 289 sizeOf _ = #{size model_triangle}
290 alignment _ = alignment (undefined :: Float) 290 alignment _ = alignment (undefined :: Float)
291 291
292 peek ptr = do 292 peek ptr = do
293 v0 <- #{peek model_triangle, v0} ptr 293 v0 <- #{peek model_triangle, v0} ptr
294 v1 <- #{peek model_triangle, v1} ptr 294 v1 <- #{peek model_triangle, v1} ptr
@@ -300,7 +300,7 @@ instance Storable Triangle where
300 t1 <- #{peek model_triangle, t1} ptr 300 t1 <- #{peek model_triangle, t1} ptr
301 t2 <- #{peek model_triangle, t2} ptr 301 t2 <- #{peek model_triangle, t2} ptr
302 return $ Triangle v0 v1 v2 n0 n1 n2 t0 t1 t2 302 return $ Triangle v0 v1 v2 n0 n1 n2 t0 t1 t2
303 303
304 poke ptr (Triangle v0 v1 v2 n0 n1 n2 t0 t1 t2) = do 304 poke ptr (Triangle v0 v1 v2 n0 n1 n2 t0 t1 t2) = do
305 #{poke model_triangle, v0} ptr v0 305 #{poke model_triangle, v0} ptr v0
306 #{poke model_triangle, v1} ptr v1 306 #{poke model_triangle, v1} ptr v1
@@ -335,16 +335,16 @@ loadModel file = do
335 dotPos <- case elemIndex '.' file of 335 dotPos <- case elemIndex '.' file of
336 Nothing -> gameError $ "file name has no extension: " ++ file 336 Nothing -> gameError $ "file name has no extension: " ++ file
337 Just p -> return p 337 Just p -> return p
338 338
339 let ext = map toLower . tail . snd $ splitAt dotPos file 339 let ext = map toLower . tail . snd $ splitAt dotPos file
340 340
341 result <- gameIO . alloca $ \ptr -> do 341 result <- liftIO . alloca $ \ptr -> do
342 status <- withCString file $ \fileCstr -> do 342 status <- withCString file $ \fileCstr -> do
343 case ext of 343 case ext of
344 "md2" -> md2_load fileCstr 0 0 ptr 344 "md2" -> md2_load fileCstr 0 0 ptr
345 "obj" -> obj_load fileCstr 0 0 ptr 345 "obj" -> obj_load fileCstr 0 0 ptr
346 _ -> return ModelNoSuitableLoader 346 _ -> return ModelNoSuitableLoader
347 347
348 case status of 348 case status of
349 ModelSuccess -> do 349 ModelSuccess -> do
350 model <- peek ptr 350 model <- peek ptr
@@ -355,7 +355,7 @@ loadModel file = do
355 ModelFileNotFound -> return . Left $ "file not found" 355 ModelFileNotFound -> return . Left $ "file not found"
356 ModelFileMismatch -> return . Left $ "file mismatch" 356 ModelFileMismatch -> return . Left $ "file mismatch"
357 ModelNoSuitableLoader -> return . Left $ "no suitable loader for extension " ++ ext 357 ModelNoSuitableLoader -> return . Left $ "no suitable loader for extension " ++ ext
358 358
359 case result of 359 case result of
360 Right model -> return model 360 Right model -> return model
361 Left err -> gameError $ "loadModel: " ++ err 361 Left err -> gameError $ "loadModel: " ++ err
@@ -392,7 +392,7 @@ transformVerts model f = model { vertices = vertices' }
392 where 392 where
393 n = numVerts model * numFrames model 393 n = numVerts model * numFrames model
394 vertices' = S.generate n f' 394 vertices' = S.generate n f'
395 f' i = f $ vertices model S.! i 395 f' i = f $ vertices model S.! i
396 396
397-- | Transform the model's normals. 397-- | Transform the model's normals.
398transformNormals :: Model -> (Vec3 -> Vec3) -> Model 398transformNormals :: Model -> (Vec3 -> Vec3) -> Model
@@ -400,14 +400,14 @@ transformNormals model f = model { normals = normals' }
400 where 400 where
401 n = numVerts model * numFrames model 401 n = numVerts model * numFrames model
402 normals' = S.generate n f' 402 normals' = S.generate n f'
403 f' i = f $ normals model S.! i 403 f' i = f $ normals model S.! i
404 404
405-- | Translate the model such that its lowest point has y = 0. 405-- | Translate the model such that its lowest point has y = 0.
406toGround :: Model -> IO Model 406toGround :: Model -> IO Model
407toGround model = 407toGround model =
408 let model' = model { vertices = S.generate n $ \i -> vertices model S.! i } 408 let model' = model { vertices = S.generate n $ \i -> vertices model S.! i }
409 n = numVerts model * numFrames model 409 n = numVerts model * numFrames model
410 in 410 in
411 with model' model_to_ground >> return model' 411 with model' model_to_ground >> return model'
412 412
413foreign import ccall "Model.h model_to_ground" 413foreign import ccall "Model.h model_to_ground"
diff --git a/Spear/GL.hs b/Spear/GL.hs
index f463109..3c1734b 100644
--- a/Spear/GL.hs
+++ b/Spear/GL.hs
@@ -36,7 +36,7 @@ module Spear.GL
36 Data.StateVar.get, 36 Data.StateVar.get,
37 37
38 -- * VAOs 38 -- * VAOs
39 VAO, 39 VAO(..),
40 newVAO, 40 newVAO,
41 bindVAO, 41 bindVAO,
42 unbindVAO, 42 unbindVAO,
@@ -48,7 +48,7 @@ module Spear.GL
48 drawElements, 48 drawElements,
49 49
50 -- * Buffers 50 -- * Buffers
51 GLBuffer, 51 GLBuffer(..),
52 TargetBuffer (..), 52 TargetBuffer (..),
53 BufferUsage (..), 53 BufferUsage (..),
54 newBuffer, 54 newBuffer,
@@ -122,7 +122,7 @@ import Unsafe.Coerce
122-- | A GLSL shader handle. 122-- | A GLSL shader handle.
123data GLSLShader = GLSLShader 123data GLSLShader = GLSLShader
124 { getShader :: GLuint, 124 { getShader :: GLuint,
125 getShaderKey :: Resource 125 getShaderKey :: ReleaseKey
126 } 126 }
127 127
128instance ResourceClass GLSLShader where 128instance ResourceClass GLSLShader where
@@ -131,7 +131,7 @@ instance ResourceClass GLSLShader where
131-- | A GLSL program handle. 131-- | A GLSL program handle.
132data GLSLProgram = GLSLProgram 132data GLSLProgram = GLSLProgram
133 { getProgram :: GLuint, 133 { getProgram :: GLuint,
134 getProgramKey :: Resource 134 getProgramKey :: ReleaseKey
135 } 135 }
136 136
137instance ResourceClass GLSLProgram where 137instance ResourceClass GLSLProgram where
@@ -173,11 +173,11 @@ attribLocation prog var = makeStateVar get set
173-- | Create a new program. 173-- | Create a new program.
174newProgram :: [GLSLShader] -> Game s GLSLProgram 174newProgram :: [GLSLShader] -> Game s GLSLProgram
175newProgram shaders = do 175newProgram shaders = do
176 h <- gameIO glCreateProgram 176 h <- liftIO glCreateProgram
177 when (h == 0) $ gameError "glCreateProgram failed" 177 when (h == 0) $ gameError "glCreateProgram failed"
178 rkey <- register $ deleteProgram h 178 rkey <- register $ deleteProgram h
179 let program = GLSLProgram h rkey 179 let program = GLSLProgram h rkey
180 mapM_ (gameIO . attachShader program) shaders 180 mapM_ (liftIO . attachShader program) shaders
181 linkProgram program 181 linkProgram program
182 return program 182 return program
183 183
@@ -192,7 +192,7 @@ deleteProgram prog = do
192linkProgram :: GLSLProgram -> Game s () 192linkProgram :: GLSLProgram -> Game s ()
193linkProgram prog = do 193linkProgram prog = do
194 let h = getProgram prog 194 let h = getProgram prog
195 err <- gameIO $ do 195 err <- liftIO $ do
196 glLinkProgram h 196 glLinkProgram h
197 alloca $ \statptr -> do 197 alloca $ \statptr -> do
198 glGetProgramiv h GL_LINK_STATUS statptr 198 glGetProgramiv h GL_LINK_STATUS statptr
@@ -235,7 +235,7 @@ loadShader shaderType file = do
235-- | Create a new shader. 235-- | Create a new shader.
236newShader :: ShaderType -> Game s GLSLShader 236newShader :: ShaderType -> Game s GLSLShader
237newShader shaderType = do 237newShader shaderType = do
238 h <- gameIO $ glCreateShader (toGLShader shaderType) 238 h <- liftIO $ glCreateShader (toGLShader shaderType)
239 case h of 239 case h of
240 0 -> gameError "glCreateShader failed" 240 0 -> gameError "glCreateShader failed"
241 _ -> do 241 _ -> do
@@ -253,10 +253,10 @@ deleteShader shader = do
253-- into the shader. 253-- into the shader.
254loadSource :: FilePath -> GLSLShader -> Game s () 254loadSource :: FilePath -> GLSLShader -> Game s ()
255loadSource file h = do 255loadSource file h = do
256 exists <- gameIO $ doesFileExist file 256 exists <- liftIO $ doesFileExist file
257 case exists of 257 case exists of
258 False -> gameError "the specified shader file does not exist" 258 False -> gameError "the specified shader file does not exist"
259 True -> gameIO $ do 259 True -> liftIO $ do
260 code <- readSource file 260 code <- readSource file
261 withCString code $ shaderSource h 261 withCString code $ shaderSource h
262 262
@@ -272,10 +272,10 @@ compile file shader = do
272 let h = getShader shader 272 let h = getShader shader
273 273
274 -- Compile 274 -- Compile
275 gameIO $ glCompileShader h 275 liftIO $ glCompileShader h
276 276
277 -- Verify status 277 -- Verify status
278 err <- gameIO $ 278 err <- liftIO $
279 alloca $ \statusPtr -> do 279 alloca $ \statusPtr -> do
280 glGetShaderiv h GL_COMPILE_STATUS statusPtr 280 glGetShaderiv h GL_COMPILE_STATUS statusPtr
281 result <- peek statusPtr 281 result <- peek statusPtr
@@ -438,7 +438,7 @@ instance Uniform [Int] where
438-- | A vertex array object. 438-- | A vertex array object.
439data VAO = VAO 439data VAO = VAO
440 { getVAO :: GLuint, 440 { getVAO :: GLuint,
441 vaoKey :: Resource 441 vaoKey :: ReleaseKey
442 } 442 }
443 443
444instance ResourceClass VAO where 444instance ResourceClass VAO where
@@ -454,7 +454,7 @@ instance Ord VAO where
454-- | Create a new vao. 454-- | Create a new vao.
455newVAO :: Game s VAO 455newVAO :: Game s VAO
456newVAO = do 456newVAO = do
457 h <- gameIO . alloca $ \ptr -> do 457 h <- liftIO . alloca $ \ptr -> do
458 glGenVertexArrays 1 ptr 458 glGenVertexArrays 1 ptr
459 peek ptr 459 peek ptr
460 460
@@ -533,11 +533,11 @@ drawElements mode count t idxs = glDrawElements mode (unsafeCoerce count) t idxs
533-- | An OpenGL buffer. 533-- | An OpenGL buffer.
534data GLBuffer = GLBuffer 534data GLBuffer = GLBuffer
535 { getBuffer :: GLuint, 535 { getBuffer :: GLuint,
536 rkey :: Resource 536 bufferKey :: ReleaseKey
537 } 537 }
538 538
539instance ResourceClass GLBuffer where 539instance ResourceClass GLBuffer where
540 getResource = rkey 540 getResource = bufferKey
541 541
542-- | The type of target buffer. 542-- | The type of target buffer.
543data TargetBuffer 543data TargetBuffer
@@ -580,7 +580,7 @@ fromUsage DynamicCopy = GL_DYNAMIC_COPY
580-- | Create a new buffer. 580-- | Create a new buffer.
581newBuffer :: Game s GLBuffer 581newBuffer :: Game s GLBuffer
582newBuffer = do 582newBuffer = do
583 h <- gameIO . alloca $ \ptr -> do 583 h <- liftIO . alloca $ \ptr -> do
584 glGenBuffers 1 ptr 584 glGenBuffers 1 ptr
585 peek ptr 585 peek ptr
586 586
@@ -656,7 +656,7 @@ withGLBuffer buf f = f $ getBuffer buf
656-- | Represents a texture resource. 656-- | Represents a texture resource.
657data Texture = Texture 657data Texture = Texture
658 { getTex :: GLuint, 658 { getTex :: GLuint,
659 texKey :: Resource 659 texKey :: ReleaseKey
660 } 660 }
661 661
662instance Eq Texture where 662instance Eq Texture where
@@ -672,7 +672,7 @@ instance ResourceClass Texture where
672-- | Create a new texture. 672-- | Create a new texture.
673newTexture :: Game s Texture 673newTexture :: Game s Texture
674newTexture = do 674newTexture = do
675 tex <- gameIO . alloca $ \ptr -> do 675 tex <- liftIO . alloca $ \ptr -> do
676 glGenTextures 1 ptr 676 glGenTextures 1 ptr
677 peek ptr 677 peek ptr
678 678
@@ -697,7 +697,7 @@ loadTextureImage ::
697loadTextureImage file minFilter magFilter = do 697loadTextureImage file minFilter magFilter = do
698 image <- loadImage file 698 image <- loadImage file
699 tex <- newTexture 699 tex <- newTexture
700 gameIO $ do 700 liftIO $ do
701 let w = width image 701 let w = width image
702 h = height image 702 h = height image
703 pix = pixels image 703 pix = pixels image
@@ -794,7 +794,7 @@ printGLError =
794assertGL :: Game s a -> String -> Game s a 794assertGL :: Game s a -> String -> Game s a
795assertGL action err = do 795assertGL action err = do
796 result <- action 796 result <- action
797 status <- gameIO getGLError 797 status <- liftIO getGLError
798 case status of 798 case status of
799 Just str -> gameError $ "OpenGL error raised: " ++ err ++ "; " ++ str 799 Just str -> gameError $ "OpenGL error raised: " ++ err ++ "; " ++ str
800 Nothing -> return result 800 Nothing -> return result
diff --git a/Spear/Game.hs b/Spear/Game.hs
index 14e3f20..92cc680 100644
--- a/Spear/Game.hs
+++ b/Spear/Game.hs
@@ -1,130 +1,130 @@
1{-# LANGUAGE GeneralizedNewtypeDeriving #-}
1module Spear.Game 2module Spear.Game
2 ( Game, 3( Game
3 GameException (..), 4, GameException (..)
4 Resource, 5, ResourceClass (..)
5 ResourceClass (..), 6, ReleaseKey
6 7 -- * Game state
7 -- * Game state 8, get
8 getGameState, 9, put
9 saveGameState, 10, modify
10 modifyGameState, 11 -- * Game resources
11 12, register
12 -- * Game resources 13, release
13 register, 14, release'
14 release, 15 -- * Error handling
15 release', 16, gameError
16 17, assertMaybe
17 -- * Error handling 18, catch
18 gameError, 19 -- * Running and IO
19 assertMaybe, 20, runGame
20 catchGameError, 21, evalGame
21 catchGameErrorFinally, 22, runSubGame
22 23, runSubGame'
23 -- * Running and IO 24, evalSubGame
24 runGame, 25, execSubGame
25 evalGame, 26, runSiblingGame
26 runSubGame, 27, runSiblingGame'
27 runSubGame', 28, evalSiblingGame
28 evalSubGame, 29, execSiblingGame
29 execSubGame, 30, liftIO
30 runSiblingGame, 31)
31 runSiblingGame',
32 evalSiblingGame,
33 execSiblingGame,
34 gameIO,
35 )
36where 32where
37 33
38import Control.Monad.Catch 34import Control.Monad.Catch
39import Control.Monad.State.Strict 35import Control.Monad.State.Strict
40import Control.Monad.Trans.Class (lift) 36import Control.Monad.Trans.Class (lift)
41import qualified Control.Monad.Trans.Resource as R 37import Control.Monad.Trans.Resource
42
43 38
44type Resource = R.ReleaseKey
45 39
40-- | Anything that holds a resource.
41--
42-- This is a convenient wrapper so that we can define the general `release'`
43-- function on any type of resource.
46class ResourceClass a where 44class ResourceClass a where
47 getResource :: a -> Resource 45 getResource :: a -> ReleaseKey
48 46
49type Game s = StateT s (R.ResourceT IO)
50 47
48-- | A game exception.
49--
50-- This is mostly a convenient wrapper around `String` so that we can throw
51-- strings directly with `gameError`.
51newtype GameException = GameException String deriving (Show) 52newtype GameException = GameException String deriving (Show)
52 53
53instance Exception GameException 54instance Exception GameException
54 55
55 56
56-- | Retrieve the game state. 57-- | The game monad.
57getGameState :: Game s s 58--
58getGameState = get 59-- The game monad performs three different roles:
59 60--
60-- | Save the game state. 61-- 1. I/O
61saveGameState :: s -> Game s () 62-- 2. Resource management.
62saveGameState = put 63-- 3. State management.
63 64newtype Game s a = Game { getGame :: StateT s (ResourceT IO) a }
64-- | Modify the game state. 65 deriving
65modifyGameState :: (s -> s) -> Game s () 66 ( Functor
66modifyGameState = modify 67 , Applicative
67 68 , Monad
68-- | Register the given cleaner. 69 , MonadIO
69register :: IO () -> Game s Resource 70 , MonadThrow
70register = lift . R.register 71 , MonadCatch
72 , MonadState s
73 , MonadResource
74 )
71 75
72-- | Release the given 'Resource'.
73release :: ResourceClass a => a -> Game s ()
74release = lift . R.release . getResource
75 76
76-- | Release the given 'Resource'. 77-- | Release the given 'Resource'.
77release' :: ResourceClass a => a -> IO () 78release' :: ResourceClass a => a -> Game s ()
78release' = R.release . getResource 79release' = release . getResource
79 80
80-- | Throw an error from the 'Game' monad. 81-- | Throw an error from the 'Game' monad.
81gameError :: String -> Game s a 82gameError :: String -> Game s a
82gameError = gameError' . GameException 83gameError = throwM . GameException
83
84-- | Throw an error from the 'Game' monad.
85gameError' :: GameException -> Game s a
86gameError' = lift . lift . throwM
87 84
88-- | Throw the given error if given 'Nothing'. 85-- | Throw the given error if given 'Nothing'.
89assertMaybe :: Maybe a -> GameException -> Game s a 86assertMaybe :: Maybe a -> GameException -> Game s a
90assertMaybe Nothing err = gameError' err 87assertMaybe Nothing err = throwM err
91assertMaybe (Just x) _ = return x 88assertMaybe (Just x) _ = return x
92 89
93-- | Run the given game with the given error handler. 90-- | Run the given game, unrolling the full monad stack and returning the game's
94catchGameError :: Game s a -> (GameException -> Game s a) -> Game s a 91-- result and its final state.
95catchGameError = catch 92--
96 93-- Any resources acquired by the given game are released when this returns.
97-- | Run the given game, catch any error, run the given finaliser and rethrow the error.
98catchGameErrorFinally :: Game s a -> Game s a -> Game s a
99catchGameErrorFinally game finally = catch game $ \err -> finally >> gameError' err
100
101-- | Run the given game.
102runGame :: Game s a -> s -> IO (a, s) 94runGame :: Game s a -> s -> IO (a, s)
103runGame game = R.runResourceT . runStateT game 95runGame game = runResourceT . runStateT (getGame game)
104 96
105-- | Run the given game and return its result. 97-- | Run the given game and return its result.
106evalGame :: Game s a -> s -> IO a 98evalGame :: Game s a -> s -> IO a
107evalGame g s = fst <$> runGame g s 99evalGame g s = fst <$> runGame g s
108 100
109-- | Fully run the given sub game, unrolling the entire monad stack. 101-- | Run the given sub-game, unrolling the full monad stack and returning the
102-- game's result and its final state.
103--
104-- Like `runGame`, this frees any resources that are acquired by the sub-game.
105-- If you want to keep acquired resources, see `runSiblingGame` instead.
110runSubGame :: Game s a -> s -> Game t (a, s) 106runSubGame :: Game s a -> s -> Game t (a, s)
111runSubGame g s = gameIO $ runGame g s 107runSubGame g s = liftIO $ runGame g s
108
109-- | Run the given sub-game and return its result.
110evalSubGame :: Game s a -> s -> Game t a
111evalSubGame g s = fst <$> runSubGame g s
112 112
113-- | Like 'runSubGame', but discarding the result. 113-- | Like 'runSubGame', but discarding the result.
114runSubGame' :: Game s a -> s -> Game t () 114runSubGame' :: Game s a -> s -> Game t ()
115runSubGame' g s = void $ runSubGame g s 115runSubGame' g s = void $ runSubGame g s
116 116
117-- | Run the given sub game and return its result. 117-- | Run the given sub-game and return its state.
118evalSubGame :: Game s a -> s -> Game t a
119evalSubGame g s = fst <$> runSubGame g s
120
121-- | Run the given sub game and return its state.
122execSubGame :: Game s a -> s -> Game t s 118execSubGame :: Game s a -> s -> Game t s
123execSubGame g s = snd <$> runSubGame g s 119execSubGame g s = snd <$> runSubGame g s
124 120
125-- | Run the given sibling game, unrolling StateT but not ResourceT. 121-- | Run the given sibling game, unrolling the state transformer but not the
122-- resource transformer.
123--
124-- Unlike `runSubGame`, any resources acquired by the sibling game are *not*
125-- released.
126runSiblingGame :: Game s a -> s -> Game t (a, s) 126runSiblingGame :: Game s a -> s -> Game t (a, s)
127runSiblingGame g s = lift $ runStateT g s 127runSiblingGame game = Game . lift . runStateT (getGame game)
128 128
129-- | Like 'runSiblingGame', but discarding the result. 129-- | Like 'runSiblingGame', but discarding the result.
130runSiblingGame' :: Game s a -> s -> Game t () 130runSiblingGame' :: Game s a -> s -> Game t ()
@@ -137,7 +137,3 @@ evalSiblingGame g s = fst <$> runSiblingGame g s
137-- | Run the given sibling game and return its state. 137-- | Run the given sibling game and return its state.
138execSiblingGame :: Game s a -> s -> Game t s 138execSiblingGame :: Game s a -> s -> Game t s
139execSiblingGame g s = snd <$> runSiblingGame g s 139execSiblingGame g s = snd <$> runSiblingGame g s
140
141-- | Perform the given IO action in the 'Game' monad.
142gameIO :: IO a -> Game s a
143gameIO = lift . lift
diff --git a/Spear/Render/AnimatedModel.hs b/Spear/Render/AnimatedModel.hs
index 8f0d6bd..e5b29ec 100644
--- a/Spear/Render/AnimatedModel.hs
+++ b/Spear/Render/AnimatedModel.hs
@@ -66,7 +66,7 @@ data AnimatedModelResource = AnimatedModelResource
66 material :: Material, 66 material :: Material,
67 texture :: Texture, 67 texture :: Texture,
68 boxes :: V.Vector Box, 68 boxes :: V.Vector Box,
69 rkey :: Resource 69 rkey :: ReleaseKey
70 } 70 }
71 71
72instance Eq AnimatedModelResource where 72instance Eq AnimatedModelResource where
@@ -121,12 +121,12 @@ animatedModelResource
121 material 121 material
122 texture 122 texture
123 model = do 123 model = do
124 RenderModel elements numFrames numVertices <- gameIO . renderModelFromModel $ model 124 RenderModel elements numFrames numVertices <- liftIO . renderModelFromModel $ model
125 elementBuf <- newBuffer 125 elementBuf <- newBuffer
126 vao <- newVAO 126 vao <- newVAO
127 boxes <- gameIO $ modelBoxes model 127 boxes <- liftIO $ modelBoxes model
128 128
129 gameIO $ do 129 liftIO $ do
130 let elemSize = 56::CUInt 130 let elemSize = 56::CUInt
131 elemSize' = fromIntegral elemSize 131 elemSize' = fromIntegral elemSize
132 n = numVertices * numFrames 132 n = numVertices * numFrames
@@ -149,9 +149,8 @@ animatedModelResource
149 enableVAOAttrib texChan 149 enableVAOAttrib texChan
150 150
151 rkey <- register $ do 151 rkey <- register $ do
152 putStrLn "Releasing animated model resource" 152 release $ vaoKey vao
153 release' vao 153 release $ bufferKey elementBuf
154 release' elementBuf
155 154
156 return $ 155 return $
157 AnimatedModelResource 156 AnimatedModelResource
diff --git a/Spear/Render/Core/Buffer.hs b/Spear/Render/Core/Buffer.hs
index db3437e..eaff475 100644
--- a/Spear/Render/Core/Buffer.hs
+++ b/Spear/Render/Core/Buffer.hs
@@ -53,19 +53,19 @@ makeBufferAndView desc = do
53 53
54makeBuffer :: BufferDesc -> Game RenderCoreState Buffer 54makeBuffer :: BufferDesc -> Game RenderCoreState Buffer
55makeBuffer (BufferDesc usage bufferData) = do 55makeBuffer (BufferDesc usage bufferData) = do
56 handle <- gameIO $ alloca $ \ptr -> glGenBuffers 1 ptr >> peek ptr 56 handle <- liftIO $ alloca $ \ptr -> glGenBuffers 1 ptr >> peek ptr
57 resourceKey <- register $ deleteBuffer' handle 57 resourceKey <- register $ deleteBuffer' handle
58 let buffer = Buffer handle resourceKey usage 58 let buffer = Buffer handle resourceKey usage
59 gameIO $ updateBuffer buffer bufferData 59 liftIO $ updateBuffer buffer bufferData
60 modifyGameState (\state -> state { 60 modify (\state -> state {
61 buffers = HashMap.insert handle buffer (buffers state) }) 61 buffers = HashMap.insert handle buffer (buffers state) })
62 return buffer 62 return buffer
63 63
64deleteBuffer :: Buffer -> Game RenderCoreState () 64deleteBuffer :: Buffer -> Game RenderCoreState ()
65deleteBuffer buffer = do 65deleteBuffer buffer = do
66 modifyGameState (\state -> state { 66 modify (\state -> state {
67 buffers = HashMap.delete (bufferHandle buffer) (buffers state) }) 67 buffers = HashMap.delete (bufferHandle buffer) (buffers state) })
68 release buffer 68 release' buffer
69 69
70-- TODO: use glBufferSubData for updates. 70-- TODO: use glBufferSubData for updates.
71updateBuffer :: Buffer -> BufferData -> IO () 71updateBuffer :: Buffer -> BufferData -> IO ()
diff --git a/Spear/Render/Core/Geometry.hs b/Spear/Render/Core/Geometry.hs
index 6c05b38..10ff709 100644
--- a/Spear/Render/Core/Geometry.hs
+++ b/Spear/Render/Core/Geometry.hs
@@ -87,23 +87,23 @@ newGeometryDesc = GeometryDesc
87makeGeometry :: GeometryDesc -> Game RenderCoreState Geometry 87makeGeometry :: GeometryDesc -> Game RenderCoreState Geometry
88makeGeometry desc = do 88makeGeometry desc = do
89 gdata <- geometryDescToData desc 89 gdata <- geometryDescToData desc
90 handle <- gameIO $ alloca $ \ptr -> glGenVertexArrays 1 ptr >> peek ptr 90 handle <- liftIO $ alloca $ \ptr -> glGenVertexArrays 1 ptr >> peek ptr
91 gameIO $ do 91 liftIO $ do
92 glBindVertexArray handle 92 glBindVertexArray handle
93 configureVertexAttributes gdata 93 configureVertexAttributes gdata
94 glBindVertexArray 0 94 glBindVertexArray 0
95 gdataRef <- gameIO $ newIORef gdata 95 gdataRef <- liftIO $ newIORef gdata
96 resourceKey <- register $ deleteGeometry' handle 96 resourceKey <- register $ deleteGeometry' handle
97 let geometry = Geometry handle resourceKey gdataRef 97 let geometry = Geometry handle resourceKey gdataRef
98 modifyGameState (\state -> state { 98 modify (\state -> state {
99 geometries = HashMap.insert handle geometry (geometries state) }) 99 geometries = HashMap.insert handle geometry (geometries state) })
100 return geometry 100 return geometry
101 101
102deleteGeometry :: Geometry -> Game RenderCoreState () 102deleteGeometry :: Geometry -> Game RenderCoreState ()
103deleteGeometry geometry = do 103deleteGeometry geometry = do
104 modifyGameState (\state -> state { 104 modify (\state -> state {
105 geometries = HashMap.delete (geometryVao geometry) (geometries state) }) 105 geometries = HashMap.delete (geometryVao geometry) (geometries state) })
106 release geometry 106 release' geometry
107 107
108renderGeometry :: Geometry -> IO () 108renderGeometry :: Geometry -> IO ()
109renderGeometry geometry = do 109renderGeometry geometry = do
diff --git a/Spear/Render/Core/Shader.hs b/Spear/Render/Core/Shader.hs
index 4ed4430..21db66f 100644
--- a/Spear/Render/Core/Shader.hs
+++ b/Spear/Render/Core/Shader.hs
@@ -53,22 +53,22 @@ compileShader :: ShaderDesc -> Game RenderCoreState Shader
53compileShader (ShaderDesc shaderType source defines) = do 53compileShader (ShaderDesc shaderType source defines) = do
54 code <- case source of 54 code <- case source of
55 ShaderFromString code -> return code 55 ShaderFromString code -> return code
56 ShaderFromFile file -> gameIO $ readFile file 56 ShaderFromFile file -> liftIO $ readFile file
57 state <- getGameState 57 state <- get
58 let shaderHash = hash code -- TODO: Should also include defines. 58 let shaderHash = hash code -- TODO: Should also include defines.
59 case HashMap.lookup shaderHash (shaders state) of 59 case HashMap.lookup shaderHash (shaders state) of
60 Just shader -> return shader 60 Just shader -> return shader
61 Nothing -> do 61 Nothing -> do
62 let definesString = makeDefinesString defines 62 let definesString = makeDefinesString defines
63 handle <- gameIO $ glCreateShader (toGLShaderType shaderType) 63 handle <- liftIO $ glCreateShader (toGLShaderType shaderType)
64 gameIO $ withCStringLen code $ \(codeCString, codeLen) -> 64 liftIO $ withCStringLen code $ \(codeCString, codeLen) ->
65 withCStringLen definesString $ \(definesCString, definesLen) -> 65 withCStringLen definesString $ \(definesCString, definesLen) ->
66 withCStringLen header $ \(headerCString, headerLen) -> 66 withCStringLen header $ \(headerCString, headerLen) ->
67 withArray [headerCString, definesCString, codeCString] $ \strPtrs -> 67 withArray [headerCString, definesCString, codeCString] $ \strPtrs ->
68 withArray (fromIntegral <$> [headerLen, definesLen, codeLen] :: [GLint]) 68 withArray (fromIntegral <$> [headerLen, definesLen, codeLen] :: [GLint])
69 $ \lengths -> 69 $ \lengths ->
70 glShaderSource handle 3 strPtrs lengths 70 glShaderSource handle 3 strPtrs lengths
71 err <- gameIO $ do 71 err <- liftIO $ do
72 glCompileShader handle 72 glCompileShader handle
73 alloca $ \statusPtr -> do 73 alloca $ \statusPtr -> do
74 glGetShaderiv handle GL_COMPILE_STATUS statusPtr 74 glGetShaderiv handle GL_COMPILE_STATUS statusPtr
@@ -87,7 +87,7 @@ compileShader (ShaderDesc shaderType source defines) = do
87 Nothing -> do 87 Nothing -> do
88 resourceKey <- register $ deleteShader' handle 88 resourceKey <- register $ deleteShader' handle
89 let shader = Shader handle resourceKey shaderType shaderHash 89 let shader = Shader handle resourceKey shaderType shaderHash
90 saveGameState $ state { 90 put $ state {
91 shaders = HashMap.insert shaderHash shader (shaders state) 91 shaders = HashMap.insert shaderHash shader (shaders state)
92 } 92 }
93 return shader 93 return shader
@@ -96,17 +96,17 @@ compileShader (ShaderDesc shaderType source defines) = do
96 96
97compileShaderProgram :: [Shader] -> Game RenderCoreState ShaderProgram 97compileShaderProgram :: [Shader] -> Game RenderCoreState ShaderProgram
98compileShaderProgram shaders = do 98compileShaderProgram shaders = do
99 state <- getGameState 99 state <- get
100 let programHash = hashShaders shaders 100 let programHash = hashShaders shaders
101 case HashMap.lookup programHash (shaderPrograms state) of 101 case HashMap.lookup programHash (shaderPrograms state) of
102 Just program -> return program 102 Just program -> return program
103 Nothing -> do 103 Nothing -> do
104 handle <- gameIO glCreateProgram 104 handle <- liftIO glCreateProgram
105 case handle of 105 case handle of
106 0 -> gameError "Failed to create shader program" 106 0 -> gameError "Failed to create shader program"
107 _ -> do 107 _ -> do
108 mapM_ (gameIO . glAttachShader handle) (shaderHandle <$> shaders) 108 mapM_ (liftIO . glAttachShader handle) (shaderHandle <$> shaders)
109 err <- gameIO $ do 109 err <- liftIO $ do
110 glLinkProgram handle 110 glLinkProgram handle
111 alloca $ \statusPtr -> do 111 alloca $ \statusPtr -> do
112 glGetProgramiv handle GL_LINK_STATUS statusPtr 112 glGetProgramiv handle GL_LINK_STATUS statusPtr
@@ -124,9 +124,9 @@ compileShaderProgram shaders = do
124 case err of 124 case err of
125 Nothing -> do 125 Nothing -> do
126 resourceKey <- register $ deleteShaderProgram' handle 126 resourceKey <- register $ deleteShaderProgram' handle
127 uniforms <- gameIO $ newIORef [] 127 uniforms <- liftIO $ newIORef []
128 let program = ShaderProgram handle resourceKey programHash uniforms 128 let program = ShaderProgram handle resourceKey programHash uniforms
129 saveGameState $ state { 129 put $ state {
130 shaderPrograms = HashMap.insert programHash program (shaderPrograms state) 130 shaderPrograms = HashMap.insert programHash program (shaderPrograms state)
131 } 131 }
132 return program 132 return program
@@ -136,15 +136,15 @@ compileShaderProgram shaders = do
136 136
137deleteShader :: Shader -> Game RenderCoreState () 137deleteShader :: Shader -> Game RenderCoreState ()
138deleteShader shader = do 138deleteShader shader = do
139 modifyGameState (\state -> state { 139 modify (\state -> state {
140 shaders = HashMap.delete (shaderHash shader) (shaders state) }) 140 shaders = HashMap.delete (shaderHash shader) (shaders state) })
141 release shader 141 release' shader
142 142
143deleteShaderProgram :: ShaderProgram -> Game RenderCoreState () 143deleteShaderProgram :: ShaderProgram -> Game RenderCoreState ()
144deleteShaderProgram program = do 144deleteShaderProgram program = do
145 modifyGameState (\state -> state { 145 modify (\state -> state {
146 shaderPrograms = HashMap.delete (shaderProgramHash program) (shaderPrograms state)}) 146 shaderPrograms = HashMap.delete (shaderProgramHash program) (shaderPrograms state)})
147 release program 147 release' program
148 148
149activateShaderProgram :: ShaderProgram -> IO () 149activateShaderProgram :: ShaderProgram -> IO ()
150activateShaderProgram program = do 150activateShaderProgram program = do
diff --git a/Spear/Render/Core/State.hs b/Spear/Render/Core/State.hs
index dac7b9a..aa42635 100644
--- a/Spear/Render/Core/State.hs
+++ b/Spear/Render/Core/State.hs
@@ -18,7 +18,7 @@ data BufferUsage
18-- | A data buffer (e.g., vertex attributes, indices). 18-- | A data buffer (e.g., vertex attributes, indices).
19data Buffer = Buffer 19data Buffer = Buffer
20 { bufferHandle :: GLuint 20 { bufferHandle :: GLuint
21 , bufferResource :: Resource 21 , bufferResource :: ReleaseKey
22 , bufferUsage :: BufferUsage 22 , bufferUsage :: BufferUsage
23 } 23 }
24 24
@@ -72,7 +72,7 @@ data GeometryData = GeometryData
72-- its state cannot become stale after an update. 72-- its state cannot become stale after an update.
73data Geometry = Geometry 73data Geometry = Geometry
74 { geometryVao :: GLuint 74 { geometryVao :: GLuint
75 , geometryResource :: Resource 75 , geometryResource :: ReleaseKey
76 , geometryData :: IORef GeometryData 76 , geometryData :: IORef GeometryData
77 } 77 }
78 78
@@ -80,7 +80,7 @@ data Geometry = Geometry
80-- | A shader. 80-- | A shader.
81data Shader = Shader 81data Shader = Shader
82 { shaderHandle :: GLuint 82 { shaderHandle :: GLuint
83 , shaderResource :: Resource 83 , shaderResource :: ReleaseKey
84 , shaderType :: ShaderType 84 , shaderType :: ShaderType
85 , shaderHash :: Int 85 , shaderHash :: Int
86 } 86 }
@@ -102,7 +102,7 @@ data ShaderUniform
102-- | A shader program. 102-- | A shader program.
103data ShaderProgram = ShaderProgram 103data ShaderProgram = ShaderProgram
104 { shaderProgramHandle :: GLuint 104 { shaderProgramHandle :: GLuint
105 , shaderProgramResource :: Resource 105 , shaderProgramResource :: ReleaseKey
106 , shaderProgramHash :: Int 106 , shaderProgramHash :: Int
107 -- Dirty set of uniforms that have been set since the last time uniforms were 107 -- Dirty set of uniforms that have been set since the last time uniforms were
108 -- applied. OpenGL retains the values of uniforms for a program until the 108 -- applied. OpenGL retains the values of uniforms for a program until the
diff --git a/Spear/Render/Immediate.hs b/Spear/Render/Immediate.hs
index 3c5f6ad..26f6513 100644
--- a/Spear/Render/Immediate.hs
+++ b/Spear/Render/Immediate.hs
@@ -78,20 +78,20 @@ deleteImmRenderer immState = do
78 78
79immStart :: Game ImmRenderState () 79immStart :: Game ImmRenderState ()
80immStart = do 80immStart = do
81 state <- getGameState 81 state <- get
82 gameIO $ activateShaderProgram (shader state) 82 liftIO $ activateShaderProgram (shader state)
83 83
84immEnd :: Game ImmRenderState () 84immEnd :: Game ImmRenderState ()
85immEnd = do 85immEnd = do
86 state <- getGameState 86 state <- get
87 gameIO $ deactivateShaderProgram (shader state) 87 liftIO $ deactivateShaderProgram (shader state)
88 88
89immDrawTriangles :: [Vector3] -> Game ImmRenderState () 89immDrawTriangles :: [Vector3] -> Game ImmRenderState ()
90immDrawTriangles vertices = do 90immDrawTriangles vertices = do
91 unless (null vertices) $ do 91 unless (null vertices) $ do
92 loadMatrixStack 92 loadMatrixStack
93 state <- getGameState 93 state <- get
94 gameIO $ do 94 liftIO $ do
95 setPositions (triangles state) vertices 95 setPositions (triangles state) vertices
96 applyUniforms (shader state) 96 applyUniforms (shader state)
97 renderGeometry (triangles state) 97 renderGeometry (triangles state)
@@ -112,42 +112,42 @@ immDrawQuads2d =
112 immDrawQuads . (<$>) (\(p0, p1, p2, p3) -> (to3d p0, to3d p1, to3d p2, to3d p3)) 112 immDrawQuads . (<$>) (\(p0, p1, p2, p3) -> (to3d p0, to3d p1, to3d p2, to3d p3))
113 113
114immLoadIdentity :: Game ImmRenderState () 114immLoadIdentity :: Game ImmRenderState ()
115immLoadIdentity = modifyGameState $ \state -> state { 115immLoadIdentity = modify $ \state -> state {
116 matrixStack = [Matrix4.id] } 116 matrixStack = [Matrix4.id] }
117 117
118immTranslate :: Vector3 -> Game ImmRenderState () 118immTranslate :: Vector3 -> Game ImmRenderState ()
119immTranslate vector = modifyGameState $ pushMatrix (Matrix4.translatev vector) 119immTranslate vector = modify $ pushMatrix (Matrix4.translatev vector)
120 120
121immPushMatrix :: Matrix4 -> Game ImmRenderState () 121immPushMatrix :: Matrix4 -> Game ImmRenderState ()
122immPushMatrix matrix = modifyGameState $ pushMatrix matrix 122immPushMatrix matrix = modify $ pushMatrix matrix
123 123
124immPopMatrix :: Game ImmRenderState () 124immPopMatrix :: Game ImmRenderState ()
125immPopMatrix = modifyGameState $ \state -> state { 125immPopMatrix = modify $ \state -> state {
126 matrixStack = case matrixStack state of 126 matrixStack = case matrixStack state of
127 [x] -> [x] -- Always keep the identity matrix on the stack. 127 [x] -> [x] -- Always keep the identity matrix on the stack.
128 x:xs -> xs } 128 x:xs -> xs }
129 129
130immPreservingMatrix :: Game ImmRenderState a -> Game ImmRenderState a 130immPreservingMatrix :: Game ImmRenderState a -> Game ImmRenderState a
131immPreservingMatrix f = do 131immPreservingMatrix f = do
132 originalStack <- matrixStack <$> getGameState 132 originalStack <- matrixStack <$> get
133 result <- f 133 result <- f
134 modifyGameState $ \state -> state { matrixStack = originalStack } 134 modify $ \state -> state { matrixStack = originalStack }
135 return result 135 return result
136 136
137immSetColour :: Vector4 -> Game ImmRenderState () 137immSetColour :: Vector4 -> Game ImmRenderState ()
138immSetColour colour = do 138immSetColour colour = do
139 state <- getGameState 139 state <- get
140 gameIO $ setUniform (Vec4Uniform "Colour" colour) (shader state) 140 liftIO $ setUniform (Vec4Uniform "Colour" colour) (shader state)
141 141
142immSetModelMatrix :: Matrix4 -> Game ImmRenderState () 142immSetModelMatrix :: Matrix4 -> Game ImmRenderState ()
143immSetModelMatrix model = do 143immSetModelMatrix model = do
144 state <- getGameState 144 state <- get
145 gameIO $ setUniform (Mat4Uniform "Model" model) (shader state) 145 liftIO $ setUniform (Mat4Uniform "Model" model) (shader state)
146 146
147immSetViewProjectionMatrix :: Matrix4 -> Game ImmRenderState () 147immSetViewProjectionMatrix :: Matrix4 -> Game ImmRenderState ()
148immSetViewProjectionMatrix viewProjection = do 148immSetViewProjectionMatrix viewProjection = do
149 state <- getGameState 149 state <- get
150 gameIO $ setUniform (Mat4Uniform "ViewProjection" viewProjection) (shader state) 150 liftIO $ setUniform (Mat4Uniform "ViewProjection" viewProjection) (shader state)
151 151
152-- Private 152-- Private
153 153
@@ -157,7 +157,7 @@ pushMatrix matrix state = state {
157 157
158loadMatrixStack :: Game ImmRenderState () 158loadMatrixStack :: Game ImmRenderState ()
159loadMatrixStack = do 159loadMatrixStack = do
160 state <- getGameState 160 state <- get
161 immSetModelMatrix (head $ matrixStack state) 161 immSetModelMatrix (head $ matrixStack state)
162 162
163to3d :: Vector2 -> Vector3 163to3d :: Vector2 -> Vector3
diff --git a/Spear/Render/StaticModel.hs b/Spear/Render/StaticModel.hs
index f4cddf8..5168cf2 100644
--- a/Spear/Render/StaticModel.hs
+++ b/Spear/Render/StaticModel.hs
@@ -44,7 +44,7 @@ data StaticModelResource = StaticModelResource
44 material :: Material, 44 material :: Material,
45 texture :: Texture, 45 texture :: Texture,
46 boxes :: V.Vector Box, 46 boxes :: V.Vector Box,
47 rkey :: Resource 47 rkey :: ReleaseKey
48 } 48 }
49 49
50instance Eq StaticModelResource where 50instance Eq StaticModelResource where
@@ -74,12 +74,12 @@ staticModelResource ::
74 Model -> 74 Model ->
75 Game s StaticModelResource 75 Game s StaticModelResource
76staticModelResource (StaticProgramChannels vertChan normChan texChan) material texture model = do 76staticModelResource (StaticProgramChannels vertChan normChan texChan) material texture model = do
77 RenderModel elements _ numVertices <- gameIO . renderModelFromModel $ model 77 RenderModel elements _ numVertices <- liftIO . renderModelFromModel $ model
78 elementBuf <- newBuffer 78 elementBuf <- newBuffer
79 vao <- newVAO 79 vao <- newVAO
80 boxes <- gameIO $ modelBoxes model 80 boxes <- liftIO $ modelBoxes model
81 81
82 gameIO $ do 82 liftIO $ do
83 let elemSize = 32::CUInt 83 let elemSize = 32::CUInt
84 elemSize' = fromIntegral elemSize 84 elemSize' = fromIntegral elemSize
85 n = numVertices 85 n = numVertices
@@ -98,9 +98,8 @@ staticModelResource (StaticProgramChannels vertChan normChan texChan) material t
98 enableVAOAttrib texChan 98 enableVAOAttrib texChan
99 99
100 rkey <- register $ do 100 rkey <- register $ do
101 putStrLn "Releasing static model resource" 101 release $ vaoKey vao
102 release' vao 102 release $ bufferKey elementBuf
103 release' elementBuf
104 103
105 return $ 104 return $
106 StaticModelResource 105 StaticModelResource
diff --git a/Spear/Scene/Loader.hs b/Spear/Scene/Loader.hs
index 3cd89f3..4bbbde0 100644
--- a/Spear/Scene/Loader.hs
+++ b/Spear/Scene/Loader.hs
@@ -43,7 +43,7 @@ type Loader = Game SceneResources
43-- | Load the scene specified by the given file. 43-- | Load the scene specified by the given file.
44loadScene :: FilePath -> Game s (SceneResources, SceneGraph) 44loadScene :: FilePath -> Game s (SceneResources, SceneGraph)
45loadScene file = do 45loadScene file = do
46 result <- gameIO $ loadSceneGraphFromFile file 46 result <- liftIO $ loadSceneGraphFromFile file
47 case result of 47 case result of
48 Left err -> gameError $ show err 48 Left err -> gameError $ show err
49 Right g -> case validate g of 49 Right g -> case validate g of
@@ -85,9 +85,9 @@ loadResource key field modifyResources load = do
85 case M.lookup key $ field sceneData of 85 case M.lookup key $ field sceneData of
86 Just val -> return val 86 Just val -> return val
87 Nothing -> do 87 Nothing -> do
88 gameIO $ printf "Loading %s..." key 88 liftIO $ printf "Loading %s..." key
89 resource <- load 89 resource <- load
90 gameIO $ printf "done\n" 90 liftIO $ printf "done\n"
91 modifyResources key resource 91 modifyResources key resource
92 return resource 92 return resource
93 93
@@ -139,9 +139,9 @@ newModel (SceneLeaf _ props) = do
139 let rotation = asRotation $ value "rotation" props 139 let rotation = asRotation $ value "rotation" props
140 scale = asVec3 $ value "scale" props 140 scale = asVec3 $ value "scale" props
141 141
142 gameIO $ printf "Loading model %s..." name 142 liftIO $ printf "Loading model %s..." name
143 model <- loadModel' file rotation scale 143 model <- loadModel' file rotation scale
144 gameIO . putStrLn $ "done" 144 liftIO . putStrLn $ "done"
145 texture <- loadTexture tex 145 texture <- loadTexture tex
146 sceneRes <- get 146 sceneRes <- get
147 147
@@ -180,7 +180,7 @@ loadModel' file rotation scale = do
180 \(Vec3 x' y' z') -> Vec3 (x s * x') (y s * y') (z s * z') 180 \(Vec3 x' y' z') -> Vec3 (x s * x') (y s * y') (z s * z')
181 ) 181 )
182 182
183 (fmap transform $ Model.loadModel file) >>= gameIO . toGround 183 (fmap transform $ Model.loadModel file) >>= liftIO . toGround
184 184
185rotateModel :: Rotation -> Model -> Model 185rotateModel :: Rotation -> Model -> Model
186rotateModel (Rotation ax ay az order) model = 186rotateModel (Rotation ax ay az order) model =
@@ -213,7 +213,7 @@ newShaderProgram (SceneLeaf _ props) = do
213 stype <- asString $ mandatory' "type" props 213 stype <- asString $ mandatory' "type" props
214 prog <- GL.newProgram [vertShader, fragShader] 214 prog <- GL.newProgram [vertShader, fragShader]
215 215
216 let getUniformLoc name = (gameIO . SV.get $ GL.uniformLocation prog name) `GL.assertGL` name 216 let getUniformLoc name = (liftIO . SV.get $ GL.uniformLocation prog name) `GL.assertGL` name
217 217
218 case stype of 218 case stype of
219 "static" -> do 219 "static" -> do
diff --git a/Spear/Window.hs b/Spear/Window.hs
index 2dcd1fa..75a38f7 100644
--- a/Spear/Window.hs
+++ b/Spear/Window.hs
@@ -208,7 +208,7 @@ whenKeyUp = whenKeyInState GLFW.KeyState'Released
208 208
209whenKeyInState :: GLFW.KeyState -> GLFW.Window -> Key -> Game s () -> Game s () 209whenKeyInState :: GLFW.KeyState -> GLFW.Window -> Key -> Game s () -> Game s ()
210whenKeyInState state window key game = do 210whenKeyInState state window key game = do
211 isDown <- fmap (==state) $ gameIO . GLFW.getKey window . toGLFWkey $ key 211 isDown <- fmap (==state) $ liftIO . GLFW.getKey window . toGLFWkey $ key
212 when isDown game 212 when isDown game
213 213
214-- | Check whether the given keys are pressed and return the value associated 214-- | Check whether the given keys are pressed and return the value associated
@@ -219,7 +219,7 @@ processKeys window = foldM f []
219 f acc (key, result) = do 219 f acc (key, result) = do
220 isDown <- 220 isDown <-
221 fmap (== GLFW.KeyState'Pressed) $ 221 fmap (== GLFW.KeyState'Pressed) $
222 gameIO . GLFW.getKey (glfwWindow window) . toGLFWkey $ 222 liftIO . GLFW.getKey (glfwWindow window) . toGLFWkey $
223 key 223 key
224 return $ if isDown then result : acc else acc 224 return $ if isDown then result : acc else acc
225 225
@@ -231,7 +231,7 @@ processButtons window = foldM f []
231 f acc (button, result) = do 231 f acc (button, result) = do
232 isDown <- 232 isDown <-
233 fmap (== GLFW.MouseButtonState'Pressed) $ 233 fmap (== GLFW.MouseButtonState'Pressed) $
234 gameIO . GLFW.getMouseButton (glfwWindow window) . toGLFWbutton $ 234 liftIO . GLFW.getMouseButton (glfwWindow window) . toGLFWbutton $
235 button 235 button
236 return $ if isDown then result : acc else acc 236 return $ if isDown then result : acc else acc
237 237