#include "rasteriser/rasteriser.h" #include "aliases.h" #include "list/typed_list.h" #include "math/math_utils.h" #include "mem_arena.h" #include "vector/vec.h" #include "window/window.h" #include #include #include #include #include internal list_float_t *interpolate(Arena *arena, i32 i0, f32 d0, i32 i1, f32 d1); internal inline void order_triangle_points(triangle_t *triangle); void draw_wireframe_triangle(window_t *wnd, Arena *arena, triangle_t triangle, colour_t colour) { order_triangle_points(&triangle); draw_line(wnd, arena, (line_t){triangle.p0, triangle.p1}, colour); draw_line(wnd, arena, (line_t){triangle.p1, triangle.p2}, colour); draw_line(wnd, arena, (line_t){triangle.p2, triangle.p0}, colour); } void draw_filled_triangle(window_t *wnd, Arena *arena, triangle_t triangle, colour_t colour) { order_triangle_points(&triangle); i32 x0 = triangle.p0.x; i32 y0 = triangle.p0.y; i32 x1 = triangle.p1.x; i32 y1 = triangle.p1.y; i32 x2 = triangle.p2.x; i32 y2 = triangle.p2.y; list_float_t *x01 = interpolate(arena, y0, x0, y1, x1); list_float_t *x12 = interpolate(arena, y1, x1, y2, x2); list_float_t *x02 = interpolate(arena, y0, x0, y2, x2); list_float_t *x012 = NULL; list_pop(x01); // Last element of x01 is a duplicate of first element in x12 list_merge(f32, arena, x012, x01, x12); list_float_t *x_left; list_float_t *x_right; u64 middle = (u64)(floorf((f32)(x02->count) / 2.0f)); if (list_get(x02, middle) < list_get(x012, middle)) { x_left = x02; x_right = x012; } else { x_left = x012; x_right = x02; } for (i64 y = y0; y <= y2; ++y) { i32 index = y - y0; for (i64 x = (i64)list_get(x_left, index); x < list_get(x_right, index); ++x) { set_pixel(wnd, x, y, colour); } } } void draw_shaded_triangle(window_t *wnd, Arena *arena, triangle_t triangle, colour_t colour) { order_triangle_points(&triangle); i32 x0 = triangle.p0.x; i32 y0 = triangle.p0.y; i32 x1 = triangle.p1.x; i32 y1 = triangle.p1.y; i32 x2 = triangle.p2.x; i32 y2 = triangle.p2.y; list_float_t *x01 = interpolate(arena, y0, x0, y1, x1); list_float_t *x12 = interpolate(arena, y1, x1, y2, x2); list_float_t *x02 = interpolate(arena, y0, x0, y2, x2); list_float_t *x012 = NULL; list_pop(x01); // Last element of x01 is a duplicate of first element in x12 list_merge(f32, arena, x012, x01, x12); f32 h0 = triangle.h0; f32 h1 = triangle.h1; f32 h2 = triangle.h2; list_float_t *h01 = interpolate(arena, y0, h0, y1, h1); list_float_t *h12 = interpolate(arena, y1, h1, y2, h2); list_float_t *h02 = interpolate(arena, y0, h0, y2, h2); list_float_t *h012 = NULL; list_pop(h01); // Last element of h01 is a duplicate of first element in h12 list_merge(f32, arena, h012, h01, h12); list_float_t *x_left; list_float_t *x_right; list_float_t *h_left; list_float_t *h_right; u64 middle = (u64)(floorf((f32)(x02->count) / 2.0f)); if (list_get(x02, middle) < list_get(x012, middle)) { x_left = x02; h_left = h02; x_right = x012; h_right = h012; } else { x_left = x012; h_left = h012; x_right = x02; h_right = h02; } list_float_t *h_segment = NULL; i32 index = -1; i64 xl = -1; i64 xr = -1; colour_t shaded_colour = (colour_t){0}; for (i64 y = y0; y <= y2; ++y) { index = y - y0; xl = (i64)list_get(x_left, index); xr = (i64)list_get(x_right, index); for (i64 x = xl; x < xr; ++x) { h_segment = interpolate(arena, xl, list_get(h_left, index), xr, list_get(h_right, index)); shaded_colour = colour_mul(colour, list_get(h_segment, x - xl)); set_pixel(wnd, x, y, shaded_colour); } } } void draw_line(window_t *wnd, Arena *arena, line_t line, colour_t colour) { list_float_t *values = NULL; if (abs(line.p1.x - line.p0.x) > abs(line.p1.y - line.p0.y)) { if (line.p1.x < line.p0.x) { swap(vec2i_t, line.p0, line.p1); } i32 x0 = line.p0.x; i32 y0 = line.p0.y; i32 x1 = line.p1.x; i32 y1 = line.p1.y; values = interpolate(arena, x0, y0, x1, y1); if (!values) { return; } for (i32 x = x0; x <= x1; ++x) { set_pixel(wnd, x, (i32)(list_get(values, x - x0)), colour); } } else { if (line.p1.y < line.p0.y) { swap(vec2i_t, line.p0, line.p1); } i32 x0 = line.p0.x; i32 y0 = line.p0.y; i32 x1 = line.p1.x; i32 y1 = line.p1.y; values = interpolate(arena, y0, x0, y1, x1); if (!values) { return; } for (i32 y = y0; y <= y1; ++y) { set_pixel(wnd, (i32)(list_get(values, y - y0)), y, colour); } } } internal list_float_t *interpolate(Arena *arena, i32 i0, f32 d0, i32 i1, f32 d1) { list_float_t *values; if (i0 == i1) { values = list_create_with_capacity(f32, arena, 20); if (values) { list_append(f32, arena, values, d0); } return values; } values = list_create(f32, arena); if (!values) { return NULL; } f32 a = (d1 - d0) / ((f32)i1 - i0); f32 d = d0; for (i32 i = i0; i <= i1; ++i) { list_append(f32, arena, values, d); d += a; } return values; } internal inline void order_triangle_points(triangle_t *triangle) { if (triangle->p1.y < triangle->p0.y) { swap(vec2i_t, triangle->p0, triangle->p1); swap(f32, triangle->h0, triangle->h1); } if (triangle->p2.y < triangle->p0.y) { swap(vec2i_t, triangle->p0, triangle->p2); swap(f32, triangle->h0, triangle->h2); } if (triangle->p2.y < triangle->p1.y) { swap(vec2i_t, triangle->p1, triangle->p2); swap(f32, triangle->h1, triangle->h2); } }