Files
Sylpheed/crates/sylpheed-formats/examples/t8ad_header_compare.rs
sylph-decoder abab343d2e re: a .t32 element carries no blend/alpha mode -- undecodable, with reach
Answers the port's ask about ptframe1/ptframe2, whose residual is uniquely higher on
flat pixels than edges and signed one direction -- a body-intensity difference.

Prior work covers .prm primitives and a refuted T8aD +0x04 bit; neither covers a
.t32 element. All 15 words of the 60-byte declaration entry are read: 3 are the
name, 8 constant, the rest kind, focus index, position and pivot. The frames are
kind 0, identical to every other plain sprite.

One candidate found and refuted by myself: T8aD +0x08 is the only word where both
frames agree uniquely on that screen, at 0x8050 -- but 38 sprites carry it
disc-wide, only 8 named frame, and the high byte tracks the archive. It is an
atlas/format word, not a mode.

Also records a false positive of my own test: +0x00 and +0x08 first read as
'separating the frames' because those words are the name string.

So any blend the port picks is authored. Reach: not looked at the executable's draw
path, where a mode selected in code rather than data would live.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-31 05:13:27 +00:00

49 lines
2.3 KiB
Rust

//! Does a `.t32` sprite's own T8aD header carry a per-sprite blend/alpha mode?
//!
//! The declaration entry does not: `ptframe1`/`ptframe2` are kind 0, identical to
//! every other plain sprite on the menu. The remaining place a mode could live is
//! the sprite's own T8aD child. ⚠️ `REFUTED.md` already kills one reading of it —
//! "`T8aD +0x04` bit `0x02` selects an additive blend" — so this is not that
//! claim; it asks whether ANY header word separates the two frames from the
//! sprites the port measures as ordinary.
//!
//! cargo run -p sylpheed-formats --example t8ad_header_compare
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");
let by = ar.read(&ar.entries()[5]).expect("entry 5");
let b = ui_layout::parse_build(&by).expect("build");
let mut names: Vec<&String> = b.sprites.keys().collect();
names.sort();
println!("{:<20} {:>8} first 12 header words", "sprite", "size");
let mut rows: Vec<(String, Vec<u32>)> = Vec::new();
for n in names {
let (off, size) = b.sprites[n];
let s = &by[off..(off + size).min(by.len())];
if s.len() < 48 { continue }
let ws: Vec<u32> = (0..12)
.map(|k| u32::from_be_bytes([s[k*4], s[k*4+1], s[k*4+2], s[k*4+3]]))
.collect();
let mark = if n.starts_with("ptframe") { " <- FRAME" } else { "" };
println!("{n:<20} {size:>8} {}{mark}",
ws.iter().map(|v| format!("{v:08X}")).collect::<Vec<_>>().join(" "));
rows.push((n.clone(), ws));
}
// which words take a value the two frames share and nobody else does?
let fr: Vec<&(String, Vec<u32>)> = rows.iter().filter(|(n, _)| n.starts_with("ptframe")).collect();
if fr.len() == 2 {
println!("\nwords where BOTH frames agree and no other sprite has that value:");
let mut any = false;
for w in 0..12 {
let a = fr[0].1[w]; let bb = fr[1].1[w];
if a != bb { continue }
if rows.iter().any(|(n, v)| !n.starts_with("ptframe") && v[w] == a) { continue }
println!(" word {w} (+0x{:02X}) = {a:08X}", w * 4); any = true;
}
if !any { println!(" NONE"); }
}
}