/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ /* * Copyright (C) 2006-2010 - Frictional Games * * This file is part of HPL1 Engine. */ #include "hpl1/engine/math/Quaternion.h" #include "hpl1/engine/math/Math.h" #include "hpl1/engine/system/low_level_system.h" namespace hpl { ////////////////////////////////////////////////////////////////////////// // CONSTRUCTORS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cQuaternion::cQuaternion() { } //----------------------------------------------------------------------- cQuaternion::cQuaternion(float afAngle, const cVector3f &avAxis) { FromAngleAxis(afAngle, avAxis); } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////// const cQuaternion cQuaternion::Identity = cQuaternion(1.0f, 0.0f, 0.0f, 0.0f); //----------------------------------------------------------------------- void cQuaternion::Normalise() { float fLen = w * w + v.x * v.x + v.y * v.y + v.z * v.z; float fFactor = 1.0f / sqrt(fLen); v = v * fFactor; w = w * fFactor; } //----------------------------------------------------------------------- void cQuaternion::ToRotationMatrix(cMatrixf &a_mtxDest) const { cMatrixf mtxA; float fTx = 2.0f * v.x; float fTy = 2.0f * v.y; float fTz = 2.0f * v.z; float fTwx = fTx * w; float fTwy = fTy * w; float fTwz = fTz * w; float fTxx = fTx * v.x; float fTxy = fTy * v.x; float fTxz = fTz * v.x; float fTyy = fTy * v.y; float fTyz = fTz * v.y; float fTzz = fTz * v.z; a_mtxDest.m[0][0] = 1.0f - (fTyy + fTzz); a_mtxDest.m[0][1] = fTxy - fTwz; a_mtxDest.m[0][2] = fTxz + fTwy; a_mtxDest.m[1][0] = fTxy + fTwz; a_mtxDest.m[1][1] = 1.0f - (fTxx + fTzz); a_mtxDest.m[1][2] = fTyz - fTwx; a_mtxDest.m[2][0] = fTxz - fTwy; a_mtxDest.m[2][1] = fTyz + fTwx; a_mtxDest.m[2][2] = 1.0f - (fTxx + fTyy); } //----------------------------------------------------------------------- void cQuaternion::FromRotationMatrix(const cMatrix &a_mtxRot) { float fTrace = a_mtxRot.m[0][0] + a_mtxRot.m[1][1] + a_mtxRot.m[2][2]; float fRoot; if (fTrace > 0.0) { // |w| > 1/2, may as well choose w > 1/2 fRoot = sqrt(fTrace + 1.0f); // 2w w = 0.5f * fRoot; fRoot = 0.5f / fRoot; // 1/(4w) v.x = (a_mtxRot.m[2][1] - a_mtxRot.m[1][2]) * fRoot; v.y = (a_mtxRot.m[0][2] - a_mtxRot.m[2][0]) * fRoot; v.z = (a_mtxRot.m[1][0] - a_mtxRot.m[0][1]) * fRoot; } else { // |w| <= 1/2 static size_t s_iNext[3] = {1, 2, 0}; size_t i = 0; if (a_mtxRot.m[1][1] > a_mtxRot.m[0][0]) i = 1; if (a_mtxRot.m[2][2] > a_mtxRot.m[i][i]) i = 2; size_t j = s_iNext[i]; size_t k = s_iNext[j]; fRoot = sqrt(a_mtxRot.m[i][i] - a_mtxRot.m[j][j] - a_mtxRot.m[k][k] + 1.0f); float *apkQuat[3] = {&v.x, &v.y, &v.z}; *apkQuat[i] = 0.5f * fRoot; fRoot = 0.5f / fRoot; w = (a_mtxRot.m[k][j] - a_mtxRot.m[j][k]) * fRoot; *apkQuat[j] = (a_mtxRot.m[j][i] + a_mtxRot.m[i][j]) * fRoot; *apkQuat[k] = (a_mtxRot.m[k][i] + a_mtxRot.m[i][k]) * fRoot; } } //----------------------------------------------------------------------- void cQuaternion::FromAngleAxis(float afAngle, const cVector3f &avAxis) { // assert: axis[] is unit length // // The quaternion representing the rotation is // q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k) float fHalfAngle = 0.5f * afAngle; float fSin = sin(fHalfAngle); w = cos(fHalfAngle); v.x = fSin * avAxis.x; v.y = fSin * avAxis.y; v.z = fSin * avAxis.z; } //----------------------------------------------------------------------- cQuaternion cQuaternion::operator+(const cQuaternion &aqB) const { cQuaternion qOut; qOut.v = v + aqB.v; qOut.w = w + aqB.w; return qOut; } //----------------------------------------------------------------------- cQuaternion cQuaternion::operator-(const cQuaternion &aqB) const { cQuaternion qOut; qOut.v = v - aqB.v; qOut.w = w - aqB.w; return qOut; } //----------------------------------------------------------------------- cQuaternion cQuaternion::operator*(const cQuaternion &aqB) const { cQuaternion qOut; qOut.w = w * aqB.w - v.x * aqB.v.x - v.y * aqB.v.y - v.z * aqB.v.z; qOut.v.x = w * aqB.v.x + v.x * aqB.w + v.y * aqB.v.z - v.z * aqB.v.y; qOut.v.y = w * aqB.v.y + v.y * aqB.w + v.z * aqB.v.x - v.x * aqB.v.z; qOut.v.z = w * aqB.v.z + v.z * aqB.w + v.x * aqB.v.y - v.y * aqB.v.x; return qOut; } //----------------------------------------------------------------------- cQuaternion cQuaternion::operator*(float afScalar) const { cQuaternion qOut; qOut.v = v * afScalar; qOut.w = w * afScalar; return qOut; } //----------------------------------------------------------------------- } // namespace hpl