summaryrefslogtreecommitdiffstats
path: root/src/foundation/Qt3DSMathUtils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/foundation/Qt3DSMathUtils.cpp')
-rw-r--r--src/foundation/Qt3DSMathUtils.cpp181
1 files changed, 181 insertions, 0 deletions
diff --git a/src/foundation/Qt3DSMathUtils.cpp b/src/foundation/Qt3DSMathUtils.cpp
new file mode 100644
index 0000000..7eee740
--- /dev/null
+++ b/src/foundation/Qt3DSMathUtils.cpp
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "foundation/Qt3DSMathUtils.h"
+#include "foundation/Qt3DSUtilities.h"
+#include "foundation/Qt3DSMat33.h"
+
+using namespace qt3ds;
+using namespace qt3ds::foundation;
+using namespace qt3ds::intrinsics;
+
+QT3DSQuat qt3ds::foundation::computeQuatFromNormal(const QT3DSVec3 &n)
+{
+ // parallel or anti-parallel
+ if (n.x > 0.9999f) {
+ // parallel
+ return QT3DSQuat::createIdentity();
+ } else if (n.x < -0.9999f) {
+ // anti-parallel
+ // contactQuaternion.fromAngleAxisFast(PXD_PI, Vector3(0.0f, 1.0f, 0.0f));
+ return QT3DSQuat(0.0f, 1.0f, 0.0f, 0.0f);
+ } else {
+ QT3DSVec3 rotVec(0.0f, -n.z, n.y);
+
+ // Convert to quat
+ NVReal angle = rotVec.magnitude();
+ rotVec *= 1.0f / angle;
+ // if(angle > 1.0f) angle = 1.0f;
+ angle = selectMin(angle, 1.0f);
+
+ // djs: injudiciously imbecilic use of trig functions, good thing Adam is going to trample
+ // this path like a
+ // frustrated rhinoceros in mating season
+
+ angle = NVAsin(angle);
+
+ // if(n.x < 0)
+ // angle = NVPi - angle;
+ angle = fsel(n.x, angle, NVPi - angle);
+
+ return QT3DSQuat(angle, rotVec);
+ }
+}
+
+/**
+\brief computes a oriented bounding box around the scaled basis.
+\param basis Input = skewed basis, Output = (normalized) orthogonal basis.
+\return Bounding box extent.
+*/
+QT3DSVec3 qt3ds::foundation::optimizeBoundingBox(QT3DSMat33 &basis)
+{
+ QT3DSVec3 *QT3DS_RESTRICT vec = &basis[0]; // PT: don't copy vectors if not needed...
+
+ // PT: since we store the magnitudes to memory, we can avoid the FCMNV afterwards
+ QT3DSVec3 magnitude(vec[0].magnitudeSquared(), vec[1].magnitudeSquared(),
+ vec[2].magnitudeSquared());
+
+// find indices sorted by magnitude
+#ifdef QT3DS_X360
+ int i = (QT3DSU32 &)(magnitude[1]) > (QT3DSU32 &)(magnitude[0]) ? 1 : 0;
+ int j = (QT3DSU32 &)(magnitude[2]) > (QT3DSU32 &)(magnitude[1 - i]) ? 2 : 1 - i;
+#else
+ int i = magnitude[1] > magnitude[0] ? 1 : 0;
+ int j = magnitude[2] > magnitude[1 - i] ? 2 : 1 - i;
+#endif
+ const int k = 3 - i - j;
+#ifdef QT3DS_X360
+ if ((QT3DSU32 &)(magnitude[i]) < (QT3DSU32 &)(magnitude[j]))
+#else
+ if (magnitude[i] < magnitude[j])
+#endif
+ swap(i, j);
+
+ // ortho-normalize basis
+
+ NVReal invSqrt = NVRecipSqrt(magnitude[i]);
+ magnitude[i] *= invSqrt;
+ vec[i] *= invSqrt; // normalize the first axis
+ NVReal dotij = vec[i].dot(vec[j]);
+ NVReal dotik = vec[i].dot(vec[k]);
+ magnitude[i] += NVAbs(dotij) + NVAbs(dotik); // elongate the axis by projection of the other two
+ vec[j] -= vec[i] * dotij; // orthogonize the two remaining axii relative to vec[i]
+ vec[k] -= vec[i] * dotik;
+
+ magnitude[j] = vec[j].normalize();
+ NVReal dotjk = vec[j].dot(vec[k]);
+ magnitude[j] += NVAbs(dotjk); // elongate the axis by projection of the other one
+ vec[k] -= vec[j] * dotjk; // orthogonize vec[k] relative to vec[j]
+
+ magnitude[k] = vec[k].normalize();
+
+ return magnitude;
+}
+
+QT3DSQuat qt3ds::foundation::slerp(const NVReal t, const QT3DSQuat &left, const QT3DSQuat &right)
+{
+ const NVReal quatEpsilon = (NVReal(1.0e-8f));
+
+ NVReal cosine = left.dot(right);
+ NVReal sign = NVReal(1);
+ if (cosine < 0) {
+ cosine = -cosine;
+ sign = NVReal(-1);
+ }
+
+ NVReal sine = NVReal(1) - cosine * cosine;
+
+ if (sine >= quatEpsilon * quatEpsilon) {
+ sine = NVSqrt(sine);
+ const NVReal angle = NVAtan2(sine, cosine);
+ const NVReal i_sin_angle = NVReal(1) / sine;
+
+ const NVReal leftw = NVSin(angle * (NVReal(1) - t)) * i_sin_angle;
+ const NVReal rightw = NVSin(angle * t) * i_sin_angle * sign;
+
+ return left * leftw + right * rightw;
+ }
+
+ return left;
+}
+
+void qt3ds::foundation::integrateTransform(const NVTransform &curTrans, const QT3DSVec3 &linvel,
+ const QT3DSVec3 &angvel, NVReal timeStep, NVTransform &result)
+{
+ result.p = curTrans.p + linvel * timeStep;
+
+ // from void NVsDynamicsContext::integrateAtomPose(NVsRigidBody* atom, Cm::BitMap
+ // &shapeChangedMap) const:
+ // Integrate the rotation using closed form quaternion integrator
+ NVReal w = angvel.magnitudeSquared();
+
+ if (w != 0.0f) {
+ w = NVSqrt(w);
+ if (w != 0.0f) {
+ const NVReal v = timeStep * w * 0.5f;
+ const NVReal q = NVCos(v);
+ const NVReal s = NVSin(v) / w;
+
+ const QT3DSVec3 pqr = angvel * s;
+ const QT3DSQuat quatVel(pqr.x, pqr.y, pqr.z, 0);
+ QT3DSQuat out; // need to have temporary, otherwise we may overwrite input if &curTrans ==
+ // &result.
+ out = quatVel * curTrans.q;
+ out.x += curTrans.q.x * q;
+ out.y += curTrans.q.y * q;
+ out.z += curTrans.q.z * q;
+ out.w += curTrans.q.w * q;
+ result.q = out;
+ return;
+ }
+ }
+ // orientation stays the same - convert from quat to matrix:
+ result.q = curTrans.q;
+}