aboutsummaryrefslogtreecommitdiffstats
path: root/src/render.c
diff options
context:
space:
mode:
authorgbc dev <gbc@localhost>2026-07-04 23:07:50 +0200
committergbc dev <gbc@localhost>2026-07-04 23:07:50 +0200
commitf4ba890eb4b98e1a65a3d9fc8ba8f62dda66895b (patch)
treecb1cccb2dfd0f1b59e59e8e86454849179c88cb2 /src/render.c
parentinput: external control channel via FIFO (diff)
downloadsl0pboy-f4ba890eb4b98e1a65a3d9fc8ba8f62dda66895b.tar.gz
sl0pboy-f4ba890eb4b98e1a65a3d9fc8ba8f62dda66895b.tar.xz
sl0pboy-f4ba890eb4b98e1a65a3d9fc8ba8f62dda66895b.zip
speed control: frame skipping to decouple terminal draw from emulation
Emulation always runs at native rate (correct game speed); --frameskip N draws only 1 of every N+1 frames so a slow terminal no longer bottlenecks the loop. Adds --fps cap, --uncapped/--turbo, live [ ] and f keys, HUD readout, and an exit summary of emulated-vs-drawn fps. Replaces the confusing --render-fps.
Diffstat (limited to 'src/render.c')
-rw-r--r--src/render.c29
1 files changed, 27 insertions, 2 deletions
diff --git a/src/render.c b/src/render.c
index f659da3..df39c99 100644
--- a/src/render.c
+++ b/src/render.c
@@ -51,8 +51,19 @@ static char outbuf[SCREEN_W * (SCREEN_H/2) * 40 + 4096];
static u8 prev_fb[SCREEN_H][SCREEN_W][3];
static bool need_full = true; // force a complete repaint
static volatile sig_atomic_t resized = 0; // set by SIGWINCH
+static int hud_frameskip = 0;
+static bool hud_turbo = false;
void render_force_full(void) { need_full = true; }
+
+// Update the on-screen HUD values; forces a status-line repaint on change.
+void render_set_hud(int frameskip, bool turbo) {
+ if (frameskip != hud_frameskip || turbo != hud_turbo) {
+ hud_frameskip = frameskip;
+ hud_turbo = turbo;
+ need_full = true;
+ }
+}
static void on_winch(int s) { (void)s; resized = 1; }
void render_frame(GB *gb) {
@@ -99,8 +110,9 @@ void render_frame(GB *gb) {
// status line: static text, only (re)draw on a full repaint
if (need_full) {
o += sprintf(o, "\x1b[0m\x1b[%d;1H\x1b[38;2;150;150;150m %.*s "
- "[wasd/arrows] z:A x:B space:sel enter:start q:quit",
- SCREEN_H/2 + 1, 15, gb->cart.title);
+ "skip:%d%s [f]ast [ ][ ] q:quit\x1b[K",
+ SCREEN_H/2 + 1, 12, gb->cart.title,
+ hud_frameskip, hud_turbo ? " TURBO" : "");
}
memcpy(prev_fb, p->fb, sizeof(prev_fb));
@@ -119,8 +131,18 @@ void render_frame(GB *gb) {
// decay[] : momentary presses (keyboard, or FIFO taps), count down per frame
static int decay[8]; // frames remaining for each BTN bit position
static u8 held; // explicitly-held buttons (FIFO)
+static int turbo_toggles; // pending fast-forward toggles (consumed by main)
+static int frameskip_delta;// pending frameskip adjustment (consumed by main)
#define HOLD_FRAMES 4
+bool input_take_turbo(void) {
+ if (turbo_toggles > 0) { turbo_toggles--; return true; }
+ return false;
+}
+int input_take_frameskip_delta(void) {
+ int d = frameskip_delta; frameskip_delta = 0; return d;
+}
+
static int mask_index(int mask) {
for (int i = 0; i < 8; i++) if ((1 << i) == mask) return i;
return -1;
@@ -226,6 +248,9 @@ bool input_poll(GB *gb) {
case 'x': case 'k': tap(BTN_B, HOLD_FRAMES); break;
case '\r': case '\n': tap(BTN_START, HOLD_FRAMES); break;
case ' ': tap(BTN_SELECT, HOLD_FRAMES); break;
+ case 'f': turbo_toggles++; break; // toggle fast-forward
+ case '[': frameskip_delta--; break; // fewer skipped frames
+ case ']': frameskip_delta++; break; // more skipped frames
case 'q': case 3: quit = true; break;
}
}