formats/cli: the bundle's other orderings, and a guard that neither is a paint order
The title screen needs an order that puts element 13 (`ptbase2.t32`, the full-screen background) behind elements 0-5 (the wordmarks) — the capture shows the wordmarks on top, so the declaration table is not it. Two other orderings the bundle carries were the cheap candidates, and both are now dead: * the **placement region** stores a keyframe group per element with an explicit element index, so it could be a second ordering. It is not — it equals the declaration order on every build on the disc. `UiBuild::placement_order` exposes it and `placement_region_order_is_never_a_second_ordering` pins it, so the refutation stays checkable instead of remembered. * the **RATC child order** is the declaration order with the `.prm` elements absent — strictly less information, and no place to put the background other than where the table already puts it. `screen info --geometry` prints both, plus each element's decoded sprite size beside `pivot*2` and every keyframe's scale/position/time — the numbers a placement hypothesis has to be tested against, and how the pivot/scale rule in the previous commit was found. `title_background_is_full_screen` pins that rule against the disc rather than a synthetic sprite. `scaled_elements_are_a_small_and_mostly_undiscriminating_minority` reports the scope honestly: 865 of 5 130 resting placements are scaled at all, and only 213 of those could tell "about the pivot" from "about the sprite centre" — which the capture did *not* settle, because `ptbase2`'s pivot is its centre. It also counts how far `pivot*2` is from the decoded size disc-wide (2 521 agree, 1 884 are off by more than 16 px), which demotes the "pivot is exactly half the texture" result to a property of the tutorial bundle.
This commit is contained in:
@@ -137,6 +137,12 @@ enum ScreenCommands {
|
||||
/// Which build (index into `screen list`); default = the largest
|
||||
#[arg(long)]
|
||||
build: Option<usize>,
|
||||
/// Also print the bundle's other orderings and, per element, the decoded
|
||||
/// sprite size beside the declared pivot and every keyframe's
|
||||
/// scale/position/time — what a placement or paint-order hypothesis has
|
||||
/// to be tested against.
|
||||
#[arg(long)]
|
||||
geometry: bool,
|
||||
},
|
||||
/// Composite one build to a PNG — the headless self-verify for the viewer
|
||||
Render {
|
||||
@@ -301,7 +307,11 @@ async fn main() -> Result<()> {
|
||||
},
|
||||
Commands::Screen { cmd } => match cmd {
|
||||
ScreenCommands::List { pak } => cmd_screen_list(&pak),
|
||||
ScreenCommands::Info { pak, build } => cmd_screen_info(&pak, build),
|
||||
ScreenCommands::Info {
|
||||
pak,
|
||||
build,
|
||||
geometry,
|
||||
} => cmd_screen_info(&pak, build, geometry),
|
||||
ScreenCommands::Render {
|
||||
pak,
|
||||
output,
|
||||
@@ -379,7 +389,7 @@ fn cmd_screen_list(pak: &Path) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn cmd_screen_info(pak: &Path, want: Option<usize>) -> Result<()> {
|
||||
fn cmd_screen_info(pak: &Path, want: Option<usize>, geometry: bool) -> Result<()> {
|
||||
use sylpheed_formats::ui_layout;
|
||||
let builds = screen_builds(pak)?;
|
||||
let idx = pick_build(&builds, want)?;
|
||||
@@ -436,9 +446,82 @@ fn cmd_screen_info(pak: &Path, want: Option<usize>) -> Result<()> {
|
||||
println!("{:<3} {:<30} → focus {link}", "", "");
|
||||
}
|
||||
}
|
||||
if geometry {
|
||||
print_geometry(&b, bytes);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// The two other orderings the bundle carries, and each element's real drawn
|
||||
/// size. Both were needed to settle the title screen's paint order — see
|
||||
/// `docs/re/BACKLOG.md`.
|
||||
fn print_geometry(b: &sylpheed_formats::ui_layout::UiBuild, bytes: &[u8]) {
|
||||
println!();
|
||||
let identity: Vec<usize> = (0..b.placement_order.len()).collect();
|
||||
println!(
|
||||
"placement-region group order: {:?}{}",
|
||||
b.placement_order,
|
||||
if b.placement_order == identity {
|
||||
" (== declaration order)"
|
||||
} else {
|
||||
" (DIFFERS from declaration order)"
|
||||
}
|
||||
);
|
||||
if let Some(kids) = sylpheed_formats::ratc::parse(bytes) {
|
||||
println!(
|
||||
"RATC child order: {:?}",
|
||||
kids.iter()
|
||||
.map(|c| format!("{}:{}", c.kind, c.name))
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
println!();
|
||||
println!("geometry — decoded sprite size vs the declared pivot, and every keyframe");
|
||||
println!(
|
||||
"{:<3} {:<26} {:>11} {:>11} {:>5} keyframes t: x,y sx%,sy% a=fade-alpha",
|
||||
"#", "sprite", "decoded", "pivot*2", "same"
|
||||
);
|
||||
for el in &b.elements {
|
||||
let dims = el
|
||||
.sprite
|
||||
.as_ref()
|
||||
.and_then(|s| b.sprites.get(s))
|
||||
.and_then(|&(off, size)| sylpheed_formats::t8ad::parse(&bytes[off..off + size]))
|
||||
.map(|img| (img.width, img.height));
|
||||
let pv = (el.pivot_x * 2, el.pivot_y * 2);
|
||||
let same = match dims {
|
||||
Some(d) if d == pv => "yes",
|
||||
Some(_) => "NO",
|
||||
None => "-",
|
||||
};
|
||||
let kfs = el
|
||||
.keyframes
|
||||
.iter()
|
||||
.map(|f| {
|
||||
format!(
|
||||
"{}: {},{} {}%,{}% a={}",
|
||||
f.time.map(|v| v.to_string()).unwrap_or_else(|| "-".into()),
|
||||
f.x,
|
||||
f.y,
|
||||
f.scale_x,
|
||||
f.scale_y,
|
||||
(f.fade >> 24) & 0xff
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ");
|
||||
println!(
|
||||
"{:<3} {:<26} {:>11} {:>11} {:>5} {kfs}",
|
||||
el.index,
|
||||
el.sprite.as_deref().unwrap_or("—"),
|
||||
dims.map(|(w, h)| format!("{w}x{h}"))
|
||||
.unwrap_or_else(|| "—".into()),
|
||||
format!("{}x{}", pv.0, pv.1),
|
||||
same,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn cmd_screen_render(
|
||||
pak: &Path,
|
||||
output: &Path,
|
||||
|
||||
Reference in New Issue
Block a user