aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Sunet <msunet@shellblade.net>2022-12-26 08:43:53 -0800
committerMarc Sunet <msunet@shellblade.net>2022-12-26 08:43:53 -0800
commit722dda8ff3e91567dbaf83e141699fd34d4889c4 (patch)
treebca1ff5b1d40d4b6cec8efc82b9f48551e7c390b
parent658237ae8a8123e1fb66c3ee39d08a51fe824156 (diff)
Add quat.
-rw-r--r--include/math/quat.h79
1 files changed, 79 insertions, 0 deletions
diff --git a/include/math/quat.h b/include/math/quat.h
new file mode 100644
index 0000000..4503abd
--- /dev/null
+++ b/include/math/quat.h
@@ -0,0 +1,79 @@
1#pragma once
2
3#include "defs.h"
4#include "mat4.h"
5#include "vec3.h"
6
7/// A quaternion.
8typedef struct quat {
9 R w, x, y, z;
10} quat;
11
12static inline quat qunit() {
13 return (quat){.x = 0.0, .y = 0.0, .z = 0.0, .w = 0.0};
14}
15
16static inline quat qmake(R x, R y, R z, R w) {
17 return (quat){.x = x, .y = y, .z = z, .w = w};
18}
19
20static inline quat quat_from_array(const R xyzw[4]) {
21 return (quat){.x = xyzw[0], .y = xyzw[1], .z = xyzw[2], .w = xyzw[3]};
22}
23
24/// Construct a rotation quaternion.
25static inline quat qmake_rot(R angle, R x, R y, R z) {
26 const R a = angle * 0.5;
27 const R sa = sin(a);
28 const R w = cos(a);
29 R mag = sqrt(x * x + y * y + z * z);
30 mag = mag == 0.0 ? 1.0 : mag;
31 x = x * sa;
32 y = y * sa;
33 z = z * sa;
34 return (quat){x / mag, y / mag, z / mag, w};
35}
36
37/// Multiply two quaternions.
38static inline quat qmul(quat q1, quat q2) {
39 const R x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y;
40 const R y = q1.w * q2.y - q1.x * q2.z + q1.y * q2.w + q1.z * q2.x;
41 const R z = q1.w * q2.z + q1.x * q2.y - q1.y * q2.x + q1.z * q2.w;
42 const R w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z;
43 return (quat){x, y, z, w};
44}
45
46/// Invert the quaternion.
47static inline quat qinv(quat q) {
48 R magsq = q.w * q.w + q.x * q.x + q.y * q.y + q.z * q.z;
49 magsq = magsq == 0.0f ? 1.0f : magsq;
50 return (quat){-q.x / magsq, -q.y / magsq, -q.z / magsq, q.w / magsq};
51}
52
53/// Return the quaternion's conjugate.
54static inline quat qconj(quat q) { return (quat){-q.x, -q.y, -q.z, q.w}; }
55
56/// Rotate the given vector by the given unit quaternion.
57static inline vec3 qrot(quat q, vec3 v) {
58 const quat p = qconj(q);
59 const quat qv = (quat){v.x, v.y, v.z, 0};
60 const quat u = qmul(qmul(q, qv), p);
61 return vec3_make(u.x, u.y, u.z);
62}
63
64/// Get a 4x4 rotation matrix from a quaternion.
65static inline mat4 mat4_from_quat(quat q) {
66 const R xx = q.x * q.x;
67 const R yy = q.y * q.y;
68 const R zz = q.z * q.z;
69 const R xy = q.x * q.y;
70 const R xz = q.x * q.z;
71 const R yz = q.y * q.z;
72 const R wx = q.w * q.x;
73 const R wy = q.w * q.y;
74 const R wz = q.w * q.z;
75 return mat4_make(1 - 2 * yy - 2 * zz, 2 * xy - 2 * wz, 2 * xz + 2 * wy, 0,
76 2 * xy + 2 * wz, 1 - 2 * xx - 2 * zz, 2 * yz - 2 * wx, 0,
77 2 * xz - 2 * wy, 2 * yz + 2 * wx, 1 - 2 * xx - 2 * yy, 0, 0,
78 0, 0, 1);
79}