From f72497e1b7a883ef305dde059fdc74c87bb2029b Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sun, 21 Jan 2024 22:36:36 +0000 Subject: [PATCH] Use barycentric coordinates instead of half space for triangle fill --- src/window.c | 61 +++++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/src/window.c b/src/window.c index 189cc7a..49acefd 100644 --- a/src/window.c +++ b/src/window.c @@ -1,5 +1,6 @@ #include "window.h" #include "aliases/aliases.h" +#include "math_utils.h" #include #include #include @@ -89,42 +90,44 @@ void draw_triangle(const window *wnd, triangle triangle, colour colour) { draw_line(wnd, &ln2, colour); } -INTERNAL inline i32 min(i32 a, i32 b, i32 c) { - i32 _min = a <= b ? a : b; - return _min <= c ? _min : c; +INTERNAL inline bool inside_triangle(triangle tri, point p) { + // Based on the following video: + // 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) { - i32 _max = a >= b ? a : b; - 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 +void fill_triangle(const window *wnd, triangle tri, colour colour) { + // Basic triangle filling algorithm inspired by // https://web.archive.org/web/20050408192410/http://sw-shader.sourceforge.net/rasterizer.html - i32 x1 = triangle.p0.x; - i32 x2 = triangle.p1.x; - i32 x3 = triangle.p2.x; + // but uses barycentric coordinates instead of half space + i32 x1 = tri.p0.x; + i32 x2 = tri.p1.x; + i32 x3 = tri.p2.x; - i32 y1 = triangle.p0.y; - i32 y2 = triangle.p1.y; - i32 y3 = triangle.p2.y; + i32 y1 = tri.p0.y; + i32 y2 = tri.p1.y; + i32 y3 = tri.p2.y; // Find bounding rect - i32 min_x = min(x1, x2, x3); - i32 max_x = max(x1, x2, x3); - i32 min_y = min(y1, y2, y3); - i32 max_y = max(y1, y2, y3); + i32 min_x = min(min(x1, x2), x3); + i32 max_x = max(max(x1, x2), x3); + i32 min_y = min(min(y1, y2), y3); + i32 max_y = max(max(y1, y2), y3); for (i32 y = min_y; y < max_y; ++y) { for (i32 x = min_x; x < max_x; ++x) { - if (half_space(x2, x1, y2, y1, x, y) >= 0 && - half_space(x3, x2, y3, y2, x, y) >= 0 && - half_space(x1, x3, y1, y3, x, y) >= 0) { + if (inside_triangle(tri, (point){x, y})) { 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) { - triangle t0 = (triangle){qd.p3, qd.p1, qd.p0}; - triangle t1 = (triangle){qd.p0, qd.p2, qd.p3}; + triangle t0 = (triangle){qd.p0, qd.p1, qd.p2}; + triangle t1 = (triangle){qd.p1, qd.p2, qd.p3}; fill_triangle(wnd, t0, colour); fill_triangle(wnd, t1, colour);