retroglyph-window 0.5.1

Shared winit windowing layer for retroglyph's windowed backends
Documentation

retroglyph-window

crates.io docs.rs coverage license

A shared windowing layer for retroglyph's window-based backends (software today; GL/wgpu are future candidates). Input and Output are independent facets of Backend, which fits a terminal process (one type implements both) but not a window, where an event loop owns input and a renderer owns output separately: this crate keeps that split (Presenter is an Output supertrait; WindowBackend owns its own Input queue) and reassembles both into one Backend via winit.

Most consumers don't depend on this crate directly; use retroglyph-software instead, which depends on it.

Both graphical backends resolve every character through an ordered FontChain of 1-bit bitmap fonts, so a fallback font built with BitmapFont::with_charset supplies coverage the primary font has no mapping for (e.g. unscii16 has no quadrants, sextants, or braille; the legacy-computing feature below fills that gap). A chain glyph is drawn from the same 1-bit mask path as any other glyph and takes the cell's foreground color, unlike a tileset sprite, which carries the colors it was authored in. A single BitmapFont converts into a FontChain of one, so callers configuring just one font never construct a chain explicitly.

Quick start

cargo add retroglyph-window

Features

Default features: winit.

default-font

⚪ Optional.

Embeds the Unscii 16 default font (font::unscii16).

Off by default so a consumer that supplies its own bitmap font pays nothing for the ~4 KB atlas; the graphical backends' own default-font features forward to this one.

dev

⚪ Optional.

Forwards retroglyph-core's dev feature, which forces development diagnostics on in a build that would otherwise compile them out (see retroglyph_core::dev).

Forwarded so a consumer of this crate can turn them on without adding a direct dependency on core just to reach the flag.

legacy-computing

⚪ Optional.

Embeds a generated block-elements/braille fallback font (font::legacy_computing): the 10 quadrant, 60 sextant, and 256 braille glyphs CP437 (and so unscii16) has no mapping for.

A separate opt-in from default-font rather than folded into it: this repertoire is a much more niche/specialized addition (subcell image rendering, braille density tricks) than the base text font, so a consumer that only wants CP437 text shouldn't pay for it. Computed at compile time by a const fn, so this adds no font asset and no new dependency.

tilesets

⚪ Optional.

Shared PNG sprite/tileset support (tileset + sprite_cache modules, issue #366).

Both graphical backends' own tilesets features forward to this one.

winit

🟢 Enabled by default.

The winit event loop and event translation (run, translate, run_windowed/run_app).

Renderer crates that only implement Presenter can disable this and depend solely on raw-window-handle; loops other than winit (SDL2, tao, custom) bring their own driver against Presenter + WindowBackend.

A game never implements Presenter itself (that's retroglyph-software's job), but a new renderer backend does. This is the whole contract it implements, sized to fit a window from its own cell geometry via WindowConfig::fit:

use retroglyph_core::backend::DrawCell;
use retroglyph_core::backend::Output;
use retroglyph_core::grid::Size;
use retroglyph_window::winit::WindowConfig;
use retroglyph_window::{Presenter, WindowHandle};
use std::sync::Arc;

struct NullPresenter;

impl Output for NullPresenter {
    type Error = core::convert::Infallible;

    fn draw<'a, I>(&mut self, _content: I) -> Result<(), Self::Error>
    where
        I: Iterator<Item = DrawCell<'a>>,
    {
        Ok(())
    }

    fn draw_layers<'a, I>(&mut self, _content: I) -> Result<(), Self::Error>
    where
        I: Iterator<Item = DrawCell<'a>>,
    {
        Ok(())
    }

    fn flush(&mut self) -> Result<(), Self::Error> {
        Ok(())
    }

    fn size(&self) -> Size {
        Size::new(10, 5)
    }

    fn clear(&mut self) -> Result<(), Self::Error> {
        Ok(())
    }

    fn resize(&mut self, _size: Size) {}
}

impl Presenter for NullPresenter {
    type SurfaceError = core::convert::Infallible;

    fn init_surface(&mut self, _window: Arc<dyn WindowHandle>) -> Result<(), Self::SurfaceError> {
        Ok(())
    }

    fn resize_surface(&mut self, _width: u32, _height: u32) {}

    fn present(&mut self) -> Result<(), Self::SurfaceError> {
        Ok(())
    }

    fn cell_size(&self) -> (u32, u32) {
        (8, 16)
    }
}

let config = WindowConfig::fit(&NullPresenter, "demo", None, true);
assert_eq!((config.width(), config.height()), (80, 80));

Hand a real Presenter (e.g. retroglyph-software's SoftwareRenderer) and a config like this to run_windowed/run_app to actually open a window and drive the event loop.

See docs.rs for the API.