ansi-terminal-game 1.9.3.0 → 1.9.4.0
raw patch · 5 files changed
+101/−32 lines, 5 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
+ Terminal.Game: boldCell :: Cell -> Cell
+ Terminal.Game: cellsPlane :: Width -> Height -> [(Coords, Cell)] -> Plane
+ Terminal.Game: colorCell :: Color -> ColorIntensity -> Cell -> Cell
+ Terminal.Game: creaCell :: Char -> Cell
+ Terminal.Game: data Cell
+ Terminal.Game: paletteColorCell :: Word8 -> Cell -> Cell
+ Terminal.Game: reverseCell :: Cell -> Cell
+ Terminal.Game: rgbColorCell :: Colour Float -> Cell -> Cell
- Terminal.Game: class () => UniformRange a
+ Terminal.Game: class UniformRange a
- Terminal.Game: data () => ByteString
+ Terminal.Game: data ByteString
- Terminal.Game: data () => Color
+ Terminal.Game: data Color
- Terminal.Game: data () => ColorIntensity
+ Terminal.Game: data ColorIntensity
- Terminal.Game: data () => Colour a
+ Terminal.Game: data Colour a
- Terminal.Game: data () => Hyphenator
+ Terminal.Game: data Hyphenator
- Terminal.Game: data () => StdGen
+ Terminal.Game: data StdGen
- Terminal.Game: data () => Timed a
+ Terminal.Game: data Timed a
Files
- NEWS +18/−0
- ansi-terminal-game.cabal +12/−12
- src/Terminal/Game.hs +20/−0
- src/Terminal/Game/Layer/Object/IO.hs +42/−20
- src/Terminal/Game/Plane.hs +9/−0
NEWS view
@@ -1,3 +1,21 @@+1.9.4.0+-------++- Thanks to José Rafael Vieira, ansi-terminal-game now sports an API for+ efficient dense-grid drawing. `Cell` is exported, along with functions+ to create Cell`s++ creaCell, colorCell, rgbColorCell, paletteColorCell,+ boldCell, reverseCell++ The most important function is++ cellsPlane :: Width -> Height -> [(Coords, Cell)] -> Plane++ which merges the cells into a `Plane` in a single pass.+ Many thanks to José!++ 1.9.3.0 -------
ansi-terminal-game.cabal view
@@ -1,5 +1,5 @@ name: ansi-terminal-game-version: 1.9.3.0+version: 1.9.4.0 synopsis: cross-platform library for terminal games description: Library which aims to replicate standard 2d game functions (blit, ticks, timers, etc.) in a terminal@@ -24,7 +24,7 @@ test/records/alone-record-left.gr, test/records/balls-dims.gr, test/records/balls-slow.gr-cabal-version: >=1.10+cabal-version: >= 1.10 flag examples description: builds examples@@ -48,24 +48,24 @@ Terminal.Game.Layer.Object.Primitive, Terminal.Game.Layer.Object.Record, Terminal.Game.Layer.Object.Test,- Terminal.Game.Utils, Terminal.Game.Plane, Terminal.Game.Random,- Terminal.Game.Timer+ Terminal.Game.Timer,+ Terminal.Game.Utils build-depends: base == 4.*, ansi-terminal >= 1.0 && < 1.2, array == 0.5.*, bytestring >= 0.10 && < 0.13, cereal == 0.5.*, clock >= 0.7 && < 0.9,- containers >=0.6 && <0.8,+ containers >= 0.6 && < 0.9, exceptions == 0.10.*, file-embed >= 0.0.15 && < 0.1, linebreak == 1.1.*, mintty == 0.1.*,- mtl >=2.2 && <2.4,- QuickCheck >= 2.13 && < 2.15,- random >= 1.2 && < 1.3,+ mtl >= 2.2 && < 2.4,+ QuickCheck >= 2.13 && < 2.18,+ random >= 1.2 && < 1.4, split == 0.2.*, terminal-size == 0.3.*, unidecode >= 0.1.0 && < 0.2,@@ -113,14 +113,14 @@ bytestring >= 0.10 && < 0.13, cereal == 0.5.*, clock >= 0.7 && < 0.9,- containers >=0.6 && <0.8,+ containers >= 0.6 && < 0.9, exceptions == 0.10.*, file-embed >= 0.0.15 && < 0.1, linebreak == 1.1.*, mintty == 0.1.*,- mtl >=2.2 && <2.4,- QuickCheck >= 2.13 && < 2.15,- random >= 1.2 && < 1.3,+ mtl >= 2.2 && < 2.4,+ QuickCheck >= 2.13 && < 2.18,+ random >= 1.2 && < 1.4, split == 0.2.*, terminal-size == 0.3.*, unidecode >= 0.1.0 && < 0.2,
src/Terminal/Game.hs view
@@ -94,6 +94,18 @@ planePaper, planeSize, + -- *** Performance blitting+ -- $performance++ Cell,+ creaCell,+ colorCell,+ rgbColorCell,+ paletteColorCell,+ boldCell,+ reverseCell,+ cellsPlane,+ -- ** Draw Draw, (%), (&), (#),@@ -215,6 +227,14 @@ -- * If you use WASD for movement, you can readily gain compatibility with -- AZERTY keyboard layout by mapping “up” to both @W@ and @Z@ and “left” -- to @A@ and @Q@. Users from France, Belgium, and Québec will thank you.++-- $performance+-- Using 'Plane' for graphics is convenient due to the many primitives+-- for drawing. If you need extra performance, @ansi-terminal-game@+-- exposes 'Cell' functions too, for efficient dense-grid drawing.+--+-- Remember that most likely the bottleneck for your app will still be+-- the terminal your users run! -- | /Usable/ terminal display size (on Win32 console the last line is -- set aside for input). Throws 'CannotGetDisplaySize' on error.
src/Terminal/Game/Layer/Object/IO.hs view
@@ -47,7 +47,7 @@ startIOInput :: TPS -> IO InputHandle startIOInput tps = SI.hSetBuffering SI.stdin SI.NoBuffering >>- SI.hSetBuffering SI.stdout SI.NoBuffering >>+ SI.hSetBuffering SI.stdout (SI.BlockBuffering Nothing) >> SI.hSetEcho SI.stdin False >> -- all the buffering settings has to happen -- at the top of startIOInput. If i move@@ -101,7 +101,11 @@ vf d = CC.modifyMVar_ d (return . (++[e])) stopEventsIO :: [CC.ThreadId] -> IO ()-stopEventsIO ts = mapM_ CC.killThread ts+stopEventsIO ts = do+ mapM_ CC.killThread ts+ SI.hSetBuffering SI.stdout SI.NoBuffering+ -- We need this to make `alone-playback` work, see (thnks jrvieira):+ -- https://stackoverflow.com/questions/27324354/haskell-compiled-io-actionorder-and-flushing ----------------- -- Game timing --@@ -187,6 +191,20 @@ -- ANCILLARIES -- ----------------- +-- represent current terminal SGR State+-- so we can keep track of it between blits+data Style = Style { sBold :: Bool+ , sReversed :: Bool+ , sColor :: Maybe ColorInfo+ }+ deriving (Eq)++resetStyle :: Style+resetStyle = Style False False Nothing++cellToStyle :: Cell -> Style+cellToStyle c = Style (isBold c) (isReversed c) (cellColor c)+ initPart :: IO () initPart = -- check thread support CM.unless CC.rtsSupportsBoundThreads@@ -232,7 +250,8 @@ (error "blitMap: different plane sizes") >> CA.setCursorPosition 0 0 >> -- setCursorPosition is *zero* based!- blitToTerminal (0, 0) (orderedCells po) (orderedCells pn)+ blitToTerminal (0, 0) (orderedCells po) (orderedCells pn) >>+ SI.hFlush SI.stdout orderedCells :: Plane -> [[Cell]] orderedCells p = LS.chunksOf (fromIntegral w) cells@@ -240,46 +259,49 @@ cells = map snd $ assocsPlane p (w, _) = planeSize p - -- ordered sequence of cells, both old and new, like they were a String to -- print to screen. -- Coords: initial blitting position -- Remember that this Column is *zero* based blitToTerminal :: Coords -> [[Cell]] -> [[Cell]] -> IO ()-blitToTerminal (rr, rc) ocs ncs = CM.foldM_ blitLine rr oldNew+blitToTerminal (rr, rc) ocs ncs = CM.foldM_ blitLine (rr, resetStyle) oldNew where oldNew :: [[(Cell, Cell)]] oldNew = zipWith zip ocs ncs - -- row = previous row- blitLine :: Row -> [(Cell, Cell)] -> IO Row- blitLine pr ccs =- CM.foldM_ blitCell 0 ccs >>+ -- row = previous row, st = current terminal style+ blitLine :: (Row, Style) -> [(Cell, Cell)] -> IO (Row, Style)+ blitLine (pr, st) ccs =+ CM.foldM blitCell (0, st) ccs >>= \(_, st') ->+ let wr = pr + 1 in -- have to use setCursorPosition (instead of nextrow) b/c -- on win there is an auto "go-to-next-line" when reaching -- column end and on win it does not do so- let wr = pr + 1 in CA.setCursorPosition (fromIntegral wr) (fromIntegral rc) >>- return wr+ return (wr, st') -- k is "spaces to skip"- blitCell :: Int -> (Cell, Cell) -> IO Int- blitCell k (clo, cln)- | cln == clo = return (k+1)- | otherwise = moveIf k >>= \k' ->- putCellStyle cln >>- return k'+ blitCell :: (Int, Style) -> (Cell, Cell) -> IO (Int, Style)+ blitCell (k, st) (clo, cln)+ | cln == clo = return (k+1, st)+ | otherwise = moveIf k >>= \k' ->+ putCellStyle st cln >>= \st' ->+ return (k', st') moveIf :: Int -> IO Int moveIf k | k == 0 = return k | otherwise = CA.cursorForward k >> return 0 -putCellStyle :: Cell -> IO ()-putCellStyle c = CA.setSGR ([CA.Reset] ++ sgrb ++ sgrr ++ sgrc) >>- putChar (cellChar c)+putCellStyle :: Style -> Cell -> IO Style+putCellStyle st c =+ CM.when (st /= cst) (CA.setSGR ([CA.Reset] ++ sgrb ++ sgrr ++ sgrc)) >>+ putChar (cellChar c) >>+ return cst where+ cst = cellToStyle c+ sgrb | isBold c = [CA.SetConsoleIntensity CA.BoldIntensity] | otherwise = []
src/Terminal/Game/Plane.hs view
@@ -113,6 +113,15 @@ reverseCell (CellChar c b _ k) = CellChar c b True k reverseCell Transparent = Transparent +-- | Creates a 'Plane' from a list of individually styled cells. +-- More efficient than folding ('&') when drawing many cells +-- as it performs a single array update instead of one per cell. +-- Cells outside the plane bounds are silently ignored. +cellsPlane :: Width -> Height -> [(Coords, Cell)] -> Plane +cellsPlane w h cells = updatePlane (blankPlane w h) (filter inside cells) + where + inside ((r, c), _) = r >= 1 && r <= h && c >= 1 && c <= w + -- | Creates 'Plane' from 'String', good way to import ASCII -- art/diagrams. Returns a 1×1 transparent plane on empty string. stringPlane :: String -> Plane