2025-10-04 04:13:48 -05:00
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
|
|
#include "pxl8_math.h"
|
|
|
|
|
|
|
|
|
|
pxl8_vec2 pxl8_vec2_add(pxl8_vec2 a, pxl8_vec2 b) {
|
2025-10-05 16:25:17 -05:00
|
|
|
return (pxl8_vec2){
|
2025-10-04 04:13:48 -05:00
|
|
|
.x = a.x + b.x,
|
|
|
|
|
.y = a.y + b.y,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pxl8_vec2 pxl8_vec2_sub(pxl8_vec2 a, pxl8_vec2 b) {
|
2025-10-05 16:25:17 -05:00
|
|
|
return (pxl8_vec2){
|
2025-10-04 04:13:48 -05:00
|
|
|
.x = a.x - b.x,
|
|
|
|
|
.y = a.y - b.y,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pxl8_vec2 pxl8_vec2_scale(pxl8_vec2 v, f32 s) {
|
2025-10-05 16:25:17 -05:00
|
|
|
return (pxl8_vec2){
|
2025-10-04 04:13:48 -05:00
|
|
|
.x = v.x * s,
|
|
|
|
|
.y = v.y * s,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
f32 pxl8_vec2_dot(pxl8_vec2 a, pxl8_vec2 b) {
|
|
|
|
|
return a.x * b.x + a.y * b.y;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
f32 pxl8_vec2_length(pxl8_vec2 v) {
|
|
|
|
|
return sqrtf(v.x * v.x + v.y * v.y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pxl8_vec2 pxl8_vec2_normalize(pxl8_vec2 v) {
|
|
|
|
|
f32 len = pxl8_vec2_length(v);
|
2025-10-05 16:25:17 -05:00
|
|
|
|
2025-10-04 04:13:48 -05:00
|
|
|
if (len < 1e-6f) return (pxl8_vec2){0};
|
2025-10-05 16:25:17 -05:00
|
|
|
|
2025-10-04 04:13:48 -05:00
|
|
|
return pxl8_vec2_scale(v, 1.0f / len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pxl8_vec3 pxl8_vec3_add(pxl8_vec3 a, pxl8_vec3 b) {
|
2025-10-05 16:25:17 -05:00
|
|
|
return (pxl8_vec3){
|
2025-11-11 12:26:22 -06:00
|
|
|
.x = a.x + b.x,
|
|
|
|
|
.y = a.y + b.y,
|
|
|
|
|
.z = a.z + b.z,
|
2025-10-04 04:13:48 -05:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pxl8_vec3 pxl8_vec3_sub(pxl8_vec3 a, pxl8_vec3 b) {
|
2025-10-05 16:25:17 -05:00
|
|
|
return (pxl8_vec3){
|
2025-11-11 12:26:22 -06:00
|
|
|
.x = a.x - b.x,
|
|
|
|
|
.y = a.y - b.y,
|
|
|
|
|
.z = a.z - b.z,
|
2025-10-04 04:13:48 -05:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pxl8_vec3 pxl8_vec3_scale(pxl8_vec3 v, f32 s) {
|
2025-10-05 16:25:17 -05:00
|
|
|
return (pxl8_vec3){
|
2025-11-11 12:26:22 -06:00
|
|
|
.x = v.x * s,
|
|
|
|
|
.y = v.y * s,
|
|
|
|
|
.z = v.z * s,
|
2025-10-04 04:13:48 -05:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
f32 pxl8_vec3_dot(pxl8_vec3 a, pxl8_vec3 b) {
|
2025-11-11 12:26:22 -06:00
|
|
|
return a.x * b.x + a.y * b.y + a.z * b.z;
|
2025-10-04 04:13:48 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pxl8_vec3 pxl8_vec3_cross(pxl8_vec3 a, pxl8_vec3 b) {
|
2025-10-05 16:25:17 -05:00
|
|
|
return (pxl8_vec3){
|
2025-10-04 04:13:48 -05:00
|
|
|
.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,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
f32 pxl8_vec3_length(pxl8_vec3 v) {
|
|
|
|
|
return sqrtf(pxl8_vec3_dot(v, v));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pxl8_vec3 pxl8_vec3_normalize(pxl8_vec3 v) {
|
|
|
|
|
f32 len = pxl8_vec3_length(v);
|
2025-10-05 16:25:17 -05:00
|
|
|
|
2025-10-04 04:13:48 -05:00
|
|
|
if (len < 1e-6f) return (pxl8_vec3){0};
|
2025-10-05 16:25:17 -05:00
|
|
|
|
2025-10-04 04:13:48 -05:00
|
|
|
return pxl8_vec3_scale(v, 1.0f / len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pxl8_mat4 pxl8_mat4_identity(void) {
|
|
|
|
|
pxl8_mat4 mat = {0};
|
2025-10-05 16:25:17 -05:00
|
|
|
|
2025-10-04 04:13:48 -05:00
|
|
|
mat.m[0] = mat.m[5] = mat.m[10] = mat.m[15] = 1.0f;
|
2025-10-05 16:25:17 -05:00
|
|
|
|
2025-10-04 04:13:48 -05:00
|
|
|
return mat;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pxl8_mat4 pxl8_mat4_multiply(pxl8_mat4 a, pxl8_mat4 b) {
|
2025-10-05 16:25:17 -05:00
|
|
|
pxl8_mat4 mat = {0};
|
|
|
|
|
|
2025-10-04 04:13:48 -05:00
|
|
|
for (i32 i = 0; i < 4; i++) {
|
|
|
|
|
for (i32 j = 0; j < 4; j++) {
|
2025-11-11 12:26:22 -06:00
|
|
|
mat.m[i * 4 + j] =
|
|
|
|
|
a.m[i * 4 + 0] * b.m[0 * 4 + j] +
|
|
|
|
|
a.m[i * 4 + 1] * b.m[1 * 4 + j] +
|
|
|
|
|
a.m[i * 4 + 2] * b.m[2 * 4 + j] +
|
|
|
|
|
a.m[i * 4 + 3] * b.m[3 * 4 + j];
|
2025-10-04 04:13:48 -05:00
|
|
|
}
|
|
|
|
|
}
|
2025-10-05 16:25:17 -05:00
|
|
|
|
|
|
|
|
return mat;
|
2025-10-04 04:13:48 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pxl8_vec4 pxl8_mat4_multiply_vec4(pxl8_mat4 m, pxl8_vec4 v) {
|
2025-10-05 16:25:17 -05:00
|
|
|
return (pxl8_vec4){
|
2025-11-11 12:26:22 -06:00
|
|
|
.x = m.m[0] * v.x + m.m[1] * v.y + m.m[2] * v.z + m.m[3] * v.w,
|
|
|
|
|
.y = m.m[4] * v.x + m.m[5] * v.y + m.m[6] * v.z + m.m[7] * v.w,
|
|
|
|
|
.z = m.m[8] * v.x + m.m[9] * v.y + m.m[10] * v.z + m.m[11] * v.w,
|
|
|
|
|
.w = m.m[12] * v.x + m.m[13] * v.y + m.m[14] * v.z + m.m[15] * v.w,
|
2025-10-05 16:25:17 -05:00
|
|
|
};
|
2025-10-04 04:13:48 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pxl8_mat4 pxl8_mat4_translate(f32 x, f32 y, f32 z) {
|
|
|
|
|
pxl8_mat4 mat = pxl8_mat4_identity();
|
2025-10-05 16:25:17 -05:00
|
|
|
|
2025-10-04 04:13:48 -05:00
|
|
|
mat.m[3] = x;
|
|
|
|
|
mat.m[7] = y;
|
|
|
|
|
mat.m[11] = z;
|
2025-10-05 16:25:17 -05:00
|
|
|
|
2025-10-04 04:13:48 -05:00
|
|
|
return mat;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pxl8_mat4 pxl8_mat4_rotate_x(f32 angle) {
|
|
|
|
|
pxl8_mat4 mat = pxl8_mat4_identity();
|
|
|
|
|
f32 c = cosf(angle);
|
|
|
|
|
f32 s = sinf(angle);
|
2025-10-05 16:25:17 -05:00
|
|
|
|
2025-10-04 04:13:48 -05:00
|
|
|
mat.m[5] = c;
|
|
|
|
|
mat.m[6] = -s;
|
|
|
|
|
mat.m[9] = s;
|
|
|
|
|
mat.m[10] = c;
|
2025-10-05 16:25:17 -05:00
|
|
|
|
2025-10-04 04:13:48 -05:00
|
|
|
return mat;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pxl8_mat4 pxl8_mat4_rotate_y(f32 angle) {
|
|
|
|
|
pxl8_mat4 mat = pxl8_mat4_identity();
|
|
|
|
|
f32 c = cosf(angle);
|
|
|
|
|
f32 s = sinf(angle);
|
2025-10-05 16:25:17 -05:00
|
|
|
|
2025-10-04 04:13:48 -05:00
|
|
|
mat.m[0] = c;
|
|
|
|
|
mat.m[2] = s;
|
|
|
|
|
mat.m[8] = -s;
|
|
|
|
|
mat.m[10] = c;
|
2025-10-05 16:25:17 -05:00
|
|
|
|
2025-10-04 04:13:48 -05:00
|
|
|
return mat;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pxl8_mat4 pxl8_mat4_rotate_z(f32 angle) {
|
|
|
|
|
pxl8_mat4 mat = pxl8_mat4_identity();
|
|
|
|
|
f32 c = cosf(angle);
|
|
|
|
|
f32 s = sinf(angle);
|
2025-10-05 16:25:17 -05:00
|
|
|
|
2025-10-04 04:13:48 -05:00
|
|
|
mat.m[0] = c;
|
|
|
|
|
mat.m[1] = -s;
|
|
|
|
|
mat.m[4] = s;
|
|
|
|
|
mat.m[5] = c;
|
2025-10-05 16:25:17 -05:00
|
|
|
|
2025-10-04 04:13:48 -05:00
|
|
|
return mat;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pxl8_mat4 pxl8_mat4_scale(f32 x, f32 y, f32 z) {
|
|
|
|
|
pxl8_mat4 mat = pxl8_mat4_identity();
|
2025-10-05 16:25:17 -05:00
|
|
|
|
2025-10-04 04:13:48 -05:00
|
|
|
mat.m[0] = x;
|
|
|
|
|
mat.m[5] = y;
|
|
|
|
|
mat.m[10] = z;
|
2025-10-05 16:25:17 -05:00
|
|
|
|
2025-10-04 04:13:48 -05:00
|
|
|
return mat;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pxl8_mat4 pxl8_mat4_ortho(f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far) {
|
|
|
|
|
pxl8_mat4 mat = {0};
|
|
|
|
|
|
|
|
|
|
mat.m[0] = 2.0f / (right - left);
|
|
|
|
|
mat.m[5] = 2.0f / (top - bottom);
|
|
|
|
|
mat.m[10] = -2.0f / (far - near);
|
|
|
|
|
mat.m[3] = -(right + left) / (right - left);
|
|
|
|
|
mat.m[7] = -(top + bottom) / (top - bottom);
|
|
|
|
|
mat.m[11] = -(far + near) / (far - near);
|
|
|
|
|
mat.m[15] = 1.0f;
|
|
|
|
|
|
|
|
|
|
return mat;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pxl8_mat4 pxl8_mat4_perspective(f32 fov, f32 aspect, f32 near, f32 far) {
|
|
|
|
|
pxl8_mat4 mat = {0};
|
|
|
|
|
f32 tan_half_fov = tanf(fov / 2.0f);
|
|
|
|
|
|
|
|
|
|
mat.m[0] = 1.0f / (aspect * tan_half_fov);
|
|
|
|
|
mat.m[5] = 1.0f / tan_half_fov;
|
|
|
|
|
mat.m[10] = -(far + near) / (far - near);
|
|
|
|
|
mat.m[11] = -(2.0f * far * near) / (far - near);
|
|
|
|
|
mat.m[14] = -1.0f;
|
|
|
|
|
|
|
|
|
|
return mat;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pxl8_mat4 pxl8_mat4_lookat(pxl8_vec3 eye, pxl8_vec3 center, pxl8_vec3 up) {
|
2025-10-05 16:25:17 -05:00
|
|
|
pxl8_mat4 mat = pxl8_mat4_identity();
|
2025-10-04 04:13:48 -05:00
|
|
|
pxl8_vec3 f = pxl8_vec3_normalize(pxl8_vec3_sub(center, eye));
|
|
|
|
|
pxl8_vec3 s = pxl8_vec3_normalize(pxl8_vec3_cross(f, up));
|
|
|
|
|
pxl8_vec3 u = pxl8_vec3_cross(s, f);
|
|
|
|
|
|
|
|
|
|
mat.m[0] = s.x;
|
|
|
|
|
mat.m[1] = s.y;
|
|
|
|
|
mat.m[2] = s.z;
|
|
|
|
|
mat.m[4] = u.x;
|
|
|
|
|
mat.m[5] = u.y;
|
|
|
|
|
mat.m[6] = u.z;
|
|
|
|
|
mat.m[8] = -f.x;
|
|
|
|
|
mat.m[9] = -f.y;
|
|
|
|
|
mat.m[10] = -f.z;
|
|
|
|
|
mat.m[3] = -pxl8_vec3_dot(s, eye);
|
|
|
|
|
mat.m[7] = -pxl8_vec3_dot(u, eye);
|
|
|
|
|
mat.m[11] = pxl8_vec3_dot(f, eye);
|
|
|
|
|
|
|
|
|
|
return mat;
|
|
|
|
|
}
|
2025-11-09 06:30:17 -06:00
|
|
|
|
|
|
|
|
pxl8_frustum pxl8_frustum_from_matrix(pxl8_mat4 vp) {
|
|
|
|
|
pxl8_frustum frustum;
|
|
|
|
|
const f32* m = vp.m;
|
|
|
|
|
|
2025-11-10 10:24:27 -06:00
|
|
|
frustum.planes[0].normal.x = m[12] - m[0];
|
|
|
|
|
frustum.planes[0].normal.y = m[13] - m[1];
|
|
|
|
|
frustum.planes[0].normal.z = m[14] - m[2];
|
|
|
|
|
frustum.planes[0].distance = m[15] - m[3];
|
|
|
|
|
|
|
|
|
|
frustum.planes[1].normal.x = m[12] + m[0];
|
|
|
|
|
frustum.planes[1].normal.y = m[13] + m[1];
|
|
|
|
|
frustum.planes[1].normal.z = m[14] + m[2];
|
|
|
|
|
frustum.planes[1].distance = m[15] + m[3];
|
|
|
|
|
|
|
|
|
|
frustum.planes[2].normal.x = m[12] + m[4];
|
|
|
|
|
frustum.planes[2].normal.y = m[13] + m[5];
|
|
|
|
|
frustum.planes[2].normal.z = m[14] + m[6];
|
|
|
|
|
frustum.planes[2].distance = m[15] + m[7];
|
|
|
|
|
|
|
|
|
|
frustum.planes[3].normal.x = m[12] - m[4];
|
|
|
|
|
frustum.planes[3].normal.y = m[13] - m[5];
|
|
|
|
|
frustum.planes[3].normal.z = m[14] - m[6];
|
|
|
|
|
frustum.planes[3].distance = m[15] - m[7];
|
|
|
|
|
|
|
|
|
|
frustum.planes[4].normal.x = m[12] - m[8];
|
|
|
|
|
frustum.planes[4].normal.y = m[13] - m[9];
|
|
|
|
|
frustum.planes[4].normal.z = m[14] - m[10];
|
|
|
|
|
frustum.planes[4].distance = m[15] - m[11];
|
|
|
|
|
|
|
|
|
|
frustum.planes[5].normal.x = m[12] + m[8];
|
|
|
|
|
frustum.planes[5].normal.y = m[13] + m[9];
|
|
|
|
|
frustum.planes[5].normal.z = m[14] + m[10];
|
|
|
|
|
frustum.planes[5].distance = m[15] + m[11];
|
2025-11-09 06:30:17 -06:00
|
|
|
|
|
|
|
|
for (i32 i = 0; i < 6; i++) {
|
|
|
|
|
f32 len = pxl8_vec3_length(frustum.planes[i].normal);
|
|
|
|
|
if (len > 1e-6f) {
|
|
|
|
|
f32 inv_len = 1.0f / len;
|
|
|
|
|
frustum.planes[i].normal = pxl8_vec3_scale(frustum.planes[i].normal, inv_len);
|
|
|
|
|
frustum.planes[i].distance *= inv_len;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return frustum;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool pxl8_frustum_test_aabb(const pxl8_frustum* frustum, pxl8_vec3 min, pxl8_vec3 max) {
|
|
|
|
|
for (i32 i = 0; i < 6; i++) {
|
|
|
|
|
pxl8_vec3 normal = frustum->planes[i].normal;
|
|
|
|
|
f32 d = frustum->planes[i].distance;
|
|
|
|
|
|
|
|
|
|
pxl8_vec3 p_vertex = {
|
|
|
|
|
(normal.x >= 0.0f) ? max.x : min.x,
|
|
|
|
|
(normal.y >= 0.0f) ? max.y : min.y,
|
|
|
|
|
(normal.z >= 0.0f) ? max.z : min.z
|
|
|
|
|
};
|
|
|
|
|
|
2025-11-10 09:39:33 -06:00
|
|
|
pxl8_vec3 n_vertex = {
|
|
|
|
|
(normal.x >= 0.0f) ? min.x : max.x,
|
|
|
|
|
(normal.y >= 0.0f) ? min.y : max.y,
|
|
|
|
|
(normal.z >= 0.0f) ? min.z : max.z
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
f32 p_dist = pxl8_vec3_dot(normal, p_vertex) + d;
|
|
|
|
|
f32 n_dist = pxl8_vec3_dot(normal, n_vertex) + d;
|
2025-11-09 06:30:17 -06:00
|
|
|
|
2025-11-10 09:39:33 -06:00
|
|
|
if (p_dist < -0.1f) {
|
2025-11-09 06:30:17 -06:00
|
|
|
return false;
|
|
|
|
|
}
|
2025-11-10 09:39:33 -06:00
|
|
|
|
|
|
|
|
if (n_dist > 0.1f) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2025-11-09 06:30:17 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|