pituicat/src/Affection.hs

151 lines
4.9 KiB
Haskell
Raw Normal View History

{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE BangPatterns #-}
2020-05-03 23:36:12 +00:00
{-# LANGUAGE ExplicitForAll #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RankNTypes #-}
2020-05-04 03:17:44 +00:00
{-# LANGUAGE TypeApplications #-}
2016-03-25 08:41:22 +00:00
module Affection
( withAffection
2017-09-09 14:47:24 +00:00
, get
2017-11-04 17:35:09 +00:00
, put
2018-01-12 21:08:23 +00:00
, liftIO
2016-12-08 17:22:29 +00:00
, module A
2016-03-25 08:41:22 +00:00
) where
2017-10-03 10:47:18 +00:00
import SDL (($=))
import qualified SDL
2018-06-16 17:34:42 +00:00
import qualified SDL.Raw.Video as SDL (glSetAttribute)
import qualified SDL.Raw.Enum as SDL
2020-10-15 16:49:04 +00:00
import qualified Graphics.Rendering.OpenGL as GL (clear, flush, ClearBuffer(..))
import qualified Graphics.GL as GLRaw
import Foreign.Marshal.Array
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as B8
2016-11-02 00:14:53 +00:00
import System.Clock
import Control.Monad.Loops
2018-06-03 00:41:49 +00:00
import Control.Monad.State.Strict
2020-10-15 16:49:04 +00:00
-- internal imports
2016-12-08 17:22:29 +00:00
import Affection.Types as A
2020-05-03 23:36:12 +00:00
import Affection.Class as A
2017-03-05 15:39:37 +00:00
import Affection.StateMachine as A
2017-09-07 04:23:01 +00:00
import Affection.Util as A
2017-11-27 01:18:23 +00:00
import Affection.MessageBus as A
2017-12-13 14:19:53 +00:00
import Affection.Subsystems as A
import Affection.Logging as A
2016-03-25 15:58:46 +00:00
2016-11-06 04:02:06 +00:00
-- | Main function which bootstraps everything else.
withAffection
2020-05-04 03:17:44 +00:00
:: forall us. (Affectionate us)
2020-05-03 23:36:12 +00:00
=> AffectionConfig us -- ^ Configuration of the Game and its engine.
2016-11-06 04:02:06 +00:00
-> IO ()
2016-11-08 04:15:44 +00:00
withAffection AffectionConfig{..} = do
liftIO $ logIO Debug "Affection starting"
liftIO $ logIO Debug "Initializing SDL"
2017-02-23 21:54:26 +00:00
-- intialiaze SDL
case initComponents of
All ->
SDL.initializeAll
Only is ->
SDL.initialize is
2017-02-23 21:54:26 +00:00
-- give SDL render quality
SDL.HintRenderScaleQuality SDL.$= SDL.ScaleLinear
2020-10-15 16:49:04 +00:00
-- sync updates with monitor
SDL.swapInterval $= SDL.SynchronizedUpdates
2017-02-23 21:54:26 +00:00
-- just checking…
do
renderQuality <- SDL.get SDL.HintRenderScaleQuality
when (renderQuality /= SDL.ScaleLinear) $
2017-12-13 14:19:53 +00:00
logIO Warn "Linear texture filtering not enabled!"
2017-02-23 21:54:26 +00:00
-- construct window
2019-01-30 11:00:28 +00:00
liftIO $ logIO Debug "Creating Window(s)"
2020-05-03 23:36:12 +00:00
windows <- zip3 (map (\(x,_,_) -> x) windowConfigs) <$>
2019-01-30 11:00:28 +00:00
mapM
2020-05-03 23:36:12 +00:00
(\wc -> SDL.createWindow windowTitle ((\(_,y,_) -> y) wc))
windowConfigs <*>
pure (map (\(_,_,z) -> z) windowConfigs)
mapM_ (SDL.showWindow . (\(_,y,_) -> y)) windows
2018-06-16 17:34:42 +00:00
_ <- SDL.glSetAttribute SDL.SDL_GL_SHARE_WITH_CURRENT_CONTEXT 1
2020-05-03 23:36:12 +00:00
contexts <- zip (map (\(x,_,_) -> x) windows) <$>
mapM (SDL.glCreateContext . (\(_,y,_) -> y)) windows
mapM_ (\w -> flip SDL.setWindowMode ((\(_,_,z) -> z) w) ((\(_,y,_) -> y) w)) windows
2018-09-25 05:02:33 +00:00
-- SDL.swapInterval $= SDL.SynchronizedUpdates -- <- causes Problems with windows
liftIO $ logIO Debug "Getting Time"
2020-10-15 16:49:04 +00:00
-- print current used GL Version
2020-10-16 04:00:30 +00:00
version <- peekArray0 (0 :: Word8) =<< GLRaw.glGetString GLRaw.GL_VERSION
2020-10-15 16:49:04 +00:00
print (B.pack version)
2017-11-27 01:18:23 +00:00
-- get current time
2017-07-29 00:40:41 +00:00
execTime <- getTime Monotonic
liftIO $ logIO Debug "Loading initial data container"
2020-05-04 03:26:49 +00:00
-- construct game data object from provided Affectionate instance
2020-05-04 03:17:44 +00:00
gameData <- loadState @us
2020-05-04 03:26:49 +00:00
-- build state container
2020-05-03 23:36:12 +00:00
let initContainer = AffectionData
{ drawWindows = windows
, glContext = contexts
, elapsedTime = 0
, deltaTime = 0
, sysTime = execTime
, pausedTime = False
}
2020-05-04 03:26:49 +00:00
-- initialize and run state
2020-05-04 11:40:57 +00:00
(_, _) <- runStateT
2020-05-04 03:26:49 +00:00
(A.runState
2016-11-04 15:06:16 +00:00
(do
2020-05-04 03:26:49 +00:00
liftIO $ logIO Debug "Starting Loop"
-- run preLoop function from Affectionate
preLoop gameData
whileM_ (hasNextStep gameData)
(do
-- get state
ad <- get
-- Measure time difference form last run
now <- liftIO $ getTime Monotonic
let lastTime = sysTime ad
-- compute dt and update elapsedTime
let !dt = fromIntegral
(toNanoSecs $ diffTimeSpec lastTime now) / (10 ^ (9 :: Int))
!ne = elapsedTime ad + dt
-- update state data object with new time values
put $ ad
{ elapsedTime = ne
, deltaTime = dt
}
-- poll events
evs <- preHandleEvents =<< liftIO SDL.pollEvents
-- handle events
handleEvents gameData evs
-- execute user defined update loop
unless (pausedTime ad) (update gameData dt)
-- clear GL buffer >> execute user defined draw loop >> flush GL buffer
liftIO $ GL.clear [GL.ColorBuffer, GL.DepthBuffer, GL.StencilBuffer]
draw gameData
liftIO GL.flush
-- actual displaying of newly drawn frame
mapM_ (SDL.glSwapWindow . (\(_,y,_) -> y)) windows
2020-05-04 11:40:57 +00:00
-- save new time
2020-05-04 06:23:03 +00:00
ad3 <- get
when (sysTime ad == sysTime ad3) (
put ad3
{ sysTime = now
}
)
2020-05-04 03:26:49 +00:00
)
)
) initContainer
liftIO $ logIO Debug "Loop ended. Cleaning"
2020-05-03 23:36:12 +00:00
cleanUp gameData
liftIO $ logIO Debug "Destroying Window"
2019-01-30 11:00:28 +00:00
mapM_ (SDL.glDeleteContext . snd) contexts
2020-05-03 23:36:12 +00:00
mapM_ (SDL.destroyWindow . (\(_,y,_) -> y)) windows
2018-09-25 05:02:33 +00:00
-- SDL.quit -- <- This causes segfaults depending on hardware
liftIO $ logIO Debug "This is the end"