| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949 |
- /*
- * Copyright (c), Recep Aslantas.
- *
- * MIT License (MIT), http://opensource.org/licenses/MIT
- * Full license can be found in the LICENSE file
- */
- /*
- Macros:
- GLM_QUAT_IDENTITY_INIT
- GLM_QUAT_IDENTITY
- Functions:
- CGLM_INLINE void glm_quat_identity(versor q);
- CGLM_INLINE void glm_quat_init(versor q, float x, float y, float z, float w);
- CGLM_INLINE void glm_quat(versor q, float angle, float x, float y, float z);
- CGLM_INLINE void glm_quatv(versor q, float angle, vec3 axis);
- CGLM_INLINE void glm_quat_copy(versor q, versor dest);
- CGLM_INLINE void glm_quat_from_vecs(vec3 a, vec3 b, versor dest);
- CGLM_INLINE float glm_quat_norm(versor q);
- CGLM_INLINE void glm_quat_normalize(versor q);
- CGLM_INLINE void glm_quat_normalize_to(versor q, versor dest);
- CGLM_INLINE float glm_quat_dot(versor p, versor q);
- CGLM_INLINE void glm_quat_conjugate(versor q, versor dest);
- CGLM_INLINE void glm_quat_inv(versor q, versor dest);
- CGLM_INLINE void glm_quat_add(versor p, versor q, versor dest);
- CGLM_INLINE void glm_quat_sub(versor p, versor q, versor dest);
- CGLM_INLINE float glm_quat_real(versor q);
- CGLM_INLINE void glm_quat_imag(versor q, vec3 dest);
- CGLM_INLINE void glm_quat_imagn(versor q, vec3 dest);
- CGLM_INLINE float glm_quat_imaglen(versor q);
- CGLM_INLINE float glm_quat_angle(versor q);
- CGLM_INLINE void glm_quat_axis(versor q, vec3 dest);
- CGLM_INLINE void glm_quat_mul(versor p, versor q, versor dest);
- CGLM_INLINE void glm_quat_mat4(versor q, mat4 dest);
- CGLM_INLINE void glm_quat_mat4t(versor q, mat4 dest);
- CGLM_INLINE void glm_quat_mat3(versor q, mat3 dest);
- CGLM_INLINE void glm_quat_mat3t(versor q, mat3 dest);
- CGLM_INLINE void glm_quat_lerp(versor from, versor to, float t, versor dest);
- CGLM_INLINE void glm_quat_lerpc(versor from, versor to, float t, versor dest);
- CGLM_INLINE void glm_quat_slerp(versor q, versor r, float t, versor dest);
- CGLM_INLINE void glm_quat_slerp_longest(versor q, versor r, float t, versor dest);
- CGLM_INLINE void glm_quat_nlerp(versor q, versor r, float t, versor dest);
- CGLM_INLINE void glm_quat_look(vec3 eye, versor ori, mat4 dest);
- CGLM_INLINE void glm_quat_for(vec3 dir, vec3 fwd, vec3 up, versor dest);
- CGLM_INLINE void glm_quat_forp(vec3 from,
- vec3 to,
- vec3 fwd,
- vec3 up,
- versor dest);
- CGLM_INLINE void glm_quat_rotatev(versor q, vec3 v, vec3 dest);
- CGLM_INLINE void glm_quat_rotate(mat4 m, versor q, mat4 dest);
- CGLM_INLINE void glm_quat_make(float * restrict src, versor dest);
- */
- #ifndef cglm_quat_h
- #define cglm_quat_h
- #include "common.h"
- #include "vec3.h"
- #include "vec4.h"
- #include "mat4.h"
- #include "mat3.h"
- #include "affine-mat.h"
- #include "affine.h"
- #ifdef CGLM_SSE_FP
- # include "simd/sse2/quat.h"
- #endif
- #ifdef CGLM_NEON_FP
- # include "simd/neon/quat.h"
- #endif
- #ifdef CGLM_SIMD_WASM
- # include "simd/wasm/quat.h"
- #endif
- CGLM_INLINE void glm_quat_normalize(versor q);
- /*
- * IMPORTANT:
- * ----------------------------------------------------------------------------
- * cglm stores quat as [x, y, z, w] since v0.3.6
- *
- * it was [w, x, y, z] before v0.3.6 it has been changed to [x, y, z, w]
- * with v0.3.6 version.
- * ----------------------------------------------------------------------------
- */
- #define GLM_QUAT_IDENTITY_INIT {0.0f, 0.0f, 0.0f, 1.0f}
- #define GLM_QUAT_IDENTITY ((versor)GLM_QUAT_IDENTITY_INIT)
- /*!
- * @brief makes given quat to identity
- *
- * @param[in, out] q quaternion
- */
- CGLM_INLINE
- void
- glm_quat_identity(versor q) {
- CGLM_ALIGN(16) versor v = GLM_QUAT_IDENTITY_INIT;
- glm_vec4_copy(v, q);
- }
- /*!
- * @brief make given quaternion array's each element identity quaternion
- *
- * @param[in, out] q quat array (must be aligned (16)
- * if alignment is not disabled)
- *
- * @param[in] count count of quaternions
- */
- CGLM_INLINE
- void
- glm_quat_identity_array(versor * __restrict q, size_t count) {
- CGLM_ALIGN(16) versor v = GLM_QUAT_IDENTITY_INIT;
- size_t i;
- for (i = 0; i < count; i++) {
- glm_vec4_copy(v, q[i]);
- }
- }
- /*!
- * @brief inits quaternion with raw values
- *
- * @param[out] q quaternion
- * @param[in] x x
- * @param[in] y y
- * @param[in] z z
- * @param[in] w w (real part)
- */
- CGLM_INLINE
- void
- glm_quat_init(versor q, float x, float y, float z, float w) {
- q[0] = x;
- q[1] = y;
- q[2] = z;
- q[3] = w;
- }
- /*!
- * @brief creates NEW quaternion with axis vector
- *
- * @param[out] q quaternion
- * @param[in] angle angle (radians)
- * @param[in] axis axis
- */
- CGLM_INLINE
- void
- glm_quatv(versor q, float angle, vec3 axis) {
- CGLM_ALIGN(8) vec3 k;
- float a, c, s;
- a = angle * 0.5f;
- c = cosf(a);
- s = sinf(a);
- glm_normalize_to(axis, k);
- q[0] = s * k[0];
- q[1] = s * k[1];
- q[2] = s * k[2];
- q[3] = c;
- }
- /*!
- * @brief creates NEW quaternion with individual axis components
- *
- * @param[out] q quaternion
- * @param[in] angle angle (radians)
- * @param[in] x axis.x
- * @param[in] y axis.y
- * @param[in] z axis.z
- */
- CGLM_INLINE
- void
- glm_quat(versor q, float angle, float x, float y, float z) {
- CGLM_ALIGN(8) vec3 axis = {x, y, z};
- glm_quatv(q, angle, axis);
- }
- /*!
- * @brief copy quaternion to another one
- *
- * @param[in] q quaternion
- * @param[out] dest destination
- */
- CGLM_INLINE
- void
- glm_quat_copy(versor q, versor dest) {
- glm_vec4_copy(q, dest);
- }
- /*!
- * @brief compute quaternion rotating vector A to vector B
- *
- * @param[in] a vec3 (must have unit length)
- * @param[in] b vec3 (must have unit length)
- * @param[out] dest quaternion (of unit length)
- */
- CGLM_INLINE
- void
- glm_quat_from_vecs(vec3 a, vec3 b, versor dest) {
- CGLM_ALIGN(8) vec3 axis;
- float cos_theta;
- float cos_half_theta;
- cos_theta = glm_vec3_dot(a, b);
- if (cos_theta >= 1.f - GLM_FLT_EPSILON) { /* a ∥ b */
- glm_quat_identity(dest);
- return;
- }
- if (cos_theta < -1.f + GLM_FLT_EPSILON) { /* angle(a, b) = π */
- glm_vec3_ortho(a, axis);
- cos_half_theta = 0.f; /* cos π/2 */
- } else {
- glm_vec3_cross(a, b, axis);
- cos_half_theta = 1.0f + cos_theta; /* cos 0 + cos θ */
- }
- glm_quat_init(dest, axis[0], axis[1], axis[2], cos_half_theta);
- glm_quat_normalize(dest);
- }
- /*!
- * @brief returns norm (magnitude) of quaternion
- *
- * @param[in] q quaternion
- */
- CGLM_INLINE
- float
- glm_quat_norm(versor q) {
- return glm_vec4_norm(q);
- }
- /*!
- * @brief normalize quaternion and store result in dest
- *
- * @param[in] q quaternion to normalze
- * @param[out] dest destination quaternion
- */
- CGLM_INLINE
- void
- glm_quat_normalize_to(versor q, versor dest) {
- #if defined(__wasm__) && defined(__wasm_simd128__)
- glmm_128 xdot, x0;
- float dot;
- x0 = glmm_load(q);
- xdot = glmm_vdot(x0, x0);
- /* dot = _mm_cvtss_f32(xdot); */
- dot = wasm_f32x4_extract_lane(xdot, 0);
- if (dot <= 0.0f) {
- glm_quat_identity(dest);
- return;
- }
- glmm_store(dest, wasm_f32x4_div(x0, wasm_f32x4_sqrt(xdot)));
- #elif defined( __SSE__ ) || defined( __SSE2__ )
- __m128 xdot, x0;
- float dot;
- x0 = glmm_load(q);
- xdot = glmm_vdot(x0, x0);
- dot = _mm_cvtss_f32(xdot);
- if (dot <= 0.0f) {
- glm_quat_identity(dest);
- return;
- }
- glmm_store(dest, _mm_div_ps(x0, _mm_sqrt_ps(xdot)));
- #else
- float dot;
- dot = glm_vec4_norm2(q);
- if (dot <= 0.0f) {
- glm_quat_identity(dest);
- return;
- }
- glm_vec4_scale(q, 1.0f / sqrtf(dot), dest);
- #endif
- }
- /*!
- * @brief normalize quaternion
- *
- * @param[in, out] q quaternion
- */
- CGLM_INLINE
- void
- glm_quat_normalize(versor q) {
- glm_quat_normalize_to(q, q);
- }
- /*!
- * @brief dot product of two quaternion
- *
- * @param[in] p quaternion 1
- * @param[in] q quaternion 2
- */
- CGLM_INLINE
- float
- glm_quat_dot(versor p, versor q) {
- return glm_vec4_dot(p, q);
- }
- /*!
- * @brief conjugate of quaternion
- *
- * @param[in] q quaternion
- * @param[out] dest conjugate
- */
- CGLM_INLINE
- void
- glm_quat_conjugate(versor q, versor dest) {
- glm_vec4_negate_to(q, dest);
- dest[3] = -dest[3];
- }
- /*!
- * @brief inverse of non-zero quaternion
- *
- * @param[in] q quaternion
- * @param[out] dest inverse quaternion
- */
- CGLM_INLINE
- void
- glm_quat_inv(versor q, versor dest) {
- CGLM_ALIGN(16) versor conj;
- glm_quat_conjugate(q, conj);
- glm_vec4_scale(conj, 1.0f / glm_vec4_norm2(q), dest);
- }
- /*!
- * @brief add (componentwise) two quaternions and store result in dest
- *
- * @param[in] p quaternion 1
- * @param[in] q quaternion 2
- * @param[out] dest result quaternion
- */
- CGLM_INLINE
- void
- glm_quat_add(versor p, versor q, versor dest) {
- glm_vec4_add(p, q, dest);
- }
- /*!
- * @brief subtract (componentwise) two quaternions and store result in dest
- *
- * @param[in] p quaternion 1
- * @param[in] q quaternion 2
- * @param[out] dest result quaternion
- */
- CGLM_INLINE
- void
- glm_quat_sub(versor p, versor q, versor dest) {
- glm_vec4_sub(p, q, dest);
- }
- /*!
- * @brief returns real part of quaternion
- *
- * @param[in] q quaternion
- */
- CGLM_INLINE
- float
- glm_quat_real(versor q) {
- return q[3];
- }
- /*!
- * @brief returns imaginary part of quaternion
- *
- * @param[in] q quaternion
- * @param[out] dest imag
- */
- CGLM_INLINE
- void
- glm_quat_imag(versor q, vec3 dest) {
- dest[0] = q[0];
- dest[1] = q[1];
- dest[2] = q[2];
- }
- /*!
- * @brief returns normalized imaginary part of quaternion
- *
- * @param[in] q quaternion
- */
- CGLM_INLINE
- void
- glm_quat_imagn(versor q, vec3 dest) {
- glm_normalize_to(q, dest);
- }
- /*!
- * @brief returns length of imaginary part of quaternion
- *
- * @param[in] q quaternion
- */
- CGLM_INLINE
- float
- glm_quat_imaglen(versor q) {
- return glm_vec3_norm(q);
- }
- /*!
- * @brief returns angle of quaternion
- *
- * @param[in] q quaternion
- */
- CGLM_INLINE
- float
- glm_quat_angle(versor q) {
- /*
- sin(theta / 2) = length(x*x + y*y + z*z)
- cos(theta / 2) = w
- theta = 2 * atan(sin(theta / 2) / cos(theta / 2))
- */
- return 2.0f * atan2f(glm_quat_imaglen(q), glm_quat_real(q));
- }
- /*!
- * @brief axis of quaternion
- *
- * @param[in] q quaternion
- * @param[out] dest axis of quaternion
- */
- CGLM_INLINE
- void
- glm_quat_axis(versor q, vec3 dest) {
- glm_quat_imagn(q, dest);
- }
- /*!
- * @brief multiplies two quaternion and stores result in dest
- * this is also called Hamilton Product
- *
- * According to WikiPedia:
- * The product of two rotation quaternions [clarification needed] will be
- * equivalent to the rotation q followed by the rotation p
- *
- * @param[in] p quaternion 1
- * @param[in] q quaternion 2
- * @param[out] dest result quaternion
- */
- CGLM_INLINE
- void
- glm_quat_mul(versor p, versor q, versor dest) {
- /*
- + (a1 b2 + b1 a2 + c1 d2 − d1 c2)i
- + (a1 c2 − b1 d2 + c1 a2 + d1 b2)j
- + (a1 d2 + b1 c2 − c1 b2 + d1 a2)k
- a1 a2 − b1 b2 − c1 c2 − d1 d2
- */
- #if defined(__wasm__) && defined(__wasm_simd128__)
- glm_quat_mul_wasm(p, q, dest);
- #elif defined( __SSE__ ) || defined( __SSE2__ )
- glm_quat_mul_sse2(p, q, dest);
- #elif defined(CGLM_NEON_FP)
- glm_quat_mul_neon(p, q, dest);
- #else
- dest[0] = p[3] * q[0] + p[0] * q[3] + p[1] * q[2] - p[2] * q[1];
- dest[1] = p[3] * q[1] - p[0] * q[2] + p[1] * q[3] + p[2] * q[0];
- dest[2] = p[3] * q[2] + p[0] * q[1] - p[1] * q[0] + p[2] * q[3];
- dest[3] = p[3] * q[3] - p[0] * q[0] - p[1] * q[1] - p[2] * q[2];
- #endif
- }
- /*!
- * @brief convert quaternion to mat4
- *
- * @param[in] q quaternion
- * @param[out] dest result matrix
- */
- CGLM_INLINE
- void
- glm_quat_mat4(versor q, mat4 dest) {
- float w, x, y, z,
- xx, yy, zz,
- xy, yz, xz,
- wx, wy, wz, norm, s;
- norm = glm_quat_norm(q);
- s = norm > 0.0f ? 2.0f / norm : 0.0f;
- x = q[0];
- y = q[1];
- z = q[2];
- w = q[3];
- xx = s * x * x; xy = s * x * y; wx = s * w * x;
- yy = s * y * y; yz = s * y * z; wy = s * w * y;
- zz = s * z * z; xz = s * x * z; wz = s * w * z;
- dest[0][0] = 1.0f - yy - zz;
- dest[1][1] = 1.0f - xx - zz;
- dest[2][2] = 1.0f - xx - yy;
- dest[0][1] = xy + wz;
- dest[1][2] = yz + wx;
- dest[2][0] = xz + wy;
- dest[1][0] = xy - wz;
- dest[2][1] = yz - wx;
- dest[0][2] = xz - wy;
- dest[0][3] = 0.0f;
- dest[1][3] = 0.0f;
- dest[2][3] = 0.0f;
- dest[3][0] = 0.0f;
- dest[3][1] = 0.0f;
- dest[3][2] = 0.0f;
- dest[3][3] = 1.0f;
- }
- /*!
- * @brief convert quaternion to mat4 (transposed)
- *
- * @param[in] q quaternion
- * @param[out] dest result matrix as transposed
- */
- CGLM_INLINE
- void
- glm_quat_mat4t(versor q, mat4 dest) {
- float w, x, y, z,
- xx, yy, zz,
- xy, yz, xz,
- wx, wy, wz, norm, s;
- norm = glm_quat_norm(q);
- s = norm > 0.0f ? 2.0f / norm : 0.0f;
- x = q[0];
- y = q[1];
- z = q[2];
- w = q[3];
- xx = s * x * x; xy = s * x * y; wx = s * w * x;
- yy = s * y * y; yz = s * y * z; wy = s * w * y;
- zz = s * z * z; xz = s * x * z; wz = s * w * z;
- dest[0][0] = 1.0f - yy - zz;
- dest[1][1] = 1.0f - xx - zz;
- dest[2][2] = 1.0f - xx - yy;
- dest[1][0] = xy + wz;
- dest[2][1] = yz + wx;
- dest[0][2] = xz + wy;
- dest[0][1] = xy - wz;
- dest[1][2] = yz - wx;
- dest[2][0] = xz - wy;
- dest[0][3] = 0.0f;
- dest[1][3] = 0.0f;
- dest[2][3] = 0.0f;
- dest[3][0] = 0.0f;
- dest[3][1] = 0.0f;
- dest[3][2] = 0.0f;
- dest[3][3] = 1.0f;
- }
- /*!
- * @brief convert quaternion to mat3
- *
- * @param[in] q quaternion
- * @param[out] dest result matrix
- */
- CGLM_INLINE
- void
- glm_quat_mat3(versor q, mat3 dest) {
- float w, x, y, z,
- xx, yy, zz,
- xy, yz, xz,
- wx, wy, wz, norm, s;
- norm = glm_quat_norm(q);
- s = norm > 0.0f ? 2.0f / norm : 0.0f;
- x = q[0];
- y = q[1];
- z = q[2];
- w = q[3];
- xx = s * x * x; xy = s * x * y; wx = s * w * x;
- yy = s * y * y; yz = s * y * z; wy = s * w * y;
- zz = s * z * z; xz = s * x * z; wz = s * w * z;
- dest[0][0] = 1.0f - yy - zz;
- dest[1][1] = 1.0f - xx - zz;
- dest[2][2] = 1.0f - xx - yy;
- dest[0][1] = xy + wz;
- dest[1][2] = yz + wx;
- dest[2][0] = xz + wy;
- dest[1][0] = xy - wz;
- dest[2][1] = yz - wx;
- dest[0][2] = xz - wy;
- }
- /*!
- * @brief convert quaternion to mat3 (transposed)
- *
- * @param[in] q quaternion
- * @param[out] dest result matrix
- */
- CGLM_INLINE
- void
- glm_quat_mat3t(versor q, mat3 dest) {
- float w, x, y, z,
- xx, yy, zz,
- xy, yz, xz,
- wx, wy, wz, norm, s;
- norm = glm_quat_norm(q);
- s = norm > 0.0f ? 2.0f / norm : 0.0f;
- x = q[0];
- y = q[1];
- z = q[2];
- w = q[3];
- xx = s * x * x; xy = s * x * y; wx = s * w * x;
- yy = s * y * y; yz = s * y * z; wy = s * w * y;
- zz = s * z * z; xz = s * x * z; wz = s * w * z;
- dest[0][0] = 1.0f - yy - zz;
- dest[1][1] = 1.0f - xx - zz;
- dest[2][2] = 1.0f - xx - yy;
- dest[1][0] = xy + wz;
- dest[2][1] = yz + wx;
- dest[0][2] = xz + wy;
- dest[0][1] = xy - wz;
- dest[1][2] = yz - wx;
- dest[2][0] = xz - wy;
- }
- /*!
- * @brief interpolates between two quaternions
- * using linear interpolation (LERP)
- *
- * @param[in] from from
- * @param[in] to to
- * @param[in] t interpolant (amount)
- * @param[out] dest result quaternion
- */
- CGLM_INLINE
- void
- glm_quat_lerp(versor from, versor to, float t, versor dest) {
- glm_vec4_lerp(from, to, t, dest);
- }
- /*!
- * @brief interpolates between two quaternions
- * using linear interpolation (LERP)
- *
- * @param[in] from from
- * @param[in] to to
- * @param[in] t interpolant (amount) clamped between 0 and 1
- * @param[out] dest result quaternion
- */
- CGLM_INLINE
- void
- glm_quat_lerpc(versor from, versor to, float t, versor dest) {
- glm_vec4_lerpc(from, to, t, dest);
- }
- /*!
- * @brief interpolates between two quaternions
- * taking the shortest rotation path using
- * normalized linear interpolation (NLERP)
- *
- * @param[in] from from
- * @param[in] to to
- * @param[in] t interpolant (amount)
- * @param[out] dest result quaternion
- */
- CGLM_INLINE
- void
- glm_quat_nlerp(versor from, versor to, float t, versor dest) {
- versor target;
- float dot;
-
- dot = glm_vec4_dot(from, to);
-
- glm_vec4_scale(to, (dot >= 0) ? 1.0f : -1.0f, target);
- glm_quat_lerp(from, target, t, dest);
- glm_quat_normalize(dest);
- }
- /*!
- * @brief interpolates between two quaternions
- * using spherical linear interpolation (SLERP)
- *
- * @param[in] from from
- * @param[in] to to
- * @param[in] t amount
- * @param[out] dest result quaternion
- */
- CGLM_INLINE
- void
- glm_quat_slerp(versor from, versor to, float t, versor dest) {
- CGLM_ALIGN(16) vec4 q1, q2;
- float cosTheta, sinTheta, angle;
- cosTheta = glm_quat_dot(from, to);
- glm_quat_copy(from, q1);
- if (fabsf(cosTheta) >= 1.0f) {
- glm_quat_copy(q1, dest);
- return;
- }
- if (cosTheta < 0.0f) {
- glm_vec4_negate(q1);
- cosTheta = -cosTheta;
- }
- sinTheta = sqrtf(1.0f - cosTheta * cosTheta);
- /* LERP to avoid zero division */
- if (fabsf(sinTheta) < 0.001f) {
- glm_quat_lerp(from, to, t, dest);
- return;
- }
- /* SLERP */
- angle = acosf(cosTheta);
- glm_vec4_scale(q1, sinf((1.0f - t) * angle), q1);
- glm_vec4_scale(to, sinf(t * angle), q2);
- glm_vec4_add(q1, q2, q1);
- glm_vec4_scale(q1, 1.0f / sinTheta, dest);
- }
- /*!
- * @brief interpolates between two quaternions
- * using spherical linear interpolation (SLERP) and always takes the long path
- *
- * @param[in] from from
- * @param[in] to to
- * @param[in] t amount
- * @param[out] dest result quaternion
- */
- CGLM_INLINE
- void
- glm_quat_slerp_longest(versor from, versor to, float t, versor dest) {
- CGLM_ALIGN(16) vec4 q1, q2;
- float cosTheta, sinTheta, angle;
- cosTheta = glm_quat_dot(from, to);
- glm_quat_copy(from, q1);
- if (fabsf(cosTheta) >= 1.0f) {
- glm_quat_copy(q1, dest);
- return;
- }
- /* longest path */
- if (!(cosTheta < 0.0f)) {
- glm_vec4_negate(q1);
- cosTheta = -cosTheta;
- }
- sinTheta = sqrtf(1.0f - cosTheta * cosTheta);
- /* LERP to avoid zero division */
- if (fabsf(sinTheta) < 0.001f) {
- glm_quat_lerp(from, to, t, dest);
- return;
- }
- /* SLERP */
- angle = acosf(cosTheta);
- glm_vec4_scale(q1, sinf((1.0f - t) * angle), q1);
- glm_vec4_scale(to, sinf(t * angle), q2);
- glm_vec4_add(q1, q2, q1);
- glm_vec4_scale(q1, 1.0f / sinTheta, dest);
- }
- /*!
- * @brief creates view matrix using quaternion as camera orientation
- *
- * @param[in] eye eye
- * @param[in] ori orientation in world space as quaternion
- * @param[out] dest view matrix
- */
- CGLM_INLINE
- void
- glm_quat_look(vec3 eye, versor ori, mat4 dest) {
- /* orientation */
- glm_quat_mat4t(ori, dest);
- /* translate */
- glm_mat4_mulv3(dest, eye, 1.0f, dest[3]);
- glm_vec3_negate(dest[3]);
- }
- /*!
- * @brief creates look rotation quaternion
- *
- * @param[in] dir direction to look
- * @param[in] up up vector
- * @param[out] dest destination quaternion
- */
- CGLM_INLINE
- void
- glm_quat_for(vec3 dir, vec3 up, versor dest) {
- CGLM_ALIGN_MAT mat3 m;
- glm_vec3_normalize_to(dir, m[2]);
- /* No need to negate in LH, but we use RH here */
- glm_vec3_negate(m[2]);
-
- glm_vec3_crossn(up, m[2], m[0]);
- glm_vec3_cross(m[2], m[0], m[1]);
- glm_mat3_quat(m, dest);
- }
- /*!
- * @brief creates look rotation quaternion using source and
- * destination positions p suffix stands for position
- *
- * @param[in] from source point
- * @param[in] to destination point
- * @param[in] up up vector
- * @param[out] dest destination quaternion
- */
- CGLM_INLINE
- void
- glm_quat_forp(vec3 from, vec3 to, vec3 up, versor dest) {
- CGLM_ALIGN(8) vec3 dir;
- glm_vec3_sub(to, from, dir);
- glm_quat_for(dir, up, dest);
- }
- /*!
- * @brief rotate vector using using quaternion
- *
- * @param[in] q quaternion
- * @param[in] v vector to rotate
- * @param[out] dest rotated vector
- */
- CGLM_INLINE
- void
- glm_quat_rotatev(versor q, vec3 v, vec3 dest) {
- CGLM_ALIGN(16) versor p;
- CGLM_ALIGN(8) vec3 u, v1, v2;
- float s;
- glm_quat_normalize_to(q, p);
- glm_quat_imag(p, u);
- s = glm_quat_real(p);
- glm_vec3_scale(u, 2.0f * glm_vec3_dot(u, v), v1);
- glm_vec3_scale(v, s * s - glm_vec3_dot(u, u), v2);
- glm_vec3_add(v1, v2, v1);
- glm_vec3_cross(u, v, v2);
- glm_vec3_scale(v2, 2.0f * s, v2);
- glm_vec3_add(v1, v2, dest);
- }
- /*!
- * @brief rotate existing transform matrix using quaternion
- *
- * @param[in] m existing transform matrix
- * @param[in] q quaternion
- * @param[out] dest rotated matrix/transform
- */
- CGLM_INLINE
- void
- glm_quat_rotate(mat4 m, versor q, mat4 dest) {
- CGLM_ALIGN_MAT mat4 rot;
- glm_quat_mat4(q, rot);
- glm_mul_rot(m, rot, dest);
- }
- /*!
- * @brief rotate existing transform matrix using quaternion at pivot point
- *
- * @param[in, out] m existing transform matrix
- * @param[in] q quaternion
- * @param[out] pivot pivot
- */
- CGLM_INLINE
- void
- glm_quat_rotate_at(mat4 m, versor q, vec3 pivot) {
- CGLM_ALIGN(8) vec3 pivotInv;
- glm_vec3_negate_to(pivot, pivotInv);
- glm_translate(m, pivot);
- glm_quat_rotate(m, q, m);
- glm_translate(m, pivotInv);
- }
- /*!
- * @brief rotate NEW transform matrix using quaternion at pivot point
- *
- * this creates rotation matrix, it assumes you don't have a matrix
- *
- * this should work faster than glm_quat_rotate_at because it reduces
- * one glm_translate.
- *
- * @param[out] m existing transform matrix
- * @param[in] q quaternion
- * @param[in] pivot pivot
- */
- CGLM_INLINE
- void
- glm_quat_rotate_atm(mat4 m, versor q, vec3 pivot) {
- CGLM_ALIGN(8) vec3 pivotInv;
- glm_vec3_negate_to(pivot, pivotInv);
- glm_translate_make(m, pivot);
- glm_quat_rotate(m, q, m);
- glm_translate(m, pivotInv);
- }
- /*!
- * @brief Create quaternion from pointer
- *
- * @param[in] src pointer to an array of floats
- * @param[out] dest quaternion
- */
- CGLM_INLINE
- void
- glm_quat_make(const float * __restrict src, versor dest) {
- dest[0] = src[0]; dest[1] = src[1];
- dest[2] = src[2]; dest[3] = src[3];
- }
- #endif /* cglm_quat_h */
|