brillo-2.0.0: Brillo/Internals/Interface/Simulate.hs
{-# LANGUAGE RankNTypes #-}
module Brillo.Internals.Interface.Simulate (simulateWithBackendIO)
where
import Brillo.Data.Color
import Brillo.Data.Display
import Brillo.Data.Picture
import Brillo.Data.ViewPort
import Brillo.Data.ViewState
import Brillo.Internals.Interface.Animate.State qualified as AN
import Brillo.Internals.Interface.Animate.Timing
import Brillo.Internals.Interface.Backend
import Brillo.Internals.Interface.Callback qualified as Callback
import Brillo.Internals.Interface.Common.Exit
import Brillo.Internals.Interface.Simulate.Idle
import Brillo.Internals.Interface.Simulate.State qualified as SM
import Brillo.Internals.Interface.ViewState.KeyMouse
import Brillo.Internals.Interface.ViewState.Motion
import Brillo.Internals.Interface.ViewState.Reshape
import Brillo.Internals.Interface.Window
import Brillo.Rendering
import Data.IORef
import System.Mem
simulateWithBackendIO ::
forall model a.
(Backend a) =>
-- | Initial state of the backend
a ->
-- | Display mode.
Display ->
-- | Background color.
Color ->
-- | Number of simulation steps to take for each second of real time.
Int ->
-- | The initial model.
model ->
-- | A function to convert the model to a picture.
(model -> IO Picture) ->
{-| A function to step the model one iteration. It is passed the
current viewport and the amount of time for this simulation
step (in seconds).
-}
(ViewPort -> Float -> model -> IO model) ->
IO ()
simulateWithBackendIO
backend
display
backgroundColor
simResolution
worldStart
worldToPicture
worldAdvance =
do
let singleStepTime = 1
-- make the simulation state
stateSR <- newIORef $ SM.stateInit simResolution
-- make a reference to the initial world
worldSR <- newIORef worldStart
-- make the initial GL view and render states
viewSR <- newIORef viewStateInit
animateSR <- newIORef AN.stateInit
renderS_ <- initState
renderSR <- newIORef renderS_
let displayFun backendRef =
do
-- convert the world to a picture
world <- readIORef worldSR
port <- viewStateViewPort <$> readIORef viewSR
picture <- worldToPicture world
-- display the picture in the current view
renderS <- readIORef renderSR
windowSize <- getWindowDimensions backendRef
-- render the frame
displayPicture
windowSize
backgroundColor
renderS
(viewPortScale port)
(applyViewPortToPicture port picture)
-- perform GC every frame to try and avoid long pauses
performGC
let callbacks =
[ Callback.Display (animateBegin animateSR)
, Callback.Display displayFun
, Callback.Display (animateEnd animateSR)
, Callback.Idle
( callback_simulate_idle
stateSR
animateSR
(viewStateViewPort <$> readIORef viewSR)
worldSR
worldAdvance
singleStepTime
)
, callback_exit ()
, callback_viewState_keyMouse viewSR
, callback_viewState_motion viewSR
, callback_viewState_reshape
]
createWindow
backend
display
backgroundColor
callbacks
(const (return ()))