"""Does bit 0x02 separate sprites by their RGB-vs-alpha content? Premultiplied alpha predicts RGB <= A everywhere for the flagged group. Tested below and refuted. What remains is a description: how often RGB exceeds A, which is the signature of glow art (bright colour carried at low alpha). Bit comes from the T8aD header; the name from the string immediately preceding it (validated 17/18 on build 4 against the RATC child order). """ import struct, zlib, glob, re, os from disc import disc_root import numpy as np from PIL import Image NAME = re.compile(rb'[A-Za-z0-9_.]{2,31}\x00') base = disc_root() + "/dat/GP_TITLE" stub = open(base + ".pak", "rb").read() n = struct.unpack_from(">I", stub, 4)[0] blob = b"".join(open(s, "rb").read() for s in sorted(glob.glob(base + ".p[0-9][0-9]"))) flags = {} # (entry_hash, name, w, h) -> flags for i in range(n): h_, off, sz = struct.unpack_from(">III", stub, 0x10 + 12 * i) st = blob[off:off + sz] if len(st) < 10: continue try: d = zlib.decompress(st[10:]) if st[:2] == b"Z1" else st except Exception: continue for m in re.finditer(b"T8aD", d): o = m.start() try: fl = struct.unpack_from(">I", d, o + 4)[0] w = struct.unpack_from(">I", d, o + 0x14)[0] hh = struct.unpack_from(">I", d, o + 0x18)[0] except Exception: continue if not (0 < w <= 4096 and 0 < hh <= 4096): continue ms = list(NAME.finditer(d[max(0, o - 64):o])) if not ms: continue flags[(f"{h_:08x}", ms[-1].group()[:-1].decode("latin1"), w, hh)] = fl rows = [] for f in sorted(glob.glob("/tmp/tex/*.png")): b = os.path.basename(f) m = re.match(r"([0-9a-f]{8})_(.+)_(\d+)x(\d+)\.png$", b) if not m: continue key = (m.group(1), m.group(2), int(m.group(3)), int(m.group(4))) fl = flags.get(key) if fl is None: continue a = np.asarray(Image.open(f).convert("RGBA")).astype(int) rgb = a[:, :, :3].max(axis=2); al = a[:, :, 3] rows.append((bool(fl & 2), 100 * float((rgb > al).mean()), m.group(2))) s = [r[1] for r in rows if r[0]]; c = [r[1] for r in rows if not r[0]] print(f"matched {len(rows)} decoded textures to a T8aD flag word") print(f" bit SET n={len(s):3d} mean %(RGB>A) {np.mean(s):6.2f} median {np.median(s):6.2f}") print(f" bit clear n={len(c):3d} mean %(RGB>A) {np.mean(c):6.2f} median {np.median(c):6.2f}") print(f"\n premultiplied would require ~0% for the flagged group -> REFUTED") # separability: what threshold best splits them, and how well? best = (0, None) for t in np.arange(0, 100, 0.5): acc = (sum(x > t for x in s) + sum(x <= t for x in c)) / len(rows) if acc > best[0]: best = (acc, t) print(f" best single-threshold accuracy: {100*best[0]:.1f}% at %(RGB>A) > {best[1]}") print(f" (base rate, always-guess-majority: {100*max(len(s),len(c))/len(rows):.1f}%)")