Vecmat 0.2.3
C math and linear algebra library for 2D/3D graphics, physics, and science.
Loading...
Searching...
No Matches
quaternion_ptr.c
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2025-2026 Igal Alkon
2// SPDX-FileCopyrightText: 2026 ALKONTEK <git@alkontek.com>
3// SPDX-License-Identifier: BSD-3-Clause
4
5#include <vecmat.h>
6#include "features/cpu.h"
7
14{
15 res->x = 0.0f;
16 res->y = 0.0f;
17 res->z = 0.0f;
18 res->w = 1.0f;
19}
20
30{
31 res->w = a->w * b->w - a->x * b->x - a->y * b->y - a->z * b->z;
32 res->x = a->w * b->x + a->x * b->w + a->y * b->z - a->z * b->y;
33 res->y = a->w * b->y - a->x * b->z + a->y * b->w + a->z * b->x;
34 res->z = a->w * b->z + a->x * b->y - a->y * b->x + a->z * b->w;
35}
36
37void quat_mul_ptr(quaternion *res, const quaternion *a, const quaternion *b)
38{
39#ifdef VECMAT_RUNTIME_DISPATCH
41 quat_mul_ptr_(res, a, b);
42#else
43 quat_mul_ptr_scalar(res, a, b);
44#endif
45}
46
56{
57 const vm_float_t len = VECMAT_SQRT(q->x * q->x + q->y * q->y + q->z * q->z + q->w * q->w);
58 if (len > 0.0f) {
59 const vm_float_t inv_len = 1.0f / len;
60 res->x = q->x * inv_len;
61 res->y = q->y * inv_len;
62 res->z = q->z * inv_len;
63 res->w = q->w * inv_len;
64 } else {
65 res->x = q->x;
66 res->y = q->y;
67 res->z = q->z;
68 res->w = q->w;
69 }
70}
71
73{
74#ifdef VECMAT_RUNTIME_DISPATCH
76 quat_normalize_ptr_(res, q);
77#else
79#endif
80}
81
91void quat_from_euler_ptr(quaternion *res, const vector3 *euler)
92{
93 const vm_float_t rad_x = deg_to_rad(euler->x / 2.0f);
94 const vm_float_t rad_y = deg_to_rad(euler->y / 2.0f);
95 const vm_float_t rad_z = deg_to_rad(euler->z / 2.0f);
96
97 const vm_float_t cx = VECMAT_COS(rad_x), sx = VECMAT_SIN(rad_x);
98 const vm_float_t cy = VECMAT_COS(rad_y), sy = VECMAT_SIN(rad_y);
99 const vm_float_t cz = VECMAT_COS(rad_z), sz = VECMAT_SIN(rad_z);
100
101 const quaternion temp = {
102 .x = sx * cy * cz - cx * sy * sz,
103 .y = cx * sy * cz + sx * cy * sz,
104 .z = cx * cy * sz - sx * sy * cz,
105 .w = cx * cy * cz + sx * sy * sz
106 };
107 quat_normalize_ptr(res, &temp);
108}
109
119{
121
122 const vm_float_t xx = q->x * q->x;
123 const vm_float_t yy = q->y * q->y;
124 const vm_float_t zz = q->z * q->z;
125 const vm_float_t xy = q->x * q->y;
126 const vm_float_t xz = q->x * q->z;
127 const vm_float_t yz = q->y * q->z;
128 const vm_float_t wx = q->w * q->x;
129 const vm_float_t wy = q->w * q->y;
130 const vm_float_t wz = q->w * q->z;
131
132 res->m11 = 1.0f - 2.0f * (yy + zz);
133 res->m12 = 2.0f * (xy - wz);
134 res->m13 = 2.0f * (xz + wy);
135 res->m21 = 2.0f * (xy + wz);
136 res->m22 = 1.0f - 2.0f * (xx + zz);
137 res->m23 = 2.0f * (yz - wx);
138 res->m31 = 2.0f * (xz - wy);
139 res->m32 = 2.0f * (yz + wx);
140 res->m33 = 1.0f - 2.0f * (xx + yy);
141}
142
150{
151 res->x = -q->x;
152 res->y = -q->y;
153 res->z = -q->z;
154 res->w = q->w;
155}
156
164{
165 const vm_float_t n2 = q->x * q->x + q->y * q->y + q->z * q->z + q->w * q->w;
166 if (n2 <= 0.0f) {
167 *res = *q;
168 return;
169 }
170 const vm_float_t inv = 1.0f / n2;
171 res->x = -q->x * inv;
172 res->y = -q->y * inv;
173 res->z = -q->z * inv;
174 res->w = q->w * inv;
175}
176
184void quat_from_axis_angle_ptr(quaternion *res, const vector3 *axis, const vm_float_t degrees)
185{
186 const vector3 n = vec3_normalize(*axis);
187 const vm_float_t half = deg_to_rad(degrees) * 0.5f;
188 const vm_float_t s = VECMAT_SIN(half);
189 res->x = n.x * s;
190 res->y = n.y * s;
191 res->z = n.z * s;
192 res->w = VECMAT_COS(half);
193}
194
202{
203 const vm_float_t trace = m->m11 + m->m22 + m->m33;
204 if (trace > 0.0f) {
205 const vm_float_t s = VECMAT_SQRT(trace + 1.0f) * 2.0f;
206 res->w = 0.25f * s;
207 res->x = (m->m32 - m->m23) / s;
208 res->y = (m->m13 - m->m31) / s;
209 res->z = (m->m21 - m->m12) / s;
210 } else if (m->m11 > m->m22 && m->m11 > m->m33) {
211 const vm_float_t s = VECMAT_SQRT(1.0f + m->m11 - m->m22 - m->m33) * 2.0f;
212 res->w = (m->m32 - m->m23) / s;
213 res->x = 0.25f * s;
214 res->y = (m->m12 + m->m21) / s;
215 res->z = (m->m13 + m->m31) / s;
216 } else if (m->m22 > m->m33) {
217 const vm_float_t s = VECMAT_SQRT(1.0f + m->m22 - m->m11 - m->m33) * 2.0f;
218 res->w = (m->m13 - m->m31) / s;
219 res->x = (m->m12 + m->m21) / s;
220 res->y = 0.25f * s;
221 res->z = (m->m23 + m->m32) / s;
222 } else {
223 const vm_float_t s = VECMAT_SQRT(1.0f + m->m33 - m->m11 - m->m22) * 2.0f;
224 res->w = (m->m21 - m->m12) / s;
225 res->x = (m->m13 + m->m31) / s;
226 res->y = (m->m23 + m->m32) / s;
227 res->z = 0.25f * s;
228 }
229 quat_normalize_ptr(res, res);
230}
231
239{
240 const matrix3 m3 = {
241 .m11 = m->m11, .m21 = m->m21, .m31 = m->m31,
242 .m12 = m->m12, .m22 = m->m22, .m32 = m->m32,
243 .m13 = m->m13, .m23 = m->m23, .m33 = m->m33
244 };
245 quat_from_mat3_ptr(res, &m3);
246}
247
256void quat_nlerp_ptr(quaternion *res, const quaternion *a, const quaternion *b, const vm_float_t t)
257{
258 quaternion bb = *b;
259 if (quat_dot(*a, *b) < 0.0f) {
260 bb.x = -bb.x;
261 bb.y = -bb.y;
262 bb.z = -bb.z;
263 bb.w = -bb.w;
264 }
265 const quaternion tmp = {
266 .x = a->x + t * (bb.x - a->x),
267 .y = a->y + t * (bb.y - a->y),
268 .z = a->z + t * (bb.z - a->z),
269 .w = a->w + t * (bb.w - a->w)
270 };
271 quat_normalize_ptr(res, &tmp);
272}
273
282void quat_slerp_ptr(quaternion *res, const quaternion *a, const quaternion *b, const vm_float_t t)
283{
284 vm_float_t d = quat_dot(*a, *b);
285 quaternion bb = *b;
286 if (d < 0.0f) {
287 d = -d;
288 bb.x = -bb.x;
289 bb.y = -bb.y;
290 bb.z = -bb.z;
291 bb.w = -bb.w;
292 }
293 if (d > 0.9995f) {
294 quat_nlerp_ptr(res, a, &bb, t);
295 return;
296 }
297 const vm_float_t theta = VECMAT_ACOS(d);
298 const vm_float_t s = VECMAT_SIN(theta);
299 const vm_float_t wa = VECMAT_SIN((1.0f - t) * theta) / s;
300 const vm_float_t wb = VECMAT_SIN(t * theta) / s;
301 res->x = a->x * wa + bb.x * wb;
302 res->y = a->y * wa + bb.y * wb;
303 res->z = a->z * wa + bb.z * wb;
304 res->w = a->w * wa + bb.w * wb;
305}
306
314void quat_rotate_vec3_ptr(vector3 *res, const quaternion *q, const vector3 *v)
315{
316 const quaternion p = {.x = v->x, .y = v->y, .z = v->z, .w = 0.0f};
317 quaternion qi;
318 quat_inverse_ptr(&qi, q);
319 quaternion qp;
320 quat_mul_ptr(&qp, q, &p);
321 quaternion out;
322 quat_mul_ptr(&out, &qp, &qi);
323 res->x = out.x;
324 res->y = out.y;
325 res->z = out.z;
326}
327
335{
336 const vm_float_t x = q->x;
337 const vm_float_t y = q->y;
338 const vm_float_t z = q->z;
339 const vm_float_t w = q->w;
340
341 const vm_float_t sinr_cosp = (vm_float_t)2.0 * (w * x + y * z);
342 const vm_float_t cosr_cosp = (vm_float_t)1.0 - (vm_float_t)2.0 * (x * x + y * y);
343 res->x = (VECMAT_ATAN2(sinr_cosp, cosr_cosp) * (vm_float_t)VM_RAD_TO_DEG);
344
345 const vm_float_t sinp = (vm_float_t)2.0 * (w * y - z * x);
346 if (VECMAT_FABS(sinp) >= (vm_float_t)1.0) {
348 } else {
349 res->y = (VECMAT_ASIN(sinp) * (vm_float_t)VM_RAD_TO_DEG);
350 }
351
352 const vm_float_t siny_cosp = (vm_float_t)2.0 * (w * z + x * y);
353 const vm_float_t cosy_cosp = (vm_float_t)1.0 - (vm_float_t)2.0 * (y * y + z * z);
354 res->z = (VECMAT_ATAN2(siny_cosp, cosy_cosp) * (vm_float_t)VM_RAD_TO_DEG);
355}
356
365{
366 quaternion n;
367 quat_normalize_ptr(&n, q);
368 const vm_float_t w = (n.w > 1.0f) ? 1.0f : (n.w < -1.0f) ? -1.0f : n.w;
369 const vm_float_t angle = rad_to_deg(2.0f * VECMAT_ACOS(w));
370 const vm_float_t s = VECMAT_SQRT(1.0f - w * w);
371 if (s < VECMAT_EPSILON) {
372 axis->x = 1.0f;
373 axis->y = 0.0f;
374 axis->z = 0.0f;
375 } else {
376 axis->x = n.x / s;
377 axis->y = n.y / s;
378 axis->z = n.z / s;
379 }
380 if (degrees) {
381 *degrees = angle;
382 }
383}
384
392{
393 matrix4 m4;
394 quat_to_mat4_ptr(&m4, q);
395 res->m11 = m4.m11; res->m21 = m4.m21; res->m31 = m4.m31;
396 res->m12 = m4.m12; res->m22 = m4.m22; res->m32 = m4.m32;
397 res->m13 = m4.m13; res->m23 = m4.m23; res->m33 = m4.m33;
398}
#define VECMAT_SCALAR_API
Definition cpu.h:17
void quat_mul_ptr(quaternion *res, const quaternion *a, const quaternion *b)
void quat_from_axis_angle_ptr(quaternion *res, const vector3 *axis, const vm_float_t degrees)
Builds a quaternion from an axis and an angle in degrees.
void quat_rotate_vec3_ptr(vector3 *res, const quaternion *q, const vector3 *v)
Rotates a vector3 by a quaternion.
void quat_to_axis_angle_ptr(vector3 *axis, vm_float_t *degrees, const quaternion *q)
Converts a quaternion to an axis and an angle in degrees.
void quat_from_mat4_ptr(quaternion *res, const matrix4 *m)
Builds a quaternion from the rotation of a 4x4 matrix.
void quat_from_mat3_ptr(quaternion *res, const matrix3 *m)
Builds a quaternion from a 3x3 rotation matrix.
VECMAT_SCALAR_API void quat_normalize_ptr_scalar(quaternion *res, const quaternion *q)
Normalizes the input quaternion and stores the result in res.
void quat_to_euler_ptr(vector3 *res, const quaternion *q)
Converts a quaternion to Euler angles in degrees (XYZ).
void quat_to_mat3_ptr(matrix3 *res, const quaternion *q)
Converts a quaternion to a 3x3 rotation matrix.
VECMAT_SCALAR_API void quat_mul_ptr_scalar(quaternion *res, const quaternion *a, const quaternion *b)
Multiplies two quaternions using Hamilton product (a * b) and stores the result in res.
void quat_slerp_ptr(quaternion *res, const quaternion *a, const quaternion *b, const vm_float_t t)
Spherical-linearly interpolates from a to b by t.
void quat_from_euler_ptr(quaternion *res, const vector3 *euler)
Converts Euler angles (in degrees, XYZ order: pitch, yaw, roll) to a quaternion and stores in res.
void quat_normalize_ptr(quaternion *res, const quaternion *q)
void quat_conjugate_ptr(quaternion *res, const quaternion *q)
Writes the conjugate of a quaternion.
void quat_nlerp_ptr(quaternion *res, const quaternion *a, const quaternion *b, const vm_float_t t)
Normalized-linearly interpolates from a to b by t.
void quat_to_mat4_ptr(matrix4 *res, const quaternion *q)
Converts a unit quaternion to a 4x4 rotation matrix and stores in res.
void quat_identity_ptr(quaternion *res)
Sets the quaternion to the identity quaternion (x=0, y=0, z=0, w=1).
void quat_inverse_ptr(quaternion *res, const quaternion *q)
Writes the inverse of a quaternion.
vm_float_t m13
Definition vecmat.h:234
vm_float_t m21
Definition vecmat.h:229
vm_float_t m32
Definition vecmat.h:233
vm_float_t m23
Definition vecmat.h:235
vm_float_t m12
Definition vecmat.h:231
vm_float_t m33
Definition vecmat.h:236
vm_float_t m11
Definition vecmat.h:228
vm_float_t m31
Definition vecmat.h:230
vm_float_t m22
Definition vecmat.h:232
vm_float_t m12
Definition vecmat.h:258
vm_float_t m13
Definition vecmat.h:262
vm_float_t m33
Definition vecmat.h:264
vm_float_t m23
Definition vecmat.h:263
vm_float_t m21
Definition vecmat.h:255
vm_float_t m22
Definition vecmat.h:259
vm_float_t m32
Definition vecmat.h:260
vm_float_t m11
Definition vecmat.h:254
vm_float_t m31
Definition vecmat.h:256
vm_float_t y
Definition vecmat.h:364
vm_float_t x
Definition vecmat.h:363
vm_float_t z
Definition vecmat.h:365
vm_float_t w
Definition vecmat.h:366
vm_float_t z
Definition vecmat.h:139
vm_float_t y
Definition vecmat.h:138
vm_float_t x
Definition vecmat.h:137
#define VECMAT_EPSILON
Definition vecmat.h:377
static const vm_float_t VM_RAD_TO_DEG
Definition vecmat.h:86
#define VECMAT_ASIN(x)
Definition vecmat.h:418
#define VECMAT_ACOS(x)
Definition vecmat.h:419
#define VECMAT_COPYSIGN(x, y)
Definition vecmat.h:428
vm_float_t rad_to_deg(vm_float_t radians)
Converts radians to degrees.
Definition vecmat.c:25
#define VECMAT_SIN(x)
Definition vecmat.h:415
vm_float_t quat_dot(quaternion a, quaternion b)
Returns the dot product of two quaternions.
Definition quaternion.c:261
#define M_PI_2
Definition vecmat.h:44
vector3 vec3_normalize(vector3 v)
Normalizes a vector3 to unit length.
Definition vector3.c:227
double vm_float_t
Definition vecmat.h:79
#define VECMAT_FABS(x)
Definition vecmat.h:413
#define VECMAT_SQRT(x)
Definition vecmat.h:414
vm_float_t deg_to_rad(vm_float_t degrees)
Converts degrees to radians.
Definition vecmat.c:14
#define VECMAT_COS(x)
Definition vecmat.h:416
#define VECMAT_ATAN2(y, x)
Definition vecmat.h:421
void vm_cpu_init(void)
Definition dispatch.c:77
void mat4_identity_ptr(matrix4 *res)
Sets the matrix to the identity matrix.
Definition matrix4_ptr.c:16