|
|
|
@ -1,6 +1,17 @@ |
|
|
|
#include <SDL2/SDL.h> |
|
|
|
#include <SDL2/SDL.h> |
|
|
|
#include <stdio.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 HOR 32 |
|
|
|
#define VER 16 |
|
|
|
#define VER 16 |
|
|
|
#define PAD 8 |
|
|
|
#define PAD 8 |
|
|
|
@ -19,27 +30,19 @@ typedef struct Brush { |
|
|
|
int down, edit, erase; |
|
|
|
int down, edit, erase; |
|
|
|
} Brush; |
|
|
|
} Brush; |
|
|
|
|
|
|
|
|
|
|
|
char *modes[] = { |
|
|
|
|
|
|
|
"line", |
|
|
|
|
|
|
|
"tone", |
|
|
|
|
|
|
|
"bold", |
|
|
|
|
|
|
|
"full", |
|
|
|
|
|
|
|
"hori", |
|
|
|
|
|
|
|
"veri", |
|
|
|
|
|
|
|
"exes", |
|
|
|
|
|
|
|
"fixe"}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int colors[] = {color1, color2, color3, color4, color0}; |
|
|
|
int colors[] = {color1, color2, color3, color4, color0}; |
|
|
|
int WIDTH = 8 * HOR + PAD * 2; |
|
|
|
int WIDTH = 8 * HOR + PAD * 2; |
|
|
|
int HEIGHT = 8 * VER + PAD * 2; |
|
|
|
int HEIGHT = 8 * VER + PAD * 2; |
|
|
|
int FPS = 30; |
|
|
|
int FPS = 30, GUIDES = 1; |
|
|
|
int GUIDES = 0; |
|
|
|
|
|
|
|
SDL_Window *gWindow = NULL; |
|
|
|
|
|
|
|
SDL_Renderer *gRenderer = NULL; |
|
|
|
|
|
|
|
SDL_Texture *gTexture = NULL; |
|
|
|
|
|
|
|
unsigned char chrbuf[SZ]; |
|
|
|
unsigned char chrbuf[SZ]; |
|
|
|
|
|
|
|
SDL_Window *gWindow; |
|
|
|
|
|
|
|
SDL_Renderer *gRenderer; |
|
|
|
|
|
|
|
SDL_Texture *gTexture; |
|
|
|
Uint32 *pixels; |
|
|
|
Uint32 *pixels; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Brush brush; |
|
|
|
|
|
|
|
|
|
|
|
/* helpers */ |
|
|
|
/* helpers */ |
|
|
|
|
|
|
|
|
|
|
|
int |
|
|
|
int |
|
|
|
@ -94,11 +97,10 @@ getchr(int x, int y) |
|
|
|
void |
|
|
|
void |
|
|
|
putchr(int x, int y, int color) |
|
|
|
putchr(int x, int y, int color) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int r = rowchr(x, y); |
|
|
|
int r = rowchr(x, y), px = x % 8; |
|
|
|
int px = x % 8; |
|
|
|
if(r < 0 || r > SZ - 8) |
|
|
|
if(x < 0 || y < 0 || x > 8 * HOR || y > 8 * VER || r > SZ - 8) |
|
|
|
|
|
|
|
return; |
|
|
|
return; |
|
|
|
if(color == 0) { |
|
|
|
if(!color) { |
|
|
|
chrbuf[r] &= ~(1UL << (7 - px)); |
|
|
|
chrbuf[r] &= ~(1UL << (7 - px)); |
|
|
|
chrbuf[r + 8] &= ~(1UL << (7 - px)); |
|
|
|
chrbuf[r + 8] &= ~(1UL << (7 - px)); |
|
|
|
} else if(color == 2) { |
|
|
|
} else if(color == 2) { |
|
|
|
@ -195,9 +197,9 @@ line(int ax, int ay, int bx, int by, int color) |
|
|
|
/* draw */ |
|
|
|
/* draw */ |
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
|
void |
|
|
|
drawtile(Uint32 *dst, int x, int y, int id) |
|
|
|
drawchr(Uint32 *dst, int x, int y, int id) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int v, h, offset = id * 16, sz = WIDTH * HEIGHT; |
|
|
|
int v, h, offset = id * 16; |
|
|
|
for(v = 0; v < 8; v++) |
|
|
|
for(v = 0; v < 8; v++) |
|
|
|
for(h = 0; h < 8; h++) { |
|
|
|
for(h = 0; h < 8; h++) { |
|
|
|
int px = (x * 8) + (8 - h); |
|
|
|
int px = (x * 8) + (8 - h); |
|
|
|
@ -206,8 +208,8 @@ drawtile(Uint32 *dst, int x, int y, int id) |
|
|
|
int ch2 = chrbuf[offset + v + 8]; |
|
|
|
int ch2 = chrbuf[offset + v + 8]; |
|
|
|
int clr = ((ch1 >> h) & 0x1) + (((ch2 >> h) & 0x1) << 1); |
|
|
|
int clr = ((ch1 >> h) & 0x1) + (((ch2 >> h) & 0x1) << 1); |
|
|
|
int key = (py + PAD) * WIDTH + (px + PAD); |
|
|
|
int key = (py + PAD) * WIDTH + (px + PAD); |
|
|
|
if(key >= 0 && key <= sz - 1) |
|
|
|
int guides = GUIDES && !clr && (x + y) % 2; |
|
|
|
dst[key] = colors[clr]; |
|
|
|
dst[key] = colors[guides ? 4 : clr]; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -217,29 +219,13 @@ draw(Uint32 *dst) |
|
|
|
int x, y; |
|
|
|
int x, y; |
|
|
|
for(y = 0; y < VER; ++y) |
|
|
|
for(y = 0; y < VER; ++y) |
|
|
|
for(x = 0; x < HOR; ++x) |
|
|
|
for(x = 0; x < HOR; ++x) |
|
|
|
drawtile(dst, x, y, x + y * HOR); |
|
|
|
drawchr(dst, x, y, x + y * HOR); |
|
|
|
SDL_UpdateTexture(gTexture, NULL, dst, WIDTH * sizeof(Uint32)); |
|
|
|
SDL_UpdateTexture(gTexture, NULL, dst, WIDTH * sizeof(Uint32)); |
|
|
|
SDL_RenderClear(gRenderer); |
|
|
|
SDL_RenderClear(gRenderer); |
|
|
|
SDL_RenderCopy(gRenderer, gTexture, NULL, NULL); |
|
|
|
SDL_RenderCopy(gRenderer, gTexture, NULL, NULL); |
|
|
|
SDL_RenderPresent(gRenderer); |
|
|
|
SDL_RenderPresent(gRenderer); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
|
|
|
update(Brush *b) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if(b->edit) |
|
|
|
|
|
|
|
SDL_SetWindowTitle(gWindow, "Nasu*"); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
SDL_SetWindowTitle(gWindow, "Nasu"); |
|
|
|
|
|
|
|
printf("%s %d:%d [%d:%dx%d]\n", |
|
|
|
|
|
|
|
modes[b->mode], |
|
|
|
|
|
|
|
b->size, |
|
|
|
|
|
|
|
b->color, |
|
|
|
|
|
|
|
HOR, |
|
|
|
|
|
|
|
VER, |
|
|
|
|
|
|
|
ZOOM); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* options */ |
|
|
|
/* options */ |
|
|
|
|
|
|
|
|
|
|
|
int |
|
|
|
int |
|
|
|
@ -250,44 +236,57 @@ error(char *msg, const char *err) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
|
void |
|
|
|
loadchr(char *path) |
|
|
|
setcolor(Brush *b, int c) |
|
|
|
{ |
|
|
|
{ |
|
|
|
FILE *f = fopen(path, "rb"); |
|
|
|
b->color = c; |
|
|
|
if(f == NULL) |
|
|
|
printf("Set Color %d\n", b->color); |
|
|
|
error("Load", "Invalid input file"); |
|
|
|
|
|
|
|
if(!fread(chrbuf, sizeof(chrbuf), 1, f)) |
|
|
|
|
|
|
|
error("Load", "Invalid input size"); |
|
|
|
|
|
|
|
fclose(f); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
|
void |
|
|
|
loadbmp(char *path) |
|
|
|
setmode(Brush *b, int m) |
|
|
|
{ |
|
|
|
{ |
|
|
|
FILE *f = fopen(path, "rb"); |
|
|
|
b->mode = m; |
|
|
|
int i, width = HOR * 8, height = VER * 8, size = 3 * width * height; |
|
|
|
printf("Set Mode %d\n", b->mode); |
|
|
|
unsigned char header[54]; |
|
|
|
} |
|
|
|
unsigned char data[4096 * 256]; |
|
|
|
|
|
|
|
if(!fread(header, sizeof(unsigned char), 54, f)) |
|
|
|
void |
|
|
|
error("Load", "Invalid bmp header"); |
|
|
|
modsize(Brush *b, int mod) |
|
|
|
if(!fread(data, sizeof(unsigned char), size, f)) |
|
|
|
{ |
|
|
|
error("Load", "Invalid bmp body"); |
|
|
|
int res = b->size + mod; |
|
|
|
for(i = 0; i < size; i += 3) |
|
|
|
if(res > 0 && res < 30) |
|
|
|
putchr((i / 3) % width, height - (i / 3) / width - 1, getclr(data[i + 2], data[i + 1], data[i])); |
|
|
|
b->size = res; |
|
|
|
fclose(f); |
|
|
|
printf("Set Size %d\n", b->size); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
|
void |
|
|
|
tochr(Brush *b) |
|
|
|
toggleguide(void) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
GUIDES = !GUIDES; |
|
|
|
|
|
|
|
draw(pixels); |
|
|
|
|
|
|
|
printf("%s Guides\n", GUIDES ? "Show" : "Hide"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
|
|
|
destroy(void) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
newchr(); |
|
|
|
|
|
|
|
draw(pixels); |
|
|
|
|
|
|
|
puts("Destroy"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
|
|
|
exportchr(Brush *b) |
|
|
|
{ |
|
|
|
{ |
|
|
|
FILE *f = fopen("nasu-export.chr", "wb"); |
|
|
|
FILE *f = fopen("nasu-export.chr", "wb"); |
|
|
|
if(!fwrite(chrbuf, sizeof(chrbuf), 1, f)) |
|
|
|
if(!fwrite(chrbuf, sizeof(chrbuf), 1, f)) |
|
|
|
error("Save", "Invalid output file"); |
|
|
|
error("Save", "Invalid output file"); |
|
|
|
fclose(f); |
|
|
|
fclose(f); |
|
|
|
b->edit = 0; |
|
|
|
b->edit = 0; |
|
|
|
|
|
|
|
puts("Exported nasu-export.chr"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
|
void |
|
|
|
tobmp(void) |
|
|
|
renderbmp(void) |
|
|
|
{ |
|
|
|
{ |
|
|
|
SDL_Surface *surface = SDL_GetWindowSurface(gWindow); |
|
|
|
SDL_Surface *surface = SDL_GetWindowSurface(gWindow); |
|
|
|
GUIDES = 0; |
|
|
|
GUIDES = 0; |
|
|
|
@ -299,6 +298,36 @@ tobmp(void) |
|
|
|
surface->pitch); |
|
|
|
surface->pitch); |
|
|
|
SDL_SaveBMP(surface, "nasu-render.bmp"); |
|
|
|
SDL_SaveBMP(surface, "nasu-render.bmp"); |
|
|
|
SDL_FreeSurface(surface); |
|
|
|
SDL_FreeSurface(surface); |
|
|
|
|
|
|
|
puts("Rendered nasu-render.bmp"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
|
|
|
loadchr(char *path) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
FILE *f = fopen(path, "rb"); |
|
|
|
|
|
|
|
if(f == NULL) |
|
|
|
|
|
|
|
error("Load", "Invalid input file"); |
|
|
|
|
|
|
|
if(!fread(chrbuf, sizeof(chrbuf), 1, f)) |
|
|
|
|
|
|
|
error("Load", "Invalid input size"); |
|
|
|
|
|
|
|
fclose(f); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
|
|
|
|
|
loadbmp(char *path) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
FILE *f = fopen(path, "rb"); |
|
|
|
|
|
|
|
int i, width = HOR * 8, height = VER * 8, size = 3 * width * height; |
|
|
|
|
|
|
|
unsigned char header[54]; |
|
|
|
|
|
|
|
unsigned char data[4096 * 256]; |
|
|
|
|
|
|
|
if(!fread(header, sizeof(unsigned char), 54, f)) |
|
|
|
|
|
|
|
error("Load", "Invalid bmp header"); |
|
|
|
|
|
|
|
if(!fread(data, sizeof(unsigned char), size, f)) |
|
|
|
|
|
|
|
error("Load", "Invalid bmp body"); |
|
|
|
|
|
|
|
for(i = 0; i < size; i += 3) { |
|
|
|
|
|
|
|
int x = (i / 3) % width, y = height - (i / 3) / width - 1; |
|
|
|
|
|
|
|
putchr(x, y, getclr(data[i + 2], data[i + 1], data[i])); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
fclose(f); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void |
|
|
|
void |
|
|
|
@ -328,7 +357,6 @@ domouse(SDL_Event *event, Brush *b) |
|
|
|
if(event->button.button == SDL_BUTTON_RIGHT) |
|
|
|
if(event->button.button == SDL_BUTTON_RIGHT) |
|
|
|
b->erase = 0; |
|
|
|
b->erase = 0; |
|
|
|
b->edit = 1; |
|
|
|
b->edit = 1; |
|
|
|
update(b); |
|
|
|
|
|
|
|
break; |
|
|
|
break; |
|
|
|
case SDL_MOUSEBUTTONDOWN: |
|
|
|
case SDL_MOUSEBUTTONDOWN: |
|
|
|
if(event->button.button == SDL_BUTTON_LEFT) { |
|
|
|
if(event->button.button == SDL_BUTTON_LEFT) { |
|
|
|
@ -356,7 +384,7 @@ domouse(SDL_Event *event, Brush *b) |
|
|
|
if(b->down) { |
|
|
|
if(b->down) { |
|
|
|
b->x = (event->motion.x - (PAD * ZOOM)) / ZOOM; |
|
|
|
b->x = (event->motion.x - (PAD * ZOOM)) / ZOOM; |
|
|
|
b->y = (event->motion.y - (PAD * ZOOM)) / ZOOM; |
|
|
|
b->y = (event->motion.y - (PAD * ZOOM)) / ZOOM; |
|
|
|
if(b->mode == 0) |
|
|
|
if(!b->mode) |
|
|
|
line(b->px, b->py, b->x, b->y, b->erase ? 0 : b->color); |
|
|
|
line(b->px, b->py, b->x, b->y, b->erase ? 0 : b->color); |
|
|
|
else |
|
|
|
else |
|
|
|
fill(b->x, b->y, b->mode, b->size, b->erase ? 0 : b->color); |
|
|
|
fill(b->x, b->y, b->mode, b->size, b->erase ? 0 : b->color); |
|
|
|
@ -373,35 +401,25 @@ dokey(SDL_Event *event, Brush *b) |
|
|
|
{ |
|
|
|
{ |
|
|
|
switch(event->key.keysym.sym) { |
|
|
|
switch(event->key.keysym.sym) { |
|
|
|
case SDLK_ESCAPE: quit(); break; |
|
|
|
case SDLK_ESCAPE: quit(); break; |
|
|
|
case SDLK_e: tochr(b); break; |
|
|
|
case SDLK_1: setmode(b, 0); break; |
|
|
|
case SDLK_r: tobmp(); break; |
|
|
|
case SDLK_2: setmode(b, 1); break; |
|
|
|
case SDLK_TAB: b->color = b->color > 2 ? 0 : b->color + 1; break; |
|
|
|
case SDLK_3: setmode(b, 2); break; |
|
|
|
case SDLK_BACKQUOTE: b->mode = 7; break; |
|
|
|
case SDLK_4: setmode(b, 3); break; |
|
|
|
case SDLK_1: b->mode = 0; break; |
|
|
|
case SDLK_5: setmode(b, 4); break; |
|
|
|
case SDLK_2: b->mode = 1; break; |
|
|
|
case SDLK_6: setmode(b, 5); break; |
|
|
|
case SDLK_3: b->mode = 2; break; |
|
|
|
case SDLK_7: setmode(b, 6); break; |
|
|
|
case SDLK_4: b->mode = 3; break; |
|
|
|
case SDLK_e: exportchr(b); break; |
|
|
|
case SDLK_5: b->mode = 4; break; |
|
|
|
case SDLK_r: renderbmp(); break; |
|
|
|
case SDLK_6: b->mode = 5; break; |
|
|
|
case SDLK_a: setcolor(b, 0); break; |
|
|
|
case SDLK_7: b->mode = 6; break; |
|
|
|
case SDLK_s: setcolor(b, 1); break; |
|
|
|
case SDLK_h: |
|
|
|
case SDLK_d: setcolor(b, 2); break; |
|
|
|
GUIDES = !GUIDES; |
|
|
|
case SDLK_f: setcolor(b, 3); break; |
|
|
|
draw(pixels); |
|
|
|
case SDLK_h: toggleguide(); break; |
|
|
|
break; |
|
|
|
case SDLK_z: modsize(b, -1); break; |
|
|
|
case SDLK_n: |
|
|
|
case SDLK_x: modsize(b, 1); break; |
|
|
|
newchr(); |
|
|
|
case SDLK_c: setmode(b, 7); break; |
|
|
|
draw(pixels); |
|
|
|
case SDLK_n: destroy(); break; |
|
|
|
break; |
|
|
|
|
|
|
|
case SDLK_z: |
|
|
|
|
|
|
|
if(b->size > 1) |
|
|
|
|
|
|
|
b->size -= 1; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SDLK_x: |
|
|
|
|
|
|
|
if(b->size < 30) |
|
|
|
|
|
|
|
b->size += 1; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
update(b); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int |
|
|
|
int |
|
|
|
@ -441,11 +459,12 @@ int |
|
|
|
main(int argc, char **argv) |
|
|
|
main(int argc, char **argv) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int ticknext = 0; |
|
|
|
int ticknext = 0; |
|
|
|
Brush brush; |
|
|
|
|
|
|
|
|
|
|
|
brush.erase = 0; |
|
|
|
brush.down = 0; |
|
|
|
brush.down = 0; |
|
|
|
brush.color = 1; |
|
|
|
brush.color = 1; |
|
|
|
brush.edit = 0; |
|
|
|
brush.edit = 0; |
|
|
|
brush.size = 10; |
|
|
|
brush.size = 8; |
|
|
|
brush.mode = 0; |
|
|
|
brush.mode = 0; |
|
|
|
|
|
|
|
|
|
|
|
if(!init()) |
|
|
|
if(!init()) |
|
|
|
@ -459,7 +478,6 @@ main(int argc, char **argv) |
|
|
|
newchr(); |
|
|
|
newchr(); |
|
|
|
|
|
|
|
|
|
|
|
draw(pixels); |
|
|
|
draw(pixels); |
|
|
|
update(&brush); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while(1) { |
|
|
|
while(1) { |
|
|
|
int tick = SDL_GetTicks(); |
|
|
|
int tick = SDL_GetTicks(); |
|
|
|
|