diff --git a/Makefile b/Makefile index 956ac31..d9c8bb2 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -CFLAGS = -Wall -Wextra -std=c99 -pedantic -O2 +CFLAGS = -Wall -Wextra -std=c99 -pedantic -O2 -g LIBS = -lSDL2 -lm -out: main.c - $(CC) $(CFLAGS) $(LIBS) $< -o $@ +out: main.c types.h + $(CC) $(CFLAGS) $(LIBS) main.c -o $@ diff --git a/main.c b/main.c index fef2f21..02386ee 100644 --- a/main.c +++ b/main.c @@ -1,3 +1,5 @@ +#define DEBUG + #include #include #include @@ -7,67 +9,97 @@ #include +/* cursed struct definitions, thanks bx */ +#include "types.h" + #define W 800 #define H 600 #define PI 3.14159265358979323844 +int wireframe = 0; + +void +die(char *msg) +{ + fprintf(stderr, "%s\n", msg); + exit(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}; -const rgb_t RED = {255, 0, 0, 255}; -const rgb_t GREEN = {0, 255, 0, 255}; -const rgb_t BLUE = {0, 0, 255, 255}; +} rgb; +const rgb WHITE = {255, 255, 255, 255}; +const rgb BLACK = {0, 0, 0, 255}; +const rgb RED = {255, 0, 0, 255}; +const rgb GREEN = {0, 255, 0, 255}; +const rgb BLUE = {0, 0, 255, 255}; typedef struct { SDL_Renderer *renderer; SDL_Window *window; SDL_Texture *tex; - rgb_t *canvas; -} sdl_state_t; + rgb *canvas; +} sdl_state; typedef struct { - double x, y; -} vec2_t; + vec2 a, b, c; +} triangle2; typedef struct { - double x, y, z; -} vec3_t; - -typedef struct { - double range; -} cam_t; - -typedef struct { - vec2_t a, b, c; -} triangle2_t; - -typedef struct { - vec3_t a, b, c; -} triangle3_t; + vec3 a, b, c; +} triangle3; typedef struct { uint32_t vertex_num; uint32_t tri_num; /* for loops */ uint32_t index_num; - vec3_t *vertices; + vec3 *vertices; uint32_t *indices; -} mesh_t; +} mesh; typedef struct { double nums[3][3]; -} matrix3x3_t; +} matrix3x3; -mesh_t -new_mesh(uint32_t vertex_num, uint32_t tri_num, uint32_t index_num, vec3_t vertices[], uint32_t indices[]) +vec3 +vec3_matrix3x3_multiply(vec3 v, matrix3x3 r) { - mesh_t ret; + return (vec3) { + .x = (v.x * r.nums[0][0]) + (v.y * r.nums[0][1]) + (v.z * r.nums[0][2]), + .y = (v.x * r.nums[1][0]) + (v.y * r.nums[1][1]) + (v.z * r.nums[1][2]), + .z = (v.x * r.nums[2][0]) + (v.y * r.nums[2][1]) + (v.z * r.nums[2][2]) + }; +} + +camera +new_camera(double range, vec3 pos, vec3 target, vec3 up) +{ + if (pos.x == target.x && + pos.y == target.y && + pos.z == target.z) + die("cannot create camera with same target and position"); + + camera ret = { + .range = range, + .pos = pos, + .target = target, + .up = up, + }; + ret.dir = vec3_normalize(vec3_sub(pos, target)); + ret.right = vec3_normalize(vec3_cross(up, ret.dir)); + + return ret; +} + +mesh +new_mesh(uint32_t vertex_num, uint32_t tri_num, uint32_t index_num, vec3 vertices[], uint32_t indices[]) +{ + mesh ret; ret.vertex_num = vertex_num; ret.tri_num = tri_num; ret.index_num = index_num; - ret.vertices = malloc(sizeof(vec3_t) * vertex_num); + ret.vertices = malloc(sizeof(vec3) * vertex_num); for (uint32_t i = 0; i < vertex_num; i++) ret.vertices[i] = vertices[i]; ret.indices = malloc(sizeof(uint32_t) * index_num); @@ -77,7 +109,7 @@ new_mesh(uint32_t vertex_num, uint32_t tri_num, uint32_t index_num, vec3_t verti return ret; } -void free_mesh(mesh_t mesh) { free(mesh.vertices); free(mesh.indices); } +void free_mesh(mesh mesh) { free(mesh.vertices); free(mesh.indices); } #define max(x, y) ((x) > (y) ? (x) : (y)) #define min(x, y) ((x) < (y) ? (x) : (y)) @@ -86,6 +118,7 @@ void free_mesh(mesh_t mesh) { free(mesh.vertices); free(mesh.indices); } (y) ^= (x); \ (x) ^= (y); \ } while (0) +#define clamp(x, min, max) (((x) >= (min)) ? ((x) <= (max)) ? (x) : (max) : (min)) void swapd(double *a, double *b) @@ -95,20 +128,20 @@ swapd(double *a, double *b) *b = tmp; } -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[], int32_t x, int32_t y, rgb_t colour); -void draw_line(rgb_t canvas[], rgb_t c, vec2_t p0, vec2_t p1); -vec2_t project(cam_t c, vec3_t v); +void clear_canvas(rgb canvas[], rgb colour); +sdl_state init_sdl(void); +void free_sdl(sdl_state state); +void render(sdl_state state); +void plot_rgb(rgb canvas[], int32_t x, int32_t y, rgb colour); +void draw_line(rgb canvas[], rgb c, vec2 p0, vec2 p1); +vec2 project(camera c, vec3 v); -sdl_state_t +sdl_state init_sdl(void) { SDL_Init(SDL_INIT_VIDEO); - sdl_state_t ret; + sdl_state ret; ret.window = SDL_CreateWindow("Game", SDL_WINDOWPOS_UNDEFINED, @@ -129,14 +162,14 @@ init_sdl(void) SDL_TEXTUREACCESS_STATIC, W, H); - ret.canvas = malloc(sizeof(rgb_t) * W * H); - clear_canvas(ret.canvas, (rgb_t){0, 0, 0, 255}); + ret.canvas = malloc(sizeof(rgb) * W * H); + clear_canvas(ret.canvas, (rgb){0, 0, 0, 255}); return ret; } void -free_sdl(sdl_state_t state) +free_sdl(sdl_state state) { SDL_DestroyRenderer(state.renderer); SDL_DestroyWindow(state.window); @@ -146,7 +179,7 @@ free_sdl(sdl_state_t state) } uint32_t -rgb_to_int(rgb_t c) +rgb_to_int(rgb c) { return (((uint32_t)c.a << 24) | ((uint32_t)c.r << 16) @@ -156,20 +189,7 @@ rgb_to_int(rgb_t c) /* display the contents of the canvas */ void -oldrender(sdl_state_t state) -{ - for (size_t y = 0; y < H; y++) { - for (size_t x = 0; x < W; x++) { - rgb_t cur = state.canvas[x + y * W]; - SDL_SetRenderDrawColor(state.renderer, cur.r, cur.g, cur.b, cur.a); - SDL_RenderDrawPoint(state.renderer, x, y); - } - } - SDL_RenderPresent(state.renderer); -} - -void -render(sdl_state_t state) +render(sdl_state state) { uint32_t pixels[H*W]; for (size_t y = 0; y < H; y++) { @@ -186,21 +206,21 @@ render(sdl_state_t state) void -plot_rgb(rgb_t canvas[], int32_t x, int32_t y, rgb_t colour) +plot_rgb(rgb canvas[], int32_t x, int32_t y, rgb colour) { if (x < W && y < H && x >= 0 && y >= 0) canvas[x + y * W] = colour; } void -clear_canvas_trailing(rgb_t canvas[], rgb_t colour) +clear_canvas_trailing(rgb canvas[], rgb colour) { for (size_t i = 0; i < W * H; i++) if ((rand()&31)==0) canvas[i] = colour; } void -clear_canvas(rgb_t canvas[], rgb_t colour) +clear_canvas(rgb canvas[], rgb colour) { for (size_t i = 0; i < W * H; i += 2) { canvas[i] = colour; @@ -209,7 +229,7 @@ clear_canvas(rgb_t canvas[], rgb_t colour) } void -draw_line(rgb_t canvas[], rgb_t c, vec2_t p0, vec2_t p1) +draw_line(rgb canvas[], rgb c, vec2 p0, vec2 p1) { int32_t x0 = (int32_t)p0.x, x1 = (int32_t)p1.x, @@ -278,17 +298,19 @@ draw_line(rgb_t canvas[], rgb_t c, vec2_t p0, vec2_t p1) } void -draw_horizontal_line(rgb_t canvas[], rgb_t c, uint32_t x0, uint32_t x1, uint32_t y) +draw_horizontal_line(rgb canvas[], rgb c, int32_t x0, int32_t x1, int32_t y) { - for (uint32_t x = x0; x <= x1; x++) { - size_t index = x + y * W; - if (index < H * W) - canvas[x + y * W] = c; - } + if (y < 0) return; + if (x0 < 0) x0 = 0; + if (x1 >= W) x1 = W - 1; + if (y >= H) return; + + for (int32_t x = x0; x <= x1; x++) + canvas[x + y * W] = c; } void -draw_triangle(rgb_t canvas[], rgb_t col, triangle2_t tri) +draw_triangle(rgb canvas[], rgb col, triangle2 tri) { draw_line(canvas, col, tri.a, tri.b); draw_line(canvas, col, tri.b, tri.c); @@ -296,59 +318,118 @@ draw_triangle(rgb_t canvas[], rgb_t col, triangle2_t tri) } void -fill_bottom_flat_triangle(rgb_t canvas[], rgb_t c, triangle2_t tri) +fill_bottom_flat_triangle(rgb canvas[], rgb c, triangle2 tri) { - assert(tri.b.y == tri.c.y); - - if (tri.b.x > tri.c.x) { - swapd(&tri.b.y, &tri.c.y); + if (tri.b.x > tri.c.x) swapd(&tri.b.x, &tri.c.x); - } - double slope0 = (tri.b.x - tri.a.x) / (tri.b.y - tri.a.y); - double slope1 = (tri.c.x - tri.a.x) / (tri.c.y - tri.a.y); + /* tri.a x + * / \ + * / \ + * tri.b x_____x tri.c + */ - double x0, x1; - x0 = x1 = tri.a.x; + int32_t ax = (int32_t)tri.a.x, + bx = (int32_t)tri.b.x, + cx = (int32_t)tri.c.x, + ay = (int32_t)tri.a.y, + by = (int32_t)tri.b.y, + cy = (int32_t)tri.c.y; - for (int y = tri.a.y; y <= tri.b.y; y++) { - /* draw_line(canvas, c, (vec2_t){x0, y}, (vec2_t){x1, y}); */ - draw_horizontal_line(canvas, c, x0, x1, y); - x0 += slope0; - x1 += slope1; + assert(ay <= cy); + assert(ay <= by); + + assert(bx <= cx); + + int32_t dx_right = abs(cx - ax); + int32_t dy_right = abs(cy - ay); + int32_t dx_left = abs(bx - ax); + int32_t dy_left = abs(by - ay); + + int32_t eps_r = 0; + int32_t eps_l = 0; + int32_t xr = ax; + int32_t xl = ax; + + int32_t xr_change = ax < cx ? 1 : -1; + int32_t xl_change = ax < bx ? 1 : -1; + + for (int32_t y = ay; y < by; y++) { + eps_r += dx_right; + eps_l += dx_left; + while (eps_r > 0) { + eps_r -= dy_right; + xr += xr_change; + } + while (eps_l > 0) { + eps_l -= dy_left; + xl += xl_change; + } + draw_horizontal_line(canvas, c, xl, xr, y); } } void -fill_top_flat_triangle(rgb_t canvas[], rgb_t c, triangle2_t tri) +fill_top_flat_triangle(rgb canvas[], rgb c, triangle2 tri) { - assert(tri.a.y == tri.b.y); - - if (tri.a.x > tri.b.x) { - swapd(&tri.a.y, &tri.b.y); + if (tri.a.x > tri.b.x) swapd(&tri.a.x, &tri.b.x); - } - double slope0 = (tri.c.x - tri.a.x) / (tri.c.y - tri.a.y); - double slope1 = (tri.c.x - tri.b.x) / (tri.c.y - tri.b.y); - - double x0, x1; - x0 = x1 = tri.c.x; - - /* note: the predicate here is y > tri.a.y - 1 because using tri.a.y - * directly causes small dots on the points of triangles. + /* tri.a x_____x tri.b + * \ / + * \ / + * tri.c x */ - for (int y = tri.c.y; y > tri.a.y - 1; y--) { - draw_horizontal_line(canvas, c, x0, x1, y); - /* draw_line(canvas, c, (vec2_t){x0, y}, (vec2_t){x1, y}); */ - x0 -= slope0; - x1 -= slope1; + + int32_t ax = (int32_t)tri.a.x, + bx = (int32_t)tri.b.x, + cx = (int32_t)tri.c.x, + ay = (int32_t)tri.a.y, + by = (int32_t)tri.b.y, + cy = (int32_t)tri.c.y; + + assert(cy >= ay); + assert(cy >= by); + + assert(ax <= bx); + + int32_t dx_right = abs(cx - bx); + int32_t dy_right = abs(cy - by); + int32_t dx_left = abs(cx - ax); + int32_t dy_left = abs(cy - ay); + + int32_t eps_r = 0; + int32_t eps_l = 0; + int32_t xr = cx; + int32_t xl = cx; + + int32_t xr_change = cx < bx ? 1 : -1; + int32_t xl_change = cx < ax ? 1 : -1; + + int32_t y; + for (y = cy; y > by; y--) { + eps_r += dx_right; + eps_l += dx_left; + while (eps_r > 0) { + eps_r -= dy_right; + xr += xr_change; + } + while (eps_l > 0) { + eps_l -= dy_left; + xl += xl_change; + } + draw_horizontal_line(canvas, c, xl, xr, y); } + + /* We're missing one line, but setting the loop conditional to be y >= by + * messes up the drawing. + */ + draw_horizontal_line(canvas, c, xl, xr, y); } /* http://www.sunshine2k.de/coding/java/TriangleRasterization/TriangleRasterization.html */ void -fill_triangle(rgb_t canvas[], rgb_t c, triangle2_t tri) +fill_triangle(rgb canvas[], rgb c, triangle2 tri) { /* tri.a <= tri.b <= tri.c */ if (tri.b.y < tri.a.y) { @@ -365,14 +446,14 @@ fill_triangle(rgb_t canvas[], rgb_t c, triangle2_t tri) } /* simple solutions */ - if (tri.b.y == tri.c.y) { + if ((int32_t)tri.b.y == (int32_t)tri.c.y) { fill_bottom_flat_triangle(canvas, c, tri); } - else if (tri.a.y == tri.b.y) { + else if ((int32_t)tri.a.y == (int32_t)tri.b.y) { fill_top_flat_triangle(canvas, c, tri); } else { - vec2_t trid = { + vec2 trid = { (tri.a.x + (tri.b.y - tri.a.y) / (tri.c.y - tri.a.y) * (tri.c.x - tri.a.x)), tri.b.y}; @@ -381,35 +462,35 @@ fill_triangle(rgb_t canvas[], rgb_t c, triangle2_t tri) swapd(&tri.a.x, &tri.b.x); } - fill_bottom_flat_triangle(canvas, c, (triangle2_t) { - tri.a, tri.b, trid - }); - fill_top_flat_triangle(canvas, c, (triangle2_t) { + fill_top_flat_triangle(canvas, c, (triangle2) { tri.b, trid, tri.c }); + fill_bottom_flat_triangle(canvas, c, (triangle2) { + tri.a, tri.b, trid + }); } } -vec2_t -midpoint(vec2_t a, vec2_t b) +vec2 +midpoint(vec2 a, vec2 b) { - return (vec2_t) { + return (vec2) { (a.x + b.x) / 2, (a.y + b.y) / 2 }; } -vec2_t -project(cam_t c, vec3_t v) +vec2 +project(camera c, vec3 v) { double r = 200 / (v.z + c.range); - return (vec2_t){W / 2 + r * v.x, H / 2 + r * v.y}; + return (vec2){W / 2 + r * v.x, H / 2 + r * v.y}; } -triangle2_t -project_triangle(cam_t c, triangle3_t tri) +triangle2 +project_triangle(camera c, triangle3 tri) { - return (triangle2_t) { + return (triangle2) { .a = project(c, tri.a), .b = project(c, tri.b), .c = project(c, tri.c), @@ -418,7 +499,7 @@ project_triangle(cam_t c, triangle3_t tri) /* saves canvas as a P6 image */ void -screenshot(rgb_t canvas[]) +screenshot(rgb canvas[]) { time_t t = time(NULL); char output[64]; @@ -427,7 +508,7 @@ screenshot(rgb_t canvas[]) 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]; + rgb cur = canvas[x + y * W]; fprintf(out, "%c%c%c", cur.r, cur.g, cur.b); } } @@ -436,107 +517,30 @@ screenshot(rgb_t canvas[]) } void -cool_effect(rgb_t canvas[]) -{ - draw_line(canvas, - WHITE, - (vec2_t) { - cos(SDL_GetTicks()*0.001) * 300 + W/2, - sin(SDL_GetTicks()*0.001) * 300 + H/2, - }, - (vec2_t) { - W/2, - H/2 - }); - - draw_line(canvas, - WHITE, - (vec2_t) { - cos(SDL_GetTicks()*0.001+1.333*PI) * 300 + W/2, - sin(SDL_GetTicks()*0.001+1.333*PI) * 300 + H/2, - }, - (vec2_t) { - W/2, - H/2 - }); - - draw_line(canvas, - WHITE, - (vec2_t) { - cos(SDL_GetTicks()*0.001+0.667*PI) * 300 + W/2, - sin(SDL_GetTicks()*0.001+0.667*PI) * 300 + H/2, - }, - (vec2_t) { - 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++) { - fill_triangle(canvas, i % 2 ? BLACK : WHITE, (triangle2_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; - } -} - -/* void */ -/* draw_plane(rgb_t canvas[], cam_t c, rgb_t col, mesh_t plane) */ -/* { */ -/* assert(plane.n == 2); */ - -/* draw_triangle(canvas, col, project_triangle(c, plane.tris[0])); */ -/* draw_triangle(canvas, col, project_triangle(c, plane.tris[1])); */ -/* } */ - -void -draw_mesh(rgb_t canvas[], - rgb_t col, - cam_t c, - mesh_t mesh -) +draw_mesh(rgb canvas[], rgb col, camera c, mesh mesh) { for (uint32_t i = 0; i < mesh.tri_num; i++) { - draw_triangle(canvas, col, project_triangle(c, (triangle3_t) { - mesh.vertices[mesh.indices[3*i ]], - mesh.vertices[mesh.indices[3*i+1]], - mesh.vertices[mesh.indices[3*i+2]], - })); + if (wireframe) + draw_triangle(canvas, col, project_triangle(c, (triangle3) { + mesh.vertices[mesh.indices[3*i ]], + mesh.vertices[mesh.indices[3*i+1]], + mesh.vertices[mesh.indices[3*i+2]], + })); + else + fill_triangle(canvas, col, project_triangle(c, (triangle3) { + mesh.vertices[mesh.indices[3*i ]], + mesh.vertices[mesh.indices[3*i+1]], + mesh.vertices[mesh.indices[3*i+2]], + })); } } -vec3_t -vec3_matrix3x3_multiply(vec3_t v, matrix3x3_t r) -{ - return (vec3_t) { - .x = (v.x * r.nums[0][0]) + (v.y * r.nums[0][1]) + (v.z * r.nums[0][2]), - .y = (v.x * r.nums[1][0]) + (v.y * r.nums[1][1]) + (v.z * r.nums[1][2]), - .z = (v.x * r.nums[2][0]) + (v.y * r.nums[2][1]) + (v.z * r.nums[2][2]) - }; -} - -matrix3x3_t -matrix3x3_multiply(matrix3x3_t r, matrix3x3_t s) +matrix3x3 +matrix3x3_multiply(matrix3x3 r, matrix3x3 s) { #define a r.nums #define b s.nums - return (matrix3x3_t) { + return (matrix3x3) { .nums = {{a[0][0] * b[0][0] + a[0][1] * b[1][0] + a[0][2] * b[2][0], a[0][0] * b[0][1] + a[0][1] * b[1][1] + a[0][2] * b[2][1], @@ -552,49 +556,57 @@ matrix3x3_multiply(matrix3x3_t r, matrix3x3_t s) #undef b } -matrix3x3_t +double +to_deg(double deg) +{ + return deg * 2 * PI / 360.0; +} + +matrix3x3 x_rotation(double deg) { - return (matrix3x3_t) { + return (matrix3x3) { .nums = - {{1, 0, 0}, - {0, cos(deg/360.0), -sin(deg/360.0)}, - {0, sin(deg/360.0), cos(deg/360.0)}} + {{1, 0, 0}, + {0, cos(to_deg(deg)), -sin(to_deg(deg))}, + {0, sin(to_deg(deg)), cos(to_deg(deg))}} }; } -matrix3x3_t +matrix3x3 y_rotation(double deg) { - return (matrix3x3_t) { + return (matrix3x3) { .nums = - {{ cos(deg/360.0), 0, sin(deg/360.0)}, - { 0, 1, 0}, - {-sin(deg/360.0), 0, cos(deg/360.0)}} + {{ cos(to_deg(deg)), 0, sin(to_deg(deg))}, + { 0, 1, 0}, + {-sin(to_deg(deg)), 0, cos(to_deg(deg))}} }; } -matrix3x3_t +matrix3x3 z_rotation(double deg) { - return (matrix3x3_t) { + return (matrix3x3) { .nums = - {{cos(deg/360.0), -sin(deg/360.0), 0}, - {sin(deg/360.0), cos(deg/360.0), 0}, - {0, 0, 1}} + {{cos(to_deg(deg)), -sin(to_deg(deg)), 0}, + {sin(to_deg(deg)), cos(to_deg(deg)), 0}, + {0, 0, 1}} }; } +#include "other.h" int main(void) { - sdl_state_t state = init_sdl(); - cam_t cam = {180}; + sdl_state state = init_sdl(); + camera cam = new_camera(180, (vec3){0, 0, 3}, (vec3){0, 0, 0}, UP); + print_camera(&cam); SDL_Event event; - vec3_t vertices[8] = { + vec3 vertices[8] = { /* front */ {0, 0, 0}, {100, 0, 0}, @@ -626,23 +638,27 @@ main(void) 3, 2, 6, 6, 7, 3, }; - const mesh_t box = new_mesh(8, 12, 3 * 12, vertices, indices); - mesh_t box_copy = new_mesh(8, 12, 3 * 12, vertices, indices); + const mesh box = new_mesh(8, 12, 3 * 12, vertices, indices); + mesh box_copy = new_mesh(8, 12, 3 * 12, vertices, indices); uint64_t t = 0; for (;;) { - matrix3x3_t m = matrix3x3_multiply( + double elapsed, start = SDL_GetPerformanceCounter(); + + matrix3x3 m = matrix3x3_multiply( matrix3x3_multiply( - z_rotation(0.7 * t), - y_rotation(0.8 * t)), - x_rotation(0.9 * t)); + z_rotation(1.2 * t), + y_rotation(1.1 * t)), + x_rotation(1.0 * t)); int x, y; uint32_t buttons = SDL_GetMouseState(&x, &y); if (buttons & SDL_BUTTON(2)) screenshot(state.canvas); + else if (buttons & (SDL_BUTTON(1))) + wireframe = !wireframe; clear_canvas(state.canvas, BLACK); @@ -656,6 +672,9 @@ main(void) if (SDL_PollEvent(&event) && event.type == SDL_QUIT) break; + elapsed = (SDL_GetPerformanceCounter() - start) / (double)SDL_GetPerformanceFrequency() * 1000.0; + SDL_Delay(clamp(16.666f - elapsed, 0, 1000)); + t++; } diff --git a/other.h b/other.h new file mode 100644 index 0000000..eea7d7e --- /dev/null +++ b/other.h @@ -0,0 +1,60 @@ +void +cool_effect(rgb canvas[]) +{ + draw_line(canvas, + WHITE, + (vec2) { + cos(SDL_GetTicks()*0.001) * 300 + W/2, + sin(SDL_GetTicks()*0.001) * 300 + H/2, + }, + (vec2) { + W/2, + H/2 + }); + + draw_line(canvas, + WHITE, + (vec2) { + cos(SDL_GetTicks()*0.001+1.333*PI) * 300 + W/2, + sin(SDL_GetTicks()*0.001+1.333*PI) * 300 + H/2, + }, + (vec2) { + W/2, + H/2 + }); + + draw_line(canvas, + WHITE, + (vec2) { + cos(SDL_GetTicks()*0.001+0.667*PI) * 300 + W/2, + sin(SDL_GetTicks()*0.001+0.667*PI) * 300 + H/2, + }, + (vec2) { + W/2, + H/2 + }); + + + /* vec2 a = {0, 100}, b = {200, 0}, c = {200, 200}; */ + vec2 a = { + cos(SDL_GetTicks()*0.001) * 300 + W/2, + sin(SDL_GetTicks()*0.001) * 300 + H/2 + }; + vec2 b = { + cos(SDL_GetTicks()*0.001+0.667*PI) * 300 + W/2, + sin(SDL_GetTicks()*0.001+0.667*PI) * 300 + H/2 + }; + vec2 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++) { + fill_triangle(canvas, i % 2 ? BLACK : WHITE, (triangle2){a, b, c}); + vec2 tmp_a = midpoint(a, b); + vec2 tmp_b = midpoint(b, c); + vec2 tmp_c = midpoint(c, a); + a = tmp_a; + b = tmp_b; + c = tmp_c; + } +} diff --git a/types.h b/types.h new file mode 100644 index 0000000..f477875 --- /dev/null +++ b/types.h @@ -0,0 +1,128 @@ +#ifdef SUB_INCLUDE_TYPES +#undef SUB_INCLUDE_TYPES + +STRUCT(vec2) + FIELD(x, double) + FIELD(y, double) +END_STRUCT + +STRUCT(vec3) + FIELD(x, double) + FIELD(y, double) + FIELD(z, double) +END_STRUCT + +STRUCT(vec4) + FIELD(x, double) + FIELD(y, double) + FIELD(z, double) + FIELD(w, double) +END_STRUCT + +STRUCT(camera) + FIELD(range, double) + FIELD(pos, vec3) + FIELD(target, vec3) + FIELD(up, vec3) + FIELD(dir, vec3) + FIELD(right, vec3) +END_STRUCT + +#else // sub include guard + +#include + +#define STRUCT(N) typedef struct N N; struct N { +#define END_STRUCT }; +#define FIELD(N, T) T N; +#define SUB_INCLUDE_TYPES +#include __FILE__ +// undefs to get rid of redef warnings +#undef STRUCT +#undef FIELD +#undef END_STRUCT + +void print_double(double *d) { + printf(" %f ", *d); +} + +#define STRUCT(N) \ + void print_##N (N *s) { \ + printf("(" #N ") {"); +#define FIELD(N, T) \ + print_##T(&s -> N); +#define END_STRUCT \ + printf("}\n"); \ + } +#define SUB_INCLUDE_TYPES +#include __FILE__ +// undefs to get rid of redef warnings +#undef STRUCT +#undef FIELD +#undef END_STRUCT + +const vec3 UP = {0, 1, 0}; + +vec3 +vec3_add(vec3 u, vec3 v) +{ + return (vec3) { + .x = u.x + v.x, + .y = u.y + v.y, + .z = u.z + v.z, + }; +} + +vec3 +vec3_sub(vec3 u, vec3 v) +{ + return (vec3) { + .x = u.x - v.x, + .y = u.y - v.y, + .z = u.z - v.z, + }; +} + +vec3 +vec3_cross(vec3 u, vec3 v) +{ + return (vec3) { + .x = u.y * v.z - u.z * v.y, + .y = u.z * v.x - u.x * v.z, + .z = u.x * v.y - u.y * v.x, + }; +} + +vec3 +vec3_normalize(vec3 u) +{ + double len = sqrt(u.x*u.x + u.y*u.y + u.z*u.z); + return (vec3) { + .x = u.x / len, + .y = u.y / len, + .z = u.z / len, + }; +} + +vec4 +vec4_add(vec4 u, vec4 v) +{ + return (vec4) { + .x = u.x + v.x, + .y = u.y + v.y, + .z = u.z + v.z, + }; +} + +vec4 +vec4_sub(vec4 u, vec4 v) +{ + return (vec4) { + .x = u.x - v.x, + .y = u.y - v.y, + .z = u.z - v.z, + }; +} + + +#endif /* SUB_INCLUDE_TYPES */