Quat.cpp (6472B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 23 24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. 25 26 =========================================================================== 27 */ 28 29 #pragma hdrstop 30 #include "../precompiled.h" 31 32 /* 33 ===================== 34 idQuat::ToAngles 35 ===================== 36 */ 37 idAngles idQuat::ToAngles() const { 38 return ToMat3().ToAngles(); 39 } 40 41 /* 42 ===================== 43 idQuat::ToRotation 44 ===================== 45 */ 46 idRotation idQuat::ToRotation() const { 47 idVec3 vec; 48 float angle; 49 50 vec.x = x; 51 vec.y = y; 52 vec.z = z; 53 angle = idMath::ACos( w ); 54 if ( angle == 0.0f ) { 55 vec.Set( 0.0f, 0.0f, 1.0f ); 56 } else { 57 //vec *= (1.0f / sin( angle )); 58 vec.Normalize(); 59 vec.FixDegenerateNormal(); 60 angle *= 2.0f * idMath::M_RAD2DEG; 61 } 62 return idRotation( vec3_origin, vec, angle ); 63 } 64 65 /* 66 ===================== 67 idQuat::ToMat3 68 ===================== 69 */ 70 idMat3 idQuat::ToMat3() const { 71 idMat3 mat; 72 float wx, wy, wz; 73 float xx, yy, yz; 74 float xy, xz, zz; 75 float x2, y2, z2; 76 77 x2 = x + x; 78 y2 = y + y; 79 z2 = z + z; 80 81 xx = x * x2; 82 xy = x * y2; 83 xz = x * z2; 84 85 yy = y * y2; 86 yz = y * z2; 87 zz = z * z2; 88 89 wx = w * x2; 90 wy = w * y2; 91 wz = w * z2; 92 93 mat[ 0 ][ 0 ] = 1.0f - ( yy + zz ); 94 mat[ 0 ][ 1 ] = xy - wz; 95 mat[ 0 ][ 2 ] = xz + wy; 96 97 mat[ 1 ][ 0 ] = xy + wz; 98 mat[ 1 ][ 1 ] = 1.0f - ( xx + zz ); 99 mat[ 1 ][ 2 ] = yz - wx; 100 101 mat[ 2 ][ 0 ] = xz - wy; 102 mat[ 2 ][ 1 ] = yz + wx; 103 mat[ 2 ][ 2 ] = 1.0f - ( xx + yy ); 104 105 return mat; 106 } 107 108 /* 109 ===================== 110 idQuat::ToMat4 111 ===================== 112 */ 113 idMat4 idQuat::ToMat4() const { 114 return ToMat3().ToMat4(); 115 } 116 117 /* 118 ===================== 119 idQuat::ToCQuat 120 ===================== 121 */ 122 idCQuat idQuat::ToCQuat() const { 123 if ( w < 0.0f ) { 124 return idCQuat( -x, -y, -z ); 125 } 126 return idCQuat( x, y, z ); 127 } 128 129 /* 130 ============ 131 idQuat::ToAngularVelocity 132 ============ 133 */ 134 idVec3 idQuat::ToAngularVelocity() const { 135 idVec3 vec; 136 137 vec.x = x; 138 vec.y = y; 139 vec.z = z; 140 vec.Normalize(); 141 return vec * idMath::ACos( w ); 142 } 143 144 /* 145 ============= 146 idQuat::ToString 147 ============= 148 */ 149 const char *idQuat::ToString( int precision ) const { 150 return idStr::FloatArrayToString( ToFloatPtr(), GetDimension(), precision ); 151 } 152 153 /* 154 ===================== 155 idQuat::Slerp 156 157 Spherical linear interpolation between two quaternions. 158 ===================== 159 */ 160 idQuat &idQuat::Slerp( const idQuat &from, const idQuat &to, float t ) { 161 idQuat temp; 162 float omega, cosom, sinom, scale0, scale1; 163 164 if ( t <= 0.0f ) { 165 *this = from; 166 return *this; 167 } 168 169 if ( t >= 1.0f ) { 170 *this = to; 171 return *this; 172 } 173 174 if ( from == to ) { 175 *this = to; 176 return *this; 177 } 178 179 cosom = from.x * to.x + from.y * to.y + from.z * to.z + from.w * to.w; 180 if ( cosom < 0.0f ) { 181 temp = -to; 182 cosom = -cosom; 183 } else { 184 temp = to; 185 } 186 187 if ( ( 1.0f - cosom ) > 1e-6f ) { 188 #if 0 189 omega = acos( cosom ); 190 sinom = 1.0f / sin( omega ); 191 scale0 = sin( ( 1.0f - t ) * omega ) * sinom; 192 scale1 = sin( t * omega ) * sinom; 193 #else 194 scale0 = 1.0f - cosom * cosom; 195 sinom = idMath::InvSqrt( scale0 ); 196 omega = idMath::ATan16( scale0 * sinom, cosom ); 197 scale0 = idMath::Sin16( ( 1.0f - t ) * omega ) * sinom; 198 scale1 = idMath::Sin16( t * omega ) * sinom; 199 #endif 200 } else { 201 scale0 = 1.0f - t; 202 scale1 = t; 203 } 204 205 *this = ( scale0 * from ) + ( scale1 * temp ); 206 return *this; 207 } 208 209 /* 210 ======================== 211 idQuat::Lerp 212 213 Approximation of spherical linear interpolation between two quaternions. The interpolation 214 traces out the exact same curve as Slerp but does not maintain a constant speed across the arc. 215 ======================== 216 */ 217 idQuat &idQuat::Lerp( const idQuat &from, const idQuat &to, const float t ) { 218 if ( t <= 0.0f ) { 219 *this = from; 220 return *this; 221 } 222 223 if ( t >= 1.0f ) { 224 *this = to; 225 return *this; 226 } 227 228 if ( from == to ) { 229 *this = to; 230 return *this; 231 } 232 233 float cosom = from.x * to.x + from.y * to.y + from.z * to.z + from.w * to.w; 234 235 float scale0 = 1.0f - t; 236 float scale1 = ( cosom >= 0.0f ) ? t : -t; 237 238 x = scale0 * from.x + scale1 * to.x; 239 y = scale0 * from.y + scale1 * to.y; 240 z = scale0 * from.z + scale1 * to.z; 241 w = scale0 * from.w + scale1 * to.w; 242 243 float s = idMath::InvSqrt( x * x + y * y + z * z + w * w ); 244 245 x *= s; 246 y *= s; 247 z *= s; 248 w *= s; 249 250 return *this; 251 } 252 253 /* 254 ============= 255 idCQuat::ToAngles 256 ============= 257 */ 258 idAngles idCQuat::ToAngles() const { 259 return ToQuat().ToAngles(); 260 } 261 262 /* 263 ============= 264 idCQuat::ToRotation 265 ============= 266 */ 267 idRotation idCQuat::ToRotation() const { 268 return ToQuat().ToRotation(); 269 } 270 271 /* 272 ============= 273 idCQuat::ToMat3 274 ============= 275 */ 276 idMat3 idCQuat::ToMat3() const { 277 return ToQuat().ToMat3(); 278 } 279 280 /* 281 ============= 282 idCQuat::ToMat4 283 ============= 284 */ 285 idMat4 idCQuat::ToMat4() const { 286 return ToQuat().ToMat4(); 287 } 288 289 /* 290 ============= 291 idCQuat::ToString 292 ============= 293 */ 294 const char *idCQuat::ToString( int precision ) const { 295 return idStr::FloatArrayToString( ToFloatPtr(), GetDimension(), precision ); 296 } 297 298 /* 299 ===================== 300 Slerp 301 302 Spherical linear interpolation between two quaternions. 303 ===================== 304 */ 305 idQuat Slerp( const idQuat & from, const idQuat & to, const float t ) { 306 return idQuat().Slerp( from, to, t ); 307 }