Files
forgotten_caves/notes/02-asset_loader.md
T
irrlichtandClaude Opus 5 5a055c048d 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>
2026-09-18 23:17:41 +02:00

2.1 KiB
Executable File
Raw Blame History

Asset Loader

Current state

PNG loading is implemented in game/src/assets.rs. Image::from_png(path) decodes via the png crate (any color type, expanded to 8-bit RGBA) and quantizes on load to the framebuffer's RGB565 format with pbio::rgb565; alpha ≥ 128 counts as opaque. The result is an Image { width, height, pixels: Vec<u16>, opaque: Vec<bool> }. Artists work in truecolor; there is no palette an asset could be "in the wrong order" for. game.rs uses it directly: Image::from_png("assets/tilesets/overworld.png").

Image also provides to_tileset() -> Vec<Tile>, which splits the image into 8×8 tiles row-major. A Tile is 64 RGB565 pixels plus a u64 opacity bitmask. Every tile is emitted; tile ID is the flat row-major index into the Vec, so tiles are never skipped or reordered. overworld.png is the unmodified Mini-Medieval Overworld.png sheet (24 columns), so Tiled tile ids line up with the Vec index.

History: the first iteration used 8-bit indexed TGAs on a palette framebuffer (RGB332, pbio master branch). The colormap-ordering fragility and the index-0-is-transparent convention are gone with the switch to pbio's truecolor16 branch.

AssetStore (a named registry) is not yet implemented. Assets are currently loaded inline in Game::start().

Goal

Add an AssetStore so that game code can ask for an asset by name rather than loading files directly at the call site.

Design notes

  • Image struct: width: u32, height: u32, pixels: Vec<u16>, opaque: Vec<bool> — done.
  • A simple AssetStore could be a HashMap<&'static str, Image> loaded at startup.
  • No streaming needed — the whole game is small enough to load everything upfront in start().
  • Transparency is the tile's mask bit, checked by blit_tile() in pixelhelper.rs. Any color — black included — can be an opaque pixel.
  • Pixel assets are stored as flat Vec<u16> of RGB565 values, row-major, width × height.
  • Future: consider embedding assets with include_bytes! to produce a single binary.

Open questions

  • Should AssetStore hold pre-split tilesets too, or just raw Image values?