docs(gfx): animated-compositor design spec + Phase 1 plan + animation RE

engine-re.md: the gfx animation/effects subsystem (gfx_anim_start/0x234, 0x1fd,
0x238 non-blocking anim clock, render model — the fades are host-loop-drivable, no
VM/host lockstep). Design spec: retained per-frame animated compositor, 4-phase.
Phase 1 plan (TDD): retained DrawLayer model + per-frame clear/recomposite. Ghidra
handlers/workers annotated (0x234/0x1fd/0x238/gfx_anim_start).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-07-07 19:41:13 -04:00
parent 2f3c40fa64
commit 011d0900c5
3 changed files with 417 additions and 0 deletions

View File

@@ -250,6 +250,29 @@ deferred — Phase 2 scope), and some object-slot CGs start with a zero anchor (
game's warm ones; default object geometry is confirmed `(0,0)` in `gfx_object_init_default`, so it is not a
missing-default bug). See `docs/phase-a-slice-plan.md` A2b-Geometry.
### The gfx animation/effects subsystem — the `AE*` fades (2026-07-07)
The `AE*` flash/glow effects (and sprite motion) are a **native time-animated retained render loop**, not
per-frame bytecode. Reversed + annotated in Ghidra:
- **Retained objects carry animation state:** an *active* flag (obj`+0` bit 4), a **progress** counter
(obj`+0x214`, starts 0), a **duration** (obj`+0x228`), and a **target vector** (obj`+0x244/248/24c`).
- **`gfx_anim_start`** (`0x47f060`, worker for op **`0x234`**) configures a per-object animation: sets the
flag, resets progress, stores duration + target. Op **`0x1fd`** (`gfx_op_0x1fd_set_vec_scaled`) sets a
scaled 3-vector.
- **Op `0x238`** (`gfx_op_0x238_set_anim_clock`) sets a **global animation clock**, **non-blocking**:
`ctx+0x51b78 = 0` (elapsed), `ctx+0x51b7c = duration` (the max per-object duration; SC0000 `label_1235a`
maxes a table to compute it). It does **not** loop/wait.
- **Frame model:** the bytecode does `configure anims (0x234/0x1fd) → set clock (0x238) → show-text →
wait-for-input` and **continues**; the native render loop advances the clock + per-object progress each
frame, interpolates, composites, presents. Render/present family nearby: `0x243/0x20c/0x21c/0x224`
(`u004162xx`, not yet fully RE'd). **⇒ the port can drive animation in the HOST per-frame loop while the
VM is parked at wait-for-input — no blocking present op, no VM/host frame-lockstep** (the answer to the
"frame loop" question).
Consequence: reproducing the fades needs a **retained per-frame animated compositor** — the current
immediate-mode permanent canvas can neither fade nor clear. Design: `docs/superpowers/specs/2026-07-07-
animated-compositor-design.md`.
---
## Native walls backlog (targets for this loop)