1b877906bSopenharmony_ci#ifndef LINMATH_H 2b877906bSopenharmony_ci#define LINMATH_H 3b877906bSopenharmony_ci 4b877906bSopenharmony_ci#include <string.h> 5b877906bSopenharmony_ci#include <math.h> 6b877906bSopenharmony_ci#include <string.h> 7b877906bSopenharmony_ci 8b877906bSopenharmony_ci/* 2021-03-21 Camilla Löwy <elmindreda@elmindreda.org> 9b877906bSopenharmony_ci * - Replaced double constants with float equivalents 10b877906bSopenharmony_ci */ 11b877906bSopenharmony_ci 12b877906bSopenharmony_ci#ifdef LINMATH_NO_INLINE 13b877906bSopenharmony_ci#define LINMATH_H_FUNC static 14b877906bSopenharmony_ci#else 15b877906bSopenharmony_ci#define LINMATH_H_FUNC static inline 16b877906bSopenharmony_ci#endif 17b877906bSopenharmony_ci 18b877906bSopenharmony_ci#define LINMATH_H_DEFINE_VEC(n) \ 19b877906bSopenharmony_citypedef float vec##n[n]; \ 20b877906bSopenharmony_ciLINMATH_H_FUNC void vec##n##_add(vec##n r, vec##n const a, vec##n const b) \ 21b877906bSopenharmony_ci{ \ 22b877906bSopenharmony_ci int i; \ 23b877906bSopenharmony_ci for(i=0; i<n; ++i) \ 24b877906bSopenharmony_ci r[i] = a[i] + b[i]; \ 25b877906bSopenharmony_ci} \ 26b877906bSopenharmony_ciLINMATH_H_FUNC void vec##n##_sub(vec##n r, vec##n const a, vec##n const b) \ 27b877906bSopenharmony_ci{ \ 28b877906bSopenharmony_ci int i; \ 29b877906bSopenharmony_ci for(i=0; i<n; ++i) \ 30b877906bSopenharmony_ci r[i] = a[i] - b[i]; \ 31b877906bSopenharmony_ci} \ 32b877906bSopenharmony_ciLINMATH_H_FUNC void vec##n##_scale(vec##n r, vec##n const v, float const s) \ 33b877906bSopenharmony_ci{ \ 34b877906bSopenharmony_ci int i; \ 35b877906bSopenharmony_ci for(i=0; i<n; ++i) \ 36b877906bSopenharmony_ci r[i] = v[i] * s; \ 37b877906bSopenharmony_ci} \ 38b877906bSopenharmony_ciLINMATH_H_FUNC float vec##n##_mul_inner(vec##n const a, vec##n const b) \ 39b877906bSopenharmony_ci{ \ 40b877906bSopenharmony_ci float p = 0.f; \ 41b877906bSopenharmony_ci int i; \ 42b877906bSopenharmony_ci for(i=0; i<n; ++i) \ 43b877906bSopenharmony_ci p += b[i]*a[i]; \ 44b877906bSopenharmony_ci return p; \ 45b877906bSopenharmony_ci} \ 46b877906bSopenharmony_ciLINMATH_H_FUNC float vec##n##_len(vec##n const v) \ 47b877906bSopenharmony_ci{ \ 48b877906bSopenharmony_ci return sqrtf(vec##n##_mul_inner(v,v)); \ 49b877906bSopenharmony_ci} \ 50b877906bSopenharmony_ciLINMATH_H_FUNC void vec##n##_norm(vec##n r, vec##n const v) \ 51b877906bSopenharmony_ci{ \ 52b877906bSopenharmony_ci float k = 1.f / vec##n##_len(v); \ 53b877906bSopenharmony_ci vec##n##_scale(r, v, k); \ 54b877906bSopenharmony_ci} \ 55b877906bSopenharmony_ciLINMATH_H_FUNC void vec##n##_min(vec##n r, vec##n const a, vec##n const b) \ 56b877906bSopenharmony_ci{ \ 57b877906bSopenharmony_ci int i; \ 58b877906bSopenharmony_ci for(i=0; i<n; ++i) \ 59b877906bSopenharmony_ci r[i] = a[i]<b[i] ? a[i] : b[i]; \ 60b877906bSopenharmony_ci} \ 61b877906bSopenharmony_ciLINMATH_H_FUNC void vec##n##_max(vec##n r, vec##n const a, vec##n const b) \ 62b877906bSopenharmony_ci{ \ 63b877906bSopenharmony_ci int i; \ 64b877906bSopenharmony_ci for(i=0; i<n; ++i) \ 65b877906bSopenharmony_ci r[i] = a[i]>b[i] ? a[i] : b[i]; \ 66b877906bSopenharmony_ci} \ 67b877906bSopenharmony_ciLINMATH_H_FUNC void vec##n##_dup(vec##n r, vec##n const src) \ 68b877906bSopenharmony_ci{ \ 69b877906bSopenharmony_ci int i; \ 70b877906bSopenharmony_ci for(i=0; i<n; ++i) \ 71b877906bSopenharmony_ci r[i] = src[i]; \ 72b877906bSopenharmony_ci} 73b877906bSopenharmony_ci 74b877906bSopenharmony_ciLINMATH_H_DEFINE_VEC(2) 75b877906bSopenharmony_ciLINMATH_H_DEFINE_VEC(3) 76b877906bSopenharmony_ciLINMATH_H_DEFINE_VEC(4) 77b877906bSopenharmony_ci 78b877906bSopenharmony_ciLINMATH_H_FUNC void vec3_mul_cross(vec3 r, vec3 const a, vec3 const b) 79b877906bSopenharmony_ci{ 80b877906bSopenharmony_ci r[0] = a[1]*b[2] - a[2]*b[1]; 81b877906bSopenharmony_ci r[1] = a[2]*b[0] - a[0]*b[2]; 82b877906bSopenharmony_ci r[2] = a[0]*b[1] - a[1]*b[0]; 83b877906bSopenharmony_ci} 84b877906bSopenharmony_ci 85b877906bSopenharmony_ciLINMATH_H_FUNC void vec3_reflect(vec3 r, vec3 const v, vec3 const n) 86b877906bSopenharmony_ci{ 87b877906bSopenharmony_ci float p = 2.f * vec3_mul_inner(v, n); 88b877906bSopenharmony_ci int i; 89b877906bSopenharmony_ci for(i=0;i<3;++i) 90b877906bSopenharmony_ci r[i] = v[i] - p*n[i]; 91b877906bSopenharmony_ci} 92b877906bSopenharmony_ci 93b877906bSopenharmony_ciLINMATH_H_FUNC void vec4_mul_cross(vec4 r, vec4 const a, vec4 const b) 94b877906bSopenharmony_ci{ 95b877906bSopenharmony_ci r[0] = a[1]*b[2] - a[2]*b[1]; 96b877906bSopenharmony_ci r[1] = a[2]*b[0] - a[0]*b[2]; 97b877906bSopenharmony_ci r[2] = a[0]*b[1] - a[1]*b[0]; 98b877906bSopenharmony_ci r[3] = 1.f; 99b877906bSopenharmony_ci} 100b877906bSopenharmony_ci 101b877906bSopenharmony_ciLINMATH_H_FUNC void vec4_reflect(vec4 r, vec4 const v, vec4 const n) 102b877906bSopenharmony_ci{ 103b877906bSopenharmony_ci float p = 2.f*vec4_mul_inner(v, n); 104b877906bSopenharmony_ci int i; 105b877906bSopenharmony_ci for(i=0;i<4;++i) 106b877906bSopenharmony_ci r[i] = v[i] - p*n[i]; 107b877906bSopenharmony_ci} 108b877906bSopenharmony_ci 109b877906bSopenharmony_citypedef vec4 mat4x4[4]; 110b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_identity(mat4x4 M) 111b877906bSopenharmony_ci{ 112b877906bSopenharmony_ci int i, j; 113b877906bSopenharmony_ci for(i=0; i<4; ++i) 114b877906bSopenharmony_ci for(j=0; j<4; ++j) 115b877906bSopenharmony_ci M[i][j] = i==j ? 1.f : 0.f; 116b877906bSopenharmony_ci} 117b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_dup(mat4x4 M, mat4x4 const N) 118b877906bSopenharmony_ci{ 119b877906bSopenharmony_ci int i; 120b877906bSopenharmony_ci for(i=0; i<4; ++i) 121b877906bSopenharmony_ci vec4_dup(M[i], N[i]); 122b877906bSopenharmony_ci} 123b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_row(vec4 r, mat4x4 const M, int i) 124b877906bSopenharmony_ci{ 125b877906bSopenharmony_ci int k; 126b877906bSopenharmony_ci for(k=0; k<4; ++k) 127b877906bSopenharmony_ci r[k] = M[k][i]; 128b877906bSopenharmony_ci} 129b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_col(vec4 r, mat4x4 const M, int i) 130b877906bSopenharmony_ci{ 131b877906bSopenharmony_ci int k; 132b877906bSopenharmony_ci for(k=0; k<4; ++k) 133b877906bSopenharmony_ci r[k] = M[i][k]; 134b877906bSopenharmony_ci} 135b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_transpose(mat4x4 M, mat4x4 const N) 136b877906bSopenharmony_ci{ 137b877906bSopenharmony_ci // Note: if M and N are the same, the user has to 138b877906bSopenharmony_ci // explicitly make a copy of M and set it to N. 139b877906bSopenharmony_ci int i, j; 140b877906bSopenharmony_ci for(j=0; j<4; ++j) 141b877906bSopenharmony_ci for(i=0; i<4; ++i) 142b877906bSopenharmony_ci M[i][j] = N[j][i]; 143b877906bSopenharmony_ci} 144b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_add(mat4x4 M, mat4x4 const a, mat4x4 const b) 145b877906bSopenharmony_ci{ 146b877906bSopenharmony_ci int i; 147b877906bSopenharmony_ci for(i=0; i<4; ++i) 148b877906bSopenharmony_ci vec4_add(M[i], a[i], b[i]); 149b877906bSopenharmony_ci} 150b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_sub(mat4x4 M, mat4x4 const a, mat4x4 const b) 151b877906bSopenharmony_ci{ 152b877906bSopenharmony_ci int i; 153b877906bSopenharmony_ci for(i=0; i<4; ++i) 154b877906bSopenharmony_ci vec4_sub(M[i], a[i], b[i]); 155b877906bSopenharmony_ci} 156b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_scale(mat4x4 M, mat4x4 const a, float k) 157b877906bSopenharmony_ci{ 158b877906bSopenharmony_ci int i; 159b877906bSopenharmony_ci for(i=0; i<4; ++i) 160b877906bSopenharmony_ci vec4_scale(M[i], a[i], k); 161b877906bSopenharmony_ci} 162b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_scale_aniso(mat4x4 M, mat4x4 const a, float x, float y, float z) 163b877906bSopenharmony_ci{ 164b877906bSopenharmony_ci vec4_scale(M[0], a[0], x); 165b877906bSopenharmony_ci vec4_scale(M[1], a[1], y); 166b877906bSopenharmony_ci vec4_scale(M[2], a[2], z); 167b877906bSopenharmony_ci vec4_dup(M[3], a[3]); 168b877906bSopenharmony_ci} 169b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_mul(mat4x4 M, mat4x4 const a, mat4x4 const b) 170b877906bSopenharmony_ci{ 171b877906bSopenharmony_ci mat4x4 temp; 172b877906bSopenharmony_ci int k, r, c; 173b877906bSopenharmony_ci for(c=0; c<4; ++c) for(r=0; r<4; ++r) { 174b877906bSopenharmony_ci temp[c][r] = 0.f; 175b877906bSopenharmony_ci for(k=0; k<4; ++k) 176b877906bSopenharmony_ci temp[c][r] += a[k][r] * b[c][k]; 177b877906bSopenharmony_ci } 178b877906bSopenharmony_ci mat4x4_dup(M, temp); 179b877906bSopenharmony_ci} 180b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_mul_vec4(vec4 r, mat4x4 const M, vec4 const v) 181b877906bSopenharmony_ci{ 182b877906bSopenharmony_ci int i, j; 183b877906bSopenharmony_ci for(j=0; j<4; ++j) { 184b877906bSopenharmony_ci r[j] = 0.f; 185b877906bSopenharmony_ci for(i=0; i<4; ++i) 186b877906bSopenharmony_ci r[j] += M[i][j] * v[i]; 187b877906bSopenharmony_ci } 188b877906bSopenharmony_ci} 189b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_translate(mat4x4 T, float x, float y, float z) 190b877906bSopenharmony_ci{ 191b877906bSopenharmony_ci mat4x4_identity(T); 192b877906bSopenharmony_ci T[3][0] = x; 193b877906bSopenharmony_ci T[3][1] = y; 194b877906bSopenharmony_ci T[3][2] = z; 195b877906bSopenharmony_ci} 196b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_translate_in_place(mat4x4 M, float x, float y, float z) 197b877906bSopenharmony_ci{ 198b877906bSopenharmony_ci vec4 t = {x, y, z, 0}; 199b877906bSopenharmony_ci vec4 r; 200b877906bSopenharmony_ci int i; 201b877906bSopenharmony_ci for (i = 0; i < 4; ++i) { 202b877906bSopenharmony_ci mat4x4_row(r, M, i); 203b877906bSopenharmony_ci M[3][i] += vec4_mul_inner(r, t); 204b877906bSopenharmony_ci } 205b877906bSopenharmony_ci} 206b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_from_vec3_mul_outer(mat4x4 M, vec3 const a, vec3 const b) 207b877906bSopenharmony_ci{ 208b877906bSopenharmony_ci int i, j; 209b877906bSopenharmony_ci for(i=0; i<4; ++i) for(j=0; j<4; ++j) 210b877906bSopenharmony_ci M[i][j] = i<3 && j<3 ? a[i] * b[j] : 0.f; 211b877906bSopenharmony_ci} 212b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_rotate(mat4x4 R, mat4x4 const M, float x, float y, float z, float angle) 213b877906bSopenharmony_ci{ 214b877906bSopenharmony_ci float s = sinf(angle); 215b877906bSopenharmony_ci float c = cosf(angle); 216b877906bSopenharmony_ci vec3 u = {x, y, z}; 217b877906bSopenharmony_ci 218b877906bSopenharmony_ci if(vec3_len(u) > 1e-4) { 219b877906bSopenharmony_ci vec3_norm(u, u); 220b877906bSopenharmony_ci mat4x4 T; 221b877906bSopenharmony_ci mat4x4_from_vec3_mul_outer(T, u, u); 222b877906bSopenharmony_ci 223b877906bSopenharmony_ci mat4x4 S = { 224b877906bSopenharmony_ci { 0, u[2], -u[1], 0}, 225b877906bSopenharmony_ci {-u[2], 0, u[0], 0}, 226b877906bSopenharmony_ci { u[1], -u[0], 0, 0}, 227b877906bSopenharmony_ci { 0, 0, 0, 0} 228b877906bSopenharmony_ci }; 229b877906bSopenharmony_ci mat4x4_scale(S, S, s); 230b877906bSopenharmony_ci 231b877906bSopenharmony_ci mat4x4 C; 232b877906bSopenharmony_ci mat4x4_identity(C); 233b877906bSopenharmony_ci mat4x4_sub(C, C, T); 234b877906bSopenharmony_ci 235b877906bSopenharmony_ci mat4x4_scale(C, C, c); 236b877906bSopenharmony_ci 237b877906bSopenharmony_ci mat4x4_add(T, T, C); 238b877906bSopenharmony_ci mat4x4_add(T, T, S); 239b877906bSopenharmony_ci 240b877906bSopenharmony_ci T[3][3] = 1.f; 241b877906bSopenharmony_ci mat4x4_mul(R, M, T); 242b877906bSopenharmony_ci } else { 243b877906bSopenharmony_ci mat4x4_dup(R, M); 244b877906bSopenharmony_ci } 245b877906bSopenharmony_ci} 246b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_rotate_X(mat4x4 Q, mat4x4 const M, float angle) 247b877906bSopenharmony_ci{ 248b877906bSopenharmony_ci float s = sinf(angle); 249b877906bSopenharmony_ci float c = cosf(angle); 250b877906bSopenharmony_ci mat4x4 R = { 251b877906bSopenharmony_ci {1.f, 0.f, 0.f, 0.f}, 252b877906bSopenharmony_ci {0.f, c, s, 0.f}, 253b877906bSopenharmony_ci {0.f, -s, c, 0.f}, 254b877906bSopenharmony_ci {0.f, 0.f, 0.f, 1.f} 255b877906bSopenharmony_ci }; 256b877906bSopenharmony_ci mat4x4_mul(Q, M, R); 257b877906bSopenharmony_ci} 258b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_rotate_Y(mat4x4 Q, mat4x4 const M, float angle) 259b877906bSopenharmony_ci{ 260b877906bSopenharmony_ci float s = sinf(angle); 261b877906bSopenharmony_ci float c = cosf(angle); 262b877906bSopenharmony_ci mat4x4 R = { 263b877906bSopenharmony_ci { c, 0.f, -s, 0.f}, 264b877906bSopenharmony_ci { 0.f, 1.f, 0.f, 0.f}, 265b877906bSopenharmony_ci { s, 0.f, c, 0.f}, 266b877906bSopenharmony_ci { 0.f, 0.f, 0.f, 1.f} 267b877906bSopenharmony_ci }; 268b877906bSopenharmony_ci mat4x4_mul(Q, M, R); 269b877906bSopenharmony_ci} 270b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_rotate_Z(mat4x4 Q, mat4x4 const M, float angle) 271b877906bSopenharmony_ci{ 272b877906bSopenharmony_ci float s = sinf(angle); 273b877906bSopenharmony_ci float c = cosf(angle); 274b877906bSopenharmony_ci mat4x4 R = { 275b877906bSopenharmony_ci { c, s, 0.f, 0.f}, 276b877906bSopenharmony_ci { -s, c, 0.f, 0.f}, 277b877906bSopenharmony_ci { 0.f, 0.f, 1.f, 0.f}, 278b877906bSopenharmony_ci { 0.f, 0.f, 0.f, 1.f} 279b877906bSopenharmony_ci }; 280b877906bSopenharmony_ci mat4x4_mul(Q, M, R); 281b877906bSopenharmony_ci} 282b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_invert(mat4x4 T, mat4x4 const M) 283b877906bSopenharmony_ci{ 284b877906bSopenharmony_ci float s[6]; 285b877906bSopenharmony_ci float c[6]; 286b877906bSopenharmony_ci s[0] = M[0][0]*M[1][1] - M[1][0]*M[0][1]; 287b877906bSopenharmony_ci s[1] = M[0][0]*M[1][2] - M[1][0]*M[0][2]; 288b877906bSopenharmony_ci s[2] = M[0][0]*M[1][3] - M[1][0]*M[0][3]; 289b877906bSopenharmony_ci s[3] = M[0][1]*M[1][2] - M[1][1]*M[0][2]; 290b877906bSopenharmony_ci s[4] = M[0][1]*M[1][3] - M[1][1]*M[0][3]; 291b877906bSopenharmony_ci s[5] = M[0][2]*M[1][3] - M[1][2]*M[0][3]; 292b877906bSopenharmony_ci 293b877906bSopenharmony_ci c[0] = M[2][0]*M[3][1] - M[3][0]*M[2][1]; 294b877906bSopenharmony_ci c[1] = M[2][0]*M[3][2] - M[3][0]*M[2][2]; 295b877906bSopenharmony_ci c[2] = M[2][0]*M[3][3] - M[3][0]*M[2][3]; 296b877906bSopenharmony_ci c[3] = M[2][1]*M[3][2] - M[3][1]*M[2][2]; 297b877906bSopenharmony_ci c[4] = M[2][1]*M[3][3] - M[3][1]*M[2][3]; 298b877906bSopenharmony_ci c[5] = M[2][2]*M[3][3] - M[3][2]*M[2][3]; 299b877906bSopenharmony_ci 300b877906bSopenharmony_ci /* Assumes it is invertible */ 301b877906bSopenharmony_ci float idet = 1.0f/( s[0]*c[5]-s[1]*c[4]+s[2]*c[3]+s[3]*c[2]-s[4]*c[1]+s[5]*c[0] ); 302b877906bSopenharmony_ci 303b877906bSopenharmony_ci T[0][0] = ( M[1][1] * c[5] - M[1][2] * c[4] + M[1][3] * c[3]) * idet; 304b877906bSopenharmony_ci T[0][1] = (-M[0][1] * c[5] + M[0][2] * c[4] - M[0][3] * c[3]) * idet; 305b877906bSopenharmony_ci T[0][2] = ( M[3][1] * s[5] - M[3][2] * s[4] + M[3][3] * s[3]) * idet; 306b877906bSopenharmony_ci T[0][3] = (-M[2][1] * s[5] + M[2][2] * s[4] - M[2][3] * s[3]) * idet; 307b877906bSopenharmony_ci 308b877906bSopenharmony_ci T[1][0] = (-M[1][0] * c[5] + M[1][2] * c[2] - M[1][3] * c[1]) * idet; 309b877906bSopenharmony_ci T[1][1] = ( M[0][0] * c[5] - M[0][2] * c[2] + M[0][3] * c[1]) * idet; 310b877906bSopenharmony_ci T[1][2] = (-M[3][0] * s[5] + M[3][2] * s[2] - M[3][3] * s[1]) * idet; 311b877906bSopenharmony_ci T[1][3] = ( M[2][0] * s[5] - M[2][2] * s[2] + M[2][3] * s[1]) * idet; 312b877906bSopenharmony_ci 313b877906bSopenharmony_ci T[2][0] = ( M[1][0] * c[4] - M[1][1] * c[2] + M[1][3] * c[0]) * idet; 314b877906bSopenharmony_ci T[2][1] = (-M[0][0] * c[4] + M[0][1] * c[2] - M[0][3] * c[0]) * idet; 315b877906bSopenharmony_ci T[2][2] = ( M[3][0] * s[4] - M[3][1] * s[2] + M[3][3] * s[0]) * idet; 316b877906bSopenharmony_ci T[2][3] = (-M[2][0] * s[4] + M[2][1] * s[2] - M[2][3] * s[0]) * idet; 317b877906bSopenharmony_ci 318b877906bSopenharmony_ci T[3][0] = (-M[1][0] * c[3] + M[1][1] * c[1] - M[1][2] * c[0]) * idet; 319b877906bSopenharmony_ci T[3][1] = ( M[0][0] * c[3] - M[0][1] * c[1] + M[0][2] * c[0]) * idet; 320b877906bSopenharmony_ci T[3][2] = (-M[3][0] * s[3] + M[3][1] * s[1] - M[3][2] * s[0]) * idet; 321b877906bSopenharmony_ci T[3][3] = ( M[2][0] * s[3] - M[2][1] * s[1] + M[2][2] * s[0]) * idet; 322b877906bSopenharmony_ci} 323b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_orthonormalize(mat4x4 R, mat4x4 const M) 324b877906bSopenharmony_ci{ 325b877906bSopenharmony_ci mat4x4_dup(R, M); 326b877906bSopenharmony_ci float s = 1.f; 327b877906bSopenharmony_ci vec3 h; 328b877906bSopenharmony_ci 329b877906bSopenharmony_ci vec3_norm(R[2], R[2]); 330b877906bSopenharmony_ci 331b877906bSopenharmony_ci s = vec3_mul_inner(R[1], R[2]); 332b877906bSopenharmony_ci vec3_scale(h, R[2], s); 333b877906bSopenharmony_ci vec3_sub(R[1], R[1], h); 334b877906bSopenharmony_ci vec3_norm(R[1], R[1]); 335b877906bSopenharmony_ci 336b877906bSopenharmony_ci s = vec3_mul_inner(R[0], R[2]); 337b877906bSopenharmony_ci vec3_scale(h, R[2], s); 338b877906bSopenharmony_ci vec3_sub(R[0], R[0], h); 339b877906bSopenharmony_ci 340b877906bSopenharmony_ci s = vec3_mul_inner(R[0], R[1]); 341b877906bSopenharmony_ci vec3_scale(h, R[1], s); 342b877906bSopenharmony_ci vec3_sub(R[0], R[0], h); 343b877906bSopenharmony_ci vec3_norm(R[0], R[0]); 344b877906bSopenharmony_ci} 345b877906bSopenharmony_ci 346b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_frustum(mat4x4 M, float l, float r, float b, float t, float n, float f) 347b877906bSopenharmony_ci{ 348b877906bSopenharmony_ci M[0][0] = 2.f*n/(r-l); 349b877906bSopenharmony_ci M[0][1] = M[0][2] = M[0][3] = 0.f; 350b877906bSopenharmony_ci 351b877906bSopenharmony_ci M[1][1] = 2.f*n/(t-b); 352b877906bSopenharmony_ci M[1][0] = M[1][2] = M[1][3] = 0.f; 353b877906bSopenharmony_ci 354b877906bSopenharmony_ci M[2][0] = (r+l)/(r-l); 355b877906bSopenharmony_ci M[2][1] = (t+b)/(t-b); 356b877906bSopenharmony_ci M[2][2] = -(f+n)/(f-n); 357b877906bSopenharmony_ci M[2][3] = -1.f; 358b877906bSopenharmony_ci 359b877906bSopenharmony_ci M[3][2] = -2.f*(f*n)/(f-n); 360b877906bSopenharmony_ci M[3][0] = M[3][1] = M[3][3] = 0.f; 361b877906bSopenharmony_ci} 362b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_ortho(mat4x4 M, float l, float r, float b, float t, float n, float f) 363b877906bSopenharmony_ci{ 364b877906bSopenharmony_ci M[0][0] = 2.f/(r-l); 365b877906bSopenharmony_ci M[0][1] = M[0][2] = M[0][3] = 0.f; 366b877906bSopenharmony_ci 367b877906bSopenharmony_ci M[1][1] = 2.f/(t-b); 368b877906bSopenharmony_ci M[1][0] = M[1][2] = M[1][3] = 0.f; 369b877906bSopenharmony_ci 370b877906bSopenharmony_ci M[2][2] = -2.f/(f-n); 371b877906bSopenharmony_ci M[2][0] = M[2][1] = M[2][3] = 0.f; 372b877906bSopenharmony_ci 373b877906bSopenharmony_ci M[3][0] = -(r+l)/(r-l); 374b877906bSopenharmony_ci M[3][1] = -(t+b)/(t-b); 375b877906bSopenharmony_ci M[3][2] = -(f+n)/(f-n); 376b877906bSopenharmony_ci M[3][3] = 1.f; 377b877906bSopenharmony_ci} 378b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_perspective(mat4x4 m, float y_fov, float aspect, float n, float f) 379b877906bSopenharmony_ci{ 380b877906bSopenharmony_ci /* NOTE: Degrees are an unhandy unit to work with. 381b877906bSopenharmony_ci * linmath.h uses radians for everything! */ 382b877906bSopenharmony_ci float const a = 1.f / tanf(y_fov / 2.f); 383b877906bSopenharmony_ci 384b877906bSopenharmony_ci m[0][0] = a / aspect; 385b877906bSopenharmony_ci m[0][1] = 0.f; 386b877906bSopenharmony_ci m[0][2] = 0.f; 387b877906bSopenharmony_ci m[0][3] = 0.f; 388b877906bSopenharmony_ci 389b877906bSopenharmony_ci m[1][0] = 0.f; 390b877906bSopenharmony_ci m[1][1] = a; 391b877906bSopenharmony_ci m[1][2] = 0.f; 392b877906bSopenharmony_ci m[1][3] = 0.f; 393b877906bSopenharmony_ci 394b877906bSopenharmony_ci m[2][0] = 0.f; 395b877906bSopenharmony_ci m[2][1] = 0.f; 396b877906bSopenharmony_ci m[2][2] = -((f + n) / (f - n)); 397b877906bSopenharmony_ci m[2][3] = -1.f; 398b877906bSopenharmony_ci 399b877906bSopenharmony_ci m[3][0] = 0.f; 400b877906bSopenharmony_ci m[3][1] = 0.f; 401b877906bSopenharmony_ci m[3][2] = -((2.f * f * n) / (f - n)); 402b877906bSopenharmony_ci m[3][3] = 0.f; 403b877906bSopenharmony_ci} 404b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_look_at(mat4x4 m, vec3 const eye, vec3 const center, vec3 const up) 405b877906bSopenharmony_ci{ 406b877906bSopenharmony_ci /* Adapted from Android's OpenGL Matrix.java. */ 407b877906bSopenharmony_ci /* See the OpenGL GLUT documentation for gluLookAt for a description */ 408b877906bSopenharmony_ci /* of the algorithm. We implement it in a straightforward way: */ 409b877906bSopenharmony_ci 410b877906bSopenharmony_ci /* TODO: The negation of of can be spared by swapping the order of 411b877906bSopenharmony_ci * operands in the following cross products in the right way. */ 412b877906bSopenharmony_ci vec3 f; 413b877906bSopenharmony_ci vec3_sub(f, center, eye); 414b877906bSopenharmony_ci vec3_norm(f, f); 415b877906bSopenharmony_ci 416b877906bSopenharmony_ci vec3 s; 417b877906bSopenharmony_ci vec3_mul_cross(s, f, up); 418b877906bSopenharmony_ci vec3_norm(s, s); 419b877906bSopenharmony_ci 420b877906bSopenharmony_ci vec3 t; 421b877906bSopenharmony_ci vec3_mul_cross(t, s, f); 422b877906bSopenharmony_ci 423b877906bSopenharmony_ci m[0][0] = s[0]; 424b877906bSopenharmony_ci m[0][1] = t[0]; 425b877906bSopenharmony_ci m[0][2] = -f[0]; 426b877906bSopenharmony_ci m[0][3] = 0.f; 427b877906bSopenharmony_ci 428b877906bSopenharmony_ci m[1][0] = s[1]; 429b877906bSopenharmony_ci m[1][1] = t[1]; 430b877906bSopenharmony_ci m[1][2] = -f[1]; 431b877906bSopenharmony_ci m[1][3] = 0.f; 432b877906bSopenharmony_ci 433b877906bSopenharmony_ci m[2][0] = s[2]; 434b877906bSopenharmony_ci m[2][1] = t[2]; 435b877906bSopenharmony_ci m[2][2] = -f[2]; 436b877906bSopenharmony_ci m[2][3] = 0.f; 437b877906bSopenharmony_ci 438b877906bSopenharmony_ci m[3][0] = 0.f; 439b877906bSopenharmony_ci m[3][1] = 0.f; 440b877906bSopenharmony_ci m[3][2] = 0.f; 441b877906bSopenharmony_ci m[3][3] = 1.f; 442b877906bSopenharmony_ci 443b877906bSopenharmony_ci mat4x4_translate_in_place(m, -eye[0], -eye[1], -eye[2]); 444b877906bSopenharmony_ci} 445b877906bSopenharmony_ci 446b877906bSopenharmony_citypedef float quat[4]; 447b877906bSopenharmony_ci#define quat_add vec4_add 448b877906bSopenharmony_ci#define quat_sub vec4_sub 449b877906bSopenharmony_ci#define quat_norm vec4_norm 450b877906bSopenharmony_ci#define quat_scale vec4_scale 451b877906bSopenharmony_ci#define quat_mul_inner vec4_mul_inner 452b877906bSopenharmony_ci 453b877906bSopenharmony_ciLINMATH_H_FUNC void quat_identity(quat q) 454b877906bSopenharmony_ci{ 455b877906bSopenharmony_ci q[0] = q[1] = q[2] = 0.f; 456b877906bSopenharmony_ci q[3] = 1.f; 457b877906bSopenharmony_ci} 458b877906bSopenharmony_ciLINMATH_H_FUNC void quat_mul(quat r, quat const p, quat const q) 459b877906bSopenharmony_ci{ 460b877906bSopenharmony_ci vec3 w; 461b877906bSopenharmony_ci vec3_mul_cross(r, p, q); 462b877906bSopenharmony_ci vec3_scale(w, p, q[3]); 463b877906bSopenharmony_ci vec3_add(r, r, w); 464b877906bSopenharmony_ci vec3_scale(w, q, p[3]); 465b877906bSopenharmony_ci vec3_add(r, r, w); 466b877906bSopenharmony_ci r[3] = p[3]*q[3] - vec3_mul_inner(p, q); 467b877906bSopenharmony_ci} 468b877906bSopenharmony_ciLINMATH_H_FUNC void quat_conj(quat r, quat const q) 469b877906bSopenharmony_ci{ 470b877906bSopenharmony_ci int i; 471b877906bSopenharmony_ci for(i=0; i<3; ++i) 472b877906bSopenharmony_ci r[i] = -q[i]; 473b877906bSopenharmony_ci r[3] = q[3]; 474b877906bSopenharmony_ci} 475b877906bSopenharmony_ciLINMATH_H_FUNC void quat_rotate(quat r, float angle, vec3 const axis) { 476b877906bSopenharmony_ci vec3 axis_norm; 477b877906bSopenharmony_ci vec3_norm(axis_norm, axis); 478b877906bSopenharmony_ci float s = sinf(angle / 2); 479b877906bSopenharmony_ci float c = cosf(angle / 2); 480b877906bSopenharmony_ci vec3_scale(r, axis_norm, s); 481b877906bSopenharmony_ci r[3] = c; 482b877906bSopenharmony_ci} 483b877906bSopenharmony_ciLINMATH_H_FUNC void quat_mul_vec3(vec3 r, quat const q, vec3 const v) 484b877906bSopenharmony_ci{ 485b877906bSopenharmony_ci/* 486b877906bSopenharmony_ci * Method by Fabian 'ryg' Giessen (of Farbrausch) 487b877906bSopenharmony_cit = 2 * cross(q.xyz, v) 488b877906bSopenharmony_civ' = v + q.w * t + cross(q.xyz, t) 489b877906bSopenharmony_ci */ 490b877906bSopenharmony_ci vec3 t; 491b877906bSopenharmony_ci vec3 q_xyz = {q[0], q[1], q[2]}; 492b877906bSopenharmony_ci vec3 u = {q[0], q[1], q[2]}; 493b877906bSopenharmony_ci 494b877906bSopenharmony_ci vec3_mul_cross(t, q_xyz, v); 495b877906bSopenharmony_ci vec3_scale(t, t, 2); 496b877906bSopenharmony_ci 497b877906bSopenharmony_ci vec3_mul_cross(u, q_xyz, t); 498b877906bSopenharmony_ci vec3_scale(t, t, q[3]); 499b877906bSopenharmony_ci 500b877906bSopenharmony_ci vec3_add(r, v, t); 501b877906bSopenharmony_ci vec3_add(r, r, u); 502b877906bSopenharmony_ci} 503b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_from_quat(mat4x4 M, quat const q) 504b877906bSopenharmony_ci{ 505b877906bSopenharmony_ci float a = q[3]; 506b877906bSopenharmony_ci float b = q[0]; 507b877906bSopenharmony_ci float c = q[1]; 508b877906bSopenharmony_ci float d = q[2]; 509b877906bSopenharmony_ci float a2 = a*a; 510b877906bSopenharmony_ci float b2 = b*b; 511b877906bSopenharmony_ci float c2 = c*c; 512b877906bSopenharmony_ci float d2 = d*d; 513b877906bSopenharmony_ci 514b877906bSopenharmony_ci M[0][0] = a2 + b2 - c2 - d2; 515b877906bSopenharmony_ci M[0][1] = 2.f*(b*c + a*d); 516b877906bSopenharmony_ci M[0][2] = 2.f*(b*d - a*c); 517b877906bSopenharmony_ci M[0][3] = 0.f; 518b877906bSopenharmony_ci 519b877906bSopenharmony_ci M[1][0] = 2*(b*c - a*d); 520b877906bSopenharmony_ci M[1][1] = a2 - b2 + c2 - d2; 521b877906bSopenharmony_ci M[1][2] = 2.f*(c*d + a*b); 522b877906bSopenharmony_ci M[1][3] = 0.f; 523b877906bSopenharmony_ci 524b877906bSopenharmony_ci M[2][0] = 2.f*(b*d + a*c); 525b877906bSopenharmony_ci M[2][1] = 2.f*(c*d - a*b); 526b877906bSopenharmony_ci M[2][2] = a2 - b2 - c2 + d2; 527b877906bSopenharmony_ci M[2][3] = 0.f; 528b877906bSopenharmony_ci 529b877906bSopenharmony_ci M[3][0] = M[3][1] = M[3][2] = 0.f; 530b877906bSopenharmony_ci M[3][3] = 1.f; 531b877906bSopenharmony_ci} 532b877906bSopenharmony_ci 533b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4o_mul_quat(mat4x4 R, mat4x4 const M, quat const q) 534b877906bSopenharmony_ci{ 535b877906bSopenharmony_ci/* XXX: The way this is written only works for orthogonal matrices. */ 536b877906bSopenharmony_ci/* TODO: Take care of non-orthogonal case. */ 537b877906bSopenharmony_ci quat_mul_vec3(R[0], q, M[0]); 538b877906bSopenharmony_ci quat_mul_vec3(R[1], q, M[1]); 539b877906bSopenharmony_ci quat_mul_vec3(R[2], q, M[2]); 540b877906bSopenharmony_ci 541b877906bSopenharmony_ci R[3][0] = R[3][1] = R[3][2] = 0.f; 542b877906bSopenharmony_ci R[0][3] = M[0][3]; 543b877906bSopenharmony_ci R[1][3] = M[1][3]; 544b877906bSopenharmony_ci R[2][3] = M[2][3]; 545b877906bSopenharmony_ci R[3][3] = M[3][3]; // typically 1.0, but here we make it general 546b877906bSopenharmony_ci} 547b877906bSopenharmony_ciLINMATH_H_FUNC void quat_from_mat4x4(quat q, mat4x4 const M) 548b877906bSopenharmony_ci{ 549b877906bSopenharmony_ci float r=0.f; 550b877906bSopenharmony_ci int i; 551b877906bSopenharmony_ci 552b877906bSopenharmony_ci int perm[] = { 0, 1, 2, 0, 1 }; 553b877906bSopenharmony_ci int *p = perm; 554b877906bSopenharmony_ci 555b877906bSopenharmony_ci for(i = 0; i<3; i++) { 556b877906bSopenharmony_ci float m = M[i][i]; 557b877906bSopenharmony_ci if( m < r ) 558b877906bSopenharmony_ci continue; 559b877906bSopenharmony_ci m = r; 560b877906bSopenharmony_ci p = &perm[i]; 561b877906bSopenharmony_ci } 562b877906bSopenharmony_ci 563b877906bSopenharmony_ci r = sqrtf(1.f + M[p[0]][p[0]] - M[p[1]][p[1]] - M[p[2]][p[2]] ); 564b877906bSopenharmony_ci 565b877906bSopenharmony_ci if(r < 1e-6) { 566b877906bSopenharmony_ci q[0] = 1.f; 567b877906bSopenharmony_ci q[1] = q[2] = q[3] = 0.f; 568b877906bSopenharmony_ci return; 569b877906bSopenharmony_ci } 570b877906bSopenharmony_ci 571b877906bSopenharmony_ci q[0] = r/2.f; 572b877906bSopenharmony_ci q[1] = (M[p[0]][p[1]] - M[p[1]][p[0]])/(2.f*r); 573b877906bSopenharmony_ci q[2] = (M[p[2]][p[0]] - M[p[0]][p[2]])/(2.f*r); 574b877906bSopenharmony_ci q[3] = (M[p[2]][p[1]] - M[p[1]][p[2]])/(2.f*r); 575b877906bSopenharmony_ci} 576b877906bSopenharmony_ci 577b877906bSopenharmony_ciLINMATH_H_FUNC void mat4x4_arcball(mat4x4 R, mat4x4 const M, vec2 const _a, vec2 const _b, float s) 578b877906bSopenharmony_ci{ 579b877906bSopenharmony_ci vec2 a; memcpy(a, _a, sizeof(a)); 580b877906bSopenharmony_ci vec2 b; memcpy(b, _b, sizeof(b)); 581b877906bSopenharmony_ci 582b877906bSopenharmony_ci float z_a = 0.f; 583b877906bSopenharmony_ci float z_b = 0.f; 584b877906bSopenharmony_ci 585b877906bSopenharmony_ci if(vec2_len(a) < 1.f) { 586b877906bSopenharmony_ci z_a = sqrtf(1.f - vec2_mul_inner(a, a)); 587b877906bSopenharmony_ci } else { 588b877906bSopenharmony_ci vec2_norm(a, a); 589b877906bSopenharmony_ci } 590b877906bSopenharmony_ci 591b877906bSopenharmony_ci if(vec2_len(b) < 1.f) { 592b877906bSopenharmony_ci z_b = sqrtf(1.f - vec2_mul_inner(b, b)); 593b877906bSopenharmony_ci } else { 594b877906bSopenharmony_ci vec2_norm(b, b); 595b877906bSopenharmony_ci } 596b877906bSopenharmony_ci 597b877906bSopenharmony_ci vec3 a_ = {a[0], a[1], z_a}; 598b877906bSopenharmony_ci vec3 b_ = {b[0], b[1], z_b}; 599b877906bSopenharmony_ci 600b877906bSopenharmony_ci vec3 c_; 601b877906bSopenharmony_ci vec3_mul_cross(c_, a_, b_); 602b877906bSopenharmony_ci 603b877906bSopenharmony_ci float const angle = acos(vec3_mul_inner(a_, b_)) * s; 604b877906bSopenharmony_ci mat4x4_rotate(R, M, c_[0], c_[1], c_[2], angle); 605b877906bSopenharmony_ci} 606b877906bSopenharmony_ci#endif 607