formats: derive the paint order from the sprite layer key

compose now sorts elements by the word at +0x08 of their sprite's T8aD header
instead of painting in declaration order, for every build except the two whose
measured order is hard-coded. That word is non-decreasing in the order the game
actually paints both measured screens, so every screen nobody has captured now
gets its layering from the file rather than from the declaration table, which is
provably not the paint order.

Verified with artifacts and both ways, not by a green build: the disc test
asserts the measured orders never invert the key and that the composite's key
sequence is sorted, and reading the word from +0x0c instead makes it fail; the
title composites identically; and GP_MISSION_SELECT — uncaptured — now composites
cleanly, committed as a capture.

Two things recorded rather than smoothed over: ties keep declaration order
because the game breaks them some other way that is not known, and the
developer-logo splash has no .rat child, so is_build rejects it and the
compositor never sees that bundle at all — its measured order is inert in
practice and screen render cannot draw it.
This commit is contained in:
Sylpheed RE agent
2026-08-19 05:28:05 +00:00
parent aa1f49633e
commit d9ae42dd55
4 changed files with 159 additions and 1 deletions

View File

@@ -64,3 +64,27 @@ port can read directly.
* **Two screens is two screens.** A third measured permutation would either
promote this to a rule or break it. The cheapest one available is any screen
whose object is resident at the same time as the title's.
## Landed in the compositor (2026-08-19)
`ui_layout::compose` now paints in the **derived** order — a stable sort of the
elements by `sprite_layer_key` — for every build except the two whose measured
order is hard-coded, which stay as the ground truth they are. Elements with no
sprite (the `.prm` primitives) have no key; they keep their declaration position
among themselves and `compose` skips them anyway.
Verified three ways rather than by a green build:
* a disc-gated test asserts the measured orders are **non-decreasing** in the key
and that the composite's key sequence comes out sorted — and it was checked
both ways: reading the word from `+0x0c` instead of `+0x08` makes it fail;
* the title still composites identically (its measured order is used);
* a screen nobody has captured — `GP_MISSION_SELECT` — now composites cleanly
([capture](../captures/mission-select-derived-order.png)).
**Found on the way, and worth its own line:** the developer-logo splash bundle
has no `.rat` child, so `ui_layout::is_build` rejects it and the compositor never
sees it. Its measured order is therefore inert in practice, and the splash cannot
be rendered by `screen render` at all. That is a separate gap in what counts as a
"build", not a paint-order question.