packages feed

yampa-sdl2-0.0.1.1: src/YampaSDL2/Backend/Output.hs

module YampaSDL2.Backend.Output
  (outputAction) where

import qualified SDL
import qualified SDL.Primitive as GFX
import SDL.Vect
import Data.Colour.SRGB
import Data.List (sortBy)
import Data.StateVar (($=))
import Control.Monad

import YampaSDL2.AppOutput ( AppOutput(..)
                           , Graphics (..)
                           , Camera (..)
                           , RenderShape (..)
                           , ShapeColour (..)
                           )
import YampaSDL2.Geometry

outputAction :: SDL.Renderer -> Bool -> AppOutput -> IO Bool
outputAction renderer changed ao =
  when changed ( do
    let os =
          sortBy (\r1 r2 -> zIndex r1 `compare` zIndex r2) $ objects (graphics ao)
        c = camera (graphics ao)

    SDL.rendererDrawColor renderer $= V4 maxBound maxBound maxBound maxBound
    texture <-
      SDL.createTexture
        renderer
        SDL.RGB24
        SDL.TextureAccessTarget
        ((fmap round . cSize) c)
    SDL.rendererRenderTarget renderer $= return texture
    SDL.clear renderer
    mapM_ (renderView renderer c) os
    SDL.rendererRenderTarget renderer $= Nothing
    SDL.clear renderer
    SDL.copy renderer texture Nothing Nothing
    SDL.present renderer
    SDL.destroyTexture texture
    )
  >> return (shouldExit ao)

renderView :: SDL.Renderer -> Camera -> RenderShape -> IO ()
renderView renderer cam rs = do
  let cameraPoint = (cPos cam)
      cameraView = (cSize cam)

  case rs of
    Container {containerCentre=centre, children=cs } -> do
      mapM_ (renderView renderer (Camera (cameraPoint - centre) cameraView)) (sortBy (\r1 r2 -> zIndex r1 `compare` zIndex r2) cs)
    RS {shape=s} -> do
      let shapePoint = shapeCentre (shape rs)
          adjustedShape =
            s { shapeCentre =
              (shapePoint - cameraPoint) + cameraView/2
            }
      case adjustedShape of
        Rectangle {shapeCentre = V2 x y, rectSize = V2 w h} -> do
          let (RGB r g b) = toSRGB24 (sColour rs)
          let draw = if sFilled rs then GFX.fillRectangle else GFX.rectangle
          draw renderer
            (round <$> V2 (x - w / 2) (getY cameraView - (y + h / 2)))
            (round <$> V2 (x + w / 2) (getY cameraView - (y - h / 2)))
            (V4 r g b maxBound)
        Circle {shapeCentre = V2 x y, radius=rad} -> do
          let (RGB r g b) = toSRGB24 (sColour rs)
          let draw = if sFilled rs then GFX.fillCircle else GFX.circle
          draw renderer
            (round <$> V2 x y)
            (round rad)
            (V4 r g b maxBound)
        Triangle {shapeCentre=V2 x y, pointA=V2 pax pay, pointB=V2 pbx pby, pointC=V2 pcx pcy} -> do
          let (RGB r g b) = toSRGB24 (sColour rs)
          let draw = if sFilled rs then GFX.fillTriangle else GFX.smoothTriangle
          draw renderer
            (round <$> V2 (x + pax) (getY cameraView - (y + pay)))
            (round <$> V2 (x + pbx) (getY cameraView - (y + pby)))
            (round <$> V2 (x + pcx) (getY cameraView - (y + pcy)))
            (V4 r g b maxBound)
  return ()

sColour :: RenderShape -> Colour Double
sColour rs =
  case colour rs of
    (Filled a) -> a
    (Unfilled a) -> a

sFilled :: RenderShape -> Bool
sFilled rs =
  case colour rs of
    (Filled _) -> True
    (Unfilled _) -> False

getY :: V2 a -> a
getY (V2 _ y) = y