pub struct Grid { /* private fields */ }Expand description
A 2D buffer of Tiles, addressable across up to 256 stacked layers.
Layer 0 is always allocated; higher layers are allocated on first write, growing the
layer-table Vec up to that layer’s id as needed (see Grid::new). Single-layer use pays
no overhead: layers 1+ stay unallocated until used, and the layer table itself never grows
past a single slot.
Requires an allocator (backed by alloc::vec::Vec), so it is unavailable
in strictly static, no-alloc environments.
Implementations§
Source§impl Grid
impl Grid
Sourcepub fn new(width: u16, height: u16) -> Self
pub fn new(width: u16, height: u16) -> Self
Creates a new grid of the given dimensions.
Layer 0 is allocated immediately. Layers 1–255 are None until first
write via put_tile; the layer table itself only
grows as far as the highest layer id ever written, not all 256 slots
up front.
Sourcepub fn from_charmap<F>(map: &str, f: F) -> Self
pub fn from_charmap<F>(map: &str, f: F) -> Self
Build a grid from a rectangular character map, one Tile per cell.
map is split on \n; the grid width is the longest line’s character
count and the height is the number of lines. Lines shorter than the
widest are padded with the default tile. f maps each character to its
tile, called once per character in reading order.
Characters are counted as Unicode scalar values (one column each), which matches ASCII / CP437 maps and level/prefab strings. Wide characters are not width-adjusted.
§Example
use retroglyph_core::{Grid, Style, Tile};
let grid = Grid::from_charmap("##\n#.", |c| match c {
'#' => Tile::new('#', Style::default()),
_ => Tile::default(),
});
assert_eq!((grid.width(), grid.height()), (2, 2));
assert_eq!(grid.get(0, 0).glyph(), '#');
assert_eq!(grid.get(1, 1).glyph(), ' ');Sourcepub const fn max_layer(&self) -> u8
pub const fn max_layer(&self) -> u8
Returns the highest layer id that has ever been allocated.
Always at least 0 (layer 0 is always allocated). This only grows: clearing a layer does not deallocate it, so the value does not shrink once a higher layer has been written.
Sourcepub fn put(&mut self, x: u16, y: u16, tile: Tile)
pub fn put(&mut self, x: u16, y: u16, tile: Tile)
Sets the tile at the given coordinates on layer 0.
Since Tile cannot carry a multi-codepoint grapheme itself (see
grapheme), overwriting a cell this way always
clears any extra text previously stored for it – use
write_grapheme to write EGCs.
§Panics
Panics if the coordinates are out of bounds.
Sourcepub fn get(&self, x: u16, y: u16) -> &Tile
pub fn get(&self, x: u16, y: u16) -> &Tile
Gets the tile at the given coordinates on layer 0.
§Panics
Panics if the coordinates are out of bounds.
Sourcepub fn grapheme(&self, layer: u8, x: u16, y: u16) -> Option<&str>
pub fn grapheme(&self, layer: u8, x: u16, y: u16) -> Option<&str>
Returns the full grapheme cluster stored for the tile at (x, y) on
layer, if any.
Some only when the tile has TileFlags::HAS_EXTRA set, i.e. it
was written via write_grapheme with a
multi-codepoint EGC (combining marks, ZWJ sequences, etc.). For the
common single-codepoint case, or without the egc feature, this is
always None; use get_tile’s
Tile::glyph and
encode_utf8 to reconstruct the string instead.
Returns None if the layer is unallocated or the coordinates are out
of bounds.
Sourcepub fn checked_put(&mut self, x: u16, y: u16, tile: Tile) -> Option<()>
pub fn checked_put(&mut self, x: u16, y: u16, tile: Tile) -> Option<()>
Tries to set the tile at the given coordinates on layer 0.
Returns None if the coordinates are out of bounds. See
put for the EGC-clearing caveat.
Sourcepub fn checked_get(&self, x: u16, y: u16) -> Option<&Tile>
pub fn checked_get(&self, x: u16, y: u16) -> Option<&Tile>
Tries to get the tile at the given coordinates on layer 0.
Returns None if the coordinates are out of bounds.
Sourcepub fn checked_get_mut(&mut self, x: u16, y: u16) -> Option<&mut Tile>
pub fn checked_get_mut(&mut self, x: u16, y: u16) -> Option<&mut Tile>
Tries to get a mutable reference to the tile at the given coordinates on layer 0.
Returns None if the coordinates are out of bounds.
Sourcepub fn cells(&self, layer: u8) -> Option<Cells<'_>>
pub fn cells(&self, layer: u8) -> Option<Cells<'_>>
Iterates all tiles on layer with their (x, y) coordinates.
Returns None if the layer is unallocated.
Sourcepub fn cells_mut(&mut self, layer: u8) -> CellsMut<'_> ⓘ
pub fn cells_mut(&mut self, layer: u8) -> CellsMut<'_> ⓘ
Iterates all tiles on layer mutably with their (x, y) coordinates.
If the layer has not been written to yet, it is allocated first.
Sourcepub fn clear(&mut self, layer: u8)
pub fn clear(&mut self, layer: u8)
Clears a specific layer, resetting all tiles to the default.
Does nothing if the layer is unallocated.
Sourcepub fn resize(&mut self, width: u16, height: u16)
pub fn resize(&mut self, width: u16, height: u16)
Resize the grid to width × height tiles.
Content within the overlapping region is preserved on all allocated layers. New cells are initialised to the default tile. Shrinking discards tiles outside the new bounds.
Sourcepub fn write_grapheme(
&mut self,
layer: u8,
x: u16,
y: u16,
grapheme: &str,
style: Style,
)
pub fn write_grapheme( &mut self, layer: u8, x: u16, y: u16, grapheme: &str, style: Style, )
Write a grapheme cluster at (x, y) on layer 0, enforcing wide-
character invariants.
This is the canonical way to place content into the grid when the egc
feature is enabled. It:
- Clears any wide character whose primary or spacer cell would be overwritten.
- Sets
TileFlags::WIDE_CHARon the primary cell and places aTileFlags::WIDE_CHAR_SPACERin the adjacent cell for 2-column characters. - Stores multi-codepoint EGCs (combining marks, ZWJ sequences) in the
layer’s EGC side-table (see
grapheme), capped at 8 codepoints total.
Does nothing if (x, y) is out of bounds, if the grapheme has zero
display width, or if a 2-column wide character would overflow the grid
(the last column needs both its own cell and a spacer).
§Panics
Panics if the grapheme’s display width exceeds u16::MAX. In
practice this cannot happen: the maximum Unicode grapheme width is 2.
Only present when the egc feature is enabled.
Source§impl Grid
impl Grid
Sourcepub fn put_tile(&mut self, layer: u8, x: u16, y: u16, tile: Tile) -> Option<()>
pub fn put_tile(&mut self, layer: u8, x: u16, y: u16, tile: Tile) -> Option<()>
Write a tile to layer at (x, y).
Allocates the layer if it has not been written to yet. Returns None
if (x, y) is out of bounds.
To read back, use get_tile.
Like put, any tile written this way has its extra
grapheme text cleared, since a caller-constructed Tile can never
legitimately carry TileFlags::HAS_EXTRA (the flag is
crate-private). Internal callers that need to preserve EGC text
across a copy (e.g. blit) follow up with a direct
extras-table write.
Sourcepub fn get_tile(&self, layer: u8, x: u16, y: u16) -> Option<&Tile>
pub fn get_tile(&self, layer: u8, x: u16, y: u16) -> Option<&Tile>
Read a tile on layer at (x, y), or None if the layer is
unallocated or the coordinates are out of bounds.
Sourcepub fn blit(
&mut self,
layer: u8,
src: &Self,
src_rect: Rect,
dst_x: u16,
dst_y: u16,
)
pub fn blit( &mut self, layer: u8, src: &Self, src_rect: Rect, dst_x: u16, dst_y: u16, )
Copy tiles from src within src_rect to self at (dst_x, dst_y)
on layer. Empty tiles (nothing written; see Tile::is_empty) are
treated as transparent and skipped. An explicit space is copied and
overwrites the destination.
Walks src’s and self’s layer buffers directly by flat index instead of going through
get_tile/put_tile per cell (see retroglyph#263):
each of those recomputes a coordinate conversion and a bounds check per cell, which this
does once per row instead. The destination layer is allocated once, up front, rather than
as a side effect of the first written cell – but only if src_rect (clamped to src’s
bounds) contains at least one non-empty tile, matching put_tile’s original
allocate-on-first-write behavior for a src_rect that is entirely transparent.
Sourcepub fn blit_alpha(
&mut self,
layer: u8,
src: &Self,
src_rect: Rect,
dst_x: u16,
dst_y: u16,
mode: BlendMode,
fg_alpha: f32,
bg_alpha: f32,
)
pub fn blit_alpha( &mut self, layer: u8, src: &Self, src_rect: Rect, dst_x: u16, dst_y: u16, mode: BlendMode, fg_alpha: f32, bg_alpha: f32, )
Same as blit but blends foreground and background
colors with the given alpha factors, using mode to compute the
blended color. fg_alpha and bg_alpha are in 0.0-1.0 range where
0.0 = keep destination, 1.0 = replace with src; for a non-
Linear mode, “replace with src” instead means
“replace with mode’s fully blended color” (see BlendMode).
Blending operates on packed RGB values; Color::Default preserves
the destination. Non-RGB color variants (Ansi/Indexed) are passed
through unblended, regardless of mode.
Requires the gem feature (default on): BlendMode::Linear’s
per-channel color lerp is delegated to gem::rgb::Lerp; the other
modes delegate to alpha_blend::blend_modes::SeparableBlendMode.
Like blit (see retroglyph#262/#263), walks src’s and self’s layer
buffers directly by flat index instead of per-cell get_tile/
put_tile, and allocates the destination layer once, up front, rather
than as a side effect of the first written cell.
Sourcepub fn layers(
&self,
) -> impl Iterator<Item = (u8, Pos, &Tile, Option<&str>)> + '_
pub fn layers( &self, ) -> impl Iterator<Item = (u8, Pos, &Tile, Option<&str>)> + '_
Yield (layer_id, Pos, &Tile, Option<&str>) for every allocated cell
across all layers, in layer-major (0 → max_layer) then row-major
order. The last element is the tile’s grapheme text (see
grapheme), Some only when
TileFlags::HAS_EXTRA is set.
Unallocated layers are skipped. This is used by backends that need
the full frame on every draw (see crate::Output::needs_full_frame).
This iterator is zero-allocation: it walks the layer buffers inline.
Sourcepub fn diff<'a>(
&'a self,
other: &'a Self,
) -> impl Iterator<Item = (u8, Pos, &'a Tile, Option<&'a str>)> + 'a
pub fn diff<'a>( &'a self, other: &'a Self, ) -> impl Iterator<Item = (u8, Pos, &'a Tile, Option<&'a str>)> + 'a
Yield (layer_id, Pos, &Tile, Option<&str>) for every changed
position across all layers, in layer-major (0 → max_layer) then
row-major order. The last element is the changed tile’s grapheme text
(see grapheme).
Three cases per layer:
- Layer absent in
self: nothing yielded. - Layer in
self, absent inother(newly allocated): allwidth × heighttiles yielded. - Layer in both: only positions where the
Tileor its grapheme text differs are yielded.selfandothermust have matching dimensions for this case; the crate never callsdiffotherwise.
This iterator is zero-allocation: it walks the layer buffers inline.