1
0

quat.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949
  1. /*
  2. * Copyright (c), Recep Aslantas.
  3. *
  4. * MIT License (MIT), http://opensource.org/licenses/MIT
  5. * Full license can be found in the LICENSE file
  6. */
  7. /*
  8. Macros:
  9. GLM_QUAT_IDENTITY_INIT
  10. GLM_QUAT_IDENTITY
  11. Functions:
  12. CGLM_INLINE void glm_quat_identity(versor q);
  13. CGLM_INLINE void glm_quat_init(versor q, float x, float y, float z, float w);
  14. CGLM_INLINE void glm_quat(versor q, float angle, float x, float y, float z);
  15. CGLM_INLINE void glm_quatv(versor q, float angle, vec3 axis);
  16. CGLM_INLINE void glm_quat_copy(versor q, versor dest);
  17. CGLM_INLINE void glm_quat_from_vecs(vec3 a, vec3 b, versor dest);
  18. CGLM_INLINE float glm_quat_norm(versor q);
  19. CGLM_INLINE void glm_quat_normalize(versor q);
  20. CGLM_INLINE void glm_quat_normalize_to(versor q, versor dest);
  21. CGLM_INLINE float glm_quat_dot(versor p, versor q);
  22. CGLM_INLINE void glm_quat_conjugate(versor q, versor dest);
  23. CGLM_INLINE void glm_quat_inv(versor q, versor dest);
  24. CGLM_INLINE void glm_quat_add(versor p, versor q, versor dest);
  25. CGLM_INLINE void glm_quat_sub(versor p, versor q, versor dest);
  26. CGLM_INLINE float glm_quat_real(versor q);
  27. CGLM_INLINE void glm_quat_imag(versor q, vec3 dest);
  28. CGLM_INLINE void glm_quat_imagn(versor q, vec3 dest);
  29. CGLM_INLINE float glm_quat_imaglen(versor q);
  30. CGLM_INLINE float glm_quat_angle(versor q);
  31. CGLM_INLINE void glm_quat_axis(versor q, vec3 dest);
  32. CGLM_INLINE void glm_quat_mul(versor p, versor q, versor dest);
  33. CGLM_INLINE void glm_quat_mat4(versor q, mat4 dest);
  34. CGLM_INLINE void glm_quat_mat4t(versor q, mat4 dest);
  35. CGLM_INLINE void glm_quat_mat3(versor q, mat3 dest);
  36. CGLM_INLINE void glm_quat_mat3t(versor q, mat3 dest);
  37. CGLM_INLINE void glm_quat_lerp(versor from, versor to, float t, versor dest);
  38. CGLM_INLINE void glm_quat_lerpc(versor from, versor to, float t, versor dest);
  39. CGLM_INLINE void glm_quat_slerp(versor q, versor r, float t, versor dest);
  40. CGLM_INLINE void glm_quat_slerp_longest(versor q, versor r, float t, versor dest);
  41. CGLM_INLINE void glm_quat_nlerp(versor q, versor r, float t, versor dest);
  42. CGLM_INLINE void glm_quat_look(vec3 eye, versor ori, mat4 dest);
  43. CGLM_INLINE void glm_quat_for(vec3 dir, vec3 fwd, vec3 up, versor dest);
  44. CGLM_INLINE void glm_quat_forp(vec3 from,
  45. vec3 to,
  46. vec3 fwd,
  47. vec3 up,
  48. versor dest);
  49. CGLM_INLINE void glm_quat_rotatev(versor q, vec3 v, vec3 dest);
  50. CGLM_INLINE void glm_quat_rotate(mat4 m, versor q, mat4 dest);
  51. CGLM_INLINE void glm_quat_make(float * restrict src, versor dest);
  52. */
  53. #ifndef cglm_quat_h
  54. #define cglm_quat_h
  55. #include "common.h"
  56. #include "vec3.h"
  57. #include "vec4.h"
  58. #include "mat4.h"
  59. #include "mat3.h"
  60. #include "affine-mat.h"
  61. #include "affine.h"
  62. #ifdef CGLM_SSE_FP
  63. # include "simd/sse2/quat.h"
  64. #endif
  65. #ifdef CGLM_NEON_FP
  66. # include "simd/neon/quat.h"
  67. #endif
  68. #ifdef CGLM_SIMD_WASM
  69. # include "simd/wasm/quat.h"
  70. #endif
  71. CGLM_INLINE void glm_quat_normalize(versor q);
  72. /*
  73. * IMPORTANT:
  74. * ----------------------------------------------------------------------------
  75. * cglm stores quat as [x, y, z, w] since v0.3.6
  76. *
  77. * it was [w, x, y, z] before v0.3.6 it has been changed to [x, y, z, w]
  78. * with v0.3.6 version.
  79. * ----------------------------------------------------------------------------
  80. */
  81. #define GLM_QUAT_IDENTITY_INIT {0.0f, 0.0f, 0.0f, 1.0f}
  82. #define GLM_QUAT_IDENTITY ((versor)GLM_QUAT_IDENTITY_INIT)
  83. /*!
  84. * @brief makes given quat to identity
  85. *
  86. * @param[in, out] q quaternion
  87. */
  88. CGLM_INLINE
  89. void
  90. glm_quat_identity(versor q) {
  91. CGLM_ALIGN(16) versor v = GLM_QUAT_IDENTITY_INIT;
  92. glm_vec4_copy(v, q);
  93. }
  94. /*!
  95. * @brief make given quaternion array's each element identity quaternion
  96. *
  97. * @param[in, out] q quat array (must be aligned (16)
  98. * if alignment is not disabled)
  99. *
  100. * @param[in] count count of quaternions
  101. */
  102. CGLM_INLINE
  103. void
  104. glm_quat_identity_array(versor * __restrict q, size_t count) {
  105. CGLM_ALIGN(16) versor v = GLM_QUAT_IDENTITY_INIT;
  106. size_t i;
  107. for (i = 0; i < count; i++) {
  108. glm_vec4_copy(v, q[i]);
  109. }
  110. }
  111. /*!
  112. * @brief inits quaternion with raw values
  113. *
  114. * @param[out] q quaternion
  115. * @param[in] x x
  116. * @param[in] y y
  117. * @param[in] z z
  118. * @param[in] w w (real part)
  119. */
  120. CGLM_INLINE
  121. void
  122. glm_quat_init(versor q, float x, float y, float z, float w) {
  123. q[0] = x;
  124. q[1] = y;
  125. q[2] = z;
  126. q[3] = w;
  127. }
  128. /*!
  129. * @brief creates NEW quaternion with axis vector
  130. *
  131. * @param[out] q quaternion
  132. * @param[in] angle angle (radians)
  133. * @param[in] axis axis
  134. */
  135. CGLM_INLINE
  136. void
  137. glm_quatv(versor q, float angle, vec3 axis) {
  138. CGLM_ALIGN(8) vec3 k;
  139. float a, c, s;
  140. a = angle * 0.5f;
  141. c = cosf(a);
  142. s = sinf(a);
  143. glm_normalize_to(axis, k);
  144. q[0] = s * k[0];
  145. q[1] = s * k[1];
  146. q[2] = s * k[2];
  147. q[3] = c;
  148. }
  149. /*!
  150. * @brief creates NEW quaternion with individual axis components
  151. *
  152. * @param[out] q quaternion
  153. * @param[in] angle angle (radians)
  154. * @param[in] x axis.x
  155. * @param[in] y axis.y
  156. * @param[in] z axis.z
  157. */
  158. CGLM_INLINE
  159. void
  160. glm_quat(versor q, float angle, float x, float y, float z) {
  161. CGLM_ALIGN(8) vec3 axis = {x, y, z};
  162. glm_quatv(q, angle, axis);
  163. }
  164. /*!
  165. * @brief copy quaternion to another one
  166. *
  167. * @param[in] q quaternion
  168. * @param[out] dest destination
  169. */
  170. CGLM_INLINE
  171. void
  172. glm_quat_copy(versor q, versor dest) {
  173. glm_vec4_copy(q, dest);
  174. }
  175. /*!
  176. * @brief compute quaternion rotating vector A to vector B
  177. *
  178. * @param[in] a vec3 (must have unit length)
  179. * @param[in] b vec3 (must have unit length)
  180. * @param[out] dest quaternion (of unit length)
  181. */
  182. CGLM_INLINE
  183. void
  184. glm_quat_from_vecs(vec3 a, vec3 b, versor dest) {
  185. CGLM_ALIGN(8) vec3 axis;
  186. float cos_theta;
  187. float cos_half_theta;
  188. cos_theta = glm_vec3_dot(a, b);
  189. if (cos_theta >= 1.f - GLM_FLT_EPSILON) { /* a ∥ b */
  190. glm_quat_identity(dest);
  191. return;
  192. }
  193. if (cos_theta < -1.f + GLM_FLT_EPSILON) { /* angle(a, b) = π */
  194. glm_vec3_ortho(a, axis);
  195. cos_half_theta = 0.f; /* cos π/2 */
  196. } else {
  197. glm_vec3_cross(a, b, axis);
  198. cos_half_theta = 1.0f + cos_theta; /* cos 0 + cos θ */
  199. }
  200. glm_quat_init(dest, axis[0], axis[1], axis[2], cos_half_theta);
  201. glm_quat_normalize(dest);
  202. }
  203. /*!
  204. * @brief returns norm (magnitude) of quaternion
  205. *
  206. * @param[in] q quaternion
  207. */
  208. CGLM_INLINE
  209. float
  210. glm_quat_norm(versor q) {
  211. return glm_vec4_norm(q);
  212. }
  213. /*!
  214. * @brief normalize quaternion and store result in dest
  215. *
  216. * @param[in] q quaternion to normalze
  217. * @param[out] dest destination quaternion
  218. */
  219. CGLM_INLINE
  220. void
  221. glm_quat_normalize_to(versor q, versor dest) {
  222. #if defined(__wasm__) && defined(__wasm_simd128__)
  223. glmm_128 xdot, x0;
  224. float dot;
  225. x0 = glmm_load(q);
  226. xdot = glmm_vdot(x0, x0);
  227. /* dot = _mm_cvtss_f32(xdot); */
  228. dot = wasm_f32x4_extract_lane(xdot, 0);
  229. if (dot <= 0.0f) {
  230. glm_quat_identity(dest);
  231. return;
  232. }
  233. glmm_store(dest, wasm_f32x4_div(x0, wasm_f32x4_sqrt(xdot)));
  234. #elif defined( __SSE__ ) || defined( __SSE2__ )
  235. __m128 xdot, x0;
  236. float dot;
  237. x0 = glmm_load(q);
  238. xdot = glmm_vdot(x0, x0);
  239. dot = _mm_cvtss_f32(xdot);
  240. if (dot <= 0.0f) {
  241. glm_quat_identity(dest);
  242. return;
  243. }
  244. glmm_store(dest, _mm_div_ps(x0, _mm_sqrt_ps(xdot)));
  245. #else
  246. float dot;
  247. dot = glm_vec4_norm2(q);
  248. if (dot <= 0.0f) {
  249. glm_quat_identity(dest);
  250. return;
  251. }
  252. glm_vec4_scale(q, 1.0f / sqrtf(dot), dest);
  253. #endif
  254. }
  255. /*!
  256. * @brief normalize quaternion
  257. *
  258. * @param[in, out] q quaternion
  259. */
  260. CGLM_INLINE
  261. void
  262. glm_quat_normalize(versor q) {
  263. glm_quat_normalize_to(q, q);
  264. }
  265. /*!
  266. * @brief dot product of two quaternion
  267. *
  268. * @param[in] p quaternion 1
  269. * @param[in] q quaternion 2
  270. */
  271. CGLM_INLINE
  272. float
  273. glm_quat_dot(versor p, versor q) {
  274. return glm_vec4_dot(p, q);
  275. }
  276. /*!
  277. * @brief conjugate of quaternion
  278. *
  279. * @param[in] q quaternion
  280. * @param[out] dest conjugate
  281. */
  282. CGLM_INLINE
  283. void
  284. glm_quat_conjugate(versor q, versor dest) {
  285. glm_vec4_negate_to(q, dest);
  286. dest[3] = -dest[3];
  287. }
  288. /*!
  289. * @brief inverse of non-zero quaternion
  290. *
  291. * @param[in] q quaternion
  292. * @param[out] dest inverse quaternion
  293. */
  294. CGLM_INLINE
  295. void
  296. glm_quat_inv(versor q, versor dest) {
  297. CGLM_ALIGN(16) versor conj;
  298. glm_quat_conjugate(q, conj);
  299. glm_vec4_scale(conj, 1.0f / glm_vec4_norm2(q), dest);
  300. }
  301. /*!
  302. * @brief add (componentwise) two quaternions and store result in dest
  303. *
  304. * @param[in] p quaternion 1
  305. * @param[in] q quaternion 2
  306. * @param[out] dest result quaternion
  307. */
  308. CGLM_INLINE
  309. void
  310. glm_quat_add(versor p, versor q, versor dest) {
  311. glm_vec4_add(p, q, dest);
  312. }
  313. /*!
  314. * @brief subtract (componentwise) two quaternions and store result in dest
  315. *
  316. * @param[in] p quaternion 1
  317. * @param[in] q quaternion 2
  318. * @param[out] dest result quaternion
  319. */
  320. CGLM_INLINE
  321. void
  322. glm_quat_sub(versor p, versor q, versor dest) {
  323. glm_vec4_sub(p, q, dest);
  324. }
  325. /*!
  326. * @brief returns real part of quaternion
  327. *
  328. * @param[in] q quaternion
  329. */
  330. CGLM_INLINE
  331. float
  332. glm_quat_real(versor q) {
  333. return q[3];
  334. }
  335. /*!
  336. * @brief returns imaginary part of quaternion
  337. *
  338. * @param[in] q quaternion
  339. * @param[out] dest imag
  340. */
  341. CGLM_INLINE
  342. void
  343. glm_quat_imag(versor q, vec3 dest) {
  344. dest[0] = q[0];
  345. dest[1] = q[1];
  346. dest[2] = q[2];
  347. }
  348. /*!
  349. * @brief returns normalized imaginary part of quaternion
  350. *
  351. * @param[in] q quaternion
  352. */
  353. CGLM_INLINE
  354. void
  355. glm_quat_imagn(versor q, vec3 dest) {
  356. glm_normalize_to(q, dest);
  357. }
  358. /*!
  359. * @brief returns length of imaginary part of quaternion
  360. *
  361. * @param[in] q quaternion
  362. */
  363. CGLM_INLINE
  364. float
  365. glm_quat_imaglen(versor q) {
  366. return glm_vec3_norm(q);
  367. }
  368. /*!
  369. * @brief returns angle of quaternion
  370. *
  371. * @param[in] q quaternion
  372. */
  373. CGLM_INLINE
  374. float
  375. glm_quat_angle(versor q) {
  376. /*
  377. sin(theta / 2) = length(x*x + y*y + z*z)
  378. cos(theta / 2) = w
  379. theta = 2 * atan(sin(theta / 2) / cos(theta / 2))
  380. */
  381. return 2.0f * atan2f(glm_quat_imaglen(q), glm_quat_real(q));
  382. }
  383. /*!
  384. * @brief axis of quaternion
  385. *
  386. * @param[in] q quaternion
  387. * @param[out] dest axis of quaternion
  388. */
  389. CGLM_INLINE
  390. void
  391. glm_quat_axis(versor q, vec3 dest) {
  392. glm_quat_imagn(q, dest);
  393. }
  394. /*!
  395. * @brief multiplies two quaternion and stores result in dest
  396. * this is also called Hamilton Product
  397. *
  398. * According to WikiPedia:
  399. * The product of two rotation quaternions [clarification needed] will be
  400. * equivalent to the rotation q followed by the rotation p
  401. *
  402. * @param[in] p quaternion 1
  403. * @param[in] q quaternion 2
  404. * @param[out] dest result quaternion
  405. */
  406. CGLM_INLINE
  407. void
  408. glm_quat_mul(versor p, versor q, versor dest) {
  409. /*
  410. + (a1 b2 + b1 a2 + c1 d2 − d1 c2)i
  411. + (a1 c2 − b1 d2 + c1 a2 + d1 b2)j
  412. + (a1 d2 + b1 c2 − c1 b2 + d1 a2)k
  413. a1 a2 − b1 b2 − c1 c2 − d1 d2
  414. */
  415. #if defined(__wasm__) && defined(__wasm_simd128__)
  416. glm_quat_mul_wasm(p, q, dest);
  417. #elif defined( __SSE__ ) || defined( __SSE2__ )
  418. glm_quat_mul_sse2(p, q, dest);
  419. #elif defined(CGLM_NEON_FP)
  420. glm_quat_mul_neon(p, q, dest);
  421. #else
  422. dest[0] = p[3] * q[0] + p[0] * q[3] + p[1] * q[2] - p[2] * q[1];
  423. dest[1] = p[3] * q[1] - p[0] * q[2] + p[1] * q[3] + p[2] * q[0];
  424. dest[2] = p[3] * q[2] + p[0] * q[1] - p[1] * q[0] + p[2] * q[3];
  425. dest[3] = p[3] * q[3] - p[0] * q[0] - p[1] * q[1] - p[2] * q[2];
  426. #endif
  427. }
  428. /*!
  429. * @brief convert quaternion to mat4
  430. *
  431. * @param[in] q quaternion
  432. * @param[out] dest result matrix
  433. */
  434. CGLM_INLINE
  435. void
  436. glm_quat_mat4(versor q, mat4 dest) {
  437. float w, x, y, z,
  438. xx, yy, zz,
  439. xy, yz, xz,
  440. wx, wy, wz, norm, s;
  441. norm = glm_quat_norm(q);
  442. s = norm > 0.0f ? 2.0f / norm : 0.0f;
  443. x = q[0];
  444. y = q[1];
  445. z = q[2];
  446. w = q[3];
  447. xx = s * x * x; xy = s * x * y; wx = s * w * x;
  448. yy = s * y * y; yz = s * y * z; wy = s * w * y;
  449. zz = s * z * z; xz = s * x * z; wz = s * w * z;
  450. dest[0][0] = 1.0f - yy - zz;
  451. dest[1][1] = 1.0f - xx - zz;
  452. dest[2][2] = 1.0f - xx - yy;
  453. dest[0][1] = xy + wz;
  454. dest[1][2] = yz + wx;
  455. dest[2][0] = xz + wy;
  456. dest[1][0] = xy - wz;
  457. dest[2][1] = yz - wx;
  458. dest[0][2] = xz - wy;
  459. dest[0][3] = 0.0f;
  460. dest[1][3] = 0.0f;
  461. dest[2][3] = 0.0f;
  462. dest[3][0] = 0.0f;
  463. dest[3][1] = 0.0f;
  464. dest[3][2] = 0.0f;
  465. dest[3][3] = 1.0f;
  466. }
  467. /*!
  468. * @brief convert quaternion to mat4 (transposed)
  469. *
  470. * @param[in] q quaternion
  471. * @param[out] dest result matrix as transposed
  472. */
  473. CGLM_INLINE
  474. void
  475. glm_quat_mat4t(versor q, mat4 dest) {
  476. float w, x, y, z,
  477. xx, yy, zz,
  478. xy, yz, xz,
  479. wx, wy, wz, norm, s;
  480. norm = glm_quat_norm(q);
  481. s = norm > 0.0f ? 2.0f / norm : 0.0f;
  482. x = q[0];
  483. y = q[1];
  484. z = q[2];
  485. w = q[3];
  486. xx = s * x * x; xy = s * x * y; wx = s * w * x;
  487. yy = s * y * y; yz = s * y * z; wy = s * w * y;
  488. zz = s * z * z; xz = s * x * z; wz = s * w * z;
  489. dest[0][0] = 1.0f - yy - zz;
  490. dest[1][1] = 1.0f - xx - zz;
  491. dest[2][2] = 1.0f - xx - yy;
  492. dest[1][0] = xy + wz;
  493. dest[2][1] = yz + wx;
  494. dest[0][2] = xz + wy;
  495. dest[0][1] = xy - wz;
  496. dest[1][2] = yz - wx;
  497. dest[2][0] = xz - wy;
  498. dest[0][3] = 0.0f;
  499. dest[1][3] = 0.0f;
  500. dest[2][3] = 0.0f;
  501. dest[3][0] = 0.0f;
  502. dest[3][1] = 0.0f;
  503. dest[3][2] = 0.0f;
  504. dest[3][3] = 1.0f;
  505. }
  506. /*!
  507. * @brief convert quaternion to mat3
  508. *
  509. * @param[in] q quaternion
  510. * @param[out] dest result matrix
  511. */
  512. CGLM_INLINE
  513. void
  514. glm_quat_mat3(versor q, mat3 dest) {
  515. float w, x, y, z,
  516. xx, yy, zz,
  517. xy, yz, xz,
  518. wx, wy, wz, norm, s;
  519. norm = glm_quat_norm(q);
  520. s = norm > 0.0f ? 2.0f / norm : 0.0f;
  521. x = q[0];
  522. y = q[1];
  523. z = q[2];
  524. w = q[3];
  525. xx = s * x * x; xy = s * x * y; wx = s * w * x;
  526. yy = s * y * y; yz = s * y * z; wy = s * w * y;
  527. zz = s * z * z; xz = s * x * z; wz = s * w * z;
  528. dest[0][0] = 1.0f - yy - zz;
  529. dest[1][1] = 1.0f - xx - zz;
  530. dest[2][2] = 1.0f - xx - yy;
  531. dest[0][1] = xy + wz;
  532. dest[1][2] = yz + wx;
  533. dest[2][0] = xz + wy;
  534. dest[1][0] = xy - wz;
  535. dest[2][1] = yz - wx;
  536. dest[0][2] = xz - wy;
  537. }
  538. /*!
  539. * @brief convert quaternion to mat3 (transposed)
  540. *
  541. * @param[in] q quaternion
  542. * @param[out] dest result matrix
  543. */
  544. CGLM_INLINE
  545. void
  546. glm_quat_mat3t(versor q, mat3 dest) {
  547. float w, x, y, z,
  548. xx, yy, zz,
  549. xy, yz, xz,
  550. wx, wy, wz, norm, s;
  551. norm = glm_quat_norm(q);
  552. s = norm > 0.0f ? 2.0f / norm : 0.0f;
  553. x = q[0];
  554. y = q[1];
  555. z = q[2];
  556. w = q[3];
  557. xx = s * x * x; xy = s * x * y; wx = s * w * x;
  558. yy = s * y * y; yz = s * y * z; wy = s * w * y;
  559. zz = s * z * z; xz = s * x * z; wz = s * w * z;
  560. dest[0][0] = 1.0f - yy - zz;
  561. dest[1][1] = 1.0f - xx - zz;
  562. dest[2][2] = 1.0f - xx - yy;
  563. dest[1][0] = xy + wz;
  564. dest[2][1] = yz + wx;
  565. dest[0][2] = xz + wy;
  566. dest[0][1] = xy - wz;
  567. dest[1][2] = yz - wx;
  568. dest[2][0] = xz - wy;
  569. }
  570. /*!
  571. * @brief interpolates between two quaternions
  572. * using linear interpolation (LERP)
  573. *
  574. * @param[in] from from
  575. * @param[in] to to
  576. * @param[in] t interpolant (amount)
  577. * @param[out] dest result quaternion
  578. */
  579. CGLM_INLINE
  580. void
  581. glm_quat_lerp(versor from, versor to, float t, versor dest) {
  582. glm_vec4_lerp(from, to, t, dest);
  583. }
  584. /*!
  585. * @brief interpolates between two quaternions
  586. * using linear interpolation (LERP)
  587. *
  588. * @param[in] from from
  589. * @param[in] to to
  590. * @param[in] t interpolant (amount) clamped between 0 and 1
  591. * @param[out] dest result quaternion
  592. */
  593. CGLM_INLINE
  594. void
  595. glm_quat_lerpc(versor from, versor to, float t, versor dest) {
  596. glm_vec4_lerpc(from, to, t, dest);
  597. }
  598. /*!
  599. * @brief interpolates between two quaternions
  600. * taking the shortest rotation path using
  601. * normalized linear interpolation (NLERP)
  602. *
  603. * @param[in] from from
  604. * @param[in] to to
  605. * @param[in] t interpolant (amount)
  606. * @param[out] dest result quaternion
  607. */
  608. CGLM_INLINE
  609. void
  610. glm_quat_nlerp(versor from, versor to, float t, versor dest) {
  611. versor target;
  612. float dot;
  613. dot = glm_vec4_dot(from, to);
  614. glm_vec4_scale(to, (dot >= 0) ? 1.0f : -1.0f, target);
  615. glm_quat_lerp(from, target, t, dest);
  616. glm_quat_normalize(dest);
  617. }
  618. /*!
  619. * @brief interpolates between two quaternions
  620. * using spherical linear interpolation (SLERP)
  621. *
  622. * @param[in] from from
  623. * @param[in] to to
  624. * @param[in] t amount
  625. * @param[out] dest result quaternion
  626. */
  627. CGLM_INLINE
  628. void
  629. glm_quat_slerp(versor from, versor to, float t, versor dest) {
  630. CGLM_ALIGN(16) vec4 q1, q2;
  631. float cosTheta, sinTheta, angle;
  632. cosTheta = glm_quat_dot(from, to);
  633. glm_quat_copy(from, q1);
  634. if (fabsf(cosTheta) >= 1.0f) {
  635. glm_quat_copy(q1, dest);
  636. return;
  637. }
  638. if (cosTheta < 0.0f) {
  639. glm_vec4_negate(q1);
  640. cosTheta = -cosTheta;
  641. }
  642. sinTheta = sqrtf(1.0f - cosTheta * cosTheta);
  643. /* LERP to avoid zero division */
  644. if (fabsf(sinTheta) < 0.001f) {
  645. glm_quat_lerp(from, to, t, dest);
  646. return;
  647. }
  648. /* SLERP */
  649. angle = acosf(cosTheta);
  650. glm_vec4_scale(q1, sinf((1.0f - t) * angle), q1);
  651. glm_vec4_scale(to, sinf(t * angle), q2);
  652. glm_vec4_add(q1, q2, q1);
  653. glm_vec4_scale(q1, 1.0f / sinTheta, dest);
  654. }
  655. /*!
  656. * @brief interpolates between two quaternions
  657. * using spherical linear interpolation (SLERP) and always takes the long path
  658. *
  659. * @param[in] from from
  660. * @param[in] to to
  661. * @param[in] t amount
  662. * @param[out] dest result quaternion
  663. */
  664. CGLM_INLINE
  665. void
  666. glm_quat_slerp_longest(versor from, versor to, float t, versor dest) {
  667. CGLM_ALIGN(16) vec4 q1, q2;
  668. float cosTheta, sinTheta, angle;
  669. cosTheta = glm_quat_dot(from, to);
  670. glm_quat_copy(from, q1);
  671. if (fabsf(cosTheta) >= 1.0f) {
  672. glm_quat_copy(q1, dest);
  673. return;
  674. }
  675. /* longest path */
  676. if (!(cosTheta < 0.0f)) {
  677. glm_vec4_negate(q1);
  678. cosTheta = -cosTheta;
  679. }
  680. sinTheta = sqrtf(1.0f - cosTheta * cosTheta);
  681. /* LERP to avoid zero division */
  682. if (fabsf(sinTheta) < 0.001f) {
  683. glm_quat_lerp(from, to, t, dest);
  684. return;
  685. }
  686. /* SLERP */
  687. angle = acosf(cosTheta);
  688. glm_vec4_scale(q1, sinf((1.0f - t) * angle), q1);
  689. glm_vec4_scale(to, sinf(t * angle), q2);
  690. glm_vec4_add(q1, q2, q1);
  691. glm_vec4_scale(q1, 1.0f / sinTheta, dest);
  692. }
  693. /*!
  694. * @brief creates view matrix using quaternion as camera orientation
  695. *
  696. * @param[in] eye eye
  697. * @param[in] ori orientation in world space as quaternion
  698. * @param[out] dest view matrix
  699. */
  700. CGLM_INLINE
  701. void
  702. glm_quat_look(vec3 eye, versor ori, mat4 dest) {
  703. /* orientation */
  704. glm_quat_mat4t(ori, dest);
  705. /* translate */
  706. glm_mat4_mulv3(dest, eye, 1.0f, dest[3]);
  707. glm_vec3_negate(dest[3]);
  708. }
  709. /*!
  710. * @brief creates look rotation quaternion
  711. *
  712. * @param[in] dir direction to look
  713. * @param[in] up up vector
  714. * @param[out] dest destination quaternion
  715. */
  716. CGLM_INLINE
  717. void
  718. glm_quat_for(vec3 dir, vec3 up, versor dest) {
  719. CGLM_ALIGN_MAT mat3 m;
  720. glm_vec3_normalize_to(dir, m[2]);
  721. /* No need to negate in LH, but we use RH here */
  722. glm_vec3_negate(m[2]);
  723. glm_vec3_crossn(up, m[2], m[0]);
  724. glm_vec3_cross(m[2], m[0], m[1]);
  725. glm_mat3_quat(m, dest);
  726. }
  727. /*!
  728. * @brief creates look rotation quaternion using source and
  729. * destination positions p suffix stands for position
  730. *
  731. * @param[in] from source point
  732. * @param[in] to destination point
  733. * @param[in] up up vector
  734. * @param[out] dest destination quaternion
  735. */
  736. CGLM_INLINE
  737. void
  738. glm_quat_forp(vec3 from, vec3 to, vec3 up, versor dest) {
  739. CGLM_ALIGN(8) vec3 dir;
  740. glm_vec3_sub(to, from, dir);
  741. glm_quat_for(dir, up, dest);
  742. }
  743. /*!
  744. * @brief rotate vector using using quaternion
  745. *
  746. * @param[in] q quaternion
  747. * @param[in] v vector to rotate
  748. * @param[out] dest rotated vector
  749. */
  750. CGLM_INLINE
  751. void
  752. glm_quat_rotatev(versor q, vec3 v, vec3 dest) {
  753. CGLM_ALIGN(16) versor p;
  754. CGLM_ALIGN(8) vec3 u, v1, v2;
  755. float s;
  756. glm_quat_normalize_to(q, p);
  757. glm_quat_imag(p, u);
  758. s = glm_quat_real(p);
  759. glm_vec3_scale(u, 2.0f * glm_vec3_dot(u, v), v1);
  760. glm_vec3_scale(v, s * s - glm_vec3_dot(u, u), v2);
  761. glm_vec3_add(v1, v2, v1);
  762. glm_vec3_cross(u, v, v2);
  763. glm_vec3_scale(v2, 2.0f * s, v2);
  764. glm_vec3_add(v1, v2, dest);
  765. }
  766. /*!
  767. * @brief rotate existing transform matrix using quaternion
  768. *
  769. * @param[in] m existing transform matrix
  770. * @param[in] q quaternion
  771. * @param[out] dest rotated matrix/transform
  772. */
  773. CGLM_INLINE
  774. void
  775. glm_quat_rotate(mat4 m, versor q, mat4 dest) {
  776. CGLM_ALIGN_MAT mat4 rot;
  777. glm_quat_mat4(q, rot);
  778. glm_mul_rot(m, rot, dest);
  779. }
  780. /*!
  781. * @brief rotate existing transform matrix using quaternion at pivot point
  782. *
  783. * @param[in, out] m existing transform matrix
  784. * @param[in] q quaternion
  785. * @param[out] pivot pivot
  786. */
  787. CGLM_INLINE
  788. void
  789. glm_quat_rotate_at(mat4 m, versor q, vec3 pivot) {
  790. CGLM_ALIGN(8) vec3 pivotInv;
  791. glm_vec3_negate_to(pivot, pivotInv);
  792. glm_translate(m, pivot);
  793. glm_quat_rotate(m, q, m);
  794. glm_translate(m, pivotInv);
  795. }
  796. /*!
  797. * @brief rotate NEW transform matrix using quaternion at pivot point
  798. *
  799. * this creates rotation matrix, it assumes you don't have a matrix
  800. *
  801. * this should work faster than glm_quat_rotate_at because it reduces
  802. * one glm_translate.
  803. *
  804. * @param[out] m existing transform matrix
  805. * @param[in] q quaternion
  806. * @param[in] pivot pivot
  807. */
  808. CGLM_INLINE
  809. void
  810. glm_quat_rotate_atm(mat4 m, versor q, vec3 pivot) {
  811. CGLM_ALIGN(8) vec3 pivotInv;
  812. glm_vec3_negate_to(pivot, pivotInv);
  813. glm_translate_make(m, pivot);
  814. glm_quat_rotate(m, q, m);
  815. glm_translate(m, pivotInv);
  816. }
  817. /*!
  818. * @brief Create quaternion from pointer
  819. *
  820. * @param[in] src pointer to an array of floats
  821. * @param[out] dest quaternion
  822. */
  823. CGLM_INLINE
  824. void
  825. glm_quat_make(const float * __restrict src, versor dest) {
  826. dest[0] = src[0]; dest[1] = src[1];
  827. dest[2] = src[2]; dest[3] = src[3];
  828. }
  829. #endif /* cglm_quat_h */