Commit Graph

8 Commits

Author SHA1 Message Date
MechaCat02
c3758e3850 port: land the play-tested work, and only that
Takes the port branch up to 77320d5e -- the state the human play-tested on
2026-09-02 -- for SOURCE paths only. Not a branch merge: `auto/port-p6-audio`
is 366 commits and 938 files, and most of that must not land.

WHAT COMES IN (76 files, all human-confirmed working):
  * the logo splash animation. 08ed3dd1 found it: `pose_at` ASSIGNED the settle
    instant instead of clamping to it, so the splash never animated at all --
    and the same bug manufactured a passing harness result, because the harness
    photographed t past the settle. Confirmed by play-test: "cannot notice any
    obvious difference from the actual game."
  * gamepad input -- (A)/(B) bound additively (`ui_accept` ships with NO joypad
    binding), stick latched with hysteresis at the game's own 61% digitise
    threshold. This is what made (A), video-skip and Extras work at all.
  * menu navigation and flow, menu audio, the exporter, the authored
    declarations, and 23 verification tools under tools/port/.

WHAT IS DELIBERATELY LEFT ON THE BRANCH:
  * everything after c0ae460a -- the F5/F6 title-timing investigation, whose own
    tip commit calls itself a "hand-off for one-minute human checks". Unchecked
    by definition; it goes through the new review gate like anything else.
  * the OPTIONS menu work of 2026-09-03. Real, probably good, NOT play-tested.
  * the F1 repeat mechanism, which its own commit calls "deliberately inert".

WHAT MUST NOT LAND, AND WHY THE .gitignore CHANGED:
  545 MB of extracted game content was committed on that branch -- 850 sprite,
  audio and transcoded video files under `export-probe/` and `export-probe2/`,
  plus 246 MB of loose .wav and .tsv at the repo root. This repository's own
  rule, in this file, is "never game content".

  The rule was not missing. It was written, and it was tightened on that very
  branch, with a careful comment explaining why BOTH `export/` and `data/base/`
  had to be listed -- while the exporter was writing to a third name that
  nobody had thought to list. Enumerating names is the thing that failed. So
  the ignore rules now describe the SHAPE: any top-level `export*/`, game media
  by extension, and loose capture output at the root. Verified both ways -- it
  catches all four offenders and ignores nothing currently tracked.

Verified: `cargo check --workspace` clean; all nine GDScript files parse in
project context, with a positive control (an injected syntax error is detected,
3 lines) so the clean result means something. `tools/port/check-all` was NOT
run -- it needs the container, the export tree and a display.
2026-09-04 16:17:14 +02:00
MechaCat02
1b1a4dfcd3 containers: an expired token could never be replaced
Some checks failed
CI / Native — ubuntu-latest (push) Failing after 8m1s
CI / WASM — Web (push) Failing after 7m13s
CI / Formatting (push) Failing after 1m10s
CI / Native — macos-latest (push) Has been cancelled
CI / Native — windows-latest (push) Has been cancelled
Credentials were seeded only when the container's copy was MISSING. So when a
session expired, the file still existed, the copy was skipped, and restarting
changed nothing -- the one recovery path a human has, re-logging in on the host,
could not reach the containers at all.

Now re-seeds whenever the host's copy is newer. Newer-wins rather than
always-copy, because a container refreshes its own token mid-run and that copy
may legitimately be the fresher of the two.

Found when both sessions expired: host credentials at 16:30, containers holding
14:20 and 14:24.
2026-08-29 16:31:53 +02:00
MechaCat02
95de29f290 feat(formats,viewer): movie subtitles, voice decode, and the movie manifest
The movie cutscene subtitle + voice pipeline, driven by the ADVERTISE_MOVIE
manifest (the authoritative movie -> subtitle -> voice index). Also flushes
several sessions of local WIP (async viewer loading, grouped-pool XBG7/hero-ship
decode, drawlog tooling). See docs/HANDOFF-movie-voice-subtitles-2026-07-19.md.

Subtitles (movie_subtitle.rs):
- Full movie->track->text chain; join multi-line captions sharing one timing
  (fixes S13A dropped "Look at it father" line); overlap-safe active_cues();
  Latin-1 accents preserved.

Voice (slb.rs): XACT .slb -> XMA1 RIFF; take the FIRST sub-wave bounded by its
declared data size (fixes S10-S16 alternate-take garble); list_voice_clips.

Manifest (movie_manifest.rs): parse ADVERTISE_MOVIE (0x5B983A08) for the real
movie->voice binding (not always VOICE_<movie>; e.g. hokyu -> VOICE_D_* in etc\).
Resolve the token's sound.pak path via sounds.tbl. DIRECT bindings only — the
demo-id shared-clip fallback for unbound hokyu movies was verified WRONG in-game
and reverted (unbound hokyu stay unvoiced; correct join key is an OPEN problem).

Viewer: manifest-driven voice (movie player toggle + solo button), standalone
"Voice Lines" browser, stacked caption overlay.

Tests: 46 formats-lib + 11 viewer-lib + movie_manifest/movie_subtitle/slb disc
tests; full workspace green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 20:15:41 +02:00
MechaCat02
e17bc0216d feat(viewer): present subtitles, fonts, PNG + text in the PAK browser
Decode and present four more PAK item types in the pack browser's detail
pane. All content is decoded off-thread in build_pak_rows and attached to
each PakRow, then rendered with egui's own texture facilities — the Bevy
texture pipeline and egui's global font system are untouched.

formats crate (Bevy-free, reusable by CLI):
- ixud: parse IXUD localized-string tables as subtitle cue lists (UTF-16BE
  pool, SUBTITLE header + (text, timecode) pairs -> Vec<Cue{start,end,text}>).
- font: OTF/TTF/ttcf metadata (family / faces / glyphs) via ttf-parser.

viewer:
- PakRow gains `content: PakContent` (Subtitle | Font | Png | Text | None);
  classify_content fills it for IXUD / fonts / PNG / xml+text within the
  existing decode budget. Font samples are pre-rasterized off-thread with
  ab_glyph into an image (ImageRgba) — ab_glyph returns Option/Result at every
  step, so a bad font yields no sample instead of panicking (the earlier
  egui set_fonts approach crashed the app on atlas rebuild).
- draw_pak_browser dispatches on content: subtitle cue table, font metadata +
  sample image, PNG image, scrollable text; else the existing IDXD detail.
  Borrow-split PakView instead of cloning the (now heavy) rows each frame;
  one hash-keyed egui texture cache serves both PNG and font-sample images.

Subtitle<->movie auto-matching is deferred: movie filenames don't hash to the
IXUD keys and no cross-reference table was found (the link is an internal
MSG_DEMO id), so the movie player gets no subtitle track yet.

Tests: ixud unit tests; disc tests for the real English subtitle track
(cues + timecodes), eng/deu localization, font metadata, and off-thread
rasterization of the real font.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 15:19:31 +02:00
MechaCat02
91bd2543f4 feat(viewer): WMV cutscene player with scrub, keyboard + audio
Add an in-explorer video player for the dat/movie/*.wmv cutscenes.

Decode via the ffmpeg/ffprobe CLI (no libav linking): video streams from an
`ffmpeg -f rawvideo -pix_fmt rgba` pipe read into fixed w*h*4 frame chunks over
a bounded channel (paused/behind => ffmpeg back-pressures on its pipe); one
reused Image is overwritten in place each tick. Audio is best-effort: the track
is pre-decoded to a temp stereo WAV and played through a rodio Sink (volume /
play / pause / seek-via-skip_duration for free). Native-only under
cfg(not(wasm32)); VideoPreview registers unconditionally so the UI compiles for
wasm. Mirrors the .pak load pipeline (FileSelected -> bg thread ->
IsoLoaderMsg::VideoLoaded -> apply_loaded_video -> advance_video_playback), with
a single free_video teardown wired into every other viewer's reset.

Controls:
- play/pause button, click-on-frame toggle, Space / arrow (+-10s) shortcuts
- seekable timeline with mm:ss labels; volume slider (greyed when no audio)
- live scrubbing: a coalescing one-shot `ffmpeg -ss -frames:v 1` grabber always
  jumps to the knob's latest position, so dragging shows the frame under the
  knob in real time; that grabbed frame also bridges the gap after a commit-seek
  so there's no black flash while the streaming decoder catches up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 14:31:52 +02:00
MechaCat02
840db9c549 fix(texture): correct Xenos de-tile + endian + cubemaps + PNG export
Reworks the XPR2 texture path after RE against the retail disc (viewer
previews were scrambled/failed).

- de-tile: replace the naive Morton-over-32×32 approximation with the
  faithful Xenos Tiled2D bank/pipe/macro-tile address formula (ported
  from xenia texture_address.h). Verified correct: the Acheron backdrop
  decodes to a sharp planet with its spiral storm.
- endian: undo the X360 word byte-swap per the fetch-constant endianness
  field (k8in16/k8in32/k16in32) — without it BCn/ARGB data is noise.
- cubemaps: parse TXCM resources (skybox/backdrops), decoding face 0,
  instead of erroring "No TX2D found".
- A8R8G8B8: correct channel order after the k8in32 swap ([A,R,G,B]→RGBA)
  — the Acheron backdrop is now correctly green, not red.
- XPR files are texture PACKS; add XPR_RES_INDEX to select a resource.
- CLI `texture export` now writes real PNGs (texpresso BCn decode +
  image), replacing the stub. Adds texpresso + image deps.
- tests/texture_disc.rs: integration test running the pipeline over real
  disc .xpr files (28/28 parse). RE debug knobs: XPR_NO_DETILE /
  XPR_NO_ENDIAN / XPR_FORCE_ENDIAN.

KNOWN ISSUE: mipmapped DXT1 textures still decode to noise — mip 0 is
not at base_address in the multi-resource packs (localized to a mip
storage-offset quirk; uncompressed + de-tile + endian are all verified).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 21:37:20 +02:00
MechaCat02
d92c7ddaea feat(viewer): ISO / extracted-dir loading pipeline + native file dialog
WIP: add iso_loader.rs — bridges the async XisoReader / synchronous
GameAssets to Bevy's ECS via background threads + mpsc channels polled
per frame (no main-thread blocking); UI open-iso/open-dir/file-select
events → texture preview. Register IsoLoaderPlugin; wire asset_loader
and the egui UI. Deps: rfd (native file dialog, workspace + viewer),
futures, and bevy tonemapping_luts feature.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 07:18:45 +02:00
MechaCat02
f8127e73b0 feat: initialise workspace — Milestone 1 asset explorer
Three-crate Cargo workspace structured per PROJECT.md spec:
- crates/sylpheed-formats  — Xbox 360 format parsers (no Bevy)
- crates/sylpheed-viewer   — Bevy 0.15 asset viewer + egui UI
- crates/sylpheed-cli      — CLI tools (extract/list/sniff/texture)

Milestone 1 features:
- XISO disc image reading via xdvdfs 0.8
- XPR2 texture container parsing + Morton de-tiling
- D3DFORMAT → wgpu TextureFormat mapping (DXT1/3/5, DXN, ARGB)
- Custom Bevy AssetLoader for .xpr files
- Orbit camera (LMB orbit, RMB pan, scroll zoom)
- egui file browser + RE notes panel
- CLI: extract / list / sniff / texture info / texture export
- GitHub Actions CI (Linux, macOS, Windows, WASM)
- Trunk WASM build config

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 21:04:07 +01:00