haskell-snake-1.0.0: src/Game/HSnake/Graphics.hs
module Game.HSnake.Graphics where
import Game.HSnake.Basic
import Game.HSnake.Board
import Game.HSnake.Game
import Game.HSnake.Player
import Game.HSnake.Snake
import Control.Lens
import Control.Monad.IO.Class (MonadIO(..))
import Data.Text (pack)
import qualified Data.Vector.Storable as DVS
import Data.Word
import Linear
import Linear.Affine
import Foreign.C.Types (CInt(..))
import qualified SDL
import qualified SDL.Font as SDLF
type SDLRect = SDL.Rectangle CInt
setColor :: SDL.Renderer -> Colour -> IO ()
setColor r White = SDL.rendererDrawColor r SDL.$= SDL.V4 maxBound maxBound maxBound maxBound
setColor r Red = SDL.rendererDrawColor r SDL.$= SDL.V4 maxBound 0 0 maxBound
setColor r Green = SDL.rendererDrawColor r SDL.$= SDL.V4 0 maxBound 0 maxBound
setColor r Blue = SDL.rendererDrawColor r SDL.$= SDL.V4 0 0 maxBound maxBound
setColor r Yellow = SDL.rendererDrawColor r SDL.$= SDL.V4 maxBound maxBound 0 maxBound
setColor r Black = SDL.rendererDrawColor r SDL.$= SDL.V4 0 0 0 maxBound
sdlColor :: Colour -> SDLF.Color
sdlColor Black = SDL.V4 0 0 0 maxBound
sdlColor White = SDL.V4 maxBound maxBound maxBound maxBound
screenWidth :: Int
screenWidth = 640
screenHeight :: Int
screenHeight = 480
screenBpp :: Int
screenBpp = 32
gameScreenWidth :: Int
gameScreenWidth = 540
gameScreenHeight :: Int
gameScreenHeight = 400
messageScreenWidth :: Int
messageScreenWidth = screenWidth - gameScreenWidth
messageScreenHeight :: Int
messageScreenHeight = screenHeight - gameScreenHeight
rectWidth :: Int
rectWidth = gameScreenWidth `div` numRectsX
rectHeight :: Int
rectHeight = gameScreenHeight `div` numRectsY
rectFromPoint :: Game.HSnake.Basic.Point -> SDLRect
rectFromPoint (Game.HSnake.Basic.Point x y) = SDL.Rectangle startPoint size
where
startX = (x - 1)*rectWidth + 1
startY = (y - 1)*rectHeight + 1
width = rectWidth - 1
height = rectHeight - 1
startPoint = P $ V2 (fromIntegral startX) (fromIntegral startY)
size = V2 (fromIntegral width) (fromIntegral height)
rects = [rectFromPoint (Game.HSnake.Basic.Point ptx pty) | ptx <- [1..numRectsX], pty <- [1..numRectsY]]
rectsVec = DVS.generate (numRectsX * numRectsY)
(\i -> rects !! i )
paintRects :: SDL.Renderer -> Colour -> IO ()
paintRects r color = do
setColor r color
SDL.fillRects r rectsVec
paintBoard :: SDL.Renderer -> IO ()
paintBoard r = do
paintRects r White
paintApple :: SDL.Renderer -> Game.HSnake.Basic.Point -> IO ()
paintApple r ap = do
setColor r Red
SDL.fillRect r $ Just rect
where
rect = rectFromPoint ap
-- | TODO: paint different snakes with different colors
paintPlayer :: SDL.Renderer -> Player -> IO ()
paintPlayer r p = paintSnake r (p^.snake) (p^.colour)
paintSnake :: SDL.Renderer -> Snake -> Colour -> IO ()
paintSnake r s c =
mapM_ (\p -> paintSnakePiece r (rectFromPoint p) c) (s^.position)
paintSnakePiece :: SDL.Renderer -> SDLRect -> Colour -> IO ()
paintSnakePiece r rect c = do
setColor r c
SDL.fillRect r $ Just rect
showGameMessages :: SDL.Window -> GameState -> IO ()
showGameMessages w gameState = do
font <- SDLF.load "liberation.ttf" 25
surface <- SDLF.solid font color levelMessage
screen <- SDL.getWindowSurface w
renderSurfaceToWindow w screen surface startPoint
SDL.freeSurface screen
SDL.freeSurface surface
SDLF.free font
where
levelMessage = pack $ "Level " ++ (show $ gameState^.level)
color = sdlColor White
startPoint = P $ V2 (fromIntegral gameScreenWidth) 0
renderSurfaceToWindow :: (MonadIO m) => SDL.Window -> SDL.Surface -> SDL.Surface -> (SDL.Point V2 CInt) -> m ()
renderSurfaceToWindow w s i startPoint = do
SDL.surfaceBlit i Nothing s (Just startPoint)
return ()
clearScreen :: SDL.Renderer -> IO ()
clearScreen r = do
setColor r Black
SDL.clear r
clearSurface :: SDL.Surface -> IO ()
clearSurface s = do
SDL.surfaceFillRect s Nothing (sdlColor Black)