This commit is contained in:
opfez 2021-09-26 00:09:49 +02:00
commit 8a872aeb54
2 changed files with 283 additions and 0 deletions

6
Makefile Normal file
View File

@ -0,0 +1,6 @@
CC = clang
CFLAGS = -Wall -Wextra -std=c99 -pedantic -O2
LIBS = -lSDL2 -lm
graphics: graphics.c
$(CC) $(CFLAGS) $(LIBS) $< -o $@

277
graphics.c Normal file
View File

@ -0,0 +1,277 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
#include <SDL2/SDL.h>
#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);
}