diff --git a/crates/sylpheed-formats/examples/frame_alpha_census.rs b/crates/sylpheed-formats/examples/frame_alpha_census.rs index 5a2bda9d..3a80f974 100644 --- a/crates/sylpheed-formats/examples/frame_alpha_census.rs +++ b/crates/sylpheed-formats/examples/frame_alpha_census.rs @@ -39,7 +39,11 @@ fn census(name: &str, img: &t8ad::T8adImage) { 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"); - for build in [5usize, 6] { + // Builds default to the two the port ships and can be overridden, so the + // same census serves the title (4) and the `PRESS (A)` plate (2). + let args: Vec = std::env::args().skip(1).filter_map(|a| a.parse().ok()).collect(); + let builds: Vec = if args.is_empty() { vec![5, 6] } else { args }; + for build in builds { let by = ar.read(&ar.entries()[build]).expect("entry"); let b = ui_layout::parse_build(&by).expect("build"); println!("=== GP_TITLE build {build} ==="); diff --git a/tools/re-capture/menu_blend_capture.sh b/tools/re-capture/menu_blend_capture.sh index e950b5b9..9caaf984 100755 --- a/tools/re-capture/menu_blend_capture.sh +++ b/tools/re-capture/menu_blend_capture.sh @@ -51,7 +51,7 @@ echo "WINDOW=$win" # gets there on its own; a run that tapped every 4 s delivered 88 presses and # ended on a black screen. s="" -deadline=$(( SECONDS + 420 )) +deadline=$(( SECONDS + ${DEADLINE:-1200} )) while [ $SECONDS -lt $deadline ]; do s="$(screen)"; echo "t=${SECONDS}s $s" [ "$s" = "title" ] && break @@ -70,10 +70,28 @@ shot "$OUT/menu.png" echo "MENU at ${SECONDS}s" if [ "${SCREEN:-menu}" = "extras" ]; then - # EXTRAS is the second item; the menu opens on NEW GAME. - python3 "$SD/pad.py" tap DOWN 0.2; sleep 1 - python3 "$SD/pad.py" tap DOWN 0.2; sleep 1 - python3 "$SD/pad.py" tap A 0.3; sleep 4 + # EXTRAS is the LAST of the five items and the menu opens on NEW GAME. Do not + # count presses: on 2026-08-31 four DOWNs landed on OPTIONS because one was + # dropped. Press until the cursor STOPS MOVING instead, which needs no item + # count and no row calibration -- `ring_row.py`'s ROW0/SPACING are x11grab + # constants and are 45 px out on a `screenshot` grab (see METHOD.md), but the + # raw row it returns is still a monotone function of the item. + row(){ shot /tmp/mbc_row.png; python3 - <<'PY' +from PIL import Image +import sys; sys.path.insert(0,"/work/tools/re-capture") +import ring_row +try: print("%.1f" % ring_row.ring_row(Image.open("/tmp/mbc_row.png"))) +except Exception: print("nan") +PY + } + prev="$(row)"; echo " cursor row $prev" + for _ in 1 2 3 4 5 6 7 8; do + python3 "$SD/pad.py" tap DOWN 0.2; sleep 2 + cur="$(row)"; echo " cursor row $cur" + [ "$cur" = "$prev" ] && break + prev="$cur" + done + python3 "$SD/pad.py" tap A 0.3; sleep 5 s="$(screen)"; echo " after EXTRAS attempt: $s"; shot "$OUT/extras.png" fi diff --git a/tools/re-capture/ui_blend_map.py b/tools/re-capture/ui_blend_map.py index 3285698c..89f0a233 100755 --- a/tools/re-capture/ui_blend_map.py +++ b/tools/re-capture/ui_blend_map.py @@ -45,29 +45,32 @@ def blend_name(raw): return "%s+%s" % (FACTOR.get(src, src), FACTOR.get(dst, dst)) -def sprite_sizes(build): - """name -> (w, h), straight off the disc via the formats crate.""" +def sprite_sizes(builds): + """name -> (w, h), straight off the disc via the formats crate. + + `builds` is a list because the live title is TWO builds composited -- 4 draws + the art and 2 draws the `PRESS (A)` plate over it -- so a capture of the + title contains elements from both and a one-build size table cannot name + them all. + """ out = subprocess.run( ["cargo", "run", "--release", "-q", "-p", "sylpheed-formats", - "--example", "frame_alpha_census"], + "--example", "frame_alpha_census", "--"] + [str(b) for b in builds], capture_output=True, text=True, cwd="/work", env={**__import__("os").environ, "SYLPHEED_DISC": "/disc"}).stdout - sizes, cur = {}, None + sizes = {} for line in out.splitlines(): - m = re.match(r"=== GP_TITLE build (\d+) ===", line) - if m: - cur = int(m.group(1)) - continue m = re.match(r"(\S+\.t32)\s+(\d+)x(\d+)", line) - if m and cur == build: + if m: sizes[m.group(1)] = (int(m.group(2)), int(m.group(3))) return sizes def main(): path = sys.argv[1] - build = int(sys.argv[sys.argv.index("--build") + 1]) if "--build" in sys.argv else 5 - sizes = sprite_sizes(build) + spec = sys.argv[sys.argv.index("--build") + 1] if "--build" in sys.argv else "5" + builds = [int(b) for b in spec.split(",")] + sizes = sprite_sizes(builds) lines = open(path).read().splitlines() rows = [] for i, line in enumerate(lines):