dm2-graphics: decode the console-only cls = (1, 0, 7, 0x0a) 1652-byte entry #266

Closed
opened 2026-07-17 18:51:34 +02:00 by jqueuniet · 1 comment
jqueuniet commented 2026-07-17 18:51:34 +02:00 (Migrated from codeberg.org)

Context

A single 1652-byte record at cls = (1, 0, 7, 0x0a) appears only on Sega-CD US/JP and Mac-JP; absent from every other port. Its format is unknown and it is the only remaining undecoded entry type in graphics.dat (ROADMAP.md:300–301). It currently falls through iter_unknown.

Scope

  • Reverse the record's structure (likely console-specific, given the port distribution — compare Sega-CD US/JP vs Mac-JP bytes for endianness/identity).
  • Add a typed decoder or, if it proves to be a static table, pin it with a fixture test like slots 1/2/0xc8.
  • Document findings in docs/formats/graphics-dat.md.

Acceptance

  • Structure documented; entry no longer classified as Unknown, or an explicit note that it stays raw with a byte-pinned fixture.
## Context A single 1652-byte record at `cls = (1, 0, 7, 0x0a)` appears only on Sega-CD US/JP and Mac-JP; absent from every other port. Its format is unknown and it is the only remaining *undecoded entry type* in `graphics.dat` (ROADMAP.md:300–301). It currently falls through `iter_unknown`. ## Scope - Reverse the record's structure (likely console-specific, given the port distribution — compare Sega-CD US/JP vs Mac-JP bytes for endianness/identity). - Add a typed decoder or, if it proves to be a static table, pin it with a fixture test like slots 1/2/0xc8. - Document findings in `docs/formats/graphics-dat.md`. ## Acceptance - Structure documented; entry no longer classified as `Unknown`, or an explicit note that it stays raw with a byte-pinned fixture.
jqueuniet commented 2026-07-17 20:00:10 +02:00 (Migrated from codeberg.org)

Identified. cls = (1, 0, 7, 0x0A) is the global creature animation frame tabletblCreatureFrameInfo14 (né _4976_5a98) in skproject's V4 engine.

Evidence

The legacy SKWIN port declares the table with the cls tuple in a comment and loads it from this exact GDAT entry at startup:

  • SKWIN/SkWinCore.h:685U8 (*_4976_5a98)[14]; // 01-00-07-0A-00-00
  • SKWIN/SkWinCore.cpp:54795-54796 — allocates QUERY_GDAT_ENTRY_DATA_LENGTH(GDAT_CATEGORY_INTERFACE_GENERAL, 0, dt07, 0xa) bytes, then LOAD_GDAT_ENTRY_DATA_TO(…, 0xa, _4976_5a98)

Consumers: SKWINSPX/src/v4/skbltgfx.cpp:798-883 (QUERY_CREATURE_PICST) and v4/skcrture.cpp:2040, indexed by animation frame ID from CREATURE_SEQUENCE_4937_000f (a static object resolves to frame 4). The inline comment at skbltgfx.cpp:798 spells out the record shape: "table has 2+4+4+4 bytes: 4 * images ID in GDAT, 4 * scales, then 4 * mirror flags".

Layout

1652 bytes = 118 records × 14 bytes. Direction indices 0 = back, 1 = left, 2 = front, 3 = right (per the CreatureAnimationFrameInfoFD_V5 comment in v0/dme.h; matches the iFaceDirImg = 2 "front" convention).

Offset Width Meaning Shipped data
0 u8 horizontal blit-position code, 0x0C = centered (skbltgfx.cpp:861) {2, 7, 8, 0xC, 0x11}
1 i8 vertical offset (skbltgfx.cpp:883) 0 in all 118 records
2..6 4×u8 per-direction image ID (cls4 under (0x0F, creatureType, dtImage, ·)) typical [n, n+3, n+2, n+3] — sides share one image
6..10 4×u8 per-direction scale, 0x40 = 100 % (CALC_STRETCHED_SIZE) {0x34, 0x3A, 0x40, 0x47, 0x4E}
10..14 4×u8 per-direction mirror flags, bit 0 = h-flip (skbltgfx.cpp:825) {0, 1, 2}; bit 1's consumer unidentified

Centered records never scale; off-center records shrink one side view and enlarge the other (between-cell advance frames).

Correction: not console-only

Extracting all 16 fixture archives shows the record is a V4-lineage (Japanese engine family) marker, not console-only. Present and byte-identical (md5 0e3991914999b2efd0b6f6586f7e3337) on pc9801-jp (retail + demo), pc9821-jp, fm-towns-jp, ibm-psv-jp, mac-jp, sega-cd-us, and sega-cd-jp; absent from all eight Western archives (dos-en/de/fr, dos-demo, dos-en-beta, amiga-eu, mac-us, mac-demo). The V5 engine never queries the slot — it keeps the same information in per-creature (0x0F, creature, dtRaw7, 0xFC/0xFD/0xFE) records (present on dos-en, absent on the JP-lineage ports), which explains the split exactly. The original "Sega-CD US/JP and Mac-JP only" claim came from the five-port slot survey, which didn't cover the four Japanese PC ports.

Resolution

Branch feat/creature-frame-info:

  • dm2_graphics::CreatureFrameTable / CreatureFrame typed decoder, exposed as Archive::creature_frame_table()
  • tests/creature_frame_fixture.rs pins the 8-port byte identity, the 8-port absence, and the per-field invariants above
  • graphics-dat.md gains § "Slot 0x0a — creature animation frame table" (replacing the out-of-scope note); ROADMAP entry checked off

The entry still flows through iter_unknown (cls3-keyed, like the font slots); the typed accessor is the dedicated path.

Identified. `cls = (1, 0, 7, 0x0A)` is the **global creature animation frame table** — `tblCreatureFrameInfo14` (né `_4976_5a98`) in skproject's V4 engine. ## Evidence The legacy SKWIN port declares the table with the cls tuple in a comment and loads it from this exact GDAT entry at startup: - `SKWIN/SkWinCore.h:685` — `U8 (*_4976_5a98)[14]; // 01-00-07-0A-00-00` - `SKWIN/SkWinCore.cpp:54795-54796` — allocates `QUERY_GDAT_ENTRY_DATA_LENGTH(GDAT_CATEGORY_INTERFACE_GENERAL, 0, dt07, 0xa)` bytes, then `LOAD_GDAT_ENTRY_DATA_TO(…, 0xa, _4976_5a98)` Consumers: `SKWINSPX/src/v4/skbltgfx.cpp:798-883` (`QUERY_CREATURE_PICST`) and `v4/skcrture.cpp:2040`, indexed by animation frame ID from `CREATURE_SEQUENCE_4937_000f` (a static object resolves to frame 4). The inline comment at `skbltgfx.cpp:798` spells out the record shape: "table has 2+4+4+4 bytes: 4 * images ID in GDAT, 4 * scales, then 4 * mirror flags". ## Layout 1652 bytes = 118 records × 14 bytes. Direction indices 0 = back, 1 = left, 2 = front, 3 = right (per the `CreatureAnimationFrameInfoFD_V5` comment in `v0/dme.h`; matches the `iFaceDirImg = 2` "front" convention). | Offset | Width | Meaning | Shipped data | |---|---|---|---| | 0 | u8 | horizontal blit-position code, `0x0C` = centered (`skbltgfx.cpp:861`) | {2, 7, 8, 0xC, 0x11} | | 1 | i8 | vertical offset (`skbltgfx.cpp:883`) | 0 in all 118 records | | 2..6 | 4×u8 | per-direction image ID (`cls4` under `(0x0F, creatureType, dtImage, ·)`) | typical `[n, n+3, n+2, n+3]` — sides share one image | | 6..10 | 4×u8 | per-direction scale, `0x40` = 100 % (`CALC_STRETCHED_SIZE`) | {0x34, 0x3A, 0x40, 0x47, 0x4E} | | 10..14 | 4×u8 | per-direction mirror flags, bit 0 = h-flip (`skbltgfx.cpp:825`) | {0, 1, 2}; bit 1's consumer unidentified | Centered records never scale; off-center records shrink one side view and enlarge the other (between-cell advance frames). ## Correction: not console-only Extracting all 16 fixture archives shows the record is a **V4-lineage (Japanese engine family) marker**, not console-only. Present and byte-identical (md5 `0e3991914999b2efd0b6f6586f7e3337`) on pc9801-jp (retail + demo), pc9821-jp, fm-towns-jp, ibm-psv-jp, mac-jp, sega-cd-us, and sega-cd-jp; absent from all eight Western archives (dos-en/de/fr, dos-demo, dos-en-beta, amiga-eu, mac-us, mac-demo). The V5 engine never queries the slot — it keeps the same information in per-creature `(0x0F, creature, dtRaw7, 0xFC/0xFD/0xFE)` records (present on dos-en, absent on the JP-lineage ports), which explains the split exactly. The original "Sega-CD US/JP and Mac-JP only" claim came from the five-port slot survey, which didn't cover the four Japanese PC ports. ## Resolution Branch `feat/creature-frame-info`: - `dm2_graphics::CreatureFrameTable` / `CreatureFrame` typed decoder, exposed as `Archive::creature_frame_table()` - `tests/creature_frame_fixture.rs` pins the 8-port byte identity, the 8-port absence, and the per-field invariants above - `graphics-dat.md` gains § "Slot 0x0a — creature animation frame table" (replacing the out-of-scope note); ROADMAP entry checked off The entry still flows through `iter_unknown` (cls3-keyed, like the font slots); the typed accessor is the dedicated path.
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#266
No description provided.