aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2024-12-30 12:48:31 -0800
committer3gg <3gg@shellblade.net>2024-12-30 12:48:31 -0800
commit34cac097d15cdd7ef0a0de8b9024db9acfe8618d (patch)
treefa573d4d4436abfa83b940938c385e929dbabd06
parentd30b146ce320a48d58d37a8f191daa4ef29fbc67 (diff)
Move window setup to App.
-rw-r--r--Demos/Pong/Main.hs9
-rw-r--r--Spear/App.hs53
-rw-r--r--Spear/Window.hs61
3 files changed, 65 insertions, 58 deletions
diff --git a/Demos/Pong/Main.hs b/Demos/Pong/Main.hs
index 66fa223..de8e6f2 100644
--- a/Demos/Pong/Main.hs
+++ b/Demos/Pong/Main.hs
@@ -26,14 +26,13 @@ data GameState = GameState
26 , world :: [GameObject] 26 , world :: [GameObject]
27 } 27 }
28 28
29options = defaultAppOptions { title = "Pong" }
29 30
30app = App defaultAppOptions step render resize 31app = App options initGame endGame step render resize
31 32
32 33
33main = 34main :: IO ()
34 withWindow (1920, 1200) (Just "Pong") initGame endGame $ 35main = runApp app
35 loop app
36
37 36
38initGame :: Window -> Game () GameState 37initGame :: Window -> Game () GameState
39initGame window = do 38initGame window = do
diff --git a/Spear/App.hs b/Spear/App.hs
index 7f23359..61ea3b1 100644
--- a/Spear/App.hs
+++ b/Spear/App.hs
@@ -1,11 +1,13 @@
1module Spear.App 1module Spear.App
2 ( App(..), 2( App(..)
3 Elapsed, 3, AppOptions(..)
4 Dt, 4, Elapsed
5 Step, 5, Dt
6 defaultAppOptions, 6, Step
7 loop, 7, defaultAppOptions
8 ) 8, runApp
9, loop
10)
9where 11where
10 12
11import Control.Monad 13import Control.Monad
@@ -26,26 +28,45 @@ type Step s = Elapsed -> Dt -> [InputEvent] -> Game s Bool
26 28
27-- | Application options. 29-- | Application options.
28data AppOptions = AppOptions 30data AppOptions = AppOptions
29 { maxFPS :: Int 31 { title :: String
32 , windowWidth :: Int
33 , windowHeight :: Int
34 , maxFPS :: Int
30 , animationFPS :: Int 35 , animationFPS :: Int
31 , enableProfiling :: Bool 36 , enableProfiling :: Bool
32 } 37 }
33 38
34defaultAppOptions = AppOptions 39defaultAppOptions = AppOptions
35 { maxFPS = 0 -- If non-zero, cap frame rate to this value. 40 { title = "Spear Application"
41 , windowWidth = 1920
42 , windowHeight = 1080
43 , maxFPS = 0 -- If non-zero, cap frame rate to this value.
36 , animationFPS = 60 -- If non-zero, use fixed time step animation. 44 , animationFPS = 60 -- If non-zero, use fixed time step animation.
37 , enableProfiling = False 45 , enableProfiling = False
38 } 46 }
39 47
40-- | Application state. 48-- | Application state.
41data App s = App 49data App s = App
42 { options :: AppOptions 50 { appOptions :: AppOptions
43 , stepApp :: Step s 51 , initApp :: Window -> Game () s
44 , renderApp :: Game s () 52 , endApp :: Game s ()
45 , resizeApp :: WindowEvent -> Game s () 53 , stepApp :: Step s
54 , renderApp :: Game s ()
55 , resizeApp :: WindowEvent -> Game s ()
46 } 56 }
47 57
48 58
59-- | Run the application.
60runApp :: App s -> IO ()
61runApp app =
62 let ops = appOptions app
63 w = windowWidth ops
64 h = windowHeight ops
65 in withWindow (w, h) (title ops) $ \window -> flip evalGame () $ do
66 gameState <- initApp app window
67 (result, endGameState) <- runSubGame (loop app window) gameState
68 runSubGame' (endApp app) endGameState
69
49-- | Convert FPS to desired delta time. 70-- | Convert FPS to desired delta time.
50fpsToDdt :: Int -> TimeDelta 71fpsToDdt :: Int -> TimeDelta
51fpsToDdt fps = if fps > 0 then secToTimeDelta (1.0 / fromIntegral fps) else 0 72fpsToDdt fps = if fps > 0 then secToTimeDelta (1.0 / fromIntegral fps) else 0
@@ -59,8 +80,8 @@ loop app window = do
59 resizeApp app (ResizeEvent width height) 80 resizeApp app (ResizeEvent width height)
60 renderApp app 81 renderApp app
61 82
62 let ddt = fpsToDdt . maxFPS . options $ app -- Desired render time step. 83 let ddt = fpsToDdt . maxFPS . appOptions $ app -- Desired render time step.
63 let animationDdt = fpsToDdt . animationFPS . options $ app -- Desired animation time step. 84 let animationDdt = fpsToDdt . animationFPS . appOptions $ app -- Desired animation time step.
64 85
65 timer <- gameIO newTimer 86 timer <- gameIO newTimer
66 gameIO $ Timer.start timer 87 gameIO $ Timer.start timer
@@ -121,7 +142,7 @@ loop' window renderDdt animationDdt lastAnimationTime inputTimer app = do
121 142
122 -- Limit frame rate if so requested by the application. 143 -- Limit frame rate if so requested by the application.
123 -- This currently makes the rendering stutter and is not very desirable. 144 -- This currently makes the rendering stutter and is not very desirable.
124 when ((maxFPS . options $ app) > 0) $ do 145 when ((maxFPS . appOptions $ app) > 0) $ do
125 frameEnd <- gameIO now 146 frameEnd <- gameIO now
126 let ddt = renderDdt 147 let ddt = renderDdt
127 let frameTime = timeDiff (lastTick timer) frameEnd 148 let frameTime = timeDiff (lastTick timer) frameEnd
diff --git a/Spear/Window.hs b/Spear/Window.hs
index 65ca243..2dcd1fa 100644
--- a/Spear/Window.hs
+++ b/Spear/Window.hs
@@ -7,7 +7,6 @@ module Spear.Window
7 Window, 7 Window,
8 Width, 8 Width,
9 Height, 9 Height,
10 Init,
11 WindowEvent(..), 10 WindowEvent(..),
12 withWindow, 11 withWindow,
13 pollWindowEvents, 12 pollWindowEvents,
@@ -21,10 +20,10 @@ module Spear.Window
21 whenKeyUp, 20 whenKeyUp,
22 processKeys, 21 processKeys,
23 processButtons, 22 processButtons,
24 InputEvent (..), 23 InputEvent(..),
25 Key (..), 24 Key(..),
26 MouseButton (..), 25 MouseButton(..),
27 MouseProp (..), 26 MouseProp(..),
28 MousePos, 27 MousePos,
29 MouseDelta, 28 MouseDelta,
30 ) 29 )
@@ -52,12 +51,6 @@ type Dimensions = (Width, Height)
52 51
53type WindowTitle = String 52type WindowTitle = String
54 53
55-- | Game initialiser.
56type Init s = Window -> Game () s
57
58-- | Game finalizer.
59type End s = Game s ()
60
61-- | Window exception. 54-- | Window exception.
62newtype WindowException = WindowException String deriving (Show) 55newtype WindowException = WindowException String deriving (Show)
63 56
@@ -85,28 +78,22 @@ data Window = Window
85 78
86withWindow :: 79withWindow ::
87 Dimensions -> 80 Dimensions ->
88 Maybe WindowTitle -> 81 WindowTitle ->
89 Init s -> 82 (Window -> IO a) ->
90 End s ->
91 (Window -> Game s a) ->
92 IO a 83 IO a
93withWindow dim@(w, h) windowTitle init end run = do 84withWindow dim@(w, h) windowTitle run = do
94 flip evalGame () $ do 85 window <- do
95 window <- gameIO $ do 86 success <- GLFW.init
96 success <- GLFW.init 87 unless success $ throw (WindowException "GLFW.initialize failed")
97 unless success $ throw (WindowException "GLFW.initialize failed") 88 setup dim windowTitle
98 setup dim windowTitle 89 result <- run window
99 gameState <- init window 90 GLFW.destroyWindow $ glfwWindow window
100 (result, endGameState) <- runSubGame (run window) gameState 91 GLFW.terminate
101 runSubGame' end endGameState 92 return result
102 gameIO $ do
103 GLFW.destroyWindow $ glfwWindow window
104 GLFW.terminate
105 return result
106 93
107setup :: 94setup ::
108 Dimensions -> 95 Dimensions ->
109 Maybe WindowTitle -> 96 WindowTitle ->
110 IO Window 97 IO Window
111setup (w, h) windowTitle = do 98setup (w, h) windowTitle = do
112 closeRequest <- newEmptyMVar 99 closeRequest <- newEmptyMVar
@@ -118,7 +105,7 @@ setup (w, h) windowTitle = do
118 GLFW.windowHint $ GLFW.WindowHint'ContextVersionMajor major 105 GLFW.windowHint $ GLFW.WindowHint'ContextVersionMajor major
119 GLFW.windowHint $ GLFW.WindowHint'ContextVersionMinor minor 106 GLFW.windowHint $ GLFW.WindowHint'ContextVersionMinor minor
120 when (major >= 3) $ GLFW.windowHint $ GLFW.WindowHint'OpenGLProfile GLFW.OpenGLProfile'Core 107 when (major >= 3) $ GLFW.windowHint $ GLFW.WindowHint'OpenGLProfile GLFW.OpenGLProfile'Core
121 GLFW.createWindow w h (fromMaybe "Spear" windowTitle) Nothing Nothing 108 GLFW.createWindow w h windowTitle Nothing Nothing
122 109
123 unless (isJust maybeWindow) 110 unless (isJust maybeWindow)
124 $ throwIO (WindowException "GLFW.openWindow failed") 111 $ throwIO (WindowException "GLFW.openWindow failed")
@@ -141,7 +128,7 @@ setup (w, h) windowTitle = do
141pollInputEvents :: Window -> IO [InputEvent] 128pollInputEvents :: Window -> IO [InputEvent]
142pollInputEvents window = do 129pollInputEvents window = do
143 GLFW.pollEvents 130 GLFW.pollEvents
144 getEvents (inputEventsMVar window) 131 getEvents (inputEventsMVar window)
145 132
146-- | Poll for window events. 133-- | Poll for window events.
147pollWindowEvents :: Window -> IO [WindowEvent] 134pollWindowEvents :: Window -> IO [WindowEvent]
@@ -206,23 +193,23 @@ replaceMVar mvar val = tryTakeMVar mvar >> putMVar mvar val
206addEvent :: MVar [a] -> a -> IO () 193addEvent :: MVar [a] -> a -> IO ()
207addEvent mvar val = 194addEvent mvar val =
208 tryTakeMVar mvar >>= \xs -> case xs of 195 tryTakeMVar mvar >>= \xs -> case xs of
209 Nothing -> putMVar mvar [val] -- >> (putStrLn $ show val) 196 Nothing -> putMVar mvar [val]
210 Just events -> putMVar mvar (val : events) -- >> (putStrLn $ show (val:events)) 197 Just events -> putMVar mvar (val : events)
211 198
212-- Input 199-- Input
213 200
214-- | Run the game action when the key is down. 201-- | Run the game action when the key is down.
215whenKeyDown :: GLFW.Window -> Key -> Game s a -> Game s () 202whenKeyDown :: GLFW.Window -> Key -> Game s () -> Game s ()
216whenKeyDown = whenKeyInState GLFW.KeyState'Pressed 203whenKeyDown = whenKeyInState GLFW.KeyState'Pressed
217 204
218-- | Run the game action when the key is up. 205-- | Run the game action when the key is up.
219whenKeyUp :: GLFW.Window -> Key -> Game s a -> Game s () 206whenKeyUp :: GLFW.Window -> Key -> Game s () -> Game s ()
220whenKeyUp = whenKeyInState GLFW.KeyState'Released 207whenKeyUp = whenKeyInState GLFW.KeyState'Released
221 208
222whenKeyInState :: GLFW.KeyState -> GLFW.Window -> Key -> Game s a -> Game s () 209whenKeyInState :: GLFW.KeyState -> GLFW.Window -> Key -> Game s () -> Game s ()
223whenKeyInState state window key game = do 210whenKeyInState state window key game = do
224 isDown <- fmap (==state) $ gameIO . GLFW.getKey window . toGLFWkey $ key 211 isDown <- fmap (==state) $ gameIO . GLFW.getKey window . toGLFWkey $ key
225 when isDown $ void game 212 when isDown game
226 213
227-- | 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
228-- with each of the pressed keys. 215-- with each of the pressed keys.