module Nes.Render (
    render,
) where

import Data.Map.Strict (empty)
import Data.Vector.Mutable
import Nes.Bus.State
import Nes.Render.Background
import Nes.Render.Frame
import Nes.Render.Monad
import qualified Nes.Render.Monad as Render
import Nes.Render.Sprite

render :: BusState -> Render DirtyFrame Rendered r ()
render :: forall r. BusState -> Render 'DirtyFrame 'Rendered r ()
render BusState
bus = Render.do
    Render 'DirtyFrame 'DirtyFrame r ()
forall (a :: RenderStep) r. Render a 'DirtyFrame r ()
clearAll
    BusState -> Render 'DirtyFrame 'BGDrawn r ()
forall r. BusState -> Render 'DirtyFrame 'BGDrawn r ()
renderBackground BusState
bus
    BusState -> Render 'BGDrawn 'BGAndSpritesDrawn r ()
forall r. BusState -> Render 'BGDrawn 'BGAndSpritesDrawn r ()
renderSprites BusState
bus
    Render 'BGAndSpritesDrawn 'Renderable r ()
forall r. Render 'BGAndSpritesDrawn 'Renderable r ()
applySprites
    Render 'Renderable 'Rendered r ()
forall r. Render 'Renderable 'Rendered r ()
renderPixels

{-# INLINE clearAll #-}
clearAll :: Render a DirtyFrame r ()
clearAll :: forall (a :: RenderStep) r. Render a 'DirtyFrame r ()
clearAll = Render.do
    (FrameState -> IO ()) -> Render a a r ()
forall a (b :: RenderStep) r.
(FrameState -> IO a) -> Render b b r a
withFrameState ((FrameState -> IO ()) -> Render a a r ())
-> (FrameState -> IO ()) -> Render a a r ()
forall a b. (a -> b) -> a -> b
$ \FrameState
st ->
        MVector (PrimState IO) (Color, PixelType)
-> (Color, PixelType) -> IO ()
forall (m :: * -> *) a.
PrimMonad m =>
MVector (PrimState m) a -> a -> m ()
set (Buffer (Color, PixelType) -> IOVector (Color, PixelType)
forall a. Buffer a -> IOVector a
unBuffer (Buffer (Color, PixelType) -> IOVector (Color, PixelType))
-> Buffer (Color, PixelType) -> IOVector (Color, PixelType)
forall a b. (a -> b) -> a -> b
$ FrameState -> Buffer (Color, PixelType)
pixelBuffer FrameState
st) ((Word8
0, Word8
0, Word8
0), PixelType
TransparentBG)
    (FrameState -> FrameState) -> Render a a r ()
forall (b :: RenderStep) r.
(FrameState -> FrameState) -> Render b b r ()
modifyFrameState ((FrameState -> FrameState) -> Render a a r ())
-> (FrameState -> FrameState) -> Render a a r ()
forall a b. (a -> b) -> a -> b
$ \FrameState
st -> FrameState
st{spritePixels = empty}
    Render a 'DirtyFrame r ()
forall (b :: RenderStep) (a :: RenderStep) r. Render a b r ()
unsafeStep

-- | Pulls pixels from 'pixelBuffer' to 'sdl2Frame'
{-# INLINE renderPixels #-}
renderPixels :: Render Renderable Rendered r ()
renderPixels :: forall r. Render 'Renderable 'Rendered r ()
renderPixels = Render.do
    (FrameState -> IO ()) -> Render 'Renderable 'Renderable r ()
forall a (b :: RenderStep) r.
(FrameState -> IO a) -> Render b b r a
withFrameState ((FrameState -> IO ()) -> Render 'Renderable 'Renderable r ())
-> (FrameState -> IO ()) -> Render 'Renderable 'Renderable r ()
forall a b. (a -> b) -> a -> b
$ \FrameState
st -> MVector (PrimState IO) (Color, PixelType)
-> (Int -> (Color, PixelType) -> IO ()) -> IO ()
forall (m :: * -> *) a b.
PrimMonad m =>
MVector (PrimState m) a -> (Int -> a -> m b) -> m ()
iforM_ (Buffer (Color, PixelType) -> IOVector (Color, PixelType)
forall a. Buffer a -> IOVector a
unBuffer (Buffer (Color, PixelType) -> IOVector (Color, PixelType))
-> Buffer (Color, PixelType) -> IOVector (Color, PixelType)
forall a b. (a -> b) -> a -> b
$ FrameState -> Buffer (Color, PixelType)
pixelBuffer FrameState
st) ((Int -> (Color, PixelType) -> IO ()) -> IO ())
-> (Int -> (Color, PixelType) -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Int
offset (Color
color, PixelType
_) ->
        let coord :: (Int, Int)
coord = (Int
offset Int -> Int -> Int
forall a. Integral a => a -> a -> a
`mod` Int
frameWidth, Int
offset Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
frameWidth)
         in Color -> (Int, Int) -> MemoryPointer -> IO ()
frameSetPixel Color
color (Int, Int)
coord (FrameState -> MemoryPointer
sdl2Frame FrameState
st)
    Render 'Renderable 'Rendered r ()
forall (b :: RenderStep) (a :: RenderStep) r. Render a b r ()
unsafeStep