re: verify the sweep leaves' full extent -- port's table confirmed, plus a new fact
Attempted to refute sylpheed-port's leaf table by measuring it against the disc. It SURVIVES to the digit: ptloop01 -> pteff03, cycle span 600, x track -639..1521, scale (100, 600); ptloop02 -> pteff03a, span 720, x -839..1721, scale (100, 800). The existing ptloop_leaf_sweep_at.rs samples only t=340..540 -- a window chosen to compare two competing fits -- so it could never have shown the extent. That gap is what let my "ptloop01/02 do not free-run" claim stand: measured over the parent's 200x90 pivot rect, which a leaf travelling -639..1521 is almost never inside. ptloop_leaf_extent.rs sweeps the whole cycle instead. New fact neither of us had: the leaves are IDENTICAL on entries 4, 5 AND 7 -- the title, the main menu and the JP title. Same leaf names, spans, x tracks, scales and parent rest position. So the menu declares exactly the same sweep as the title, and the still-open menu question is about the game's behaviour rather than a different declaration. The quad is 400 px wide at scale_x 100 % -- not widened -- and scale_y 600/800 % makes it 1080/1440 px tall, taller than the screen. A full-height strip crossing the frame and going off both sides, which is why a phase-to-phase diff covers the union of two positions and looks frame-wide. And my own "centre running x~921->1041" was a 30-unit window of a 600-unit cycle whose centre spans -439..1721. A sub-range is not an extent -- the same caution as a pivot not being a bounding box, one level up, and I made both errors within a day. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
This commit is contained in:
51
crates/sylpheed-formats/examples/ptloop_leaf_extent.rs
Normal file
51
crates/sylpheed-formats/examples/ptloop_leaf_extent.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
//! The FULL extent of the two title sweep leaves, across their whole cycle.
|
||||
//!
|
||||
//! `ptloop_leaf_sweep_at.rs` samples t=340..540 — a window chosen to compare two
|
||||
//! competing fits — so it never showed how far the leaves travel. That gap let a
|
||||
//! claim stand that `ptloop01/02` "do not free-run", measured over the PARENT's
|
||||
//! 200x90 rect, which is a pivot anchor the leaf spends almost no time inside.
|
||||
//! `sylpheed-port` reports x tracks of -639..1521 and -839..1721 from their
|
||||
//! export; this checks that against the disc.
|
||||
//!
|
||||
//! cargo run -p sylpheed-formats --example ptloop_leaf_extent
|
||||
use sylpheed_formats::{pak::PakArchive, ui_layout};
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
let root = PathBuf::from(std::env::var("SYLPHEED_DISC").expect("SYLPHEED_DISC"));
|
||||
let ar = PakArchive::open(root.join("dat/GP_TITLE.pak")).expect("GP_TITLE.pak");
|
||||
for entry in [4usize, 5, 7] {
|
||||
let Ok(by) = ar.read(&ar.entries()[entry]) else { continue };
|
||||
let Some(b) = ui_layout::parse_build(&by) else { continue };
|
||||
println!("\n######## GP_TITLE entry {entry} ########");
|
||||
for parent in ["ptloop01", "ptloop02"] {
|
||||
let Some(el) = b.elements.iter().find(|e| e.name.starts_with(parent)) else {
|
||||
println!(" {parent}: not present in this build"); continue };
|
||||
let Some(&(off, size)) = b.records.get(&el.name) else {
|
||||
println!(" {}: no nested record", el.name); continue };
|
||||
let span = u32::from_be_bytes(by[off + 8..off + 12].try_into().unwrap());
|
||||
let Some(lb) = ui_layout::parse_build(&by[off..off + size]) else {
|
||||
println!(" {}: leaf will not parse", el.name); continue };
|
||||
println!(" {} parent rest ({},{}) nested cycle span {span}",
|
||||
el.name, el.keyframes.last().map(|k| k.x).unwrap_or(0),
|
||||
el.keyframes.last().map(|k| k.y).unwrap_or(0));
|
||||
for le in &lb.elements {
|
||||
let (mut lo, mut hi) = (i64::MAX, i64::MIN);
|
||||
let (mut sxs, mut sys) = (Vec::new(), Vec::new());
|
||||
for t in 0..=span {
|
||||
if let Some(k) = le.pose_at(t) {
|
||||
lo = lo.min(k.x as i64); hi = hi.max(k.x as i64);
|
||||
if !sxs.contains(&k.scale_x) { sxs.push(k.scale_x) }
|
||||
if !sys.contains(&k.scale_y) { sys.push(k.scale_y) }
|
||||
}
|
||||
}
|
||||
let w = (le.pivot_x * 2) as i64;
|
||||
println!(" leaf {:<12} pivot {}x{} quad w={w} x track {lo} .. {hi} \
|
||||
(centre {} .. {}) scale_x {:?} scale_y {:?}",
|
||||
le.name, le.pivot_x, le.pivot_y,
|
||||
lo + le.pivot_x as i64, hi + le.pivot_x as i64, sxs, sys);
|
||||
}
|
||||
}
|
||||
}
|
||||
println!("--- END ---");
|
||||
}
|
||||
47
docs/re/data/ptloop-leaf-extent.txt
Normal file
47
docs/re/data/ptloop-leaf-extent.txt
Normal file
@@ -0,0 +1,47 @@
|
||||
# The two title sweep leaves, across their WHOLE cycle. 2026-08-30.
|
||||
# instrument: examples/ptloop_leaf_extent.rs
|
||||
#
|
||||
# Why this exists: ptloop_leaf_sweep_at.rs samples t=340..540, a window chosen to
|
||||
# compare two competing fits, so it never showed how far the leaves travel. That
|
||||
# gap let a claim stand that ptloop01/02 "do not free-run", measured over the
|
||||
# PARENT's 200x90 rect -- a pivot anchor the leaf is almost never inside.
|
||||
#
|
||||
# sylpheed-port reported x tracks of -639..1521 and -839..1721 from their export.
|
||||
# Checked against the disc, independently:
|
||||
|
||||
######## GP_TITLE entry 4 ########
|
||||
ptloop01.rat parent rest (441,270) nested cycle span 600
|
||||
leaf pteff03.t32 pivot 200x90 quad w=400 x track -639 .. 1521 (centre -439 .. 1721) scale_x [100] scale_y [600]
|
||||
ptloop02.rat parent rest (441,270) nested cycle span 720
|
||||
leaf pteff03a.t32 pivot 200x90 quad w=400 x track -839 .. 1721 (centre -639 .. 1921) scale_x [100] scale_y [800]
|
||||
|
||||
######## GP_TITLE entry 5 ########
|
||||
ptloop01.rat parent rest (441,270) nested cycle span 600
|
||||
leaf pteff03.t32 pivot 200x90 quad w=400 x track -639 .. 1521 (centre -439 .. 1721) scale_x [100] scale_y [600]
|
||||
ptloop02.rat parent rest (441,270) nested cycle span 720
|
||||
leaf pteff03a.t32 pivot 200x90 quad w=400 x track -839 .. 1721 (centre -639 .. 1921) scale_x [100] scale_y [800]
|
||||
|
||||
######## GP_TITLE entry 7 ########
|
||||
ptloop01.rat parent rest (441,270) nested cycle span 600
|
||||
leaf pteff03.t32 pivot 200x90 quad w=400 x track -639 .. 1521 (centre -439 .. 1721) scale_x [100] scale_y [600]
|
||||
ptloop02.rat parent rest (441,270) nested cycle span 720
|
||||
leaf pteff03a.t32 pivot 200x90 quad w=400 x track -839 .. 1721 (centre -639 .. 1921) scale_x [100] scale_y [800]
|
||||
--- END ---
|
||||
|
||||
# CONFIRMED to the digit: ptloop01 -> pteff03, span 600, x -639..1521,
|
||||
# scale (100, 600); ptloop02 -> pteff03a, span 720, x -839..1721, scale (100,800).
|
||||
#
|
||||
# 📌 AND A FACT NEITHER OF US HAD: the leaves are IDENTICAL on entries 4, 5 and 7
|
||||
# -- the title, the MAIN MENU and the JP title. Same leaf names, same spans, same
|
||||
# x tracks, same scales, same parent rest position. So the menu carries exactly
|
||||
# the same sweep as the title, at the declaration level.
|
||||
#
|
||||
# The quad is 400 px wide at scale_x 100 % -- not widened -- and scale_y 600/800 %
|
||||
# makes it 1080 / 1440 px tall, taller than the 720-px screen. A full-height strip
|
||||
# whose left edge travels -639..1521, i.e. right across the frame and off both
|
||||
# sides. Two phases of that are hundreds of pixels apart, which is why a
|
||||
# phase-to-phase diff covers the union of both positions and looks frame-wide.
|
||||
#
|
||||
# ⚠️ My own earlier figure, "centre running x~921->1041", is a 30-UNIT WINDOW of a
|
||||
# 600-unit cycle whose centre spans -439..1721. A sub-range is not an extent --
|
||||
# the same caution as a pivot not being a bounding box, one level up.
|
||||
@@ -154,6 +154,30 @@ parent is static while the **leaf record animates**, and the two nested records
|
||||
cycle at *different* lengths, **600 and 720**. My "single static keyframe" was a
|
||||
statement about the parent only.
|
||||
|
||||
✅ **Their full table also survives an independent check against the disc**
|
||||
([`data/ptloop-leaf-extent.txt`](../data/ptloop-leaf-extent.txt)), to the digit:
|
||||
|
||||
| | `ptloop01` | `ptloop02` |
|
||||
|---|---|---|
|
||||
| leaf | `pteff03` | `pteff03a` |
|
||||
| cycle span | 600 | 720 |
|
||||
| x track (left edge) | **−639 … 1521** | **−839 … 1721** |
|
||||
| scale | (100 %, **600 %**) | (100 %, **800 %**) |
|
||||
|
||||
The quad is 400 px wide and **not** widened; `scale_y` makes it 1080 / 1440 px
|
||||
tall — a full-height strip taller than the screen, whose left edge travels right
|
||||
across the frame and off both sides.
|
||||
|
||||
📌 **And a fact neither of us had: these leaves are IDENTICAL on entries 4, 5 and
|
||||
7** — the title, the **main menu**, and the JP title. Same leaf names, spans, x
|
||||
tracks, scales and parent rest position. So the menu declares exactly the same
|
||||
sweep as the title; the open menu question is about the game's *behaviour*, not
|
||||
about a different declaration.
|
||||
|
||||
⚠️ **My own "centre running x≈921→1041" was a 30-unit window of a 600-unit cycle**
|
||||
whose centre spans −439…1721. A sub-range is not an extent — the same caution as a
|
||||
pivot not being a bounding box, one level up, and I made both errors in one day.
|
||||
|
||||
⚠️ The era adjudication is unaffected: its box is x 389..776, and the overlap with
|
||||
the sweep band (x 721..776) shows no between-session differences — the 645 in-box
|
||||
differing pixels all sit at y 99..128.
|
||||
|
||||
Reference in New Issue
Block a user