aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Demos/Pong/Main.hs20
-rw-r--r--Spear/App.hs51
-rw-r--r--Spear/Game.hs12
-rw-r--r--Spear/Render/Immediate.hs4
4 files changed, 55 insertions, 32 deletions
diff --git a/Demos/Pong/Main.hs b/Demos/Pong/Main.hs
index 993c0ff..22b1021 100644
--- a/Demos/Pong/Main.hs
+++ b/Demos/Pong/Main.hs
@@ -7,7 +7,7 @@ import Pong
7import Spear.App 7import Spear.App
8import Spear.Game 8import Spear.Game
9import Spear.Math.AABB 9import Spear.Math.AABB
10import Spear.Math.Matrix4 as Matrix4 hiding (position) 10import Spear.Math.Matrix4 as Matrix4
11import Spear.Math.Spatial 11import Spear.Math.Spatial
12import Spear.Math.Spatial2 12import Spear.Math.Spatial2
13import Spear.Math.Vector 13import Spear.Math.Vector
@@ -20,12 +20,10 @@ import Spear.Sound.State
20import Spear.Window 20import Spear.Window
21 21
22import Control.Monad (when) 22import Control.Monad (when)
23import Data.Maybe (mapMaybe)
24 23
25 24
26data Pong = Pong 25data Pong = Pong
27 { immRenderState :: ImmRenderState 26 { viewProjection :: Matrix4
28 , viewProjection :: Matrix4
29 , backgroundMusic :: SoundSource 27 , backgroundMusic :: SoundSource
30 , world :: [GameObject] 28 , world :: [GameObject]
31 } 29 }
@@ -43,10 +41,6 @@ main = runApp app
43 41
44initGame :: Game AppContext Pong 42initGame :: Game AppContext Pong
45initGame = do 43initGame = do
46 renderCoreState <- contextRenderCoreState <$> get
47 (immRenderState, renderCoreState') <- runSiblingGame renderCoreState newImmRenderer
48 -- TODO: This can work if we use FlexibleContexts and change the function signatures.
49 --immRenderState <- newImmRenderer
50 music <- siblingGame $ do 44 music <- siblingGame $ do
51 musicBuffer <- loadAudioFile "/home/jeanne/Casual Tiki Party Main.wav" 45 musicBuffer <- loadAudioFile "/home/jeanne/Casual Tiki Party Main.wav"
52 music <- makeSoundSource 46 music <- makeSoundSource
@@ -54,13 +48,10 @@ initGame = do
54 setSoundLoopMode music Loop 48 setSoundLoopMode music Loop
55 playSounds [music] 49 playSounds [music]
56 return music 50 return music
57 return $ Pong immRenderState Matrix4.id music newWorld 51 return $ Pong Matrix4.id music newWorld
58 52
59endGame :: Game GameState () 53endGame :: Game GameState ()
60endGame = do 54endGame = return ()
61 renderCoreState <- appRenderCoreState <$> get
62 game <- getGameState
63 exec' runSiblingGame renderCoreState (deleteImmRenderer $ immRenderState game)
64 55
65 56
66step :: Elapsed -> Dt -> [InputEvent] -> Game GameState Bool 57step :: Elapsed -> Dt -> [InputEvent] -> Game GameState Bool
@@ -86,7 +77,7 @@ exitRequested = elem (KeyDown KEY_ESC)
86render :: Game GameState () 77render :: Game GameState ()
87render = do 78render = do
88 gameState <- getGameState 79 gameState <- getGameState
89 immRenderState' <- exec runSiblingGame (immRenderState gameState) $ do 80 siblingGame $ do
90 immStart 81 immStart
91 immSetViewProjectionMatrix (viewProjection gameState) 82 immSetViewProjectionMatrix (viewProjection gameState)
92 -- Clear the background to a different colour than the playable area to make 83 -- Clear the background to a different colour than the playable area to make
@@ -95,7 +86,6 @@ render = do
95 clearBuffers [ColourBuffer] 86 clearBuffers [ColourBuffer]
96 render' $ world gameState 87 render' $ world gameState
97 immEnd 88 immEnd
98 putGameState $ gameState { immRenderState = immRenderState' }
99 89
100render' :: [GameObject] -> Game ImmRenderState () 90render' :: [GameObject] -> Game ImmRenderState ()
101render' world = do 91render' world = do
diff --git a/Spear/App.hs b/Spear/App.hs
index 75bf6fa..6e8f5f2 100644
--- a/Spear/App.hs
+++ b/Spear/App.hs
@@ -1,3 +1,4 @@
1{-# LANGUAGE FlexibleInstances #-}
1{-# LANGUAGE MultiParamTypeClasses #-} 2{-# LANGUAGE MultiParamTypeClasses #-}
2 3
3module Spear.App 4module Spear.App
@@ -19,6 +20,7 @@ where
19 20
20import Spear.Game 21import Spear.Game
21import Spear.Render.Core.State 22import Spear.Render.Core.State
23import Spear.Render.Immediate
22import Spear.Sound.Sound 24import Spear.Sound.Sound
23import Spear.Sound.State 25import Spear.Sound.State
24import Spear.Sys.Timer as Timer 26import Spear.Sys.Timer as Timer
@@ -78,46 +80,61 @@ data AppContext = AppContext
78 { contextWindow :: Window 80 { contextWindow :: Window
79 , contextRenderCoreState :: RenderCoreState 81 , contextRenderCoreState :: RenderCoreState
80 , contextSoundState :: SoundState 82 , contextSoundState :: SoundState
83 , contextImmRenderState :: ImmRenderState
81 } 84 }
82 85
83instance HasState AppContext RenderCoreState where 86instance HasState AppContext RenderCoreState where
84 getInnerState = contextRenderCoreState 87 getInnerState = contextRenderCoreState
85 setInnerState context renderCoreState = context { contextRenderCoreState = renderCoreState } 88 setInnerState context state = context { contextRenderCoreState = state }
86 89
87instance HasState AppContext SoundState where 90instance HasState AppContext SoundState where
88 getInnerState = contextSoundState 91 getInnerState = contextSoundState
89 setInnerState context soundState = context { contextSoundState = soundState } 92 setInnerState context state = context { contextSoundState = state }
93
94instance HasState AppContext ImmRenderState where
95 getInnerState = contextImmRenderState
96 setInnerState context state = context { contextImmRenderState = state }
90 97
91-- | Application state. 98-- | Application state.
92data AppState s = AppState 99data AppState s = AppState
93 { appWindow :: Window 100 { appWindow :: Window
94 , appRenderCoreState :: RenderCoreState 101 , appRenderCoreState :: RenderCoreState
95 , appSoundState :: SoundState 102 , appSoundState :: SoundState
96 , customState :: s 103 , appImmRenderState :: ImmRenderState
104 , appCustomState :: s
97 } 105 }
98 106
107-- Requires FlexibleInstances.
108instance HasState (AppState s) s where
109 getInnerState = appCustomState
110 setInnerState appState state = appState { appCustomState = state }
111
99instance HasState (AppState s) RenderCoreState where 112instance HasState (AppState s) RenderCoreState where
100 getInnerState = appRenderCoreState 113 getInnerState = appRenderCoreState
101 setInnerState appState renderCoreState = appState { appRenderCoreState = renderCoreState } 114 setInnerState appState state = appState { appRenderCoreState = state }
102 115
103instance HasState (AppState s) SoundState where 116instance HasState (AppState s) SoundState where
104 getInnerState = appSoundState 117 getInnerState = appSoundState
105 setInnerState appState soundState = appState { appSoundState = soundState } 118 setInnerState appState state = appState { appSoundState = state }
119
120instance HasState (AppState s) ImmRenderState where
121 getInnerState = appImmRenderState
122 setInnerState appState state = appState { appImmRenderState = state }
106 123
107 124
108-- | Get the custom state in the app state. 125-- | Get the custom state in the app state.
109getGameState :: Game (AppState s) s 126getGameState :: Game (AppState s) s
110getGameState = customState <$> get 127getGameState = appCustomState <$> get
111 128
112-- | Put the custom state in the app state. 129-- | Put the custom state in the app state.
113putGameState :: s -> Game (AppState s) () 130putGameState :: s -> Game (AppState s) ()
114putGameState custom = do 131putGameState custom = do
115 appState <- get 132 appState <- get
116 put $ appState { customState = custom } 133 put $ appState { appCustomState = custom }
117 134
118-- | Modify the custom state in the app state. 135-- | Modify the custom state in the app state.
119modifyGameState :: (s -> s) -> Game (AppState s) () 136modifyGameState :: (s -> s) -> Game (AppState s) ()
120modifyGameState f = modify $ \appState -> appState { customState = f (customState appState )} 137modifyGameState f = modify $ \appState -> appState { appCustomState = f (appCustomState appState )}
121 138
122-- | Run the application. 139-- | Run the application.
123runApp :: App s -> IO () 140runApp :: App s -> IO ()
@@ -129,21 +146,29 @@ runApp app =
129 withWindow (w, h) (title ops) $ \window -> 146 withWindow (w, h) (title ops) $ \window ->
130 withSoundContext $ eval runGame () $ do 147 withSoundContext $ eval runGame () $ do
131 -- Create initial context. 148 -- Create initial context.
149 -- We could modify function signatures such as:
150 -- newImmRenderer :: HasState s RenderCoreState => Game s ImmRenderState
151 -- to simplify things a bit. But I'm not sure I want HasState to
152 -- proliferate like that right now.
132 initialSoundState <- eval runSiblingGame () initSoundSystem 153 initialSoundState <- eval runSiblingGame () initSoundSystem
133 let context = AppContext window newRenderCoreState initialSoundState 154 (immRenderState, renderCoreState) <- runSiblingGame newRenderCoreState newImmRenderer
155 let context = AppContext window renderCoreState initialSoundState immRenderState
134 -- Create initial app state. 156 -- Create initial app state.
135 (gameState, context') <- runSiblingGame context (initApp app) 157 (gameState, context') <- runSiblingGame context (initApp app)
136 let appState = AppState { 158 let appState = AppState {
137 appWindow = contextWindow context' 159 appWindow = contextWindow context'
138 , appRenderCoreState = contextRenderCoreState context' 160 , appRenderCoreState = contextRenderCoreState context'
139 , appSoundState = contextSoundState context' 161 , appSoundState = contextSoundState context'
140 , customState = gameState 162 , appImmRenderState = contextImmRenderState context'
163 , appCustomState = gameState
141 } 164 }
142 -- Run app. 165 -- Run app.
143 (result, endGameState) <- runSiblingGame appState (loop app window) 166 (result, endAppState) <- runSubGame appState $ do
167 loop app window
168 endApp app
144 -- Shut down. 169 -- Shut down.
145 exec' runSiblingGame endGameState (endApp app) 170 exec' runSiblingGame (appRenderCoreState endAppState) $ deleteImmRenderer (appImmRenderState endAppState)
146 exec' runSiblingGame (appSoundState appState) destroySoundSystem 171 exec' runSiblingGame (appSoundState endAppState) destroySoundSystem
147 172
148-- | Enter the main application loop. 173-- | Enter the main application loop.
149loop :: App s -> Window -> Game (AppState s) () 174loop :: App s -> Window -> Game (AppState s) ()
diff --git a/Spear/Game.hs b/Spear/Game.hs
index 1af8e9b..0c8b963 100644
--- a/Spear/Game.hs
+++ b/Spear/Game.hs
@@ -1,3 +1,4 @@
1{-# LANGUAGE FlexibleInstances #-}
1{-# LANGUAGE GeneralizedNewtypeDeriving #-} 2{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2{-# LANGUAGE MultiParamTypeClasses #-} 3{-# LANGUAGE MultiParamTypeClasses #-}
3 4
@@ -79,6 +80,11 @@ class HasState s t where
79 getInnerState :: s -> t 80 getInnerState :: s -> t
80 setInnerState :: s -> t -> s 81 setInnerState :: s -> t -> s
81 82
83-- Identity instance.
84instance HasState s s where
85 getInnerState = id
86 setInnerState s s' = s'
87
82 88
83-- | Release the given 'Resource'. 89-- | Release the given 'Resource'.
84release' :: ResourceClass a => a -> Game s () 90release' :: ResourceClass a => a -> Game s ()
@@ -129,7 +135,7 @@ exec' runner game state = void $ runner game state
129-- | Run a sibling game on nested state. 135-- | Run a sibling game on nested state.
130siblingGame :: HasState s t => Game t a -> Game s a 136siblingGame :: HasState s t => Game t a -> Game s a
131siblingGame tAction = do 137siblingGame tAction = do
132 tState <- getInnerState <$> get 138 outerState <- getInnerState <$> get
133 (result, tState') <- runSiblingGame tState tAction 139 (result, outerState') <- runSiblingGame outerState tAction
134 modify $ \outerState -> setInnerState outerState tState' 140 modify $ \outerState -> setInnerState outerState outerState'
135 return result 141 return result
diff --git a/Spear/Render/Immediate.hs b/Spear/Render/Immediate.hs
index b3a8998..786e844 100644
--- a/Spear/Render/Immediate.hs
+++ b/Spear/Render/Immediate.hs
@@ -74,7 +74,9 @@ deleteImmRenderer immState = do
74 deleteGeometry (triangles immState) 74 deleteGeometry (triangles immState)
75 75
76-- The functions below are all defined inside the Game ImmRenderState monad so 76-- The functions below are all defined inside the Game ImmRenderState monad so
77-- that all of the drawing can conveniently happen inside the monad. 77-- that all of the drawing can conveniently happen inside the monad. They could
78-- technically be defined inside MonadIO, but then we would have to explicitly
79-- pass in the ImmRenderState.
78 80
79immStart :: Game ImmRenderState () 81immStart :: Game ImmRenderState ()
80immStart = do 82immStart = do