This repository has been archived on 2026-09-16. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Syplheed-Reborn/docs/re/structures/hud-glyph-quad.md
Sylpheed RE agent 00a06abc77 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
2026-08-24 10:07:43 +00:00

2.8 KiB
Raw Blame History

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 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.