filled triangles
This commit is contained in:
parent
8a872aeb54
commit
d7607503f3
211
graphics.c
211
graphics.c
|
@ -1,3 +1,4 @@
|
|||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue