Files
armorpaint/base/sources/iron_math.c
T
2026-08-21 22:35:30 +02:00

1030 lines
26 KiB
C

#include "iron_math.h"
#include "iron_alloc.h"
#include <limits.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
void iron_color_components(uint32_t color, float *red, float *green, float *blue, float *alpha) {
*alpha = ((color & 0xff000000) >> 24) / 255.0f;
*red = ((color & 0x00ff0000) >> 16) / 255.0f;
*green = ((color & 0x0000ff00) >> 8) / 255.0f;
*blue = (color & 0x000000ff) / 255.0f;
}
// xoshiro256** 1.0
static inline uint64_t rotl(const uint64_t x, int k) {
return (x << k) | (x >> (64 - k));
}
static uint64_t s[4] = {1, 2, 3, 4};
uint64_t next(void) {
const uint64_t result = rotl(s[1] * 5, 7) * 9;
const uint64_t t = s[1] << 17;
s[2] ^= s[0];
s[3] ^= s[1];
s[1] ^= s[2];
s[0] ^= s[3];
s[2] ^= t;
s[3] = rotl(s[3], 45);
return result;
}
void iron_random_init(int64_t seed) {
s[0] = (uint64_t)seed;
s[1] = 2;
s[2] = 3;
s[3] = 4;
s[1] = next();
s[2] = next();
s[3] = next();
}
int64_t iron_random_get(void) {
return (int64_t)next();
}
int64_t iron_random_get_max(int64_t max) {
int64_t value = iron_random_get();
return (value < -LLONG_MAX ? LLONG_MAX : llabs(value)) % (max + 1);
}
int64_t iron_random_get_in(int64_t min, int64_t max) {
int64_t value = iron_random_get();
return (value < -LLONG_MAX ? LLONG_MAX : llabs(value)) % (max + 1 - min) + min;
}
// ██╗ ██╗███████╗ ██████╗██████╗
// ██║ ██║██╔════╝██╔════╝╚════██╗
// ██║ ██║█████╗ ██║ █████╔╝
// ╚██╗ ██╔╝██╔══╝ ██║ ██╔═══╝
// ╚████╔╝ ███████╗╚██████╗███████╗
// ╚═══╝ ╚══════╝ ╚═════╝╚══════╝
float vec2_len(vec2_t v) {
return sqrtf(v.x * v.x + v.y * v.y);
}
vec2_t vec2_set_len(vec2_t v, float length) {
float current_length = vec2_len(v);
if (current_length == 0) {
return v;
}
float mul = length / current_length;
v.x *= mul;
v.y *= mul;
return v;
}
vec2_t vec2_mult(vec2_t v, float f) {
v.x *= f;
v.y *= f;
return v;
}
vec2_t vec2_add(vec2_t a, vec2_t b) {
a.x += b.x;
a.y += b.y;
return a;
}
vec2_t vec2_sub(vec2_t a, vec2_t b) {
a.x -= b.x;
a.y -= b.y;
return a;
}
float vec2_cross(vec2_t a, vec2_t b) {
return a.x * b.y - a.y * b.x;
}
vec2_t vec2_norm(vec2_t v) {
float n = vec2_len(v);
if (n > 0.0) {
float inv_n = 1.0f / n;
v.x *= inv_n;
v.y *= inv_n;
}
return v;
}
float vec2_dot(vec2_t a, vec2_t b) {
return a.x * b.x + a.y * b.y;
}
vec2_t vec2_nan() {
vec2_t v;
v.x = NAN;
return v;
}
bool vec2_isnan(vec2_t v) {
return isnan(v.x);
}
// ██╗ ██╗███████╗ ██████╗██╗ ██╗
// ██║ ██║██╔════╝██╔════╝██║ ██║
// ██║ ██║█████╗ ██║ ███████║
// ╚██╗ ██╔╝██╔══╝ ██║ ╚════██║
// ╚████╔╝ ███████╗╚██████╗ ██║
// ╚═══╝ ╚══════╝ ╚═════╝ ╚═╝
f32_array_t *vec3_to_f32_array(vec4_t v) {
f32_array_t *res = f32_array_create(3);
res->buffer[0] = v.x;
res->buffer[1] = v.y;
res->buffer[2] = v.z;
return res;
}
vec4_t vec4_cross(vec4_t a, vec4_t b) {
vec4_t v;
v.x = a.y * b.z - a.z * b.y;
v.y = a.z * b.x - a.x * b.z;
v.z = a.x * b.y - a.y * b.x;
return v;
}
vec4_t vec4_add(vec4_t a, vec4_t b) {
a.x += b.x;
a.y += b.y;
a.z += b.z;
a.w += b.w;
return a;
}
vec4_t vec4_fadd(vec4_t a, float x, float y, float z, float w) {
a.x += x;
a.y += y;
a.z += z;
a.w += w;
return a;
}
vec4_t vec4_norm(vec4_t a) {
float n = vec4_len(a);
if (n > 0.0) {
float inv_n = 1.0f / n;
a.x *= inv_n;
a.y *= inv_n;
a.z *= inv_n;
}
return a;
}
vec4_t vec4_mult(vec4_t a, float f) {
a.x *= f;
a.y *= f;
a.z *= f;
a.w *= f;
return a;
}
float vec4_dot(vec4_t a, vec4_t b) {
return a.x * b.x + a.y * b.y + a.z * b.z;
}
vec4_t vec4_apply_proj(vec4_t a, mat4_t m) {
vec4_t v;
float d = 1.0 / (m.m[3] * a.x + m.m[7] * a.y + m.m[11] * a.z + m.m[15]); // Perspective divide
v.x = (m.m[0] * a.x + m.m[4] * a.y + m.m[8] * a.z + m.m[12]) * d;
v.y = (m.m[1] * a.x + m.m[5] * a.y + m.m[9] * a.z + m.m[13]) * d;
v.z = (m.m[2] * a.x + m.m[6] * a.y + m.m[10] * a.z + m.m[14]) * d;
return v;
}
vec4_t vec4_apply_mat4(vec4_t a, mat4_t m) {
vec4_t v;
v.x = m.m[0] * a.x + m.m[4] * a.y + m.m[8] * a.z + m.m[12] * a.w;
v.y = m.m[1] * a.x + m.m[5] * a.y + m.m[9] * a.z + m.m[13] * a.w;
v.z = m.m[2] * a.x + m.m[6] * a.y + m.m[10] * a.z + m.m[14] * a.w;
v.w = m.m[3] * a.x + m.m[7] * a.y + m.m[11] * a.z + m.m[15] * a.w;
return v;
}
vec4_t vec4_apply_axis_angle(vec4_t a, vec4_t axis, float angle) {
quat_t q = quat_from_axis_angle(axis, angle);
return vec4_apply_quat(a, q);
}
vec4_t vec4_apply_quat(vec4_t a, quat_t q) {
vec4_t v;
float ix = q.w * a.x + q.y * a.z - q.z * a.y;
float iy = q.w * a.y + q.z * a.x - q.x * a.z;
float iz = q.w * a.z + q.x * a.y - q.y * a.x;
float iw = -q.x * a.x - q.y * a.y - q.z * a.z;
v.x = ix * q.w + iw * -q.x + iy * -q.z - iz * -q.y;
v.y = iy * q.w + iw * -q.y + iz * -q.x - ix * -q.z;
v.z = iz * q.w + iw * -q.z + ix * -q.y - iy * -q.x;
return v;
}
bool vec4_equals(vec4_t a, vec4_t b) {
return a.x == b.x && a.y == b.y && a.z == b.z;
}
bool vec4_almost_equals(vec4_t a, vec4_t b, float prec) {
return fabs(a.x - b.x) < prec && fabs(a.y - b.y) < prec && fabs(a.z - b.z) < prec;
}
float vec4_len(vec4_t a) {
return sqrtf(a.x * a.x + a.y * a.y + a.z * a.z);
}
vec4_t vec4_sub(vec4_t a, vec4_t b) {
a.x -= b.x;
a.y -= b.y;
a.z -= b.z;
return a;
}
float vec4_dist(vec4_t v1, vec4_t v2) {
return vec4_fdist(v1.x, v1.y, v1.z, v2.x, v2.y, v2.z);
}
float vec4_fdist(float v1x, float v1y, float v1z, float v2x, float v2y, float v2z) {
float vx = v1x - v2x;
float vy = v1y - v2y;
float vz = v1z - v2z;
return sqrtf(vx * vx + vy * vy + vz * vz);
}
vec4_t vec4_reflect(vec4_t a, vec4_t n) {
float d = 2 * vec4_dot(a, n);
a.x -= d * n.x;
a.y -= d * n.y;
a.z -= d * n.z;
return a;
}
vec4_t vec4_clamp(vec4_t a, float min, float max) {
float l = vec4_len(a);
if (l < min) {
return vec4_mult(vec4_norm(a), min);
}
else if (l > max) {
return vec4_mult(vec4_norm(a), max);
}
return a;
}
vec4_t vec4_x_axis() {
return (vec4_t){1.0, 0.0, 0.0, 1.0};
}
vec4_t vec4_y_axis() {
return (vec4_t){0.0, 1.0, 0.0, 1.0};
}
vec4_t vec4_z_axis() {
return (vec4_t){0.0, 0.0, 1.0, 1.0};
}
vec4_t vec4_nan() {
vec4_t v;
v.x = NAN;
return v;
}
bool vec4_isnan(vec4_t v) {
return isnan(v.x);
}
// ██████╗ ██╗ ██╗ █████╗ ████████╗
// ██╔═══██╗██║ ██║██╔══██╗╚══██╔══╝
// ██║ ██║██║ ██║███████║ ██║
// ██║▄▄ ██║██║ ██║██╔══██║ ██║
// ╚██████╔╝╚██████╔╝██║ ██║ ██║
// ╚══▀▀═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝
quat_t quat_from_axis_angle(vec4_t axis, float angle) {
float s = sinf(angle * 0.5);
quat_t q;
q.x = axis.x * s;
q.y = axis.y * s;
q.z = axis.z * s;
q.w = cosf(angle * 0.5);
return quat_norm(q);
}
quat_t quat_from_mat(mat4_t m) {
m = mat4_to_rot(m);
return quat_from_rot_mat(m);
}
quat_t quat_from_rot_mat(mat4_t m) {
// Assumes the upper 3x3 is a pure rotation matrix
float m11 = m.m[0];
float m12 = m.m[4];
float m13 = m.m[8];
float m21 = m.m[1];
float m22 = m.m[5];
float m23 = m.m[9];
float m31 = m.m[2];
float m32 = m.m[6];
float m33 = m.m[10];
float tr = m11 + m22 + m33;
float s = 0.0;
quat_t q;
if (tr > 0) {
s = 0.5 / sqrtf(tr + 1.0);
q.w = 0.25 / s;
q.x = (m32 - m23) * s;
q.y = (m13 - m31) * s;
q.z = (m21 - m12) * s;
}
else if (m11 > m22 && m11 > m33) {
s = 2.0 * sqrtf(1.0 + m11 - m22 - m33);
q.w = (m32 - m23) / s;
q.x = 0.25 * s;
q.y = (m12 + m21) / s;
q.z = (m13 + m31) / s;
}
else if (m22 > m33) {
s = 2.0 * sqrtf(1.0 + m22 - m11 - m33);
q.w = (m13 - m31) / s;
q.x = (m12 + m21) / s;
q.y = 0.25 * s;
q.z = (m23 + m32) / s;
}
else {
s = 2.0 * sqrtf(1.0 + m33 - m11 - m22);
q.w = (m21 - m12) / s;
q.x = (m13 + m31) / s;
q.y = (m23 + m32) / s;
q.z = 0.25 * s;
}
return quat_norm(q);
}
quat_t quat_mult(quat_t a, quat_t b) {
quat_t q;
q.x = a.x * b.w + a.w * b.x + a.y * b.z - a.z * b.y;
q.y = a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x;
q.z = a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w;
q.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z;
return q;
}
quat_t quat_norm(quat_t q) {
float l = sqrtf(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w);
if (l == 0.0) {
q.x = 0;
q.y = 0;
q.z = 0;
q.w = 0;
}
else {
l = 1.0 / l;
q.x *= l;
q.y *= l;
q.z *= l;
q.w *= l;
}
return q;
}
vec4_t quat_get_euler(quat_t q) {
float a = -2 * (q.x * q.z - q.w * q.y);
float b = q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z;
float c = 2 * (q.x * q.y + q.w * q.z);
float d = -2 * (q.y * q.z - q.w * q.x);
float e = q.w * q.w - q.x * q.x + q.y * q.y - q.z * q.z;
return (vec4_t){atan2f(d, e), atan2f(a, b), asinf(c), 1.0};
}
quat_t quat_from_euler(float x, float y, float z) {
float f = x / 2;
float c1 = cosf(f);
float s1 = sinf(f);
f = y / 2;
float c2 = cosf(f);
float s2 = sinf(f);
f = z / 2;
float c3 = cosf(f);
float s3 = sinf(f);
// YZX
quat_t q;
q.x = s1 * c2 * c3 + c1 * s2 * s3;
q.y = c1 * s2 * c3 + s1 * c2 * s3;
q.z = c1 * c2 * s3 - s1 * s2 * c3;
q.w = c1 * c2 * c3 - s1 * s2 * s3;
return q;
}
float quat_dot(quat_t a, quat_t b) {
return (a.x * b.x) + (a.y * b.y) + (a.z * b.z) + (a.w * b.w);
}
quat_t quat_from_to(vec4_t v0, vec4_t v1) {
// Rotation formed by direction vectors
// v0 and v1 should be normalized first
float dot = vec4_dot(v0, v1);
if (dot < -0.999999) {
vec4_t a = vec4_cross(vec4_x_axis(), v0);
if (vec4_len(a) < 0.000001) {
a = vec4_cross(vec4_y_axis(), v0);
}
a = vec4_norm(a);
return quat_from_axis_angle(a, IRON_PI);
}
else if (dot > 0.999999) {
return (quat_t){0, 0, 0, 1};
}
else {
vec4_t a = vec4_cross(v0, v1);
quat_t q = (quat_t){a.x, a.y, a.z, 1.0 + dot};
return quat_norm(q);
}
}
quat_t quat_inv(quat_t q) {
float l = q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w;
l = -1.0 / l;
q.x = q.x * l;
q.y = q.y * l;
q.z = q.z * l;
q.w = -q.w * l;
return q;
}
quat_t quat_slerp(quat_t a, quat_t b, float t) {
float dot = quat_dot(a, b);
if (dot < 0.0f) {
b.x = -b.x;
b.y = -b.y;
b.z = -b.z;
b.w = -b.w;
dot = -dot;
}
if (dot > 0.9995f) {
quat_t r = {a.x + t * (b.x - a.x), a.y + t * (b.y - a.y), a.z + t * (b.z - a.z), a.w + t * (b.w - a.w)};
return quat_norm(r);
}
float theta_0 = acosf(dot);
float theta = theta_0 * t;
float sin_t = sinf(theta);
float sin_t0 = sinf(theta_0);
float s0 = cosf(theta) - dot * sin_t / sin_t0;
float s1 = sin_t / sin_t0;
return (quat_t){s0 * a.x + s1 * b.x, s0 * a.y + s1 * b.y, s0 * a.z + s1 * b.z, s0 * a.w + s1 * b.w};
}
// ███╗ ███╗ █████╗ ████████╗██████╗
// ████╗ ████║██╔══██╗╚══██╔══╝╚════██╗
// ██╔████╔██║███████║ ██║ █████╔╝
// ██║╚██╔╝██║██╔══██║ ██║ ╚═══██╗
// ██║ ╚═╝ ██║██║ ██║ ██║ ██████╔╝
// ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═════╝
mat3_t mat3_identity() {
return (mat3_t){1, 0, 0, 0, 1, 0, 0, 0, 1};
}
mat3_t mat3_translation(float x, float y) {
return (mat3_t){1, 0, 0, 0, 1, 0, x, y, 1};
}
mat3_t mat3_rotation(float alpha) {
return (mat3_t){cosf(alpha), sinf(alpha), 0, -sinf(alpha), cosf(alpha), 0, 0, 0, 1};
}
mat3_t mat3_scale(mat3_t m, vec4_t v) {
m.m[0] *= v.x;
m.m[1] *= v.x;
m.m[2] *= v.x;
m.m[3] *= v.y;
m.m[4] *= v.y;
m.m[5] *= v.y;
m.m[6] *= v.z;
m.m[7] *= v.z;
m.m[8] *= v.z;
return m;
}
mat3_t mat3_set_from4(mat4_t m4) {
mat3_t m;
m.m[0] = m4.m[0];
m.m[1] = m4.m[1];
m.m[2] = m4.m[2];
m.m[3] = m4.m[4];
m.m[4] = m4.m[5];
m.m[5] = m4.m[6];
m.m[6] = m4.m[8];
m.m[7] = m4.m[9];
m.m[8] = m4.m[10];
return m;
}
mat3_t mat3_multmat(mat3_t a, mat3_t b) {
return (mat3_t){a.m[0] * b.m[0] + a.m[3] * b.m[1] + a.m[6] * b.m[2], a.m[1] * b.m[0] + a.m[4] * b.m[1] + a.m[7] * b.m[2],
a.m[2] * b.m[0] + a.m[5] * b.m[1] + a.m[8] * b.m[2], a.m[0] * b.m[3] + a.m[3] * b.m[4] + a.m[6] * b.m[5],
a.m[1] * b.m[3] + a.m[4] * b.m[4] + a.m[7] * b.m[5], a.m[2] * b.m[3] + a.m[5] * b.m[4] + a.m[8] * b.m[5],
a.m[0] * b.m[6] + a.m[3] * b.m[7] + a.m[6] * b.m[8], a.m[1] * b.m[6] + a.m[4] * b.m[7] + a.m[7] * b.m[8],
a.m[2] * b.m[6] + a.m[5] * b.m[7] + a.m[8] * b.m[8]};
}
mat3_t mat3_transpose(mat3_t m) {
float f = m.m[1];
m.m[1] = m.m[3];
m.m[3] = f;
f = m.m[2];
m.m[2] = m.m[6];
m.m[6] = f;
f = m.m[5];
m.m[5] = m.m[7];
m.m[7] = f;
return m;
}
mat3_t mat3_nan() {
mat3_t m;
m.m[0] = NAN;
return m;
}
bool mat3_isnan(mat3_t m) {
return isnan(m.m[0]);
}
// ███╗ ███╗ █████╗ ████████╗██╗ ██╗
// ████╗ ████║██╔══██╗╚══██╔══╝██║ ██║
// ██╔████╔██║███████║ ██║ ███████║
// ██║╚██╔╝██║██╔══██║ ██║ ╚════██║
// ██║ ╚═╝ ██║██║ ██║ ██║ ██║
// ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝
mat4_t mat4_identity() {
return (mat4_t){1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0};
}
mat4_t mat4_from_f32_array(f32_array_t *a, int offset) {
mat4_t m;
memcpy(m.m, a->buffer + offset, 16 * sizeof(float));
return m;
}
f32_array_t *mat4_to_f32_array(mat4_t m) {
f32_array_t *a = f32_array_create(16);
memcpy(a->buffer, m.m, 16 * sizeof(float));
return a;
}
mat4_t mat4_persp(float fov_y, float aspect, float zn, float zf) {
float uh = 1.0 / tanf(fov_y / 2);
float uw = uh / aspect;
return (mat4_t){uw, 0, 0, 0, 0, uh, 0, 0, 0, 0, (zf + zn) / (zn - zf), -1, 0, 0, 2 * zf * zn / (zn - zf), 0};
}
mat4_t mat4_ortho(float left, float right, float bottom, float top, float znear, float zfar) {
float rl = right - left;
float tb = top - bottom;
float fn = zfar - znear;
float tx = -(right + left) / (rl);
float ty = -(top + bottom) / (tb);
float tz = -(zfar + znear) / (fn);
return (mat4_t){2 / rl, 0, 0, 0, 0, 2 / tb, 0, 0, 0, 0, -2 / fn, 0, tx, ty, tz, 1};
}
mat4_t mat4_rot_z(float alpha) {
float ca = cosf(alpha);
float sa = sinf(alpha);
return (mat4_t){ca, sa, 0, 0, -sa, ca, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
}
mat4_t mat4_compose(vec4_t loc, quat_t rot, vec4_t scl) {
mat4_t m = mat4_from_quat(rot);
m = mat4_scale(m, scl);
m = mat4_set_loc(m, loc);
return m;
}
mat4_t mat4_tween(mat4_t a, mat4_t b, float t) {
mat4_decomposed_t *da = mat4_decompose(a);
mat4_decomposed_t *db = mat4_decompose(b);
vec4_t loc = {da->loc.x + t * (db->loc.x - da->loc.x), da->loc.y + t * (db->loc.y - da->loc.y), da->loc.z + t * (db->loc.z - da->loc.z), 1.0f};
vec4_t scl = {da->scl.x + t * (db->scl.x - da->scl.x), da->scl.y + t * (db->scl.y - da->scl.y), da->scl.z + t * (db->scl.z - da->scl.z), 1.0f};
quat_t rot = quat_slerp(da->rot, db->rot, t);
return mat4_compose(loc, rot, scl);
}
mat4_decomposed_t *mat4_decompose(mat4_t m) {
vec4_t loc;
quat_t rot;
vec4_t scl;
loc.x = m.m[12];
loc.y = m.m[13];
loc.z = m.m[14];
scl.x = vec4_len((vec4_t){m.m[0], m.m[1], m.m[2], 1.0});
scl.y = vec4_len((vec4_t){m.m[4], m.m[5], m.m[6], 1.0});
scl.z = vec4_len((vec4_t){m.m[8], m.m[9], m.m[10], 1.0});
if (mat4_determinant(m) < 0.0) {
scl.x = -scl.x;
}
float invs = 1.0 / scl.x; // Scale the rotation part
m.m[0] *= invs;
m.m[1] *= invs;
m.m[2] *= invs;
invs = 1.0 / scl.y;
m.m[4] *= invs;
m.m[5] *= invs;
m.m[6] *= invs;
invs = 1.0 / scl.z;
m.m[8] *= invs;
m.m[9] *= invs;
m.m[10] *= invs;
rot = quat_from_rot_mat(m);
// Frame temporary..
mat4_decomposed_t *dec = (mat4_decomposed_t *)string_tmp_alloc(sizeof(mat4_decomposed_t));
dec->loc = loc;
dec->rot = rot;
dec->scl = scl;
return dec;
}
mat4_t mat4_set_loc(mat4_t m, vec4_t v) {
m.m[12] = v.x;
m.m[13] = v.y;
m.m[14] = v.z;
return m;
}
mat4_t mat4_from_quat(quat_t q) {
float x2 = q.x + q.x;
float y2 = q.y + q.y;
float z2 = q.z + q.z;
float xx = q.x * x2;
float xy = q.x * y2;
float xz = q.x * z2;
float yy = q.y * y2;
float yz = q.y * z2;
float zz = q.z * z2;
float wx = q.w * x2;
float wy = q.w * y2;
float wz = q.w * z2;
mat4_t m;
m.m[0] = 1.0 - (yy + zz);
m.m[4] = xy - wz;
m.m[8] = xz + wy;
m.m[1] = xy + wz;
m.m[5] = 1.0 - (xx + zz);
m.m[9] = yz - wx;
m.m[2] = xz - wy;
m.m[6] = yz + wx;
m.m[10] = 1.0 - (xx + yy);
m.m[3] = 0.0;
m.m[7] = 0.0;
m.m[11] = 0.0;
m.m[12] = 0.0;
m.m[13] = 0.0;
m.m[14] = 0.0;
m.m[15] = 1.0;
return m;
}
mat4_t mat4_translate(mat4_t m, float x, float y, float z) {
m.m[0] += x * m.m[3];
m.m[1] += y * m.m[3];
m.m[2] += z * m.m[3];
m.m[4] += x * m.m[7];
m.m[5] += y * m.m[7];
m.m[6] += z * m.m[7];
m.m[8] += x * m.m[11];
m.m[9] += y * m.m[11];
m.m[10] += z * m.m[11];
m.m[12] += x * m.m[15];
m.m[13] += y * m.m[15];
m.m[14] += z * m.m[15];
return m;
}
mat4_t mat4_scale(mat4_t m, vec4_t v) {
m.m[0] *= v.x;
m.m[1] *= v.x;
m.m[2] *= v.x;
m.m[3] *= v.x;
m.m[4] *= v.y;
m.m[5] *= v.y;
m.m[6] *= v.y;
m.m[7] *= v.y;
m.m[8] *= v.z;
m.m[9] *= v.z;
m.m[10] *= v.z;
m.m[11] *= v.z;
return m;
}
mat4_t mat4_mult_mat3x4(mat4_t a, mat4_t b) {
float a00 = a.m[0];
float a01 = a.m[1];
float a02 = a.m[2];
float a03 = a.m[3];
float a10 = a.m[4];
float a11 = a.m[5];
float a12 = a.m[6];
float a13 = a.m[7];
float a20 = a.m[8];
float a21 = a.m[9];
float a22 = a.m[10];
float a23 = a.m[11];
float a30 = a.m[12];
float a31 = a.m[13];
float a32 = a.m[14];
float a33 = a.m[15];
float b0 = b.m[0];
float b1 = b.m[4];
float b2 = b.m[8];
float b3 = b.m[12];
mat4_t m;
m.m[0] = a00 * b0 + a01 * b1 + a02 * b2 + a03 * b3;
m.m[4] = a10 * b0 + a11 * b1 + a12 * b2 + a13 * b3;
m.m[8] = a20 * b0 + a21 * b1 + a22 * b2 + a23 * b3;
m.m[12] = a30 * b0 + a31 * b1 + a32 * b2 + a33 * b3;
b0 = b.m[1];
b1 = b.m[5];
b2 = b.m[9];
b3 = b.m[13];
m.m[1] = a00 * b0 + a01 * b1 + a02 * b2 + a03 * b3;
m.m[5] = a10 * b0 + a11 * b1 + a12 * b2 + a13 * b3;
m.m[9] = a20 * b0 + a21 * b1 + a22 * b2 + a23 * b3;
m.m[13] = a30 * b0 + a31 * b1 + a32 * b2 + a33 * b3;
b0 = b.m[2];
b1 = b.m[6];
b2 = b.m[10];
b3 = b.m[14];
m.m[2] = a00 * b0 + a01 * b1 + a02 * b2 + a03 * b3;
m.m[6] = a10 * b0 + a11 * b1 + a12 * b2 + a13 * b3;
m.m[10] = a20 * b0 + a21 * b1 + a22 * b2 + a23 * b3;
m.m[14] = a30 * b0 + a31 * b1 + a32 * b2 + a33 * b3;
m.m[3] = 0;
m.m[7] = 0;
m.m[11] = 0;
m.m[15] = 1;
return m;
}
mat4_t mat4_mult_mat(mat4_t a, mat4_t b) {
float a00 = a.m[0];
float a01 = a.m[1];
float a02 = a.m[2];
float a03 = a.m[3];
float a10 = a.m[4];
float a11 = a.m[5];
float a12 = a.m[6];
float a13 = a.m[7];
float a20 = a.m[8];
float a21 = a.m[9];
float a22 = a.m[10];
float a23 = a.m[11];
float a30 = a.m[12];
float a31 = a.m[13];
float a32 = a.m[14];
float a33 = a.m[15];
float b0 = b.m[0];
float b1 = b.m[4];
float b2 = b.m[8];
float b3 = b.m[12];
a.m[0] = a00 * b0 + a01 * b1 + a02 * b2 + a03 * b3;
a.m[4] = a10 * b0 + a11 * b1 + a12 * b2 + a13 * b3;
a.m[8] = a20 * b0 + a21 * b1 + a22 * b2 + a23 * b3;
a.m[12] = a30 * b0 + a31 * b1 + a32 * b2 + a33 * b3;
b0 = b.m[1];
b1 = b.m[5];
b2 = b.m[9];
b3 = b.m[13];
a.m[1] = a00 * b0 + a01 * b1 + a02 * b2 + a03 * b3;
a.m[5] = a10 * b0 + a11 * b1 + a12 * b2 + a13 * b3;
a.m[9] = a20 * b0 + a21 * b1 + a22 * b2 + a23 * b3;
a.m[13] = a30 * b0 + a31 * b1 + a32 * b2 + a33 * b3;
b0 = b.m[2];
b1 = b.m[6];
b2 = b.m[10];
b3 = b.m[14];
a.m[2] = a00 * b0 + a01 * b1 + a02 * b2 + a03 * b3;
a.m[6] = a10 * b0 + a11 * b1 + a12 * b2 + a13 * b3;
a.m[10] = a20 * b0 + a21 * b1 + a22 * b2 + a23 * b3;
a.m[14] = a30 * b0 + a31 * b1 + a32 * b2 + a33 * b3;
b0 = b.m[3];
b1 = b.m[7];
b2 = b.m[11];
b3 = b.m[15];
a.m[3] = a00 * b0 + a01 * b1 + a02 * b2 + a03 * b3;
a.m[7] = a10 * b0 + a11 * b1 + a12 * b2 + a13 * b3;
a.m[11] = a20 * b0 + a21 * b1 + a22 * b2 + a23 * b3;
a.m[15] = a30 * b0 + a31 * b1 + a32 * b2 + a33 * b3;
return a;
}
mat4_t mat4_inv(mat4_t a) {
float a00 = a.m[0];
float a01 = a.m[1];
float a02 = a.m[2];
float a03 = a.m[3];
float a10 = a.m[4];
float a11 = a.m[5];
float a12 = a.m[6];
float a13 = a.m[7];
float a20 = a.m[8];
float a21 = a.m[9];
float a22 = a.m[10];
float a23 = a.m[11];
float a30 = a.m[12];
float a31 = a.m[13];
float a32 = a.m[14];
float a33 = a.m[15];
float b00 = a00 * a11 - a01 * a10;
float b01 = a00 * a12 - a02 * a10;
float b02 = a00 * a13 - a03 * a10;
float b03 = a01 * a12 - a02 * a11;
float b04 = a01 * a13 - a03 * a11;
float b05 = a02 * a13 - a03 * a12;
float b06 = a20 * a31 - a21 * a30;
float b07 = a20 * a32 - a22 * a30;
float b08 = a20 * a33 - a23 * a30;
float b09 = a21 * a32 - a22 * a31;
float b10 = a21 * a33 - a23 * a31;
float b11 = a22 * a33 - a23 * a32;
float det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
if (det == 0.0) {
return mat4_identity();
}
det = 1.0 / det;
mat4_t m;
m.m[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
m.m[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
m.m[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
m.m[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
m.m[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
m.m[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
m.m[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
m.m[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
m.m[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
m.m[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
m.m[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
m.m[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
m.m[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
m.m[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
m.m[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
m.m[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
return m;
}
mat4_t mat4_transpose(mat4_t m) {
float f = m.m[1];
m.m[1] = m.m[4];
m.m[4] = f;
f = m.m[2];
m.m[2] = m.m[8];
m.m[8] = f;
f = m.m[3];
m.m[3] = m.m[12];
m.m[12] = f;
f = m.m[6];
m.m[6] = m.m[9];
m.m[9] = f;
f = m.m[7];
m.m[7] = m.m[13];
m.m[13] = f;
f = m.m[11];
m.m[11] = m.m[14];
m.m[14] = f;
return m;
}
mat4_t mat4_transpose3(mat4_t m) {
float f = m.m[1];
m.m[1] = m.m[4];
m.m[4] = f;
f = m.m[2];
m.m[2] = m.m[8];
m.m[8] = f;
f = m.m[6];
m.m[6] = m.m[9];
m.m[9] = f;
return m;
}
vec4_t mat4_get_loc(mat4_t m) {
return (vec4_t){m.m[12], m.m[13], m.m[14], m.m[15]};
}
vec4_t mat4_get_scale(mat4_t m) {
return (vec4_t){sqrtf(m.m[0] * m.m[0] + m.m[4] * m.m[4] + m.m[8] * m.m[8]), sqrtf(m.m[1] * m.m[1] + m.m[5] * m.m[5] + m.m[9] * m.m[9]),
sqrtf(m.m[2] * m.m[2] + m.m[6] * m.m[6] + m.m[10] * m.m[10]), 1.0};
}
mat4_t mat4_mult(mat4_t m, float s) {
m.m[0] *= s;
m.m[1] *= s;
m.m[2] *= s;
m.m[3] *= s;
m.m[4] *= s;
m.m[5] *= s;
m.m[6] *= s;
m.m[7] *= s;
m.m[8] *= s;
m.m[9] *= s;
m.m[10] *= s;
m.m[11] *= s;
m.m[12] *= s;
m.m[13] *= s;
m.m[14] *= s;
m.m[15] *= s;
return m;
}
mat4_t mat4_to_rot(mat4_t m) {
float scale = 1.0 / vec4_len((vec4_t){m.m[0], m.m[1], m.m[2], 1.0});
m.m[0] = m.m[0] * scale;
m.m[1] = m.m[1] * scale;
m.m[2] = m.m[2] * scale;
scale = 1.0 / vec4_len((vec4_t){m.m[4], m.m[5], m.m[6], 1.0});
m.m[4] = m.m[4] * scale;
m.m[5] = m.m[5] * scale;
m.m[6] = m.m[6] * scale;
scale = 1.0 / vec4_len((vec4_t){m.m[8], m.m[9], m.m[10], 1.0});
m.m[8] = m.m[8] * scale;
m.m[9] = m.m[9] * scale;
m.m[10] = m.m[10] * scale;
m.m[3] = 0.0;
m.m[7] = 0.0;
m.m[11] = 0.0;
m.m[12] = 0.0;
m.m[13] = 0.0;
m.m[14] = 0.0;
m.m[15] = 1.0;
return m;
}
vec4_t mat4_right(mat4_t m) {
return vec4_norm((vec4_t){m.m[0], m.m[1], m.m[2], 1.0});
}
vec4_t mat4_look(mat4_t m) {
return vec4_norm((vec4_t){m.m[4], m.m[5], m.m[6], 1.0});
}
vec4_t mat4_up(mat4_t m) {
return vec4_norm((vec4_t){m.m[8], m.m[9], m.m[10], 1.0});
}
float mat4_cofactor(float m0, float m1, float m2, float m3, float m4, float m5, float m6, float m7, float m8) {
return m0 * (m4 * m8 - m5 * m7) - m1 * (m3 * m8 - m5 * m6) + m2 * (m3 * m7 - m4 * m6);
}
float mat4_determinant(mat4_t m) {
float c00 = mat4_cofactor(m.m[5], m.m[9], m.m[13], m.m[6], m.m[10], m.m[14], m.m[7], m.m[11], m.m[15]);
float c01 = mat4_cofactor(m.m[4], m.m[8], m.m[12], m.m[6], m.m[10], m.m[14], m.m[7], m.m[11], m.m[15]);
float c02 = mat4_cofactor(m.m[4], m.m[8], m.m[12], m.m[5], m.m[9], m.m[13], m.m[7], m.m[11], m.m[15]);
float c03 = mat4_cofactor(m.m[4], m.m[8], m.m[12], m.m[5], m.m[9], m.m[13], m.m[6], m.m[10], m.m[14]);
return m.m[0] * c00 - m.m[1] * c01 + m.m[2] * c02 - m.m[3] * c03;
}
mat4_t mat4_nan() {
mat4_t m;
m.m[0] = NAN;
return m;
}
bool mat4_isnan(mat4_t m) {
return isnan(m.m[0]);
}