From 8a872aeb54383d2bb929bbac4ed16f4306cee85a Mon Sep 17 00:00:00 2001 From: opfez Date: Sun, 26 Sep 2021 00:09:49 +0200 Subject: [PATCH] initial --- Makefile | 6 ++ graphics.c | 277 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 283 insertions(+) create mode 100644 Makefile create mode 100644 graphics.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2230f62 --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +CC = clang +CFLAGS = -Wall -Wextra -std=c99 -pedantic -O2 +LIBS = -lSDL2 -lm + +graphics: graphics.c + $(CC) $(CFLAGS) $(LIBS) $< -o $@ diff --git a/graphics.c b/graphics.c new file mode 100644 index 0000000..b8d84e2 --- /dev/null +++ b/graphics.c @@ -0,0 +1,277 @@ +#include +#include +#include +#include + +#include + +#define W 800 +#define H 600 +#define PI acos(-1) + +typedef struct { + unsigned char r, g, b, a; +} rgb_t; +const rgb_t WHITE = {255, 255, 255, 255}; +const rgb_t BLACK = {0, 0, 0, 255}; + +typedef struct { + SDL_Renderer *renderer; + SDL_Window *window; + rgb_t *canvas; +} sdl_state_t; + +typedef struct { + int x, y; +} vec2_t; + +typedef struct { + vec2_t a, b, c; +} triangle_t; + +#define max(x, y) ((x) > (y) ? (x) : (y)) +#define min(x, y) ((x) < (y) ? (x) : (y)) +#define swap(x, y) do { \ + (x) ^= (y); \ + (y) ^= (x); \ + (x) ^= (y); \ + } while (0) + +void clear_canvas(rgb_t canvas[], rgb_t colour); +sdl_state_t init_sdl(void); +void free_sdl(sdl_state_t state); +void render(sdl_state_t state); +void plot_rgb(rgb_t canvas[], uint16_t x, uint16_t y, rgb_t colour); +void draw_line(rgb_t canvas[], rgb_t c, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); + +sdl_state_t +init_sdl(void) +{ + SDL_Init(SDL_INIT_VIDEO); + + sdl_state_t ret; + + ret.window = SDL_CreateWindow("Game", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + W, + H, + // TODO: when we have a proper event loop, we can + // add resizing windows. + /* SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN); */ + SDL_WINDOW_MOUSE_CAPTURE | SDL_WINDOW_SHOWN); + ret.renderer = SDL_CreateRenderer(ret.window, -1, SDL_RENDERER_SOFTWARE); + SDL_SetRenderDrawColor(ret.renderer, 0, 0, 0, 255); + SDL_RenderClear(ret.renderer); + SDL_RenderPresent(ret.renderer); + + ret.canvas = malloc(sizeof(rgb_t) * W * H); + clear_canvas(ret.canvas, (rgb_t){0, 0, 0, 255}); + + return ret; +} + +void +free_sdl(sdl_state_t state) +{ + SDL_DestroyRenderer(state.renderer); + SDL_DestroyWindow(state.window); + free(state.canvas); + SDL_Quit(); +} + +void +render(sdl_state_t state) +{ + for (size_t y = 0; y < H; y++) { + for (size_t x = 0; x < W; x++) { + rgb_t curr = state.canvas[x + y * W]; + SDL_SetRenderDrawColor(state.renderer, curr.r, curr.g, curr.b, curr.a); + SDL_RenderDrawPoint(state.renderer, x, y); + } + } + + SDL_RenderPresent(state.renderer); +} + +void +plot_rgb(rgb_t canvas[], uint16_t x, uint16_t y, rgb_t colour) +{ + if (x < W && y < H && x >= 0 && y >= 0) + canvas[x + y * W] = colour; +} + +void +clear_canvas(rgb_t canvas[], rgb_t colour) +{ + for (size_t y = 0; y < H; y++) { + for (size_t x = 0; x < W; x++) { + plot_rgb(canvas, x, y, colour); + } + } +} + +void +draw_line(rgb_t canvas[], rgb_t c, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) +{ + if (x0 > x1) { + swap(x0, x1); + swap(y0, y1); + } + + int dx = abs(x1 - x0); + int dy = abs(y1 - y0); + int eps = 0; + + if (y1 > y0) { + if (dy < dx) { + int y = y0; + for (int x = x0; x <= x1; x++) { + plot_rgb(canvas, x, y, c); + eps += dy; + if ((eps << 1) >= dx) { + y++; + eps -= dx; + } + } + } + else { + int x = x0; + for (int y = y0; y <= y1; y++) { + plot_rgb(canvas, x, y, c); + eps += dx; + if ((eps << 1) >= dy) { + x++; + eps -= dy; + } + } + } + } + else { + if (dy < dx) { + int y = y0; + for (int x = x0; x <= x1; x++) { + plot_rgb(canvas, x, y, c); + eps += dy; + if ((eps << 1) >= dx) { + y--; + eps -= dx; + } + } + } + else { + swap(x0, x1); + swap(y0, y1); + int x = x0; + for (int y = y0; y <= y1; y++) { + plot_rgb(canvas, x, y, c); + eps += dx; + if ((eps << 1) >= dy) { + x--; + eps -= dy; + } + } + } + } +} + +void +draw_triangle(rgb_t canvas[], rgb_t c, triangle_t tri) +{ + draw_line(canvas, c, tri.a.x, tri.a.y, tri.b.x, tri.b.y); + draw_line(canvas, c, tri.b.x, tri.b.y, tri.c.x, tri.c.y); + draw_line(canvas, c, tri.c.x, tri.c.y, tri.a.x, tri.a.y); +} + +vec2_t +midpoint(vec2_t a, vec2_t b) +{ + return (vec2_t) { + (a.x + b.x) / 2, + (a.y + b.y) / 2 + }; +} + +/* saves canvas as a P6 image */ +void +screenshot(rgb_t canvas[]) +{ + time_t t = time(NULL); + char output[64]; + strftime(output, sizeof(output), "screenshot-%Y%m%d-%H%M%S.ppm", localtime(&t)); + FILE *out = fopen(output, "w"); + fprintf(out, "P6\n%d %d\n255\n", W, H); + for (int y = 0; y < H; y++) { + for (int x = 0; x < W; x++) { + rgb_t cur = canvas[x + y * W]; + fprintf(out, "%c%c%c", cur.r, cur.g, cur.b); + } + } + fclose(out); + fprintf(stderr, "Saved %s\n", output); +} + +int +main(void) +{ + sdl_state_t state = init_sdl(); + + SDL_Event event; + int y = 0; + for (;;) { + clear_canvas(state.canvas, BLACK); + + draw_line(state.canvas, + WHITE, + cos(SDL_GetTicks()*0.001) * 300 + W/2, + sin(SDL_GetTicks()*0.001) * 300 + H/2, + W/2, + H/2); + + draw_line(state.canvas, + WHITE, + cos(SDL_GetTicks()*0.001+1.333*PI) * 300 + W/2, + sin(SDL_GetTicks()*0.001+1.333*PI) * 300 + H/2, + W/2, + H/2); + + draw_line(state.canvas, + WHITE, + cos(SDL_GetTicks()*0.001+0.667*PI) * 300 + W/2, + sin(SDL_GetTicks()*0.001+0.667*PI) * 300 + H/2, + W/2, + H/2); + + + /* vec2_t a = {0, 100}, b = {200, 0}, c = {200, 200}; */ + vec2_t a = { + cos(SDL_GetTicks()*0.001) * 300 + W/2, + sin(SDL_GetTicks()*0.001) * 300 + H/2 + }; + vec2_t b = { + cos(SDL_GetTicks()*0.001+0.667*PI) * 300 + W/2, + sin(SDL_GetTicks()*0.001+0.667*PI) * 300 + H/2 + }; + vec2_t c = { + cos(SDL_GetTicks()*0.001+1.333*PI) * 300 + W/2, + sin(SDL_GetTicks()*0.001+1.333*PI) * 300 + H/2, + }; + for (int i = 0; i < 10; i++) { + draw_triangle(state.canvas, WHITE, (triangle_t){a, b, c}); + vec2_t tmp_a = midpoint(a, b); + vec2_t tmp_b = midpoint(b, c); + vec2_t tmp_c = midpoint(c, a); + a = tmp_a; + b = tmp_b; + c = tmp_c; + } + + render(state); + if (SDL_PollEvent(&event) && event.type == SDL_QUIT) + break; + else + y++; + } + + free_sdl(state); +}