mirror of https://git.sr.ht/~rabbits/nasu
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
660 lines
15 KiB
660 lines
15 KiB
#include <SDL2/SDL.h> |
|
#include <stdio.h> |
|
|
|
/* |
|
Copyright (c) 2020 Devine Lu Linvega |
|
|
|
Permission to use, copy, modify, and distribute this software for any |
|
purpose with or without fee is hereby granted, provided that the above |
|
copyright notice and this permission notice appear in all copies. |
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|
WITH REGARD TO THIS SOFTWARE. |
|
*/ |
|
|
|
#define HOR 32 |
|
#define VER 16 |
|
#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 Brush { |
|
int x, y, px, py, vx, vy; |
|
int mode, size, color; |
|
int down, erase; |
|
Uint8 clip[16]; |
|
} Brush; |
|
|
|
int WIDTH = 8 * HOR + 8 * PAD * 2; |
|
int HEIGHT = 8 * (VER + 2) + 8 * PAD * 2; |
|
int FPS = 30, GUIDES = 1, BIGPIXEL = 0, ZOOM = 2, COLORS = 1; |
|
|
|
Document doc; |
|
Brush brush; |
|
|
|
Uint32 theme[] = { |
|
0x000000, |
|
0xee3333, |
|
0xffccaa, |
|
0xcccccc, |
|
0x222222}; |
|
|
|
Uint8 icons[][8] = { |
|
{0xfe, 0x82, 0x82, 0xfe, 0x82, 0x82, 0xfe, 0x00}, /* brush:1bit */ |
|
{0xfe, 0x92, 0x92, 0xfe, 0x92, 0x92, 0xfe, 0x00}, /* brush:2bit */ |
|
{0x38, 0x44, 0x82, 0x82, 0x82, 0x44, 0x38, 0x00}, /* color:blank */ |
|
{0x38, 0x7c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x00}, /* color:full */ |
|
{0x02, 0x02, 0x04, 0x38, 0x40, 0x80, 0x80, 0x00}, /* brush:line */ |
|
{0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0x00}, /* brush:pattern0 */ |
|
{0xaa, 0x54, 0xaa, 0x54, 0xaa, 0x54, 0xaa, 0x00}, /* brush:pattern2 */ |
|
{0x88, 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00}, /* brush:pattern4 */ |
|
{0x44, 0xba, 0x44, 0x44, 0x44, 0xba, 0x44, 0x00}, /* brush:cleanup */ |
|
{0x30, 0x48, 0x84, 0x84, 0x48, 0x34, 0x02, 0x00}, /* view:grid */ |
|
{0x32, 0x45, 0x82, 0x84, 0x48, 0x34, 0x02, 0x00}, /* view:bigpixels */ |
|
{0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xe0, 0x10, 0x00}, /* clip:blank */ |
|
{0x82, 0xc5, 0xe2, 0xf0, 0xf8, 0xe0, 0x10, 0x00}, /* clip:active */ |
|
{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 */ |
|
}; |
|
|
|
SDL_Window *gWindow; |
|
SDL_Renderer *gRenderer; |
|
SDL_Texture *gTexture; |
|
Uint32 *pixels; |
|
|
|
#pragma mark - HELPERS |
|
|
|
int |
|
clamp(int val, int min, int max) |
|
{ |
|
return (val >= min) ? (val <= max) ? val : max : min; |
|
} |
|
|
|
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 |
|
distance(int ax, int ay, int bx, int by) |
|
{ |
|
return (bx - ax) * (bx - ax) + (by - ay) * (by - ay); |
|
} |
|
|
|
int |
|
screenpos(int pos, int offset) |
|
{ |
|
pos -= (PAD * 8 * ZOOM); |
|
pos /= ZOOM; |
|
if(BIGPIXEL) { |
|
pos /= 8; |
|
pos += offset; |
|
} |
|
return pos; |
|
} |
|
|
|
int |
|
hasclip(void) |
|
{ |
|
int i; |
|
for(i = 0; i < 16; ++i) |
|
if(brush.clip[i]) |
|
return 1; |
|
return 0; |
|
} |
|
|
|
#pragma mark - CHR HANDLERS |
|
|
|
int |
|
rowchr(int x, int y) |
|
{ |
|
return (y % 8) + ((x / 8 + y / 8 * HOR) * 16); |
|
} |
|
|
|
int |
|
getchr(int x, int y) |
|
{ |
|
int ch1, ch2, r = rowchr(x, y); |
|
if(r < 0 || r > SZ - 8) |
|
return 0; |
|
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) |
|
return 2; |
|
if(ch1 && ch2) |
|
return 3; |
|
return 0; |
|
} |
|
|
|
void |
|
putchr(int x, int y, int color) |
|
{ |
|
int row = rowchr(x, y), col = x % 8; |
|
if(x < 0 || x >= HOR * 8 || y < 0 || y >= VER * 8) |
|
return; |
|
if(color == 0 || color == 2) |
|
doc.data[row] &= ~(1UL << (7 - col)); |
|
else |
|
doc.data[row] |= 1UL << (7 - col); |
|
if(color == 0 || color == 1) |
|
doc.data[row + 8] &= ~(1UL << (7 - col)); |
|
else |
|
doc.data[row + 8] |= 1UL << (7 - col); |
|
doc.unsaved = 1; |
|
} |
|
|
|
int |
|
jagg(int x, int y) |
|
{ |
|
int n = getchr(x, y + 1); |
|
int e = getchr(x + 1, y); |
|
int s = getchr(x, y - 1); |
|
int w = getchr(x - 1, y); |
|
int h = getchr(x, y); |
|
if(h == n && h == e && h != s && h != w) |
|
return 1; |
|
if(h == e && h == s && h != w && h != n) |
|
return 1; |
|
if(h == s && h == w && h != n && h != e) |
|
return 1; |
|
if(h == w && h == n && h != e && h != s) |
|
return 1; |
|
return 0; |
|
} |
|
|
|
int |
|
patt(int x, int y, int mode) |
|
{ |
|
if(mode == 3) |
|
return ((x + y) % 4) == 0 && ((y - x) % 4) == 0; |
|
if(mode == 2) |
|
return ((x + y) % 2) == 0 && ((y - x) % 2) == 0; |
|
if(mode == 1) |
|
return 1; |
|
return 0; |
|
} |
|
|
|
void |
|
fill(int x, int y, int mode, int size, int color) |
|
{ |
|
int ox, oy; |
|
for(ox = x - (size / 2); ox < x + size; ++ox) |
|
for(oy = y - (size / 2); oy < y + size; ++oy) |
|
if(distance(x, y, ox, oy) > size) |
|
continue; |
|
else if(mode == 4 && jagg(ox, oy)) |
|
putchr(ox, oy, 0); |
|
else if(patt(ox, oy, mode)) |
|
putchr(ox, oy, color); |
|
} |
|
|
|
void |
|
line(int ax, int ay, int bx, int by, 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(;;) { |
|
putchr(ax, ay, color); |
|
if(ax == bx && ay == by) |
|
break; |
|
e2 = 2 * err; |
|
if(e2 >= dy) { |
|
err += dy; |
|
ax += sx; |
|
} |
|
if(e2 <= dx) { |
|
err += dx; |
|
ay += sy; |
|
} |
|
} |
|
} |
|
|
|
#pragma mark - DRAW |
|
|
|
void |
|
clear(Uint32 *dst) |
|
{ |
|
int v, h; |
|
for(v = 0; v < HEIGHT; v++) |
|
for(h = 0; h < WIDTH; h++) |
|
dst[v * WIDTH + h] = theme[0]; |
|
} |
|
|
|
void |
|
putpixel(Uint32 *dst, int x, int y, int color) |
|
{ |
|
if(x >= 0 && x < WIDTH - 8 && y >= 0 && y < HEIGHT - 8) |
|
dst[(y + PAD * 8) * WIDTH + (x + PAD * 8)] = theme[color]; |
|
} |
|
|
|
void |
|
drawchr(Uint32 *dst, int x, int y, Uint8 *sprite) |
|
{ |
|
int v, h; |
|
for(v = 0; v < 8; v++) |
|
for(h = 0; h < 8; h++) { |
|
int ch1 = ((sprite[v] >> h) & 0x1); |
|
int ch2 = (((sprite[v + 8] >> h) & 0x1) << 1); |
|
int clr = ch1 + ch2; |
|
int guides = GUIDES && !clr && ((x + y) / 8) % 2; |
|
putpixel(dst, x + 7 - h, y + v, guides ? 4 : clr); |
|
} |
|
} |
|
|
|
void |
|
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 ch1 = (sprite[v] >> (7 - h)) & 0x1; |
|
putpixel(dst, x + h, y + v, ch1 ? fg : bg); |
|
} |
|
} |
|
|
|
int |
|
bigchrguides(int x, int y, int h, int v) |
|
{ |
|
if(!GUIDES) |
|
return 0; |
|
/* horizontal guides */ |
|
if(x % 8 == 0 && h == 0 && x > 0) |
|
return 1; |
|
if(h == 0 && v % 2 == 0 && x > 0) |
|
return 1; |
|
/* vertical guides */ |
|
if(y % 8 == 0 && v == 0 && y > 0) |
|
return 1; |
|
if(v == 0 && h % 2 == 0 && y > 0) |
|
return 1; |
|
return 0; |
|
} |
|
|
|
void |
|
drawbig(Uint32 *dst, int x, int y, int id) |
|
{ |
|
int v, h; |
|
for(v = 0; v < 8; v++) |
|
for(h = 0; h < 8; h++) { |
|
int guides = bigchrguides(brush.vx + x, brush.vy + y, h, v); |
|
putpixel(dst, |
|
x * 8 + h, |
|
y * 8 + v, |
|
guides && id == 0 ? 4 : id); |
|
} |
|
} |
|
|
|
void |
|
drawui(Uint32 *dst) |
|
{ |
|
int bottom = VER * 8 + 8; |
|
drawicn(dst, 0, bottom, icons[COLORS], 1, 0); |
|
drawicn(dst, 0x10, bottom, brush.color == 1 ? icons[3] : icons[2], 1, 0); |
|
drawicn(dst, 0x18, bottom, brush.color == 2 ? icons[3] : icons[2], 2, 0); |
|
drawicn(dst, 0x20, bottom, brush.color == 3 ? icons[3] : icons[2], 3, 0); |
|
drawicn(dst, 0x30, bottom, icons[4], brush.mode == 0 ? 1 : 2, 0); |
|
drawicn(dst, 0x38, bottom, icons[5], brush.mode == 1 ? 1 : 2, 0); |
|
drawicn(dst, 0x40, bottom, icons[6], brush.mode == 2 ? 1 : 2, 0); |
|
drawicn(dst, 0x48, bottom, icons[7], brush.mode == 3 ? 1 : 2, 0); |
|
drawicn(dst, 0x50, bottom, icons[8], brush.mode == 4 ? 1 : 2, 0); |
|
drawicn(dst, 0x60, bottom, icons[hasclip() ? 12 : 11], brush.mode == 5 ? 1 : 2, 0); |
|
drawicn(dst, 0x68, bottom, icons[BIGPIXEL ? 10 : 9], brush.mode == 6 ? 1 : 2, 0); |
|
drawicn(dst, 0x78, bottom, icons[GUIDES ? 14 : 13], GUIDES ? 1 : 2, 0); |
|
drawicn(dst, (HOR - 1) * 0x08, bottom, icons[15], doc.unsaved ? 2 : 3, 0); /* save state */ |
|
} |
|
|
|
void |
|
redraw(Uint32 *dst) |
|
{ |
|
int x, y; |
|
clear(dst); |
|
drawui(dst); |
|
for(y = 0; y < VER; ++y) |
|
for(x = 0; x < HOR; ++x) |
|
if(BIGPIXEL) { |
|
if(x + brush.vx < HOR * 8 && y + brush.vy < VER * 8) |
|
drawbig(dst, x, y, getchr(x + brush.vx, y + brush.vy) % (COLORS ? 4 : 2)); |
|
} else { |
|
if(COLORS) |
|
drawchr(dst, x * 8, y * 8, &doc.data[(x + y * HOR) * 16]); |
|
else |
|
drawicn(dst, x * 8, y * 8, &doc.data[(x + y * HOR) * 16], 1, 0); |
|
} |
|
SDL_UpdateTexture(gTexture, NULL, dst, WIDTH * sizeof(Uint32)); |
|
SDL_RenderClear(gRenderer); |
|
SDL_RenderCopy(gRenderer, gTexture, NULL, NULL); |
|
SDL_RenderPresent(gRenderer); |
|
} |
|
|
|
#pragma mark - OPTIONS |
|
|
|
int |
|
error(char *msg, const char *err) |
|
{ |
|
printf("Error %s: %s\n", msg, err); |
|
return 0; |
|
} |
|
|
|
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) |
|
{ |
|
FILE *f = fopen(name, "w"); |
|
if(!fwrite(d->data, sizeof(d->data), 1, f)) |
|
return error("Save", "Failure"); |
|
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; |
|
} |
|
|
|
int |
|
savebmp(void) |
|
{ |
|
int w, h; |
|
SDL_Surface *sshot; |
|
SDL_GetRendererOutputSize(gRenderer, &w, &h); |
|
w /= ZOOM; |
|
h /= ZOOM; |
|
sshot = SDL_CreateRGBSurfaceFrom(pixels, w, h, 8 * 4, w * 4, 0, 0, 0, 0); |
|
SDL_SaveBMP(sshot, "screenshot.bmp"); |
|
printf("Rendered screenshot\n"); |
|
SDL_FreeSurface(sshot); |
|
return 1; |
|
} |
|
|
|
void |
|
lookat(int x, int y) |
|
{ |
|
brush.vx = clamp(x, 0, WIDTH - HOR - 2 * PAD * 8); |
|
brush.vy = clamp(y, 0, HEIGHT - VER - 3 * PAD * 8); |
|
redraw(pixels); |
|
} |
|
|
|
void |
|
clearclip(Uint8 *clip) |
|
{ |
|
int i; |
|
for(i = 0; i < 16; ++i) |
|
clip[i] = 0; |
|
redraw(pixels); |
|
} |
|
|
|
void |
|
copyclip(Uint8 *clip, int id) |
|
{ |
|
int i; |
|
if(id < 0 || id >= HOR * VER) |
|
return; |
|
for(i = 0; i < 16; ++i) |
|
clip[i] = doc.data[(id * 16) + i]; |
|
redraw(pixels); |
|
} |
|
|
|
void |
|
pasteclip(Uint8 *clip, int id) |
|
{ |
|
int i; |
|
if(id < 0 || id >= HOR * VER) |
|
return; |
|
for(i = 0; i < 16; ++i) |
|
doc.data[(id * 16) + i] = clip[i]; |
|
clearclip(clip); |
|
} |
|
|
|
void |
|
selectoption(int option) |
|
{ |
|
switch(option) { |
|
case 0: savemode(&COLORS, !COLORS); break; |
|
case 2: savemode(&brush.color, 1); break; |
|
case 3: savemode(&brush.color, 2); break; |
|
case 4: savemode(&brush.color, 3); break; |
|
case 6: savemode(&brush.mode, 0); break; |
|
case 7: savemode(&brush.mode, 1); break; |
|
case 8: savemode(&brush.mode, 2); break; |
|
case 9: savemode(&brush.mode, 3); break; |
|
case 10: savemode(&brush.mode, 4); break; |
|
case 12: savemode(&brush.mode, 5); break; |
|
case 13: savemode(&brush.mode, 6); break; |
|
case 15: savemode(&GUIDES, !GUIDES); break; |
|
case HOR - 1: savedoc(&doc, doc.name); break; |
|
} |
|
} |
|
|
|
void |
|
quit(void) |
|
{ |
|
free(pixels); |
|
SDL_DestroyTexture(gTexture); |
|
gTexture = NULL; |
|
SDL_DestroyRenderer(gRenderer); |
|
gRenderer = NULL; |
|
SDL_DestroyWindow(gWindow); |
|
gWindow = NULL; |
|
SDL_Quit(); |
|
exit(0); |
|
} |
|
|
|
#pragma mark - TRIGGERS |
|
|
|
void |
|
domouse(SDL_Event *event) |
|
{ |
|
int ctrl = SDL_GetModState() & KMOD_LCTRL || SDL_GetModState() & KMOD_RCTRL; |
|
|
|
switch(event->type) { |
|
case SDL_MOUSEBUTTONUP: |
|
if(event->button.button == SDL_BUTTON_LEFT) |
|
brush.down = 0; |
|
if(event->button.button == SDL_BUTTON_RIGHT) |
|
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) |
|
brush.erase = 1; |
|
if(event->button.button == SDL_BUTTON_MIDDLE) |
|
line(brush.px, brush.py, screenpos(event->motion.x, brush.vx), screenpos(event->motion.y, brush.vy), brush.erase ? 0 : brush.color); |
|
brush.px = screenpos(event->motion.x, brush.vx); |
|
brush.py = screenpos(event->motion.y, brush.vy); |
|
if(!BIGPIXEL) |
|
lookat((brush.px / 8) * 8, (brush.py / 8) * 8); |
|
if(brush.mode == 5) { |
|
if(event->button.button == SDL_BUTTON_LEFT && hasclip()) |
|
pasteclip(brush.clip, brush.px / 8 + brush.py / 8 * HOR); |
|
else |
|
copyclip(brush.clip, brush.px / 8 + brush.py / 8 * HOR); |
|
} else if(brush.mode == 6) |
|
BIGPIXEL = !BIGPIXEL; |
|
else if(ctrl) |
|
savemode(&brush.color, getchr(brush.px, brush.py)); |
|
else if(brush.down) { |
|
if(brush.mode == 0) |
|
putchr(brush.px, brush.py, brush.erase ? 0 : brush.color); |
|
else |
|
fill(brush.px, brush.py, brush.mode, brush.size, brush.erase ? 0 : brush.color); |
|
} |
|
redraw(pixels); |
|
break; |
|
case SDL_MOUSEMOTION: |
|
if(brush.down) { |
|
brush.x = screenpos(event->motion.x, brush.vx); |
|
brush.y = screenpos(event->motion.y, brush.vy); |
|
if(ctrl) /* color picker */ |
|
savemode(&brush.color, getchr(brush.px, brush.py)); |
|
else if(!brush.mode) |
|
line(brush.px, brush.py, brush.x, brush.y, brush.erase ? 0 : brush.color); |
|
else |
|
fill(brush.x, brush.y, brush.mode, brush.size, brush.erase ? 0 : brush.color); |
|
redraw(pixels); |
|
brush.px = brush.x; |
|
brush.py = brush.y; |
|
} |
|
break; |
|
} |
|
} |
|
|
|
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; |
|
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 ? savebmp() : savedoc(&doc, doc.name); break; |
|
case SDLK_h: savemode(&GUIDES, !GUIDES); break; |
|
} |
|
} else { |
|
switch(event->key.keysym.sym) { |
|
case SDLK_1: savemode(&brush.color, 1); break; |
|
case SDLK_2: savemode(&brush.color, 2); break; |
|
case SDLK_3: savemode(&brush.color, 3); break; |
|
case SDLK_4: savemode(&brush.color, 0); break; |
|
case SDLK_a: savemode(&brush.mode, 0); break; |
|
case SDLK_s: savemode(&brush.mode, 1); break; |
|
case SDLK_d: savemode(&brush.mode, 2); break; |
|
case SDLK_f: savemode(&brush.mode, 3); break; |
|
case SDLK_g: savemode(&brush.mode, 4); break; |
|
case SDLK_c: savemode(&brush.mode, 5); break; |
|
case SDLK_b: savemode(&brush.mode, 6); break; |
|
case SDLK_z: savemode(&brush.size, brush.size + (brush.size > 1 ? -1 : 0)); break; |
|
case SDLK_x: savemode(&brush.size, brush.size + (brush.size < 30 ? 1 : 0)); break; |
|
case SDLK_UP: lookat(brush.vx, brush.vy - 1); break; |
|
case SDLK_DOWN: lookat(brush.vx, brush.vy + 1); break; |
|
case SDLK_LEFT: lookat(brush.vx - 1, brush.vy); break; |
|
case SDLK_RIGHT: lookat(brush.vx + 1, brush.vy); break; |
|
case SDLK_SPACE: savemode(&COLORS, !COLORS); break; |
|
case SDLK_ESCAPE: |
|
savemode(&brush.mode, 0); |
|
clearclip(brush.clip); |
|
break; |
|
} |
|
} |
|
} |
|
|
|
int |
|
init(void) |
|
{ |
|
if(SDL_Init(SDL_INIT_VIDEO) < 0) |
|
return error("Init", SDL_GetError()); |
|
gWindow = SDL_CreateWindow("Nasu", |
|
SDL_WINDOWPOS_UNDEFINED, |
|
SDL_WINDOWPOS_UNDEFINED, |
|
WIDTH * ZOOM, |
|
HEIGHT * ZOOM, |
|
SDL_WINDOW_SHOWN); |
|
if(gWindow == NULL) |
|
return error("Window", SDL_GetError()); |
|
gRenderer = SDL_CreateRenderer(gWindow, -1, 0); |
|
if(gRenderer == NULL) |
|
return error("Renderer", SDL_GetError()); |
|
gTexture = SDL_CreateTexture(gRenderer, |
|
SDL_PIXELFORMAT_ARGB8888, |
|
SDL_TEXTUREACCESS_STATIC, |
|
WIDTH, |
|
HEIGHT); |
|
if(gTexture == NULL) |
|
return error("Texture", SDL_GetError()); |
|
pixels = (Uint32 *)malloc(WIDTH * HEIGHT * sizeof(Uint32)); |
|
if(pixels == NULL) |
|
return error("Pixels", "Failed to allocate memory"); |
|
clear(pixels); |
|
return 1; |
|
} |
|
|
|
int |
|
main(int argc, char **argv) |
|
{ |
|
int ticknext = 0; |
|
brush.color = 1; |
|
brush.size = 10; |
|
if(!init()) |
|
return error("Init", "Failure"); |
|
if(argc > 1) { |
|
if(!opendoc(&doc, argv[1])) |
|
makedoc(&doc, argv[1]); |
|
} else |
|
makedoc(&doc, "untitled.chr"); |
|
while(1) { |
|
int tick = SDL_GetTicks(); |
|
SDL_Event event; |
|
if(tick < ticknext) |
|
SDL_Delay(ticknext - tick); |
|
ticknext = tick + (1000 / FPS); |
|
while(SDL_PollEvent(&event) != 0) { |
|
switch(event.type) { |
|
case SDL_QUIT: quit(); break; |
|
case SDL_MOUSEBUTTONUP: |
|
case SDL_MOUSEBUTTONDOWN: |
|
case SDL_MOUSEMOTION: domouse(&event); break; |
|
case SDL_KEYDOWN: dokey(&event); break; |
|
case SDL_WINDOWEVENT: |
|
if(event.window.event == SDL_WINDOWEVENT_EXPOSED) |
|
redraw(pixels); |
|
break; |
|
} |
|
} |
|
} |
|
quit(); |
|
return 0; |
|
}
|
|
|