diff --git a/runtime/include/host_overlay.h b/runtime/include/host_overlay.h index e00d6020..8d5f054a 100644 --- a/runtime/include/host_overlay.h +++ b/runtime/include/host_overlay.h @@ -46,6 +46,14 @@ void psx_host_overlay_set_draw_cb(PsxHostOverlayDrawFn fn, void *ctx); int psx_host_overlay_has_draw(void); void psx_host_overlay_draw(int width, int height); /* renderer side */ +/* ---- Game HUD layer --------------------------------------------------------- + * A title's own heads-up display, drawn once per presented frame (real and + * generated) under the in-game menu, same thread and GL rules as the overlay + * callback above. Set once (title activation) and kept for the session; NULL + * unregisters (no wait: the registrant keeps fn and ctx alive for the session). */ +void psx_host_set_hud_draw_cb(PsxHostOverlayDrawFn fn, void *ctx); +void psx_host_hud_draw(int width, int height); /* renderer side */ + /* ---- P3: input sink ----------------------------------------------------- * The sink sees every host SDL event first (main thread), in the normal event * drain and in the host pause loop. Returning non-zero consumes the event. diff --git a/runtime/src/gpu_gl_renderer.c b/runtime/src/gpu_gl_renderer.c index 745e3be0..6b91eb61 100644 --- a/runtime/src/gpu_gl_renderer.c +++ b/runtime/src/gpu_gl_renderer.c @@ -9931,8 +9931,10 @@ static void gl_swap_with_osd(void) { } if (ov_image(3, &px, &ow, &oh) && px) gl_draw_osd_image(px, ow, oh, ww, wh, 0, 0, ww, wh); - /* In-game overlay provider (host_overlay.h P2), over everything - * the host composes; no-op unless one registered. */ + /* The title's HUD layer, then the in-game overlay provider + * (host_overlay.h P2) over everything; each a no-op unless one + * registered. */ + psx_host_hud_draw(ww, wh); psx_host_overlay_draw(ww, wh); } } diff --git a/runtime/src/host_overlay.c b/runtime/src/host_overlay.c index bd610f97..6c7b87ae 100644 --- a/runtime/src/host_overlay.c +++ b/runtime/src/host_overlay.c @@ -101,6 +101,20 @@ void psx_host_overlay_draw(int width, int height) { atomic_fetch_sub(&s_draw_inflight, 1); } +/* ---- Game HUD layer ------------------------------------------------------- */ +static PsxHostOverlayDrawFn s_hud_fn = NULL; +static void *s_hud_ctx = NULL; + +void psx_host_set_hud_draw_cb(PsxHostOverlayDrawFn fn, void *ctx) { + s_hud_ctx = ctx; + s_hud_fn = fn; +} + +void psx_host_hud_draw(int width, int height) { + PsxHostOverlayDrawFn fn = s_hud_fn; + if (fn && width > 0 && height > 0) fn(width, height, s_hud_ctx); +} + /* ---- P3: input sink -------------------------------------------------------- */ static PsxHostInputSinkFn s_sink_fn = NULL; static void *s_sink_ctx = NULL;