dm2-graphics: champion portraits decode with wrong codec on FM-Towns and skip overlay composition on console ports #188

Closed
opened 2026-07-05 07:48:00 +02:00 by jqueuniet · 1 comment
jqueuniet commented 2026-07-05 07:48:00 +02:00 (Migrated from codeberg.org)

Problem

Champion::parse decodes portraits via decode_portrait (crates/dm2-graphics/src/champion.rs ~223), which calls Image::parse directly on the record payload. That bypasses both dispatch layers the archive-level image path has:

  1. Format-4 codec dispatch. On the FM-Towns archive, Image::parse runs the format-5 4-bit RLE instead of Image::parse_fm_towns's C4towns codec. FM-Towns has 32 champion portraits + 16 stats records; the format-5 RLE decodes C4towns streams to garbage without erroring (its EOF handling is lenient), so archive.champion(h) on FM-Towns returns silently wrong portrait pixels.
  2. Overlay composition. On Mac JP / Amiga / Sega CD, 14-15 of the 32 champion portraits are listed as overlays in the (0, 0, 0x08, 0) chain table. Decoding an overlay record with the underlay decoder misparses from the very first nibble (underlays read a 6-nibble sub-palette, overlays 5), so those portraits come out fully garbled — and idx == 5 runs that should show the underlay through render as palette literals.

champion_fixture.rs only exercises DOS-EN and Mac US, which have neither overlays nor format-4, so the tests can't see it.

Fix direction

Route portrait decoding through the archive: resolve the record's payload index and call Archive::compose_image_at_dbidx (which already handles both the format-4 dispatch via decode_image_payload and the overlay chain). decode_portrait keeps its error mapping; only the decode call changes.

## Problem `Champion::parse` decodes portraits via `decode_portrait` (`crates/dm2-graphics/src/champion.rs` ~223), which calls `Image::parse` directly on the record payload. That bypasses both dispatch layers the archive-level image path has: 1. **Format-4 codec dispatch.** On the FM-Towns archive, `Image::parse` runs the format-5 4-bit RLE instead of `Image::parse_fm_towns`'s C4towns codec. FM-Towns has 32 champion portraits + 16 stats records; the format-5 RLE decodes C4towns streams to garbage without erroring (its EOF handling is lenient), so `archive.champion(h)` on FM-Towns returns silently wrong portrait pixels. 2. **Overlay composition.** On Mac JP / Amiga / Sega CD, 14-15 of the 32 champion portraits are listed as overlays in the `(0, 0, 0x08, 0)` chain table. Decoding an overlay record with the underlay decoder misparses from the very first nibble (underlays read a 6-nibble sub-palette, overlays 5), so those portraits come out fully garbled — and `idx == 5` runs that should show the underlay through render as palette literals. `champion_fixture.rs` only exercises DOS-EN and Mac US, which have neither overlays nor format-4, so the tests can't see it. ## Fix direction Route portrait decoding through the archive: resolve the record's payload index and call `Archive::compose_image_at_dbidx` (which already handles both the format-4 dispatch via `decode_image_payload` and the overlay chain). `decode_portrait` keeps its error mapping; only the decode call changes.
jqueuniet commented 2026-07-06 06:22:43 +02:00 (Migrated from codeberg.org)

Fixed by #208 (merged into main).

Fixed by #208 (merged into `main`).
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
jqueuniet/dm2-tools#188
No description provided.