From 0a08e1941d43dcba7ded5b4f4492fd2d52b7f84d Mon Sep 17 00:00:00 2001 From: cancel Date: Sun, 25 Nov 2018 03:00:20 +0900 Subject: [PATCH] Add basic 'field' manipulation and simple test --- main.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 118 insertions(+), 8 deletions(-) diff --git a/main.c b/main.c index 9bb826c..8bf2dc8 100644 --- a/main.c +++ b/main.c @@ -18,7 +18,7 @@ typedef struct { U32 width; } Field; -void field_init_zero(Field* f, U32 height, U32 width) { +void field_init_zeros(Field* f, U32 height, U32 width) { size_t num_cells = height * width; f->buffer = calloc(num_cells, sizeof(Term)); f->height = height; @@ -48,6 +48,102 @@ void field_deinit(Field* f) { #endif } +void field_copy_subrect(Field* src, Field* dest, U32 src_y, U32 src_x, + U32 dest_y, U32 dest_x, U32 height, U32 width) { + size_t src_height = src->height; + size_t src_width = src->width; + size_t dest_height = dest->height; + size_t dest_width = dest->width; + if (src_height <= src_y || src_width <= src_x || dest_height <= dest_y || + dest_width <= dest_x) + return; + size_t ny_0 = src_height - src_y; + size_t ny_1 = dest_height - dest_y; + size_t ny = height; + if (ny_0 < ny) + ny = ny_0; + if (ny_1 < ny) + ny = ny_1; + if (ny == 0) + return; + size_t row_copy_0 = src_width - src_x; + size_t row_copy_1 = dest_width - dest_x; + size_t row_copy = width; + if (row_copy_0 < row_copy) + row_copy = row_copy_0; + if (row_copy_1 < row_copy) + row_copy = row_copy_1; + size_t copy_bytes = row_copy * sizeof(Term); + Term* src_p = src->buffer + src_y * src_width + src_x; + Term* dest_p = dest->buffer + dest_y * dest_width + dest_x; + size_t src_stride; + size_t dest_stride; + if (src_y >= dest_y) { + src_stride = src_width; + dest_stride = dest_width; + } else { + src_p += (ny - 1) * src_width; + dest_p += (ny - 1) * dest_width; + src_stride = -src_width; + dest_stride = -dest_width; + } + size_t iy = 0; + for (;;) { + memmove(dest_p, src_p, copy_bytes); + ++iy; + if (iy == ny) + break; + src_p += src_stride; + dest_p += dest_stride; + } +} + +void field_fill_subrect(Field* f, U32 y, U32 x, U32 height, U32 width, + Term fill_char) { + size_t f_height = f->height; + size_t f_width = f->width; + if (y >= f_height || x >= f_width) + return; + size_t rows_0 = f_height - y; + size_t rows = height; + if (rows_0 < rows) + rows = rows_0; + if (rows == 0) + return; + size_t columns_0 = f_width - x; + size_t columns = width; + if (columns_0 < columns) + columns = columns_0; + size_t fill_bytes = columns * sizeof(Term); + Term* p = f->buffer + y * f_width + x; + size_t iy = 0; + for (;;) { + memset(p, fill_char, fill_bytes); + ++iy; + if (iy == rows) + break; + p += f_width; + } +} + +void field_debug_draw(Field* f, int term_y, int term_x) { + enum { Line_buffer_count = 4096 }; + chtype line_buffer[Line_buffer_count]; + size_t f_height = f->height; + size_t f_width = f->width; + Term* f_buffer = f->buffer; + if (f_width > Line_buffer_count) + return; + for (size_t iy = 0; iy < f_height; ++iy) { + Term* row_p = f_buffer + f_width * iy; + for (size_t ix = 0; ix < f_width; ++ix) { + line_buffer[ix] = (chtype)row_p[ix]; + } + move(iy + term_y, term_x); + addchnstr(line_buffer, (int)f_width); + } +} + typedef struct { chtype* buffer; int size_y; @@ -162,10 +258,10 @@ int main() { // Don't block on calls like getch() -- have it ERR immediately if the user // hasn't typed anything. That way we can mix other timers in our code, // instead of being a slave only to terminal input. - nodelay(stdscr, TRUE); + // nodelay(stdscr, TRUE); - view_state vs; - init_view_state(&vs); + Field field; + field_init_fill(&field, 16, 16, '.'); printw("Type any character to fill it in an alternating grid, or\ntype '"); attron(A_BOLD); @@ -174,8 +270,10 @@ int main() { printw("' to quit\n"); refresh(); + char fill_char = '?'; for (;;) { int ch = getch(); + clear(); if (ch == 'q') break; // ncurses gives us ERR if there was no user input. We'll sleep for 0 @@ -190,16 +288,28 @@ int main() { // ncurses gives us the special value KEY_RESIZE if the user didn't // actually type anything, but the terminal resized. If that happens to us, // just re-use the fill character from last time. + char new_fill_char; if (ch < CHAR_MIN || ch > CHAR_MAX || ch == KEY_RESIZE) - ch = vs.fill_char; + new_fill_char = '?'; + else + new_fill_char = (char)ch; int term_height = getmaxy(stdscr); int term_width = getmaxx(stdscr); assert(term_height >= 0 && term_width >= 0); - update_view_state(&vs, term_height, term_width, (chtype)ch); - draw_view_state(&vs); + if (new_fill_char != fill_char) { + fill_char = new_fill_char; + } + field_fill_subrect(&field, 1, 1, field.height - 2, field.width - 2, + fill_char); + field_debug_draw(&field, 0, 0); + field_copy_subrect(&field, &field, 0, 0, 4, 4, 8, 8); + field_copy_subrect(&field, &field, 0, 0, 0, 0, 0, 0); + field_debug_draw(&field, field.height + 1, 0); + field_copy_subrect(&field, &field, 6, 6, 9, 9, 30, 30); + field_debug_draw(&field, 0, field.width + 1); refresh(); } - deinit_view_state(&vs); + field_deinit(&field); endwin(); return 0; }