aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/action.h22
-rw-r--r--src/canvas.c534
-rw-r--r--src/canvas.h40
-rw-r--r--src/cdraw.c194
-rw-r--r--src/cdraw.h35
-rw-r--r--src/config.h34
-rw-r--r--src/debug.c86
-rw-r--r--src/debug.h14
-rw-r--r--src/palette.c113
-rw-r--r--src/palette.h15
-rw-r--r--src/tools.c39
-rw-r--r--src/tools.h16
-rw-r--r--src/types.h11
-rw-r--r--src/ui.c692
-rw-r--r--src/ui.h36
-rw-r--r--src/user.c238
16 files changed, 2119 insertions, 0 deletions
diff --git a/src/action.h b/src/action.h
new file mode 100644
index 0000000..7405418
--- /dev/null
+++ b/src/action.h
@@ -0,0 +1,22 @@
+enum Actions_Types {
+ ACT_PIXELSCOLORS,
+}
+
+struct act_pixcol {
+ long int p; /* Position */
+ unsigned int c; /* Color */
+};
+
+struct Action {
+ int type;
+ ActUnion act;
+};
+
+struct ActionPixelsColors {
+ long int cnt;
+ struct act_pixcol *pix;
+}
+
+typedef union {
+ ActionPixelsColors px;
+} ActUnion;
diff --git a/src/canvas.c b/src/canvas.c
new file mode 100644
index 0000000..5e29566
--- /dev/null
+++ b/src/canvas.c
@@ -0,0 +1,534 @@
+#include <stdlib.h>
+#include <string.h>
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_image.h>
+
+#include "types.h"
+#include "canvas.h"
+#include "cdraw.h"
+#include "palette.h"
+#include "tools.h"
+#include "debug.h"
+
+uint8 is_drawing;
+
+#define COORD(x,y) ((x) + (y) * c->w)
+
+static Layer *layer_create(uint, uint);
+static void layer_destroy(Layer *);
+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 uint8
+canvas_coord_get(Canvas *c, long int tx, long int ty, long int *x, long int *y)
+{
+ if (tx < c->x || ty < c->y) return 1;
+ tx = (tx - c->x) / c->zoom;
+ ty = (ty - c->y) / c->zoom;
+ if (tx >= c->w || ty >= c->h) return 1;
+ *x = tx;
+ *y = ty;
+ return 0;
+}
+
+Canvas *
+canvas_init(uint w, uint h, void *ren)
+{
+ Canvas *c;
+ int i, j;
+ SDL_Rect dest;
+
+ dest.w = dest.h = 16;
+ is_drawing = 0;
+ c = (Canvas *)malloc(sizeof(Canvas));
+ c->w = w;
+ c->h = h;
+ c->cur_col = 0;
+ c->cur_layer = 0;
+ c->zoom = 1;
+ c->proj_path = NULL;
+ c->layer_arr_cnt = 1;
+ c->layer_arr_sz = 1;
+ c->x = c->y = 0;
+ c->layers = malloc(sizeof(*(c->layers)));
+ c->temp_pix = malloc(w * h * sizeof(SDL_Point));
+ c->pres_pix = malloc(w * h * sizeof(* c->pres_pix));
+
+ c->layers[0] = layer_create(w, h);
+
+ for (i = 0; i < c->w * c->h; ++i)
+ c->pres_pix[i] = 0;
+
+ if (c->layers[0] == NULL) {
+ fprintf(stderr, "Error while creating layer");
+ free(c);
+ return NULL;
+ }
+
+ c->back = SDL_CreateTexture(
+ ren, SDL_PIXELFORMAT_RGBA8888,
+ SDL_TEXTUREACCESS_TARGET,
+ w, h);
+
+ if (c->back == NULL) {
+ printf("SDL_CreateTexture failed: %s\n", SDL_GetError());
+ free(c);
+ return NULL;
+ }
+
+ c->pres = SDL_CreateTexture(
+ ren, SDL_PIXELFORMAT_RGBA8888,
+ SDL_TEXTUREACCESS_TARGET,
+ w, h);
+
+ if (c->pres == NULL) {
+ printf("SDL_CreateTexture failed: %s\n", SDL_GetError());
+ free(c);
+ return NULL;
+ }
+
+ SDL_SetRenderTarget(ren, c->back);
+ for (i = 0; i < w; i += 16) {
+ dest.x = i;
+ for (j = 0; j < h; j += 16) {
+ dest.y = j;
+ if (((j+i)>>4)&1)
+ SDL_SetRenderDrawColor(ren, 225, 225, 225, 255);
+ else
+ SDL_SetRenderDrawColor(ren, 125, 125, 125, 255);
+ SDL_RenderFillRect(ren, &dest);
+ }
+ }
+ SDL_SetRenderTarget(ren, NULL);
+
+ return c;
+}
+
+Canvas *
+canvas_open(const char *path, void *ren)
+{
+ int ver, w, h;
+ Canvas *c;
+ FILE *fp = fopen(path, "r");
+ if (fp == NULL) return NULL;
+ fscanf(fp, "%d;%d;%d;", &ver, &w, &h);
+ c = canvas_init(w, h, ren);
+ fread(c->layers[0]->pix, sizeof *(c->layers[0]->pix), c->w*c->h, fp);
+ fclose(fp);
+
+ canvas_refresh(c);
+ canvas_set_proj_path(c, path);
+
+ return c;
+}
+
+Canvas *
+canvas_import_png(const char *path, void *ren)
+{
+/* TODO: check path and SDL errors */
+/* TODO: import to layer */
+ Canvas *c;
+/* TODO: solve prob (maybe using STB) */
+/* TODO: really a hack. Rewrite */
+ SDL_Texture *tex;
+ SDL_Surface *sur;
+ SDL_Rect rect;
+ rect.x = rect.y = 0;
+ sur = IMG_Load(path);
+ if (sur == NULL) return NULL;
+ tex = SDL_CreateTextureFromSurface(ren, sur);
+ if (tex == NULL) return NULL;
+
+ c = canvas_init(sur->w, sur->h, ren);
+ if (c == NULL) return NULL;
+
+ SDL_SetRenderTarget(ren, c->pres);
+ SDL_RenderCopy(ren, tex, NULL, NULL);
+ rect.w = sur->w;
+ rect.h = sur->h;
+ SDL_RenderReadPixels(ren, &rect, SDL_PIXELFORMAT_RGBA8888,
+ c->layers[0]->pix, (sizeof *(c->layers[0]->pix)) * c->w);
+ SDL_SetRenderTarget(ren, NULL);
+
+ SDL_DestroyTexture(tex);
+ SDL_FreeSurface(sur);
+ canvas_refresh(c);
+
+ return c;
+}
+
+void
+canvas_destroy(Canvas *c)
+{
+ int i;
+ if (c == NULL) return;
+ SDL_DestroyTexture(c->pres);
+ SDL_DestroyTexture(c->back);
+ for (i = 0; i < c->layer_arr_cnt; ++i)
+ layer_destroy(c->layers[i]);
+ free(c->layers);
+ free(c->temp_pix);
+ free(c->pres_pix);
+ free(c->proj_path);
+ free(c);
+ SDL_SetWindowTitle(win, "cdraw");
+}
+
+void
+canvas_redraw(Canvas *c, void *ren, int mx, int my)
+{
+ long int x, y;
+ SDL_SetRenderTarget(ren, c->pres);
+ SDL_RenderCopy(ren,c->back,NULL,NULL);
+ /* TODO: Draw the pointer between selected layers instead of on top of all layers */
+ /* TODO: Draw by copying data, not calling SDL function */
+ for (x = 0; x < c->w; ++x) {
+ for (y = 0; y < c->h; ++y) {
+ SDL_SetRenderDrawColor(ren, INTTOCOLA(c->pres_pix[COORD(x, y)]));
+ SDL_RenderDrawPoint(ren, x, y);
+ }
+ }
+ if (mx > 0 && my > 0 && canvas_coord_get(c, mx, my, &x, &y) == 0) {
+ SDL_SetRenderDrawColor(ren,
+ ((Palette *)def_palette)->clist[c->cur_col].r,
+ ((Palette *)def_palette)->clist[c->cur_col].g,
+ ((Palette *)def_palette)->clist[c->cur_col].b,
+ 255);
+ SDL_RenderDrawPoint(ren, x, y);
+ }
+ if (is_drawing) {
+ SDL_SetRenderDrawColor(ren, 30, 30, 30, 255);
+ SDL_RenderDrawPoint(ren, 0, 0);
+ }
+ SDL_SetRenderTarget(ren, NULL);
+ return;
+}
+
+void
+canvas_present(Canvas *c, void *ren)
+{
+ SDL_Rect dest;
+ dest.x = c->x;
+ dest.y = c->y;
+ dest.h = c->h*c->zoom;
+ dest.w = c->w*c->zoom;
+ SDL_RenderCopy(ren,c->pres,NULL,&dest);
+}
+
+void
+canvas_zoom_change(Canvas *c, short int v)
+{
+ if (v < 0) {
+ if (c->zoom <= (-v))
+ c->zoom = (-v)+1;
+ }
+ c->zoom += v;
+ if (c->zoom > maxzoom)
+ c->zoom = maxzoom;
+}
+
+/* TODO: make static */
+void
+canvas_point_draw(Canvas *c, long int x, long int y)
+{
+ unsigned int oldcol, newcol;
+ int i;
+/* TODO: better */
+ oldcol = c->layers[c->cur_layer]->pix[COORD(x,y)];
+ newcol = COLTOINTA(
+ ((Palette *)def_palette)->clist[c->cur_col].r,
+ ((Palette *)def_palette)->clist[c->cur_col].g,
+ ((Palette *)def_palette)->clist[c->cur_col].b,
+ 255);
+
+ if (tool_array[tool_cur] == TOOL_TYPE_ERASER)
+ newcol = 0;
+
+ if (newcol == oldcol)
+ return;
+
+ SDL_SetRenderTarget(ren, c->pres);
+ if (tool_array[tool_cur] == TOOL_TYPE_ERASER) {
+ c->layers[c->cur_layer]->pix[COORD(x,y)] = 0;
+ canvas_point_redraw(c, x, y);
+ } else if (tool_array[tool_cur] == TOOL_TYPE_PENCIL) {
+ 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,
+ ((Palette *)def_palette)->clist[c->cur_col].b,
+ 255);
+ canvas_point_redraw(c, x, 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_SetRenderTarget(ren, NULL);
+}
+
+/* Mouse input */
+void
+canvas_mousel_down(Canvas *c, long int x, long int y)
+{
+ int i;
+ if (canvas_coord_get(c, x, y, &x, &y))
+ return;
+ switch (tool_array[tool_cur]) {
+ case TOOL_TYPE_CPICKER:
+ for (i = 0; i < ((Palette *)def_palette)->num; ++i) {
+ if (c->layers[c->cur_layer]->pix[COORD(x,y)] == COLTOINTA(
+ ((Palette *)def_palette)->clist[i].r,
+ ((Palette *)def_palette)->clist[i].g,
+ ((Palette *)def_palette)->clist[i].b,
+ 255)) {
+ c->cur_col = i;
+ /* ui_redraw_panel(UI_PANELTYPE_PALETTE); */
+ break;
+ }
+ }
+ break;
+ case TOOL_TYPE_PENCIL:
+ case TOOL_TYPE_ERASER:
+ case TOOL_TYPE_FILL:
+ is_drawing = 1;
+ canvas_point_draw(c, x, y);
+ break;
+ }
+}
+
+void
+canvas_mouse_move(Canvas *c, long int x, long int y)
+{
+ if (is_drawing == 0)
+ return;
+ if (canvas_coord_get(c, x, y, &x, &y))
+ return;
+ switch (tool_array[tool_cur]) {
+ case TOOL_TYPE_PENCIL:
+ case TOOL_TYPE_ERASER:
+ case TOOL_TYPE_FILL:
+ canvas_point_draw(c, x, y);
+ break;
+ }
+}
+
+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*/
+/* }*/
+ is_drawing = 0;
+}
+
+void
+canvas_move_x(Canvas *c, long int delta)
+{
+ c->x += delta;
+}
+
+void
+canvas_move_y(Canvas *c, long int delta)
+{
+ c->y += delta;
+}
+
+
+uint8
+canvas_save(Canvas *c, const char *path, short int s)
+{
+ FILE *fp = fopen(path, "w");
+ if (fp == NULL) {
+ /* TODO: Error handling */
+ return 1;
+ }
+
+ fprintf(fp, "1;%d;%d;", c->w, c->h);
+ int u = fwrite(c->layers[0]->pix, sizeof *(c->layers[0]->pix), c->w*c->h, fp);
+ fclose(fp);
+ if (s)
+ canvas_set_proj_path(c, path);
+}
+
+uint8
+canvas_export_png(Canvas *c, const char *path, void *ren)
+{
+/* TODO: check path */
+ SDL_Surface *surf;
+ /* SDL_Texture *tex; */
+ SDL_Rect dest;
+ int i, j, k, ret = 0;
+ dest.x = dest.y = 0;
+ dest.w = c->w;
+ dest.h = c->h;
+
+
+ surf = SDL_CreateRGBSurfaceWithFormat( 0, c->w, c->h, 32, SDL_PIXELFORMAT_RGBA8888);
+ ret = ret || (surf == NULL);
+
+ SDL_LockSurface(surf);
+
+/* TODO: Assuming bad stuff (pixel size) */
+ for (j = 0; j < c->h; j++) {
+ for (k = 0; k < c->w; k++) {
+ canvas_point_redraw(c, k, j);
+ ((unsigned int *)surf->pixels)[COORD(k,j)] = c->pres_pix[COORD(k, j)];
+ }
+ }
+
+ SDL_UnlockSurface(surf);
+ ret = ret || (IMG_SavePNG(surf, path) == -1);
+ SDL_FreeSurface(surf);
+
+ if (ret)
+ fprintf(stderr, "%s:%d:canvas_export_png: Error while exporting\n", __FILE__, __LINE__);
+ return ret;
+}
+
+void
+canvas_add_layer(Canvas *c, unsigned char pos)
+{
+ int i;
+ if (c == NULL)
+ return;
+ pos = (pos > c->layer_arr_cnt) ? c->layer_arr_cnt : pos;
+
+ if (c->layer_arr_cnt == c->layer_arr_sz) {
+ c->layer_arr_sz *= 2;
+ c->layers = realloc(c->layers, c->layer_arr_sz * sizeof(* c->layers));
+ }
+
+ for (i = c->layer_arr_cnt; i > pos; i--) {
+ c->layers[i] = c->layers[i-1];
+ }
+
+ c->layer_arr_cnt++;
+ c->layers[pos] = layer_create(c->w, c->h);
+}
+
+void
+canvas_refresh(Canvas *c)
+{
+ int i, j;
+ for (i = 0; i < c->w; ++i)
+ for (j = 0; j < c->h; ++j)
+ canvas_point_redraw(c, i, j);
+}
+
+static void
+canvas_set_proj_path(Canvas *c, const char *path)
+{
+ char *title;
+ free(c->proj_path);
+ c->proj_path = malloc((strlen(path) + 1) * sizeof(char));
+ memcpy(c->proj_path, path, (strlen(path) + 1) * sizeof(char));
+
+
+ /* TODO Set title format from config.h */
+ title = malloc((strlen(path) + 8) * sizeof(char));
+ strcpy(title, "cdraw: ");
+ strcat(title, path);
+
+ SDL_SetWindowTitle(win, title);
+ free(title);
+}
+
+static Layer *
+layer_create(uint w, uint h)
+{
+ Layer *res;
+ int i;
+ /* TODO: better error handling and maybe allocating together? */
+ res = malloc(sizeof *res);
+
+ res->pix = malloc(h * w * sizeof(* res->pix));
+ if (res->pix == NULL) {
+ fprintf(stderr, "Error creating layer\n");
+ layer_destroy(res);
+ return NULL;
+ }
+
+ for (i = 0; i < w*h; ++i)
+ res->pix[i] = 0;
+
+ return res;
+}
+
+static void
+layer_destroy(Layer *lay)
+{
+ if (lay->pix != NULL)
+ free(lay->pix);
+ free(lay);
+}
+
+static uint
+canvas_fill_bfs(Canvas *c, int x, int y, uint oldcol, uint newcol)
+{
+ int cnt;
+ SDL_Point *pnt;
+
+ if (c == NULL)
+ return 0;
+
+ pnt = c->temp_pix;
+ 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;
+
+ for (; pnt != &((SDL_Point *)c->temp_pix)[cnt]; ++pnt) {
+ 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;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+ }
+
+ return cnt;
+}
+
+static uint
+canvas_blend_color(uint a, uint b)
+{
+ /* TODO: do actual blending */
+ if ((b&0xff) == 0) return a;
+ return b;
+}
+
+static void
+canvas_point_redraw(Canvas *c, long int x, long int y)
+{
+ 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)]);
+}
diff --git a/src/canvas.h b/src/canvas.h
new file mode 100644
index 0000000..2bdb775
--- /dev/null
+++ b/src/canvas.h
@@ -0,0 +1,40 @@
+struct Layer {
+ unsigned int *pix;
+};
+
+struct Canvas {
+ unsigned char layer_arr_cnt, layer_arr_sz;
+ unsigned int cur_col, cur_layer;
+ unsigned int w, h, zoom;
+ char *proj_path;
+ struct Layer **layers;
+ int x, y;
+ void *back, *pres;
+ void *temp_pix;
+ uint *pres_pix;
+};
+
+typedef struct Layer Layer;
+typedef struct Canvas Canvas;
+
+extern unsigned char is_drawing;
+extern const unsigned int maxzoom; /* move to another tab */
+extern Canvas* cur_canvas; /* current canvas */
+
+Canvas *canvas_init(unsigned int, unsigned int, void *);
+Canvas *canvas_import_png(const char *, void *);
+Canvas *canvas_open(const char *, void *); /* TODO: open function per version */
+void canvas_destroy(Canvas *);
+void canvas_redraw(Canvas *, void *, int, int);
+void canvas_present(Canvas *, void *);
+void canvas_zoom_change(Canvas *, short int);
+void canvas_point_draw(Canvas *, long int, long int);
+void canvas_mousel_up(Canvas *);
+void canvas_mousel_down(Canvas *, long int, long int);
+void canvas_mouse_move(Canvas *, long int, long int);
+void canvas_add_layer(Canvas *, unsigned char);
+void canvas_move_x(Canvas *, long int);
+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 *);
diff --git a/src/cdraw.c b/src/cdraw.c
new file mode 100644
index 0000000..5f3a1b5
--- /dev/null
+++ b/src/cdraw.c
@@ -0,0 +1,194 @@
+#include <stdio.h>
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_image.h>
+
+#include "cdraw.h"
+#include "types.h"
+#include "canvas.h"
+#include "debug.h"
+#include "palette.h"
+#include "ui.h"
+
+/* macros */
+#define LENGTH(X) (sizeof X / sizeof X[0])
+
+typedef struct {
+ SDL_Keymod mod;
+ SDL_Keycode sym;
+ void (*func)(const Arg *);
+ const Arg arg;
+} Key;
+
+#include "config.h"
+
+SDL_Window *win;
+void *ren;
+void *def_palette;
+struct Canvas* cur_canvas;
+
+/* TODO: window resize change mouseX and mouse Y */
+int mouseX, mouseY;
+
+void keypress(SDL_Keysym *);
+
+void
+keypress(SDL_Keysym *k)
+{
+ static Key *p, *end;
+ /* printf("Key pressed: %d %d %d\n", k->sym, k->mod, KMOD_SHIFT); */
+ for (p = keys, end = &p[LENGTH(keys)]; p != end; ++p) {
+ if (k->sym == p->sym
+ && k->mod == p->mod)
+ p->func(&(p->arg));
+ }
+}
+
+uint
+main_quit()
+{
+ /* TODO: checks */
+ canvas_destroy(cur_canvas);
+ ui_destroy();
+ SDL_DestroyWindow(win);
+ IMG_Quit();
+ SDL_Quit();
+ return 1;
+}
+
+uint
+main_window_init(const char *s)
+{
+ int ss;
+ if (SDL_Init(SDL_INIT_VIDEO) < 0) {
+ printf("SDL_Init failed: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ if (IMG_Init(IMG_INIT_PNG) == 0)
+ return 1;
+
+ win = SDL_CreateWindow("cdraw",
+ SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
+ 512, 256,
+ SDL_WINDOW_RESIZABLE);
+ if (win == NULL) {
+ printf("SDL_CreateWindow failed: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ ren = SDL_CreateRenderer(win, -1, 0);
+ if (ren == NULL) {
+ printf("SDL_CreateRenderer failed: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ SDL_SetRenderDrawColor(ren, 18, 18, 18, 255);
+ SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_BLEND);
+ SDL_RenderPresent(ren);
+
+ def_palette = palette_open_gpl(def_palette_path);
+ if (def_palette == NULL)
+ return 1;
+
+ ui_create("assets/ui.png");
+ if (s == NULL)
+ cur_canvas = canvas_init(64, 64, ren);
+ else {
+ ss = strlen(s);
+ if (ss > 4 && strcmp(&s[ss-4], ".cdr") == 0)
+ cur_canvas = canvas_open(s, ren);
+ else
+ cur_canvas = canvas_import_png(s, ren);
+ }
+
+ ui_redraw_panel(UI_PANELTYPE_CANVAS);
+ if (cur_canvas == NULL)
+ return 1;
+
+ return 0;
+}
+
+uint
+main_event_handle()
+{
+ static uint8 q, r;
+ static SDL_Event event;
+ q = r = 0;
+ while (SDL_PollEvent(&event)) {
+ switch (event.type) {
+ case SDL_QUIT:
+ q = 1;
+ break;
+ case SDL_WINDOWEVENT:
+ switch (event.window.event) {
+ case SDL_WINDOWEVENT_RESIZED:
+ r = 1;
+ /* FALLTROUGH */
+ case SDL_WINDOWEVENT_MOVED:
+ break;
+ }
+ break;
+ case SDL_MOUSEBUTTONDOWN:
+ switch (event.button.button) {
+ case SDL_BUTTON_LEFT:
+ ui_mousel_down(event.button.x, event.button.y);
+ break;
+ case SDL_BUTTON_RIGHT:
+ break;
+ }
+ break;
+ case SDL_MOUSEBUTTONUP:
+ switch (event.button.button) {
+ case SDL_BUTTON_LEFT:
+ ui_mousel_up(event.button.x, event.button.y);
+ is_drawing = 0;
+ break;
+ }
+ break;
+ case SDL_MOUSEMOTION:
+ mouseX = event.motion.x;
+ mouseY = event.motion.y;
+ ui_mouse_move(mouseX, mouseY);
+ break;
+ case SDL_KEYDOWN:
+ keypress(&event.key.keysym);
+ break;
+ }
+ }
+
+ if (r)
+ ui_resize();
+
+ SDL_SetRenderDrawColor(ren, INTTOCOL(back_c), 255);
+ SDL_RenderClear(ren);
+ ui_present();
+ SDL_RenderPresent(ren);
+
+ if (q)
+ return main_quit();
+ return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+ Uint32 ltick, fdif;
+
+ if (main_window_init(argc > 1 ? argv[1] : NULL))
+ return 1;
+
+ fdif = 1000 / fps;
+ while (1) {
+ ltick = SDL_GetTicks();
+ if (main_event_handle())
+ break;
+ ltick = SDL_GetTicks() - ltick;
+
+ if (ltick < fdif)
+ SDL_Delay(fdif-ltick);
+ }
+
+#ifdef F_MEMORY_DEBUG
+ f_debug_mem_show();
+#endif
+}
diff --git a/src/cdraw.h b/src/cdraw.h
new file mode 100644
index 0000000..0f57a7f
--- /dev/null
+++ b/src/cdraw.h
@@ -0,0 +1,35 @@
+typedef union {
+ int i;
+ unsigned int u;
+ float f;
+ const void *v;
+ const char *s;
+} Arg;
+
+extern SDL_Window *win;
+extern void *ren;
+extern void *def_palette;
+extern const char *def_palette_path;
+extern int mouseX, mouseY;
+extern const unsigned int back_c;
+
+unsigned int main_event_handle();
+unsigned int main_window_init();
+unsigned int main_quit();
+
+/* Functions for user bind to something else */
+void user_canvas_zoom_change(const Arg *);
+void user_canvas_move_x(const Arg *);
+void user_canvas_move_y(const Arg *);
+void user_canvas_save(const Arg *);
+void user_canvas_open(const Arg *);
+void user_canvas_export_png(const Arg *);
+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_tool_change(const Arg *);
+void user_layer_chng(const Arg *);
+void user_testing_layer_add(const Arg *);
+void user_testing_reload_tex(const Arg *);
+void user_debug_mem_show(const Arg *);
diff --git a/src/config.h b/src/config.h
new file mode 100644
index 0000000..e1a954a
--- /dev/null
+++ b/src/config.h
@@ -0,0 +1,34 @@
+#define COLTOINT(R,G,B) (R<<16)+(G<<8)+B
+
+const unsigned int maxzoom = 20;
+const unsigned int fps = 30;
+const char *def_palette_path = "assets/default.gpl";
+const char *def_theme_file = "assets/ui.png";
+const unsigned int back_c = COLTOINT(146, 161, 185);
+
+static Key keys[] = {
+ /* modifier key function argument */
+ {0, SDLK_EQUALS, user_canvas_zoom_change, {.i = 1}},
+ {0, SDLK_MINUS, user_canvas_zoom_change, {.i = -1}},
+ {0, SDLK_UP, user_canvas_move_y, {.i = 10}},
+ {0, SDLK_DOWN, user_canvas_move_y, {.i = -10}},
+ {0, SDLK_LEFT, user_canvas_move_x, {.i = 10}},
+ {0, SDLK_RIGHT, user_canvas_move_x, {.i = -10}},
+ {0, SDLK_s, user_canvas_save, {.v = NULL}},
+ {0, SDLK_r, user_canvas_refresh, {.v = NULL}},
+ {0, SDLK_o, user_canvas_open, {.s = NULL}},
+ {KMOD_LSHIFT, SDLK_e, user_canvas_export_png, {.v = NULL}},
+ {KMOD_LSHIFT, SDLK_i, user_canvas_import_png, {.s = NULL}},
+ {0, SDLK_b, user_tool_change, {.i = 0}},
+ {0, SDLK_e, user_tool_change, {.i = 1}},
+ {0, SDLK_f, user_tool_change, {.i = 2}},
+ {0, SDLK_i, user_tool_change, {.i = 3}},
+ {0, SDLK_n, user_canvas_create_new, {.v = NULL}},
+ {0, SDLK_LEFTBRACKET, user_canvas_pal_col_chng, {.i = -1}},
+ {0, SDLK_RIGHTBRACKET, user_canvas_pal_col_chng, {.i = 1}},
+/* {0, SDLK_j, user_testing_layer_add, {.i = 1}},*/
+ {KMOD_LSHIFT, SDLK_r, user_testing_reload_tex, {.i = 1}},
+/* {KMOD_LSHIFT, SDLK_LEFTBRACKET, user_layer_chng, {.i = -1}},*/
+/* {KMOD_LSHIFT, SDLK_RIGHTBRACKET, user_layer_chng, {.i = 1}},*/
+ {0, SDLK_m, user_debug_mem_show, {.v = NULL}},
+};
diff --git a/src/debug.c b/src/debug.c
new file mode 100644
index 0000000..3f2b85a
--- /dev/null
+++ b/src/debug.c
@@ -0,0 +1,86 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+struct debug_header {
+ const char *f;
+ unsigned int l;
+ size_t s;
+ struct debug_header *next, *prev;
+};
+
+typedef struct debug_header d_header;
+
+d_header *d_head;
+
+void *
+f_debug_mem_malloc(size_t s, const char *f, unsigned int l)
+{
+ d_header *m = malloc(s + sizeof(*m));
+ /* fprintf(stdout, "%s:%u: malloc(%zi)\n", f, l, s); */
+ if (m == NULL) return m;
+ m->f = f;
+ m->l = l;
+ m->s = s;
+ m->next = d_head;
+ if (d_head)
+ m->next->prev = m;
+ m->prev = NULL;
+ d_head = m;
+ return m+1;
+}
+
+void
+f_debug_mem_free(void *s, const char *f, unsigned int l)
+{
+ d_header *m;
+ if (s != NULL) {
+ m = (d_header *)s - 1;
+ m->s = ~m->s;
+
+ if (m->prev == NULL) {
+ assert(d_head == m);
+ d_head = m->next;
+ } else {
+ m->prev->next = m->next;
+ }
+
+ if (m->next) m->next->prev = m->prev;
+ /* fprintf(stdout, "%s:%u: free()\n", f, l); */
+ free(m);
+ }
+}
+
+void *
+f_debug_mem_realloc(void *x, size_t s, const char *f, unsigned int l)
+{
+ d_header *m;
+ void *q;
+ if (x == NULL) {
+ return f_debug_mem_malloc(s, f, l);
+ } else if (s == 0) {
+ f_debug_mem_free(x, f, l);
+ return NULL;
+ } else {
+ m = (d_header *)x - 1;
+ if (s <= m->s) return x;
+ q = f_debug_mem_malloc(s, f, l);
+ if (q) {
+ memcpy(q, x, m->s);
+ f_debug_mem_free(x, f, l);
+ }
+ return q;
+ }
+}
+
+void
+f_debug_mem_show()
+{
+ d_header *m = d_head;
+ while (m) {
+ fprintf(stdout, "%s:%u: %zd bytes at %p\n", m->f, m->l, m->s, (void*)(m+1));
+ m = m->next;
+ }
+}
+
+#include "debug.h"
diff --git a/src/debug.h b/src/debug.h
new file mode 100644
index 0000000..20285c9
--- /dev/null
+++ b/src/debug.h
@@ -0,0 +1,14 @@
+void *f_debug_mem_malloc(size_t, const char *, unsigned int);
+void *f_debug_mem_realloc(void *, size_t, const char *, unsigned int);
+void f_debug_mem_free(void *, const char *, unsigned int);
+void f_debug_mem_show();
+
+#define F_MEMORY_DEBUG
+
+#ifdef F_MEMORY_DEBUG
+
+#define malloc(n) f_debug_mem_malloc(n, __FILE__, __LINE__)
+#define realloc(n,s) f_debug_mem_realloc(n, s, __FILE__, __LINE__)
+#define free(n) f_debug_mem_free(n, __FILE__, __LINE__)
+
+#endif
diff --git a/src/palette.c b/src/palette.c
new file mode 100644
index 0000000..3584e55
--- /dev/null
+++ b/src/palette.c
@@ -0,0 +1,113 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "palette.h"
+#include "debug.h"
+#include "types.h"
+
+Palette *
+palette_clone(const Palette *p)
+{
+ Palette *res;
+
+ /* TODO: better malloc (place list and num together) */
+ res = malloc(sizeof(Palette));
+ res->clist = malloc(p->num*sizeof(*p->clist));
+
+ res->num = p->num;
+ memcpy(res->clist, p->clist, p->num * sizeof(*p->clist));
+
+ return res;
+}
+
+static char *
+palette_intern_get_num(char *s, int *a)
+{
+ while (*s == ' ' || *s == '\t')
+ ++s;
+ if (*s == '\n')
+ *a = -1;
+ else {
+ *a = 0;
+ while (*s >= '0' && *s <= '9') {
+ *a = (*a) * 10;
+ *a += (int) (*s-'0');
+ ++s;
+ }
+ }
+
+ return s;
+}
+
+static uint8
+palette_intern_get_color(char *s, Color *c)
+{
+ int a;
+ char *st = s;
+
+ st = palette_intern_get_num(st, &a);
+ if (a < 0 || a > 255) return 1;
+ c->r = a;
+
+ st = palette_intern_get_num(st, &a);
+ if (a < 0 || a > 255) return 1;
+ c->g = a;
+
+ st = palette_intern_get_num(st, &a);
+ if (a < 0 || a > 255) return 1;
+ c->b = a;
+
+ return 0;
+}
+
+static uint
+palette_intern_get_color_number(const char *s)
+{
+ FILE *fp;
+ char line[1024];
+ size_t len = 1024;
+ uint ans = 0;
+
+ fp = fopen(s, "r");
+ while (fgets(line, len, fp)) {
+ if (line[0] >= '0' && line[0] <= '9')
+ ++ans;
+ }
+ fclose(fp);
+
+ return ans;
+}
+
+Palette *
+palette_open_gpl(const char *p)
+{
+ /* TODO: check if file exists */
+ /* TODO: better parsing */
+ /* TODO: better malloc (place list and num together) */
+ Palette *res;
+ FILE *fp;
+ Color *c;
+ char line[1024];
+ size_t len = 1024;
+
+ res = malloc(sizeof(Palette));
+ res->num = palette_intern_get_color_number(p);
+ res->clist = malloc(res->num*sizeof(*res->clist));
+ c = res->clist;
+
+ fp = fopen(p, "r");
+ while (fgets(line, len, fp)) {
+ if (line[0] >= '0' && line[0] <= '9') {
+ if (palette_intern_get_color(line, c)) {
+ free(res->clist);
+ free(res);
+ return NULL;
+ }
+ c++;
+ }
+ }
+ fclose(fp);
+
+ return res;
+}
diff --git a/src/palette.h b/src/palette.h
new file mode 100644
index 0000000..3ac5c93
--- /dev/null
+++ b/src/palette.h
@@ -0,0 +1,15 @@
+struct Color {
+ unsigned char r, g, b;
+};
+
+struct Palette {
+ unsigned int num;
+ struct Color *clist;
+};
+
+typedef struct Color Color;
+typedef struct Palette Palette;
+
+Palette *palette_open_gpl(const char *);
+Palette *palette_clone(const Palette *);
+Palette *palette_open_gpl(const char *);
diff --git a/src/tools.c b/src/tools.c
new file mode 100644
index 0000000..1ff979a
--- /dev/null
+++ b/src/tools.c
@@ -0,0 +1,39 @@
+#include <assert.h>
+
+#include "tools.h"
+#include "types.h"
+#include "canvas.h"
+#include "ui.h"
+
+uint8 tool_cur;
+static uint8 prev_tool;
+
+/* TODO: Move to config.h */
+uint8 tool_array[] = {
+ TOOL_TYPE_PENCIL,
+ TOOL_TYPE_ERASER,
+ TOOL_TYPE_FILL,
+ TOOL_TYPE_CPICKER,
+ TOOL_TYPE_ZOOMOUT,
+ TOOL_TYPE_ZOOMIN,
+ TOOL_TYPE_EMPTY,
+ TOOL_TYPE_CLOWN,
+};
+
+void
+tool_change(uint8 t)
+{
+ if (t != tool_cur) {
+ canvas_mousel_up(cur_canvas);
+ assert(t < tool_array_size());
+ t = (t < tool_array_size()) ? t : tool_array_size() - 1;
+ tool_cur = t;
+ ui_redraw_panel(UI_PANELTYPE_BUTTONS);
+ }
+}
+
+uint8
+tool_array_size()
+{
+ return (sizeof tool_array / sizeof *tool_array);
+}
diff --git a/src/tools.h b/src/tools.h
new file mode 100644
index 0000000..c18afe3
--- /dev/null
+++ b/src/tools.h
@@ -0,0 +1,16 @@
+enum Tool_Types {
+ TOOL_TYPE_PENCIL,
+ TOOL_TYPE_ERASER,
+ TOOL_TYPE_FILL,
+ TOOL_TYPE_ZOOMIN,
+ TOOL_TYPE_ZOOMOUT,
+ TOOL_TYPE_CLOWN,
+ TOOL_TYPE_CPICKER,
+ TOOL_TYPE_EMPTY,
+};
+
+extern unsigned char tool_array[];
+extern unsigned char tool_cur;
+
+void tool_change(unsigned char);
+unsigned char tool_array_size();
diff --git a/src/types.h b/src/types.h
new file mode 100644
index 0000000..dc6789e
--- /dev/null
+++ b/src/types.h
@@ -0,0 +1,11 @@
+#define uint unsigned int
+#define uint8 unsigned char
+#define uint16 uint16_t
+#define uint32 unsigned int
+
+#define COLTOINT(R,G,B) (((unsigned int)R)<<16)|(((unsigned int)G)<<8)|(unsigned int)B
+#define INTTOCOL(C) (C>>16), ((C>>8)%256), (C%256)
+#define COLTOINTA(R,G,B,A) (((COLTOINT(R,G,B)) << 8)|(unsigned int)A)
+#define INTTOCOLA(C) (C>>24), ((C>>16)&0xFF), ((C>>8)&0xFF), (C&0xFF)
+
+#define LENGTH(S) ((sizeof S)/(sizeof S[0]))
diff --git a/src/ui.c b/src/ui.c
new file mode 100644
index 0000000..ccc2de9
--- /dev/null
+++ b/src/ui.c
@@ -0,0 +1,692 @@
+#include <stdio.h>
+#include <assert.h>
+#include <SDL2/SDL.h>
+#include <SDL2/SDL_image.h>
+
+#include "ui.h"
+#include "cdraw.h"
+#include "types.h"
+#include "canvas.h"
+#include "tools.h"
+#include "debug.h"
+#include "palette.h"
+
+#define fpan main_ui->focus_panel
+#define LENGTH(X) (sizeof X / sizeof *X)
+#define MAX(a, b) (((a) > (b)) ? (a) : (b));
+
+static const SDL_Rect ui_frame_rect[] = {
+ {0, 0, 8, 8},
+ {16, 0, 8, 8},
+ {0, 16, 8, 8},
+ {16, 16, 8, 8},
+ {8, 0, 8, 8},
+ {8, 16, 8, 8},
+ {0, 8, 8, 8},
+ {16, 8, 8, 8},
+};
+static const SDL_Rect ui_buttons_rect[] = {
+ {0, 24, 28, 28},
+ {0, 52, 28, 28},
+ {0, 80, 32, 32},
+ /* TODO: y -= 2 all the rects below */
+ {28, 26, 28, 28}, /* Pencil */
+ {28, 54, 28, 28}, /* Eraser */
+ {84, 26, 28, 28}, /* Fill Bucket */
+ {56, 26, 28, 28}, /* Zoom in */
+ {56, 54, 28, 28}, /* Zoom out */
+ {84, 54, 28, 28}, /* Clown */
+ {56, 82, 28, 28}, /* Color Picker */
+};
+
+struct UIPanel {
+ uint8 type, redraw;
+ SDL_Rect geom;
+ SDL_Texture *pres;
+};
+
+struct UIPanelCanvas {
+ UIPanel head;
+ /* Canvas *canv; */
+};
+
+struct UIPanelPalette {
+ UIPanel head;
+};
+
+struct UIPanelButtons {
+ UIPanel head;
+};
+
+struct UIPanelDivider {
+ UIPanel head;
+ UIPanel *x, *y;
+ uint8 st; /* states: (0 bit - hor/vert, 1 bit - ra/lb) */
+ int fw, lw, of;
+};
+
+struct UIPanelTimeline {
+ UIPanel head;
+};
+
+struct UI {
+ SDL_Texture *theme;
+ int w, h;
+ UIPanel *focus_panel;
+ UIPanelDivider p_divs[3];
+ UIPanelCanvas p_canvas;
+ UIPanelPalette p_palette;
+ UIPanelButtons p_buttons;
+ UIPanelTimeline p_timeline;
+};
+
+UI *main_ui;
+
+static UIPanel *ui_focus_panel(int, int);
+static void ui_focus_panel_change(int, int);
+
+/* Panel functions */
+static uint8 ui_panel_init(UIPanel *, uint8);
+static uint8 ui_panel_resize(UIPanel *, int, int, uint, uint);
+static uint8 ui_panel_draw_frame(UIPanel *);
+static uint8 ui_panel_redraw(UIPanel *);
+static uint8 ui_panel_present(UIPanel *);
+
+/* Panel canvas functions */
+static uint8 ui_panel_canvas_init(UIPanelCanvas *);
+static uint8 ui_panel_canvas_redraw(UIPanelCanvas *);
+
+/* Panel palette functions */
+static uint8 ui_panel_palette_init(UIPanelPalette *);
+static uint8 ui_panel_palette_redraw(UIPanelPalette *);
+
+/* Panel buttons functions */
+static uint8 ui_panel_buttons_init(UIPanelButtons *);
+static uint8 ui_panel_buttons_redraw(UIPanelButtons *);
+
+/* Panel timeline functions */
+static uint8 ui_panel_timeline_init(UIPanelTimeline *);
+static uint8 ui_panel_timeline_redraw(UIPanelTimeline *);
+
+/* Panel divider functions */
+static uint8 ui_panel_divider_init(UIPanelDivider *, int, int, int, uint8, UIPanel *, UIPanel *);
+static uint8 ui_panel_divider_resize(UIPanelDivider *, int, int, int, int);
+
+void
+ui_create(const char *path)
+{
+/* TODO: error checking */
+ int i;
+ main_ui = malloc(sizeof *main_ui);
+ main_ui->theme = NULL;
+ main_ui->focus_panel = NULL;
+ main_ui->w = main_ui->h = -1;
+ if (ui_theme_load(path))
+ exit(1);
+
+ SDL_SetTextureBlendMode(main_ui->theme, SDL_BLENDMODE_BLEND);
+
+ ui_panel_canvas_init(&main_ui->p_canvas);
+ ui_panel_palette_init(&main_ui->p_palette);
+ ui_panel_buttons_init(&main_ui->p_buttons);
+ ui_panel_timeline_init(&main_ui->p_timeline);
+
+ /* ui_panel_divider_init(&main_ui->p_divs[0], 5, 10, 100, 1, &main_ui->p_canvas, &main_ui->p_timeline); */
+ ui_panel_divider_init(&main_ui->p_divs[0], 5, 5, 120, 0, &main_ui->p_divs[1], &main_ui->p_divs[2]);
+ ui_panel_divider_init(&main_ui->p_divs[1], 0, 8, 22+31*((tool_array_size()+2)/3), 3, &main_ui->p_palette, &main_ui->p_buttons);
+ ui_panel_divider_init(&main_ui->p_divs[2], 0, 5, 70, 3, &main_ui->p_canvas, &main_ui->p_timeline);
+
+ ui_resize();
+}
+
+void
+ui_destroy()
+{
+ if (main_ui == NULL) return;
+ if (main_ui->theme) SDL_DestroyTexture(main_ui->theme);
+ free(main_ui);
+}
+
+uint8
+ui_resize()
+{
+ static int w, h;
+ if (main_ui == NULL)
+ return 1;
+
+ SDL_GetRendererOutputSize(ren, &w, &h);
+ if (w != main_ui->w || h != main_ui->h) {
+ main_ui->w = w;
+ main_ui->h = h;
+ ui_panel_resize(&main_ui->p_divs[0], 0, 0, w, h);
+ /* ui_panel_resize(&main_ui->p_palette.head, 5, 5, 120, main_ui->h-42-31*((tool_array_size()+2)/3)); */
+ /* ui_panel_resize(&main_ui->p_buttons.head, 5, main_ui->h-27-31*((tool_array_size()+2)/3), 120, 22+31*((tool_array_size()+2)/3)); */
+ /* ui_panel_resize(&main_ui->p_canvas.head, 130, 5, main_ui->w - 135, main_ui->h-85); */
+ /* ui_panel_resize(&main_ui->p_timeline.head, 130, main_ui->h-75, main_ui->w - 135,70); */
+ ui_redraw();
+ }
+ return 0;
+}
+
+void
+ui_redraw()
+{
+ main_ui->p_canvas.head.redraw = 1;
+ main_ui->p_palette.head.redraw = 1;
+ main_ui->p_buttons.head.redraw = 1;
+ main_ui->p_timeline.head.redraw = 1;
+}
+
+void
+ui_redraw_panel(uint8 type)
+{
+ switch (type) {
+ case UI_PANELTYPE_PALETTE:
+ main_ui->p_palette.head.redraw = 1;
+ break;
+ case UI_PANELTYPE_CANVAS:
+ main_ui->p_canvas.head.redraw = 1;
+ break;
+ case UI_PANELTYPE_BUTTONS:
+ main_ui->p_buttons.head.redraw = 1;
+ break;
+ case UI_PANELTYPE_TIMELINE:
+ main_ui->p_timeline.head.redraw = 1;
+ break;
+ default:
+ fprintf(stderr, "%s:%d:ui_redraw_panel: No implementation for %u\n", __FILE__, __LINE__, type);
+ break;
+ }
+}
+
+void
+ui_present()
+{
+ if (main_ui->p_palette.head.redraw)
+ ui_panel_redraw(&main_ui->p_palette.head);
+ if (main_ui->p_canvas.head.redraw)
+ ui_panel_redraw(&main_ui->p_canvas.head);
+ if (main_ui->p_buttons.head.redraw)
+ ui_panel_redraw(&main_ui->p_buttons.head);
+ if (main_ui->p_timeline.head.redraw)
+ ui_panel_redraw(&main_ui->p_timeline.head);
+ ui_panel_present(&main_ui->p_palette.head);
+ ui_panel_present(&main_ui->p_canvas.head);
+ ui_panel_present(&main_ui->p_buttons.head);
+ ui_panel_present(&main_ui->p_timeline.head);
+}
+
+void
+ui_mousel_down(int x, int y)
+{
+ int col;
+ Arg arg;
+ ui_focus_panel_change(x, y);
+
+ if (main_ui->focus_panel == NULL)
+ return;
+
+ switch (main_ui->focus_panel->type) {
+ case UI_PANELTYPE_CANVAS:
+ if (cur_canvas != NULL) {
+ canvas_mousel_down(cur_canvas,
+ x - fpan->geom.x - 8,
+ y - fpan->geom.y - 8);
+ fpan->redraw = 1;
+ }
+ break;
+ case UI_PANELTYPE_PALETTE:
+ if (cur_canvas == NULL)
+ return;
+ col = (x - fpan->geom.x - 8) / 26;
+ if (col > 3) col = 3;
+ col += (((y - fpan->geom.y - 8) / 26) << 2);
+
+
+ if (col < ((Palette *)def_palette)->num && col >= 0)
+ cur_canvas->cur_col = col;
+ break;
+ case UI_PANELTYPE_BUTTONS:
+
+ /* TODO Better */
+ col = (x - fpan->geom.x - 15) / 30;
+ if (col > 2)
+ break;
+
+ col += 3 * ((y - fpan->geom.y - 2) / 30);
+
+ if (col >= tool_array_size() || col < 0)
+ break;
+ switch (tool_array[col]) {
+ case TOOL_TYPE_ZOOMOUT:
+ /* TODO: user functions must mostly be wrappers for internal fucntions */
+ arg.i = -1;
+ user_canvas_zoom_change(&arg);
+ break;
+ case TOOL_TYPE_ZOOMIN:
+ arg.i = 1;
+ user_canvas_zoom_change(&arg);
+ break;
+ case TOOL_TYPE_CLOWN:
+ fprintf(stdout, "You have been clowned 🤡\n");
+ break;
+ case TOOL_TYPE_EMPTY:
+ break;
+ default:
+ tool_change(col);
+ break;
+ }
+ break;
+ }
+}
+
+void
+ui_mousel_up(int x, int y)
+{
+ ui_focus_panel_change(x, y);
+
+ if (main_ui->focus_panel == NULL)
+ return;
+
+ switch (main_ui->focus_panel->type) {
+ case UI_PANELTYPE_CANVAS:
+ if (cur_canvas != NULL)
+ canvas_mousel_up(cur_canvas);
+ fpan->redraw = 1;
+ break;
+ }
+}
+
+void
+ui_mouse_move(int x, int y)
+{
+ ui_focus_panel_change(x, y);
+
+ if (main_ui->focus_panel == NULL)
+ return;
+
+ switch (main_ui->focus_panel->type) {
+ case UI_PANELTYPE_CANVAS:
+ if (cur_canvas != NULL) {
+ canvas_mouse_move(cur_canvas,
+ x - fpan->geom.x - 8,
+ y - fpan->geom.y - 8);
+ fpan->redraw = 1;
+ }
+ break;
+ }
+}
+
+uint8
+ui_theme_load(const char *path)
+{
+/* TODO: check path */
+ if (main_ui->theme != NULL)
+ SDL_DestroyTexture(main_ui->theme);
+
+ SDL_Surface *surf = IMG_Load(path);
+ if (surf == NULL) return 1;
+ main_ui->theme = SDL_CreateTextureFromSurface(ren, surf);
+ SDL_FreeSurface(surf);
+ if (main_ui->theme == NULL) return 1;
+
+ return 0;
+}
+
+static UIPanel *
+ui_focus_panel(int x, int y)
+{
+ SDL_Rect *r;
+ if (main_ui == NULL) return NULL;
+
+ r = &main_ui->p_palette.head.geom;
+ if (r->x <= x && r->y <= y
+ && x - r->x < r->w && y - r->y < r->h)
+ return &main_ui->p_palette.head;
+
+ r = &main_ui->p_buttons.head.geom;
+ if (r->x <= x && r->y <= y
+ && x - r->x < r->w && y - r->y < r->h)
+ return &main_ui->p_buttons.head;
+
+ r = &main_ui->p_canvas.head.geom;
+ if (r->x <= x && r->y <= y
+ && x - r->x < r->w && y - r->y < r->h)
+ return &main_ui->p_canvas.head;
+
+ return NULL;
+}
+
+static void
+ui_focus_panel_change(int x, int y)
+{
+ UIPanel *u;
+ u = ui_focus_panel(x, y);
+
+ if (u == main_ui->focus_panel)
+ return;
+
+ if (main_ui->focus_panel != NULL) {
+ switch (main_ui->focus_panel->type) {
+ case UI_PANELTYPE_CANVAS:
+ is_drawing = 0;
+ main_ui->focus_panel = u;
+ ui_redraw_panel(UI_PANELTYPE_CANVAS);
+ break;
+ default:
+ break;
+ }
+ }
+
+ main_ui->focus_panel = u;
+}
+
+/* Panel functions */
+static uint8
+ui_panel_init(UIPanel *p, uint8 type)
+{
+ p->pres = NULL;
+ p->type = type;
+ p->redraw = 1;
+ p->geom.w = p->geom.h = 0;
+
+ return 0;
+}
+
+static uint8
+ui_panel_resize(UIPanel *p, int x, int y, uint w, uint h)
+{
+ if (p->type == UI_PANELTYPE_DIVIDER)
+ return ui_panel_divider_resize((UIPanelDivider *)p, x, y, w, h);
+ p->geom.x = x;
+ p->geom.y = y;
+
+ /* assert(w > 16 && h > 16); */
+ if (w < 16 || h < 16)
+ return 1;
+ if (p->geom.w == w && p->geom.h == h)
+ return 0;
+
+ p->geom.w = w;
+ p->geom.h = h;
+
+ if (p->pres != NULL)
+ SDL_DestroyTexture(p->pres);
+
+ p->pres = SDL_CreateTexture(
+ ren, SDL_PIXELFORMAT_RGBA8888,
+ SDL_TEXTUREACCESS_TARGET,
+ w, h);
+
+ SDL_SetTextureBlendMode(p->pres, SDL_BLENDMODE_BLEND);
+
+ return 0;
+}
+
+static uint8
+ui_panel_redraw(UIPanel *p)
+{
+/* TODO: something for paralel threads? */
+/* TODO: Correct switch case intendation(not here) */
+ if (p->pres == NULL)
+ return 1;
+
+ p->redraw = 0;
+
+ SDL_SetRenderTarget(ren, p->pres);
+ SDL_SetRenderDrawColor(ren, 0, 0, 0, 0);
+ SDL_RenderClear(ren);
+ switch (p->type) {
+ case UI_PANELTYPE_CANVAS:
+ ui_panel_canvas_redraw((UIPanelCanvas *)p);
+ break;
+ case UI_PANELTYPE_PALETTE:
+ ui_panel_palette_redraw((UIPanelPalette *)p);
+ break;
+ case UI_PANELTYPE_BUTTONS:
+ ui_panel_buttons_redraw((UIPanelButtons *)p);
+ break;
+ case UI_PANELTYPE_TIMELINE:
+ ui_panel_draw_frame(p);
+ break;
+ default:
+ fprintf(stderr, "%s:%d:ui_panel_redraw: No redraw fuction for %u\n", __FILE__, __LINE__, p->type);
+ break;
+ }
+ SDL_SetRenderTarget(ren, NULL);
+
+ return 0;
+}
+
+static uint8
+ui_panel_draw_frame(UIPanel *p)
+{
+ static SDL_Rect dest;
+ dest.x = 0;
+ dest.y = 0;
+ dest.h = 8;
+ dest.w = p->geom.w;
+ SDL_RenderCopy(ren, main_ui->theme, &ui_frame_rect[4], &dest);
+ dest.y = p->geom.h-8;
+ SDL_RenderCopy(ren, main_ui->theme, &ui_frame_rect[5], &dest);
+ dest.w = 8;
+ dest.h = p->geom.h;
+ dest.y = 0;
+ SDL_RenderCopy(ren, main_ui->theme, &ui_frame_rect[6], &dest);
+ dest.x = p->geom.w-8;
+ SDL_RenderCopy(ren, main_ui->theme, &ui_frame_rect[7], &dest);
+
+ dest.h = 8;
+ SDL_RenderCopy(ren, main_ui->theme, &ui_frame_rect[1], &dest);
+ dest.x = 0;
+ SDL_RenderCopy(ren, main_ui->theme, &ui_frame_rect[0], &dest);
+ dest.y = p->geom.h-8;
+ SDL_RenderCopy(ren, main_ui->theme, &ui_frame_rect[2], &dest);
+ dest.x = p->geom.w-8;
+ SDL_RenderCopy(ren, main_ui->theme, &ui_frame_rect[3], &dest);
+
+ return 0;
+}
+
+static uint8
+ui_panel_present(UIPanel *p)
+{
+ return SDL_RenderCopy(ren, p->pres, NULL, &p->geom);
+}
+
+/* Panel canvas functions */
+static uint8
+ui_panel_canvas_init(UIPanelCanvas *p)
+{
+ return ui_panel_init((UIPanel *)p, UI_PANELTYPE_CANVAS);
+}
+
+static uint8
+ui_panel_canvas_redraw(UIPanelCanvas *p)
+{
+ static SDL_Rect dest;
+ dest.x = 8;
+ dest.y = 8;
+ dest.w = p->head.geom.w - 16;
+ dest.h = p->head.geom.h - 16;
+ SDL_RenderSetViewport(ren, &dest);
+ SDL_SetRenderDrawColor(ren, 18, 18, 18, 255);
+ SDL_RenderClear(ren);
+ if (cur_canvas != NULL) {
+ SDL_RenderSetViewport(ren, NULL);
+ canvas_redraw(cur_canvas, ren,
+ mouseX - p->head.geom.x - 8,
+ mouseY - p->head.geom.y - 8);
+ SDL_SetRenderTarget(ren, p->head.pres);
+ SDL_RenderSetViewport(ren, &dest);
+ canvas_present(cur_canvas, ren);
+ }
+ SDL_RenderSetViewport(ren, NULL);
+ ui_panel_draw_frame(&p->head);
+ return 0;
+}
+
+/* Panel palette functions */
+static uint8
+ui_panel_palette_init(UIPanelPalette *p)
+{
+ return ui_panel_init((UIPanel *)p, UI_PANELTYPE_PALETTE);
+}
+
+static uint8
+ui_panel_palette_redraw(UIPanelPalette *p)
+{
+ static SDL_Rect dest;
+ Palette *pp;
+ int i;
+
+ pp = def_palette;
+ dest.x = 8;
+ dest.y = 8;
+ dest.w = p->head.geom.w - 16;
+ dest.h = p->head.geom.h - 16;
+ SDL_RenderSetViewport(ren, &dest);
+ SDL_SetRenderDrawColor(ren, 18, 18, 18, 255);
+ SDL_RenderClear(ren);
+
+ SDL_SetRenderDrawColor(ren, 0, 0, 0, 255);
+ if (pp != NULL) {
+ dest.x = dest.y = 0;
+ dest.w = 120;
+ if (pp->num > 3) {
+ dest.h = 26 * (pp->num >> 2);
+ SDL_RenderFillRect(ren, &dest);
+ }
+
+ if (pp->num % 4) {
+ dest.w = 26 * (pp->num % 4);
+ dest.h = 26;
+ dest.y = 26 * (pp->num >> 2);
+ SDL_RenderFillRect(ren, &dest);
+ }
+
+ dest.w = dest.h = 24;
+ for (i = 0; i < pp->num; ++i) {
+ dest.x = 1 + (i % 4) * 26;
+ dest.y = 1 + (i / 4) * 26;
+ SDL_SetRenderDrawColor(ren,
+ pp->clist[i].r, pp->clist[i].g,
+ pp->clist[i].b, 255);
+ SDL_RenderFillRect(ren, &dest);
+ }
+ }
+ SDL_RenderSetViewport(ren, NULL);
+ ui_panel_draw_frame(&p->head);
+ return 0;
+}
+
+/* Panel buttons functions */
+static uint8
+ui_panel_buttons_init(UIPanelButtons *p)
+{
+ return ui_panel_init((UIPanel *)p, UI_PANELTYPE_BUTTONS);
+}
+
+static uint8
+ui_panel_buttons_redraw(UIPanelButtons *p)
+{
+ static SDL_Rect dest1;
+ static SDL_Rect dest2;
+ int i;
+
+ dest1.x = 14;
+ dest1.y = 0;
+ dest1.w = p->head.geom.w - 28;
+ dest1.h = p->head.geom.h;
+ SDL_RenderSetViewport(ren, &dest1);
+ SDL_SetRenderDrawColor(ren, INTTOCOL(back_c), 255);
+ SDL_RenderClear(ren);
+ dest1.w = 28;
+ dest1.h = 28;
+ dest2.w = 32;
+ dest2.h = 32;
+ for (i = 0; i < tool_array_size(); ++i) {
+ if (tool_array[i] == TOOL_TYPE_EMPTY) continue;
+ dest1.x = 2 + (i % 3) * 30;
+ dest1.y = 2 + (i / 3) * 30;
+ dest2.x = (i % 3) * 30;
+ dest2.y = (i / 3) * 30;
+ SDL_RenderCopy(ren, main_ui->theme, &ui_buttons_rect[2], &dest2);
+ if (i == tool_cur)
+ SDL_RenderCopy(ren, main_ui->theme, &ui_buttons_rect[0], &dest1);
+ else
+ SDL_RenderCopy(ren, main_ui->theme, &ui_buttons_rect[1], &dest1);
+ SDL_RenderCopy(ren, main_ui->theme, &ui_buttons_rect[tool_array[i]+3], &dest1);
+ }
+ SDL_RenderSetViewport(ren, NULL);
+ /* ui_panel_draw_frame(&p->head); */
+ return 0;
+}
+
+/* Panel timeline functions */
+static uint8
+ui_panel_timeline_init(UIPanelTimeline *p)
+{
+ return ui_panel_init((UIPanel *)p, UI_PANELTYPE_TIMELINE);
+}
+
+/* Panel divider functions */
+static uint8
+ui_panel_divider_init(UIPanelDivider *p, int fw, int lw, int of, uint8 st, UIPanel *p1, UIPanel *p2)
+{
+ ui_panel_init((UIPanel *)p, UI_PANELTYPE_DIVIDER);
+ p->fw = fw;
+ p->lw = lw;
+ p->of = of;
+ p->st = st;
+ p->x = p1;
+ p->y = p2;
+ return 0;
+}
+
+static uint8
+ui_panel_divider_resize(UIPanelDivider *p, int x, int y, int w, int h)
+{
+ SDL_Rect g1, g2;
+ p->head.geom.x = x;
+ p->head.geom.y = y;
+ p->head.geom.w = w;
+ p->head.geom.h = h;
+
+ if (p->st & 1) {
+ /* Horizontal line */
+ g1.w = g2.w = MAX(0, p->head.geom.w - 2 * p->fw);
+
+ if (p->st & 2) {
+ g2.h = p->of;
+ g1.h = MAX(0, p->head.geom.h - 2 * p->fw - p->of - p->lw);
+ } else {
+ g1.h = p->of;
+ g2.h = MAX(0, p->head.geom.h - 2 * p->fw - p->of - p->lw);
+ }
+
+ g1.x = g2.x = x + p->fw;
+ g1.y = y + p->fw;
+ g2.y = y + p->fw + p->lw + g1.h;
+ } else {
+ /* Vertical line */
+ g1.h = g2.h = MAX(0, p->head.geom.h - 2 * p->fw);
+
+ if (p->st & 2) {
+ g2.w = p->of;
+ g1.w = MAX(0, p->head.geom.w - 2 * p->fw - p->of - p->lw);
+ } else {
+ g1.w = p->of;
+ g2.w = MAX(0, p->head.geom.w - 2 * p->fw - p->of - p->lw);
+ }
+
+ g1.y = g2.y = x + p->fw;
+ g1.x = x + p->fw;
+ g2.x = x + p->fw + p->lw + g1.w;
+ }
+
+ ui_panel_resize(p->x, g1.x, g1.y, g1.w, g1.h);
+ ui_panel_resize(p->y, g2.x, g2.y, g2.w, g2.h);
+
+ return 0;
+}
diff --git a/src/ui.h b/src/ui.h
new file mode 100644
index 0000000..19c8881
--- /dev/null
+++ b/src/ui.h
@@ -0,0 +1,36 @@
+enum UI_PanelType {
+ UI_PANELTYPE_CANVAS,
+ UI_PANELTYPE_PALETTE,
+ UI_PANELTYPE_BUTTONS,
+ UI_PANELTYPE_TIMELINE,
+ UI_PANELTYPE_DIVIDER,
+};
+
+struct UI;
+struct UIPanel;
+struct UIPanelCanvas;
+struct UIPanelPalette;
+struct UIPanelButtons;
+struct UIPanelTimeline;
+struct UIPanelDivider;
+
+typedef struct UI UI;
+typedef struct UIPanel UIPanel;
+typedef struct UIPanelCanvas UIPanelCanvas;
+typedef struct UIPanelPalette UIPanelPalette;
+typedef struct UIPanelButtons UIPanelButtons;
+typedef struct UIPanelTimeline UIPanelTimeline;
+typedef struct UIPanelDivider UIPanelDivider;
+
+extern UI *main_ui;
+
+void ui_create(const char *);
+void ui_destroy();
+unsigned char ui_resize();
+void ui_redraw();
+void ui_redraw_panel(unsigned char);
+void ui_present();
+void ui_mousel_up(int, int);
+void ui_mousel_down(int, int);
+void ui_mouse_move(int, int);
+unsigned char ui_theme_load(const char *);
diff --git a/src/user.c b/src/user.c
new file mode 100644
index 0000000..d5a545e
--- /dev/null
+++ b/src/user.c
@@ -0,0 +1,238 @@
+#include <stdio.h>
+#include <string.h>
+#include <SDL2/SDL.h>
+
+#include "ui.h"
+#include "debug.h"
+#undef malloc()
+#undef realloc()
+#undef free()
+#define SDL_Window void
+#include "cdraw.h"
+#include "types.h"
+#include "tools.h"
+#include "canvas.h"
+#include "palette.h"
+
+void
+user_canvas_zoom_change(const Arg *x)
+{
+ if (cur_canvas == NULL) return;
+ int oldzoom = cur_canvas->zoom;
+ canvas_zoom_change(cur_canvas, x->i);
+ /* canvas_move_x(cur_canvas, (oldzoom - (int)cur_canvas->zoom) * (int)cur_canvas->w / 2); */
+ /* canvas_move_y(cur_canvas, (oldzoom - (int)cur_canvas->zoom) * (int)cur_canvas->h / 2); */
+ ui_redraw_panel(UI_PANELTYPE_CANVAS);
+}
+
+void
+user_canvas_move_x(const Arg *x)
+{
+ if (cur_canvas == NULL) return;
+ canvas_move_x(cur_canvas, x->i);
+ ui_redraw_panel(UI_PANELTYPE_CANVAS);
+}
+
+void
+user_canvas_move_y(const Arg *x)
+{
+ if (cur_canvas == NULL) return;
+ canvas_move_y(cur_canvas, x->i);
+ ui_redraw_panel(UI_PANELTYPE_CANVAS);
+}
+
+void
+user_canvas_save(const Arg *x)
+{
+ char line[1024];
+ if (cur_canvas == NULL) return;
+ if (cur_canvas->proj_path != NULL)
+ goto SAVENONSP;
+ printf("Project File Name (save): ");
+ fflush(stdout);
+
+ do {
+ fgets(line, 1024, stdin);
+ } while (strlen(line) < 4);
+ line[strcspn(line, "\n")] = '\0';
+ printf("Saved project to file %s\n", line);
+ canvas_save(cur_canvas, line, 1);
+ return;
+SAVENONSP:
+ canvas_save(cur_canvas, cur_canvas->proj_path, 0);
+ printf("Saved project to file %s\n", cur_canvas->proj_path);
+}
+
+void
+user_canvas_open(const Arg *x)
+{
+ char line[1024];
+ canvas_destroy(cur_canvas);
+
+ if (x->s == NULL) {
+ printf("File Name (open): ");
+ fflush(stdout);
+
+ do {
+ fgets(line, 1024, stdin);
+ } while (strlen(line) < 4);
+ line[strcspn(line, "\n")] = '\0';
+ cur_canvas = canvas_open(line, ren);
+ } else {
+ cur_canvas = canvas_open(x->s, ren);
+ }
+
+/* TODO: show error window */
+ if (cur_canvas == NULL)
+ puts("Error opening file");
+ ui_redraw_panel(UI_PANELTYPE_CANVAS);
+}
+
+void
+user_canvas_export_png(const Arg *x)
+{
+ char line[1024];
+ if (cur_canvas == NULL) return;
+ printf("File Name (export): ");
+ fflush(stdout);
+
+ do {
+ fgets(line, 1024, stdin);
+ } while (strlen(line) < 4);
+ line[strcspn(line, "\n")] = '\0';
+/* TODO: show error window */
+ if (canvas_export_png(cur_canvas, line, ren))
+ puts("Error while saving file");
+ else
+ puts("File saved");
+}
+
+void
+user_canvas_refresh(const Arg *x)
+{
+ if (cur_canvas == NULL) return;
+ puts("Refreshed canvas");
+ canvas_refresh(cur_canvas);
+ ui_redraw_panel(UI_PANELTYPE_CANVAS);
+}
+
+void
+user_canvas_create_new(const Arg *x)
+{
+ int w, h;
+ printf("Width: ");
+ fflush(stdout);
+ scanf("%d", &w);
+ printf("Height: ");
+ fflush(stdout);
+ scanf("%d", &h);
+ if (cur_canvas != NULL)
+ canvas_destroy(cur_canvas);
+
+ cur_canvas = canvas_init(w, h, ren);
+ ui_redraw_panel(UI_PANELTYPE_CANVAS);
+}
+
+void
+user_canvas_import_png(const Arg *x)
+{
+ char line[1024];
+ canvas_destroy(cur_canvas);
+
+ if (x->s == NULL) {
+ printf("File Name (i): ");
+ fflush(stdout);
+
+ do {
+ fgets(line, 1024, stdin);
+ } while (strlen(line) < 4);
+ line[strcspn(line, "\n")] = '\0';
+ cur_canvas = canvas_import_png(line, ren);
+ } else {
+ cur_canvas = canvas_import_png(x->s, ren);
+ }
+
+/* TODO: show error window */
+ if (cur_canvas == NULL)
+ puts("Error opening file");
+ ui_redraw_panel(UI_PANELTYPE_CANVAS);
+}
+
+void
+user_canvas_pal_col_chng(const Arg *x)
+{
+ cur_canvas->cur_col += ((Palette*)def_palette)->num;
+ cur_canvas->cur_col += x->i;
+ cur_canvas->cur_col %= ((Palette*)def_palette)->num;
+ ui_redraw_panel(UI_PANELTYPE_CANVAS);
+}
+
+void
+user_tool_change(const Arg *x)
+{
+ tool_change(x->i);
+}
+
+void
+user_testing_layer_add(const Arg *x)
+{
+/* TODO: temp function */
+ canvas_add_layer(cur_canvas, -1);
+ fprintf(stdout, "%s:%u: added layer\n", __FILE__, __LINE__);
+ cur_canvas->cur_layer = cur_canvas->layer_arr_cnt-1;
+}
+
+void
+user_layer_chng(const Arg *x)
+{
+ cur_canvas->cur_layer += (unsigned int)cur_canvas->layer_arr_cnt;
+ cur_canvas->cur_layer += x->i;
+ cur_canvas->cur_layer %= cur_canvas->layer_arr_cnt;
+
+ fprintf(stdout, "%s:%u: changed to layer %u\n", __FILE__, __LINE__, cur_canvas->cur_layer);
+ ui_redraw_panel(UI_PANELTYPE_CANVAS);
+}
+
+void
+user_debug_mem_show(const Arg *x)
+{
+ fprintf(stdout, "DEBUG INFO:\n");
+ f_debug_mem_show();
+}
+
+void
+user_testing_reload_tex(const Arg *_x)
+{
+/* TODO: temp function */
+ /* ui_redraw(); */
+ /* return; */
+ SDL_Rect dest;
+ int i;
+ long int x, y;
+
+ if (cur_canvas == NULL) return;
+ dest.x = dest.y = 0;
+ dest.w = cur_canvas->w * 2;
+ dest.h = cur_canvas->h * 2;
+
+ SDL_DestroyTexture(*((void **)main_ui));
+
+ *((void **)main_ui) = SDL_CreateTexture( ren, SDL_PIXELFORMAT_RGBA8888,
+ SDL_TEXTUREACCESS_TARGET, dest.w, dest.h);
+ SDL_SetTextureBlendMode(*((void **)main_ui), SDL_BLENDMODE_BLEND);
+ SDL_SetRenderTarget(ren, *((void **)main_ui));
+
+ for (x = 0; x < cur_canvas->w; ++x) {
+ for (y = 0; y < cur_canvas->h; ++y) {
+ SDL_SetRenderDrawColor(ren, INTTOCOLA(cur_canvas->pres_pix[x + y * cur_canvas->w]));
+ SDL_RenderDrawPoint(ren, 2*x, 2*y);
+ SDL_RenderDrawPoint(ren, 2*x+1, 2*y);
+ SDL_RenderDrawPoint(ren, 2*x+1, 2*y+1);
+ SDL_RenderDrawPoint(ren, 2*x, 2*y+1);
+ }
+ }
+
+ SDL_SetRenderTarget(ren, NULL);
+ ui_redraw();
+}
+