diff options
author | Krow Savcik <krow@savcik.xyz> | 2024-02-06 22:56:21 +0200 |
---|---|---|
committer | Krow Savcik <krow@savcik.xyz> | 2024-02-06 22:56:21 +0200 |
commit | c918280fb5de6e6256cfd9a438b3578c04e3afc2 (patch) | |
tree | ba72e1464c487b61d4376647769c93cdbccf7a21 /src/canvas.c | |
parent | 009a890482edfb2247da1d69b86f4d193699e3cb (diff) |
feautre: added undo/redo buttons
The change history is kept in a ring buffer of definite size 2000.
Diffstat (limited to 'src/canvas.c')
-rw-r--r-- | src/canvas.c | 166 |
1 files changed, 135 insertions, 31 deletions
diff --git a/src/canvas.c b/src/canvas.c index ea50d53..ce8772b 100644 --- a/src/canvas.c +++ b/src/canvas.c @@ -4,6 +4,7 @@ #include <SDL2/SDL_image.h> #include "types.h" +#include "action.h" #include "canvas.h" #include "cdraw.h" #include "palette.h" @@ -13,6 +14,8 @@ uint8 is_drawing; #define COORD(x,y) ((x) + (y) * c->w) +#define HNEXT(i) (i == HISTLENGTH-1 ? 0 : i+1) +#define HPREV(i) (i == 0 ? HISTLENGTH-1 : i-1) static Layer *layer_create(uint, uint); static void layer_destroy(Layer *); @@ -20,6 +23,9 @@ static uint canvas_fill_bfs(Canvas *, int, int, uint, uint); static uint canvas_blend_color(uint, uint); static void canvas_point_redraw(Canvas *, long int, long int); static void canvas_set_proj_path(Canvas *, const char *); +static void action_do(Canvas *); +static void action_remove(Action *); +static void action_pixcols_redo(Canvas *, Action *); static uint8 canvas_coord_get(Canvas *c, long int tx, long int ty, long int *x, long int *y) @@ -52,8 +58,12 @@ canvas_init(uint w, uint h, void *ren) c->layer_arr_cnt = 1; c->layer_arr_sz = 1; c->x = c->y = 0; + c->hist_i = c->hist_s = c->hist_isend = 0; + c->hist_e = HNEXT(c->hist_s); c->layers = malloc(sizeof(*(c->layers))); - c->temp_pix = malloc(w * h * sizeof(SDL_Point)); + c->temp_pix = malloc(w * h * sizeof(* c->temp_pix)); + for (i = 0; i < HISTLENGTH; ++i) + c->history[i].type = ACT_NULL; c->pres_pix = malloc(w * h * sizeof(* c->pres_pix)); c->layers[0] = layer_create(w, h); @@ -184,6 +194,8 @@ canvas_destroy(Canvas *c) SDL_DestroyTexture(c->half_pres); for (i = 0; i < c->layer_arr_cnt; ++i) layer_destroy(c->layers[i]); + for (i = 0; i < HISTLENGTH; ++i) + action_remove(&c->history[i]); free(c->layers); free(c->temp_pix); free(c->pres_pix); @@ -260,11 +272,17 @@ canvas_point_draw(Canvas *c, long int x, long int y) SDL_SetRenderTarget(ren, c->half_pres); if (tool_array[tool_cur] == TOOL_TYPE_ERASER) { + c->temp_pix[c->temp_cnt].x = x; + c->temp_pix[c->temp_cnt].y = y; + c->temp_pix[c->temp_cnt++].c = c->layers[c->cur_layer]->pix[COORD(x,y)]; c->layers[c->cur_layer]->pix[COORD(x,y)] = 0; canvas_point_redraw(c, x, y); SDL_SetRenderDrawColor(ren, INTTOCOLA(c->pres_pix[COORD(x,y)])); SDL_RenderDrawPoint(ren, x, y); } else if (tool_array[tool_cur] == TOOL_TYPE_PENCIL) { + c->temp_pix[c->temp_cnt].x = x; + c->temp_pix[c->temp_cnt].y = y; + c->temp_pix[c->temp_cnt++].c = c->layers[c->cur_layer]->pix[COORD(x,y)]; c->layers[c->cur_layer]->pix[COORD(x,y)] = COLTOINTA( ((Palette *)def_palette)->clist[c->cur_col].r, ((Palette *)def_palette)->clist[c->cur_col].g, @@ -276,10 +294,11 @@ canvas_point_draw(Canvas *c, long int x, long int y) } else if (tool_array[tool_cur] == TOOL_TYPE_FILL) { oldcol = canvas_fill_bfs(c, x, y, oldcol, newcol); for (i = 0; i < oldcol; ++i) { - canvas_point_redraw(c, ((SDL_Point *)c->temp_pix)[i].x, ((SDL_Point *)c->temp_pix)[i].y); - SDL_SetRenderDrawColor(ren, INTTOCOLA(c->pres_pix[COORD(((SDL_Point *)c->temp_pix)[i].x,((SDL_Point *)c->temp_pix)[i].y)])); - SDL_RenderDrawPoint(ren, ((SDL_Point *)c->temp_pix)[i].x, ((SDL_Point *)c->temp_pix)[i].y); + canvas_point_redraw(c, c->temp_pix[i].x, c->temp_pix[i].y); + SDL_SetRenderDrawColor(ren, INTTOCOLA(c->pres_pix[COORD(c->temp_pix[i].x, c->temp_pix[i].y)])); + SDL_RenderDrawPoint(ren, c->temp_pix[i].x, c->temp_pix[i].y); } + canvas_mousel_up(c); } SDL_SetRenderTarget(ren, NULL); } @@ -309,6 +328,7 @@ canvas_mousel_down(Canvas *c, long int x, long int y) case TOOL_TYPE_ERASER: case TOOL_TYPE_FILL: is_drawing = 1; + c->temp_cnt = 0; canvas_point_draw(c, x, y); break; } @@ -333,9 +353,11 @@ canvas_mouse_move(Canvas *c, long int x, long int y) void canvas_mousel_up(Canvas *c) { -/* if (is_drawing && (tool_array[tool_cur] == TOOL_TYPE_PENCIL || tool_array[tool_cur] = TOOL_TYPE_ERASER)) {*/ -/*TODO: save action*/ -/* }*/ + if (is_drawing && (tool_array[tool_cur] == TOOL_TYPE_PENCIL || tool_array[tool_cur] == TOOL_TYPE_ERASER || tool_array[tool_cur] == TOOL_TYPE_FILL) && c->temp_cnt != 0) { + action_do(c); + c->temp_cnt = 0; + } + is_drawing = 0; } @@ -489,52 +511,52 @@ layer_destroy(Layer *lay) static uint canvas_fill_bfs(Canvas *c, int x, int y, uint oldcol, uint newcol) { - int cnt; - SDL_Point *pnt; + struct action_pixcol *pnt; - if (c == NULL) - return 0; + if (c == NULL) + return 0; - pnt = c->temp_pix; - cnt = 1; + pnt = c->temp_pix; + c->temp_cnt = 1; - ((SDL_Point *)c->temp_pix)[0].x = x; - ((SDL_Point *)c->temp_pix)[0].y = y; - c->layers[c->cur_layer]->pix[COORD(x,y)] = newcol; + c->temp_pix[0].x = x; + c->temp_pix[0].y = y; + c->layers[c->cur_layer]->pix[COORD(x,y)] = newcol; - for (; pnt != &((SDL_Point *)c->temp_pix)[cnt]; ++pnt) { + for (; pnt != &(c->temp_pix)[c->temp_cnt]; ++pnt) { + pnt[0].c = oldcol; x = pnt[0].x; y = pnt[0].y; if (x > 0 && c->layers[c->cur_layer]->pix[COORD(x - 1,y)] == oldcol) { c->layers[c->cur_layer]->pix[COORD(x-1, y)] = newcol; - ((SDL_Point *)c->temp_pix)[cnt].x = x - 1; - ((SDL_Point *)c->temp_pix)[cnt].y = y; - ++cnt; + c->temp_pix[c->temp_cnt].x = x - 1; + c->temp_pix[c->temp_cnt].y = y; + ++c->temp_cnt; } if (x < c->w - 1 && c->layers[c->cur_layer]->pix[COORD(x+1, y)] == oldcol) { c->layers[c->cur_layer]->pix[COORD(x+1, y)] = newcol; - ((SDL_Point *)c->temp_pix)[cnt].x = x + 1; - ((SDL_Point *)c->temp_pix)[cnt].y = y; - ++cnt; + c->temp_pix[c->temp_cnt].x = x + 1; + c->temp_pix[c->temp_cnt].y = y; + ++c->temp_cnt; } if (y > 0 && c->layers[c->cur_layer]->pix[COORD(x, y-1)] == oldcol) { c->layers[c->cur_layer]->pix[COORD(x, y-1)] = newcol; - ((SDL_Point *)c->temp_pix)[cnt].x = x; - ((SDL_Point *)c->temp_pix)[cnt].y = y - 1; - ++cnt; + c->temp_pix[c->temp_cnt].x = x; + c->temp_pix[c->temp_cnt].y = y - 1; + ++c->temp_cnt; } if (y < c->h - 1 && c->layers[c->cur_layer]->pix[COORD(x, y+1)] == oldcol) { c->layers[c->cur_layer]->pix[COORD(x, y+1)] = newcol; - ((SDL_Point *)c->temp_pix)[cnt].x = x; - ((SDL_Point *)c->temp_pix)[cnt].y = y + 1; - ++cnt; + c->temp_pix[c->temp_cnt].x = x; + c->temp_pix[c->temp_cnt].y = y + 1; + ++c->temp_cnt; } } - return cnt; + return c->temp_cnt; } static uint @@ -548,10 +570,92 @@ canvas_blend_color(uint a, uint b) static void canvas_point_redraw(Canvas *c, long int x, long int y) { - /* expects for the render target to be c->half_pres */ int i; c->pres_pix[COORD(x, y)] = 0; for (i = 0; i < c->layer_arr_cnt; i++) c->pres_pix[COORD(x, y)] = canvas_blend_color(c->pres_pix[COORD(x, y)], c->layers[i]->pix[COORD(x, y)]); } + +static void +action_do(Canvas *c) +{ + action_remove(&c->history[c->hist_i]); + c->history[c->hist_i].type = ACT_PIXELSCOLORS; + c->history[c->hist_i].act.px.cnt = c->temp_cnt; + c->history[c->hist_i].act.px.pix = malloc(c->temp_cnt * sizeof(struct action_pixcol)); + memcpy(c->history[c->hist_i].act.px.pix, c->temp_pix, c->temp_cnt * sizeof(struct action_pixcol)); + if (c->hist_i == c->hist_e) + c->hist_e = HNEXT(c->hist_e); + + if (c->hist_isend && c->hist_s == c->hist_i) + c->hist_s = HNEXT(c->hist_s); + + c->hist_isend = 1; + c->hist_i = HNEXT(c->hist_i); + c->hist_e = c->hist_i; +} + +void +action_undo(Canvas *c) +{ + if (!c->hist_isend && c->hist_i == c->hist_s) + return; + + c->hist_i = HPREV(c->hist_i); + c->hist_isend = 0; + + switch(c->history[c->hist_i].type) { + case ACT_PIXELSCOLORS: + action_pixcols_redo(c, &c->history[c->hist_i]); + break; + } +} + +void +action_redo(Canvas *c) +{ + if (c->hist_isend) + return; + + switch(c->history[c->hist_i].type) { + case ACT_PIXELSCOLORS: + action_pixcols_redo(c, &c->history[c->hist_i]); + break; + } + + c->hist_i = HNEXT(c->hist_i); + c->hist_isend = (c->hist_i == c->hist_e); +} + +static void +action_remove(Action *a) +{ + switch(a->type) { + case ACT_PIXELSCOLORS: + free(a->act.px.pix); + break; + } + + a->type = ACT_NULL; +} + +static void +action_pixcols_redo(Canvas *c, Action *a) +{ + struct action_pixcol *pnt, *end; + unsigned int col; + pnt = a->act.px.pix; + end = &pnt[a->act.px.cnt]; + + SDL_SetRenderTarget(ren, c->half_pres); + for (; pnt != end; pnt++) { + col = c->layers[c->cur_layer]->pix[COORD(pnt->x, pnt->y)]; + c->layers[c->cur_layer]->pix[COORD(pnt->x, pnt->y)] = pnt->c; + pnt->c = col; + canvas_point_redraw(c, pnt->x, pnt->y); + SDL_SetRenderDrawColor(ren, INTTOCOLA(c->pres_pix[COORD(pnt->x, pnt->y)])); + SDL_RenderDrawPoint(ren, pnt->x, pnt->y); + } + SDL_SetRenderTarget(ren, NULL); +} |