diff options
| author | Marc Sunet <msunet@shellblade.net> | 2022-12-26 08:43:53 -0800 |
|---|---|---|
| committer | Marc Sunet <msunet@shellblade.net> | 2022-12-26 08:43:53 -0800 |
| commit | 722dda8ff3e91567dbaf83e141699fd34d4889c4 (patch) | |
| tree | bca1ff5b1d40d4b6cec8efc82b9f48551e7c390b | |
| parent | 658237ae8a8123e1fb66c3ee39d08a51fe824156 (diff) | |
Add quat.
| -rw-r--r-- | include/math/quat.h | 79 |
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. | ||
| 8 | typedef struct quat { | ||
| 9 | R w, x, y, z; | ||
| 10 | } quat; | ||
| 11 | |||
| 12 | static inline quat qunit() { | ||
| 13 | return (quat){.x = 0.0, .y = 0.0, .z = 0.0, .w = 0.0}; | ||
| 14 | } | ||
| 15 | |||
| 16 | static inline quat qmake(R x, R y, R z, R w) { | ||
| 17 | return (quat){.x = x, .y = y, .z = z, .w = w}; | ||
| 18 | } | ||
| 19 | |||
| 20 | static 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. | ||
| 25 | static 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. | ||
| 38 | static 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. | ||
| 47 | static 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. | ||
| 54 | static 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. | ||
| 57 | static 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. | ||
| 65 | static 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 | } | ||
