packages feed

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 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