@@ 31,7 31,7 @@ typedef struct {
} Point2d;
typedef struct {
- int color, selection;
+ int size, color, selection;
Point2d *touch, origin;
} Brush;
@@ 46,10 46,17 @@ typedef enum {
TRIANGLE
} LineType;
+typedef enum {
+ SQUARE,
+ ROUND,
+ DIAGONAL
+} LineCap;
+
typedef struct {
- int color, len;
+ int size, color, len;
Point2d points[256];
LineType type;
+ LineCap cap;
} Path2d;
typedef struct {
@@ 85,7 92,10 @@ Uint8 icons[][8] = {
{0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e, 0xfe, 0x00}, /* triangle */
{0x00, 0x00, 0x00, 0x82, 0x44, 0x38, 0x00, 0x00}, /* eye open */
{0x00, 0x38, 0x44, 0x92, 0x28, 0x10, 0x00, 0x00}, /* eye closed */
- {0x10, 0x54, 0x28, 0xc6, 0x28, 0x54, 0x10, 0x00} /* unsaved */
+ {0x10, 0x54, 0x28, 0xc6, 0x28, 0x54, 0x10, 0x00}, /* unsaved */
+ {0x16, 0x16, 0x76, 0xce, 0xbc, 0xb0, 0xb0, 0x00}, /* cap:round */
+ {0x16, 0x16, 0xf6, 0x86, 0xbe, 0xb0, 0xb0, 0x00}, /* cap:square */
+ {0x16, 0x14, 0x2c, 0x28, 0x58, 0x50, 0xb0, 0x00} /* cap:diagonal */
};
SDL_Window *gWindow = NULL;
@@ 140,6 150,12 @@ equ2d(Point2d *a, Point2d *b)
}
int
+dis2d(Point2d *a, Point2d *b)
+{
+ return (b->x - a->x) * (b->x - a->x) + (b->y - a->y) * (b->y - a->y);
+}
+
+int
cpos(char *s, char c)
{
int i = 0;
@@ 225,6 241,14 @@ colortheme(Uint32 hex)
return 0;
}
+Path2d *
+getselection(void)
+{
+ if(shape.len < 1)
+ return NULL;
+ return &shape.paths[brush.selection];
+}
+
#pragma mark - Draw
void
@@ 256,13 280,30 @@ putpixel(Uint32 *dst, int x, int y, int color)
}
void
-line(Uint32 *dst, int ax, int ay, int bx, int by, int color)
+putcap(Uint32 *dst, int x, int y, LineCap cap, int size, int color)
+{
+ int w, h;
+ Point2d a = Pt2d(x, y);
+ for(h = 0; h < size; ++h)
+ for(w = 0; w < size; ++w) {
+ Point2d b = Pt2d(x - size / 2 + w, y - size / 2 + h);
+ if(cap == ROUND && dis2d(&a, &b) < size)
+ putpixel(dst, b.x, b.y, color);
+ else if(cap == DIAGONAL && (h == w || h == w + 1))
+ putpixel(dst, b.x, b.y, color);
+ else if(cap == SQUARE)
+ putpixel(dst, b.x, b.y, color);
+ }
+}
+
+void
+line(Uint32 *dst, int ax, int ay, int bx, int by, LineCap cap, int size, int color)
{
int dx = abs(bx - ax), sx = ax < bx ? 1 : -1;
int dy = -abs(by - ay), sy = ay < by ? 1 : -1;
int err = dx + dy, e2;
for(;;) {
- putpixel(dst, ax, ay, color);
+ putcap(dst, ax, ay, cap, size, color);
if(ax == bx && ay == by)
break;
e2 = 2 * err;
@@ 278,7 319,7 @@ line(Uint32 *dst, int ax, int ay, int bx, int by, int color)
}
void
-ellipse(Uint32 *dst, int x0, int y0, int x1, int y1, int cadran, int color)
+ellipse(Uint32 *dst, int x0, int y0, int x1, int y1, int cadran, LineCap cap, int size, int color)
{
int a = abs(x1 - x0), b = abs(y1 - y0), b1 = b & 1;
int dx = 4 * (1.0 - a) * b * b, dy = 4 * (b1 + 1) * a * a;
@@ 295,13 336,13 @@ ellipse(Uint32 *dst, int x0, int y0, int x1, int y1, int cadran, int color)
b1 = 8 * b * b;
do {
if(cadran == -1 || cadran == 1)
- putpixel(dst, x1, y0, color);
+ putcap(dst, x1, y0, cap, size, color);
if(cadran == -1 || cadran == 2)
- putpixel(dst, x0, y0, color);
+ putcap(dst, x0, y0, cap, size, color);
if(cadran == -1 || cadran == 3)
- putpixel(dst, x0, y1, color);
+ putcap(dst, x0, y1, cap, size, color);
if(cadran == -1 || cadran == 0)
- putpixel(dst, x1, y1, color);
+ putcap(dst, x1, y1, cap, size, color);
e2 = 2 * err;
if(e2 <= dy) {
y0++;
@@ 317,7 358,7 @@ ellipse(Uint32 *dst, int x0, int y0, int x1, int y1, int cadran, int color)
}
void
-arc(Uint32 *dst, int x0, int y0, int x1, int y1, int x2, int y2, int color)
+arc(Uint32 *dst, int x0, int y0, int x1, int y1, int x2, int y2, LineCap cap, int size, int color)
{
int cadran, col = (y1 - y0) * (x2 - x1) - (y2 - y1) * (x1 - x0);
x1 = x2;
@@ 363,25 404,25 @@ arc(Uint32 *dst, int x0, int y0, int x1, int y1, int x2, int y2, int color)
cadran = 1;
}
}
- ellipse(dst, x0, y0, x1, y1, cadran, color);
+ ellipse(dst, x0, y0, x1, y1, cadran, cap, size, color);
}
void
-rectangle(Uint32 *dst, int x0, int y0, int x1, int y1, int color)
+rectangle(Uint32 *dst, int x0, int y0, int x1, int y1, LineCap cap, int size, int color)
{
- line(dst, x0, y0, x0, y1, color);
- line(dst, x0, y1, x1, y1, color);
- line(dst, x1, y1, x1, y0, color);
- line(dst, x1, y0, x0, y0, color);
+ line(dst, x0, y0, x0, y1, cap, size, color);
+ line(dst, x0, y1, x1, y1, cap, size, color);
+ line(dst, x1, y1, x1, y0, cap, size, color);
+ line(dst, x1, y0, x0, y0, cap, size, color);
}
void
handle(Uint32 *dst, int x0, int y0, int r, int color)
{
- line(dst, x0, y0 - r, x0 + r, y0, color);
- line(dst, x0 + r, y0, x0, y0 + r, color);
- line(dst, x0, y0 + r, x0 - r, y0, color);
- line(dst, x0 - r, y0, x0, y0 - r, color);
+ line(dst, x0, y0 - r, x0 + r, y0, SQUARE, 1, color);
+ line(dst, x0 + r, y0, x0, y0 + r, SQUARE, 1, color);
+ line(dst, x0, y0 + r, x0 - r, y0, SQUARE, 1, color);
+ line(dst, x0 - r, y0, x0, y0 - r, SQUARE, 1, color);
}
int
@@ 397,7 438,7 @@ intri2d(Point2d p, Point2d p0, Point2d p1, Point2d p2)
}
void
-triangle(Uint32 *dst, int x0, int y0, int x1, int y1, int x2, int y2, int color)
+triangle(Uint32 *dst, int x0, int y0, int x1, int y1, int x2, int y2, LineCap cap, int size, int color)
{
int minx = (x0 <= x1 && x0 <= x2) ? x0 : (x1 <= x0 && x1 <= x2) ? x1
: x2;
@@ 411,7 452,7 @@ triangle(Uint32 *dst, int x0, int y0, int x1, int y1, int x2, int y2, int color)
for(y = miny; y < maxy; ++y)
for(x = minx; x < maxx; ++x)
if(intri2d(Pt2d(x, y), Pt2d(x0, y0), Pt2d(x1, y1), Pt2d(x2, y2)))
- putpixel(dst, x, y, color);
+ putcap(dst, x, y, cap, size, color);
}
void
@@ 419,13 460,13 @@ arrow(Uint32 *dst, int x0, int y0, int x1, int y1, int color)
{
int Par = 8;
double slopy = atan2((y1 - y0), (x1 - x0)), cosy = cos(slopy), siny = sin(slopy);
- line(dst, x1, y1, x0, y0, color);
- line(dst, x1, y1, x1 + (int)(-Par * cosy - (Par / 2.0 * siny)), y1 + (int)(-Par * siny + (Par / 2.0 * cosy)), color);
- line(dst, x1, y1, x1 + (int)(-Par * cosy + (Par / 2.0 * siny)), y1 - (int)(Par / 2.0 * cosy + Par * siny), color);
+ line(dst, x1, y1, x0, y0, SQUARE, 1, color);
+ line(dst, x1, y1, x1 + (int)(-Par * cosy - (Par / 2.0 * siny)), y1 + (int)(-Par * siny + (Par / 2.0 * cosy)), SQUARE, 1, color);
+ line(dst, x1, y1, x1 + (int)(-Par * cosy + (Par / 2.0 * siny)), y1 - (int)(Par / 2.0 * cosy + Par * siny), SQUARE, 1, color);
}
void
-bezier(Uint32 *dst, int x0, int y0, int x1, int y1, int x2, int y2, int color)
+bezier(Uint32 *dst, int x0, int y0, int x1, int y1, int x2, int y2, LineCap cap, int size, int color)
{
int i, segs = 8;
Point2d prev = Pt2d(x0, y0);
@@ 433,7 474,7 @@ bezier(Uint32 *dst, int x0, int y0, int x1, int y1, int x2, int y2, int color)
Point2d a = mid2d(Pt2d(x0, y0), Pt2d(x1, y1), i, segs);
Point2d b = mid2d(Pt2d(x1, y1), Pt2d(x2, y2), i, segs);
Point2d c = mid2d(a, b, i, segs);
- line(dst, prev.x, prev.y, c.x, c.y, color);
+ line(dst, prev.x, prev.y, c.x, c.y, cap, size, color);
prev = c;
}
}
@@ 454,11 495,11 @@ drawpath(Uint32 *dst, Path2d *path, int guides)
if(j < path->len - 1) {
Point2d b = add2d(&path->points[j + 1], &brush.origin);
if(path->type == LINE)
- line(dst, a.x, a.y, b.x, b.y, path->color);
+ line(dst, a.x, a.y, b.x, b.y, path->cap, path->size, path->color);
else if(path->type == RECTANGLE)
- rectangle(dst, a.x, a.y, b.x, b.y, path->color);
+ rectangle(dst, a.x, a.y, b.x, b.y, path->cap, path->size, path->color);
else if(path->type == ELLIPSE)
- ellipse(dst, a.x, a.y, b.x, b.y, -1, path->color);
+ ellipse(dst, a.x, a.y, b.x, b.y, -1, path->cap, path->size, path->color);
else if(path->type == TRANSLATE) {
setpt2d(&brush.origin, brush.origin.x + b.x - a.x, brush.origin.y + b.y - a.y);
if(GUIDES)
@@ 469,16 510,16 @@ drawpath(Uint32 *dst, Path2d *path, int guides)
Point2d b = add2d(&path->points[j + 1], &brush.origin);
Point2d c = add2d(&path->points[j + 2], &brush.origin);
if(path->type == ARC)
- arc(dst, a.x, a.y, b.x, b.y, c.x, c.y, path->color);
+ arc(dst, a.x, a.y, b.x, b.y, c.x, c.y, path->cap, path->size, path->color);
else if(path->type == BEZIER)
- bezier(dst, a.x, a.y, b.x, b.y, c.x, c.y, path->color);
+ bezier(dst, a.x, a.y, b.x, b.y, c.x, c.y, path->cap, path->size, path->color);
else if(path->type == TRIANGLE)
- triangle(dst, a.x, a.y, b.x, b.y, c.x, c.y, path->color);
+ triangle(dst, a.x, a.y, b.x, b.y, c.x, c.y, path->cap, path->size, path->color);
if(path->type == ARC || path->type == BEZIER)
j++;
}
if(path->type == POINT)
- putpixel(dst, a.x, a.y, path->color);
+ putcap(dst, a.x, a.y, path->cap, path->size, path->color);
}
for(j = 0; j < path->len; ++j)
if(guides)
@@ 515,6 556,7 @@ drawui(Uint32 *dst)
{
int clr = brush.selection >= 0 ? shape.paths[brush.selection].color : 1;
int bottom = VER * 8 + 8;
+ Path2d *selection = getselection();
drawicn(dst, 0, bottom, icons[clr == 1 ? 1 : 0], 1, 0);
drawicn(dst, 1 * 8, bottom, icons[clr == 2 ? 1 : 0], 2, 0);
drawicn(dst, 2 * 8, bottom, icons[clr == 3 ? 1 : 0], 3, 0);
@@ 524,7 566,16 @@ drawui(Uint32 *dst)
drawicn(dst, 7 * 8, bottom, icons[5], cancast(RECTANGLE) ? 2 : 3, 0);
drawicn(dst, 8 * 8, bottom, icons[1], cancast(ELLIPSE) ? 2 : 3, 0);
drawicn(dst, 9 * 8, bottom, icons[8], cancast(TRIANGLE) ? 2 : 3, 0);
- drawicn(dst, 12 * 8, bottom, icons[GUIDES ? 10 : 9], GUIDES ? 1 : 2, 0);
+ if(selection) {
+ drawicn(dst, 11 * 8, bottom, icons[12], selection->cap == ROUND ? 1 : 2, 0);
+ drawicn(dst, 12 * 8, bottom, icons[13], selection->cap == SQUARE ? 1 : 2, 0);
+ drawicn(dst, 13 * 8, bottom, icons[14], selection->cap == DIAGONAL ? 1 : 2, 0);
+ } else {
+ drawicn(dst, 11 * 8, bottom, icons[12], 3, 0);
+ drawicn(dst, 12 * 8, bottom, icons[13], 3, 0);
+ drawicn(dst, 13 * 8, bottom, icons[14], 3, 0);
+ }
+ drawicn(dst, 16 * 8, bottom, icons[GUIDES ? 10 : 9], GUIDES ? 1 : 2, 0);
drawicn(dst, (HOR - 1) * 8, bottom, icons[11], doc.unsaved ? 2 : 3, 0); /* save state */
}
@@ 542,12 593,15 @@ redraw(Uint32 *dst)
/* draw stack */
for(i = 0; i < stack.len; ++i) {
Point2d *a = &stack.points[i];
- handle(dst, a->x, a->y, 2, brush.color + 1);
if(i < stack.len - 1) {
Point2d *b = &stack.points[i + 1];
- line(dst, a->x, a->y, b->x, b->y, 4);
+ line(dst, a->x, a->y, b->x, b->y, SQUARE, 1, 4);
}
}
+ for(i = 0; i < stack.len; ++i) {
+ Point2d *a = &stack.points[i];
+ handle(dst, a->x, a->y, 2, brush.color + 1);
+ }
drawui(dst);
SDL_UpdateTexture(gTexture, NULL, dst, WIDTH * sizeof(Uint32));
SDL_RenderClear(gRenderer);
@@ 734,8 788,10 @@ cast(LineType type)
shape.paths[shape.len].len = stack.len;
for(i = 0; i < shape.paths[shape.len].len; ++i)
setpt2d(&shape.paths[shape.len].points[i], stack.points[i].x, stack.points[i].y);
+ shape.paths[shape.len].size = brush.size;
shape.paths[shape.len].color = brush.color;
- shape.paths[shape.len++].type = type;
+ shape.paths[shape.len].type = type;
+ shape.paths[shape.len++].cap = SQUARE;
cancel();
}
@@ 766,6 822,25 @@ setcolor(int c)
}
void
+setbrushsize(int c)
+{
+ if(brush.selection >= 0)
+ shape.paths[brush.selection].size = c;
+ brush.size = c;
+ redraw(pixels);
+}
+
+void
+setcap(LineCap cap)
+{
+ Path2d *sel = getselection();
+ if(sel) {
+ sel->cap = cap;
+ redraw(pixels);
+ }
+}
+
+void
loadtxt(FILE *f)
{
char line[256], query[256];
@@ 826,7 901,12 @@ selectoption(int option)
case 7: cast(RECTANGLE); break;
case 8: cast(ELLIPSE); break;
case 9: cast(TRIANGLE); break;
- case 12: savemode(&GUIDES, !GUIDES); break;
+
+ case 11: setcap(ROUND); break;
+ case 12: setcap(SQUARE); break;
+ case 13: setcap(DIAGONAL); break;
+
+ case 16: savemode(&GUIDES, !GUIDES); break;
}
}
@@ 904,8 984,12 @@ dokey(SDL_Event *event)
case SDLK_a: cast(LINE); break;
case SDLK_s: cast(ARC); break;
case SDLK_d: cast(BEZIER); break;
+ case SDLK_z: setbrushsize(brush.size + (brush.size > 1 ? -1 : 0)); break;
+ case SDLK_x: setbrushsize(brush.size + (brush.size < 32 ? 1 : 0)); break;
+ /*
case SDLK_z: cast(POINT); break;
case SDLK_x: cast(RECTANGLE); break;
+ */
case SDLK_c: cast(ELLIPSE); break;
case SDLK_v: cast(TRANSLATE); break;
case SDLK_t: cast(TRIANGLE); break;
@@ 951,6 1035,7 @@ main(int argc, char *argv[])
return error("Init", "Failure");
if(argc > 1)
loadtxt(fopen(argv[1], "r"));
+ brush.size = 1;
cancel();
setcolor(1);
while(1) {