diff --git a/include/camera/camera.h b/include/camera/camera.h
index c13a57c..ee1ffc6 100644
--- a/include/camera/camera.h
+++ b/include/camera/camera.h
@@ -9,7 +9,7 @@ typedef struct {
   vec3f_t rotation;
 } camera_t;
 
-vec2i_t project_point(vec3f_t point, const window_t *wnd,
-                      const camera_t *camera, vec3f_t viewport);
+mat4x4f_t inverse_camera_translation_matrix(const camera_t *camera);
+mat4x4f_t inverse_camera_rotation_matrix(const camera_t *camera);
 
 #endif // !CAMERA_H
diff --git a/include/rasteriser/rasteriser.h b/include/rasteriser/rasteriser.h
index 0029e08..36caf6b 100644
--- a/include/rasteriser/rasteriser.h
+++ b/include/rasteriser/rasteriser.h
@@ -41,12 +41,18 @@ typedef struct {
 } model_t;
 
 typedef struct {
-  model_t *model;
+  f32 scale;
+  vec3f_t rotation;
   vec3f_t position;
+} transform_t;
+
+typedef struct {
+  model_t *model;
+  transform_t transform;
 } instance_t;
 
-void render_instance(window_t *wnd, Arena *arena, const camera_t *camera,
-                     vec3f_t viewport, const instance_t *instance_t);
+void render_instance(window_t *wnd, Arena *arena, mat3x4f_t proj_cam_mat,
+                     const instance_t *instance);
 void draw_wireframe_triangle(window_t *wnd, Arena *arena, triangle_t triangle);
 void draw_filled_triangle(window_t *wnd, Arena *arena, triangle_t triangle);
 void draw_shaded_triangle(window_t *wnd, Arena *arena, triangle_t triangle);
diff --git a/include/vector/vec.h b/include/vector/vec.h
index 599e403..b0c8299 100644
--- a/include/vector/vec.h
+++ b/include/vector/vec.h
@@ -39,6 +39,25 @@ typedef struct {
   f32 w;
 } vec4f_t;
 
+typedef struct {
+  vec3f_t row0;
+  vec3f_t row1;
+  vec3f_t row2;
+} mat3x3f_t;
+
+typedef struct {
+  vec4f_t row0;
+  vec4f_t row1;
+  vec4f_t row2;
+} mat3x4f_t;
+
+typedef struct {
+  vec4f_t row0;
+  vec4f_t row1;
+  vec4f_t row2;
+  vec4f_t row3;
+} mat4x4f_t;
+
 #define vec_add(T, v1, v2) vec_add_##T(v1, v2)
 #define vec_sub(T, v1, v2) vec_sub_##T(v1, v2)
 #define vec_mul(T, v1, v2) vec_mul_##T(v1, v2)
@@ -103,4 +122,12 @@ f32 vec_dot_vec4f_t(vec4f_t v1, vec4f_t v2);
 f32 vec_magnitude_vec4f_t(vec4f_t v);
 vec4f_t vec_unit_vec4f_t(vec4f_t v);
 
+mat4x4f_t get_translation_matrix(vec3f_t translation);
+mat4x4f_t get_rotation_matrix(vec3f_t rotation);
+mat4x4f_t get_scaling_matrix(vec3f_t scale);
+mat3x3f_t get_rotation_mat3x3f(vec3f_t rotation);
+vec3f_t mul_mat3x4f_by_vec4f(mat3x4f_t mat, vec4f_t vec);
+mat3x4f_t mul_mat3x4f_by_mat4x4f(mat3x4f_t mat1, mat4x4f_t mat2);
+mat4x4f_t mul_mat4x4f(mat4x4f_t mat1, mat4x4f_t mat2);
+
 #endif // !VEC_H
diff --git a/src/camera/camera.c b/src/camera/camera.c
index 70a7e6f..152a054 100644
--- a/src/camera/camera.c
+++ b/src/camera/camera.c
@@ -1,15 +1,12 @@
 #include "camera/camera.h"
 #include "vector/vec.h"
-#include "window/window.h"
 
-vec2i_t project_point(vec3f_t point, const window_t *wnd,
-                      const camera_t *camera, vec3f_t viewport) {
-  if (point.z == 0.0f) {
-    return (vec2i_t){.x = 0, .y = 0};
-  }
-
-  f32 x = point.x * viewport.z / point.z;
-  f32 y = point.y * viewport.z / point.z;
-
-  return viewport_to_window(wnd, x, y, viewport);
+mat4x4f_t inverse_camera_translation_matrix(const camera_t *camera) {
+  vec3f_t inverse_translation = vec_mul_num(vec3f_t, camera->position, -1.0f);
+  return get_translation_matrix(inverse_translation);
+}
+
+mat4x4f_t inverse_camera_rotation_matrix(const camera_t *camera) {
+  vec3f_t inverse_rotation = vec_mul_num(vec3f_t, camera->rotation, -1.0f);
+  return get_rotation_matrix(inverse_rotation);
 }
diff --git a/src/rasteriser/main.c b/src/rasteriser/main.c
index f33506f..3eb555b 100644
--- a/src/rasteriser/main.c
+++ b/src/rasteriser/main.c
@@ -2,6 +2,7 @@
 #include "list/typed_list.h"
 #include "mem_arena.h"
 #include "mem_utils.h"
+#include "misc/misc_utils.h"
 #include "rasteriser/rasteriser.h"
 #include "vector/vec.h"
 #include "window/window.h"
@@ -36,50 +37,67 @@ int main(void) {
     return EXIT_FAILURE;
   }
   // Vertices
-  list_append(vec3f_t, arena, vertices, ((vec3f_t){1, 1, 1}));
-  list_append(vec3f_t, arena, vertices, ((vec3f_t){-1, 1, 1}));
-  list_append(vec3f_t, arena, vertices, ((vec3f_t){-1, -1, 1}));
-  list_append(vec3f_t, arena, vertices, ((vec3f_t){1, -1, 1}));
-  list_append(vec3f_t, arena, vertices, ((vec3f_t){1, 1, -1}));
-  list_append(vec3f_t, arena, vertices, ((vec3f_t){-1, 1, -1}));
-  list_append(vec3f_t, arena, vertices, ((vec3f_t){-1, -1, -1}));
-  list_append(vec3f_t, arena, vertices, ((vec3f_t){1, -1, -1}));
+  vec3f_t verts[] = {
+      (vec3f_t){1, 1, 1},    (vec3f_t){-1, 1, 1},  (vec3f_t){-1, -1, 1},
+      (vec3f_t){1, -1, 1},   (vec3f_t){1, 1, -1},  (vec3f_t){-1, 1, -1},
+      (vec3f_t){-1, -1, -1}, (vec3f_t){1, -1, -1},
+  };
+  for (u64 i = 0; i < ARR_LEN(verts); ++i) {
+    list_append(vec3f_t, arena, vertices, verts[i]);
+  }
 
   list_scene_triangle_t *triangles = list_create(scene_triangle_t, arena);
   if (!triangles) {
     return EXIT_FAILURE;
   }
   // Triangles
-  list_append(scene_triangle_t, arena, triangles,
-              ((scene_triangle_t){0, 1, 2, (colour_t){.colour = 0xff0000ff}}));
-  list_append(scene_triangle_t, arena, triangles,
-              ((scene_triangle_t){0, 2, 3, (colour_t){.colour = 0xff0000ff}}));
-  list_append(scene_triangle_t, arena, triangles,
-              ((scene_triangle_t){4, 0, 3, (colour_t){.colour = 0x00ff00ff}}));
-  list_append(scene_triangle_t, arena, triangles,
-              ((scene_triangle_t){4, 3, 7, (colour_t){.colour = 0x00ff00ff}}));
-  list_append(scene_triangle_t, arena, triangles,
-              ((scene_triangle_t){5, 4, 7, (colour_t){.colour = 0x0000ffff}}));
-  list_append(scene_triangle_t, arena, triangles,
-              ((scene_triangle_t){5, 7, 6, (colour_t){.colour = 0x0000ffff}}));
-  list_append(scene_triangle_t, arena, triangles,
-              ((scene_triangle_t){1, 5, 6, (colour_t){.colour = 0xffff00ff}}));
-  list_append(scene_triangle_t, arena, triangles,
-              ((scene_triangle_t){1, 6, 2, (colour_t){.colour = 0xffff00ff}}));
-  list_append(scene_triangle_t, arena, triangles,
-              ((scene_triangle_t){4, 5, 1, (colour_t){.colour = 0xff00ffff}}));
-  list_append(scene_triangle_t, arena, triangles,
-              ((scene_triangle_t){4, 1, 0, (colour_t){.colour = 0xff00ffff}}));
-  list_append(scene_triangle_t, arena, triangles,
-              ((scene_triangle_t){2, 6, 7, (colour_t){.colour = 0x00ffffff}}));
-  list_append(scene_triangle_t, arena, triangles,
-              ((scene_triangle_t){2, 7, 3, (colour_t){.colour = 0x00ffffff}}));
+  scene_triangle_t tris[] = {
+      (scene_triangle_t){0, 1, 2, (colour_t){.colour = 0xff0000ff}},
+      (scene_triangle_t){0, 2, 3, (colour_t){.colour = 0xff0000ff}},
+      (scene_triangle_t){4, 0, 3, (colour_t){.colour = 0x00ff00ff}},
+      (scene_triangle_t){4, 3, 7, (colour_t){.colour = 0x00ff00ff}},
+      (scene_triangle_t){5, 4, 7, (colour_t){.colour = 0x0000ffff}},
+      (scene_triangle_t){5, 7, 6, (colour_t){.colour = 0x0000ffff}},
+      (scene_triangle_t){1, 5, 6, (colour_t){.colour = 0xffff00ff}},
+      (scene_triangle_t){1, 6, 2, (colour_t){.colour = 0xffff00ff}},
+      (scene_triangle_t){4, 5, 1, (colour_t){.colour = 0xff00ffff}},
+      (scene_triangle_t){4, 1, 0, (colour_t){.colour = 0xff00ffff}},
+      (scene_triangle_t){2, 6, 7, (colour_t){.colour = 0x00ffffff}},
+      (scene_triangle_t){2, 7, 3, (colour_t){.colour = 0x00ffffff}},
+  };
+  for (u64 i = 0; i < ARR_LEN(tris); ++i) {
+    list_append(scene_triangle_t, arena, triangles, tris[i]);
+  }
 
   model_t cube = {.vertices = vertices, .triangles = triangles};
-  instance_t cube_01 = {.model = &cube,
-                        .position = (vec3f_t){-1.5f, 0.0f, 8.0f}};
-  instance_t cube_02 = {.model = &cube,
-                        .position = (vec3f_t){1.7f, 1.5f, 7.0f}};
+  instance_t cube_01 = {
+      .model = &cube,
+      .transform =
+          {
+              .scale = 1.0f,
+              .rotation = (vec3f_t){0},
+              .position = (vec3f_t){-1.5f, 0.0f, 8.0f},
+          },
+  };
+  instance_t cube_02 = {
+      .model = &cube,
+      .transform =
+          {
+              .scale = 1.0f,
+              .rotation = {0},
+              .position = (vec3f_t){1.7f, 1.5f, 7.0f},
+          },
+  };
+
+  mat3x4f_t proj_matrix = {
+      (vec4f_t){viewport.z * window.width / viewport.x, 0.0f, 0.0f, 0.0f},
+      (vec4f_t){0.0f, viewport.z * window.height / viewport.y, 0.0f, 0.0f},
+      (vec4f_t){0.0f, 0.0f, 1.0f, 0.0f},
+  };
+  mat4x4f_t cam_inverse_rotation = {0};
+  mat4x4f_t cam_inverse_translation = {0};
+  mat4x4f_t cam_matrix = {0};
+  mat3x4f_t proj_cam_matrix = {0};
 
   bool running = true;
   SDL_Event event = {0};
@@ -105,10 +123,15 @@ int main(void) {
       }
     }
 
+    cam_inverse_rotation = inverse_camera_rotation_matrix(&camera);
+    cam_inverse_translation = inverse_camera_translation_matrix(&camera);
+    cam_matrix = mul_mat4x4f(cam_inverse_rotation, cam_inverse_translation);
+    proj_cam_matrix = mul_mat3x4f_by_mat4x4f(proj_matrix, cam_matrix);
+
     clear_window(&window, bg);
 
-    render_instance(&window, arena, &camera, viewport, &cube_01);
-    render_instance(&window, arena, &camera, viewport, &cube_02);
+    render_instance(&window, arena, proj_cam_matrix, &cube_01);
+    render_instance(&window, arena, proj_cam_matrix, &cube_02);
 
     swap_buffers(&window);
 
diff --git a/src/rasteriser/rasteriser.c b/src/rasteriser/rasteriser.c
index 49c66c1..0914fba 100644
--- a/src/rasteriser/rasteriser.c
+++ b/src/rasteriser/rasteriser.c
@@ -12,23 +12,34 @@
 #include <sys/mman.h>
 
 internal list_float *interpolate(Arena *arena, i32 i0, f32 d0, i32 i1, f32 d1);
-
 internal inline void order_triangle_points(triangle_t *triangle);
 
-void render_instance(window_t *wnd, Arena *arena, const camera_t *camera,
-                     vec3f_t viewport, const instance_t *instance) {
+void render_instance(window_t *wnd, Arena *arena, mat3x4f_t proj_cam_mat,
+                     const instance_t *instance) {
   list_vec2i_t *projected = list_create_with_capacity(
       vec2i_t, arena, instance->model->vertices->count * sizeof(vec3f_t));
   if (!projected) {
     return;
   }
 
+  mat4x4f_t t_mat = get_translation_matrix(instance->transform.position);
+  mat4x4f_t r_mat = get_rotation_matrix(instance->transform.rotation);
+  mat4x4f_t s_mat = get_scaling_matrix((vec3f_t){instance->transform.scale,
+                                                 instance->transform.scale,
+                                                 instance->transform.scale});
+  mat4x4f_t tr_mat = mul_mat4x4f(t_mat, r_mat);
+  mat4x4f_t trs_mat = mul_mat4x4f(tr_mat, s_mat);
+
+  mat3x4f_t xf_proj_mat = mul_mat3x4f_by_mat4x4f(proj_cam_mat, trs_mat);
+
   vec3f_t vertex = {0};
+  vec2i_t point = {0};
   for (u64 i = 0; i < instance->model->vertices->count; ++i) {
     vertex = list_get(instance->model->vertices, i);
-    vertex = vec_add(vec3f_t, vertex, instance->position);
-    list_append(vec2i_t, arena, projected,
-                project_point(vertex, wnd, camera, viewport));
+    vertex = mul_mat3x4f_by_vec4f(
+        xf_proj_mat, (vec4f_t){vertex.x, vertex.y, vertex.z, 1.0f});
+    point = (vec2i_t){(i32)(vertex.x / vertex.z), (i32)(vertex.y / vertex.z)};
+    list_append(vec2i_t, arena, projected, point);
   }
 
   for (u64 i = 0; i < instance->model->triangles->count; ++i) {
diff --git a/src/vector/vec.c b/src/vector/vec.c
index 3a9d929..133d7e4 100644
--- a/src/vector/vec.c
+++ b/src/vector/vec.c
@@ -2,12 +2,6 @@
 #include "math/math_utils.h"
 #include <math.h>
 
-typedef struct {
-  vec3f_t row0;
-  vec3f_t row1;
-  vec3f_t row2;
-} mat3x3f_t;
-
 vec2i_t vec_add_vec2i_t(vec2i_t v1, vec2i_t v2) {
   return (vec2i_t){.x = v1.x + v2.x, .y = v1.y + v2.y};
 }
@@ -145,36 +139,7 @@ vec3f_t vec_unit_vec3f_t(vec3f_t v) {
 }
 
 vec3f_t vec_rotate_vec3f_t(vec3f_t original, vec3f_t rotation) {
-  f32 x_rad = RADIANS(rotation.x);
-  f32 y_rad = RADIANS(rotation.y);
-  f32 z_rad = RADIANS(rotation.z);
-
-  f32 cos_x = cosf(x_rad);
-  f32 sin_x = sinf(x_rad);
-
-  f32 cos_y = cosf(y_rad);
-  f32 sin_y = sinf(y_rad);
-
-  f32 cos_z = cosf(z_rad);
-  f32 sin_z = sinf(z_rad);
-
-  f32 row0_col0 = cos_z * cos_y;
-  f32 row0_col1 = cos_z * sin_y * sin_x - sin_z * cos_x;
-  f32 row0_col2 = cos_z * sin_y * cos_x + sin_z * sin_x;
-
-  f32 row1_col0 = sin_z * cos_y;
-  f32 row1_col1 = sin_z * sin_y * sin_x + cos_z * cos_x;
-  f32 row1_col2 = sin_z * sin_y * cos_x - cos_z * sin_x;
-
-  f32 row2_col0 = -sin_y;
-  f32 row2_col1 = cos_y * sin_x;
-  f32 row2_col2 = cos_y * cos_x;
-
-  mat3x3f_t matrix = {
-      .row0 = {row0_col0, row0_col1, row0_col2},
-      .row1 = {row1_col0, row1_col1, row1_col2},
-      .row2 = {row2_col0, row2_col1, row2_col2},
-  };
+  mat3x3f_t matrix = get_rotation_mat3x3f(rotation);
 
   // clang-format off
 	return (vec3f_t){
@@ -264,3 +229,160 @@ vec4f_t vec_unit_vec4f_t(vec4f_t v) {
   return (vec4f_t){v.x / magnitude, v.y / magnitude, v.z / magnitude,
                    v.w / magnitude};
 }
+
+mat4x4f_t get_scaling_matrix(vec3f_t scale) {
+  // clang-format off
+  return (mat4x4f_t){
+      (vec4f_t){scale.x, 0.0f, 0.0f, 0.0f},
+      (vec4f_t){0.0f, scale.y, 0.0f, 0.0f},
+      (vec4f_t){0.0f, 0.0f, scale.z, 0.0f},
+      (vec4f_t){0.0f, 0.0f,    0.0f, 1.0f},
+  };
+  // clang-format on
+}
+
+mat3x3f_t get_rotation_mat3x3f(vec3f_t rotation) {
+  f32 x_rad = RADIANS(rotation.x);
+  f32 y_rad = RADIANS(rotation.y);
+  f32 z_rad = RADIANS(rotation.z);
+
+  f32 cos_x = cosf(x_rad);
+  f32 sin_x = sinf(x_rad);
+
+  f32 cos_y = cosf(y_rad);
+  f32 sin_y = sinf(y_rad);
+
+  f32 cos_z = cosf(z_rad);
+  f32 sin_z = sinf(z_rad);
+
+  f32 row0_col0 = cos_z * cos_y;
+  f32 row0_col1 = cos_z * sin_y * sin_x - sin_z * cos_x;
+  f32 row0_col2 = cos_z * sin_y * cos_x + sin_z * sin_x;
+
+  f32 row1_col0 = sin_z * cos_y;
+  f32 row1_col1 = sin_z * sin_y * sin_x + cos_z * cos_x;
+  f32 row1_col2 = sin_z * sin_y * cos_x - cos_z * sin_x;
+
+  f32 row2_col0 = -sin_y;
+  f32 row2_col1 = cos_y * sin_x;
+  f32 row2_col2 = cos_y * cos_x;
+
+  return (mat3x3f_t){
+      .row0 = {row0_col0, row0_col1, row0_col2},
+      .row1 = {row1_col0, row1_col1, row1_col2},
+      .row2 = {row2_col0, row2_col1, row2_col2},
+  };
+}
+
+mat4x4f_t get_translation_matrix(vec3f_t translation) {
+  return (mat4x4f_t){
+      (vec4f_t){1.0f, 0.0f, 0.0f, translation.x},
+      (vec4f_t){0.0f, 1.0f, 0.0f, translation.y},
+      (vec4f_t){0.0f, 0.0f, 1.0f, translation.z},
+      (vec4f_t){0.0f, 0.0f, 0.0f, 1.0f},
+  };
+}
+
+mat4x4f_t get_rotation_matrix(vec3f_t rotation) {
+  mat3x3f_t mat = get_rotation_mat3x3f(rotation);
+
+  // clang-format off
+  return (mat4x4f_t){
+      (vec4f_t){mat.row0.x, mat.row0.y, mat.row0.z, 0.0f},
+      (vec4f_t){mat.row1.x, mat.row1.y, mat.row1.z, 0.0f},
+      (vec4f_t){mat.row2.x, mat.row2.y, mat.row2.z, 0.0f},
+      (vec4f_t){      0.0f,       0.0f,       0.0f, 1.0f},
+  };
+  // clang-format on
+}
+
+vec3f_t mul_mat3x4f_by_vec4f(mat3x4f_t mat, vec4f_t vec) {
+  f32 x = mat.row0.x * vec.x + mat.row0.y * vec.y + mat.row0.z * vec.z +
+          mat.row0.w * vec.w;
+  f32 y = mat.row1.x * vec.x + mat.row1.y * vec.y + mat.row1.z * vec.z +
+          mat.row1.w * vec.w;
+  f32 z = mat.row2.x * vec.x + mat.row2.y * vec.y + mat.row2.z * vec.z +
+          mat.row2.w * vec.w;
+
+  return (vec3f_t){x, y, z};
+}
+
+mat3x4f_t mul_mat3x4f_by_mat4x4f(mat3x4f_t mat1, mat4x4f_t mat2) {
+  f32 row0_col0 = mat1.row0.x * mat2.row0.x + mat1.row0.y * mat2.row1.x +
+                  mat1.row0.z * mat2.row2.x + mat1.row0.w * mat2.row3.x;
+  f32 row0_col1 = mat1.row0.x * mat2.row0.y + mat1.row0.y * mat2.row1.y +
+                  mat1.row0.z * mat2.row2.y + mat1.row0.w * mat2.row3.y;
+  f32 row0_col2 = mat1.row0.x * mat2.row0.z + mat1.row0.y * mat2.row1.z +
+                  mat1.row0.z * mat2.row2.z + mat1.row0.w * mat2.row3.z;
+  f32 row0_col3 = mat1.row0.x * mat2.row0.w + mat1.row0.y * mat2.row1.w +
+                  mat1.row0.z * mat2.row2.w + mat1.row0.w * mat2.row3.w;
+
+  f32 row1_col0 = mat1.row1.x * mat2.row0.x + mat1.row1.y * mat2.row1.x +
+                  mat1.row1.z * mat2.row2.x + mat1.row1.w * mat2.row3.x;
+  f32 row1_col1 = mat1.row1.x * mat2.row0.y + mat1.row1.y * mat2.row1.y +
+                  mat1.row1.z * mat2.row2.y + mat1.row1.w * mat2.row3.y;
+  f32 row1_col2 = mat1.row1.x * mat2.row0.z + mat1.row1.y * mat2.row1.z +
+                  mat1.row1.z * mat2.row2.z + mat1.row1.w * mat2.row3.z;
+  f32 row1_col3 = mat1.row1.x * mat2.row0.w + mat1.row1.y * mat2.row1.w +
+                  mat1.row1.z * mat2.row2.w + mat1.row1.w * mat2.row3.w;
+
+  f32 row2_col0 = mat1.row2.x * mat2.row0.x + mat1.row2.y * mat2.row1.x +
+                  mat1.row2.z * mat2.row2.x + mat1.row2.w * mat2.row3.x;
+  f32 row2_col1 = mat1.row2.x * mat2.row0.y + mat1.row2.y * mat2.row1.y +
+                  mat1.row2.z * mat2.row2.y + mat1.row2.w * mat2.row3.y;
+  f32 row2_col2 = mat1.row2.x * mat2.row0.z + mat1.row2.y * mat2.row1.z +
+                  mat1.row2.z * mat2.row2.z + mat1.row2.w * mat2.row3.z;
+  f32 row2_col3 = mat1.row2.x * mat2.row0.w + mat1.row2.y * mat2.row1.w +
+                  mat1.row2.z * mat2.row2.w + mat1.row2.w * mat2.row3.w;
+
+  return (mat3x4f_t){
+      (vec4f_t){row0_col0, row0_col1, row0_col2, row0_col3},
+      (vec4f_t){row1_col0, row1_col1, row1_col2, row1_col3},
+      (vec4f_t){row2_col0, row2_col1, row2_col2, row2_col3},
+  };
+}
+
+mat4x4f_t mul_mat4x4f(mat4x4f_t mat1, mat4x4f_t mat2) {
+  f32 row0_col0 = mat1.row0.x * mat2.row0.x + mat1.row0.y * mat2.row1.x +
+                  mat1.row0.z * mat2.row2.x + mat1.row0.w * mat2.row3.x;
+  f32 row0_col1 = mat1.row0.x * mat2.row0.y + mat1.row0.y * mat2.row1.y +
+                  mat1.row0.z * mat2.row2.y + mat1.row0.w * mat2.row3.y;
+  f32 row0_col2 = mat1.row0.x * mat2.row0.z + mat1.row0.y * mat2.row1.z +
+                  mat1.row0.z * mat2.row2.z + mat1.row0.w * mat2.row3.z;
+  f32 row0_col3 = mat1.row0.x * mat2.row0.w + mat1.row0.y * mat2.row1.w +
+                  mat1.row0.z * mat2.row2.w + mat1.row0.w * mat2.row3.w;
+
+  f32 row1_col0 = mat1.row1.x * mat2.row0.x + mat1.row1.y * mat2.row1.x +
+                  mat1.row1.z * mat2.row2.x + mat1.row1.w * mat2.row3.x;
+  f32 row1_col1 = mat1.row1.x * mat2.row0.y + mat1.row1.y * mat2.row1.y +
+                  mat1.row1.z * mat2.row2.y + mat1.row1.w * mat2.row3.y;
+  f32 row1_col2 = mat1.row1.x * mat2.row0.z + mat1.row1.y * mat2.row1.z +
+                  mat1.row1.z * mat2.row2.z + mat1.row1.w * mat2.row3.z;
+  f32 row1_col3 = mat1.row1.x * mat2.row0.w + mat1.row1.y * mat2.row1.w +
+                  mat1.row1.z * mat2.row2.w + mat1.row1.w * mat2.row3.w;
+
+  f32 row2_col0 = mat1.row2.x * mat2.row0.x + mat1.row2.y * mat2.row1.x +
+                  mat1.row2.z * mat2.row2.x + mat1.row2.w * mat2.row3.x;
+  f32 row2_col1 = mat1.row2.x * mat2.row0.y + mat1.row2.y * mat2.row1.y +
+                  mat1.row2.z * mat2.row2.y + mat1.row2.w * mat2.row3.y;
+  f32 row2_col2 = mat1.row2.x * mat2.row0.z + mat1.row2.y * mat2.row1.z +
+                  mat1.row2.z * mat2.row2.z + mat1.row2.w * mat2.row3.z;
+  f32 row2_col3 = mat1.row2.x * mat2.row0.w + mat1.row2.y * mat2.row1.w +
+                  mat1.row2.z * mat2.row2.w + mat1.row2.w * mat2.row3.w;
+
+  f32 row3_col0 = mat1.row3.x * mat2.row0.x + mat1.row3.y * mat2.row1.x +
+                  mat1.row3.z * mat2.row2.x + mat1.row3.w * mat2.row3.x;
+  f32 row3_col1 = mat1.row3.x * mat2.row0.y + mat1.row3.y * mat2.row1.y +
+                  mat1.row3.z * mat2.row2.y + mat1.row3.w * mat2.row3.y;
+  f32 row3_col2 = mat1.row3.x * mat2.row0.z + mat1.row3.y * mat2.row1.z +
+                  mat1.row3.z * mat2.row2.z + mat1.row3.w * mat2.row3.z;
+  f32 row3_col3 = mat1.row3.x * mat2.row0.w + mat1.row3.y * mat2.row1.w +
+                  mat1.row3.z * mat2.row2.w + mat1.row3.w * mat2.row3.w;
+
+  return (mat4x4f_t){
+      (vec4f_t){row0_col0, row0_col1, row0_col2, row0_col3},
+      (vec4f_t){row1_col0, row1_col1, row1_col2, row1_col3},
+      (vec4f_t){row2_col0, row2_col1, row2_col2, row2_col3},
+      (vec4f_t){row3_col0, row3_col1, row3_col2, row3_col3},
+  };
+}