revolver

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

platform_math.c (18978B)


      1 //////////////////////////////////////////////////////////////////
      2 // platform_math.c
      3 
      4 // range
      5 
      6 RV_GLOBAL s64 rv_range_diff(rv_range range)
      7 {
      8 	return range.max - range.min;
      9 }
     10 
     11 //////////////////////////////////////////////////////////////////
     12 // vector math
     13 
     14 
     15 // vec2
     16 RV_GLOBAL rv_vec2 rv_vec2_neg(rv_vec2 v) {
     17     return rv_vec2_scale(v, -1);
     18 }
     19 RV_GLOBAL rv_vec2 rv_vec2_norm(rv_vec2 v) {
     20     f32 len = rv_vec2_len(v);
     21     return rv_vec2_scale(v, len != 0.f ? 1.0f / rv_vec2_len(v) : 1.f);
     22 }
     23 RV_GLOBAL rv_vec2 rv_vec2_scale(rv_vec2 v, f32 s)
     24 {
     25     return rv_v2(v.x * s, v.y * s);
     26 }
     27 RV_GLOBAL rv_vec2 rv_vec2_add(rv_vec2 a, rv_vec2 b)
     28 {
     29     return rv_v2(a.x + b.x, a.y + b.y);
     30 }
     31 RV_GLOBAL rv_vec2 rv_vec2_sub(rv_vec2 a, rv_vec2 b)
     32 {
     33     return rv_v2(a.x - b.x, a.y - b.y);
     34 }
     35 RV_GLOBAL rv_vec2 rv_vec2_mul(rv_vec2 a, rv_vec2 b)
     36 {
     37     return rv_v2(a.x * b.x, a.y * b.y);
     38 }
     39 RV_GLOBAL rv_vec2 rv_vec2_div(rv_vec2 a, rv_vec2 b)
     40 {
     41     return rv_v2(a.x / b.x, a.y / b.y);
     42 }
     43 RV_GLOBAL rv_vec2 rv_vec2_project_onto(rv_vec2 a, rv_vec2 b)
     44 {
     45     f32 dot = rv_vec2_dot(a, b);
     46     f32 len = rv_vec2_dot(b, b);
     47 
     48     // Orthogonal, so return b
     49     if (len == 0.f) return b;
     50 
     51     return rv_vec2_scale(b, dot / len);
     52 }
     53 
     54 RV_GLOBAL f32 rv_vec2_len(rv_vec2 v)
     55 {
     56     return (f32)sqrtf(rv_vec2_dot(v, v));
     57 }
     58 RV_GLOBAL f32 rv_vec2_dist(rv_vec2 a, rv_vec2 b)
     59 {
     60     f32 dx = (a.x - b.x);
     61     f32 dy = (a.y - b.y);
     62     return (float)(sqrtf(dx * dx + dy * dy));
     63 }
     64 RV_GLOBAL f32 rv_vec2_cross(rv_vec2 a, rv_vec2 b)
     65 {
     66     return a.x * b.y - a.y * b.x;
     67 }
     68 RV_GLOBAL f32 rv_vec2_angle(rv_vec2 a, rv_vec2 b)
     69 {
     70     return (float)acos(rv_vec2_dot(a, b) / (rv_vec2_len(a) * rv_vec2_len(b)));
     71 }
     72 RV_GLOBAL f32 rv_vec2_dot(rv_vec2 a, rv_vec2 b)
     73 {
     74     return (f32)(a.x * b.x + a.y * b.y);
     75 }
     76 
     77 RV_GLOBAL bool32 rv_vec2_nan(rv_vec2 v)
     78 {
     79     if (v.x != v.x || v.y != v.y) return true;
     80     return false;
     81 }
     82 RV_GLOBAL bool32 rv_vec2_eq(rv_vec2 a, rv_vec2 b)
     83 {
     84     return (a.x == b.x && a.y == b.y);
     85 }
     86 
     87 
     88 // vec3
     89 RV_GLOBAL rv_vec3 rv_vec3_neg(rv_vec3 v)
     90 {
     91     return rv_vec3_scale(v, -1.f);
     92 }
     93 RV_GLOBAL rv_vec3 rv_vec3_scale(rv_vec3 v, f32 s)
     94 {
     95     return rv_v3(v.x * s, v.y * s, v.z * s);
     96 }
     97 RV_GLOBAL rv_vec3 rv_vec3_norm(rv_vec3 v)
     98 {
     99     f32 len = rv_vec3_len(v);
    100     return len == 0.f ? v : rv_vec3_scale(v, 1.f / len);
    101 }
    102 RV_GLOBAL rv_vec3 rv_vec3_add(rv_vec3 a, rv_vec3 b)
    103 {
    104     return rv_v3(a.x + b.x, a.y + b.y, a.z + b.z);
    105 }
    106 RV_GLOBAL rv_vec3 rv_vec3_sub(rv_vec3 a, rv_vec3 b)
    107 {
    108     return rv_v3(a.x - b.x, a.y - b.y, a.z - b.z);
    109 }
    110 RV_GLOBAL rv_vec3 rv_vec3_mul(rv_vec3 a, rv_vec3 b)
    111 {
    112     return rv_v3(a.x * b.x, a.y * b.y, a.z * b.z);
    113 }
    114 RV_GLOBAL rv_vec3 rv_vec3_div(rv_vec3 a, rv_vec3 b)
    115 {
    116     return rv_v3(a.x / b.x, a.y / b.y, a.z / b.z);
    117 }
    118 RV_GLOBAL rv_vec3 rv_vec3_project_onto(rv_vec3 a, rv_vec3 b)
    119 {
    120     f32 dot = rv_vec3_dot(a, b);
    121     f32 len = rv_vec3_dot(b, b);
    122 
    123     // Orthogonal, so return b
    124     if (len == 0.f) return b;
    125 
    126     return rv_vec3_scale(b, dot / len);
    127 }
    128 RV_GLOBAL rv_vec3 rv_vec3_cross(rv_vec3 a, rv_vec3 b)
    129 {
    130     return rv_v3
    131     (
    132         a.y * b.z - a.z * b.y,
    133         a.z * b.x - a.x * b.z,
    134         a.x * b.y - a.y * b.x
    135     );
    136 }
    137 
    138 RV_GLOBAL f32 rv_vec3_len(rv_vec3 v)
    139 {
    140     return (f32)sqrt(rv_vec3_dot(v, v));
    141 }
    142 RV_GLOBAL f32 rv_vec3_dist(rv_vec3 a, rv_vec3 b)
    143 {
    144     f32 dx = (a.x - b.x);
    145     f32 dy = (a.y - b.y);
    146     f32 dz = (a.z - b.z);
    147     return sqrtf(dx * dx + dy * dy + dz * dz);
    148 }
    149 RV_GLOBAL f32 rv_vec3_dot(rv_vec3 a, rv_vec3 b)
    150 {
    151     return (f32)((a.x * b.x) + (a.y * b.y) + a.z * b.z);
    152 }
    153 
    154 RV_GLOBAL bool32 rv_vec3_nan(rv_vec3 v)
    155 {
    156     if (v.x != v.x || v.y != v.y || v.z != v.z) return true;
    157     return false;
    158 }
    159 RV_GLOBAL bool32 rv_vec3_eq(rv_vec3 a, rv_vec3 b)
    160 {
    161     return (a.x == b.x && a.y == b.y && a.z == b.z);
    162 }
    163 RV_GLOBAL bool32 rv_vec3_same_dir(rv_vec3 a, rv_vec3 b)
    164 {
    165     return (rv_vec3_dot(a, b) > 0.f);
    166 }
    167 
    168 // vec4
    169 RV_GLOBAL rv_vec4 rv_vec4_neg(rv_vec4 v)
    170 {
    171     return rv_vec4_scale(v, -1);
    172 }
    173 RV_GLOBAL rv_vec4 rv_vec4_scale(rv_vec4 v, f32 s)
    174 {
    175     return rv_v4(v.x * s, v.y * s, v.z * s, v.w * s);
    176 }
    177 RV_GLOBAL rv_vec4 rv_vec4_norm(rv_vec4 v)
    178 {
    179     return rv_vec4_scale(v, 1.0f / rv_vec4_len(v));
    180 }
    181 RV_GLOBAL rv_vec4 rv_vec4_add(rv_vec4 a, rv_vec4 b)
    182 {
    183     return rv_v4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
    184 }
    185 RV_GLOBAL rv_vec4 rv_vec4_sub(rv_vec4 a, rv_vec4 b)
    186 {
    187     return rv_v4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
    188 }
    189 RV_GLOBAL rv_vec4 rv_vec4_mul(rv_vec4 a, rv_vec4 b)
    190 {
    191     return rv_v4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);
    192 }
    193 RV_GLOBAL rv_vec4 rv_vec4_div(rv_vec4 a, rv_vec4 b)
    194 {
    195     return rv_v4(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w);
    196 }
    197 RV_GLOBAL rv_vec4 rv_vec4_project_onto(rv_vec4 a, rv_vec4 b)
    198 {
    199     f32 dot = rv_vec4_dot(a, b);
    200     f32 len = rv_vec4_dot(b, b);
    201 
    202     // Orthogonal, so return b
    203     if (len == 0.f) return b;
    204 
    205     return rv_vec4_scale(b, dot / len);
    206 }
    207 RV_GLOBAL rv_vec4 rv_vec4_from_color(rv_color_t c)
    208 {
    209     return rv_v4((float)c.r / 255.0f, (float)c.g / 255.0f, (float)c.b / 255.0f, (float)c.a / 255.0f);
    210 }
    211 
    212 RV_GLOBAL f32 rv_vec4_len(rv_vec4 v)
    213 {
    214     return (f32)sqrtf(rv_vec4_dot(v, v));
    215 }
    216 RV_GLOBAL f32 rv_vec4_dist(rv_vec4 a, rv_vec4 b)
    217 {
    218     f32 dx = (a.x - b.x);
    219     f32 dy = (a.y - b.y);
    220     f32 dz = (a.z - b.z);
    221     f32 dw = (a.w - b.w);
    222     return (float)(sqrtf(dx * dx + dy * dy + dz * dz + dw * dw));
    223 }
    224 RV_GLOBAL f32 rv_vec4_dot(rv_vec4 a, rv_vec4 b)
    225 {
    226     return (f32)(a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w);
    227 }
    228 
    229 RV_GLOBAL bool32 rv_vec4_nan(rv_vec4 v)
    230 {
    231     if (v.x != v.x || v.y != v.y || v.z != v.z || v.w != v.w) return true;
    232     return false;
    233 }
    234 RV_GLOBAL bool32 rv_vec4_eq(rv_vec4 a, rv_vec4 b)
    235 {
    236     return (a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w);
    237 }
    238 
    239 
    240 //////////////////////////////////////////////////////////////////
    241 // matrix math
    242 
    243 
    244 RV_GLOBAL rv_mat4 rv_mat4_translatev(rv_vec3 v)
    245 {
    246     rv_mat4 m_res = rv_mat4_identity();
    247 
    248     m_res.elements[0 + 4 * 3] = v.x;
    249     m_res.elements[1 + 4 * 3] = v.y;
    250     m_res.elements[2 + 4 * 3] = v.z;
    251 
    252     return m_res;
    253 }
    254 RV_GLOBAL rv_mat4 rv_mat4_rotatev(f32 angle, rv_vec3 axis)
    255 {
    256     rv_mat4 m_res = rv_mat4_identity();
    257 
    258     float a = angle;
    259     float c = (float)cos(a);
    260     float s = (float)sin(a);
    261 
    262     rv_vec3 naxis = rv_vec3_norm(axis);
    263     float x = naxis.x;
    264     float y = naxis.y;
    265     float z = naxis.z;
    266 
    267     //First column
    268     m_res.elements[0 + 0 * 4] = x * x * (1 - c) + c;
    269     m_res.elements[1 + 0 * 4] = x * y * (1 - c) + z * s;
    270     m_res.elements[2 + 0 * 4] = x * z * (1 - c) - y * s;
    271 
    272     //Second column
    273     m_res.elements[0 + 1 * 4] = x * y * (1 - c) - z * s;
    274     m_res.elements[1 + 1 * 4] = y * y * (1 - c) + c;
    275     m_res.elements[2 + 1 * 4] = y * z * (1 - c) + x * s;
    276 
    277     //Third column
    278     m_res.elements[0 + 2 * 4] = x * z * (1 - c) + y * s;
    279     m_res.elements[1 + 2 * 4] = y * z * (1 - c) - x * s;
    280     m_res.elements[2 + 2 * 4] = z * z * (1 - c) + c;
    281 
    282     return m_res;
    283 }
    284 RV_GLOBAL rv_mat4 rv_mat4_scalev(rv_vec3 v)
    285 {
    286     rv_mat4 m_res = rv_mat4_identity();
    287     m_res.elements[0 + 0 * 4] = v.x;
    288     m_res.elements[1 + 1 * 4] = v.y;
    289     m_res.elements[2 + 2 * 4] = v.z;
    290     return m_res;
    291 }
    292 RV_GLOBAL rv_mat4 rv_mat4_transpose(rv_mat4 m)
    293 {
    294     rv_mat4 t = rv_mat4_identity();
    295 
    296     // First row
    297     t.elements[0 * 4 + 0] = m.elements[0 * 4 + 0];
    298     t.elements[1 * 4 + 0] = m.elements[0 * 4 + 1];
    299     t.elements[2 * 4 + 0] = m.elements[0 * 4 + 2];
    300     t.elements[3 * 4 + 0] = m.elements[0 * 4 + 3];
    301 
    302     // Second row
    303     t.elements[0 * 4 + 1] = m.elements[1 * 4 + 0];
    304     t.elements[1 * 4 + 1] = m.elements[1 * 4 + 1];
    305     t.elements[2 * 4 + 1] = m.elements[1 * 4 + 2];
    306     t.elements[3 * 4 + 1] = m.elements[1 * 4 + 3];
    307 
    308     // Third row
    309     t.elements[0 * 4 + 2] = m.elements[2 * 4 + 0];
    310     t.elements[1 * 4 + 2] = m.elements[2 * 4 + 1];
    311     t.elements[2 * 4 + 2] = m.elements[2 * 4 + 2];
    312     t.elements[3 * 4 + 2] = m.elements[2 * 4 + 3];
    313 
    314     // Fourth row
    315     t.elements[0 * 4 + 3] = m.elements[3 * 4 + 0];
    316     t.elements[1 * 4 + 3] = m.elements[3 * 4 + 1];
    317     t.elements[2 * 4 + 3] = m.elements[3 * 4 + 2];
    318     t.elements[3 * 4 + 3] = m.elements[3 * 4 + 3];
    319 
    320     return t;
    321 }
    322 RV_GLOBAL rv_mat4 rv_mat4_inverse(rv_mat4 m)
    323 {
    324     rv_mat4 res = rv_mat4_identity();
    325 
    326     f32 temp[16];
    327 
    328     temp[0] = m.elements[5] * m.elements[10] * m.elements[15] -
    329         m.elements[5] * m.elements[11] * m.elements[14] -
    330         m.elements[9] * m.elements[6] * m.elements[15] +
    331         m.elements[9] * m.elements[7] * m.elements[14] +
    332         m.elements[13] * m.elements[6] * m.elements[11] -
    333         m.elements[13] * m.elements[7] * m.elements[10];
    334 
    335     temp[4] = -m.elements[4] * m.elements[10] * m.elements[15] +
    336         m.elements[4] * m.elements[11] * m.elements[14] +
    337         m.elements[8] * m.elements[6] * m.elements[15] -
    338         m.elements[8] * m.elements[7] * m.elements[14] -
    339         m.elements[12] * m.elements[6] * m.elements[11] +
    340         m.elements[12] * m.elements[7] * m.elements[10];
    341 
    342     temp[8] = m.elements[4] * m.elements[9] * m.elements[15] -
    343         m.elements[4] * m.elements[11] * m.elements[13] -
    344         m.elements[8] * m.elements[5] * m.elements[15] +
    345         m.elements[8] * m.elements[7] * m.elements[13] +
    346         m.elements[12] * m.elements[5] * m.elements[11] -
    347         m.elements[12] * m.elements[7] * m.elements[9];
    348 
    349     temp[12] = -m.elements[4] * m.elements[9] * m.elements[14] +
    350         m.elements[4] * m.elements[10] * m.elements[13] +
    351         m.elements[8] * m.elements[5] * m.elements[14] -
    352         m.elements[8] * m.elements[6] * m.elements[13] -
    353         m.elements[12] * m.elements[5] * m.elements[10] +
    354         m.elements[12] * m.elements[6] * m.elements[9];
    355 
    356     temp[1] = -m.elements[1] * m.elements[10] * m.elements[15] +
    357         m.elements[1] * m.elements[11] * m.elements[14] +
    358         m.elements[9] * m.elements[2] * m.elements[15] -
    359         m.elements[9] * m.elements[3] * m.elements[14] -
    360         m.elements[13] * m.elements[2] * m.elements[11] +
    361         m.elements[13] * m.elements[3] * m.elements[10];
    362 
    363     temp[5] = m.elements[0] * m.elements[10] * m.elements[15] -
    364         m.elements[0] * m.elements[11] * m.elements[14] -
    365         m.elements[8] * m.elements[2] * m.elements[15] +
    366         m.elements[8] * m.elements[3] * m.elements[14] +
    367         m.elements[12] * m.elements[2] * m.elements[11] -
    368         m.elements[12] * m.elements[3] * m.elements[10];
    369 
    370     temp[9] = -m.elements[0] * m.elements[9] * m.elements[15] +
    371         m.elements[0] * m.elements[11] * m.elements[13] +
    372         m.elements[8] * m.elements[1] * m.elements[15] -
    373         m.elements[8] * m.elements[3] * m.elements[13] -
    374         m.elements[12] * m.elements[1] * m.elements[11] +
    375         m.elements[12] * m.elements[3] * m.elements[9];
    376 
    377     temp[13] = m.elements[0] * m.elements[9] * m.elements[14] -
    378         m.elements[0] * m.elements[10] * m.elements[13] -
    379         m.elements[8] * m.elements[1] * m.elements[14] +
    380         m.elements[8] * m.elements[2] * m.elements[13] +
    381         m.elements[12] * m.elements[1] * m.elements[10] -
    382         m.elements[12] * m.elements[2] * m.elements[9];
    383 
    384     temp[2] = m.elements[1] * m.elements[6] * m.elements[15] -
    385         m.elements[1] * m.elements[7] * m.elements[14] -
    386         m.elements[5] * m.elements[2] * m.elements[15] +
    387         m.elements[5] * m.elements[3] * m.elements[14] +
    388         m.elements[13] * m.elements[2] * m.elements[7] -
    389         m.elements[13] * m.elements[3] * m.elements[6];
    390 
    391     temp[6] = -m.elements[0] * m.elements[6] * m.elements[15] +
    392         m.elements[0] * m.elements[7] * m.elements[14] +
    393         m.elements[4] * m.elements[2] * m.elements[15] -
    394         m.elements[4] * m.elements[3] * m.elements[14] -
    395         m.elements[12] * m.elements[2] * m.elements[7] +
    396         m.elements[12] * m.elements[3] * m.elements[6];
    397 
    398     temp[10] = m.elements[0] * m.elements[5] * m.elements[15] -
    399         m.elements[0] * m.elements[7] * m.elements[13] -
    400         m.elements[4] * m.elements[1] * m.elements[15] +
    401         m.elements[4] * m.elements[3] * m.elements[13] +
    402         m.elements[12] * m.elements[1] * m.elements[7] -
    403         m.elements[12] * m.elements[3] * m.elements[5];
    404 
    405     temp[14] = -m.elements[0] * m.elements[5] * m.elements[14] +
    406         m.elements[0] * m.elements[6] * m.elements[13] +
    407         m.elements[4] * m.elements[1] * m.elements[14] -
    408         m.elements[4] * m.elements[2] * m.elements[13] -
    409         m.elements[12] * m.elements[1] * m.elements[6] +
    410         m.elements[12] * m.elements[2] * m.elements[5];
    411 
    412     temp[3] = -m.elements[1] * m.elements[6] * m.elements[11] +
    413         m.elements[1] * m.elements[7] * m.elements[10] +
    414         m.elements[5] * m.elements[2] * m.elements[11] -
    415         m.elements[5] * m.elements[3] * m.elements[10] -
    416         m.elements[9] * m.elements[2] * m.elements[7] +
    417         m.elements[9] * m.elements[3] * m.elements[6];
    418 
    419     temp[7] = m.elements[0] * m.elements[6] * m.elements[11] -
    420         m.elements[0] * m.elements[7] * m.elements[10] -
    421         m.elements[4] * m.elements[2] * m.elements[11] +
    422         m.elements[4] * m.elements[3] * m.elements[10] +
    423         m.elements[8] * m.elements[2] * m.elements[7] -
    424         m.elements[8] * m.elements[3] * m.elements[6];
    425 
    426     temp[11] = -m.elements[0] * m.elements[5] * m.elements[11] +
    427         m.elements[0] * m.elements[7] * m.elements[9] +
    428         m.elements[4] * m.elements[1] * m.elements[11] -
    429         m.elements[4] * m.elements[3] * m.elements[9] -
    430         m.elements[8] * m.elements[1] * m.elements[7] +
    431         m.elements[8] * m.elements[3] * m.elements[5];
    432 
    433     temp[15] = m.elements[0] * m.elements[5] * m.elements[10] -
    434         m.elements[0] * m.elements[6] * m.elements[9] -
    435         m.elements[4] * m.elements[1] * m.elements[10] +
    436         m.elements[4] * m.elements[2] * m.elements[9] +
    437         m.elements[8] * m.elements[1] * m.elements[6] -
    438         m.elements[8] * m.elements[2] * m.elements[5];
    439 
    440     float determinant = m.elements[0] * temp[0] + m.elements[1] * temp[4] + m.elements[2] * temp[8] + m.elements[3] * temp[12];
    441     determinant = 1.0f / determinant;
    442 
    443     for (int i = 0; i < 4 * 4; i++)
    444         res.elements[i] = (float)(temp[i] * (float)determinant);
    445 
    446     return res;
    447 }
    448 RV_GLOBAL rv_mat4 rv_mat4_look_at(rv_vec3 position, rv_vec3 target, rv_vec3 up)
    449 {
    450     rv_vec3 f = rv_vec3_norm(rv_vec3_sub(target, position));
    451     rv_vec3 s = rv_vec3_norm(rv_vec3_cross(f, up));
    452     rv_vec3 u = rv_vec3_cross(s, f);
    453 
    454     rv_mat4 m_res = rv_mat4_identity();
    455     m_res.elements[0 * 4 + 0] = s.x;
    456     m_res.elements[1 * 4 + 0] = s.y;
    457     m_res.elements[2 * 4 + 0] = s.z;
    458 
    459     m_res.elements[0 * 4 + 1] = u.x;
    460     m_res.elements[1 * 4 + 1] = u.y;
    461     m_res.elements[2 * 4 + 1] = u.z;
    462 
    463     m_res.elements[0 * 4 + 2] = -f.x;
    464     m_res.elements[1 * 4 + 2] = -f.y;
    465     m_res.elements[2 * 4 + 2] = -f.z;
    466 
    467     m_res.elements[3 * 4 + 0] = -rv_vec3_dot(s, position);;
    468     m_res.elements[3 * 4 + 1] = -rv_vec3_dot(u, position);
    469     m_res.elements[3 * 4 + 2] = rv_vec3_dot(f, position);
    470 
    471     return m_res;
    472 }
    473 
    474 RV_GLOBAL rv_mat4 rv_mat4_mul(rv_mat4 m0, rv_mat4 m1)
    475 {
    476     rv_mat4 m_res = {0};
    477     for (u32 y = 0; y < 4; ++y) {
    478         for (u32 x = 0; x < 4; ++x) {
    479             f32 sum = 0.0f;
    480             for (u32 e = 0; e < 4; ++e) {
    481                 sum += m0.elements[x + e * 4] * m1.elements[e + y * 4];
    482             }
    483             m_res.elements[x + y * 4] = sum;
    484         }
    485     }
    486 
    487     return m_res;
    488 }
    489 RV_GLOBAL rv_mat4 rv_mat4_mul_list_(rv_mat4* m_list, s64 m_list_len)
    490 {
    491     va_list ap;
    492     rv_mat4 m = rv_mat4_identity();
    493     for (uint32_t i = 0; i < m_list_len; ++i) {
    494         m = rv_mat4_mul(m, m_list[i]);
    495     }
    496     return m;
    497 }
    498 RV_GLOBAL rv_vec4 rv_mat4_mul_vec4(rv_mat4 m, rv_vec4 v)
    499 {
    500     return rv_v4
    501     (
    502         m.elements[0 + 4 * 0] * v.x + m.elements[0 + 4 * 1] * v.y + m.elements[0 + 4 * 2] * v.z + m.elements[0 + 4 * 3] * v.w,
    503         m.elements[1 + 4 * 0] * v.x + m.elements[1 + 4 * 1] * v.y + m.elements[1 + 4 * 2] * v.z + m.elements[1 + 4 * 3] * v.w,
    504         m.elements[2 + 4 * 0] * v.x + m.elements[2 + 4 * 1] * v.y + m.elements[2 + 4 * 2] * v.z + m.elements[2 + 4 * 3] * v.w,
    505         m.elements[3 + 4 * 0] * v.x + m.elements[3 + 4 * 1] * v.y + m.elements[3 + 4 * 2] * v.z + m.elements[3 + 4 * 3] * v.w
    506     );
    507 }
    508 RV_GLOBAL rv_vec3 rv_mat4_mul_vec3(rv_mat4 m, rv_vec3 v)
    509 {
    510     return rv_mat4_mul_vec4(m, rv_v4(.xyz = v, .w = 1.f)).xyz;
    511 }
    512 
    513 RV_GLOBAL rv_mat4 rv_mat4_ortho_norm(rv_mat4 m)
    514 {
    515     m.v.right = rv_vec4_norm(m.v.right);
    516     m.v.up = rv_vec4_norm(m.v.up);
    517     m.v.dir = rv_vec4_norm(m.v.dir);
    518     return m;
    519 }
    520 RV_GLOBAL rv_mat4 rv_mat4_ortho(f32 l, f32 r, f32 b, f32 t, f32 n, f32 f)
    521 {
    522     rv_mat4 m_res = rv_mat4_identity();
    523 
    524     // Main diagonal
    525     m_res.elements[0 + 0 * 4] = 2.0f / (r - l);
    526     m_res.elements[1 + 1 * 4] = 2.0f / (t - b);
    527     m_res.elements[2 + 2 * 4] = -2.0f / (f - n);
    528 
    529     // Last column
    530     m_res.elements[0 + 3 * 4] = -(r + l) / (r - l);
    531     m_res.elements[1 + 3 * 4] = -(t + b) / (t - b);
    532     m_res.elements[2 + 3 * 4] = -(f + n) / (f - n);
    533 
    534     return m_res;
    535 }
    536 RV_GLOBAL rv_mat4 rv_mat4_perspective(f32 fov, f32 asp_ratio, f32 n, f32 f)
    537 {
    538     // Zero matrix
    539     rv_mat4 m_res = {0};
    540 
    541     f32 q = 1.0f / (float)tan(rv_deg2rad(0.5f * fov));
    542     f32 a = q / asp_ratio;
    543     f32 b = (n + f) / (n - f);
    544     f32 c = (2.0f * n * f) / (n - f);
    545 
    546     m_res.elements[0 + 0 * 4] = a;
    547     m_res.elements[1 + 1 * 4] = q;
    548     m_res.elements[2 + 2 * 4] = b;
    549     m_res.elements[2 + 3 * 4] = c;
    550     m_res.elements[3 + 2 * 4] = -1.0f;
    551 
    552     return m_res;
    553 }
    554 
    555 RV_GLOBAL void rv_mat4_decompose(const rv_mat4* m, rv_vec3* translation, rv_vec3* rotation, rv_vec3* scale)
    556 {
    557     rv_mat4 mat = *m;
    558 
    559     scale->xyz[0] = rv_vec4_len(mat.v.right);
    560     scale->xyz[1] = rv_vec4_len(mat.v.up);
    561     scale->xyz[2] = rv_vec4_len(mat.v.dir);
    562 
    563     mat = rv_mat4_ortho_norm(mat);
    564 
    565     rotation->xyz[0] = rv_rad2deg(atan2f(mat.m[1][2], mat.m[2][2]));
    566     rotation->xyz[1] = rv_rad2deg(atan2f(-mat.m[0][2], sqrtf(mat.m[1][2] * mat.m[1][2] +
    567                 mat.m[2][2] * mat.m[2][2])));
    568     rotation->xyz[2] = rv_rad2deg(atan2f(mat.m[0][1], mat.m[0][0]));
    569 
    570     translation->xyz[0] = mat.v.position.x;
    571     translation->xyz[1] = mat.v.position.y;
    572     translation->xyz[2] = mat.v.position.z;
    573 }
    574 RV_GLOBAL rv_mat4 rv_mat4_recompose(rv_vec3 translation, rv_vec3 rotation, rv_vec3 scale)
    575 {
    576     rv_mat4 mat = rv_mat4_identity();
    577 
    578     rv_vec3 direction_unary[3] = {
    579         RV_XAXIS,
    580         RV_YAXIS,
    581         RV_ZAXIS
    582     };
    583 
    584     rv_mat4 rot[3] = {rv_mat4_identity(), rv_mat4_identity(), rv_mat4_identity()};
    585     for (uint32_t i = 0; i < 3; ++i) {
    586         rot[i] = rv_mat4_rotatev(rv_deg2rad(rotation.xyz[i]), direction_unary[i]);
    587     }
    588 
    589     mat = rv_mat4_mul_list(rot[2], rot[1], rot[0]);
    590 
    591     float valid_scale[3] = {0};
    592     for (uint32_t i = 0; i < 3; ++i) {
    593         valid_scale[i] = fabsf(scale.xyz[i]) < RV_EPSILON ? 0.001f : scale.xyz[i];
    594     }
    595 
    596     mat.v.right = rv_vec4_scale(mat.v.right, valid_scale[0]);
    597     mat.v.up = rv_vec4_scale(mat.v.up, valid_scale[1]);
    598     mat.v.dir = rv_vec4_scale(mat.v.dir, valid_scale[2]);
    599     mat.v.position = rv_v4(translation.xyz[0], translation.xyz[1], translation.xyz[2], 1.f);
    600 
    601     return mat;
    602 }