Switch to using transformation matrices

This commit is contained in:
Abdelrahman Said 2024-06-30 02:40:04 +01:00
parent 9ba7a8c414
commit b81304e759
7 changed files with 282 additions and 96 deletions

View File

@ -9,7 +9,7 @@ typedef struct {
vec3f_t rotation; vec3f_t rotation;
} camera_t; } camera_t;
vec2i_t project_point(vec3f_t point, const window_t *wnd, mat4x4f_t inverse_camera_translation_matrix(const camera_t *camera);
const camera_t *camera, vec3f_t viewport); mat4x4f_t inverse_camera_rotation_matrix(const camera_t *camera);
#endif // !CAMERA_H #endif // !CAMERA_H

View File

@ -41,12 +41,18 @@ typedef struct {
} model_t; } model_t;
typedef struct { typedef struct {
model_t *model; f32 scale;
vec3f_t rotation;
vec3f_t position; vec3f_t position;
} transform_t;
typedef struct {
model_t *model;
transform_t transform;
} instance_t; } instance_t;
void render_instance(window_t *wnd, Arena *arena, const camera_t *camera, void render_instance(window_t *wnd, Arena *arena, mat3x4f_t proj_cam_mat,
vec3f_t viewport, const instance_t *instance_t); const instance_t *instance);
void draw_wireframe_triangle(window_t *wnd, Arena *arena, triangle_t triangle); 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_filled_triangle(window_t *wnd, Arena *arena, triangle_t triangle);
void draw_shaded_triangle(window_t *wnd, Arena *arena, triangle_t triangle); void draw_shaded_triangle(window_t *wnd, Arena *arena, triangle_t triangle);

View File

@ -39,6 +39,25 @@ typedef struct {
f32 w; f32 w;
} vec4f_t; } 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_add(T, v1, v2) vec_add_##T(v1, v2)
#define vec_sub(T, v1, v2) vec_sub_##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) #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); f32 vec_magnitude_vec4f_t(vec4f_t v);
vec4f_t vec_unit_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 #endif // !VEC_H

View File

@ -1,15 +1,12 @@
#include "camera/camera.h" #include "camera/camera.h"
#include "vector/vec.h" #include "vector/vec.h"
#include "window/window.h"
vec2i_t project_point(vec3f_t point, const window_t *wnd, mat4x4f_t inverse_camera_translation_matrix(const camera_t *camera) {
const camera_t *camera, vec3f_t viewport) { vec3f_t inverse_translation = vec_mul_num(vec3f_t, camera->position, -1.0f);
if (point.z == 0.0f) { return get_translation_matrix(inverse_translation);
return (vec2i_t){.x = 0, .y = 0}; }
}
mat4x4f_t inverse_camera_rotation_matrix(const camera_t *camera) {
f32 x = point.x * viewport.z / point.z; vec3f_t inverse_rotation = vec_mul_num(vec3f_t, camera->rotation, -1.0f);
f32 y = point.y * viewport.z / point.z; return get_rotation_matrix(inverse_rotation);
return viewport_to_window(wnd, x, y, viewport);
} }

View File

@ -2,6 +2,7 @@
#include "list/typed_list.h" #include "list/typed_list.h"
#include "mem_arena.h" #include "mem_arena.h"
#include "mem_utils.h" #include "mem_utils.h"
#include "misc/misc_utils.h"
#include "rasteriser/rasteriser.h" #include "rasteriser/rasteriser.h"
#include "vector/vec.h" #include "vector/vec.h"
#include "window/window.h" #include "window/window.h"
@ -36,50 +37,67 @@ int main(void) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
// Vertices // Vertices
list_append(vec3f_t, arena, vertices, ((vec3f_t){1, 1, 1})); vec3f_t verts[] = {
list_append(vec3f_t, arena, vertices, ((vec3f_t){-1, 1, 1})); (vec3f_t){1, 1, 1}, (vec3f_t){-1, 1, 1}, (vec3f_t){-1, -1, 1},
list_append(vec3f_t, arena, vertices, ((vec3f_t){-1, -1, 1})); (vec3f_t){1, -1, 1}, (vec3f_t){1, 1, -1}, (vec3f_t){-1, 1, -1},
list_append(vec3f_t, arena, vertices, ((vec3f_t){1, -1, 1})); (vec3f_t){-1, -1, -1}, (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})); for (u64 i = 0; i < ARR_LEN(verts); ++i) {
list_append(vec3f_t, arena, vertices, ((vec3f_t){-1, -1, -1})); list_append(vec3f_t, arena, vertices, verts[i]);
list_append(vec3f_t, arena, vertices, ((vec3f_t){1, -1, -1})); }
list_scene_triangle_t *triangles = list_create(scene_triangle_t, arena); list_scene_triangle_t *triangles = list_create(scene_triangle_t, arena);
if (!triangles) { if (!triangles) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
// Triangles // Triangles
list_append(scene_triangle_t, arena, triangles, scene_triangle_t tris[] = {
((scene_triangle_t){0, 1, 2, (colour_t){.colour = 0xff0000ff}})); (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}},
((scene_triangle_t){0, 2, 3, (colour_t){.colour = 0xff0000ff}})); (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}},
((scene_triangle_t){4, 0, 3, (colour_t){.colour = 0x00ff00ff}})); (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}},
((scene_triangle_t){4, 3, 7, (colour_t){.colour = 0x00ff00ff}})); (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}},
((scene_triangle_t){5, 4, 7, (colour_t){.colour = 0x0000ffff}})); (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}},
((scene_triangle_t){5, 7, 6, (colour_t){.colour = 0x0000ffff}})); (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){1, 5, 6, (colour_t){.colour = 0xffff00ff}})); };
list_append(scene_triangle_t, arena, triangles, for (u64 i = 0; i < ARR_LEN(tris); ++i) {
((scene_triangle_t){1, 6, 2, (colour_t){.colour = 0xffff00ff}})); list_append(scene_triangle_t, arena, triangles, tris[i]);
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}}));
model_t cube = {.vertices = vertices, .triangles = triangles}; model_t cube = {.vertices = vertices, .triangles = triangles};
instance_t cube_01 = {.model = &cube, instance_t cube_01 = {
.position = (vec3f_t){-1.5f, 0.0f, 8.0f}}; .model = &cube,
instance_t cube_02 = {.model = &cube, .transform =
.position = (vec3f_t){1.7f, 1.5f, 7.0f}}; {
.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; bool running = true;
SDL_Event event = {0}; 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); clear_window(&window, bg);
render_instance(&window, arena, &camera, viewport, &cube_01); render_instance(&window, arena, proj_cam_matrix, &cube_01);
render_instance(&window, arena, &camera, viewport, &cube_02); render_instance(&window, arena, proj_cam_matrix, &cube_02);
swap_buffers(&window); swap_buffers(&window);

View File

@ -12,23 +12,34 @@
#include <sys/mman.h> #include <sys/mman.h>
internal list_float *interpolate(Arena *arena, i32 i0, f32 d0, i32 i1, f32 d1); internal list_float *interpolate(Arena *arena, i32 i0, f32 d0, i32 i1, f32 d1);
internal inline void order_triangle_points(triangle_t *triangle); internal inline void order_triangle_points(triangle_t *triangle);
void render_instance(window_t *wnd, Arena *arena, const camera_t *camera, void render_instance(window_t *wnd, Arena *arena, mat3x4f_t proj_cam_mat,
vec3f_t viewport, const instance_t *instance) { const instance_t *instance) {
list_vec2i_t *projected = list_create_with_capacity( list_vec2i_t *projected = list_create_with_capacity(
vec2i_t, arena, instance->model->vertices->count * sizeof(vec3f_t)); vec2i_t, arena, instance->model->vertices->count * sizeof(vec3f_t));
if (!projected) { if (!projected) {
return; 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}; vec3f_t vertex = {0};
vec2i_t point = {0};
for (u64 i = 0; i < instance->model->vertices->count; ++i) { for (u64 i = 0; i < instance->model->vertices->count; ++i) {
vertex = list_get(instance->model->vertices, i); vertex = list_get(instance->model->vertices, i);
vertex = vec_add(vec3f_t, vertex, instance->position); vertex = mul_mat3x4f_by_vec4f(
list_append(vec2i_t, arena, projected, xf_proj_mat, (vec4f_t){vertex.x, vertex.y, vertex.z, 1.0f});
project_point(vertex, wnd, camera, viewport)); 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) { for (u64 i = 0; i < instance->model->triangles->count; ++i) {

View File

@ -2,12 +2,6 @@
#include "math/math_utils.h" #include "math/math_utils.h"
#include <math.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) { 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}; 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) { vec3f_t vec_rotate_vec3f_t(vec3f_t original, vec3f_t rotation) {
f32 x_rad = RADIANS(rotation.x); mat3x3f_t matrix = get_rotation_mat3x3f(rotation);
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},
};
// clang-format off // clang-format off
return (vec3f_t){ 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, return (vec4f_t){v.x / magnitude, v.y / magnitude, v.z / magnitude,
v.w / 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},
};
}