Add bitmap font, UI primitives and a HUD with message log

Ports the CP437 font renderer from wds to the framebuffer: proportional
advance from measured ink bounds, luminance-keyed mask, word wrap. The
right 80 px strip becomes a HUD with name, HP bar, population and a log
fed from sim events; Attacked/Died now carry the type ids the log needs,
since the victim is gone from the world by the time events are read.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-20 17:31:17 +02:00
co-authored by Claude Opus 5
parent 03a12c82dc
commit bb12f095d8
9 changed files with 415 additions and 104 deletions
+12 -27
View File
@@ -2,35 +2,20 @@
## Current state
No UI primitives exist. The framebuffer is currently filled by the game world only
(`render_viewport` in `game.rs`: tile pass + entity sprite pass). `pixelhelper.rs` has
low-level pixel/blit helpers but nothing higher-level.
`game/src/ui.rs` — procedural primitives on the RGB565 framebuffer, all clipped:
`fill_rect`, `draw_rect` (1 px outline), `draw_hbar` (value/max bar).
## Goal
The HUD (`Game::render_hud` in `game.rs`) lives in the 80 px strip right of the 240×240
viewport: player name, HP bar, population counters, a divider, then the message log
filling the rest bottom-up (newest line always visible, lines wrapped to the panel).
The log is a `VecDeque<String>` fed from `Sim` events in `Game::handle_events`.
Draw common roguelike UI elements (panels, borders, HUD bars, etc.) procedurally into the
`u8` framebuffer, composited on top of the game world.
## Design notes
The virtual resolution is 320×240, so UI layout should be designed in those pixel units.
Likely primitives needed (built on top of `pixelhelper.rs`):
- `fill_rect(frame, x, y, w, h, color)` — solid filled rectangle
- `draw_rect(frame, x, y, w, h, color)` — 1-pixel border rectangle
- `draw_border_box(frame, x, y, w, h, tileset)` — box drawn with corner/edge tiles from
a tileset (classic roguelike panel look)
- `draw_hbar(frame, x, y, w, value, max, fg, bg)` — horizontal progress/HP bar
Panels are typically fixed regions of the screen (e.g. a status bar at the bottom 40px,
a message log on the right). Hard-coding these regions first is fine; extract to a layout
system only if needed.
The UI layer draws after the world layer so it always appears on top. Draw order within
the UI should be back-to-front (backgrounds before text).
Draw order: world, then HUD. The HUD overwrites the right-edge bleed of the tile pass,
which is why there is still no clip-rect on the blit primitives.
## Open questions
- Tileset-based borders vs. line-drawing: which look are we going for?
- Does the message log need scrolling? Probably not at first.
- Tileset-based borders vs. line-drawing: line-drawing for now (`draw_rect`); a 9-slice
ornament frame like `wds` has is an option once the look matters.
- Does the message log need scrolling? Not yet — `LOG_LINES` keeps 40, the panel shows
what fits.