Use barycentric coordinates instead of half space for triangle fill
This commit is contained in:
parent
b329e0feb4
commit
f72497e1b7
61
src/window.c
61
src/window.c
@ -1,5 +1,6 @@
|
|||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include "aliases/aliases.h"
|
#include "aliases/aliases.h"
|
||||||
|
#include "math_utils.h"
|
||||||
#include <SDL2/SDL_rect.h>
|
#include <SDL2/SDL_rect.h>
|
||||||
#include <SDL2/SDL_render.h>
|
#include <SDL2/SDL_render.h>
|
||||||
#include <SDL2/SDL_video.h>
|
#include <SDL2/SDL_video.h>
|
||||||
@ -89,42 +90,44 @@ void draw_triangle(const window *wnd, triangle triangle, colour colour) {
|
|||||||
draw_line(wnd, &ln2, colour);
|
draw_line(wnd, &ln2, colour);
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL inline i32 min(i32 a, i32 b, i32 c) {
|
INTERNAL inline bool inside_triangle(triangle tri, point p) {
|
||||||
i32 _min = a <= b ? a : b;
|
// Based on the following video:
|
||||||
return _min <= c ? _min : c;
|
// https://www.youtube.com/watch?v=HYAgJN3x4GA
|
||||||
|
f32 cy_min_ay = tri.p2.y - tri.p0.y;
|
||||||
|
f32 cx_min_ax = tri.p2.x - tri.p0.x;
|
||||||
|
f32 by_min_ay = tri.p1.y - tri.p0.y;
|
||||||
|
f32 bx_min_ax = tri.p1.x - tri.p0.x;
|
||||||
|
|
||||||
|
f32 w1 =
|
||||||
|
(tri.p0.x * cy_min_ay + (p.y - tri.p0.y) * cx_min_ax - p.x * cy_min_ay) /
|
||||||
|
(by_min_ay * cx_min_ax - bx_min_ax * cy_min_ay);
|
||||||
|
|
||||||
|
f32 w2 = (p.y - tri.p0.y - w1 * by_min_ay) / cy_min_ay;
|
||||||
|
|
||||||
|
return w1 >= 0.0f && w2 >= 0.0f && (w1 + w2) <= 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL inline i32 max(i32 a, i32 b, i32 c) {
|
void fill_triangle(const window *wnd, triangle tri, colour colour) {
|
||||||
i32 _max = a >= b ? a : b;
|
// Basic triangle filling algorithm inspired by
|
||||||
return _max >= c ? _max : c;
|
|
||||||
}
|
|
||||||
|
|
||||||
INTERNAL inline i32 half_space(i32 x1, i32 x2, i32 y1, i32 y2, i32 x, i32 y) {
|
|
||||||
return (x2 - x1) * (y - y1) - (y2 - y1) * (x - x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fill_triangle(const window *wnd, triangle triangle, colour colour) {
|
|
||||||
// Basic triangle filling algorithm from
|
|
||||||
// https://web.archive.org/web/20050408192410/http://sw-shader.sourceforge.net/rasterizer.html
|
// https://web.archive.org/web/20050408192410/http://sw-shader.sourceforge.net/rasterizer.html
|
||||||
i32 x1 = triangle.p0.x;
|
// but uses barycentric coordinates instead of half space
|
||||||
i32 x2 = triangle.p1.x;
|
i32 x1 = tri.p0.x;
|
||||||
i32 x3 = triangle.p2.x;
|
i32 x2 = tri.p1.x;
|
||||||
|
i32 x3 = tri.p2.x;
|
||||||
|
|
||||||
i32 y1 = triangle.p0.y;
|
i32 y1 = tri.p0.y;
|
||||||
i32 y2 = triangle.p1.y;
|
i32 y2 = tri.p1.y;
|
||||||
i32 y3 = triangle.p2.y;
|
i32 y3 = tri.p2.y;
|
||||||
|
|
||||||
// Find bounding rect
|
// Find bounding rect
|
||||||
i32 min_x = min(x1, x2, x3);
|
i32 min_x = min(min(x1, x2), x3);
|
||||||
i32 max_x = max(x1, x2, x3);
|
i32 max_x = max(max(x1, x2), x3);
|
||||||
i32 min_y = min(y1, y2, y3);
|
i32 min_y = min(min(y1, y2), y3);
|
||||||
i32 max_y = max(y1, y2, y3);
|
i32 max_y = max(max(y1, y2), y3);
|
||||||
|
|
||||||
for (i32 y = min_y; y < max_y; ++y) {
|
for (i32 y = min_y; y < max_y; ++y) {
|
||||||
for (i32 x = min_x; x < max_x; ++x) {
|
for (i32 x = min_x; x < max_x; ++x) {
|
||||||
if (half_space(x2, x1, y2, y1, x, y) >= 0 &&
|
if (inside_triangle(tri, (point){x, y})) {
|
||||||
half_space(x3, x2, y3, y2, x, y) >= 0 &&
|
|
||||||
half_space(x1, x3, y1, y3, x, y) >= 0) {
|
|
||||||
draw_point(wnd, (point){x, y}, colour);
|
draw_point(wnd, (point){x, y}, colour);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,8 +147,8 @@ void draw_quad(const window *wnd, quad qd, colour colour) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void fill_quad(const window *wnd, quad qd, colour colour) {
|
void fill_quad(const window *wnd, quad qd, colour colour) {
|
||||||
triangle t0 = (triangle){qd.p3, qd.p1, qd.p0};
|
triangle t0 = (triangle){qd.p0, qd.p1, qd.p2};
|
||||||
triangle t1 = (triangle){qd.p0, qd.p2, qd.p3};
|
triangle t1 = (triangle){qd.p1, qd.p2, qd.p3};
|
||||||
|
|
||||||
fill_triangle(wnd, t0, colour);
|
fill_triangle(wnd, t0, colour);
|
||||||
fill_triangle(wnd, t1, colour);
|
fill_triangle(wnd, t1, colour);
|
||||||
|
Loading…
Reference in New Issue
Block a user