From de3c8b89bbc4e728df93552267099106966d3651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Janouch?= Date: Thu, 23 Oct 2014 23:23:09 +0200 Subject: Back the canvas with a real bitmap The first step towards making this actually useful. Also the canvas can be now scrolled with the middle mouse button. --- autistdraw.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 170 insertions(+), 11 deletions(-) diff --git a/autistdraw.c b/autistdraw.c index effd220..90b5ed8 100644 --- a/autistdraw.c +++ b/autistdraw.c @@ -17,6 +17,9 @@ #include "config.h" #define PALETTE_WIDTH 9 ///< Width of the palette +#define TOP_BAR_CUTOFF 3 ///< Height of the top bar + +#define BITMAP_BLOCK_SIZE 50 ///< Step for extending bitmap size typedef struct app_context app_context_t; struct app_context @@ -25,6 +28,23 @@ struct app_context chtype palette[2 * 9]; ///< Attribute palette + uint8_t *bitmap; ///< Canvas data for drawing + int bitmap_x; ///< X coord. of left top bitmap corner + int bitmap_y; ///< Y coord. of left top bitmap corner + size_t bitmap_w; ///< Canvas data width + size_t bitmap_h; ///< Canvas data height + + int center_x; ///< X coordinate at center + int center_y; ///< Y coordinate at center + + // These two are computed from `center_x' and `center_y': + + int corner_x; ///< X coordinate of LT screen corner + int corner_y; ///< Y coordinate of LT screen corner + + int move_saved_x; ///< Saved X coord. for moving + int move_saved_y; ///< Saved Y coord. for moving + uint8_t current_color_left; ///< Left mouse button color uint8_t current_color_right; ///< Right mouse button color }; @@ -82,6 +102,13 @@ init_palette (app_context_t *app) app->current_color_left = app->current_color_right = 9; } +static void +update_canvas_for_screen (app_context_t *app) +{ + app->corner_x = app->center_x - COLS / 2; + app->corner_y = app->center_y - (LINES - TOP_BAR_CUTOFF) / 2; +} + static void redraw (app_context_t *app) { @@ -102,6 +129,117 @@ redraw (app_context_t *app) refresh (); } +static bool +is_in_bitmap_data (app_context_t *app, int x, int y) +{ + return x >= app->bitmap_x + && y >= app->bitmap_y + && x < app->bitmap_x + (int) app->bitmap_w + && y < app->bitmap_y + (int) app->bitmap_h; +} + +static void +redraw_canvas (app_context_t *app) +{ + int y = app->corner_y; + for (int screen_y = TOP_BAR_CUTOFF; screen_y < LINES; screen_y++, y++) + { + move (screen_y, 0); + + int x = app->corner_x; + for (int screen_x = 0; screen_x < COLS; screen_x++, x++) + { + uint8_t color; + if (!is_in_bitmap_data (app, x, y)) + color = 0; + else + { + int data_x = x - app->bitmap_x; + int data_y = y - app->bitmap_y; + color = app->bitmap[data_y * app->bitmap_w + data_x]; + } + + addch (app->palette[color]); + } + } + refresh (); +} + +static bool +is_visible (app_context_t *app, int x, int y) +{ + return x >= app->corner_x + && y >= app->corner_y + && x < app->corner_x + COLS + && y < app->corner_y + LINES - TOP_BAR_CUTOFF; +} + +static void +make_place_for_point (app_context_t *app, int x, int y) +{ + if (is_in_bitmap_data (app, x, y)) + return; + + // Make sure the point has some place to go + int new_bitmap_x = app->bitmap_x; + int new_bitmap_y = app->bitmap_y; + + while (new_bitmap_x > x) + new_bitmap_x -= BITMAP_BLOCK_SIZE; + while (new_bitmap_y > y) + new_bitmap_y -= BITMAP_BLOCK_SIZE; + + int new_bitmap_w = app->bitmap_w + (app->bitmap_x - new_bitmap_x); + int new_bitmap_h = app->bitmap_h + (app->bitmap_y - new_bitmap_y); + + while (new_bitmap_x + new_bitmap_w <= x) + new_bitmap_w += BITMAP_BLOCK_SIZE; + while (new_bitmap_y + new_bitmap_h <= y) + new_bitmap_h += BITMAP_BLOCK_SIZE; + + uint8_t *new_bitmap = calloc (new_bitmap_w * new_bitmap_h, + sizeof *new_bitmap); + if (app->bitmap) + { + // Copy data, assuming that the area can only get larger + for (size_t data_y = 0; data_y < app->bitmap_h; data_y++) + memcpy (new_bitmap + + ((data_y + app->bitmap_y - new_bitmap_y) * new_bitmap_w) + + (app->bitmap_x - new_bitmap_x), + app->bitmap + (data_y * app->bitmap_w), + app->bitmap_w * sizeof *new_bitmap); + + free (app->bitmap); + } + + // Replace the bitmap with the reallocated version + app->bitmap_x = new_bitmap_x; + app->bitmap_y = new_bitmap_y; + app->bitmap_w = new_bitmap_w; + app->bitmap_h = new_bitmap_h; + app->bitmap = new_bitmap; +} + +static void +draw_point (app_context_t *app, int x, int y, uint8_t color) +{ + make_place_for_point (app, x, y); + + int data_x = x - app->bitmap_x; + int data_y = y - app->bitmap_y; + app->bitmap[data_y * app->bitmap_w + data_x] = color; + + if (is_visible (app, x, y)) + { + int screen_x = x - app->corner_x; + int screen_y = y - app->corner_y + TOP_BAR_CUTOFF; + + move (screen_y, screen_x); + addch (app->palette[color]); + refresh (); + } +} + static bool on_key (app_context_t *app, termo_key_t *key) { @@ -117,13 +255,31 @@ on_key (app_context_t *app, termo_key_t *key) if (key->type != TERMO_TYPE_MOUSE) return true; - int line, col, button; + int screen_y, screen_x, button; termo_mouse_event_t event; - termo_interpret_mouse (app->tk, key, &event, &button, &line, &col); + termo_interpret_mouse (app->tk, key, &event, &button, &screen_y, &screen_x); if (event != TERMO_MOUSE_PRESS && event != TERMO_MOUSE_DRAG) return true; + if (button == 2) + { + if (event == TERMO_MOUSE_DRAG) + { + app->corner_x += app->move_saved_x - screen_x; + app->corner_y += app->move_saved_y - screen_y; + + app->center_x += app->move_saved_x - screen_x; + app->center_y += app->move_saved_y - screen_y; + + redraw_canvas (app); + } + + app->move_saved_x = screen_x; + app->move_saved_y = screen_y; + return true; + } + uint8_t *color; if (button == 1) color = &app->current_color_left; @@ -132,16 +288,15 @@ on_key (app_context_t *app, termo_key_t *key) else return true; - move (line, col); - if (line >= 3) - { - addch (app->palette[*color]); - refresh (); - } - else if (line > 0 && event != TERMO_MOUSE_DRAG) + int canvas_x = app->corner_x + screen_x; + int canvas_y = app->corner_y + screen_y - TOP_BAR_CUTOFF; + + if (screen_y >= TOP_BAR_CUTOFF) + draw_point (app, canvas_x, canvas_y, *color); + else if (screen_y > 0 && event != TERMO_MOUSE_DRAG) { - int pair = (float) col / COLS * PALETTE_WIDTH; - *color = pair + (line - 1) * PALETTE_WIDTH; + int pair = (float) screen_x / COLS * PALETTE_WIDTH; + *color = pair + (screen_y - 1) * PALETTE_WIDTH; } return true; @@ -197,7 +352,9 @@ main (int argc, char *argv[]) app.tk = tk; init_palette (&app); + update_canvas_for_screen (&app); redraw (&app); + redraw_canvas (&app); termo_result_t ret; termo_key_t key; @@ -228,7 +385,9 @@ main (int argc, char *argv[]) endwin (); refresh (); + update_canvas_for_screen (&app); redraw (&app); + redraw_canvas (&app); } if (fds[0].revents & (POLLIN | POLLHUP | POLLERR)) termo_advisereadable (tk); -- cgit v1.2.3