Nimbin2git.christianimmanuel.de / Games / strichmaennchen / linalg.c

strichmaennchen git · main

git clone https://git.christianimmanuel.de/games/strichmaennchen.gitwget https://git.christianimmanuel.de/games/strichmaennchen/archive/strichmaennchen.tar.gz
linalg.c 7.5 KB · 268 lines raw
#include "linalg.h"
#include <math.h>
#include <stdio.h>


float cosf(float x);
float tanf(float x);
float sinf(float x);
float sqrtf(float x);


Vec4 vec4(float x, float y, float z, float w) {
    Vec4 v = {x, y, z, w};
    return v;
}

Vec4 vec4_sub(Vec4 a, Vec4 b) {
    Vec4 r = {a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w};
    return r;
}

Vec4 mat4_mul_vec4(Mat4 m, Vec4 v) {
    Vec4 r;
    r.x = m.m[0]*v.x + m.m[1]*v.y + m.m[2]*v.z + m.m[3]*v.w;
    r.y = m.m[4]*v.x + m.m[5]*v.y + m.m[6]*v.z + m.m[7]*v.w;
    r.z = m.m[8]*v.x + m.m[9]*v.y + m.m[10]*v.z + m.m[11]*v.w;
    r.w = m.m[12]*v.x + m.m[13]*v.y + m.m[14]*v.z + m.m[15]*v.w;
    return r;
}

Vec3 vec3(float x, float y, float z) {
    Vec3 v = {x, y, z};
    return v;
}

Vec3 vec3_negate(Vec3 v) {
    return (Vec3){ -v.x, -v.y, -v.z };
}

float vec3_dot(Vec3 a, Vec3 b) {
    return a.x*b.x + a.y*b.y + a.z*b.z;
}

Mat4 mat4_identity() {
    Mat4 m = {{0}};
    m.m[0]=1; m.m[5]=1; m.m[10]=1; m.m[15]=1;
    return m;
}

Mat4 mat4_translate(Vec3 v) {
    Mat4 m = mat4_identity();
    m.m[12] = v.x;
    m.m[13] = v.y;
    m.m[14] = v.z;
    return m;
}

float vec3_length(Vec3 v) {
    return sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);
}

Vec3 vec3_normalize(Vec3 v) {
    float len = sqrtf(v.x*v.x + v.y*v.y + v.z*v.z);
    return (Vec3){ v.x/len, v.y/len, v.z/len };
}

Vec3 vec3_scale(Vec3 v, float s) {
    return (Vec3){v.x * s, v.y * s, v.z * s};
}

Vec3 vec3_div_scalar(Vec4 v) {
    float inv_w = 1.0f / v.w;
    Vec3 r = { v.x * inv_w, v.y * inv_w, v.z * inv_w };
    return r;
}


Vec3 vec3_div_scalar_f(Vec3 v, float s) {
    return (Vec3){v.x / s, v.y / s, v.z / s};
}

Vec3 vec3_cross(Vec3 a, Vec3 b) {
    return (Vec3){
        a.y*b.z - a.z*b.y,
        a.z*b.x - a.x*b.z,
        a.x*b.y - a.y*b.x
    };
}

Vec3 vec3_rotate(Vec3 v, Vec3 rot) {
    // Apply ZYX rotation (roll, pitch, yaw)
    float cx = cosf(rot.x), sx = sinf(rot.x);
    float cy = cosf(rot.y), sy = sinf(rot.y);
    float cz = cosf(rot.z), sz = sinf(rot.z);

    // Rotation around X
    Vec3 rx = {v.x, v.y*cx - v.z*sx, v.y*sx + v.z*cx};
    // Rotation around Y
    Vec3 ry = {rx.x*cy + rx.z*sy, rx.y, -rx.x*sy + rx.z*cy};
    // Rotation around Z
    Vec3 rz = {ry.x*cz - ry.y*sz, ry.x*sz + ry.y*cz, ry.z};
    return rz;
}

Vec3 vec3_add(Vec3 a, Vec3 b) {
    return (Vec3){ a.x + b.x, a.y + b.y, a.z + b.z };
}

Vec3 vec3_sub(Vec3 a, Vec3 b) {
    return (Vec3){a.x - b.x, a.y - b.y, a.z - b.z};
}

Vec3 mat4_mul_vec3_dir(Mat4 m, Vec3 v) {
    Vec3 r;
    r.x = m.m[0] * v.x + m.m[4] * v.y + m.m[8]  * v.z;
    r.y = m.m[1] * v.x + m.m[5] * v.y + m.m[9]  * v.z;
    r.z = m.m[2] * v.x + m.m[6] * v.y + m.m[10] * v.z;
    return r;
}

// Placeholder for future perspective/lookAt
Mat4 mat4_perspective(float fov_deg, float aspect, float near, float far) {
    float f = 1.0f / tanf(fov_deg * 0.5f * (3.14159265f / 180.0f));
    Mat4 m = {{0}};

    m.m[0]  = f / aspect;        // scale X by aspect
    m.m[5]  = f;                 // scale Y
    m.m[10] = -(far + near) / (far - near);
    m.m[11] = -1.0f;
    m.m[14] = -(2.0f * far * near) / (far - near);
    m.m[15] = 0.0f;

    return m;
}

Mat4 mat4_inverse(Mat4 m) {
    Mat4 inv;
    float *a = m.m, *o = inv.m;

    o[0] =   a[5]*a[10]*a[15] - a[5]*a[11]*a[14] - a[9]*a[6]*a[15]
           + a[9]*a[7]*a[14] + a[13]*a[6]*a[11] - a[13]*a[7]*a[10];
    o[4] =  -a[4]*a[10]*a[15] + a[4]*a[11]*a[14] + a[8]*a[6]*a[15]
           - a[8]*a[7]*a[14] - a[12]*a[6]*a[11] + a[12]*a[7]*a[10];
    o[8] =   a[4]*a[9]*a[15] - a[4]*a[11]*a[13] - a[8]*a[5]*a[15]
           + a[8]*a[7]*a[13] + a[12]*a[5]*a[11] - a[12]*a[7]*a[9];
    o[12] = -a[4]*a[9]*a[14] + a[4]*a[10]*a[13] + a[8]*a[5]*a[14]
           - a[8]*a[6]*a[13] - a[12]*a[5]*a[10] + a[12]*a[6]*a[9];
    o[1] =  -a[1]*a[10]*a[15] + a[1]*a[11]*a[14] + a[9]*a[2]*a[15]
           - a[9]*a[3]*a[14] - a[13]*a[2]*a[11] + a[13]*a[3]*a[10];
    o[5] =   a[0]*a[10]*a[15] - a[0]*a[11]*a[14] - a[8]*a[2]*a[15]
           + a[8]*a[3]*a[14] + a[12]*a[2]*a[11] - a[12]*a[3]*a[10];
    o[9] =  -a[0]*a[9]*a[15] + a[0]*a[11]*a[13] + a[8]*a[1]*a[15]
           - a[8]*a[3]*a[13] - a[12]*a[1]*a[11] + a[12]*a[3]*a[9];
    o[13] =  a[0]*a[9]*a[14] - a[0]*a[10]*a[13] - a[8]*a[1]*a[14]
           + a[8]*a[2]*a[13] + a[12]*a[1]*a[10] - a[12]*a[2]*a[9];
    o[2] =   a[1]*a[6]*a[15] - a[1]*a[7]*a[14] - a[5]*a[2]*a[15]
           + a[5]*a[3]*a[14] + a[13]*a[2]*a[7] - a[13]*a[3]*a[6];
    o[6] =  -a[0]*a[6]*a[15] + a[0]*a[7]*a[14] + a[4]*a[2]*a[15]
           - a[4]*a[3]*a[14] - a[12]*a[2]*a[7] + a[12]*a[3]*a[6];
    o[10] =  a[0]*a[5]*a[15] - a[0]*a[7]*a[13] - a[4]*a[1]*a[15]
           + a[4]*a[3]*a[13] + a[12]*a[1]*a[7] - a[12]*a[3]*a[5];
    o[14] = -a[0]*a[5]*a[14] + a[0]*a[6]*a[13] + a[4]*a[1]*a[14]
           - a[4]*a[2]*a[13] - a[12]*a[1]*a[6] + a[12]*a[2]*a[5];
    o[3] =  -a[1]*a[6]*a[11] + a[1]*a[7]*a[10] + a[5]*a[2]*a[11]
           - a[5]*a[3]*a[10] - a[9]*a[2]*a[7] + a[9]*a[3]*a[6];
    o[7] =   a[0]*a[6]*a[11] - a[0]*a[7]*a[10] - a[4]*a[2]*a[11]
           + a[4]*a[3]*a[10] + a[8]*a[2]*a[7] - a[8]*a[3]*a[6];
    o[11] = -a[0]*a[5]*a[11] + a[0]*a[7]*a[9] + a[4]*a[1]*a[11]
           - a[4]*a[3]*a[9] - a[8]*a[1]*a[7] + a[8]*a[3]*a[5];
    o[15] =  a[0]*a[5]*a[10] - a[0]*a[6]*a[9] - a[4]*a[1]*a[10]
           + a[4]*a[2]*a[9] + a[8]*a[1]*a[6] - a[8]*a[2]*a[5];

    float det = a[0]*o[0] + a[1]*o[4] + a[2]*o[8] + a[3]*o[12];
    if (det == 0.0f) {
        // return identity if not invertible
        Mat4 id = { {1,0,0,0,
                     0,1,0,0,
                     0,0,1,0,
                     0,0,0,1} };
        return id;
    }

    det = 1.0f / det;
    for (int i = 0; i < 16; i++) o[i] *= det;
    return inv;
}

Mat4 mat4_orthographic(float left, float right, float bottom, float top, float near, float far) {
    Mat4 result = {0};

    result.m[0]  = 2.0f / (right - left);
    result.m[5]  = 2.0f / (top - bottom);
    result.m[10] = -2.0f / (far - near);
    result.m[12] = -(right + left) / (right - left);
    result.m[13] = -(top + bottom) / (top - bottom);
    result.m[14] = -(far + near) / (far - near);
    result.m[15] = 1.0f;

    return result;
}

Mat4 mat4_lookAt(Vec3 eye, Vec3 center, Vec3 up) {
    Vec3 f = vec3_normalize(vec3_sub(center, eye));
    Vec3 s = vec3_normalize(vec3_cross(f, up));
    Vec3 u = vec3_cross(s, f);

    Mat4 m = mat4_identity();

    // rotation part
    m.m[0] = s.x;  m.m[4] = s.y;  m.m[8]  = s.z;
    m.m[1] = u.x;  m.m[5] = u.y;  m.m[9]  = u.z;
    m.m[2] = -f.x; m.m[6] = -f.y; m.m[10] = -f.z;

    // translation part
    m.m[12] = -vec3_dot(s, eye);
    m.m[13] = -vec3_dot(u, eye);
    m.m[14] =  vec3_dot(f, eye);

    return m;
}

Mat4 mat4_mul(Mat4 a, Mat4 b) {
    Mat4 r = {{0}};
    for (int row=0; row<4; ++row)
        for (int col=0; col<4; ++col)
            for (int k=0; k<4; ++k)
                r.m[row + col*4] += a.m[row + k*4] * b.m[k + col*4];
    return r;
}

Mat4 mat4_rotate_y(float angle_rad) {
    Mat4 m = mat4_identity();
    float c = cosf(angle_rad);
    float s = sinf(angle_rad);

    m.m[0] = c;   m.m[2] = s;
    m.m[5] = 1.0f;
    m.m[8] = -s;  m.m[10] = c;
    m.m[15] = 1.0f;

    return m;
}

Mat4 mat4_rotate_x(float angle_rad) {
    Mat4 m = mat4_identity();
    float c = cosf(angle_rad);
    float s = sinf(angle_rad);

    m.m[0] = 1.0f;
    m.m[5] = c;   m.m[6] = -s;
    m.m[9] = s;   m.m[10] = c;
    m.m[15] = 1.0f;

    return m;
}

Mat4 mat4_rotate_z(float angle_rad) {
    Mat4 m = mat4_identity();
    float c = cosf(angle_rad);
    float s = sinf(angle_rad);

    m.m[0] = c;   m.m[1] = -s;
    m.m[4] = s;   m.m[5] = c;
    m.m[10] = 1.0f;
    m.m[15] = 1.0f;

    return m;
}