btQuaternion.h 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909
  1. /*
  2. Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/
  3. This software is provided 'as-is', without any express or implied warranty.
  4. In no event will the authors be held liable for any damages arising from the use of this software.
  5. Permission is granted to anyone to use this software for any purpose,
  6. including commercial applications, and to alter it and redistribute it freely,
  7. subject to the following restrictions:
  8. 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
  9. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  10. 3. This notice may not be removed or altered from any source distribution.
  11. */
  12. #ifndef BT_SIMD__QUATERNION_H_
  13. #define BT_SIMD__QUATERNION_H_
  14. #include "btVector3.h"
  15. #include "btQuadWord.h"
  16. #ifdef BT_USE_SSE
  17. //const __m128 ATTRIBUTE_ALIGNED16(vOnes) = {1.0f, 1.0f, 1.0f, 1.0f};
  18. #define vOnes (_mm_set_ps(1.0f, 1.0f, 1.0f, 1.0f))
  19. #endif
  20. #if defined(BT_USE_SSE)
  21. #define vQInv (_mm_set_ps(+0.0f, -0.0f, -0.0f, -0.0f))
  22. #define vPPPM (_mm_set_ps(-0.0f, +0.0f, +0.0f, +0.0f))
  23. #elif defined(BT_USE_NEON)
  24. const btSimdFloat4 ATTRIBUTE_ALIGNED16(vQInv) = {-0.0f, -0.0f, -0.0f, +0.0f};
  25. const btSimdFloat4 ATTRIBUTE_ALIGNED16(vPPPM) = {+0.0f, +0.0f, +0.0f, -0.0f};
  26. #endif
  27. /**@brief The btQuaternion implements quaternion to perform linear algebra rotations in combination with btMatrix3x3, btVector3 and btTransform. */
  28. class btQuaternion : public btQuadWord {
  29. public:
  30. /**@brief No initialization constructor */
  31. btQuaternion() {}
  32. #if (defined(BT_USE_SSE_IN_API) && defined(BT_USE_SSE))|| defined(BT_USE_NEON)
  33. // Set Vector
  34. SIMD_FORCE_INLINE btQuaternion(const btSimdFloat4 vec)
  35. {
  36. mVec128 = vec;
  37. }
  38. // Copy constructor
  39. SIMD_FORCE_INLINE btQuaternion(const btQuaternion& rhs)
  40. {
  41. mVec128 = rhs.mVec128;
  42. }
  43. // Assignment Operator
  44. SIMD_FORCE_INLINE btQuaternion&
  45. operator=(const btQuaternion& v)
  46. {
  47. mVec128 = v.mVec128;
  48. return *this;
  49. }
  50. #endif
  51. // template <typename btScalar>
  52. // explicit Quaternion(const btScalar *v) : Tuple4<btScalar>(v) {}
  53. /**@brief Constructor from scalars */
  54. btQuaternion(const btScalar& _x, const btScalar& _y, const btScalar& _z, const btScalar& _w)
  55. : btQuadWord(_x, _y, _z, _w)
  56. {}
  57. /**@brief Axis angle Constructor
  58. * @param axis The axis which the rotation is around
  59. * @param angle The magnitude of the rotation around the angle (Radians) */
  60. btQuaternion(const btVector3& _axis, const btScalar& _angle)
  61. {
  62. setRotation(_axis, _angle);
  63. }
  64. /**@brief Constructor from Euler angles
  65. * @param yaw Angle around Y unless BT_EULER_DEFAULT_ZYX defined then Z
  66. * @param pitch Angle around X unless BT_EULER_DEFAULT_ZYX defined then Y
  67. * @param roll Angle around Z unless BT_EULER_DEFAULT_ZYX defined then X */
  68. btQuaternion(const btScalar& yaw, const btScalar& pitch, const btScalar& roll)
  69. {
  70. #ifndef BT_EULER_DEFAULT_ZYX
  71. setEuler(yaw, pitch, roll);
  72. #else
  73. setEulerZYX(yaw, pitch, roll);
  74. #endif
  75. }
  76. /**@brief Set the rotation using axis angle notation
  77. * @param axis The axis around which to rotate
  78. * @param angle The magnitude of the rotation in Radians */
  79. void setRotation(const btVector3& axis, const btScalar& _angle)
  80. {
  81. btScalar d = axis.length();
  82. btAssert(d != btScalar(0.0));
  83. btScalar s = btSin(_angle * btScalar(0.5)) / d;
  84. setValue(axis.x() * s, axis.y() * s, axis.z() * s,
  85. btCos(_angle * btScalar(0.5)));
  86. }
  87. /**@brief Set the quaternion using Euler angles
  88. * @param yaw Angle around Y
  89. * @param pitch Angle around X
  90. * @param roll Angle around Z */
  91. void setEuler(const btScalar& yaw, const btScalar& pitch, const btScalar& roll)
  92. {
  93. btScalar halfYaw = btScalar(yaw) * btScalar(0.5);
  94. btScalar halfPitch = btScalar(pitch) * btScalar(0.5);
  95. btScalar halfRoll = btScalar(roll) * btScalar(0.5);
  96. btScalar cosYaw = btCos(halfYaw);
  97. btScalar sinYaw = btSin(halfYaw);
  98. btScalar cosPitch = btCos(halfPitch);
  99. btScalar sinPitch = btSin(halfPitch);
  100. btScalar cosRoll = btCos(halfRoll);
  101. btScalar sinRoll = btSin(halfRoll);
  102. setValue(cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw,
  103. cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw,
  104. sinRoll * cosPitch * cosYaw - cosRoll * sinPitch * sinYaw,
  105. cosRoll * cosPitch * cosYaw + sinRoll * sinPitch * sinYaw);
  106. }
  107. /**@brief Set the quaternion using euler angles
  108. * @param yaw Angle around Z
  109. * @param pitch Angle around Y
  110. * @param roll Angle around X */
  111. void setEulerZYX(const btScalar& yaw, const btScalar& pitch, const btScalar& roll)
  112. {
  113. btScalar halfYaw = btScalar(yaw) * btScalar(0.5);
  114. btScalar halfPitch = btScalar(pitch) * btScalar(0.5);
  115. btScalar halfRoll = btScalar(roll) * btScalar(0.5);
  116. btScalar cosYaw = btCos(halfYaw);
  117. btScalar sinYaw = btSin(halfYaw);
  118. btScalar cosPitch = btCos(halfPitch);
  119. btScalar sinPitch = btSin(halfPitch);
  120. btScalar cosRoll = btCos(halfRoll);
  121. btScalar sinRoll = btSin(halfRoll);
  122. setValue(sinRoll * cosPitch * cosYaw - cosRoll * sinPitch * sinYaw, //x
  123. cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw, //y
  124. cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw, //z
  125. cosRoll * cosPitch * cosYaw + sinRoll * sinPitch * sinYaw); //formerly yzx
  126. }
  127. /**@brief Add two quaternions
  128. * @param q The quaternion to add to this one */
  129. SIMD_FORCE_INLINE btQuaternion& operator+=(const btQuaternion& q)
  130. {
  131. #if defined (BT_USE_SSE_IN_API) && defined (BT_USE_SSE)
  132. mVec128 = _mm_add_ps(mVec128, q.mVec128);
  133. #elif defined(BT_USE_NEON)
  134. mVec128 = vaddq_f32(mVec128, q.mVec128);
  135. #else
  136. m_floats[0] += q.x();
  137. m_floats[1] += q.y();
  138. m_floats[2] += q.z();
  139. m_floats[3] += q.m_floats[3];
  140. #endif
  141. return *this;
  142. }
  143. /**@brief Subtract out a quaternion
  144. * @param q The quaternion to subtract from this one */
  145. btQuaternion& operator-=(const btQuaternion& q)
  146. {
  147. #if defined (BT_USE_SSE_IN_API) && defined (BT_USE_SSE)
  148. mVec128 = _mm_sub_ps(mVec128, q.mVec128);
  149. #elif defined(BT_USE_NEON)
  150. mVec128 = vsubq_f32(mVec128, q.mVec128);
  151. #else
  152. m_floats[0] -= q.x();
  153. m_floats[1] -= q.y();
  154. m_floats[2] -= q.z();
  155. m_floats[3] -= q.m_floats[3];
  156. #endif
  157. return *this;
  158. }
  159. /**@brief Scale this quaternion
  160. * @param s The scalar to scale by */
  161. btQuaternion& operator*=(const btScalar& s)
  162. {
  163. #if defined (BT_USE_SSE_IN_API) && defined (BT_USE_SSE)
  164. __m128 vs = _mm_load_ss(&s); // (S 0 0 0)
  165. vs = bt_pshufd_ps(vs, 0); // (S S S S)
  166. mVec128 = _mm_mul_ps(mVec128, vs);
  167. #elif defined(BT_USE_NEON)
  168. mVec128 = vmulq_n_f32(mVec128, s);
  169. #else
  170. m_floats[0] *= s;
  171. m_floats[1] *= s;
  172. m_floats[2] *= s;
  173. m_floats[3] *= s;
  174. #endif
  175. return *this;
  176. }
  177. /**@brief Multiply this quaternion by q on the right
  178. * @param q The other quaternion
  179. * Equivilant to this = this * q */
  180. btQuaternion& operator*=(const btQuaternion& q)
  181. {
  182. #if defined (BT_USE_SSE_IN_API) && defined (BT_USE_SSE)
  183. __m128 vQ2 = q.get128();
  184. __m128 A1 = bt_pshufd_ps(mVec128, BT_SHUFFLE(0,1,2,0));
  185. __m128 B1 = bt_pshufd_ps(vQ2, BT_SHUFFLE(3,3,3,0));
  186. A1 = A1 * B1;
  187. __m128 A2 = bt_pshufd_ps(mVec128, BT_SHUFFLE(1,2,0,1));
  188. __m128 B2 = bt_pshufd_ps(vQ2, BT_SHUFFLE(2,0,1,1));
  189. A2 = A2 * B2;
  190. B1 = bt_pshufd_ps(mVec128, BT_SHUFFLE(2,0,1,2));
  191. B2 = bt_pshufd_ps(vQ2, BT_SHUFFLE(1,2,0,2));
  192. B1 = B1 * B2; // A3 *= B3
  193. mVec128 = bt_splat_ps(mVec128, 3); // A0
  194. mVec128 = mVec128 * vQ2; // A0 * B0
  195. A1 = A1 + A2; // AB12
  196. mVec128 = mVec128 - B1; // AB03 = AB0 - AB3
  197. A1 = _mm_xor_ps(A1, vPPPM); // change sign of the last element
  198. mVec128 = mVec128+ A1; // AB03 + AB12
  199. #elif defined(BT_USE_NEON)
  200. float32x4_t vQ1 = mVec128;
  201. float32x4_t vQ2 = q.get128();
  202. float32x4_t A0, A1, B1, A2, B2, A3, B3;
  203. float32x2_t vQ1zx, vQ2wx, vQ1yz, vQ2zx, vQ2yz, vQ2xz;
  204. {
  205. float32x2x2_t tmp;
  206. tmp = vtrn_f32( vget_high_f32(vQ1), vget_low_f32(vQ1) ); // {z x}, {w y}
  207. vQ1zx = tmp.val[0];
  208. tmp = vtrn_f32( vget_high_f32(vQ2), vget_low_f32(vQ2) ); // {z x}, {w y}
  209. vQ2zx = tmp.val[0];
  210. }
  211. vQ2wx = vext_f32(vget_high_f32(vQ2), vget_low_f32(vQ2), 1);
  212. vQ1yz = vext_f32(vget_low_f32(vQ1), vget_high_f32(vQ1), 1);
  213. vQ2yz = vext_f32(vget_low_f32(vQ2), vget_high_f32(vQ2), 1);
  214. vQ2xz = vext_f32(vQ2zx, vQ2zx, 1);
  215. A1 = vcombine_f32(vget_low_f32(vQ1), vQ1zx); // X Y z x
  216. B1 = vcombine_f32(vdup_lane_f32(vget_high_f32(vQ2), 1), vQ2wx); // W W W X
  217. A2 = vcombine_f32(vQ1yz, vget_low_f32(vQ1));
  218. B2 = vcombine_f32(vQ2zx, vdup_lane_f32(vget_low_f32(vQ2), 1));
  219. A3 = vcombine_f32(vQ1zx, vQ1yz); // Z X Y Z
  220. B3 = vcombine_f32(vQ2yz, vQ2xz); // Y Z x z
  221. A1 = vmulq_f32(A1, B1);
  222. A2 = vmulq_f32(A2, B2);
  223. A3 = vmulq_f32(A3, B3); // A3 *= B3
  224. A0 = vmulq_lane_f32(vQ2, vget_high_f32(vQ1), 1); // A0 * B0
  225. A1 = vaddq_f32(A1, A2); // AB12 = AB1 + AB2
  226. A0 = vsubq_f32(A0, A3); // AB03 = AB0 - AB3
  227. // change the sign of the last element
  228. A1 = (btSimdFloat4)veorq_s32((int32x4_t)A1, (int32x4_t)vPPPM);
  229. A0 = vaddq_f32(A0, A1); // AB03 + AB12
  230. mVec128 = A0;
  231. #else
  232. setValue(
  233. m_floats[3] * q.x() + m_floats[0] * q.m_floats[3] + m_floats[1] * q.z() - m_floats[2] * q.y(),
  234. m_floats[3] * q.y() + m_floats[1] * q.m_floats[3] + m_floats[2] * q.x() - m_floats[0] * q.z(),
  235. m_floats[3] * q.z() + m_floats[2] * q.m_floats[3] + m_floats[0] * q.y() - m_floats[1] * q.x(),
  236. m_floats[3] * q.m_floats[3] - m_floats[0] * q.x() - m_floats[1] * q.y() - m_floats[2] * q.z());
  237. #endif
  238. return *this;
  239. }
  240. /**@brief Return the dot product between this quaternion and another
  241. * @param q The other quaternion */
  242. btScalar dot(const btQuaternion& q) const
  243. {
  244. #if defined BT_USE_SIMD_VECTOR3 && defined (BT_USE_SSE_IN_API) && defined (BT_USE_SSE)
  245. __m128 vd;
  246. vd = _mm_mul_ps(mVec128, q.mVec128);
  247. __m128 t = _mm_movehl_ps(vd, vd);
  248. vd = _mm_add_ps(vd, t);
  249. t = _mm_shuffle_ps(vd, vd, 0x55);
  250. vd = _mm_add_ss(vd, t);
  251. return _mm_cvtss_f32(vd);
  252. #elif defined(BT_USE_NEON)
  253. float32x4_t vd = vmulq_f32(mVec128, q.mVec128);
  254. float32x2_t x = vpadd_f32(vget_low_f32(vd), vget_high_f32(vd));
  255. x = vpadd_f32(x, x);
  256. return vget_lane_f32(x, 0);
  257. #else
  258. return m_floats[0] * q.x() +
  259. m_floats[1] * q.y() +
  260. m_floats[2] * q.z() +
  261. m_floats[3] * q.m_floats[3];
  262. #endif
  263. }
  264. /**@brief Return the length squared of the quaternion */
  265. btScalar length2() const
  266. {
  267. return dot(*this);
  268. }
  269. /**@brief Return the length of the quaternion */
  270. btScalar length() const
  271. {
  272. return btSqrt(length2());
  273. }
  274. /**@brief Normalize the quaternion
  275. * Such that x^2 + y^2 + z^2 +w^2 = 1 */
  276. btQuaternion& normalize()
  277. {
  278. #if defined (BT_USE_SSE_IN_API) && defined (BT_USE_SSE)
  279. __m128 vd;
  280. vd = _mm_mul_ps(mVec128, mVec128);
  281. __m128 t = _mm_movehl_ps(vd, vd);
  282. vd = _mm_add_ps(vd, t);
  283. t = _mm_shuffle_ps(vd, vd, 0x55);
  284. vd = _mm_add_ss(vd, t);
  285. vd = _mm_sqrt_ss(vd);
  286. vd = _mm_div_ss(vOnes, vd);
  287. vd = bt_pshufd_ps(vd, 0); // splat
  288. mVec128 = _mm_mul_ps(mVec128, vd);
  289. return *this;
  290. #else
  291. return *this /= length();
  292. #endif
  293. }
  294. /**@brief Return a scaled version of this quaternion
  295. * @param s The scale factor */
  296. SIMD_FORCE_INLINE btQuaternion
  297. operator*(const btScalar& s) const
  298. {
  299. #if defined (BT_USE_SSE_IN_API) && defined (BT_USE_SSE)
  300. __m128 vs = _mm_load_ss(&s); // (S 0 0 0)
  301. vs = bt_pshufd_ps(vs, 0x00); // (S S S S)
  302. return btQuaternion(_mm_mul_ps(mVec128, vs));
  303. #elif defined(BT_USE_NEON)
  304. return btQuaternion(vmulq_n_f32(mVec128, s));
  305. #else
  306. return btQuaternion(x() * s, y() * s, z() * s, m_floats[3] * s);
  307. #endif
  308. }
  309. /**@brief Return an inversely scaled versionof this quaternion
  310. * @param s The inverse scale factor */
  311. btQuaternion operator/(const btScalar& s) const
  312. {
  313. btAssert(s != btScalar(0.0));
  314. return *this * (btScalar(1.0) / s);
  315. }
  316. /**@brief Inversely scale this quaternion
  317. * @param s The scale factor */
  318. btQuaternion& operator/=(const btScalar& s)
  319. {
  320. btAssert(s != btScalar(0.0));
  321. return *this *= btScalar(1.0) / s;
  322. }
  323. /**@brief Return a normalized version of this quaternion */
  324. btQuaternion normalized() const
  325. {
  326. return *this / length();
  327. }
  328. /**@brief Return the ***half*** angle between this quaternion and the other
  329. * @param q The other quaternion */
  330. btScalar angle(const btQuaternion& q) const
  331. {
  332. btScalar s = btSqrt(length2() * q.length2());
  333. btAssert(s != btScalar(0.0));
  334. return btAcos(dot(q) / s);
  335. }
  336. /**@brief Return the angle between this quaternion and the other along the shortest path
  337. * @param q The other quaternion */
  338. btScalar angleShortestPath(const btQuaternion& q) const
  339. {
  340. btScalar s = btSqrt(length2() * q.length2());
  341. btAssert(s != btScalar(0.0));
  342. if (dot(q) < 0) // Take care of long angle case see http://en.wikipedia.org/wiki/Slerp
  343. return btAcos(dot(-q) / s) * btScalar(2.0);
  344. else
  345. return btAcos(dot(q) / s) * btScalar(2.0);
  346. }
  347. /**@brief Return the angle of rotation represented by this quaternion */
  348. btScalar getAngle() const
  349. {
  350. btScalar s = btScalar(2.) * btAcos(m_floats[3]);
  351. return s;
  352. }
  353. /**@brief Return the angle of rotation represented by this quaternion along the shortest path*/
  354. btScalar getAngleShortestPath() const
  355. {
  356. btScalar s;
  357. if (dot(*this) < 0)
  358. s = btScalar(2.) * btAcos(m_floats[3]);
  359. else
  360. s = btScalar(2.) * btAcos(-m_floats[3]);
  361. return s;
  362. }
  363. /**@brief Return the axis of the rotation represented by this quaternion */
  364. btVector3 getAxis() const
  365. {
  366. btScalar s_squared = 1.f-m_floats[3]*m_floats[3];
  367. if (s_squared < btScalar(10.) * SIMD_EPSILON) //Check for divide by zero
  368. return btVector3(1.0, 0.0, 0.0); // Arbitrary
  369. btScalar s = 1.f/btSqrt(s_squared);
  370. return btVector3(m_floats[0] * s, m_floats[1] * s, m_floats[2] * s);
  371. }
  372. /**@brief Return the inverse of this quaternion */
  373. btQuaternion inverse() const
  374. {
  375. #if defined (BT_USE_SSE_IN_API) && defined (BT_USE_SSE)
  376. return btQuaternion(_mm_xor_ps(mVec128, vQInv));
  377. #elif defined(BT_USE_NEON)
  378. return btQuaternion((btSimdFloat4)veorq_s32((int32x4_t)mVec128, (int32x4_t)vQInv));
  379. #else
  380. return btQuaternion(-m_floats[0], -m_floats[1], -m_floats[2], m_floats[3]);
  381. #endif
  382. }
  383. /**@brief Return the sum of this quaternion and the other
  384. * @param q2 The other quaternion */
  385. SIMD_FORCE_INLINE btQuaternion
  386. operator+(const btQuaternion& q2) const
  387. {
  388. #if defined (BT_USE_SSE_IN_API) && defined (BT_USE_SSE)
  389. return btQuaternion(_mm_add_ps(mVec128, q2.mVec128));
  390. #elif defined(BT_USE_NEON)
  391. return btQuaternion(vaddq_f32(mVec128, q2.mVec128));
  392. #else
  393. const btQuaternion& q1 = *this;
  394. return btQuaternion(q1.x() + q2.x(), q1.y() + q2.y(), q1.z() + q2.z(), q1.m_floats[3] + q2.m_floats[3]);
  395. #endif
  396. }
  397. /**@brief Return the difference between this quaternion and the other
  398. * @param q2 The other quaternion */
  399. SIMD_FORCE_INLINE btQuaternion
  400. operator-(const btQuaternion& q2) const
  401. {
  402. #if defined (BT_USE_SSE_IN_API) && defined (BT_USE_SSE)
  403. return btQuaternion(_mm_sub_ps(mVec128, q2.mVec128));
  404. #elif defined(BT_USE_NEON)
  405. return btQuaternion(vsubq_f32(mVec128, q2.mVec128));
  406. #else
  407. const btQuaternion& q1 = *this;
  408. return btQuaternion(q1.x() - q2.x(), q1.y() - q2.y(), q1.z() - q2.z(), q1.m_floats[3] - q2.m_floats[3]);
  409. #endif
  410. }
  411. /**@brief Return the negative of this quaternion
  412. * This simply negates each element */
  413. SIMD_FORCE_INLINE btQuaternion operator-() const
  414. {
  415. #if defined (BT_USE_SSE_IN_API) && defined (BT_USE_SSE)
  416. return btQuaternion(_mm_xor_ps(mVec128, btvMzeroMask));
  417. #elif defined(BT_USE_NEON)
  418. return btQuaternion((btSimdFloat4)veorq_s32((int32x4_t)mVec128, (int32x4_t)btvMzeroMask) );
  419. #else
  420. const btQuaternion& q2 = *this;
  421. return btQuaternion( - q2.x(), - q2.y(), - q2.z(), - q2.m_floats[3]);
  422. #endif
  423. }
  424. /**@todo document this and it's use */
  425. SIMD_FORCE_INLINE btQuaternion farthest( const btQuaternion& qd) const
  426. {
  427. btQuaternion diff,sum;
  428. diff = *this - qd;
  429. sum = *this + qd;
  430. if( diff.dot(diff) > sum.dot(sum) )
  431. return qd;
  432. return (-qd);
  433. }
  434. /**@todo document this and it's use */
  435. SIMD_FORCE_INLINE btQuaternion nearest( const btQuaternion& qd) const
  436. {
  437. btQuaternion diff,sum;
  438. diff = *this - qd;
  439. sum = *this + qd;
  440. if( diff.dot(diff) < sum.dot(sum) )
  441. return qd;
  442. return (-qd);
  443. }
  444. /**@brief Return the quaternion which is the result of Spherical Linear Interpolation between this and the other quaternion
  445. * @param q The other quaternion to interpolate with
  446. * @param t The ratio between this and q to interpolate. If t = 0 the result is this, if t=1 the result is q.
  447. * Slerp interpolates assuming constant velocity. */
  448. btQuaternion slerp(const btQuaternion& q, const btScalar& t) const
  449. {
  450. btScalar magnitude = btSqrt(length2() * q.length2());
  451. btAssert(magnitude > btScalar(0));
  452. btScalar product = dot(q) / magnitude;
  453. if (btFabs(product) < btScalar(1))
  454. {
  455. // Take care of long angle case see http://en.wikipedia.org/wiki/Slerp
  456. const btScalar sign = (product < 0) ? btScalar(-1) : btScalar(1);
  457. const btScalar theta = btAcos(sign * product);
  458. const btScalar s1 = btSin(sign * t * theta);
  459. const btScalar d = btScalar(1.0) / btSin(theta);
  460. const btScalar s0 = btSin((btScalar(1.0) - t) * theta);
  461. return btQuaternion(
  462. (m_floats[0] * s0 + q.x() * s1) * d,
  463. (m_floats[1] * s0 + q.y() * s1) * d,
  464. (m_floats[2] * s0 + q.z() * s1) * d,
  465. (m_floats[3] * s0 + q.m_floats[3] * s1) * d);
  466. }
  467. else
  468. {
  469. return *this;
  470. }
  471. }
  472. static const btQuaternion& getIdentity()
  473. {
  474. static const btQuaternion identityQuat(btScalar(0.),btScalar(0.),btScalar(0.),btScalar(1.));
  475. return identityQuat;
  476. }
  477. SIMD_FORCE_INLINE const btScalar& getW() const { return m_floats[3]; }
  478. };
  479. /**@brief Return the product of two quaternions */
  480. SIMD_FORCE_INLINE btQuaternion
  481. operator*(const btQuaternion& q1, const btQuaternion& q2)
  482. {
  483. #if defined (BT_USE_SSE_IN_API) && defined (BT_USE_SSE)
  484. __m128 vQ1 = q1.get128();
  485. __m128 vQ2 = q2.get128();
  486. __m128 A0, A1, B1, A2, B2;
  487. A1 = bt_pshufd_ps(vQ1, BT_SHUFFLE(0,1,2,0)); // X Y z x // vtrn
  488. B1 = bt_pshufd_ps(vQ2, BT_SHUFFLE(3,3,3,0)); // W W W X // vdup vext
  489. A1 = A1 * B1;
  490. A2 = bt_pshufd_ps(vQ1, BT_SHUFFLE(1,2,0,1)); // Y Z X Y // vext
  491. B2 = bt_pshufd_ps(vQ2, BT_SHUFFLE(2,0,1,1)); // z x Y Y // vtrn vdup
  492. A2 = A2 * B2;
  493. B1 = bt_pshufd_ps(vQ1, BT_SHUFFLE(2,0,1,2)); // z x Y Z // vtrn vext
  494. B2 = bt_pshufd_ps(vQ2, BT_SHUFFLE(1,2,0,2)); // Y Z x z // vext vtrn
  495. B1 = B1 * B2; // A3 *= B3
  496. A0 = bt_splat_ps(vQ1, 3); // A0
  497. A0 = A0 * vQ2; // A0 * B0
  498. A1 = A1 + A2; // AB12
  499. A0 = A0 - B1; // AB03 = AB0 - AB3
  500. A1 = _mm_xor_ps(A1, vPPPM); // change sign of the last element
  501. A0 = A0 + A1; // AB03 + AB12
  502. return btQuaternion(A0);
  503. #elif defined(BT_USE_NEON)
  504. float32x4_t vQ1 = q1.get128();
  505. float32x4_t vQ2 = q2.get128();
  506. float32x4_t A0, A1, B1, A2, B2, A3, B3;
  507. float32x2_t vQ1zx, vQ2wx, vQ1yz, vQ2zx, vQ2yz, vQ2xz;
  508. {
  509. float32x2x2_t tmp;
  510. tmp = vtrn_f32( vget_high_f32(vQ1), vget_low_f32(vQ1) ); // {z x}, {w y}
  511. vQ1zx = tmp.val[0];
  512. tmp = vtrn_f32( vget_high_f32(vQ2), vget_low_f32(vQ2) ); // {z x}, {w y}
  513. vQ2zx = tmp.val[0];
  514. }
  515. vQ2wx = vext_f32(vget_high_f32(vQ2), vget_low_f32(vQ2), 1);
  516. vQ1yz = vext_f32(vget_low_f32(vQ1), vget_high_f32(vQ1), 1);
  517. vQ2yz = vext_f32(vget_low_f32(vQ2), vget_high_f32(vQ2), 1);
  518. vQ2xz = vext_f32(vQ2zx, vQ2zx, 1);
  519. A1 = vcombine_f32(vget_low_f32(vQ1), vQ1zx); // X Y z x
  520. B1 = vcombine_f32(vdup_lane_f32(vget_high_f32(vQ2), 1), vQ2wx); // W W W X
  521. A2 = vcombine_f32(vQ1yz, vget_low_f32(vQ1));
  522. B2 = vcombine_f32(vQ2zx, vdup_lane_f32(vget_low_f32(vQ2), 1));
  523. A3 = vcombine_f32(vQ1zx, vQ1yz); // Z X Y Z
  524. B3 = vcombine_f32(vQ2yz, vQ2xz); // Y Z x z
  525. A1 = vmulq_f32(A1, B1);
  526. A2 = vmulq_f32(A2, B2);
  527. A3 = vmulq_f32(A3, B3); // A3 *= B3
  528. A0 = vmulq_lane_f32(vQ2, vget_high_f32(vQ1), 1); // A0 * B0
  529. A1 = vaddq_f32(A1, A2); // AB12 = AB1 + AB2
  530. A0 = vsubq_f32(A0, A3); // AB03 = AB0 - AB3
  531. // change the sign of the last element
  532. A1 = (btSimdFloat4)veorq_s32((int32x4_t)A1, (int32x4_t)vPPPM);
  533. A0 = vaddq_f32(A0, A1); // AB03 + AB12
  534. return btQuaternion(A0);
  535. #else
  536. return btQuaternion(
  537. q1.w() * q2.x() + q1.x() * q2.w() + q1.y() * q2.z() - q1.z() * q2.y(),
  538. q1.w() * q2.y() + q1.y() * q2.w() + q1.z() * q2.x() - q1.x() * q2.z(),
  539. q1.w() * q2.z() + q1.z() * q2.w() + q1.x() * q2.y() - q1.y() * q2.x(),
  540. q1.w() * q2.w() - q1.x() * q2.x() - q1.y() * q2.y() - q1.z() * q2.z());
  541. #endif
  542. }
  543. SIMD_FORCE_INLINE btQuaternion
  544. operator*(const btQuaternion& q, const btVector3& w)
  545. {
  546. #if defined (BT_USE_SSE_IN_API) && defined (BT_USE_SSE)
  547. __m128 vQ1 = q.get128();
  548. __m128 vQ2 = w.get128();
  549. __m128 A1, B1, A2, B2, A3, B3;
  550. A1 = bt_pshufd_ps(vQ1, BT_SHUFFLE(3,3,3,0));
  551. B1 = bt_pshufd_ps(vQ2, BT_SHUFFLE(0,1,2,0));
  552. A1 = A1 * B1;
  553. A2 = bt_pshufd_ps(vQ1, BT_SHUFFLE(1,2,0,1));
  554. B2 = bt_pshufd_ps(vQ2, BT_SHUFFLE(2,0,1,1));
  555. A2 = A2 * B2;
  556. A3 = bt_pshufd_ps(vQ1, BT_SHUFFLE(2,0,1,2));
  557. B3 = bt_pshufd_ps(vQ2, BT_SHUFFLE(1,2,0,2));
  558. A3 = A3 * B3; // A3 *= B3
  559. A1 = A1 + A2; // AB12
  560. A1 = _mm_xor_ps(A1, vPPPM); // change sign of the last element
  561. A1 = A1 - A3; // AB123 = AB12 - AB3
  562. return btQuaternion(A1);
  563. #elif defined(BT_USE_NEON)
  564. float32x4_t vQ1 = q.get128();
  565. float32x4_t vQ2 = w.get128();
  566. float32x4_t A1, B1, A2, B2, A3, B3;
  567. float32x2_t vQ1wx, vQ2zx, vQ1yz, vQ2yz, vQ1zx, vQ2xz;
  568. vQ1wx = vext_f32(vget_high_f32(vQ1), vget_low_f32(vQ1), 1);
  569. {
  570. float32x2x2_t tmp;
  571. tmp = vtrn_f32( vget_high_f32(vQ2), vget_low_f32(vQ2) ); // {z x}, {w y}
  572. vQ2zx = tmp.val[0];
  573. tmp = vtrn_f32( vget_high_f32(vQ1), vget_low_f32(vQ1) ); // {z x}, {w y}
  574. vQ1zx = tmp.val[0];
  575. }
  576. vQ1yz = vext_f32(vget_low_f32(vQ1), vget_high_f32(vQ1), 1);
  577. vQ2yz = vext_f32(vget_low_f32(vQ2), vget_high_f32(vQ2), 1);
  578. vQ2xz = vext_f32(vQ2zx, vQ2zx, 1);
  579. A1 = vcombine_f32(vdup_lane_f32(vget_high_f32(vQ1), 1), vQ1wx); // W W W X
  580. B1 = vcombine_f32(vget_low_f32(vQ2), vQ2zx); // X Y z x
  581. A2 = vcombine_f32(vQ1yz, vget_low_f32(vQ1));
  582. B2 = vcombine_f32(vQ2zx, vdup_lane_f32(vget_low_f32(vQ2), 1));
  583. A3 = vcombine_f32(vQ1zx, vQ1yz); // Z X Y Z
  584. B3 = vcombine_f32(vQ2yz, vQ2xz); // Y Z x z
  585. A1 = vmulq_f32(A1, B1);
  586. A2 = vmulq_f32(A2, B2);
  587. A3 = vmulq_f32(A3, B3); // A3 *= B3
  588. A1 = vaddq_f32(A1, A2); // AB12 = AB1 + AB2
  589. // change the sign of the last element
  590. A1 = (btSimdFloat4)veorq_s32((int32x4_t)A1, (int32x4_t)vPPPM);
  591. A1 = vsubq_f32(A1, A3); // AB123 = AB12 - AB3
  592. return btQuaternion(A1);
  593. #else
  594. return btQuaternion(
  595. q.w() * w.x() + q.y() * w.z() - q.z() * w.y(),
  596. q.w() * w.y() + q.z() * w.x() - q.x() * w.z(),
  597. q.w() * w.z() + q.x() * w.y() - q.y() * w.x(),
  598. -q.x() * w.x() - q.y() * w.y() - q.z() * w.z());
  599. #endif
  600. }
  601. SIMD_FORCE_INLINE btQuaternion
  602. operator*(const btVector3& w, const btQuaternion& q)
  603. {
  604. #if defined (BT_USE_SSE_IN_API) && defined (BT_USE_SSE)
  605. __m128 vQ1 = w.get128();
  606. __m128 vQ2 = q.get128();
  607. __m128 A1, B1, A2, B2, A3, B3;
  608. A1 = bt_pshufd_ps(vQ1, BT_SHUFFLE(0,1,2,0)); // X Y z x
  609. B1 = bt_pshufd_ps(vQ2, BT_SHUFFLE(3,3,3,0)); // W W W X
  610. A1 = A1 * B1;
  611. A2 = bt_pshufd_ps(vQ1, BT_SHUFFLE(1,2,0,1));
  612. B2 = bt_pshufd_ps(vQ2, BT_SHUFFLE(2,0,1,1));
  613. A2 = A2 *B2;
  614. A3 = bt_pshufd_ps(vQ1, BT_SHUFFLE(2,0,1,2));
  615. B3 = bt_pshufd_ps(vQ2, BT_SHUFFLE(1,2,0,2));
  616. A3 = A3 * B3; // A3 *= B3
  617. A1 = A1 + A2; // AB12
  618. A1 = _mm_xor_ps(A1, vPPPM); // change sign of the last element
  619. A1 = A1 - A3; // AB123 = AB12 - AB3
  620. return btQuaternion(A1);
  621. #elif defined(BT_USE_NEON)
  622. float32x4_t vQ1 = w.get128();
  623. float32x4_t vQ2 = q.get128();
  624. float32x4_t A1, B1, A2, B2, A3, B3;
  625. float32x2_t vQ1zx, vQ2wx, vQ1yz, vQ2zx, vQ2yz, vQ2xz;
  626. {
  627. float32x2x2_t tmp;
  628. tmp = vtrn_f32( vget_high_f32(vQ1), vget_low_f32(vQ1) ); // {z x}, {w y}
  629. vQ1zx = tmp.val[0];
  630. tmp = vtrn_f32( vget_high_f32(vQ2), vget_low_f32(vQ2) ); // {z x}, {w y}
  631. vQ2zx = tmp.val[0];
  632. }
  633. vQ2wx = vext_f32(vget_high_f32(vQ2), vget_low_f32(vQ2), 1);
  634. vQ1yz = vext_f32(vget_low_f32(vQ1), vget_high_f32(vQ1), 1);
  635. vQ2yz = vext_f32(vget_low_f32(vQ2), vget_high_f32(vQ2), 1);
  636. vQ2xz = vext_f32(vQ2zx, vQ2zx, 1);
  637. A1 = vcombine_f32(vget_low_f32(vQ1), vQ1zx); // X Y z x
  638. B1 = vcombine_f32(vdup_lane_f32(vget_high_f32(vQ2), 1), vQ2wx); // W W W X
  639. A2 = vcombine_f32(vQ1yz, vget_low_f32(vQ1));
  640. B2 = vcombine_f32(vQ2zx, vdup_lane_f32(vget_low_f32(vQ2), 1));
  641. A3 = vcombine_f32(vQ1zx, vQ1yz); // Z X Y Z
  642. B3 = vcombine_f32(vQ2yz, vQ2xz); // Y Z x z
  643. A1 = vmulq_f32(A1, B1);
  644. A2 = vmulq_f32(A2, B2);
  645. A3 = vmulq_f32(A3, B3); // A3 *= B3
  646. A1 = vaddq_f32(A1, A2); // AB12 = AB1 + AB2
  647. // change the sign of the last element
  648. A1 = (btSimdFloat4)veorq_s32((int32x4_t)A1, (int32x4_t)vPPPM);
  649. A1 = vsubq_f32(A1, A3); // AB123 = AB12 - AB3
  650. return btQuaternion(A1);
  651. #else
  652. return btQuaternion(
  653. +w.x() * q.w() + w.y() * q.z() - w.z() * q.y(),
  654. +w.y() * q.w() + w.z() * q.x() - w.x() * q.z(),
  655. +w.z() * q.w() + w.x() * q.y() - w.y() * q.x(),
  656. -w.x() * q.x() - w.y() * q.y() - w.z() * q.z());
  657. #endif
  658. }
  659. /**@brief Calculate the dot product between two quaternions */
  660. SIMD_FORCE_INLINE btScalar
  661. dot(const btQuaternion& q1, const btQuaternion& q2)
  662. {
  663. return q1.dot(q2);
  664. }
  665. /**@brief Return the length of a quaternion */
  666. SIMD_FORCE_INLINE btScalar
  667. length(const btQuaternion& q)
  668. {
  669. return q.length();
  670. }
  671. /**@brief Return the angle between two quaternions*/
  672. SIMD_FORCE_INLINE btScalar
  673. btAngle(const btQuaternion& q1, const btQuaternion& q2)
  674. {
  675. return q1.angle(q2);
  676. }
  677. /**@brief Return the inverse of a quaternion*/
  678. SIMD_FORCE_INLINE btQuaternion
  679. inverse(const btQuaternion& q)
  680. {
  681. return q.inverse();
  682. }
  683. /**@brief Return the result of spherical linear interpolation betwen two quaternions
  684. * @param q1 The first quaternion
  685. * @param q2 The second quaternion
  686. * @param t The ration between q1 and q2. t = 0 return q1, t=1 returns q2
  687. * Slerp assumes constant velocity between positions. */
  688. SIMD_FORCE_INLINE btQuaternion
  689. slerp(const btQuaternion& q1, const btQuaternion& q2, const btScalar& t)
  690. {
  691. return q1.slerp(q2, t);
  692. }
  693. SIMD_FORCE_INLINE btVector3
  694. quatRotate(const btQuaternion& rotation, const btVector3& v)
  695. {
  696. btQuaternion q = rotation * v;
  697. q *= rotation.inverse();
  698. #if defined BT_USE_SIMD_VECTOR3 && defined (BT_USE_SSE_IN_API) && defined (BT_USE_SSE)
  699. return btVector3(_mm_and_ps(q.get128(), btvFFF0fMask));
  700. #elif defined(BT_USE_NEON)
  701. return btVector3((float32x4_t)vandq_s32((int32x4_t)q.get128(), btvFFF0Mask));
  702. #else
  703. return btVector3(q.getX(),q.getY(),q.getZ());
  704. #endif
  705. }
  706. SIMD_FORCE_INLINE btQuaternion
  707. shortestArcQuat(const btVector3& v0, const btVector3& v1) // Game Programming Gems 2.10. make sure v0,v1 are normalized
  708. {
  709. btVector3 c = v0.cross(v1);
  710. btScalar d = v0.dot(v1);
  711. if (d < -1.0 + SIMD_EPSILON)
  712. {
  713. btVector3 n,unused;
  714. btPlaneSpace1(v0,n,unused);
  715. return btQuaternion(n.x(),n.y(),n.z(),0.0f); // just pick any vector that is orthogonal to v0
  716. }
  717. btScalar s = btSqrt((1.0f + d) * 2.0f);
  718. btScalar rs = 1.0f / s;
  719. return btQuaternion(c.getX()*rs,c.getY()*rs,c.getZ()*rs,s * 0.5f);
  720. }
  721. SIMD_FORCE_INLINE btQuaternion
  722. shortestArcQuatNormalize2(btVector3& v0,btVector3& v1)
  723. {
  724. v0.normalize();
  725. v1.normalize();
  726. return shortestArcQuat(v0,v1);
  727. }
  728. #endif //BT_SIMD__QUATERNION_H_