diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.c | 5 | ||||
| -rw-r--r-- | src/render.c | 45 | ||||
| -rw-r--r-- | src/render.h | 1 |
3 files changed, 48 insertions, 3 deletions
@@ -76,6 +76,8 @@ static void print_usage(FILE *out, const char *prog) { " --sixel [scale] sixel graphics output; scale = pixel zoom 1-6 (def 2)\n" " --chrome draw a Game Boy body around the LCD (sixel display)\n" " --palette NAME recolor the LCD: dmg|green (pea green), pocket|gray\n" +" --shrink N shrink the half-block display N x (1-4); capture and\n" +" recording stay full-res\n" " --green alias for --palette dmg\n" " --frameskip N draw 1 of every (N+1) frames\n" "\n" @@ -172,6 +174,9 @@ int main(int argc, char **argv) { } else if (!strcmp(a, "--sixel")) { sixel = true; if (has_val) sixel_scale = atoi(argv[++i]); + } else if (!strcmp(a, "--shrink")) { + if (!has_val) { fprintf(stderr, "%s: --shrink needs a value\n", prog); return 1; } + render_set_shrink(atoi(argv[++i])); } else if (!strcmp(a, "--chrome")) { chrome = true; } else if (!strcmp(a, "--palette")) { 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" : ""); } diff --git a/src/render.h b/src/render.h index 1be1290..fed4ec8 100644 --- a/src/render.h +++ b/src/render.h @@ -11,6 +11,7 @@ void render_set_hud(int frameskip, bool turbo); // update HUD readout // Switch terminal output to sixel graphics (scale = integer pixel zoom, >=1). // Pass on=false to use the default Unicode half-block renderer. void render_set_sixel(bool on, int scale); +void render_set_shrink(int n); // half-block display downscale (1-4, def 1) // Draw a Game Boy body/frame around the LCD (sixel output only); buttons on the // drawn shell light up while pressed. No effect unless sixel mode is enabled. void render_set_chrome(bool on); |
