Add the akgl_ui subsystem: clay-backed menus, HUDs and dialogs #3

Merged
andrew merged 15 commits from clay-ui into main 2026-08-02 16:14:50 -04:00
2 changed files with 22 additions and 1 deletions
Showing only changes of commit f772da7296 - Show all commits

View File

@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.10)
# The single source of truth for the library version. It drives the generated
# include/akgl/version.h, the shared library's VERSION and SOVERSION, and the
# Version field in akgl.pc. Bump it here and nowhere else.
project(akgl VERSION 0.8.0 LANGUAGES C)
project(akgl VERSION 0.9.0 LANGUAGES C)
# Memory checking reuses the suites that already exist -- `ctest -T memcheck`
# runs every registered test under valgrind -- rather than adding programs of its

21
TODO.md
View File

@@ -1273,6 +1273,15 @@ engines spend the same frame**.
cached") with the raw-SDL control row the perf rules require. Budget to
move: `tests/perf_render.c:391`.
**The UI subsystem is this cache's second consumer, and the bigger one.**
`akgl_ui_execute_commands` (`src/ui.c`) draws every TEXT render command
through `akgl_text_rendertextat`, one wrapped line per command per frame —
a menu of five rows re-rasterizes five lines at 60 Hz whether or not any
of them changed, where the original HUD case was one line changing once a
second. Abstract-on-the-second-consumer says this item's time has come;
the key already fits, since clay hands the executor stable text bytes
between frames.
3. **Non-raising sprite lookup — target 10, a design change.** Give
`akgl_character_sprite_get` (`src/character.c:84-94`) the companion that
returns `NULL` without raising, then convert the three sites that raise
@@ -2196,6 +2205,18 @@ a live defect -- but nothing rejects it, and `max_timestep` is caller-settable.
`renderfunc`. This item is the half that remains: one uniform `scale`, with no way
to expand a single axis.
3. **`akgl_ControlMap.mouseid` and `.penid` are still dead fields, deliberately.**
The UI subsystem (0.9.0) brought the mouse into the library, and it would have
been natural to wire these up on the way -- it did not, on purpose. Control maps
translate device events into *actor handler calls*, and the UI wants absolute
pointer state per event; those are different consumers, and building
gameplay-mouse machinery into `src/controller.c` with no game asking for it is
the abstract-before-the-second-consumer mistake. The mouse path lives in
`src/ui.c` (`akgl_ui_handle_event`); when a game wants mouse-driven actors,
*that* is the consumer these fields were declared for, and the work lands in
`controller.c` then. Same for `.axis`, `.axis_range_min` and `.axis_range_max`,
which `akgl_controller_handle_event` has never consulted.
## Found while writing the manual
Twenty-one chapters and two tutorial games were written against `src/` rather than