~rabbits/nasu

7a7d95e8c81c43e214afb9670bb51b1d87905f0d — neauoire 2 years ago 4049159
Misc standardization
2 files changed, 108 insertions(+), 83 deletions(-)

M README.md
M nasu.c
M README.md => README.md +6 -9
@@ 22,22 22,19 @@ To resume working on a tileset:

### Generics

- `+` Zoom In
- `-` Zoom Out

### IO

- `E` Export(nasu-export.chr)
- `R` Render(nasu-render.bmp)
- `ctrl+n` New
- `ctrl+s` Save(.chr)
- `ctrl+shift+s` Save(.bmp)
- `ctrl+plus` Zoom In
- `ctrl+minus` Zoom Out
- `ctrl+H` Toggle Guides

### General

- `1-4` Colors0-3
- `ASDFG` Modes0-4
- `H` Toggle Guides
- `Z` Decr. Brush Size
- `X` Incr. Brush Size
- `N` Clear

### Paint


M nasu.c => nasu.c +102 -74
@@ 14,21 14,27 @@ 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 {
	char name[256];
	Uint8 data[SZ];
} Document;

typedef struct Brush {
	int x, y, px, py;
	int mode, size, color;
	int down, erase;
} 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;

Document doc;
Brush brush;

Uint32 theme[] = {


@@ 50,7 56,6 @@ Uint8 icons[][8] = {
	{0x00, 0x38, 0x44, 0x92, 0x28, 0x10, 0x00, 0x00}  /* eye closed */
};

Uint8 chrbuf[SZ];
SDL_Window *gWindow;
SDL_Renderer *gRenderer;
SDL_Texture *gTexture;


@@ 58,6 63,16 @@ Uint32 *pixels;

/* helpers */

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

int
distance(int ax, int ay, int bx, int by)
{


@@ 85,14 100,6 @@ shex(char *s, int len)

/* chr */

void
newchr(void)
{
	int i;
	for(i = 0; i < SZ; ++i)
		chrbuf[i] = 0x00;
}

int
rowchr(int x, int y)
{


@@ 105,8 112,8 @@ getchr(int x, int y)
	int ch1, ch2, r = rowchr(x, y);
	if(r < 0 || r > SZ - 8)
		return 0;
	ch1 = (chrbuf[r] >> (7 - x % 8)) & 1;
	ch2 = (chrbuf[r + 8] >> (7 - x % 8)) & 1;
	ch1 = (doc.data[r] >> (7 - x % 8)) & 1;
	ch2 = (doc.data[r + 8] >> (7 - x % 8)) & 1;
	if(ch1 && !ch2)
		return 1;
	if(!ch1 && ch2)


@@ 125,13 132,13 @@ putchr(int x, int y, int color)
	if(y < 0 || y >= VER * 8)
		return;
	if(color == 0 || color == 2)
		chrbuf[row] &= ~(1UL << (7 - col));
		doc.data[row] &= ~(1UL << (7 - col));
	else
		chrbuf[row] |= 1UL << (7 - col);
		doc.data[row] |= 1UL << (7 - col);
	if(color == 0 || color == 1)
		chrbuf[row + 8] &= ~(1UL << (7 - col));
		doc.data[row + 8] &= ~(1UL << (7 - col));
	else
		chrbuf[row + 8] |= 1UL << (7 - col);
		doc.data[row + 8] |= 1UL << (7 - col);
}

int


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

void


@@ 227,8 234,8 @@ drawchr(Uint32 *dst, int x, int y, int id)
		for(h = 0; h < 8; h++) {
			int px = (x * 8) + (8 - h);
			int py = (y * 8) + v;
			int ch1 = chrbuf[offset + v];
			int ch2 = chrbuf[offset + v + 8];
			int ch1 = doc.data[offset + v];
			int ch2 = doc.data[offset + v + 8];
			int clr = ((ch1 >> h) & 0x1) + (((ch2 >> h) & 0x1) << 1);
			int guides = GUIDES && !clr && (x + y) % 2;
			putpixel(dst, px, py, guides ? 4 : clr);


@@ 236,13 243,13 @@ drawchr(Uint32 *dst, int x, int y, int id)
}

void
drawicon(Uint32 *dst, int x, int y, Uint8 *icon, int color)
drawicon(Uint32 *dst, int x, int y, Uint8 *icon, 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 clr = (icon[v] >> (7 - h)) & 0x1;
			putpixel(dst, x + h, y + v, clr == 1 ? fg : bg);
		}
}



@@ 250,16 257,15 @@ void
drawui(Uint32 *dst)
{
	int bottom = VER * 8 + 8;
	drawicon(dst, 0, bottom, brush.color == 1 ? icons[1] : icons[0], 1);
	drawicon(dst, 8, bottom, brush.color == 2 ? icons[1] : icons[0], 2);
	drawicon(dst, 16, bottom, brush.color == 3 ? icons[1] : icons[0], 3);
	drawicon(dst, 4 * 8, bottom, icons[2], brush.mode == 0 ? 1 : 2);
	drawicon(dst, 5 * 8, bottom, icons[3], brush.mode == 1 ? 1 : 2);
	drawicon(dst, 6 * 8, bottom, icons[4], brush.mode == 2 ? 1 : 2);
	drawicon(dst, 7 * 8, bottom, icons[5], brush.mode == 3 ? 1 : 2);
	drawicon(dst, 8 * 8, bottom, icons[6], brush.mode == 4 ? 1 : 2);

	drawicon(dst, 10 * 8, bottom, icons[GUIDES ? 8 : 7], GUIDES ? 1 : 2);
	drawicon(dst, 0, bottom, brush.color == 1 ? icons[1] : icons[0], 1, 0);
	drawicon(dst, 8, bottom, brush.color == 2 ? icons[1] : icons[0], 2, 0);
	drawicon(dst, 16, bottom, brush.color == 3 ? icons[1] : icons[0], 3, 0);
	drawicon(dst, 4 * 8, bottom, icons[2], brush.mode == 0 ? 1 : 2, 0);
	drawicon(dst, 5 * 8, bottom, icons[3], brush.mode == 1 ? 1 : 2, 0);
	drawicon(dst, 6 * 8, bottom, icons[4], brush.mode == 2 ? 1 : 2, 0);
	drawicon(dst, 7 * 8, bottom, icons[5], brush.mode == 3 ? 1 : 2, 0);
	drawicon(dst, 8 * 8, bottom, icons[6], brush.mode == 4 ? 1 : 2, 0);
	drawicon(dst, 10 * 8, bottom, icons[GUIDES ? 8 : 7], GUIDES ? 1 : 2, 0);
}

void


@@ 330,21 336,38 @@ setguides(int v)
}

void
destroy(void)
newchr(void)
{
	newchr();
	int i;
	for(i = 0; i < SZ; ++i)
		doc.data[i] = 0x00;
	scpy("untitled.chr", doc.name, 256);
	printf("New: %s\n", doc.name);
	redraw(pixels);
	puts("Destroy");
}

int
exportchr(void)
savechr(void)
{
	FILE *f = fopen("nasu-export.chr", "wb");
	if(!fwrite(chrbuf, sizeof(chrbuf), 1, f))
	FILE *f = fopen(doc.name, "wb");
	if(!fwrite(doc.data, sizeof(doc.data), 1, f))
		return error("Export", "Failure");
	fclose(f);
	puts("Export: nasu-export.chr");
	printf("Save: %s\n", doc.name);
	return 1;
}

int
openchr(char *name)
{
	FILE *f = fopen(name, "r");
	if(!f)
		return error("Load", "Invalid input file");
	if(!fread(doc.data, sizeof(doc.data), 1, f))
		return error("Load", "Invalid input size");
	scpy(name, doc.name, 256);
	fclose(f);
	printf("Load: %s\n", doc.name);
	return 1;
}



@@ 364,18 387,6 @@ renderbmp(void)
	return 1;
}

int
loadchr(FILE *f)
{
	if(!f)
		return error("Load", "Invalid input file");
	if(!fread(chrbuf, sizeof(chrbuf), 1, f))
		return error("Load", "Invalid input size");
	puts("Load: Complete");
	fclose(f);
	return 1;
}

void
loadtheme(FILE *f)
{


@@ 434,6 445,10 @@ domouse(SDL_Event *event)
			brush.erase = 0;
		break;
	case SDL_MOUSEBUTTONDOWN:
		if(event->motion.y / ZOOM / 8 - PAD == VER + 1) {
			selectoption(event->motion.x / ZOOM / 8 - PAD);
			return;
		}
		if(event->button.button == SDL_BUTTON_LEFT)
			brush.down = 1;
		if(event->button.button == SDL_BUTTON_RIGHT)


@@ 441,16 456,14 @@ domouse(SDL_Event *event)
		if(event->button.button == SDL_BUTTON_MIDDLE) {
			brush.erase = 0;
			if(brush.px != 0 && brush.py != 0) {
				brush.x = (event->motion.x - (PAD * ZOOM)) / ZOOM;
				brush.y = (event->motion.y - (PAD * ZOOM)) / ZOOM;
				brush.x = (event->motion.x - (PAD * 8 * ZOOM)) / ZOOM;
				brush.y = (event->motion.y - (PAD * 8 * ZOOM)) / ZOOM;
				line(brush.px - 1, brush.py, brush.x, brush.y, brush.erase ? 0 : brush.color);
				redraw(pixels);
			}
		}
		brush.px = (event->motion.x - (PAD * ZOOM)) / ZOOM;
		brush.py = (event->motion.y - (PAD * ZOOM)) / ZOOM;
		if(event->motion.y / ZOOM / 8 == VER + 2)
			selectoption(event->motion.x / ZOOM / 8 - 1);
		brush.px = (event->motion.x - (PAD * 8 * ZOOM)) / ZOOM;
		brush.py = (event->motion.y - (PAD * 8 * ZOOM)) / ZOOM;
		if(brush.down && brush.mode == 0) {
			putchr(brush.px - 1, brush.py, brush.erase ? 0 : brush.color);
			redraw(pixels);


@@ 458,8 471,8 @@ domouse(SDL_Event *event)
		break;
	case SDL_MOUSEMOTION:
		if(brush.down) {
			brush.x = (event->motion.x - (PAD * ZOOM)) / ZOOM;
			brush.y = (event->motion.y - (PAD * ZOOM)) / ZOOM;
			brush.x = (event->motion.x - (PAD * 8 * ZOOM)) / ZOOM;
			brush.y = (event->motion.y - (PAD * 8 * ZOOM)) / ZOOM;
			if(!brush.mode)
				line(brush.px - 1, brush.py, brush.x - 1, brush.y, brush.erase ? 0 : brush.color);
			else


@@ 475,26 488,45 @@ domouse(SDL_Event *event)
void
dokey(SDL_Event *event)
{
	int shift = SDL_GetModState() & KMOD_LSHIFT || SDL_GetModState() & KMOD_RSHIFT;
	int ctrl = SDL_GetModState() & KMOD_LCTRL || SDL_GetModState() & KMOD_RCTRL;
	switch(event->key.keysym.sym) {
	case SDLK_EQUALS:
	case SDLK_PLUS: modzoom(1); break;
	case SDLK_PLUS:
		if(ctrl)
			modzoom(1);
		break;
	case SDLK_UNDERSCORE:
	case SDLK_MINUS: modzoom(-1); break;
	case SDLK_MINUS:
		if(ctrl)
			modzoom(-1);
		break;
	case SDLK_1: setcolor(&brush, 1); break;
	case SDLK_2: setcolor(&brush, 2); break;
	case SDLK_3: setcolor(&brush, 3); break;
	case SDLK_4: setcolor(&brush, 0); break;
	case SDLK_e: exportchr(); break;
	case SDLK_r: renderbmp(); break;
	case SDLK_a: setmode(&brush, 0); break;
	case SDLK_s: setmode(&brush, 1); break;
	case SDLK_s:
		if(ctrl && shift)
			renderbmp();
		else if(ctrl)
			savechr();
		else
			setmode(&brush, 1);
		break;
	case SDLK_d: setmode(&brush, 2); break;
	case SDLK_f: setmode(&brush, 3); break;
	case SDLK_g: setmode(&brush, 4); break;
	case SDLK_h: setguides(!GUIDES); break;
	case SDLK_h:
		if(ctrl)
			setguides(!GUIDES);
		break;
	case SDLK_z: modsize(&brush, -1); break;
	case SDLK_x: modsize(&brush, 1); break;
	case SDLK_n: destroy(); break;
	case SDLK_n:
		if(ctrl)
			newchr();
		break;
	}
}



@@ 532,17 564,13 @@ int
main(int argc, char **argv)
{
	int ticknext = 0;
	brush.erase = 0;
	brush.down = 0;
	brush.color = 1;
	brush.size = 10;
	brush.mode = 0;
	if(!init())
		return error("Init", "Failure");
	loadtheme(fopen("theme.svg", "r"));
	newchr();
	if(argc > 1)
		loadchr(fopen(argv[1], "r"));
	if(argc > 1 && !openchr(argv[1]))
		newchr();
	redraw(pixels);
	while(1) {
		int tick = SDL_GetTicks();