Skip to content

Add a first-class .xtf texture decoder - #14

Merged
colemancda merged 3 commits into
mainfrom
feature/xtf-decoder
Jul 18, 2026
Merged

colemancda merged 3 commits into
mainfrom
feature/xtf-decoder

Conversation

@colemancda

Copy link
Copy Markdown
Owner

Summary

  • XtfFile joins GunBoundFile as a first-class format: parses the 9-byte header ([width u32 LE][height u32 LE][format u8]) and decodes the 16-bit body as ARGB4444 (format 1) or RGB565 into an ImgFile.Frame, so any dimensions/format flow through the existing texture pipeline. Replaces the previous hard-coded 256×256 hazard-texture path in AssetLibrary, which now delegates to it.
  • Follows the library's API convention: the ParserSpan overload is primary, the array entry point wraps withParserSpan, truncation surfaces as parsing errors, and a dimension bound rejects corrupt headers before any large allocation.
  • GunBoundExtract xtf subcommand decodes a .xtf entry to PNG, mirroring image.
  • Header layout confirmed empirically against every .xtf in graphics.xfs (all 256×256, format 1). The hazard/smoke surfaces decode to real art (TornadoTexture renders the swirl sprite correctly); AvataTexture1 decodes to 0 alpha pixels, corroborating the decomp's finding that those are blank runtime render targets. The .xtf string never appears in the original binary, so the format is documented as empirical rather than decomp-confirmed.

Tests

Six unit tests: exact-pixel ARGB4444/RGB565 decodes, non-square dimensions, span/array agreement, truncation, invalid/absurd dimensions — plus the real TornadoTexture.xtf checked in as a fixture with its decode pinned exactly (256×256, 35,609 alpha pixels) so a pixel-interpretation regression can't slip by.

Test plan

  • swift test — 560 tests passing
  • GunBoundExtract xtf verified against real archive entries
  • CI green on this PR

Promotes the hard-coded 256x256 hazard-texture path to a first-class
XtfFile decoder in GunBoundFile that parses the 9-byte header
([width u32][height u32][format u8]) and decodes the body as ARGB4444
(format 1) or RGB565, so any dimensions/format decode. AssetLibrary's
xtfTexture now delegates to it. Header layout confirmed against every
.xtf in graphics.xfs.
Decodes a .xtf texture surface to PNG via XtfFile, mirroring the
'image' command — verified against the real TornadoTexture/A_smoke
(real content) and AvataTexture (blank runtime target).
Rewrites the decoder to the library convention — the ParserSpan
overload is primary and the array entry point wraps withParserSpan,
with truncation surfacing as parsing errors and a dimension bound
guarding corrupt headers against huge allocations. Adds the real
TornadoTexture.xtf from graphics.xfs as a fixture, pinning its exact
256x256 ARGB4444 decode (35609 alpha pixels) so a pixel-interpretation
regression can't slip by.
@colemancda
colemancda merged commit 8195650 into main Jul 18, 2026
5 checks passed
@colemancda
colemancda deleted the feature/xtf-decoder branch July 18, 2026 06:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant