parabox/app/Rendering.hs
2022-12-02 10:54:31 -08:00

126 lines
3.7 KiB
Haskell

module Rendering where
import Data.Array
import Data.Map (Map)
import Data.Map qualified as Map
import Data.Set qualified as Set
import Graphics.Vty
import Data.List (intersperse)
import Model
renderBox :: World -> Map Location Char -> Box -> Char -> Image
renderBox world locMap box boxName =
vertCat
[
horizCat
[
if boxWalls box ! (y,x) then unit myAttr '▓'
else case Map.lookup (Location boxName y x) locMap of
Nothing -> unit myAttr '░'
Just n -> unit (boxColor (worldBoxes world Map.! n)) n
| x <- [xlo .. xhi]
]
| let ((ylo,xlo),(yhi,xhi)) = bounds (boxWalls box)
, let myAttr = boxColor box
, y <- [ylo .. yhi]
, let unit a x = string a [x,x]
]
renderBox' :: World -> Map Location Char -> Box -> Char -> Int -> Image
renderBox' world locMap box boxName scale
| scale == 1 = renderBox world locMap box boxName
| otherwise =
vertCat
[
horizCat
[
if boxWalls box ! (y,x) then unit myAttr '▓'
else case Map.lookup (Location boxName y x) locMap of
Nothing -> unit myAttr '░'
Just n -> renderBox' world locMap box' n (scale `div` boxSize box)
where
box' = worldBoxes world Map.! n
| x <- [xlo .. xhi]
]
| let ((ylo,xlo),(yhi,xhi)) = bounds (boxWalls box)
, let myAttr = boxColor box
, y <- [ylo .. yhi]
]
where
unit a x =
vertCat (replicate scale (string a (replicate (2*scale) x)))
drawNestedWorld :: World -> Image
drawNestedWorld world =
-- (3*49) + 49 + (3*49)
cropTop (49 + 2*border) $
cropLeft (2*(49 + 2*border)) $
cropBottom (2*49 + border) $
cropRight (2*(2*49 + border)) $
vertCat [
horizCat [
case stackedLoc world (Location name1 y x) of
Nothing -> unit (withForeColor defAttr black) '?'
Just (Location n y x) ->
let box = worldBoxes world Map.! n
myAttr = boxColor box in
if boxWalls box ! (y,x) then unit myAttr '▓'
else case Map.lookup (Location n y x) locMap of
Nothing -> unit myAttr '░'
Just n -> renderBox' world locMap box' n (49 `div` boxSize box)
where
box' = worldBoxes world Map.! n
| x <- [x1-1 .. x1+1]
]
| y <- [y1-1 .. y1+1]
]
where
border = 20
unit a x =
vertCat (replicate 49 (string a (replicate (2*49) x)))
locMap = Map.fromList [(boxLocation loc, n) | (n, loc) <- Map.toList (worldBoxes world)]
-- name1 is the box the player is standing in
Location name0 _ _ = boxLocation (worldBoxes world Map.! worldMe world)
Location name1 y1 x1 = boxLocation (worldBoxes world Map.! name0)
drawWorld :: World -> Image
drawWorld world =
horizCat $
intersperse (char defAttr ' ')
[
renderBox world locMap box boxName
| (boxName, box) <- Map.toList (worldBoxes world)
]
where
locMap = Map.fromList [(boxLocation loc, n) | (n, loc) <- Map.toList (worldBoxes world)]
stackedLoc :: World -> Location -> Maybe Location
stackedLoc world = go Set.empty
where
go visited loc | Set.member loc visited = Nothing
go visited loc@(Location b y x) =
do box <- Map.lookup b (worldBoxes world)
let bnds@((ylo,xlo),(yhi,xhi)) = bounds (boxWalls box)
if inRange bnds (y, x)
then Just loc
else
let dx = overflow (xlo,xhi) x
dy = overflow (ylo,yhi) y
Location parent py px = boxLocation box
in go (Set.insert loc visited) (Location parent (py+dy) (px+dx))
overflow :: (Int, Int) -> Int -> Int
overflow (lo,hi) x
| x < lo = x - lo
| x > hi = x - hi
| otherwise = 0