/opencollada/Externals/lib3ds/src/lib3ds_quat.c

https://github.com/AsherBond/MondocosmOS · C · 298 lines · 192 code · 50 blank · 56 comment · 22 complexity · 6d4fc8d49e0934f3c681def7f480fcb0 MD5 · raw file

  1. /*
  2. Copyright (C) 1996-2008 by Jan Eric Kyprianidis <www.kyprianidis.com>
  3. All rights reserved.
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published
  6. by the Free Software Foundation, either version 2.1 of the License, or
  7. (at your option) any later version.
  8. Thisprogram is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License
  13. along with this program; If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. /** @file lib3ds_quat.c
  16. Quaternion mathematics implementation */
  17. #include "lib3ds_impl.h"
  18. /*!
  19. * Set a quaternion to Identity
  20. */
  21. void
  22. lib3ds_quat_identity(float c[4]) {
  23. c[0] = c[1] = c[2] = 0.0f;
  24. c[3] = 1.0f;
  25. }
  26. /*!
  27. * Copy a quaternion.
  28. */
  29. void
  30. lib3ds_quat_copy(float dest[4], float src[4]) {
  31. int i;
  32. for (i = 0; i < 4; ++i) {
  33. dest[i] = src[i];
  34. }
  35. }
  36. /*!
  37. * Compute a quaternion from axis and angle.
  38. *
  39. * \param c Computed quaternion
  40. * \param axis Rotation axis
  41. * \param angle Angle of rotation, radians.
  42. */
  43. void
  44. lib3ds_quat_axis_angle(float c[4], float axis[3], float angle) {
  45. double omega, s;
  46. double l;
  47. l = sqrt(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]);
  48. if (l < LIB3DS_EPSILON) {
  49. c[0] = c[1] = c[2] = 0.0f;
  50. c[3] = 1.0f;
  51. } else {
  52. omega = -0.5 * angle;
  53. s = sin(omega) / l;
  54. c[0] = (float)s * axis[0];
  55. c[1] = (float)s * axis[1];
  56. c[2] = (float)s * axis[2];
  57. c[3] = (float)cos(omega);
  58. }
  59. }
  60. /*!
  61. * Negate a quaternion
  62. */
  63. void
  64. lib3ds_quat_neg(float c[4]) {
  65. int i;
  66. for (i = 0; i < 4; ++i) {
  67. c[i] = -c[i];
  68. }
  69. }
  70. /*!
  71. * Compute the conjugate of a quaternion
  72. */
  73. void
  74. lib3ds_quat_cnj(float c[4]) {
  75. int i;
  76. for (i = 0; i < 3; ++i) {
  77. c[i] = -c[i];
  78. }
  79. }
  80. /*!
  81. * Multiply two quaternions.
  82. *
  83. * \param c Result
  84. * \param a,b Inputs
  85. */
  86. void
  87. lib3ds_quat_mul(float c[4], float a[4], float b[4]) {
  88. float qa[4], qb[4];
  89. lib3ds_quat_copy(qa, a);
  90. lib3ds_quat_copy(qb, b);
  91. c[0] = qa[3] * qb[0] + qa[0] * qb[3] + qa[1] * qb[2] - qa[2] * qb[1];
  92. c[1] = qa[3] * qb[1] + qa[1] * qb[3] + qa[2] * qb[0] - qa[0] * qb[2];
  93. c[2] = qa[3] * qb[2] + qa[2] * qb[3] + qa[0] * qb[1] - qa[1] * qb[0];
  94. c[3] = qa[3] * qb[3] - qa[0] * qb[0] - qa[1] * qb[1] - qa[2] * qb[2];
  95. }
  96. /*!
  97. * Multiply a quaternion by a scalar.
  98. */
  99. void
  100. lib3ds_quat_scalar(float c[4], float k) {
  101. int i;
  102. for (i = 0; i < 4; ++i) {
  103. c[i] *= k;
  104. }
  105. }
  106. /*!
  107. * Normalize a quaternion.
  108. */
  109. void
  110. lib3ds_quat_normalize(float c[4]) {
  111. double l, m;
  112. l = sqrt(c[0] * c[0] + c[1] * c[1] + c[2] * c[2] + c[3] * c[3]);
  113. if (fabs(l) < LIB3DS_EPSILON) {
  114. c[0] = c[1] = c[2] = 0.0f;
  115. c[3] = 1.0f;
  116. } else {
  117. int i;
  118. m = 1.0f / l;
  119. for (i = 0; i < 4; ++i) {
  120. c[i] = (float)(c[i] * m);
  121. }
  122. }
  123. }
  124. /*!
  125. * Compute the inverse of a quaternion.
  126. */
  127. void
  128. lib3ds_quat_inv(float c[4]) {
  129. double l, m;
  130. l = sqrt(c[0] * c[0] + c[1] * c[1] + c[2] * c[2] + c[3] * c[3]);
  131. if (fabs(l) < LIB3DS_EPSILON) {
  132. c[0] = c[1] = c[2] = 0.0f;
  133. c[3] = 1.0f;
  134. } else {
  135. m = 1.0f / l;
  136. c[0] = (float)(-c[0] * m);
  137. c[1] = (float)(-c[1] * m);
  138. c[2] = (float)(-c[2] * m);
  139. c[3] = (float)(c[3] * m);
  140. }
  141. }
  142. /*!
  143. * Compute the dot-product of a quaternion.
  144. */
  145. float
  146. lib3ds_quat_dot(float a[4], float b[4]) {
  147. return(a[0]*b[0] + a[1]*b[1] + a[2]*b[2] + a[3]*b[3]);
  148. }
  149. float
  150. lib3ds_quat_norm(float c[4]) {
  151. return(c[0]*c[0] + c[1]*c[1] + c[2]*c[2] + c[3]*c[3]);
  152. }
  153. void
  154. lib3ds_quat_ln(float c[4]) {
  155. double om, s, t;
  156. s = sqrt(c[0] * c[0] + c[1] * c[1] + c[2] * c[2]);
  157. om = atan2(s, (double)c[3]);
  158. if (fabs(s) < LIB3DS_EPSILON) {
  159. t = 0.0f;
  160. } else {
  161. t = om / s;
  162. }
  163. {
  164. int i;
  165. for (i = 0; i < 3; ++i) {
  166. c[i] = (float)(c[i] * t);
  167. }
  168. c[3] = 0.0f;
  169. }
  170. }
  171. void
  172. lib3ds_quat_ln_dif(float c[4], float a[4], float b[4]) {
  173. float invp[4];
  174. lib3ds_quat_copy(invp, a);
  175. lib3ds_quat_inv(invp);
  176. lib3ds_quat_mul(c, invp, b);
  177. lib3ds_quat_ln(c);
  178. }
  179. void
  180. lib3ds_quat_exp(float c[4]) {
  181. double om, sinom;
  182. om = sqrt(c[0] * c[0] + c[1] * c[1] + c[2] * c[2]);
  183. if (fabs(om) < LIB3DS_EPSILON) {
  184. sinom = 1.0f;
  185. } else {
  186. sinom = sin(om) / om;
  187. }
  188. {
  189. int i;
  190. for (i = 0; i < 3; ++i) {
  191. c[i] = (float)(c[i] * sinom);
  192. }
  193. c[3] = (float)cos(om);
  194. }
  195. }
  196. void
  197. lib3ds_quat_slerp(float c[4], float a[4], float b[4], float t) {
  198. double l;
  199. double om, sinom;
  200. double sp, sq;
  201. float flip = 1.0f;
  202. int i;
  203. l = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
  204. if (l < 0) {
  205. flip = -1.0f;
  206. l = -l;
  207. }
  208. om = acos(l);
  209. sinom = sin(om);
  210. if (fabs(sinom) > LIB3DS_EPSILON) {
  211. sp = sin((1.0f - t) * om) / sinom;
  212. sq = sin(t * om) / sinom;
  213. } else {
  214. sp = 1.0f - t;
  215. sq = t;
  216. }
  217. sq *= flip;
  218. for (i = 0; i < 4; ++i) {
  219. c[i] = (float)(sp * a[i] + sq * b[i]);
  220. }
  221. }
  222. void
  223. lib3ds_quat_squad(float c[4], float a[4], float p[4], float q[4], float b[4], float t) {
  224. float ab[4];
  225. float pq[4];
  226. lib3ds_quat_slerp(ab, a, b, t);
  227. lib3ds_quat_slerp(pq, p, q, t);
  228. lib3ds_quat_slerp(c, ab, pq, 2*t*(1 - t));
  229. }
  230. void
  231. lib3ds_quat_tangent(float c[4], float p[4], float q[4], float n[4]) {
  232. float dn[4], dp[4], x[4];
  233. int i;
  234. lib3ds_quat_ln_dif(dn, q, n);
  235. lib3ds_quat_ln_dif(dp, q, p);
  236. for (i = 0; i < 4; i++) {
  237. x[i] = -1.0f / 4.0f * (dn[i] + dp[i]);
  238. }
  239. lib3ds_quat_exp(x);
  240. lib3ds_quat_mul(c, q, x);
  241. }
  242. void
  243. lib3ds_quat_dump(float q[4]) {
  244. printf("%f %f %f %f\n", q[0], q[1], q[2], q[3]);
  245. }