From d7607503f3699fa8294cff60badcdb190d84f4f6 Mon Sep 17 00:00:00 2001 From: opfez Date: Sun, 26 Sep 2021 19:10:41 +0200 Subject: [PATCH] filled triangles --- graphics.c | 211 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 160 insertions(+), 51 deletions(-) diff --git a/graphics.c b/graphics.c index b8d84e2..b41044f 100644 --- a/graphics.c +++ b/graphics.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -14,6 +15,9 @@ typedef struct { } 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}; typedef struct { SDL_Renderer *renderer; @@ -80,6 +84,7 @@ free_sdl(sdl_state_t state) SDL_Quit(); } +// TODO: Highly unefficient. Makes a *lot* of SDL calls. void render(sdl_state_t state) { @@ -129,7 +134,7 @@ draw_line(rgb_t canvas[], rgb_t c, uint16_t x0, uint16_t y0, uint16_t x1, uint16 for (int x = x0; x <= x1; x++) { plot_rgb(canvas, x, y, c); eps += dy; - if ((eps << 1) >= dx) { + if ((eps * 2) >= dx) { y++; eps -= dx; } @@ -140,7 +145,7 @@ draw_line(rgb_t canvas[], rgb_t c, uint16_t x0, uint16_t y0, uint16_t x1, uint16 for (int y = y0; y <= y1; y++) { plot_rgb(canvas, x, y, c); eps += dx; - if ((eps << 1) >= dy) { + if ((eps * 2) >= dy) { x++; eps -= dy; } @@ -153,7 +158,7 @@ draw_line(rgb_t canvas[], rgb_t c, uint16_t x0, uint16_t y0, uint16_t x1, uint16 for (int x = x0; x <= x1; x++) { plot_rgb(canvas, x, y, c); eps += dy; - if ((eps << 1) >= dx) { + if ((eps * 2) >= dx) { y--; eps -= dx; } @@ -166,7 +171,7 @@ draw_line(rgb_t canvas[], rgb_t c, uint16_t x0, uint16_t y0, uint16_t x1, uint16 for (int y = y0; y <= y1; y++) { plot_rgb(canvas, x, y, c); eps += dx; - if ((eps << 1) >= dy) { + if ((eps * 2) >= dy) { x--; eps -= dy; } @@ -175,6 +180,13 @@ draw_line(rgb_t canvas[], rgb_t c, uint16_t x0, uint16_t y0, uint16_t x1, uint16 } } +void +draw_horizontal_line(rgb_t canvas[], rgb_t c, uint16_t x0, uint16_t x1, uint16_t y) +{ + for (uint16_t x = x0; x < x1; x++) + canvas[x + y * W] = c; +} + void draw_triangle(rgb_t canvas[], rgb_t c, triangle_t tri) { @@ -183,6 +195,96 @@ draw_triangle(rgb_t canvas[], rgb_t c, triangle_t tri) draw_line(canvas, c, tri.c.x, tri.c.y, tri.a.x, tri.a.y); } +void +fill_bottom_flat_triangle(rgb_t canvas[], rgb_t c, triangle_t tri) +{ + assert(tri.b.y == tri.c.y); + + if (tri.b.x > tri.c.x) { + swap(tri.b.y, tri.c.y); + swap(tri.b.x, tri.c.x); + } + + float slope0 = (float)(tri.b.x - tri.a.x) / (float)(tri.b.y - tri.a.y); + float slope1 = (float)(tri.c.x - tri.a.x) / (float)(tri.c.y - tri.a.y); + + float x0, x1; + x0 = x1 = tri.a.x; + + for (int y = tri.a.y; y <= tri.b.y; y++) { + draw_horizontal_line(canvas, c, x0, x1, y); + x0 += slope0; + x1 += slope1; + } +} + +void +fill_top_flat_triangle(rgb_t canvas[], rgb_t c, triangle_t tri) +{ + assert(tri.a.y == tri.b.y); + + if (tri.a.x > tri.b.x) { + swap(tri.a.y, tri.b.y); + swap(tri.a.x, tri.b.x); + } + + float slope0 = (float)(tri.c.x - tri.a.x) / (float)(tri.c.y - tri.a.y); + float slope1 = (float)(tri.c.x - tri.b.x) / (float)(tri.c.y - tri.b.y); + + float x0, x1; + x0 = x1 = tri.c.x; + + for (int y = tri.c.y; y > tri.a.y; y--) { + draw_horizontal_line(canvas, c, x0, x1, y); + x0 -= slope0; + x1 -= slope1; + } +} + +/* http://www.sunshine2k.de/coding/java/TriangleRasterization/TriangleRasterization.html */ +void +fill_triangle(rgb_t canvas[], rgb_t c, triangle_t tri) +{ + /* tri.a <= tri.b <= tri.c */ + if (tri.b.y < tri.a.y) { + swap(tri.b.y, tri.a.y); + swap(tri.b.x, tri.a.x); + } + if (tri.c.y < tri.a.y) { + swap(tri.c.y, tri.a.y); + swap(tri.c.x, tri.a.x); + } + if (tri.c.y < tri.b.y) { + swap(tri.c.y, tri.b.y); + swap(tri.c.x, tri.b.x); + } + + /* simple solutions */ + if (tri.b.y == tri.c.y) { + fill_bottom_flat_triangle(canvas, c, tri); + } + else if (tri.a.y == tri.b.y) { + fill_top_flat_triangle(canvas, c, tri); + } + else { + vec2_t trid = { + (tri.a.x + ((float)(tri.b.y - tri.a.y) / (float)(tri.c.y - tri.a.y)) * (tri.c.x - tri.a.x)), + tri.b.y}; + + if (tri.a.y > tri.b.y) { + swap(tri.a.y, tri.b.y); + swap(tri.a.x, tri.b.x); + } + + fill_bottom_flat_triangle(canvas, c, (triangle_t) { + tri.a, tri.b, trid + }); + fill_top_flat_triangle(canvas, c, (triangle_t) { + tri.b, trid, tri.c + }); + } +} + vec2_t midpoint(vec2_t a, vec2_t b) { @@ -211,66 +313,73 @@ screenshot(rgb_t canvas[]) fprintf(stderr, "Saved %s\n", output); } +void +cool_effect(rgb_t canvas[]) +{ + draw_line(canvas, + WHITE, + cos(SDL_GetTicks()*0.001) * 300 + W/2, + sin(SDL_GetTicks()*0.001) * 300 + H/2, + W/2, + H/2); + + draw_line(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(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++) { + fill_triangle(canvas, i % 2 ? BLACK : 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; + } +} + int main(void) { sdl_state_t state = init_sdl(); SDL_Event event; - int y = 0; for (;;) { + uint32_t buttons = SDL_GetMouseState(NULL, NULL); + if (buttons & SDL_BUTTON(3)) + break; + 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; - } + cool_effect(state.canvas); render(state); if (SDL_PollEvent(&event) && event.type == SDL_QUIT) break; - else - y++; } free_sdl(state);