~rabbits/dotgrid

c771d92540f7e89b77bbb7c82aae0f76ab59a88a — neauoire 2 years ago 38c7e01
Started standardization
2 files changed, 183 insertions(+), 180 deletions(-)

M build.sh
M dotgrid.c
M build.sh => build.sh +2 -2
@@ 7,10 7,10 @@ clang-format -i dotgrid.c
rm ./dotgrid

# debug(slow)
# cc -std=c89 -DDEBUG -Wall -Wpedantic -Wshadow -Wextra -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=int-conversion -Wvla -g -Og -fsanitize=address -fsanitize=undefined dotgrid.c -L/usr/local/lib -lSDL2 -lm -o dotgrid
cc -std=c89 -DDEBUG -Wall -Wno-unknown-pragmas -Wpedantic -Wshadow -Wextra -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=int-conversion -Wvla -g -Og -fsanitize=address -fsanitize=undefined dotgrid.c -L/usr/local/lib -lSDL2 -lm -o dotgrid

# build(fast)
cc dotgrid.c -std=c89 -Os -DNDEBUG -g0 -s -Wall -L/usr/local/lib -lSDL2 -lm -o dotgrid
# cc dotgrid.c -std=c89 -Os -DNDEBUG -g0 -s -Wall -Wno-unknown-pragmas -L/usr/local/lib -lSDL2 -lm -o dotgrid

# Size
echo "Size: $(du -sk ./dotgrid)"

M dotgrid.c => dotgrid.c +181 -178
@@ 15,12 15,18 @@ WITH REGARD TO THIS SOFTWARE.

#define HOR 32
#define VER 16
#define PAD 8
#define PAD 2
#define SZ (HOR * VER * 16)

typedef unsigned char Uint8;

typedef struct {
	int unsaved;
	char name[256];
	Uint8 data[SZ];
} Document;

typedef struct {
	int x, y;
} Point2d;



@@ 50,16 56,15 @@ typedef struct {
	Path2d paths[256];
} Shape2d;

Document doc;
Path2d stack;
Shape2d shape;
Brush brush;

int WIDTH = 8 * HOR + PAD * 2;
int HEIGHT = 8 * (VER + 2) + PAD * 2;
int WIDTH = 8 * HOR + 8 * PAD * 2;
int HEIGHT = 8 * (VER + 2) + 8 * PAD * 2;
int FPS = 30, GUIDES = 1, ZOOM = 2;

/* Interface */

Uint32 theme[] = {
	0x000000,
	0xFFFFFF,


@@ 77,7 82,8 @@ Uint8 icons[][8] = {
	{0x1e, 0x06, 0x0a, 0x12, 0x20, 0x40, 0x80, 0x00},
	{0x06, 0x18, 0x22, 0x40, 0x42, 0x80, 0xaa, 0x00},
	{0x00, 0x00, 0x00, 0x82, 0x44, 0x38, 0x00, 0x00}, /* eye open */
	{0x00, 0x38, 0x44, 0x92, 0x28, 0x10, 0x00, 0x00}  /* eye closed */
	{0x00, 0x38, 0x44, 0x92, 0x28, 0x10, 0x00, 0x00}, /* eye closed */
	{0x10, 0x54, 0x28, 0xc6, 0x28, 0x54, 0x10, 0x00}  /* unsaved */
};

SDL_Window *gWindow = NULL;


@@ 85,7 91,7 @@ SDL_Renderer *gRenderer = NULL;
SDL_Texture *gTexture = NULL;
Uint32 *pixels;

/* helpers */
#pragma mark - Helpers

Point2d *
setpt2d(Point2d *p, int x, int y)


@@ 160,6 166,16 @@ scmp(char *a, char *b)
	return 0;
}

char *
scpy(char *src, char *dst, int len)
{
	int i = 0;
	while((dst[i] = src[i]) && i < len - 2)
		i++;
	dst[i + 1] = '\0';
	return dst;
}

int
sint(char *s, int len)
{


@@ 169,25 185,6 @@ sint(char *s, int len)
	return num;
}

Uint8
chex(char c)
{
	if(c >= 'a' && c <= 'f')
		return 10 + c - 'a';
	if(c >= 'A' && c <= 'F')
		return 10 + c - 'A';
	return (c - '0') & 0xF;
}

int
shex(char *s, int len)
{
	int i, n = 0;
	for(i = 0; i < len; ++i)
		n |= (chex(s[i]) << ((len - i - 1) * 4));
	return n;
}

int
cancast(LineType type)
{


@@ 224,7 221,7 @@ colortheme(Uint32 hex)
	return 0;
}

/* draw */
#pragma mark - Draw

void
clear(Uint32 *dst)


@@ 238,7 235,7 @@ clear(Uint32 *dst)
int
keypixel(int x, int y)
{
	return (y + PAD) * WIDTH + (x + PAD);
	return (y + PAD * 8) * WIDTH + (x + PAD * 8);
}

int


@@ 251,7 248,7 @@ void
putpixel(Uint32 *dst, int x, int y, int color)
{
	if(x >= 0 && x < WIDTH - 8 && y >= 0 && y < HEIGHT - 8)
		dst[keypixel(x, y)] = theme[color];
		dst[(y + PAD * 8) * WIDTH + (x + PAD * 8)] = theme[color];
}

void


@@ 456,8 453,8 @@ void
drawguides(Uint32 *dst, int step)
{
	int x, y;
	for(x = 2; x < WIDTH - 16; x++)
		for(y = 2; y < HEIGHT - 32; y++)
	for(x = 2; x < HOR * 8; x++)
		for(y = 2; y < VER * 8; y++)
			if(x % (step * 2) == y % (step * 2) && x % (step * 2) == 0)
				putpixel(dst, x, y, 3);
			else if(x % step == 0 && y % 2 == 0)


@@ 467,13 464,13 @@ drawguides(Uint32 *dst, int step)
}

void
drawicon(Uint32 *dst, int x, int y, Uint8 *icon, int color)
drawicn(Uint32 *dst, int x, int y, Uint8 *sprite, int fg, int bg)
{
	int v, h;
	for(v = 0; v < 8; v++)
		for(h = 0; h < 8; h++) {
			int c = (icon[v] >> (8 - h)) & 0x1;
			putpixel(dst, x + h, y + v, c ? color : 0);
			int ch1 = (sprite[v] >> (7 - h)) & 0x1;
			putpixel(dst, x + h, y + v, ch1 ? fg : bg);
		}
}



@@ 482,17 479,17 @@ drawui(Uint32 *dst)
{
	int clr = brush.selection >= 0 ? shape.paths[brush.selection].color : 1;
	int bottom = VER * 8 + 8;
	drawicon(dst, 0, bottom, icons[clr == 1 ? 1 : 0], 1);
	drawicon(dst, 1 * 8, bottom, icons[clr == 2 ? 1 : 0], 2);
	drawicon(dst, 2 * 8, bottom, icons[clr == 3 ? 1 : 0], 3);
	drawicon(dst, 4 * 8, bottom, icons[2], cancast(LINE) ? 2 : 3);
	drawicon(dst, 5 * 8, bottom, icons[3], cancast(ARC) ? 2 : 3);
	drawicon(dst, 6 * 8, bottom, icons[4], cancast(BEZIER) ? 2 : 3);
	drawicon(dst, 7 * 8, bottom, icons[5], cancast(RECTANGLE) ? 2 : 3);
	drawicon(dst, 8 * 8, bottom, icons[1], cancast(ELLIPSE) ? 2 : 3);
	drawicon(dst, 9 * 8, bottom, icons[6], cancast(TRANSLATE) ? 2 : 3);

	drawicon(dst, 11 * 8, bottom, icons[GUIDES ? 9 : 8], GUIDES ? 1 : 2);
	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);
	drawicn(dst, 4 * 8, bottom, icons[2], cancast(LINE) ? 2 : 3, 0);
	drawicn(dst, 5 * 8, bottom, icons[3], cancast(ARC) ? 2 : 3, 0);
	drawicn(dst, 6 * 8, bottom, icons[4], cancast(BEZIER) ? 2 : 3, 0);
	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[6], cancast(TRANSLATE) ? 2 : 3, 0);
	drawicn(dst, 11 * 8, bottom, icons[GUIDES ? 9 : 8], GUIDES ? 1 : 2, 0);
	drawicn(dst, (HOR - 1) * 8, bottom, icons[10], doc.unsaved ? 2 : 3, 0); /* save state */
}

void


@@ 522,7 519,7 @@ redraw(Uint32 *dst)
	SDL_RenderPresent(gRenderer);
}

/* options */
#pragma mark - Options

int
error(char *msg, const char *err)


@@ 532,6 529,108 @@ error(char *msg, const char *err)
}

void
savemode(int *i, int v)
{
	*i = v;
	redraw(pixels);
}

void
makedoc(Document *d, char *name)
{
	int i;
	for(i = 0; i < SZ; ++i)
		d->data[i] = 0x00;
	d->unsaved = 0;
	scpy(name, d->name, 256);
	printf("Made: %s\n", d->name);
	redraw(pixels);
}

int
savedoc(Document *d, char *name)
{
	int i, j, c = -1;
	FILE *f = fopen(name, "w");
	char *names[] = {
		"point",
		"line",
		"arc",
		"bezier",
		"rectangle",
		"ellipse",
		"translate"};
	for(i = 0; i < shape.len; ++i) {
		Path2d *p = &shape.paths[i];
		if(c != p->color) {
			fprintf(f, "%d setcolor\n", p->color);
			c = p->color;
		}
		for(j = 0; j < p->len; ++j)
			fprintf(f, "%d,%d ", p->points[j].x, p->points[j].y);
		fprintf(f, "%s\n", names[(int)p->type]);
	}
	fclose(f);
	d->unsaved = 0;
	scpy(name, d->name, 256);
	fclose(f);
	printf("Saved: %s\n", d->name);
	redraw(pixels);
	return 1;
}

int
opendoc(Document *d, char *name)
{
	FILE *f = fopen(name, "r");
	if(!f)
		return error("Load", "Invalid input file");
	fread(doc.data, sizeof(doc.data), 1, f);
	d->unsaved = 0;
	scpy(name, doc.name, 256);
	fclose(f);
	printf("Loaded: %s\n", doc.name);
	redraw(pixels);
	return 1;
}

void
putchr(Uint8 *chrbuf, int row, int col, int color)
{
	if(row < 0 || row > SZ - 8)
		return;
	if(color == 0 || color == 2)
		chrbuf[row] &= ~(1UL << (7 - col));
	else
		chrbuf[row] |= 1UL << (7 - col);
	if(color == 0 || color == 1)
		chrbuf[row + 8] &= ~(1UL << (7 - col));
	else
		chrbuf[row + 8] |= 1UL << (7 - col);
}

int
savechr(void)
{
	int h, v, x, y;
	Uint8 chrbuf[SZ];
	FILE *f = fopen("dotgrid-export.chr", "wb");
	for(v = 0; v < VER; ++v)
		for(h = 0; h < HOR; ++h)
			for(y = 0; y < 8; ++y)
				for(x = 0; x < 8; ++x)
					putchr(chrbuf,
						y + (h + v * HOR) * 16,
						x,
						colortheme(getpixel(pixels, h * 8 + x, v * 8 + y)));
	if(!fwrite(chrbuf, sizeof(chrbuf), 1, f))
		error("Save", "Invalid output file");
	fclose(f);
	puts("Exported dotgrid-export.chr");
	return 1;
}

void
modzoom(int mod)
{
	if((mod > 0 && ZOOM < 4) || (mod < 0 && ZOOM > 1)) {


@@ 631,93 730,6 @@ setcolor(int c)
}

void
setguides(int v)
{
	GUIDES = v;
	redraw(pixels);
}

void
renderbmp(void)
{
	SDL_Surface *surface = SDL_GetWindowSurface(gWindow);
	setguides(0);
	SDL_RenderReadPixels(gRenderer,
		NULL,
		SDL_PIXELFORMAT_ARGB8888,
		surface->pixels,
		surface->pitch);
	if(SDL_SaveBMP(surface, "dotgrid-render.bmp"))
		printf("SDL_SaveBMP failed: %s\n", SDL_GetError());
	else
		puts("Rendered dotgrid-render.bmp");
	SDL_FreeSurface(surface);
}

void
putchr(Uint8 *chrbuf, int row, int col, int color)
{
	if(row < 0 || row > SZ - 8)
		return;
	if(color == 0 || color == 2)
		chrbuf[row] &= ~(1UL << (7 - col));
	else
		chrbuf[row] |= 1UL << (7 - col);
	if(color == 0 || color == 1)
		chrbuf[row + 8] &= ~(1UL << (7 - col));
	else
		chrbuf[row + 8] |= 1UL << (7 - col);
}

void
exportchr(void)
{
	int h, v, x, y;
	Uint8 chrbuf[SZ];
	FILE *f = fopen("dotgrid-export.chr", "wb");
	setguides(0);
	for(v = 0; v < VER; ++v)
		for(h = 0; h < HOR; ++h)
			for(y = 0; y < 8; ++y)
				for(x = 0; x < 8; ++x)
					putchr(chrbuf,
						y + (h + v * HOR) * 16,
						x,
						colortheme(getpixel(pixels, h * 8 + x, v * 8 + y)));
	if(!fwrite(chrbuf, sizeof(chrbuf), 1, f))
		error("Save", "Invalid output file");
	fclose(f);
	puts("Exported dotgrid-export.chr");
}

void
savetxt(void)
{
	int i, j, c = -1;
	FILE *f = fopen("dotgrid-shape.txt", "w");
	char *names[] = {
		"point",
		"line",
		"arc",
		"bezier",
		"rectangle",
		"ellipse",
		"translate"};
	for(i = 0; i < shape.len; ++i) {
		Path2d *p = &shape.paths[i];
		if(c != p->color) {
			fprintf(f, "%d setcolor\n", p->color);
			c = p->color;
		}
		for(j = 0; j < p->len; ++j)
			fprintf(f, "%d,%d ", p->points[j].x, p->points[j].y);
		fprintf(f, "%s\n", names[(int)p->type]);
	}
	fclose(f);
	puts("Saved dotgrid-shape.txt");
}

void
loadtxt(FILE *f)
{
	char line[256], query[256];


@@ 766,23 778,6 @@ loadtxt(FILE *f)
}

void
loadtheme(FILE *f)
{
	int id = 0;
	char line[256];
	if(!f)
		return;
	while(fgets(line, 256, f)) {
		int i = 0;
		while(line[i++] && id < 5) {
			if(line[i] == '#')
				theme[id++] = shex(line + i + 1, 6);
		}
	}
	fclose(f);
}

void
selectoption(int option)
{
	switch(option) {


@@ 795,7 790,7 @@ selectoption(int option)
	case 7: cast(RECTANGLE); break;
	case 8: cast(ELLIPSE); break;
	case 10: cast(TRANSLATE); break;
	case 11: setguides(!GUIDES); break;
	case 11: savemode(&GUIDES, !GUIDES); break;
	}
}



@@ 813,13 808,15 @@ quit(void)
	exit(0);
}

#pragma mark - Triggers

void
domouse(SDL_Event *event)
{
	Point2d magnet;
	Point2d touch = Pt2d(
		(event->motion.x - (PAD * ZOOM)) / ZOOM,
		(event->motion.y - (PAD * ZOOM)) / ZOOM);
		(event->motion.x - (PAD * 8 * ZOOM)) / ZOOM,
		(event->motion.y - (PAD * 8 * ZOOM)) / ZOOM);
	mag2d(setpt2d(&magnet, touch.x, touch.y), 8);
	switch(event->type) {
	case SDL_MOUSEBUTTONUP:


@@ 832,8 829,8 @@ domouse(SDL_Event *event)
		brush.touch = NULL;
		break;
	case SDL_MOUSEBUTTONDOWN:
		if(event->motion.y / ZOOM / 8 == VER + 2)
			selectoption(event->motion.x / ZOOM / 8 - 1);
		if(event->motion.y / ZOOM / 8 - PAD == VER + 1)
			selectoption(event->motion.x / ZOOM / 8 - PAD);
		else
			selectpoint(&magnet);
		break;


@@ 847,28 844,35 @@ domouse(SDL_Event *event)
void
dokey(SDL_Event *event)
{
	switch(event->key.keysym.sym) {
	case SDLK_EQUALS:
	case SDLK_PLUS: modzoom(1); break;
	case SDLK_UNDERSCORE:
	case SDLK_MINUS: modzoom(-1); break;
	case SDLK_ESCAPE: cancel(); break;
	case SDLK_BACKSPACE: erase(); break;
	case SDLK_1: setcolor(1); break;
	case SDLK_2: setcolor(2); break;
	case SDLK_3: setcolor(3); break;
	case SDLK_e: exportchr(); break;
	case SDLK_r: renderbmp(); break;
	case SDLK_t: savetxt(); break;
	case SDLK_a: cast(LINE); break;
	case SDLK_s: cast(ARC); break;
	case SDLK_d: cast(BEZIER); break;
	case SDLK_h: setguides(!GUIDES); 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_n: destroy(); break;
	int shift = SDL_GetModState() & KMOD_LSHIFT || SDL_GetModState() & KMOD_RSHIFT;
	int ctrl = SDL_GetModState() & KMOD_LCTRL || SDL_GetModState() & KMOD_RCTRL;
	if(ctrl) {
		switch(event->key.keysym.sym) {
		/* Generic */
		case SDLK_n: makedoc(&doc, "untitled.chr"); break;
		case SDLK_r: opendoc(&doc, doc.name); break;
		case SDLK_s: shift ? savechr() : savedoc(&doc, doc.name); break;
		case SDLK_h: savemode(&GUIDES, !GUIDES); break;
		}
	} else {
		switch(event->key.keysym.sym) {
		case SDLK_EQUALS:
		case SDLK_PLUS: modzoom(1); break;
		case SDLK_UNDERSCORE:
		case SDLK_MINUS: modzoom(-1); break;
		case SDLK_ESCAPE: cancel(); break;
		case SDLK_BACKSPACE: erase(); break;
		case SDLK_1: setcolor(1); break;
		case SDLK_2: setcolor(2); break;
		case SDLK_3: setcolor(3); break;
		case SDLK_a: cast(LINE); break;
		case SDLK_s: cast(ARC); break;
		case SDLK_d: cast(BEZIER); 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;
		}
	}
}



@@ 908,7 912,6 @@ main(int argc, char *argv[])
	int ticknext = 0;
	if(!init())
		return error("Init", "Failure");
	loadtheme(fopen("theme.svg", "r"));
	if(argc > 1)
		loadtxt(fopen(argv[1], "r"));
	cancel();