# 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 SECONDARY vtable — 32 adjustor thunks Read out of guest memory: 32 consecutive code pointers in `0x823c43b0 … 0x823c45a0`, terminated by `0xfffffffc`. 🔴 **Corrected 2026-08-24, same session.** The first write-up called these "32 methods" and the three xrefs to the table "three construction sites". Both were wrong, and `sylpheed.db`'s disassembly says why — every slot points at a **16-byte adjustor thunk**: ``` lwz r11, -4(r3) ; the this-adjustment stored just before the object subf r3, r11, r3 ; fix up `this` b .long 0 ``` That is the classic PPC/MSVC thunk for a **secondary base subobject**, so `0x820B2A64` is a *secondary* vtable and the class uses multiple inheritance. `sub_823C3148`, which the first write-up listed as a constructor because it *references* the table, is in fact the branch target of one of the table's own thunks. **Where the real methods live.** Taking the 32 branch targets: 32 distinct addresses, **18** of them known function starts in `sylpheed.db`, in two clusters — `0x823c3xxx` (beside the thunk block itself) and `0x823e3xxx`. The rest land on further stubs immediately after the block. **None** of the 32 appears in any of the 1 150 vtables the DB classified, so nothing places this class in a named hierarchy; the disc's RTTI carries no class names. The two clusters are what a derived class looks like — its own overrides next to its own thunks, and inherited implementations elsewhere — but that is a reading, not a measurement. ## 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.