aboutsummaryrefslogtreecommitdiffstats
path: root/src/render.c
diff options
context:
space:
mode:
authorgbc dev <gbc@localhost>2026-07-18 20:41:19 +0200
committergbc dev <gbc@localhost>2026-07-18 20:41:19 +0200
commitfa1579cc9f209dbeb14ab277dc9c4ac741ace57c (patch)
tree7ca130f0d360e93460de2cae71daeb97c3819d0f /src/render.c
parentmain: allow --sock (control/debug socket) in headless mode (diff)
downloadsl0pboy-fa1579cc9f209dbeb14ab277dc9c4ac741ace57c.tar.gz
sl0pboy-fa1579cc9f209dbeb14ab277dc9c4ac741ace57c.tar.xz
sl0pboy-fa1579cc9f209dbeb14ab277dc9c4ac741ace57c.zip
render: --shrink N - downscale the half-block live display (1-4)
Decimates the LCD N x N before the half-block encode so the monitor pane takes 160/N cols x 72/N rows. Display-only: capture, recording and sixel still read the full-res framebuffer. Decimation is max-luma pick, not box-average: terminal fonts are 1px bright strokes on dark background, and averaging dims them into grey mush (the 'blurry font' regression). Keeping the brightest source pixel of each block preserves stroke brightness and hue.
Diffstat (limited to 'src/render.c')
-rw-r--r--src/render.c45
1 files changed, 42 insertions, 3 deletions
diff --git a/src/render.c b/src/render.c
index 4f612ae..1f232d8 100644
--- a/src/render.c
+++ b/src/render.c
@@ -477,6 +477,24 @@ const u8 *render_capture_frame(GB *gb, int *w, int *h) {
return &fb[0][0][0];
}
+// ---- half-block live-display downscale (--shrink N) ------------------------
+// Purely a *display* concern: the LCD is decimated N x N before the
+// half-block encode, so the pane takes 160/N cols x 72/N rows. Capture,
+// recording and sixel are untouched (they read the full-res framebuffer).
+// Decimation is MAX-LUMA PICK, not box-average: terminal fonts are 1px
+// bright strokes on dark background, and averaging dims them into grey
+// mush. Keeping the brightest source pixel of each block preserves both
+// stroke brightness and hue (it's always a real pixel, never a blend).
+static int shrink = 1;
+static u8 shrink_fb[SCREEN_H][SCREEN_W][3];
+
+void render_set_shrink(int n) {
+ if (n < 1) n = 1;
+ if (n > 4) n = 4;
+ shrink = n;
+ resized = 1; // force a clear + full repaint
+}
+
void render_frame(GB *gb) {
if (sixel_enabled) {
if (chrome_enabled) render_frame_chrome(gb);
@@ -485,6 +503,27 @@ void render_frame(GB *gb) {
}
PPU *p = &gb->ppu;
u8 (*fb)[SCREEN_W][3] = lcd_fb(p);
+ int W = SCREEN_W, H = SCREEN_H;
+ if (shrink > 1) {
+ W = SCREEN_W / shrink;
+ H = (SCREEN_H / shrink) & ~1; // even, so rows pair into cells
+ for (int y = 0; y < H; y++)
+ for (int x = 0; x < W; x++) {
+ u8 *best = fb[y*shrink][x*shrink];
+ int bl = -1;
+ for (int dy = 0; dy < shrink; dy++)
+ for (int dx = 0; dx < shrink; dx++) {
+ u8 *s = fb[y*shrink + dy][x*shrink + dx];
+ // integer luma: 2R + 5G + B (~BT.601)
+ int l = 2*s[0] + 5*s[1] + s[2];
+ if (l > bl) { bl = l; best = s; }
+ }
+ shrink_fb[y][x][0] = best[0];
+ shrink_fb[y][x][1] = best[1];
+ shrink_fb[y][x][2] = best[2];
+ }
+ fb = shrink_fb;
+ }
char *o = outbuf;
if (resized) { resized = 0; need_full = true; o += sprintf(o, "\x1b[2J"); }
@@ -496,9 +535,9 @@ void render_frame(GB *gb) {
int PR = -1, PG = -1, PB = -1; // last-emitted bg
int cur_row = -2, cur_col = -2; // terminal cell just written (0-indexed)
- for (int y = 0; y < SCREEN_H; y += 2) {
+ for (int y = 0; y < H; y += 2) {
int row = y / 2;
- for (int x = 0; x < SCREEN_W; x++) {
+ for (int x = 0; x < W; x++) {
u8 *top = fb[y][x];
u8 *bot = fb[y+1][x];
if (!need_full) {
@@ -528,7 +567,7 @@ void render_frame(GB *gb) {
if (need_full) {
o += sprintf(o, "\x1b[0m\x1b[%d;1H\x1b[38;2;150;150;150m %.*s "
"skip:%d%s [f]ast [ ][ ] q:quit\x1b[K",
- SCREEN_H/2 + 1, 12, gb->cart.title,
+ H/2 + 1, 12, gb->cart.title,
hud_frameskip, hud_turbo ? " TURBO" : "");
}