@@ 1,21 @@
+MIT License
+
+Copyright (c) Devine Lu Linvega
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
@@ 1,443 @@
+#include <SDL2/SDL.h>
+#include <stdio.h>
+
+typedef struct Point {
+ int x;
+ int y;
+} Point;
+
+typedef struct Size {
+ int w;
+ int h;
+} Size;
+
+typedef struct Brush {
+ int mode;
+ int size;
+ int erase;
+ int down;
+ int button;
+ Point pos;
+ Point prev;
+} Brush;
+
+static int SCREEN_WIDTH = 512;
+static int SCREEN_HEIGHT = 512;
+static int FPS = 30;
+int ZOOM = 1;
+
+uint32_t* pixels;
+
+SDL_Window* gWindow = NULL;
+SDL_Renderer* gRenderer = NULL;
+SDL_Texture* gTexture = NULL;
+
+/* helpers */
+
+Point*
+setpt(Point* p, int x, int y)
+{
+ p->x = x;
+ p->y = y;
+ return p;
+}
+
+/* noodle */
+
+int
+patt(int mode, int size, Point p)
+{
+ if(mode == 1)
+ return ((p.x + p.y) % 4) == 0 && ((p.y - p.x) % 4) == 0;
+ if(mode == 2)
+ return ((p.x + p.y) % 2) == 0 && ((p.y - p.x) % 2) == 0;
+ if(mode == 3)
+ return 1;
+ if(mode == 4)
+ return p.y % size == 0;
+ if(mode == 5)
+ return p.x % size == 0;
+ if(mode == 6)
+ return (p.x + p.y) % size == 0 || (p.x - p.y) % size == 0;
+ return 0;
+}
+
+void
+pixel(uint32_t* dst, Point p, int color)
+{
+ dst[p.y * SCREEN_WIDTH + p.x] = color;
+}
+
+void
+line(uint32_t* dst, Point p0, Point p1, int color)
+{
+ double dx = abs(p1.x - p0.x), sx = p0.x < p1.x ? 1 : -1;
+ double dy = -abs(p1.y - p0.y), sy = p0.y < p1.y ? 1 : -1;
+ double err = dx + dy, e2;
+ for(;;) {
+ pixel(dst, p0, color);
+ if(p0.x == p1.x && p0.y == p1.y)
+ break;
+ e2 = 2 * err;
+ if(e2 >= dy) {
+ err += dy;
+ p0.x += sx;
+ }
+ if(e2 <= dx) {
+ err += dx;
+ p0.y += sy;
+ }
+ }
+}
+
+void
+fill(uint32_t* dst, int mode, int size, Point p0, int color)
+{
+ int x, y;
+ Point p;
+ for(x = 0; x < size; ++x)
+ for(y = 0; y < size; ++y) {
+ setpt(&p, p0.x + x, p0.y + y);
+ if(patt(mode, size, p))
+ pixel(dst, p, color);
+ }
+}
+
+void export(uint32_t* dst)
+{
+ /* TODO: chr file export */
+}
+
+void
+title(Brush* b)
+{
+ /* TODO: Format a title that includes brush mode, brush size, canvas size and offset */
+ printf("mode:%d size:%d\n", b->mode, b->size);
+ if(b->mode == 0)
+ SDL_SetWindowTitle(gWindow, "noodle(line)");
+ else if(b->mode == 1)
+ SDL_SetWindowTitle(gWindow, "noodle(tone1)");
+ else if(b->mode == 2)
+ SDL_SetWindowTitle(gWindow, "noodle(tone2)");
+ else if(b->mode == 3)
+ SDL_SetWindowTitle(gWindow, "noodle(full)");
+ else
+ SDL_SetWindowTitle(gWindow, "noodle(other)");
+}
+
+void
+move(Point* p, int x, int y)
+{
+ int req = 0;
+ if(p->x != x) {
+ setpt(p, x, p->y);
+ req = 1;
+ }
+ if(p->y != y) {
+ setpt(p, p->x, y);
+ req = 1;
+ }
+ /* TODO MOVE DRAWING
+ if(req)
+ debug(b);
+ */
+}
+
+void
+select(Brush* b, int m, int s)
+{
+ int req = 0;
+ if(b->mode != m) {
+ b->mode = m;
+ req = 1;
+ }
+ if(b->size != s) {
+ b->size = s;
+ req = 1;
+ }
+ if(req)
+ title(b);
+}
+
+void
+zoom(void)
+{
+}
+
+void
+clean(void)
+{
+}
+
+/* SDL */
+
+int
+error(char* msg, const char* err)
+{
+ printf("Error %s: %s\n", msg, err);
+ return 0;
+}
+
+int
+init_array(void)
+{
+ int i, j;
+ pixels = (uint32_t*)malloc(SCREEN_WIDTH * SCREEN_HEIGHT * sizeof(uint32_t));
+
+ if(pixels == NULL)
+ return error("init_array", "could not allocate memory for pixels");
+
+ for(i = 0; i < SCREEN_HEIGHT; i++)
+ for(j = 0; j < SCREEN_WIDTH; j++)
+ pixels[i * SCREEN_WIDTH + j] = 0xffffff;
+
+ return 1;
+}
+
+int
+init(void)
+{
+ if(SDL_Init(SDL_INIT_VIDEO) < 0)
+ return error("init", SDL_GetError());
+
+ gWindow = SDL_CreateWindow("nasu6", SDL_WINDOWPOS_UNDEFINED,
+ SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH,
+ SCREEN_HEIGHT, 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, SCREEN_WIDTH,
+ SCREEN_HEIGHT);
+
+ if(gTexture == NULL)
+ return error("texture", SDL_GetError());
+
+ init_array();
+
+ return 1;
+}
+
+void
+quit(void)
+{
+ free(pixels);
+ SDL_DestroyTexture(gTexture);
+ gTexture = NULL;
+ SDL_DestroyRenderer(gRenderer);
+ gRenderer = NULL;
+ SDL_DestroyWindow(gWindow);
+ gWindow = NULL;
+ SDL_Quit();
+ exit(0);
+}
+
+void
+handle_mouse(SDL_Event* event, Brush* b)
+{
+ switch(event->type) {
+ case SDL_MOUSEBUTTONUP:
+ if(event->button.button == SDL_BUTTON_LEFT)
+ b->down = 0;
+ if(event->button.button == SDL_BUTTON_RIGHT)
+ b->erase = 0;
+ setpt(&b->prev, 0, 0);
+ break;
+ case SDL_MOUSEBUTTONDOWN:
+ if(event->button.button == SDL_BUTTON_LEFT)
+ b->down = 1;
+ if(event->button.button == SDL_BUTTON_RIGHT)
+ b->erase = 1;
+ setpt(&b->prev, event->motion.x, event->motion.y);
+ case SDL_MOUSEMOTION:
+ if(b->down) {
+ setpt(&b->pos, event->motion.x, event->motion.y);
+ if(b->mode == 0)
+ line(pixels, b->prev, b->pos, b->erase ? 0xffffff : 0x000000);
+ else
+ fill(pixels, b->mode, b->size, b->pos, b->erase ? 0xffffff : 0x000000);
+ setpt(&b->prev, b->pos.x, b->pos.y);
+ }
+ break;
+ }
+}
+
+void
+handle_keypress(SDL_Event* event, Brush* b, Point* o)
+{
+ switch(event->key.keysym.sym) {
+ case SDLK_ESCAPE:
+ quit();
+ break;
+ /* I/O */
+ case SDLK_e:
+ export(pixels);
+ break;
+ /* move */
+ case SDLK_w:
+ move(o, o->x, o->y--);
+ break;
+ case SDLK_a:
+ move(o, o->x--, o->y);
+ break;
+ case SDLK_s:
+ move(o, o->x, o->y++);
+ break;
+ case SDLK_d:
+ move(o, o->x++, o->y);
+ break;
+ case SDLK_q:
+ move(o, 0, 0);
+ break;
+ /* Mode */
+ case SDLK_1:
+ select(b, 0, b->size);
+ break;
+ case SDLK_2:
+ select(b, 1, b->size);
+ break;
+ case SDLK_3:
+ select(b, 2, b->size);
+ break;
+ case SDLK_4:
+ select(b, 3, b->size);
+ break;
+ case SDLK_5:
+ select(b, 4, b->size);
+ break;
+ case SDLK_6:
+ select(b, 5, b->size);
+ break;
+ case SDLK_7:
+ select(b, 6, b->size);
+ break;
+ /* brush */
+ case SDLK_z:
+ select(b, b->mode, b->size - 1);
+ break;
+ case SDLK_x:
+ select(b, b->mode, b->size + 1);
+ break;
+ /* Special */
+ case SDLK_BACKQUOTE:
+ zoom();
+ case SDLK_SPACE:
+ clean();
+ break;
+ }
+}
+
+void
+paint(uint32_t* dst, int id, int color)
+{
+ int ti = id / 64;
+ int px = (ti / 256) * 128;
+ int py = 0;
+ int tx = (ti % 16) * 8;
+ int ty = ((ti / 16) * 8) % 128;
+ Point p;
+ p.x = px + tx + (id % 8);
+ p.y = py + ty + ((id % 64) / 8);
+ if(color == 1)
+ pixel(dst, p, 0x00FFFF);
+ else if(color == 2)
+ pixel(dst, p, 0xFF0000);
+ else if(color == 3)
+ pixel(dst, p, 0x00FF00);
+ else
+ pixel(dst, p, 0x0000FF);
+}
+
+int
+load(FILE* f)
+{
+ int b, i, j, id;
+ int ch1;
+ int ch2;
+ int color;
+ unsigned char buffer[1024 * 4];
+ if(!fread(buffer, sizeof(buffer), 1, f)) {
+ printf("ERROR\n");
+ return 0;
+ }
+
+ id = 0;
+ for(b = 0; b < (1024 * 4) - 16; b += 16) {
+ for(i = 0; i < 8; i++) {
+ for(j = 7; j >= 0; j--) {
+ ch1 = buffer[b + i];
+ ch2 = buffer[b + i + 16];
+ color = ((ch1 >> j) & 0x1) + (((ch2 >> j) & 0x1) << 1);
+ paint(pixels, id, color);
+ id++;
+ }
+ }
+ }
+
+ return 1;
+}
+
+int
+main(int argc, char** argv)
+{
+ int ticknext = 0;
+ Brush brush;
+ Point offset;
+ FILE* f;
+
+ if(!init())
+ return error("Could not initialize SDL", "");
+
+ if(argc < 2)
+ return error("Missing input file", "");
+
+ f = fopen(argv[1], "rb");
+
+ if(f == NULL)
+ return error("Invalid input file.", "");
+
+ load(f);
+
+ select(&brush, 0, 10);
+ move(&offset, 0, 0);
+
+ /* main game loop */
+
+ while(1) {
+
+ int tick = SDL_GetTicks();
+ SDL_Event event;
+
+ if(SDL_QUIT == event.type)
+ exit(0);
+
+ if(tick < ticknext)
+ SDL_Delay(ticknext - tick);
+
+ ticknext = tick + (1000 / FPS);
+
+ SDL_UpdateTexture(gTexture, NULL, pixels, SCREEN_WIDTH * sizeof(uint32_t));
+
+ while(SDL_PollEvent(&event) != 0) {
+ if(event.type == SDL_MOUSEBUTTONUP ||
+ event.type == SDL_MOUSEBUTTONDOWN ||
+ event.type == SDL_MOUSEMOTION) {
+ handle_mouse(&event, &brush);
+ } else if(event.type == SDL_KEYDOWN) {
+ handle_keypress(&event, &brush, &offset);
+ }
+ }
+ SDL_RenderClear(gRenderer);
+ SDL_RenderCopy(gRenderer, gTexture, NULL, NULL);
+ SDL_RenderPresent(gRenderer);
+ }
+
+ quit();
+ return 0;
+}