diff options
| author | WormHeamer | 2025-11-04 19:13:16 -0500 |
|---|---|---|
| committer | WormHeamer | 2025-11-04 19:13:16 -0500 |
| commit | 02e1a8abb7d43c8cb6e7fbf473c8ddc7f9eee37a (patch) | |
| tree | ee5ce1374c4e796f665278e283ff7229af3145f8 /main.c | |
| parent | e379662045c4dc6e149b84ab9e43ceecb427451e (diff) | |
stuff
Diffstat (limited to 'main.c')
| -rw-r--r-- | main.c | 188 |
1 files changed, 119 insertions, 69 deletions
@@ -96,6 +96,9 @@ VuiWindow vui_win = { .back = &vui_win.buf2, }; +#define LINES (vui_win.height) +#define COLS (vui_win.width) + #define BCHR(b,x,y) ((b)->chr[(x) + (y) * (b)->width]) #define BATTR(b,x,y) ((b)->attr[(x) + (y) * (b)->width]) #define CHR(x,y) BCHR(vui_win.front, x, y) @@ -159,14 +162,14 @@ static void resize_buf(VuiBuffer *buf, unsigned nw, unsigned nh) { static void vui_resize(unsigned nw, unsigned nh) { resize_buf(&vui_win.buf1, nw, nh); resize_buf(&vui_win.buf2, nw, nh); - vui_win.width = nw; + vui_win.width = nw; vui_win.height = nh; } static void vui_adjust(void) { unsigned w, h; vui_getwinsz(&w, &h); - if (w != vui_win.width || h != vui_win.height) { + if (w != COLS || h != LINES) { vui_resize(w, h); vui_win.redraw_all = 1; } @@ -212,40 +215,61 @@ static void free_buf(VuiBuffer *buf) { buf->height = 0; } +static inline int bchr_equiv(VuiBuffer *back, VuiBuffer *front, int x, int y) { + return BCHR(back,x,y) == BCHR(front,x,y) + && (BATTR(back,x,y) == BATTR(front,x,y) + /* || BCHR(back,x,y) == ' ' */); +} + +static char *vui_out = NULL; +static size_t vui_outn = 0; +static size_t vui_out_cap = 0; + void vui_fini(void) { tcsetattr(STDIN_FILENO, TCSANOW, &vui_init_stdin_tos); tcsetattr(STDOUT_FILENO, TCSANOW, &vui_init_stdout_tos); vui_curs_vis(1); free_buf(&vui_win.buf1); free_buf(&vui_win.buf2); + free(vui_out); + vui_out = NULL; + vui_out_cap = 0; printf(CSI "H" CSI "2J" CSI "0m"); } -static inline int bchr_equiv(VuiBuffer *back, VuiBuffer *front, int x, int y) { - return BCHR(back,x,y) == BCHR(front,x,y) - && (BATTR(back,x,y) == BATTR(front,x,y) - /* || BCHR(back,x,y) == ' ' */); +void vui_out_fit(size_t n) { + size_t c = stdc_bit_ceil(n); + if (c > vui_out_cap) { + char *p = realloc(vui_out, c); + if (!p) { + vui_fini(); + fprintf(stderr, "failed to reallocate vui output buffer\n"); + exit(1); + } + vui_out = p; + vui_out_cap = c; + } } -static char vui_out[65536]; -static unsigned short vui_outn = 0; - void vui_outf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); int n = vsnprintf(NULL, 0, fmt, ap); va_end(ap); va_start(ap, fmt); + vui_out_fit(vui_outn + n); vsprintf(&vui_out[vui_outn], fmt, ap); vui_outn += n; va_end(ap); } static inline void vui_outc(char c) { + vui_out_fit(vui_outn + 1); vui_out[vui_outn++] = c; } static inline void vui_outsn(const char *s, unsigned n) { + vui_out_fit(vui_outn + n); memcpy(&vui_out[vui_outn], s, n); vui_outn += n; } @@ -257,7 +281,7 @@ static inline void vui_outs(const char *s) { static inline void vui_out_flush(void) { fwrite(vui_out, 1, vui_outn, stdout); fflush(stdout); -#if 1 +#if 0 static unsigned out_frame = 0; FILE *f = fopen("out_log.txt", "a"); assert(f); @@ -287,9 +311,9 @@ static inline void curs_move(int src_x, int src_y, int dst_x, int dst_y) { } } else if (src_y != dst_y) { if (dst_y == src_y - 1) { - vui_outs("\x1bM"); + vui_outs("\x1b" "M"); } else if (dst_y == src_y + 1) { - vui_outs("\x1bD"); + vui_outs("\x1b" "D"); } if (dst_y > 0) { vui_outf(CSI "%dd", dst_y + 1); } else { @@ -302,12 +326,17 @@ static void attr_chg(VuiAttr *ptr, VuiAttr to) { VuiAttr from = *ptr; if (from == to) return; - int chg_attr = (ATTR_A(from) != ATTR_A(to)); - chg_attr = 0; + int attr_chg_count = stdc_count_ones(ATTR_A(from) ^ ATTR_A(to)); + int chg_attr = !!attr_chg_count; + if (!chg_attr) goto chg_colors; + + /* deduct color changes */ + attr_chg_count -= (ATTR_FG(to) == ATTR_FG(from)) && (ATTR_FG(to) != ATTR_DEFAULT); + attr_chg_count -= (ATTR_BG(to) == ATTR_BG(from)) && (ATTR_BG(to) != ATTR_DEFAULT); - /* popcnt(f_attr ^ t_attr) to detect nr. of changes */ + int should_rebuild = (attr_chg_count > 1) || to == ATTR_DEFAULT; - if (chg_attr) { + if (should_rebuild) { vui_outs(CSI "0"); if (to & A_BOLD) vui_outs(";1"); if (to & A_DIM) vui_outs(";2"); @@ -318,8 +347,29 @@ static void attr_chg(VuiAttr *ptr, VuiAttr to) { from = ATTR_DEFAULT; assert(ATTR_FG(from) == FG_WHITE); assert(ATTR_BG(from) == BG_BLACK); + } else { + vui_outs(CSI); + if ((to ^ from) & A_BOLD) { + if (to & A_BOLD) vui_outs(";1"); + else { + vui_outs(";22"); + from &= (~A_BOLD & ~A_DIM); + } + } + if ((to ^ from) & A_DIM) { + if (to & A_BOLD) vui_outs(";2"); + else { + vui_outs(";22"); + from &= (~A_BOLD & ~A_DIM); + } + } + if ((to ^ from) & A_ITALIC) vui_outs((to & A_ITALIC) ? ";3" : ";23"); + if ((to ^ from) & A_UNDERSCORE) vui_outs((to & A_UNDERSCORE) ? ";4" : ";24"); + if ((to ^ from) & A_BLINK) vui_outs((to & A_BLINK) ? ";5" : ";25"); + if ((to ^ from) & A_REVERSE) vui_outs((to & A_REVERSE) ? ";7" : ";27"); } +chg_colors: int f_fg = ATTR_FG(from); int f_bg = ATTR_BG(from); int t_fg = ATTR_FG(to); @@ -352,6 +402,7 @@ static void attr_chg(VuiAttr *ptr, VuiAttr to) { unsigned vui_changes = 0; unsigned vui_max_change = 0; unsigned vui_out_chars = 0; +int scrolled_x = 0, scrolled_y = 0; void vui_scroll_buf(VuiBuffer *b, int dx, int dy); @@ -362,15 +413,20 @@ void vui_blit(void) { vui_outf(CSI "H" CSI "0m"); VuiAttr attr_last = ATTR_DEFAULT; + scrolled_x = vui_win.scroll_x; + scrolled_y = vui_win.scroll_y; + if (vui_win.redraw_all) { - vui_changes = vui_win.width * vui_win.height; - for (unsigned y = 0; y < vui_win.height; y++) { - for (unsigned x = 0; x < vui_win.width; x++) { + vui_changes = COLS * LINES; + for (unsigned y = 0; y < LINES; y++) { + for (unsigned x = 0; x < COLS; x++) { attr_chg(&attr_last, ATTR(x, y)); vui_outc(CHR(x, y)); } } vui_win.redraw_all = 0; + vui_win.scroll_x = 0; + vui_win.scroll_y = 0; goto copy_buf; } @@ -390,24 +446,25 @@ void vui_blit(void) { */ if (vui_win.scroll_x || vui_win.scroll_y) { - if (abs(vui_win.scroll_x) >= vui_win.width || abs(vui_win.scroll_y) > vui_win.height) { + if (abs(vui_win.scroll_x) >= COLS || abs(vui_win.scroll_y) > LINES) { vui_outs(CSI "2J"); goto scrolled; } if (vui_win.scroll_x < 0) { - for (unsigned y = 0; y < vui_win.height; y++) { + for (unsigned y = 0; y < LINES; y++) { curs_move(cur_x, cur_y, 0, y); vui_outf(CSI "%dP", -vui_win.scroll_x); cur_y = y; } } else if (vui_win.scroll_x > 0) { - for (unsigned y = 0; y < vui_win.height; y++) { + for (unsigned y = 0; y < LINES; y++) { curs_move(cur_x, cur_y, 0, y); vui_outf(CSI "%d@", vui_win.scroll_x); cur_y = y; } } + if (vui_win.scroll_y < 0) { if (vui_win.scroll_y == -1) vui_outs(CSI "S"); else vui_outf(CSI "%dS", -vui_win.scroll_y); @@ -422,14 +479,17 @@ scrolled: vui_win.scroll_y = 0; } - for (unsigned y = 0; y < vui_win.height; y++) { + vui_win.scroll_x = 0; + vui_win.scroll_y = 0; + + for (unsigned y = 0; y < LINES; y++) { unsigned x = 0; - while (x < vui_win.width) { - while (x < vui_win.width && bchr_equiv(back, front, x, y)) x++; - if (x >= vui_win.width) break; + while (x < COLS) { + while (x < COLS && bchr_equiv(back, front, x, y)) x++; + if (x >= COLS) break; unsigned x0 = x; VuiAttr a = ATTR(x0, y); - while (x < vui_win.width && !bchr_equiv(back, front, x, y) && ATTR(x, y) == a) x++; + while (x < COLS && !bchr_equiv(back, front, x, y) && ATTR(x, y) == a) x++; if (x0 != x) { vui_changes++; curs_move(cur_x, cur_y, x0, y); @@ -452,7 +512,7 @@ copy_buf: } void vui_chra(int x, int y, char c, VuiAttr a) { - if (x >= 0 && x < (int)vui_win.width && y >= 0 && y < (int)vui_win.height) { + if (x >= 0 && x < (int)COLS && y >= 0 && y < (int)LINES) { CHR(x, y) = c; ATTR(x, y) = a; } @@ -463,18 +523,17 @@ void vui_chr(int x, int y, char c) { } int vui_avprintf(int x, int y, VuiAttr a, const char *fmt, va_list ap) { - //return 0; va_list ap2; va_copy(ap2, ap); int n = vsnprintf(NULL, 0, fmt, ap); - if (x < 0) x = vui_win.width + x - (n - 1); - if (y < 0) y = vui_win.height + y; - if (x >= vui_win.width || y >= vui_win.height) return n; + if (x < 0) x = COLS + x - (n - 1); + if (y < 0) y = LINES + y; + if (x >= COLS || y >= LINES) return n; if (n > 0) { char buf[n + 1]; vsnprintf(buf, n + 1, fmt, ap2); - memcpy(&CHR(x,y), buf, n < vui_win.width - x ? n : vui_win.width - x); - for (unsigned x1 = x; x1 < vui_win.width && x1 < x + n; x1++) { + memcpy(&CHR(x,y), buf, n < COLS - x ? n : COLS - x); + for (unsigned x1 = x; x1 < COLS && x1 < x + n; x1++) { ATTR(x1, y) = a; } } @@ -524,22 +583,14 @@ void vui_scroll_buf(VuiBuffer *b, int dx, int dy) { } if (dx > 0) { for (unsigned i = 0; i < b->height; i++) { - memmove(b->chr + (i * b->width) + dx, b->chr + (i * b->width), sizeof(*b->chr) * (b->width - dx)); - } - for (unsigned i = 0; i < b->height; i++) { + memmove(b->chr + (i * b->width) + dx, b->chr + (i * b->width), sizeof(*b->chr) * (b->width - dx)); memmove(b->attr + (i * b->width) + dx, b->attr + (i * b->width), sizeof(*b->attr) * (b->width - dx)); - } - for (unsigned i = 0; i < b->height; i++) { vui_clrspan(b, 0, dx, i); } } else if (dx < 0) { for (unsigned i = 0; i < b->height; i++) { memmove(b->chr + (i * b->width), b->chr + (i * b->width) - dx, sizeof(*b->chr) * (b->width + dx)); - } - for (unsigned i = 0; i < b->height; i++) { memmove(b->attr + (i * b->width), b->attr + (i * b->width) - dx, sizeof(*b->attr) * (b->width + dx)); - } - for (unsigned i = 0; i < b->height; i++) { vui_clrspan(b, b->width + dx - 1, b->width, i); } @@ -557,7 +608,7 @@ int dx = 0, dy = 0; int camx = 0, camy = 0; int C = '*'; unsigned frame = 0; -int half_y = 1; +int half_y = 0; void draw(void *ctx) { (void)ctx; @@ -568,9 +619,9 @@ void draw(void *ctx) { vui_chra(x, y-1, C, ((x + y) & 0xf) | BG_BLUE | A_UNDERSCORE); vui_chra(x, y+1, C, ((x + y) & 0xf) | BG_BLUE | A_UNDERSCORE); - vui_printf(-1, -1, "(%u, %u)", vui_win.width, vui_win.height); - //vui_printf(0, -1, "front buffer = %p", (void*)vui_win.front); - vui_printf(-1, 0, "longest change = %3u, changes = %5u, output = %5u, chars = %5u", vui_max_change, vui_changes, vui_out_chars, vui_win.width * vui_win.height); + vui_printf(-1, -1, "(%u, %u)", COLS, LINES); + vui_printf(0, -1, "scrolled (%d, %d)", scrolled_x, scrolled_y); + vui_printf(-1, 0, "longest change = %3u, changes = %5u, output = %5u, chars = %5u", vui_max_change, vui_changes, vui_out_chars, COLS * LINES); vui_blit(); } @@ -581,18 +632,15 @@ int main(int argc, const char **argv) { for (;;) { frame++; - //camx += dx; x += dx; int ydy = dy; - if (half_y) { - ydy = (frame & 1) ? (dy / 2) : dy - (dy / 2); - } + if (half_y) ydy = (frame & 1) ? (dy / 2) : dy - (dy / 2); y += ydy; - unsigned left = 32; - unsigned right = vui_win.width - (left + 1); - unsigned top = left >> half_y; - unsigned bottom = vui_win.height - (top + 1); + int left = 32; + int right = COLS - (left + 1); + int top = left >> half_y; + int bottom = LINES - (top + 1); int lcamx = camx, lcamy = camy; if (x < left) { camx += x - left; x = left; } @@ -616,21 +664,25 @@ int main(int argc, const char **argv) { #if 1 /* weird cellular automata */ if (!paused) { - // int dx = 0, dy = 0; /* shadow on purpose */ - - for (int y = 0; y < vui_win.height; y++) { - for (int x = 0; x < vui_win.width; x++) { + int vsteps = (COLS * LINES) / 2048; + if (!vsteps) vsteps++; + vsteps = 1; + int y0 = LINES * (frame % vsteps) / vsteps; + int y1 = y0 + LINES / vsteps; + if (y1 > LINES) y1 = LINES; + for (int y = y0; y < y1; y++) { + for (int x = 0; x < COLS; x++) { if (frame & 1) { int txa = x, tya = y, txc = x, tyc = y; txa += (random() % 3) - 1; tya += (random() % 3) - 1; txc += (random() % 3) - 1; tyc += (random() % 3) - 1; - if (txa >= 0 && txa < vui_win.width && tya >= 0 && tya < vui_win.height) { + if (txa >= 0 && txa < COLS && tya >= 0 && tya < LINES) { ATTR(txa, tya) = (BATTR(vui_win.back,x,y) & ~0xf) | (ATTR(txa,tya) & 0xf); if (!(random() & 127)) ATTR(x,y) = ATTR_DEFAULT; } - if (txc >= 0 && txc < vui_win.width && tyc >= 0 && tyc < vui_win.height) { + if (txc >= 0 && txc < COLS && tyc >= 0 && tyc < LINES) { CHR(txc, tyc) = BCHR(vui_win.back, x, y); ATTR(txc, tyc) = (ATTR(txc,tyc) & ~0xf) | (BATTR(vui_win.back,x,y) & 0xf); if (!(random() & 127)) CHR(x,y) = ' '; @@ -639,10 +691,9 @@ int main(int argc, const char **argv) { } } - //vui_win.redraw_all = 1; - for (unsigned i = 0; i < isqrt(vui_win.width * vui_win.height) / 10; i++) { - int tx = random() % vui_win.width; - int ty = random() % vui_win.height; + for (unsigned i = 0; i < isqrt(COLS * LINES) / 10; i++) { + int tx = random() % COLS; + int ty = random() % LINES; VuiAttr a = ((random()&15) << 4) | (random()&15); vui_chra(tx, ty, ' ' + (random() % 0x5f), a); } @@ -650,8 +701,8 @@ int main(int argc, const char **argv) { #else vui_clear(); - for (unsigned y = 0; y < vui_win.height; y++) { - for (unsigned x = 0; x < vui_win.width; x++) { + for (unsigned y = 0; y < LINES; y++) { + for (unsigned x = 0; x < COLS; x++) { int tx = x + camx, ty = y + camy; char ch = " ',."[(tx^ty)&3]; ch = ' '; @@ -660,7 +711,6 @@ int main(int argc, const char **argv) { } } #endif - // win.redraw_all = 1; draw(NULL); clock_nanosleep(CLOCK_MONOTONIC, 0, &(struct timespec) { .tv_nsec = 15 * 1000000 }, NULL); @@ -684,6 +734,6 @@ int main(int argc, const char **argv) { } } vui_fini(); - printf(CSI "2J" CSI "H %u, %u\n", vui_win.width, vui_win.height); + printf(CSI "2J" CSI "H %u, %u\n", COLS, LINES); return 0; } |
