Files
2026-02-02 04:50:13 +01:00

187 lines
5.6 KiB
C++

/* 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 <http://www.gnu.org/licenses/>.
*
*/
/*
* 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<float> &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