esoeylemez / rapid

Rapid prototyping with GHCi
Other
55 stars 5 forks source link

Working with SDL #3

Open mgajda opened 4 years ago

mgajda commented 4 years ago

I tried to use rapid library with SDL2:

import SDL

develMain = rapid 0 $ \r -> do
  (win, rend) <- createRef "SDL" initSDL
  restart "mainloop" $ render (win, rend)

initSDL = do
  SDL.initialize [InitVideo]
  ctxWindow    <- SDL.createWindow "AlienExp" SDL.defaultWindow { SDL.windowInitialSize = SDL.V2 screenWidth screenHeight }
  ctxRenderer  <- SDL.createRenderer ctxWindow (-1) SDL.defaultRenderer

Unfortunately it hangs, and does not redraw window after GHC reload.

eyeinsky commented 3 years ago

Does SDL2 work from regular ghci?

mgajda commented 3 years ago

Without rapid? It seems it does.

mewhhaha commented 3 years ago

I had issues with the SDL2 window hanging when reloading with rapid and I "resolved" it by starting up the SDL2 resources in startWith asyncBound (Something to do with the stability of the thread? I actually don't know why it made it work better!). Maybe something similar would work here?

I do something akin to the following; and I'm able to change the step-function game to change the color of the window. While I was trying it out I had some issue when I didn't have a condition for exiting the loop in play then it would just hang indefinitely on startup (Why is this?). Maybe someone knows a better way of doing this. I just got it working and didn't want to touch it at risk of not making it work again. 😄

-- .ghcid
--command "stack ghci my-game" -W --test "Reload.update"

-- Reload.hs
...
import Game (game)
import Play (play)

update =
  Rapid.rapid 0 $ \r -> do
    var <- Rapid.createRef r "step" (newTMVarIO game)

    Rapid.startWith Async.asyncBound r "sdl" $ do
      play
        ( \renderer -> do
            step <- liftIO $ atomically $ readTMVar var
            step renderer
        )
        "test"
        (SDL.V2 640 480)

    _ <- atomically $ swapTMVar var game
    pure ()

-- Play.hs
...
rendererConfig :: SDL.RendererConfig
rendererConfig =
  SDL.RendererConfig
    { SDL.rendererType = SDL.AcceleratedVSyncRenderer,
      SDL.rendererTargetTexture = False
    }

play :: (SDL.Renderer -> IO ()) -> Text -> SDL.V2 CInt -> IO ()
play step title windowSize = do
  SDL.initialize [SDL.InitVideo]
  window <- SDL.createWindow title $ SDL.defaultWindow {SDL.windowInitialSize = windowSize}
  SDL.showWindow window
  renderer <- SDL.createRenderer window (-1) rendererConfig

  let loop = do
        events <- fmap SDL.eventPayload <$> SDL.pollEvents
        SDL.clear renderer
        step renderer
        SDL.present renderer
        unless (SDL.QuitEvent `elem` events) loop
  loop

-- Game.hs
...
game :: SDL.Renderer -> IO ()
game renderer = do
  SDL.rendererDrawColor renderer SDL.$= SDL.V4 14 0 0 0