~rabbits/dotgrid

d3c17bb909666c230d009e59078015bfe46ff16c — neauoire 2 years ago 2177caf
Some progress on path thickness and that sort of things
3 files changed, 130 insertions(+), 41 deletions(-)

M README.md
M dotgrid.c
D exed-output-selection.c
M README.md => README.md +5 -0
@@ 54,3 54,8 @@ To resume working on a shape:

- `mouse1` Add point
- `mouse2` Remove point

## TODOs

- use fscan to parse file
- re-implement transforms starting from the end of the paths.

M dotgrid.c => dotgrid.c +125 -40
@@ 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) {

D exed-output-selection.c => exed-output-selection.c +0 -1
@@ 1,1 0,0 @@
{0x02, 0x06, 0x0e, 0x1e, 0x3e, 0x7e, 0xfe, 0x00}
\ No newline at end of file