From 600a2f7a6e7144f23569d5e86b5fea64cbcb6691 Mon Sep 17 00:00:00 2001 From: Sadeep Madurange Date: Sun, 7 Aug 2022 12:49:43 +0800 Subject: Support for wide char, 24-bit RGB, ghosting effects. --- src/main.c | 313 ++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 184 insertions(+), 129 deletions(-) (limited to 'src/main.c') diff --git a/src/main.c b/src/main.c index 338cc3a..a7ecb51 100644 --- a/src/main.c +++ b/src/main.c @@ -11,89 +11,159 @@ #include #include -#define ANSI_COL_DROP "\x1b[97m" +#define UNICODE_MIN 0x0021 +#define UNICODE_MAX 0x007E + +#define RAIN_RATE 60 +#define RAIN_DENSITY 0.6 + +#define COLOR_BG_RED 0 +#define COLOR_BG_GRN 0 +#define COLOR_BG_BLU 0 +#define COLOR_HD_RED 255 +#define COLOR_HD_GRN 255 +#define COLOR_HD_BLU 255 +#define COLOR_TL_RED 40 +#define COLOR_TL_GRN 254 +#define COLOR_TL_BLU 20 + #define ANSI_CUR_HIDE "\e[?25l" #define ANSI_CUR_SHOW "\e[?25h" #define ANSI_CUR_RESET "\x1b[H" -#define ANSI_SCRN_CLEAR "\x1b[2J" +#define ANSI_FONT_BOLD "\x1b[1m" #define ANSI_FONT_RESET "\x1b[0m" +#define ANSI_SCRN_CLEAR "\x1b[2J" + +enum { red, green, blue }; + +typedef union color_tag { + uint32_t rgb; + unsigned char color[4]; +} color; typedef struct matrix_tag { - int rows; - int cols; + size_t rows; + size_t cols; + size_t *col; + size_t *row; + char *shade; wchar_t *code; + color *rgb; } matrix; -static int mat_index(const matrix *mat, int row, int col) { +static size_t mat_idx(const matrix *mat, size_t row, size_t col) { return mat->cols * row + col; } -static int mat_init(matrix *mat, struct winsize *ws) { - int i, j; +static void mat_put_code(matrix *mat, size_t row, size_t col) { + mat->code[mat_idx(mat, row, col)] = + rand() % (UNICODE_MAX - UNICODE_MIN) + UNICODE_MIN; +} - static wchar_t code[] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', - 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}; +static void shuffle(size_t *a, size_t n) { + size_t i, j; - static int codelen = sizeof(code) / sizeof(code[0]); + for (i = n - 1; i > 0; i--) { + j = rand() % (i + 1); + a[j] = a[i] ^ a[j]; + a[i] = a[i] ^ a[j]; + a[j] = a[i] ^ a[j]; + } +} + +static int mat_init(matrix *mat, const struct winsize *ws) { + size_t i; - mat->rows = ws->ws_row + 1; mat->cols = ws->ws_col; + mat->rows = ws->ws_row + 1; + mat->code = realloc(mat->code, sizeof mat->code[0] * mat->rows * mat->cols); - if (mat->code) { - for (i = 0; i < mat->rows; i++) { - for (j = 0; j < mat->cols; j++) - mat->code[mat_index(mat, i, j)] = code[rand() % codelen]; - } - return 1; + if (!mat->code) + return 0; + + mat->rgb = realloc(mat->rgb, sizeof mat->rgb[0] * mat->rows * mat->cols); + if (!mat->rgb) { + free(mat->code); + return 0; } - return 0; -} -typedef struct table_tag { - int len; // number of columns - int *cols; // column indices - int *rows; // row indices ((rows[i], cols[i]) points to a cell in the matrix) - int *attr; // cell attributes -} table; + mat->shade = realloc(mat->shade, sizeof mat->shade[0] * mat->cols); + if (!mat->shade) { + free(mat->code); + free(mat->rgb); + return 0; + } -static void shuffle(int *a, int n) { - int i, j, tmp; + mat->col = realloc(mat->col, sizeof mat->col[0] * mat->cols); + if (!mat->col) { + free(mat->code); + free(mat->rgb); + free(mat->shade); + return 0; + } - for (i = n - 1; i > 0; i--) { - j = rand() % (i + 1); - tmp = a[j]; - a[j] = a[i]; - a[i] = tmp; + mat->row = realloc(mat->row, sizeof mat->row[0] * mat->cols); + if (!mat->row) { + free(mat->code); + free(mat->rgb); + free(mat->col); + free(mat->shade); + return 0; + } + + for (i = 0; i < mat->cols; i++) { + mat->row[i] = 0; + mat->col[i] = i; + mat->shade[i] = 0; } + + shuffle(mat->col, mat->cols); + return 1; } -static int tab_init(table *tab, const matrix *mat) { - size_t i; +static void mat_reset_head(matrix *mat, size_t row, size_t col) { + unsigned char *sc, *tc; - tab->len = mat->cols; - tab->cols = realloc(tab->cols, sizeof tab->cols[0] * tab->len); - tab->rows = realloc(tab->rows, sizeof tab->rows[0] * tab->len); - tab->attr = realloc(tab->attr, sizeof tab->attr[0] * tab->len); + sc = mat->rgb[mat_idx(mat, 0, col)].color; + tc = mat->rgb[mat_idx(mat, row, col)].color; + tc[red] = sc[red]; + tc[green] = sc[green]; + tc[blue] = sc[blue]; +} - if (tab->cols && tab->rows && tab->attr) { - for (i = 0; i < mat->cols; i++) { - tab->rows[i] = 0; - tab->cols[i] = i; - tab->attr[i] = 0; - } - shuffle(tab->cols, tab->len); - return 1; - } - return 0; +static void mat_set_tail(matrix *mat, size_t row, size_t col) { + unsigned char *color; + + color = mat->rgb[mat_idx(mat, row, col)].color; + color[red] = COLOR_TL_RED; + color[green] = COLOR_TL_GRN; + color[blue] = COLOR_TL_BLU; +} + +static void mat_set_head(matrix *mat, size_t row, size_t col) { + unsigned char *color; + + color = mat->rgb[mat_idx(mat, row, col)].color; + color[red] = COLOR_HD_RED; + color[green] = COLOR_HD_GRN; + color[blue] = COLOR_HD_BLU; } -static void tab_free(table *tab) { - free(tab->cols); - free(tab->rows); - free(tab->attr); +static void mat_shade(matrix *mat, size_t row, size_t col) { + unsigned char *color; + + color = mat->rgb[mat_idx(mat, row, col)].color; + color[red] = color[red] - (color[red] - COLOR_BG_RED) / 2; + color[green] = color[green] - (color[green] - COLOR_BG_GRN) / 2; + color[blue] = color[blue] - (color[blue] - COLOR_BG_BLU) / 2; +} + +static void mat_free(matrix *mat) { + free(mat->code); + free(mat->col); + free(mat->row); + free(mat->rgb); + free(mat->shade); } static int term_init() { @@ -102,6 +172,8 @@ static int term_init() { if (tcgetattr(STDIN_FILENO, &ta) == 0) { ta.c_lflag &= ~ECHO; if (tcsetattr(STDIN_FILENO, TCSANOW, &ta) == 0) { + wprintf(L"\x1b[48;2;%d;%d;%dm", COLOR_BG_RED, COLOR_BG_GRN, COLOR_BG_BLU); + wprintf(L"%s", ANSI_FONT_BOLD); wprintf(L"%s", ANSI_CUR_HIDE); wprintf(L"%s", ANSI_CUR_RESET); wprintf(L"%s", ANSI_SCRN_CLEAR); @@ -128,45 +200,17 @@ static void term_reset() { setvbuf(stdout, 0, _IOLBF, 0); } -static void term_size(struct winsize *ws) { +static void term_size(const struct winsize *ws) { ioctl(STDOUT_FILENO, TIOCGWINSZ, ws); } -static void term_clear_cell(int row, int col) { - wprintf(L"\x1b[%d;%dH ", row, col); -} - -static void term_reset_cell(const matrix *mat, int row, int col) { - wprintf(L"\x1b[%d;%dH\x1b[39m%lc", row, col, - mat->code[mat_index(mat, row, col)]); -} - -static void term_print(const matrix *mat, int row, int col) { - wprintf(L"\x1b[%d;%dH%s%lc", row, col, ANSI_COL_DROP, - mat->code[mat_index(mat, row, col)]); -} +static void term_print(const matrix *mat, size_t row, size_t col) { + size_t idx; -static void term_glitch(int row, int col) { - static wchar_t code[] = { - 0x0413, // Г - 0x0418, // И - 0x042F, // Я - 0x2200, // ∀ - 0x04D9, // ә - 0x0500, // Ԁ - 0x2203, // ∃ - 0x2132, // Ⅎ - 0x0245, // Ʌ - 0x037B, // ͻ - 0x03FD, // Ͻ - 0x041F, // П - 0x04D4, // Ӕ - 0x0424, // Ф - }; - - static int codelen = sizeof(code) / sizeof(code[0]); - - wprintf(L"\x1b[%d;%dH\x1b[39m%lc", row, col, code[rand() % codelen]); + idx = mat_idx(mat, row, col); + wprintf(L"\x1b[%d;%dH\x1b[38;2;%d;%d;%dm%lc", row, col, + mat->rgb[idx].color[red], mat->rgb[idx].color[green], + mat->rgb[idx].color[blue], mat->code[idx]); } static volatile int run; @@ -183,11 +227,10 @@ static void handle_signal(int sa) { int main(int argc, char *argv[]) { matrix mat; - table tab; struct winsize ws; struct timespec ts; struct sigaction sa; - int i, cols, blank, delay, tmp; + size_t i, j, len, maxlen; setlocale(LC_CTYPE, ""); @@ -208,54 +251,66 @@ int main(int argc, char *argv[]) { return 1; } - tab = (table){0}; - if (!tab_init(&tab, &mat)) { - term_reset(); - return 1; - } - - delay = 75; - ts.tv_sec = delay / 1000; - ts.tv_nsec = (delay % 1000) * 1000000; + ts.tv_sec = RAIN_RATE / 1000; + ts.tv_nsec = (RAIN_RATE % 1000) * 1000000; - run = cols = 1; - blank = tab.cols[tab.len - 1]; + run = 1, len = 1; + maxlen = mat.cols * RAIN_DENSITY; while (run) { - for (i = 0; run && i < cols; i++) { - if (tab.rows[i] == mat.rows) { - tab.rows[i] = 0; - term_reset_cell(&mat, mat.rows - 1, tab.cols[i]); + for (i = 0; run && i < len; i++) { + if (mat.row[i] == mat.rows) { + mat_reset_head(&mat, mat.row[i] - 1, mat.col[i]); + term_print(&mat, mat.rows - 1, mat.col[i]); + mat.row[i] = 0; } - if (tab.attr[i] == 0) { - // hard-coding to 5 (row[i] - rand() % rows[i] glitches on empty rows) - if (tab.rows[i] > 5 && rand() % 6 == 0) - term_glitch(tab.rows[i] - 5, tab.cols[i]); - if (tab.rows[i] > 0) - term_reset_cell(&mat, tab.rows[i] - 1, tab.cols[i]); - term_print(&mat, tab.rows[i], tab.cols[i]); - if (tab.rows[i] == mat.rows - 1) - tab.attr[i] = 1; - tab.rows[i]++; + if (mat.shade[i] == 0) { + if (mat.row[i] > 0) { + mat_set_tail(&mat, mat.row[i] - 1, mat.col[i]); + term_print(&mat, mat.row[i] - 1, mat.col[i]); + } + mat_set_head(&mat, mat.row[i], mat.col[i]); + mat_put_code(&mat, mat.row[i], mat.col[i]); + term_print(&mat, mat.row[i], mat.col[i]); + if (mat.row[i] > 0 && rand() % 6 == 0) { + j = rand() % mat.row[i]; + if (mat.code[mat_idx(&mat, j, mat.col[i])] != ' ') { + mat_put_code(&mat, j, mat.col[i]); + term_print(&mat, j, mat.col[i]); + } + } + if (mat.row[i] == mat.rows - 1) + mat.shade[i] = 1; + mat.row[i]++; + } else if (mat.shade[i] == 1 || mat.shade[i] == 2) { + mat_shade(&mat, mat.row[i], mat.col[i]); + term_print(&mat, mat.row[i], mat.col[i]); + if (mat.row[i] == mat.rows - 1) + mat.shade[i]++; + mat.row[i]++; } else { - term_clear_cell(tab.rows[i], tab.cols[i]); - if (tab.rows[i] == mat.rows - 1) { - tab.rows[i] = 0; - tab.attr[i] = 0; - tmp = blank; - blank = tab.cols[i]; - tab.cols[i] = tmp; + mat.code[mat_idx(&mat, mat.row[i], mat.col[i])] = ' '; + term_print(&mat, mat.row[i], mat.col[i]); + if (mat.row[i] == mat.rows - 1) { + mat.row[i] = 0; + mat.shade[i] = 0; + j = rand() % (mat.cols - maxlen) + maxlen; + mat.col[i] = mat.col[i] ^ mat.col[j]; + mat.col[j] = mat.col[i] ^ mat.col[j]; + mat.col[i] = mat.col[i] ^ mat.col[j]; } else - tab.rows[i]++; + mat.row[i]++; } } - if (cols < tab.len * 0.6) - tab.rows[cols++] = 0; + if (len < maxlen && + mat.row[len - 1] >= rand() % (int)(mat.rows * 0.25)) { + mat.row[len] = 0; + mat.shade[len++] = 0; + } fflush(stdout); nanosleep(&ts, &ts); } term_reset(); - tab_free(&tab); - free(mat.code); + mat_free(&mat); return 0; } -- cgit v1.2.3