1/// @ref gtc_quaternion 2/// @file glm/gtc/quaternion.inl 3 4#include "../trigonometric.hpp" 5#include "../geometric.hpp" 6#include "../exponential.hpp" 7#include <limits> 8 9namespace glm{ 10namespace detail 11{ 12 template <typename T, precision P, bool Aligned> 13 struct compute_dot<tquat, T, P, Aligned> 14 { 15 static GLM_FUNC_QUALIFIER T call(tquat<T, P> const& x, tquat<T, P> const& y) 16 { 17 tvec4<T, P> tmp(x.x * y.x, x.y * y.y, x.z * y.z, x.w * y.w); 18 return (tmp.x + tmp.y) + (tmp.z + tmp.w); 19 } 20 }; 21 22 template <typename T, precision P, bool Aligned> 23 struct compute_quat_add 24 { 25 static tquat<T, P> call(tquat<T, P> const& q, tquat<T, P> const& p) 26 { 27 return tquat<T, P>(q.w + p.w, q.x + p.x, q.y + p.y, q.z + p.z); 28 } 29 }; 30 31 template <typename T, precision P, bool Aligned> 32 struct compute_quat_sub 33 { 34 static tquat<T, P> call(tquat<T, P> const& q, tquat<T, P> const& p) 35 { 36 return tquat<T, P>(q.w - p.w, q.x - p.x, q.y - p.y, q.z - p.z); 37 } 38 }; 39 40 template <typename T, precision P, bool Aligned> 41 struct compute_quat_mul_scalar 42 { 43 static tquat<T, P> call(tquat<T, P> const& q, T s) 44 { 45 return tquat<T, P>(q.w * s, q.x * s, q.y * s, q.z * s); 46 } 47 }; 48 49 template <typename T, precision P, bool Aligned> 50 struct compute_quat_div_scalar 51 { 52 static tquat<T, P> call(tquat<T, P> const& q, T s) 53 { 54 return tquat<T, P>(q.w / s, q.x / s, q.y / s, q.z / s); 55 } 56 }; 57 58 template <typename T, precision P, bool Aligned> 59 struct compute_quat_mul_vec4 60 { 61 static tvec4<T, P> call(tquat<T, P> const & q, tvec4<T, P> const & v) 62 { 63 return tvec4<T, P>(q * tvec3<T, P>(v), v.w); 64 } 65 }; 66}//namespace detail 67 68 // -- Component accesses -- 69 70 template <typename T, precision P> 71 GLM_FUNC_QUALIFIER T & tquat<T, P>::operator[](typename tquat<T, P>::length_type i) 72 { 73 assert(i >= 0 && i < this->length()); 74 return (&x)[i]; 75 } 76 77 template <typename T, precision P> 78 GLM_FUNC_QUALIFIER T const & tquat<T, P>::operator[](typename tquat<T, P>::length_type i) const 79 { 80 assert(i >= 0 && i < this->length()); 81 return (&x)[i]; 82 } 83 84 // -- Implicit basic constructors -- 85 86# if !GLM_HAS_DEFAULTED_FUNCTIONS || !defined(GLM_FORCE_NO_CTOR_INIT) 87 template <typename T, precision P> 88 GLM_FUNC_QUALIFIER GLM_CONSTEXPR tquat<T, P>::tquat() 89# ifndef GLM_FORCE_NO_CTOR_INIT 90 : x(0), y(0), z(0), w(1) 91# endif 92 {} 93# endif 94 95# if !GLM_HAS_DEFAULTED_FUNCTIONS 96 template <typename T, precision P> 97 GLM_FUNC_QUALIFIER GLM_CONSTEXPR tquat<T, P>::tquat(tquat<T, P> const & q) 98 : x(q.x), y(q.y), z(q.z), w(q.w) 99 {} 100# endif//!GLM_HAS_DEFAULTED_FUNCTIONS 101 102 template <typename T, precision P> 103 template <precision Q> 104 GLM_FUNC_QUALIFIER GLM_CONSTEXPR tquat<T, P>::tquat(tquat<T, Q> const & q) 105 : x(q.x), y(q.y), z(q.z), w(q.w) 106 {} 107 108 // -- Explicit basic constructors -- 109 110 template <typename T, precision P> 111 GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tquat<T, P>::tquat(ctor) 112 {} 113 114 template <typename T, precision P> 115 GLM_FUNC_QUALIFIER GLM_CONSTEXPR tquat<T, P>::tquat(T const & s, tvec3<T, P> const & v) 116 : x(v.x), y(v.y), z(v.z), w(s) 117 {} 118 119 template <typename T, precision P> 120 GLM_FUNC_QUALIFIER GLM_CONSTEXPR tquat<T, P>::tquat(T const & w, T const & x, T const & y, T const & z) 121 : x(x), y(y), z(z), w(w) 122 {} 123 124 // -- Conversion constructors -- 125 126 template <typename T, precision P> 127 template <typename U, precision Q> 128 GLM_FUNC_QUALIFIER GLM_CONSTEXPR tquat<T, P>::tquat(tquat<U, Q> const & q) 129 : x(static_cast<T>(q.x)) 130 , y(static_cast<T>(q.y)) 131 , z(static_cast<T>(q.z)) 132 , w(static_cast<T>(q.w)) 133 {} 134 135 //template <typename valType> 136 //GLM_FUNC_QUALIFIER tquat<valType>::tquat 137 //( 138 // valType const & pitch, 139 // valType const & yaw, 140 // valType const & roll 141 //) 142 //{ 143 // tvec3<valType> eulerAngle(pitch * valType(0.5), yaw * valType(0.5), roll * valType(0.5)); 144 // tvec3<valType> c = glm::cos(eulerAngle * valType(0.5)); 145 // tvec3<valType> s = glm::sin(eulerAngle * valType(0.5)); 146 // 147 // this->w = c.x * c.y * c.z + s.x * s.y * s.z; 148 // this->x = s.x * c.y * c.z - c.x * s.y * s.z; 149 // this->y = c.x * s.y * c.z + s.x * c.y * s.z; 150 // this->z = c.x * c.y * s.z - s.x * s.y * c.z; 151 //} 152 153 template <typename T, precision P> 154 GLM_FUNC_QUALIFIER tquat<T, P>::tquat(tvec3<T, P> const & u, tvec3<T, P> const & v) 155 { 156 tvec3<T, P> const LocalW(cross(u, v)); 157 T Dot = detail::compute_dot<tvec3, T, P, detail::is_aligned<P>::value>::call(u, v); 158 tquat<T, P> q(T(1) + Dot, LocalW.x, LocalW.y, LocalW.z); 159 160 *this = normalize(q); 161 } 162 163 template <typename T, precision P> 164 GLM_FUNC_QUALIFIER tquat<T, P>::tquat(tvec3<T, P> const & eulerAngle) 165 { 166 tvec3<T, P> c = glm::cos(eulerAngle * T(0.5)); 167 tvec3<T, P> s = glm::sin(eulerAngle * T(0.5)); 168 169 this->w = c.x * c.y * c.z + s.x * s.y * s.z; 170 this->x = s.x * c.y * c.z - c.x * s.y * s.z; 171 this->y = c.x * s.y * c.z + s.x * c.y * s.z; 172 this->z = c.x * c.y * s.z - s.x * s.y * c.z; 173 } 174 175 template <typename T, precision P> 176 GLM_FUNC_QUALIFIER tquat<T, P>::tquat(tmat3x3<T, P> const & m) 177 { 178 *this = quat_cast(m); 179 } 180 181 template <typename T, precision P> 182 GLM_FUNC_QUALIFIER tquat<T, P>::tquat(tmat4x4<T, P> const & m) 183 { 184 *this = quat_cast(m); 185 } 186 187# if GLM_HAS_EXPLICIT_CONVERSION_OPERATORS 188 template <typename T, precision P> 189 GLM_FUNC_QUALIFIER tquat<T, P>::operator tmat3x3<T, P>() 190 { 191 return mat3_cast(*this); 192 } 193 194 template <typename T, precision P> 195 GLM_FUNC_QUALIFIER tquat<T, P>::operator tmat4x4<T, P>() 196 { 197 return mat4_cast(*this); 198 } 199# endif//GLM_HAS_EXPLICIT_CONVERSION_OPERATORS 200 201 template <typename T, precision P> 202 GLM_FUNC_QUALIFIER tquat<T, P> conjugate(tquat<T, P> const & q) 203 { 204 return tquat<T, P>(q.w, -q.x, -q.y, -q.z); 205 } 206 207 template <typename T, precision P> 208 GLM_FUNC_QUALIFIER tquat<T, P> inverse(tquat<T, P> const & q) 209 { 210 return conjugate(q) / dot(q, q); 211 } 212 213 // -- Unary arithmetic operators -- 214 215# if !GLM_HAS_DEFAULTED_FUNCTIONS 216 template <typename T, precision P> 217 GLM_FUNC_QUALIFIER tquat<T, P> & tquat<T, P>::operator=(tquat<T, P> const & q) 218 { 219 this->w = q.w; 220 this->x = q.x; 221 this->y = q.y; 222 this->z = q.z; 223 return *this; 224 } 225# endif//!GLM_HAS_DEFAULTED_FUNCTIONS 226 227 template <typename T, precision P> 228 template <typename U> 229 GLM_FUNC_QUALIFIER tquat<T, P> & tquat<T, P>::operator=(tquat<U, P> const & q) 230 { 231 this->w = static_cast<T>(q.w); 232 this->x = static_cast<T>(q.x); 233 this->y = static_cast<T>(q.y); 234 this->z = static_cast<T>(q.z); 235 return *this; 236 } 237 238 template <typename T, precision P> 239 template <typename U> 240 GLM_FUNC_QUALIFIER tquat<T, P> & tquat<T, P>::operator+=(tquat<U, P> const& q) 241 { 242 return (*this = detail::compute_quat_add<T, P, detail::is_aligned<P>::value>::call(*this, tquat<T, P>(q))); 243 } 244 245 template <typename T, precision P> 246 template <typename U> 247 GLM_FUNC_QUALIFIER tquat<T, P> & tquat<T, P>::operator-=(tquat<U, P> const& q) 248 { 249 return (*this = detail::compute_quat_sub<T, P, detail::is_aligned<P>::value>::call(*this, tquat<T, P>(q))); 250 } 251 252 template <typename T, precision P> 253 template <typename U> 254 GLM_FUNC_QUALIFIER tquat<T, P> & tquat<T, P>::operator*=(tquat<U, P> const & r) 255 { 256 tquat<T, P> const p(*this); 257 tquat<T, P> const q(r); 258 259 this->w = p.w * q.w - p.x * q.x - p.y * q.y - p.z * q.z; 260 this->x = p.w * q.x + p.x * q.w + p.y * q.z - p.z * q.y; 261 this->y = p.w * q.y + p.y * q.w + p.z * q.x - p.x * q.z; 262 this->z = p.w * q.z + p.z * q.w + p.x * q.y - p.y * q.x; 263 return *this; 264 } 265 266 template <typename T, precision P> 267 template <typename U> 268 GLM_FUNC_QUALIFIER tquat<T, P> & tquat<T, P>::operator*=(U s) 269 { 270 return (*this = detail::compute_quat_mul_scalar<T, P, detail::is_aligned<P>::value>::call(*this, static_cast<U>(s))); 271 } 272 273 template <typename T, precision P> 274 template <typename U> 275 GLM_FUNC_QUALIFIER tquat<T, P> & tquat<T, P>::operator/=(U s) 276 { 277 return (*this = detail::compute_quat_div_scalar<T, P, detail::is_aligned<P>::value>::call(*this, static_cast<U>(s))); 278 } 279 280 // -- Unary bit operators -- 281 282 template <typename T, precision P> 283 GLM_FUNC_QUALIFIER tquat<T, P> operator+(tquat<T, P> const & q) 284 { 285 return q; 286 } 287 288 template <typename T, precision P> 289 GLM_FUNC_QUALIFIER tquat<T, P> operator-(tquat<T, P> const & q) 290 { 291 return tquat<T, P>(-q.w, -q.x, -q.y, -q.z); 292 } 293 294 // -- Binary operators -- 295 296 template <typename T, precision P> 297 GLM_FUNC_QUALIFIER tquat<T, P> operator+(tquat<T, P> const & q, tquat<T, P> const & p) 298 { 299 return tquat<T, P>(q) += p; 300 } 301 302 template <typename T, precision P> 303 GLM_FUNC_QUALIFIER tquat<T, P> operator*(tquat<T, P> const & q, tquat<T, P> const & p) 304 { 305 return tquat<T, P>(q) *= p; 306 } 307 308 template <typename T, precision P> 309 GLM_FUNC_QUALIFIER tvec3<T, P> operator*(tquat<T, P> const & q, tvec3<T, P> const & v) 310 { 311 tvec3<T, P> const QuatVector(q.x, q.y, q.z); 312 tvec3<T, P> const uv(glm::cross(QuatVector, v)); 313 tvec3<T, P> const uuv(glm::cross(QuatVector, uv)); 314 315 return v + ((uv * q.w) + uuv) * static_cast<T>(2); 316 } 317 318 template <typename T, precision P> 319 GLM_FUNC_QUALIFIER tvec3<T, P> operator*(tvec3<T, P> const & v, tquat<T, P> const & q) 320 { 321 return glm::inverse(q) * v; 322 } 323 324 template <typename T, precision P> 325 GLM_FUNC_QUALIFIER tvec4<T, P> operator*(tquat<T, P> const& q, tvec4<T, P> const& v) 326 { 327 return detail::compute_quat_mul_vec4<T, P, detail::is_aligned<P>::value>::call(q, v); 328 } 329 330 template <typename T, precision P> 331 GLM_FUNC_QUALIFIER tvec4<T, P> operator*(tvec4<T, P> const & v, tquat<T, P> const & q) 332 { 333 return glm::inverse(q) * v; 334 } 335 336 template <typename T, precision P> 337 GLM_FUNC_QUALIFIER tquat<T, P> operator*(tquat<T, P> const & q, T const & s) 338 { 339 return tquat<T, P>( 340 q.w * s, q.x * s, q.y * s, q.z * s); 341 } 342 343 template <typename T, precision P> 344 GLM_FUNC_QUALIFIER tquat<T, P> operator*(T const & s, tquat<T, P> const & q) 345 { 346 return q * s; 347 } 348 349 template <typename T, precision P> 350 GLM_FUNC_QUALIFIER tquat<T, P> operator/(tquat<T, P> const & q, T const & s) 351 { 352 return tquat<T, P>( 353 q.w / s, q.x / s, q.y / s, q.z / s); 354 } 355 356 // -- Boolean operators -- 357 358 template <typename T, precision P> 359 GLM_FUNC_QUALIFIER bool operator==(tquat<T, P> const & q1, tquat<T, P> const & q2) 360 { 361 return (q1.x == q2.x) && (q1.y == q2.y) && (q1.z == q2.z) && (q1.w == q2.w); 362 } 363 364 template <typename T, precision P> 365 GLM_FUNC_QUALIFIER bool operator!=(tquat<T, P> const & q1, tquat<T, P> const & q2) 366 { 367 return (q1.x != q2.x) || (q1.y != q2.y) || (q1.z != q2.z) || (q1.w != q2.w); 368 } 369 370 // -- Operations -- 371 372 template <typename T, precision P> 373 GLM_FUNC_QUALIFIER T length(tquat<T, P> const & q) 374 { 375 return glm::sqrt(dot(q, q)); 376 } 377 378 template <typename T, precision P> 379 GLM_FUNC_QUALIFIER tquat<T, P> normalize(tquat<T, P> const & q) 380 { 381 T len = length(q); 382 if(len <= T(0)) // Problem 383 return tquat<T, P>(1, 0, 0, 0); 384 T oneOverLen = T(1) / len; 385 return tquat<T, P>(q.w * oneOverLen, q.x * oneOverLen, q.y * oneOverLen, q.z * oneOverLen); 386 } 387 388 template <typename T, precision P> 389 GLM_FUNC_QUALIFIER tquat<T, P> cross(tquat<T, P> const & q1, tquat<T, P> const & q2) 390 { 391 return tquat<T, P>( 392 q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z, 393 q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y, 394 q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z, 395 q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x); 396 } 397/* 398 // (x * sin(1 - a) * angle / sin(angle)) + (y * sin(a) * angle / sin(angle)) 399 template <typename T, precision P> 400 GLM_FUNC_QUALIFIER tquat<T, P> mix(tquat<T, P> const & x, tquat<T, P> const & y, T const & a) 401 { 402 if(a <= T(0)) return x; 403 if(a >= T(1)) return y; 404 405 float fCos = dot(x, y); 406 tquat<T, P> y2(y); //BUG!!! tquat<T, P> y2; 407 if(fCos < T(0)) 408 { 409 y2 = -y; 410 fCos = -fCos; 411 } 412 413 //if(fCos > 1.0f) // problem 414 float k0, k1; 415 if(fCos > T(0.9999)) 416 { 417 k0 = T(1) - a; 418 k1 = T(0) + a; //BUG!!! 1.0f + a; 419 } 420 else 421 { 422 T fSin = sqrt(T(1) - fCos * fCos); 423 T fAngle = atan(fSin, fCos); 424 T fOneOverSin = static_cast<T>(1) / fSin; 425 k0 = sin((T(1) - a) * fAngle) * fOneOverSin; 426 k1 = sin((T(0) + a) * fAngle) * fOneOverSin; 427 } 428 429 return tquat<T, P>( 430 k0 * x.w + k1 * y2.w, 431 k0 * x.x + k1 * y2.x, 432 k0 * x.y + k1 * y2.y, 433 k0 * x.z + k1 * y2.z); 434 } 435 436 template <typename T, precision P> 437 GLM_FUNC_QUALIFIER tquat<T, P> mix2 438 ( 439 tquat<T, P> const & x, 440 tquat<T, P> const & y, 441 T const & a 442 ) 443 { 444 bool flip = false; 445 if(a <= static_cast<T>(0)) return x; 446 if(a >= static_cast<T>(1)) return y; 447 448 T cos_t = dot(x, y); 449 if(cos_t < T(0)) 450 { 451 cos_t = -cos_t; 452 flip = true; 453 } 454 455 T alpha(0), beta(0); 456 457 if(T(1) - cos_t < 1e-7) 458 beta = static_cast<T>(1) - alpha; 459 else 460 { 461 T theta = acos(cos_t); 462 T sin_t = sin(theta); 463 beta = sin(theta * (T(1) - alpha)) / sin_t; 464 alpha = sin(alpha * theta) / sin_t; 465 } 466 467 if(flip) 468 alpha = -alpha; 469 470 return normalize(beta * x + alpha * y); 471 } 472*/ 473 474 template <typename T, precision P> 475 GLM_FUNC_QUALIFIER tquat<T, P> mix(tquat<T, P> const & x, tquat<T, P> const & y, T a) 476 { 477 T cosTheta = dot(x, y); 478 479 // Perform a linear interpolation when cosTheta is close to 1 to avoid side effect of sin(angle) becoming a zero denominator 480 if(cosTheta > T(1) - epsilon<T>()) 481 { 482 // Linear interpolation 483 return tquat<T, P>( 484 mix(x.w, y.w, a), 485 mix(x.x, y.x, a), 486 mix(x.y, y.y, a), 487 mix(x.z, y.z, a)); 488 } 489 else 490 { 491 // Essential Mathematics, page 467 492 T angle = acos(cosTheta); 493 return (sin((T(1) - a) * angle) * x + sin(a * angle) * y) / sin(angle); 494 } 495 } 496 497 template <typename T, precision P> 498 GLM_FUNC_QUALIFIER tquat<T, P> lerp(tquat<T, P> const & x, tquat<T, P> const & y, T a) 499 { 500 // Lerp is only defined in [0, 1] 501 assert(a >= static_cast<T>(0)); 502 assert(a <= static_cast<T>(1)); 503 504 return x * (T(1) - a) + (y * a); 505 } 506 507 template <typename T, precision P> 508 GLM_FUNC_QUALIFIER tquat<T, P> slerp(tquat<T, P> const & x, tquat<T, P> const & y, T a) 509 { 510 tquat<T, P> z = y; 511 512 T cosTheta = dot(x, y); 513 514 // If cosTheta < 0, the interpolation will take the long way around the sphere. 515 // To fix this, one quat must be negated. 516 if (cosTheta < T(0)) 517 { 518 z = -y; 519 cosTheta = -cosTheta; 520 } 521 522 // Perform a linear interpolation when cosTheta is close to 1 to avoid side effect of sin(angle) becoming a zero denominator 523 if(cosTheta > T(1) - epsilon<T>()) 524 { 525 // Linear interpolation 526 return tquat<T, P>( 527 mix(x.w, z.w, a), 528 mix(x.x, z.x, a), 529 mix(x.y, z.y, a), 530 mix(x.z, z.z, a)); 531 } 532 else 533 { 534 // Essential Mathematics, page 467 535 T angle = acos(cosTheta); 536 return (sin((T(1) - a) * angle) * x + sin(a * angle) * z) / sin(angle); 537 } 538 } 539 540 template <typename T, precision P> 541 GLM_FUNC_QUALIFIER tquat<T, P> rotate(tquat<T, P> const & q, T const & angle, tvec3<T, P> const & v) 542 { 543 tvec3<T, P> Tmp = v; 544 545 // Axis of rotation must be normalised 546 T len = glm::length(Tmp); 547 if(abs(len - T(1)) > T(0.001)) 548 { 549 T oneOverLen = static_cast<T>(1) / len; 550 Tmp.x *= oneOverLen; 551 Tmp.y *= oneOverLen; 552 Tmp.z *= oneOverLen; 553 } 554 555 T const AngleRad(angle); 556 T const Sin = sin(AngleRad * T(0.5)); 557 558 return q * tquat<T, P>(cos(AngleRad * T(0.5)), Tmp.x * Sin, Tmp.y * Sin, Tmp.z * Sin); 559 //return gtc::quaternion::cross(q, tquat<T, P>(cos(AngleRad * T(0.5)), Tmp.x * fSin, Tmp.y * fSin, Tmp.z * fSin)); 560 } 561 562 template <typename T, precision P> 563 GLM_FUNC_QUALIFIER tvec3<T, P> eulerAngles(tquat<T, P> const & x) 564 { 565 return tvec3<T, P>(pitch(x), yaw(x), roll(x)); 566 } 567 568 template <typename T, precision P> 569 GLM_FUNC_QUALIFIER T roll(tquat<T, P> const & q) 570 { 571 return T(atan(T(2) * (q.x * q.y + q.w * q.z), q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z)); 572 } 573 574 template <typename T, precision P> 575 GLM_FUNC_QUALIFIER T pitch(tquat<T, P> const & q) 576 { 577 return T(atan(T(2) * (q.y * q.z + q.w * q.x), q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z)); 578 } 579 580 template <typename T, precision P> 581 GLM_FUNC_QUALIFIER T yaw(tquat<T, P> const & q) 582 { 583 return asin(clamp(T(-2) * (q.x * q.z - q.w * q.y), T(-1), T(1))); 584 } 585 586 template <typename T, precision P> 587 GLM_FUNC_QUALIFIER tmat3x3<T, P> mat3_cast(tquat<T, P> const & q) 588 { 589 tmat3x3<T, P> Result(T(1)); 590 T qxx(q.x * q.x); 591 T qyy(q.y * q.y); 592 T qzz(q.z * q.z); 593 T qxz(q.x * q.z); 594 T qxy(q.x * q.y); 595 T qyz(q.y * q.z); 596 T qwx(q.w * q.x); 597 T qwy(q.w * q.y); 598 T qwz(q.w * q.z); 599 600 Result[0][0] = T(1) - T(2) * (qyy + qzz); 601 Result[0][1] = T(2) * (qxy + qwz); 602 Result[0][2] = T(2) * (qxz - qwy); 603 604 Result[1][0] = T(2) * (qxy - qwz); 605 Result[1][1] = T(1) - T(2) * (qxx + qzz); 606 Result[1][2] = T(2) * (qyz + qwx); 607 608 Result[2][0] = T(2) * (qxz + qwy); 609 Result[2][1] = T(2) * (qyz - qwx); 610 Result[2][2] = T(1) - T(2) * (qxx + qyy); 611 return Result; 612 } 613 614 template <typename T, precision P> 615 GLM_FUNC_QUALIFIER tmat4x4<T, P> mat4_cast(tquat<T, P> const & q) 616 { 617 return tmat4x4<T, P>(mat3_cast(q)); 618 } 619 620 template <typename T, precision P> 621 GLM_FUNC_QUALIFIER tquat<T, P> quat_cast(tmat3x3<T, P> const & m) 622 { 623 T fourXSquaredMinus1 = m[0][0] - m[1][1] - m[2][2]; 624 T fourYSquaredMinus1 = m[1][1] - m[0][0] - m[2][2]; 625 T fourZSquaredMinus1 = m[2][2] - m[0][0] - m[1][1]; 626 T fourWSquaredMinus1 = m[0][0] + m[1][1] + m[2][2]; 627 628 int biggestIndex = 0; 629 T fourBiggestSquaredMinus1 = fourWSquaredMinus1; 630 if(fourXSquaredMinus1 > fourBiggestSquaredMinus1) 631 { 632 fourBiggestSquaredMinus1 = fourXSquaredMinus1; 633 biggestIndex = 1; 634 } 635 if(fourYSquaredMinus1 > fourBiggestSquaredMinus1) 636 { 637 fourBiggestSquaredMinus1 = fourYSquaredMinus1; 638 biggestIndex = 2; 639 } 640 if(fourZSquaredMinus1 > fourBiggestSquaredMinus1) 641 { 642 fourBiggestSquaredMinus1 = fourZSquaredMinus1; 643 biggestIndex = 3; 644 } 645 646 T biggestVal = sqrt(fourBiggestSquaredMinus1 + T(1)) * T(0.5); 647 T mult = static_cast<T>(0.25) / biggestVal; 648 649 tquat<T, P> Result(uninitialize); 650 switch(biggestIndex) 651 { 652 case 0: 653 Result.w = biggestVal; 654 Result.x = (m[1][2] - m[2][1]) * mult; 655 Result.y = (m[2][0] - m[0][2]) * mult; 656 Result.z = (m[0][1] - m[1][0]) * mult; 657 break; 658 case 1: 659 Result.w = (m[1][2] - m[2][1]) * mult; 660 Result.x = biggestVal; 661 Result.y = (m[0][1] + m[1][0]) * mult; 662 Result.z = (m[2][0] + m[0][2]) * mult; 663 break; 664 case 2: 665 Result.w = (m[2][0] - m[0][2]) * mult; 666 Result.x = (m[0][1] + m[1][0]) * mult; 667 Result.y = biggestVal; 668 Result.z = (m[1][2] + m[2][1]) * mult; 669 break; 670 case 3: 671 Result.w = (m[0][1] - m[1][0]) * mult; 672 Result.x = (m[2][0] + m[0][2]) * mult; 673 Result.y = (m[1][2] + m[2][1]) * mult; 674 Result.z = biggestVal; 675 break; 676 677 default: // Silence a -Wswitch-default warning in GCC. Should never actually get here. Assert is just for sanity. 678 assert(false); 679 break; 680 } 681 return Result; 682 } 683 684 template <typename T, precision P> 685 GLM_FUNC_QUALIFIER tquat<T, P> quat_cast(tmat4x4<T, P> const & m4) 686 { 687 return quat_cast(tmat3x3<T, P>(m4)); 688 } 689 690 template <typename T, precision P> 691 GLM_FUNC_QUALIFIER T angle(tquat<T, P> const & x) 692 { 693 return acos(x.w) * T(2); 694 } 695 696 template <typename T, precision P> 697 GLM_FUNC_QUALIFIER tvec3<T, P> axis(tquat<T, P> const & x) 698 { 699 T tmp1 = static_cast<T>(1) - x.w * x.w; 700 if(tmp1 <= static_cast<T>(0)) 701 return tvec3<T, P>(0, 0, 1); 702 T tmp2 = static_cast<T>(1) / sqrt(tmp1); 703 return tvec3<T, P>(x.x * tmp2, x.y * tmp2, x.z * tmp2); 704 } 705 706 template <typename T, precision P> 707 GLM_FUNC_QUALIFIER tquat<T, P> angleAxis(T const & angle, tvec3<T, P> const & v) 708 { 709 tquat<T, P> Result(uninitialize); 710 711 T const a(angle); 712 T const s = glm::sin(a * static_cast<T>(0.5)); 713 714 Result.w = glm::cos(a * static_cast<T>(0.5)); 715 Result.x = v.x * s; 716 Result.y = v.y * s; 717 Result.z = v.z * s; 718 return Result; 719 } 720 721 template <typename T, precision P> 722 GLM_FUNC_QUALIFIER tvec4<bool, P> lessThan(tquat<T, P> const & x, tquat<T, P> const & y) 723 { 724 tvec4<bool, P> Result(uninitialize); 725 for(length_t i = 0; i < x.length(); ++i) 726 Result[i] = x[i] < y[i]; 727 return Result; 728 } 729 730 template <typename T, precision P> 731 GLM_FUNC_QUALIFIER tvec4<bool, P> lessThanEqual(tquat<T, P> const & x, tquat<T, P> const & y) 732 { 733 tvec4<bool, P> Result(uninitialize); 734 for(length_t i = 0; i < x.length(); ++i) 735 Result[i] = x[i] <= y[i]; 736 return Result; 737 } 738 739 template <typename T, precision P> 740 GLM_FUNC_QUALIFIER tvec4<bool, P> greaterThan(tquat<T, P> const & x, tquat<T, P> const & y) 741 { 742 tvec4<bool, P> Result(uninitialize); 743 for(length_t i = 0; i < x.length(); ++i) 744 Result[i] = x[i] > y[i]; 745 return Result; 746 } 747 748 template <typename T, precision P> 749 GLM_FUNC_QUALIFIER tvec4<bool, P> greaterThanEqual(tquat<T, P> const & x, tquat<T, P> const & y) 750 { 751 tvec4<bool, P> Result(uninitialize); 752 for(length_t i = 0; i < x.length(); ++i) 753 Result[i] = x[i] >= y[i]; 754 return Result; 755 } 756 757 template <typename T, precision P> 758 GLM_FUNC_QUALIFIER tvec4<bool, P> equal(tquat<T, P> const & x, tquat<T, P> const & y) 759 { 760 tvec4<bool, P> Result(uninitialize); 761 for(length_t i = 0; i < x.length(); ++i) 762 Result[i] = x[i] == y[i]; 763 return Result; 764 } 765 766 template <typename T, precision P> 767 GLM_FUNC_QUALIFIER tvec4<bool, P> notEqual(tquat<T, P> const & x, tquat<T, P> const & y) 768 { 769 tvec4<bool, P> Result(uninitialize); 770 for(length_t i = 0; i < x.length(); ++i) 771 Result[i] = x[i] != y[i]; 772 return Result; 773 } 774 775 template <typename T, precision P> 776 GLM_FUNC_QUALIFIER tvec4<bool, P> isnan(tquat<T, P> const& q) 777 { 778 GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'isnan' only accept floating-point inputs"); 779 780 return tvec4<bool, P>(isnan(q.x), isnan(q.y), isnan(q.z), isnan(q.w)); 781 } 782 783 template <typename T, precision P> 784 GLM_FUNC_QUALIFIER tvec4<bool, P> isinf(tquat<T, P> const& q) 785 { 786 GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'isinf' only accept floating-point inputs"); 787 788 return tvec4<bool, P>(isinf(q.x), isinf(q.y), isinf(q.z), isinf(q.w)); 789 } 790}//namespace glm 791 792#if GLM_ARCH != GLM_ARCH_PURE && GLM_HAS_ALIGNED_TYPE 793# include "quaternion_simd.inl" 794#endif 795 796