aboutsummaryrefslogtreecommitdiff
path: root/src/canvas.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/canvas.c')
-rw-r--r--src/canvas.c166
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);
+}