Banjo API 0.0.1
C99 game development API
Loading...
Searching...
No Matches
quat.h
Go to the documentation of this file.
1
30#ifndef BJ_QUAT_H
31#define BJ_QUAT_H
32
33#include <banjo/api.h>
34#include <banjo/math.h>
35#include <banjo/vec.h>
36#include <banjo/mat.h>
37
52typedef struct bj_vec4_t bj_quat;
53
65 void
66) {
67 return (bj_quat){ BJ_FZERO, BJ_FZERO, BJ_FZERO, BJ_F(1.0) };
68}
69
81 bj_quat a,
82 bj_quat b
83) {
84 return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
85}
86
96 bj_quat q
97) {
98 return bj_quat_dot(q, q);
99}
100
108 bj_quat q
109) {
110 return bj_sqrt(bj_quat_norm2(q));
111}
112
123 bj_quat q
124) {
125 const bj_real n2 = bj_quat_norm2(q);
126 if (n2 <= BJ_EPSILON) {
127 return bj_quat_identity();
128 }
129 const bj_real inv = BJ_F(1.0) / bj_sqrt(n2);
130 return (bj_quat){ q.x * inv, q.y * inv, q.z * inv, q.w * inv };
131}
132
146 bj_quat q
147) {
148 return (bj_quat){ -q.x, -q.y, -q.z, q.w };
149}
150
164 bj_quat q
165) {
166 const bj_real n2 = bj_quat_norm2(q);
167 if (n2 <= BJ_EPSILON) {
168 return bj_quat_identity();
169 }
170 const bj_real inv = BJ_F(1.0) / n2;
171 return (bj_quat){ -q.x * inv, -q.y * inv, -q.z * inv, q.w * inv };
172}
173
186 bj_quat p,
187 bj_quat q
188) {
189 return (bj_quat){
190 p.w*q.x + p.x*q.w + p.y*q.z - p.z*q.y,
191 p.w*q.y - p.x*q.z + p.y*q.w + p.z*q.x,
192 p.w*q.z + p.x*q.y - p.y*q.x + p.z*q.w,
193 p.w*q.w - p.x*q.x - p.y*q.y - p.z*q.z
194 };
195}
196
212 bj_quat a,
213 bj_quat b,
214 bj_real t
215) {
216 bj_real cos_omega = bj_quat_dot(a, b);
217 bj_quat bb = b;
218 if (cos_omega < BJ_FZERO) {
219 cos_omega = -cos_omega;
220 bb.x = -b.x;
221 bb.y = -b.y;
222 bb.z = -b.z;
223 bb.w = -b.w;
224 }
225
226 /* Clamp for numerical safety */
227 if (cos_omega > BJ_F(1.0)) cos_omega = BJ_F(1.0);
228 if (cos_omega < -BJ_F(1.0)) cos_omega = -BJ_F(1.0);
229
230 if (cos_omega > BJ_F(1.0) - BJ_EPSILON) {
231 return bj_quat_normalize((bj_quat){
232 a.x + t*(bb.x - a.x),
233 a.y + t*(bb.y - a.y),
234 a.z + t*(bb.z - a.z),
235 a.w + t*(bb.w - a.w)
236 });
237 }
238
239 const bj_real omega = bj_acos(cos_omega);
240 const bj_real sin_omega = bj_sin(omega);
241 if (sin_omega <= BJ_EPSILON) {
242 /* Fallback to nlerp */
243 return bj_quat_normalize((bj_quat){
244 a.x + t*(bb.x - a.x),
245 a.y + t*(bb.y - a.y),
246 a.z + t*(bb.z - a.z),
247 a.w + t*(bb.w - a.w)
248 });
249 }
250
251 const bj_real wa = bj_sin((BJ_F(1.0) - t) * omega) / sin_omega;
252 const bj_real wb = bj_sin(t * omega) / sin_omega;
253 return (bj_quat){
254 wa * a.x + wb * bb.x,
255 wa * a.y + wb * bb.y,
256 wa * a.z + wb * bb.z,
257 wa * a.w + wb * bb.w
258 };
259}
260
271 bj_vec3 axis,
272 bj_real angle_rad
273) {
274 const bj_real alen2 = axis.x*axis.x + axis.y*axis.y + axis.z*axis.z;
275 if (alen2 <= BJ_EPSILON) {
276 return bj_quat_identity();
277 }
278 const bj_real invlen = BJ_F(1.0) / bj_sqrt(alen2);
279 const bj_vec3 n = (bj_vec3){
280 axis.x * invlen, axis.y * invlen, axis.z * invlen
281 };
282 const bj_real h = angle_rad * BJ_F(0.5);
283 const bj_real s = bj_sin(h);
284 const bj_real c = bj_cos(h);
285 return (bj_quat){ n.x * s, n.y * s, n.z * s, c };
286}
287
299 bj_quat q,
300 bj_vec3 v
301) {
302 bj_vec3 u = (bj_vec3){ q.x, q.y, q.z };
303 bj_vec3 t = bj_vec3_cross(u, v);
304 t.x += t.x; t.y += t.y; t.z += t.z; /* 2*(u×v) */
305 bj_vec3 r = (bj_vec3){
306 v.x + q.w * t.x + (u.y * t.z - u.z * t.y),
307 v.y + q.w * t.y + (u.z * t.x - u.x * t.z),
308 v.z + q.w * t.z + (u.x * t.y - u.y * t.x)
309 };
310 return r;
311}
312
321 bj_quat q,
322 bj_vec4 v
323) {
324 bj_vec3 r3 = bj_quat_rotate_vec3(q, (bj_vec3){ v.x, v.y, v.z });
325 return (bj_vec4){ .x = r3.x, .y = r3.y, .z = r3.z, .w = v.w };
326}
327
339 bj_quat q
340) {
341 q = bj_quat_normalize(q);
342 bj_real xx = q.x * q.x, yy = q.y * q.y, zz = q.z * q.z;
343 bj_real xy = q.x * q.y, xz = q.x * q.z, yz = q.y * q.z;
344 bj_real wx = q.w * q.x, wy = q.w * q.y, wz = q.w * q.z;
345
347
348 bj_real* m = M->m;
349 /* Column 0 */
350 m[BJ_M4(0,0)] = BJ_F(1.0) - BJ_F(2.0) * (yy + zz);
351 m[BJ_M4(0,1)] = BJ_F(2.0) * (xy + wz);
352 m[BJ_M4(0,2)] = BJ_F(2.0) * (xz - wy);
353 m[BJ_M4(0,3)] = BJ_FZERO;
354 /* Column 1 */
355 m[BJ_M4(1,0)] = BJ_F(2.0) * (xy - wz);
356 m[BJ_M4(1,1)] = BJ_F(1.0) - BJ_F(2.0) * (xx + zz);
357 m[BJ_M4(1,2)] = BJ_F(2.0) * (yz + wx);
358 m[BJ_M4(1,3)] = BJ_FZERO;
359 /* Column 2 */
360 m[BJ_M4(2,0)] = BJ_F(2.0) * (xz + wy);
361 m[BJ_M4(2,1)] = BJ_F(2.0) * (yz - wx);
362 m[BJ_M4(2,2)] = BJ_F(1.0) - BJ_F(2.0) * (xx + yy);
363 m[BJ_M4(2,3)] = BJ_FZERO;
364 /* Column 3 */
365 m[BJ_M4(3,0)] = BJ_FZERO;
366 m[BJ_M4(3,1)] = BJ_FZERO;
367 m[BJ_M4(3,2)] = BJ_FZERO;
368 m[BJ_M4(3,3)] = BJ_F(1.0);
369}
370
382 const bj_mat4* BJ_RESTRICT M
383) {
384 const bj_real* m = M->m;
385 bj_real m00 = m[BJ_M4(0,0)], m01 = m[BJ_M4(1,0)], m02 = m[BJ_M4(2,0)];
386 bj_real m10 = m[BJ_M4(0,1)], m11 = m[BJ_M4(1,1)], m12 = m[BJ_M4(2,1)];
387 bj_real m20 = m[BJ_M4(0,2)], m21 = m[BJ_M4(1,2)], m22 = m[BJ_M4(2,2)];
388
389 const bj_real trace = m00 + m11 + m22;
390 if (trace > BJ_FZERO) {
391 const bj_real s = bj_sqrt(trace + BJ_F(1.0)) * BJ_F(2.0);
392 const bj_real w = BJ_F(0.25) * s;
393 const bj_real x = (m21 - m12) / s;
394 const bj_real y = (m02 - m20) / s;
395 const bj_real z = (m10 - m01) / s;
396 return bj_quat_normalize((bj_quat){ x, y, z, w });
397 }
398
399 if (m00 > m11 && m00 > m22) {
400 const bj_real s = bj_sqrt(BJ_F(1.0) + m00 - m11 - m22) * BJ_F(2.0);
401 const bj_real w = (m21 - m12) / s;
402 const bj_real x = BJ_F(0.25) * s;
403 const bj_real y = (m01 + m10) / s;
404 const bj_real z = (m02 + m20) / s;
405 return bj_quat_normalize((bj_quat){ x, y, z, w });
406 } else if (m11 > m22) {
407 const bj_real s = bj_sqrt(BJ_F(1.0) - m00 + m11 - m22) * BJ_F(2.0);
408 const bj_real w = (m02 - m20) / s;
409 const bj_real x = (m01 + m10) / s;
410 const bj_real y = BJ_F(0.25) * s;
411 const bj_real z = (m12 + m21) / s;
412 return bj_quat_normalize((bj_quat){ x, y, z, w });
413 } else {
414 const bj_real s = bj_sqrt(BJ_F(1.0) - m00 - m11 + m22) * BJ_F(2.0);
415 const bj_real w = (m10 - m01) / s;
416 const bj_real x = (m02 + m20) / s;
417 const bj_real y = (m12 + m21) / s;
418 const bj_real z = BJ_F(0.25) * s;
419 return bj_quat_normalize((bj_quat){ x, y, z, w });
420 }
421}
422
423#endif /* BJ_QUAT_H */
424
General-purpose definitions for Banjo API.
#define BJ_INLINE
BJ_INLINE expands to an inline specifier appropriate for the toolchain.
Definition api.h:217
#define BJ_RESTRICT
BJ_RESTRICT expands to the appropriate restrict qualifier per toolchain.
Definition api.h:183
bj_real y
Definition vec.h:40
bj_real z
Definition vec.h:54
bj_real x
Definition vec.h:52
bj_real y
Definition vec.h:53
bj_real x
Definition vec.h:39
bj_real z
Definition vec.h:41
bj_real w
Definition vec.h:55
struct bj_vec3_t bj_vec3
Definition vec.h:43
static bj_real bj_quat_norm2(bj_quat q)
Squared Euclidean norm.
Definition quat.h:95
static bj_vec4 bj_quat_rotate_vec4(bj_quat q, bj_vec4 v)
Rotate a 4D vector by a quaternion, preserving w.
Definition quat.h:320
struct bj_mat4x4_t bj_mat4
Definition mat.h:45
static bj_quat bj_quat_mul(bj_quat p, bj_quat q)
Hamilton product p * q.
Definition quat.h:185
struct bj_vec4_t bj_vec4
Definition vec.h:57
#define bj_acos
Arc cosine.
Definition math.h:209
#define bj_sin
Sine.
Definition math.h:221
struct bj_vec4_t bj_quat
Quaternion type alias based on the 4D vector struct.
Definition quat.h:52
static bj_vec3 bj_quat_rotate_vec3(bj_quat q, bj_vec3 v)
Rotate a 3D vector by a quaternion.
Definition quat.h:298
static bj_quat bj_quat_slerp(bj_quat a, bj_quat b, bj_real t)
Spherical linear interpolation between two orientations.
Definition quat.h:211
static bj_quat bj_quat_normalize(bj_quat q)
Normalize a quaternion.
Definition quat.h:122
static bj_quat bj_quat_inverse(bj_quat q)
Multiplicative inverse of a quaternion.
Definition quat.h:163
#define BJ_FZERO
Zero constant in bj_real.
Definition math.h:64
static bj_quat bj_quat_identity(void)
Return the identity quaternion.
Definition quat.h:64
static bj_vec3 bj_vec3_cross(bj_vec3 l, bj_vec3 r)
3D cross product: res = l × r (right-hand rule).
Definition vec.h:453
#define bj_cos
Cosine.
Definition math.h:212
static bj_real bj_quat_norm(bj_quat q)
Euclidean norm (length).
Definition quat.h:107
static bj_quat bj_quat_from_mat4(const bj_mat4 *restrict M)
Build a quaternion from a 4×4 rotation matrix.
Definition quat.h:381
#define BJ_EPSILON
Machine epsilon for bj_real when float is selected.
Definition math.h:55
static bj_real bj_quat_dot(bj_quat a, bj_quat b)
4D dot product between two quaternions.
Definition quat.h:80
static void bj_mat4_set_identity(bj_mat4 *restrict M)
Set a 4×4 matrix to identity.
Definition mat.h:664
#define BJ_F(x)
Literal suffix helper for bj_real when float is selected.
Definition math.h:53
static void bj_quat_to_mat4(bj_mat4 *restrict M, bj_quat q)
Fill a 4×4 rotation matrix from a quaternion.
Definition quat.h:337
#define bj_sqrt
Square root.
Definition math.h:222
float bj_real
Selected real type for float configuration.
Definition math.h:51
static bj_quat bj_quat_conjugate(bj_quat q)
Conjugate of a quaternion.
Definition quat.h:145
#define BJ_M4(c, r)
Definition mat.h:46
static bj_quat bj_quat_from_axis_angle(bj_vec3 axis, bj_real angle_rad)
Build a quaternion from a rotation axis and angle.
Definition quat.h:270
bj_vec4: 4D vector of bj_real values.
Definition vec.h:51
C99 math shim with bj_real precision type and scalar utilities.
C99 math shim with bj_real precision type and scalar utilities.
vector manipulation API