diff --git a/include/rasteriser/rasteriser.h b/include/rasteriser/rasteriser.h
index 3cf639c..894a883 100644
--- a/include/rasteriser/rasteriser.h
+++ b/include/rasteriser/rasteriser.h
@@ -21,6 +21,7 @@ typedef struct {
 
 void draw_wireframe_triangle(window_t *wnd, triangle_t triangle,
                              colour_t colour);
+void draw_filled_triangle(window_t *wnd, triangle_t triangle, colour_t colour);
 void draw_line(window_t *wnd, line_t line, colour_t colour);
 
 #endif // !RASTERISER_H
diff --git a/src/rasteriser/main.c b/src/rasteriser/main.c
index 0d9738d..4fc2bd1 100644
--- a/src/rasteriser/main.c
+++ b/src/rasteriser/main.c
@@ -40,8 +40,9 @@ int main(void) {
 
     clear_window(&window, bg);
 
+    draw_filled_triangle(&window, triangle, (colour_t){.colour = 0x00ff00ff});
     draw_wireframe_triangle(&window, triangle,
-                            (colour_t){.colour = 0xffffffff});
+                            (colour_t){.colour = 0x000000ff});
 
     swap_buffers(&window);
   }
diff --git a/src/rasteriser/rasteriser.c b/src/rasteriser/rasteriser.c
index da68e02..79b61d2 100644
--- a/src/rasteriser/rasteriser.c
+++ b/src/rasteriser/rasteriser.c
@@ -4,18 +4,60 @@
 #include "vector/vec.h"
 #include "window/window.h"
 #include <assert.h>
+#include <math.h>
 #include <stdio.h>
+#include <string.h>
 #include <sys/mman.h>
 
 internal list_float_t *interpolate(i32 i0, f32 d0, i32 i1, f32 d1);
 
+internal inline void order_triangle_points(triangle_t *triangle);
+
 void draw_wireframe_triangle(window_t *wnd, triangle_t triangle,
                              colour_t colour) {
+  order_triangle_points(&triangle);
+
   draw_line(wnd, (line_t){triangle.p0, triangle.p1}, colour);
   draw_line(wnd, (line_t){triangle.p1, triangle.p2}, colour);
   draw_line(wnd, (line_t){triangle.p2, triangle.p0}, colour);
 }
 
+void draw_filled_triangle(window_t *wnd, 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(y0, x0, y1, x1);
+  list_float_t *x12 = interpolate(y1, x1, y2, x2);
+  list_float_t *x02 = interpolate(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, 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) {
+    for (i64 x = list_get(x_left, y - y0); x < list_get(x_right, y - y0); ++x) {
+      set_pixel(wnd, x, y, colour);
+    }
+  }
+}
+
 void draw_line(window_t *wnd, line_t line, colour_t colour) {
   list_float_t *values = NULL;
 
@@ -86,3 +128,15 @@ internal list_float_t *interpolate(i32 i0, f32 d0, i32 i1, f32 d1) {
 
   return values;
 }
+
+internal inline void order_triangle_points(triangle_t *triangle) {
+  if (triangle->p1.y < triangle->p0.y) {
+    vec_swap(vec2i_t, triangle->p0, triangle->p1);
+  }
+  if (triangle->p2.y < triangle->p0.y) {
+    vec_swap(vec2i_t, triangle->p0, triangle->p2);
+  }
+  if (triangle->p2.y < triangle->p1.y) {
+    vec_swap(vec2i_t, triangle->p1, triangle->p2);
+  }
+}