formats: decode the HUD glyph quad behind the objective counter

Following the pointers that move with REMAINING OB lands on four identical
objects whose first word is 0x820B2A64. Read live: that address holds 32
consecutive code pointers in 0x823c43b0..0x823c45a0 terminated by 0xfffffffc - a
vtable - and sylpheed.db has three ref xrefs to it from sub_823C3060,
sub_823C3148 and sub_823C31E0, i.e. three construction sites, the same pattern
the splash item vtable shows. No name: the disc's RTTI carries none.

The instance is a textured quad: a pixel size at +0x1c/+0x20 (34 x 42 for a
digit) and four vertices at +0x30/+0x48/+0x60/+0x78, each a colour and a UV pair.
The four UVs measured are the corners of an axis-aligned rectangle in order, all
0xffffffff.

The atlas size is a check rather than a guess: the UV rectangle is 0.0265 x
0.0547, and multiplying by 1280 x 768 gives 33.9 x 42.0 against the 34.0 x 42.0
stored in the object's own size fields - two independent fields agreeing to a
rounding step.

Also recorded: these objects churn. Re-reading an old pointer target a minute
later returned unrelated data, so this is a snapshot of a live pool.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
This commit is contained in:
Sylpheed RE agent
2026-08-24 10:07:43 +00:00
parent b847bac3bb
commit 9367f91ec0

View File

@@ -0,0 +1,75 @@
# The HUD's glyph quad — vtable `0x820B2A64`
**Status: ✅ `CONFIRMED` for the object layout and the atlas size**, read live off
a Stage 02 run and checked against itself. 🟡 the class has no name (RTTI carries
none disc-wide).
## How it was reached
[`mission-objective-counter.md`](mission-objective-counter.md) found that the
words moving with `REMAINING OB` are four ASCII digits and four guest pointers.
Following the pointers lands on four objects with an identical shape, whose first
word is `0x820B2A64`.
## It is a vtable, with three constructors
Read out of guest memory: **32 consecutive code pointers**, all inside
`0x823c43b0 … 0x823c45a0`, terminated by `0xfffffffc`. `sylpheed.db` has three
`ref` xrefs to it, from `sub_823C3060`, `sub_823C3148` and `sub_823C31E0` — three
construction sites, the same pattern the splash item vtable `0x820b30b4` shows.
The DB does not classify `0x820B2A64` itself as a vtable and knows no name for
it, which is expected: the disc's RTTI carries no class names.
## The instance
```
-0x0c f32 1280.0 ) the design space, immediately before the object
-0x08 f32 720.0 )
+0x00 u32 0x820B2A64 vtable
+0x1c f32 34.0 width in pixels
+0x20 f32 42.0 height in pixels
+0x30 u32 0xffffffff vertex 0 colour
+0x34 f32 u u
+0x38 f32 v v
+0x48 … vertex 1 (+0x18 stride)
+0x60 … vertex 2
+0x78 … vertex 3
```
Measured on one digit glyph:
| vertex | colour | u | v |
|---|---|---|---|
| 0 | `0xffffffff` | 0.5477 | 0.5013 |
| 1 | `0xffffffff` | 0.5742 | 0.5013 |
| 2 | `0xffffffff` | 0.5742 | 0.5560 |
| 3 | `0xffffffff` | 0.5477 | 0.5560 |
Four corners of an axis-aligned rectangle, in order, all untinted — a textured
quad.
## ✅ The atlas is 1280 × 768, and that is a check rather than a guess
The UV rectangle is 0.0265 × 0.0547. Multiply by **1280 × 768**:
```
0.0265 × 1280 = 33.9 -> the width stored at +0x1c is 34.0
0.0547 × 768 = 42.0 -> the height stored at +0x20 is 42.0
```
Two independent fields of the same object agree to within a rounding step, which
is what makes the atlas size a measurement instead of a plausible number.
## ⚠️ These objects churn
The four pointers next to the counter swap as the digit changes, and re-reading
one of the *old* targets a minute later returned unrelated data — the object had
been recycled. Anything read here is a snapshot of a live pool, not a stable
address.
## What this is for
It gives the port a decoded HUD text primitive: a glyph is a quad with a pixel
size and four UVs into a 1280×768 atlas, drawn by a class with 32 virtual methods
and three constructors. And it explains why the objective counter was so easy to
find in RAM — the value sits inside the widget that renders it.