Switch to 16-bit truecolor framebuffer and PNG assets

pbio moves to git.bnd.wtf/irrlicht/pbio.git branch truecolor16: the
framebuffer is now RGB565 u16, no palette. Assets are loaded from PNG via
the png crate and quantized to RGB565 on load; transparency comes from the
alpha channel as a per-tile opacity mask, so any color (black included) can
be opaque. The TGA loader and the palette-order fragility are gone.

overworld.png is the unmodified Mini-Medieval Overworld sheet (same 24-column
layout as the old TGA, so map tile ids are unchanged); entities.png holds the
player sprite extracted from the old entities.tga.

Adds an ignored snapshot test that renders the first frame headlessly to a
PNG for eyeballing the renderer without a window.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
irrlicht
2026-09-18 23:17:41 +02:00
co-authored by Claude Opus 5
parent 64a6e1d42d
commit 5a055c048d
14 changed files with 212 additions and 96 deletions
+8 -5
View File
@@ -5,7 +5,8 @@ Local single-player roguelike with a continuously simulated, tick-based world.
Workspace layout: `sim/` (headless world simulation — tiles, entities, movement rules,
tick loop; no platform dependencies, unit-testable) and `game/` (the executable — window,
rendering, input, pathfinding, camera; owns a `Sim` and drives it). The platform layer —
window, GPU, input, RGB332 palette — lives in the external `pbio` crate (git dependency),
window, GPU, input, RGB565 framebuffer — lives in the external `pbio` crate (git dependency,
branch `truecolor16`),
not in this repo.
History: this fork started from a client/server multiplayer architecture (authoritative UDP
@@ -17,9 +18,11 @@ crate's `tick`/`set_action` interface is the seam a server could be wrapped arou
## Achieved milestones
- [x] TGA loader: `Image`, `from_tga`, `to_tileset`, `decode_rle` in `game/src/assets.rs`
- [x] PNG loader: `Image::from_png` (via the `png` crate, quantized to RGB565 on load, alpha
mask), `to_tileset` → `Vec<Tile>` in `game/src/assets.rs`. Framebuffer is 16-bit
truecolor (`pbio` branch `truecolor16`)
- [x] Pixel helpers: `set_pixel`, `extract`, `blit`, `blit_tile` in `game/src/game/pixelhelper.rs`
— signed `i32` offsets, clip against all four framebuffer edges, index 0 = transparent
— signed `i32` offsets, clip against all four framebuffer edges, per-tile opacity mask
- [x] Input system: `GameAction`, `InputMap`, `InputState` in `game/src/input.rs` (over `pbio::Key`)
- [x] World model: `World` of 32×32 palette-compressed `Chunk`s (64-entry `TileDef` palette,
6-bit tile indices), entities indexed per chunk, `entities_in_viewport`
@@ -27,7 +30,7 @@ crate's `tick`/`set_action` interface is the seam a server could be wrapped arou
dimensions), `load_world` slices it into chunks, invisible solid border at the map rim.
See `notes/07-map-loader.md`
- [x] Tile rendering: chunk-based world rendering straight from `World` (`render_viewport`)
- [x] Sprite-based entity rendering: entity `type_id` → tile in `entities.tga`, blitted with transparency
- [x] Sprite-based entity rendering: entity `type_id` → tile in `entities.png`, blitted with transparency
- [x] Hybrid tick loop: 24 Hz base tick, movement in `entity_tick` every 4th tick (6 Hz);
the game loop drives the sim with a fixed-timestep accumulator. See `notes/06-hybrid-tick-loop.md`
- [x] Intent model: one scheduled action per entity per movement window (`Sim::set_action`),
@@ -118,7 +121,7 @@ Sprite rendering, camera follow and entity interpolation have all landed.
### Later — UI / HUD
- Bitmap font renderer: 8×8 glyph sheet TGA, `draw_text(frame, font, x, y, color, text)` — see `notes/04`
- Bitmap font renderer: 8×8 glyph sheet PNG, `draw_text(frame, font, x, y, color, text)` — see `notes/04`
- UI primitives in `game/src/ui.rs`: `fill_rect`, `draw_rect`, `draw_hbar` — see `notes/05`
- HUD layout (320×240): HP bar + player name bottom 16px, message log right panel
- A real clip-rect on the blit primitives belongs here — once the viewport and HUD panels are