aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--assets/small.cdrbin16392 -> 65546 bytes
-rw-r--r--assets/small.pngbin614 -> 801 bytes
-rw-r--r--assets/ui.pngbin1214 -> 1648 bytes
-rwxr-xr-xconv2
-rw-r--r--src/action.h25
-rw-r--r--src/canvas.c166
-rw-r--r--src/canvas.h14
-rw-r--r--src/cdraw.c1
-rw-r--r--src/cdraw.h2
-rw-r--r--src/tools.c4
-rw-r--r--src/tools.h2
-rw-r--r--src/ui.c11
-rw-r--r--src/user.c17
13 files changed, 197 insertions, 47 deletions
diff --git a/assets/small.cdr b/assets/small.cdr
index 6f827c9..0008801 100644
--- a/assets/small.cdr
+++ b/assets/small.cdr
Binary files differ
diff --git a/assets/small.png b/assets/small.png
index 98a200d..8664b55 100644
--- a/assets/small.png
+++ b/assets/small.png
Binary files differ
diff --git a/assets/ui.png b/assets/ui.png
index ef0d60e..91d3018 100644
--- a/assets/ui.png
+++ b/assets/ui.png
Binary files differ
diff --git a/conv b/conv
index 10d562b..c523b77 100755
--- a/conv
+++ b/conv
@@ -1 +1 @@
-gm convert assets/small.png -scale 128 assets/ui.png
+gm convert assets/small.png -scale 256 assets/ui.png
diff --git a/src/action.h b/src/action.h
index 7405418..d9b7698 100644
--- a/src/action.h
+++ b/src/action.h
@@ -1,22 +1,25 @@
+typedef struct Action Action;
+
enum Actions_Types {
+ ACT_NULL,
ACT_PIXELSCOLORS,
-}
-
-struct act_pixcol {
- long int p; /* Position */
- unsigned int c; /* Color */
};
-struct Action {
- int type;
- ActUnion act;
+struct action_pixcol {
+ int x, y; /* Position */
+ unsigned int c; /* Color */
};
struct ActionPixelsColors {
long int cnt;
- struct act_pixcol *pix;
-}
+ struct actiton_pixcol *pix;
+};
typedef union {
- ActionPixelsColors px;
+ struct ActionPixelsColors px;
} ActUnion;
+
+struct Action {
+ int type;
+ ActUnion act;
+};
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);
+}
diff --git a/src/canvas.h b/src/canvas.h
index 104f130..bc96ab9 100644
--- a/src/canvas.h
+++ b/src/canvas.h
@@ -1,5 +1,10 @@
+/* Should include action.h before it */
+
+/* TODO: move to config.h */
+#define HISTLENGTH 2000
+
struct Layer {
- unsigned int *pix;
+ unsigned int *pix;
};
struct Canvas {
@@ -10,8 +15,11 @@ struct Canvas {
struct Layer **layers;
int x, y;
void *back, *pres, *half_pres;
- void *temp_pix;
+ struct action_pixcol *temp_pix;
+ int temp_cnt;
uint *pres_pix;
+ Action history[HISTLENGTH];
+ int hist_s, hist_e, hist_i, hist_isend;
};
typedef struct Layer Layer;
@@ -38,3 +46,5 @@ void canvas_move_y(Canvas *, long int);
void canvas_refresh(Canvas *);
unsigned char canvas_save(Canvas *, const char *, short int);
unsigned char canvas_export_png(Canvas *, const char *, void *);
+void action_undo(Canvas *);
+void action_redo(Canvas *);
diff --git a/src/cdraw.c b/src/cdraw.c
index c0c06c5..25c0dba 100644
--- a/src/cdraw.c
+++ b/src/cdraw.c
@@ -4,6 +4,7 @@
#include "cdraw.h"
#include "types.h"
+#include "action.h"
#include "canvas.h"
#include "debug.h"
#include "palette.h"
diff --git a/src/cdraw.h b/src/cdraw.h
index 38bb058..1d66b6b 100644
--- a/src/cdraw.h
+++ b/src/cdraw.h
@@ -29,6 +29,8 @@ void user_canvas_import_png(const Arg *);
void user_canvas_refresh(const Arg *);
void user_canvas_create_new(const Arg *);
void user_canvas_pal_col_chng(const Arg *);
+void user_canvas_undo(const Arg *);
+void user_canvas_redo(const Arg *);
void user_tool_change(const Arg *);
void user_layer_chng(const Arg *);
void user_testing_layer_add(const Arg *);
diff --git a/src/tools.c b/src/tools.c
index 1ff979a..97f335c 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -2,6 +2,7 @@
#include "tools.h"
#include "types.h"
+#include "action.h"
#include "canvas.h"
#include "ui.h"
@@ -16,8 +17,9 @@ uint8 tool_array[] = {
TOOL_TYPE_CPICKER,
TOOL_TYPE_ZOOMOUT,
TOOL_TYPE_ZOOMIN,
- TOOL_TYPE_EMPTY,
+ TOOL_TYPE_UNDO,
TOOL_TYPE_CLOWN,
+ TOOL_TYPE_REDO,
};
void
diff --git a/src/tools.h b/src/tools.h
index c18afe3..cd232de 100644
--- a/src/tools.h
+++ b/src/tools.h
@@ -6,6 +6,8 @@ enum Tool_Types {
TOOL_TYPE_ZOOMOUT,
TOOL_TYPE_CLOWN,
TOOL_TYPE_CPICKER,
+ TOOL_TYPE_UNDO,
+ TOOL_TYPE_REDO,
TOOL_TYPE_EMPTY,
};
diff --git a/src/ui.c b/src/ui.c
index ccc2de9..28a54f6 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -6,6 +6,7 @@
#include "ui.h"
#include "cdraw.h"
#include "types.h"
+#include "action.h"
#include "canvas.h"
#include "tools.h"
#include "debug.h"
@@ -37,6 +38,8 @@ static const SDL_Rect ui_buttons_rect[] = {
{56, 54, 28, 28}, /* Zoom out */
{84, 54, 28, 28}, /* Clown */
{56, 82, 28, 28}, /* Color Picker */
+ {84, 82, 28, 28}, /* Undo */
+ {84, 110, 28, 28}, /* Redo */
};
struct UIPanel {
@@ -272,6 +275,12 @@ ui_mousel_down(int x, int y)
break;
case TOOL_TYPE_EMPTY:
break;
+ case TOOL_TYPE_UNDO:
+ user_canvas_undo(NULL);
+ break;
+ case TOOL_TYPE_REDO:
+ user_canvas_redo(NULL);
+ break;
default:
tool_change(col);
break;
@@ -369,7 +378,7 @@ ui_focus_panel_change(int x, int y)
if (main_ui->focus_panel != NULL) {
switch (main_ui->focus_panel->type) {
case UI_PANELTYPE_CANVAS:
- is_drawing = 0;
+ canvas_mousel_up(cur_canvas);
main_ui->focus_panel = u;
ui_redraw_panel(UI_PANELTYPE_CANVAS);
break;
diff --git a/src/user.c b/src/user.c
index 0261c65..927e852 100644
--- a/src/user.c
+++ b/src/user.c
@@ -12,6 +12,7 @@
#include "cdraw.h"
#include "types.h"
#include "tools.h"
+#include "action.h"
#include "canvas.h"
#include "palette.h"
@@ -242,3 +243,19 @@ choose_file_path(const char *prompt, char *input)
if (ft != stdin) pclose(ft);
}
+
+void
+user_canvas_undo(const Arg *x)
+{
+ if (cur_canvas == NULL) return;
+ action_undo(cur_canvas);
+ ui_redraw_panel(UI_PANELTYPE_CANVAS);
+}
+
+void
+user_canvas_redo(const Arg *x)
+{
+ if (cur_canvas == NULL) return;
+ action_redo(cur_canvas);
+ ui_redraw_panel(UI_PANELTYPE_CANVAS);
+}