aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/main.c5
-rw-r--r--src/render.c45
-rw-r--r--src/render.h1
3 files changed, 48 insertions, 3 deletions
diff --git a/src/main.c b/src/main.c
index 0dec4df..811e0a4 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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);