From bc82d4ee28b0ca0e86b096069b7a61cbb082a93b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 23 Jun 2020 21:07:12 +0200 Subject: [PATCH] sixel: wip: split up image being overwritten, rather than erasing it Instead of completely erasing a sixel image when it is being "overwritten" (text is printed somewhere within the image, or another sixel image is emitted within the first image), split it up into up to four pieces: 'above', 'below', 'to-the-left' and 'to-the-right'. This is currently very un-optimized, but seems to produce correct results. --- sixel.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++- sixel.h | 1 + terminal.c | 3 +- 3 files changed, 142 insertions(+), 2 deletions(-) diff --git a/sixel.c b/sixel.c index 2186795c..23ded128 100644 --- a/sixel.c +++ b/sixel.c @@ -154,10 +154,143 @@ sixel_delete_at_cursor(struct terminal *term) term, term->grid->cursor.point.row, term->grid->cursor.point.col); } +static void +sixel_split(struct terminal *term, struct sixel *six, int row, int col) +{ + assert(row >= six->pos.row); + assert(row < six->pos.row + six->rows); + assert(col >= six->pos.col); + assert(col < six->pos.col + six->cols); + + int rel_row = row - six->pos.row; + int rel_col = col - six->pos.col; + + if (rel_row > 0) { + struct sixel above = { + .width = six->width, + .height = rel_row * term->cell_height, + .rows = rel_row, + .cols = six->cols, + .pos = six->pos, + }; + above.data = malloc(above.width * above.height * sizeof(uint32_t)); + memcpy(above.data, six->data, above.width * above.height * sizeof(uint32_t)); + + above.pix = pixman_image_create_bits_no_clear( + PIXMAN_a8r8g8b8, + above.width, above.height, + above.data, above.width * sizeof(uint32_t)); + + tll_push_back(term->grid->sixel_images, above); + } + + if (rel_row + 1 < six->rows) { + struct sixel below = { + .width = six->width, + .height = six->height - (rel_row + 1) * term->cell_height, + .rows = six->rows - (rel_row + 1), + .cols = six->cols, + .pos = (struct coord){ + six->pos.col, + (six->pos.row + rel_row + 1) & (term->grid->num_rows - 1)}, + }; + below.data = malloc(below.width * below.height * sizeof(uint32_t)); + memcpy( + below.data, + &((const uint32_t *)six->data)[(rel_row + 1) * term->cell_height * six->width], + below.width * below.height * sizeof(uint32_t)); + below.pix = pixman_image_create_bits_no_clear( + PIXMAN_a8r8g8b8, + below.width, below.height, + below.data, below.width * sizeof(uint32_t)); + + tll_push_back(term->grid->sixel_images, below); + } + + if (rel_col > 0) { + struct sixel left = { + .width = rel_col * term->cell_width, + .height = min(term->cell_height, six->height - rel_row * term->cell_height), + .rows = 1, + .cols = rel_col, + .pos = (struct coord){six->pos.col, + (six->pos.row + rel_row) & (term->grid->num_rows - 1)}, + }; + left.data = malloc(left.width * left.height * sizeof(uint32_t)); + for (size_t i = 0; i < term->cell_height; i++) + memcpy( + &((uint32_t *)left.data)[i * left.width], + &((const uint32_t *)six->data)[(rel_row * term->cell_height + i) * six->width], + left.width * sizeof(uint32_t)); + left.pix = pixman_image_create_bits_no_clear( + PIXMAN_a8r8g8b8, + left.width, left.height, + left.data, left.width * sizeof(uint32_t)); + tll_push_back(term->grid->sixel_images, left); + + } + + if (rel_col + 1 < six->cols) { + struct sixel right = { + .width = six->width - (rel_col + 1) * term->cell_width, + .height = min(term->cell_height, six->height - rel_row * term->cell_height), + .rows = 1, + .cols = six->cols - (rel_col + 1), + .pos = (struct coord){six->pos.col + rel_col + 1, + (six->pos.row + rel_row) & (term->grid->num_rows - 1)}, + }; + right.data = malloc(right.width * right.height * sizeof(uint32_t)); + for (size_t i = 0; i < term->cell_height; i++) + memcpy( + &((uint32_t *)right.data)[i * right.width], + &((const uint32_t *)six->data)[(rel_row * term->cell_height + i) * six->width + (rel_col + 1) * term->cell_width], + right.width * sizeof(uint32_t)); + right.pix = pixman_image_create_bits_no_clear( + PIXMAN_a8r8g8b8, + right.width, right.height, + right.data, right.width * sizeof(uint32_t)); + tll_push_back(term->grid->sixel_images, right); + } +} + +void +sixel_split_at_point(struct terminal *term, int _row, int col) +{ + if (likely(tll_length(term->grid->sixel_images) == 0)) + return; + + const int row = (term->grid->offset + _row) & (term->grid->num_rows - 1); + + tll_foreach(term->grid->sixel_images, it) { + struct sixel *six = &it->item; + + const int six_start = six->pos.row; + const int six_end = six_start + six->rows - 1; + + if (row >= six_start && row <= six_end) { + const int col_start = six->pos.col; + const int col_end = six->pos.col + six->cols; + + if (col >= col_start && col < col_end) { + //sixel_erase(term, six); + sixel_split(term, six, row, col); + sixel_erase(term, six); + tll_remove(term->grid->sixel_images, it); + } + } + } +} + +void +sixel_split_at_cursor(struct terminal *term) +{ + sixel_split_at_point(term, term->grid->cursor.point.row, term->grid->cursor.point.col); +} + void sixel_unhook(struct terminal *term) { - sixel_delete_at_cursor(term); + //sixel_delete_at_cursor(term); struct sixel image = { .data = term->sixel.image.data, @@ -170,6 +303,11 @@ sixel_unhook(struct terminal *term) (term->grid->offset + term->grid->cursor.point.row) & (term->grid->num_rows - 1)}, }; + for (int row = 0; row < image.rows; row++) { + for (int col = 0; col < image.cols; col++) + sixel_split_at_point(term, term->grid->cursor.point.row + row, term->grid->cursor.point.col + col); + } + LOG_DBG("generating %dx%d pixman image", image.width, image.height); image.pix = pixman_image_create_bits_no_clear( diff --git a/sixel.h b/sixel.h index a10f14f2..2f3b0d86 100644 --- a/sixel.h +++ b/sixel.h @@ -15,6 +15,7 @@ void sixel_destroy(struct sixel *sixel); void sixel_delete_in_range(struct terminal *term, int start, int end); void sixel_delete_at_row(struct terminal *term, int _row); void sixel_delete_at_cursor(struct terminal *term); +void sixel_split_at_cursor(struct terminal *term); void sixel_colors_report_current(struct terminal *term); void sixel_colors_reset(struct terminal *term); diff --git a/terminal.c b/terminal.c index dd0c8c81..01fd50be 100644 --- a/terminal.c +++ b/terminal.c @@ -2381,7 +2381,8 @@ term_print(struct terminal *term, wchar_t wc, int width) print_linewrap(term); print_insert(term, width); - sixel_delete_at_cursor(term); + //sixel_delete_at_cursor(term); + sixel_split_at_cursor(term); /* *Must* get current cell *after* linewrap+insert */ struct row *row = term->grid->cur_row;