#include vec3 vec3_create(f32 x, f32 y, f32 z) { return (vec3){ x, y, z }; } vec3 vec3_add(vec3 u, vec3 v) { return (vec3){ .x = u.x + v.x, .y = u.y + v.y, .z = u.z + v.z }; } vec3 vec3_sub(vec3 a, vec3 b) { return (vec3){ a.x - b.x, a.y - b.y, a.z - b.z }; } vec3 vec3_mult(vec3 a, f32 s) { return (vec3){ a.x * s, a.y * s, a.z * s }; } vec3 vec3_div(vec3 a, f32 s) { return (vec3){ a.x / s, a.y / s, a.z / s }; } f32 vec3_len_squared(vec3 a) { return (a.x * a.x) + (a.y * a.y) + (a.z * a.z); } f32 vec3_len(vec3 a) { return sqrtf(vec3_len_squared(a)); } vec3 vec3_negate(vec3 a) { return (vec3){ -a.x, -a.y, -a.z }; } vec3 vec3_normalise(vec3 a) { f32 length = vec3_len(a); return vec3_div(a, length); } f32 vec3_dot(vec3 a, vec3 b) { return a.x * b.x + a.y * b.y + a.z * b.z; } vec3 vec3_cross(vec3 a, vec3 b) { return (vec3){ .x = a.y * b.z - a.z * b.y, .y = a.z * b.x - a.x * b.z, .z = a.x * b.y - a.y * b.x }; } vec4 vec4_create(f32 x, f32 y, f32 z, f32 w) { return (vec4){ x, y, z, w }; } f32 quat_dot(quat a, quat b) { return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; } quat quat_normalise(quat a) { f32 length = sqrtf(quat_dot(a, a)); // same as len squared return (quat){ a.x / length, a.y / length, a.z / length, a.w / length }; } quat quat_from_axis_angle(vec3 axis, f32 angle, bool normalize) { const f32 half_angle = 0.5f * angle; f32 s = sinf(half_angle); f32 c = cosf(half_angle); quat q = (quat){ s * axis.x, s * axis.y, s * axis.z, c }; if (normalize) { return quat_normalise(q); } return q; } mat4 mat4_ident() { return (mat4){ .data = { 1.0, 0., 0., 0., 0., 1., 0., 0., 0., 0., 1., 0., 0., 0., 0., 1.0 } }; } mat4 mat4_translation(vec3 position) { mat4 out_matrix = mat4_ident(); out_matrix.data[12] = position.x; out_matrix.data[13] = position.y; out_matrix.data[14] = position.z; return out_matrix; } mat4 mat4_scale(vec3 scale) { mat4 out_matrix = mat4_ident(); out_matrix.data[0] = scale.x; out_matrix.data[5] = scale.y; out_matrix.data[10] = scale.z; return out_matrix; } // TODO: double check this mat4 mat4_rotation(quat rotation) { mat4 out_matrix = mat4_ident(); quat n = quat_normalise(rotation); out_matrix.data[0] = 1.0f - 2.0f * n.y * n.y - 2.0f * n.z * n.z; out_matrix.data[1] = 2.0f * n.x * n.y - 2.0f * n.z * n.w; out_matrix.data[2] = 2.0f * n.x * n.z + 2.0f * n.y * n.w; out_matrix.data[4] = 2.0f * n.x * n.y + 2.0f * n.z * n.w; out_matrix.data[5] = 1.0f - 2.0f * n.x * n.x - 2.0f * n.z * n.z; out_matrix.data[6] = 2.0f * n.y * n.z - 2.0f * n.x * n.w; out_matrix.data[8] = 2.0f * n.x * n.z - 2.0f * n.y * n.w; out_matrix.data[9] = 2.0f * n.y * n.z + 2.0f * n.x * n.w; out_matrix.data[10] = 1.0f - 2.0f * n.x * n.x - 2.0f * n.y * n.y; return out_matrix; } // mat4 mat4_mult(mat4 lhs, mat4 rhs) { // mat4 out_matrix = mat4_ident(); // const f32* m1_ptr = lhs.data; // const f32* m2_ptr = rhs.data; // f32* dst_ptr = out_matrix.data; // for (i32 i = 0; i < 4; ++i) { // for (i32 j = 0; j < 4; ++j) { // *dst_ptr = m1_ptr[0] * m2_ptr[0 + j] + m1_ptr[1] * m2_ptr[4 + j] + m1_ptr[2] * m2_ptr[8 + j] + // m1_ptr[3] * m2_ptr[12 + j]; // dst_ptr++; // } // m1_ptr += 4; // } // return out_matrix; // } mat4 mat4_mult(mat4 lhs, mat4 rhs) { mat4 out_matrix = mat4_ident(); for (i32 row = 0; row < 4; row++) { for (i32 col = 0; col < 4; col++) { f32 sum = 0; for (i32 i = 0; i < 4; i++) { // column-major: first matrix columns × second matrix rows sum += lhs.data[row + i * 4] * rhs.data[i + col * 4]; } out_matrix.data[row + col * 4] = sum; } } return out_matrix; } mat4 mat4_perspective(f32 fov_radians, f32 aspect_ratio, f32 near_z, f32 far_z) { f32 half_tan_fov = tanf(fov_radians * 0.5f); mat4 out_matrix = { .data = { 0 } }; out_matrix.data[0] = 1.0f / (aspect_ratio * half_tan_fov); out_matrix.data[5] = 1.0f / half_tan_fov; out_matrix.data[10] = -((far_z + near_z) / (far_z - near_z)); out_matrix.data[11] = -1.0f; out_matrix.data[14] = -((2.0f * far_z * near_z) / (far_z - near_z)); return out_matrix; } mat4 mat4_look_at(vec3 position, vec3 target, vec3 up) { mat4 out_matrix; vec3 z_axis; z_axis.x = target.x - position.x; z_axis.y = target.y - position.y; z_axis.z = target.z - position.z; z_axis = vec3_normalise(z_axis); vec3 x_axis = vec3_normalise(vec3_cross(z_axis, up)); vec3 y_axis = vec3_cross(x_axis, z_axis); out_matrix.data[0] = x_axis.x; out_matrix.data[1] = y_axis.x; out_matrix.data[2] = -z_axis.x; out_matrix.data[3] = 0; out_matrix.data[4] = x_axis.y; out_matrix.data[5] = y_axis.y; out_matrix.data[6] = -z_axis.y; out_matrix.data[7] = 0; out_matrix.data[8] = x_axis.z; out_matrix.data[9] = y_axis.z; out_matrix.data[10] = -z_axis.z; out_matrix.data[11] = 0; out_matrix.data[12] = -vec3_dot(x_axis, position); out_matrix.data[13] = -vec3_dot(y_axis, position); out_matrix.data[14] = vec3_dot(z_axis, position); out_matrix.data[15] = 1.0f; return out_matrix; }