Files
Sylpheed/tools/re-capture/read_draws.py
sylph-decoder 9d695debae re: refute my own batching hypothesis -- blend state, not linkage
Last iteration I proposed that the two sweeps share one indices=8 draw
because ptloop01 links to ptloop02, and said testing it needed a
loading-screen capture I lack. Wrong twice: a linked pair was already in
every capture, ptbtn00 -> ptbtn00f.

Measured: ptbtn00f is drawn ALONE in 899 (f6b) and 1441 (f6) draws and
batched in ZERO, while the sweeps pair up in 1092 and 1744. Linkage does not
batch. The constraint is blend state -- ptbtn00f is additive and its linked
partner alpha-over, which cannot share a draw. The sweeps batch because both
are additive on one page.

Page+blend is necessary but not sufficient: 8154/alpha-over appears as two
separate draws in a single frame, 2108 such draws in f6b. This removes a
wrong cause rather than supplying a batching rule.

Extends read_draws.py to preserve draw grouping (draw index and quad count
per draw); check_labels.py still passes unchanged as a regression control.

Refutation attempt on the port's 0x3002/0x3003 menu-item reading: survives.
958 of 970 stems contain "btn"; the 12 exceptions are psselect_slot and
psselect_slot_blank, which are menu rows.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
2026-09-04 13:15:57 +00:00

74 lines
3.0 KiB
Python
Executable File

#!/usr/bin/env python3
"""Read a Xenia UI draw log -- EVERY quad, not the first vertex of each draw.
⚠️ THIS EXISTS BECAUSE THE OBVIOUS READER IS WRONG. A draw line carries
`indices=N` vertices on ONE `v:` line, and N is routinely 8 -- two quads batched
into a single draw. A reader that takes the first `v: [...]` match per line sees
one of them and silently drops the rest.
That produced a clean, complete-looking negative twice in this corpus
(`f6-unit5-pteff03a-never-drawn.md`, `f6-unit6-...`), both refuted by
`f6-unit11-pteff03a-IS-drawn.md`. `REFUTED.md` L170 had already recorded a draw
carrying two rotated parallelograms. Use this reader; do not re-roll the regex.
from read_draws import read
frames = read(path) # {frame: [Quad, ...]} Quad = (page, verts, alpha, blend, cx)
"""
import re, collections
_F = re.compile(r'^--- frame (\d+) ')
_TEX = re.compile(r'tex\[base=(0x[0-9A-F]+) (\d+)x(\d+) fmt=(\d+)(?: h=([0-9A-F]+))?\]')
_IDX = re.compile(r'indices=(\d+)')
_V = re.compile(r'\[(-?\d+\.\d+),(-?\d+\.\d+),z=[-\d.]+,col=([0-9A-F]{8})\]')
class Quad(tuple):
__slots__ = ()
def __new__(cls, page, verts, alpha, blend, cx, draw=-1, nquads=1):
return tuple.__new__(cls, (page, verts, alpha, blend, cx, draw, nquads))
page = property(lambda s: s[0])
verts = property(lambda s: s[1])
alpha = property(lambda s: s[2])
blend = property(lambda s: s[3])
cx = property(lambda s: s[4])
draw = property(lambda s: s[5]) # index of the draw line within the frame
nquads = property(lambda s: s[6]) # how many quads that draw carried
def read(path):
frames = collections.defaultdict(list)
frame = page = blend = None
idx = 0
draw_no = -1
for line in open(path, errors='replace'):
m = _F.match(line)
if m:
frame = int(m.group(1)); draw_no = -1; continue
if frame is None:
continue
mt = _TEX.search(line)
if mt:
page = mt.group(5) or mt.group(1)
mi = _IDX.search(line); idx = int(mi.group(1)) if mi else 0
mb = re.search(r'blend=(0x[0-9A-F]+)', line); blend = mb.group(1) if mb else None
continue
if page is not None and ' v: ' in line:
vs = _V.findall(line)
draw_no += 1
nq = len(vs) // 4
# every group of 4 vertices is one quad; a partial tail is dropped
for q in range(nq):
quad = vs[q*4:(q+1)*4]
cx = sum(float(v[0]) for v in quad) / 4
frames[frame].append(Quad(page, [(float(a), float(b)) for a, b, _ in quad],
int(quad[0][2][:2], 16), blend, round(cx, 3),
draw_no, nq))
page = None
return dict(frames)
if __name__ == '__main__':
import sys
fr = read(sys.argv[1])
ks = sorted(fr)
tot = sum(len(v) for v in fr.values())
print(f"{len(ks)} frames, {tot} quads, frames {ks[0]}..{ks[-1]}")
print(f"mean quads/frame {tot/len(ks):.2f}")