diff options
Diffstat (limited to 'src/foundation/Qt3DSMat44.h')
-rw-r--r-- | src/foundation/Qt3DSMat44.h | 497 |
1 files changed, 497 insertions, 0 deletions
diff --git a/src/foundation/Qt3DSMat44.h b/src/foundation/Qt3DSMat44.h new file mode 100644 index 0000000..53a66e2 --- /dev/null +++ b/src/foundation/Qt3DSMat44.h @@ -0,0 +1,497 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QT3DS_FOUNDATION_QT3DS_MAT44_H +#define QT3DS_FOUNDATION_QT3DS_MAT44_H +/** \addtogroup foundation +@{ +*/ + +#include "foundation/Qt3DSQuat.h" +#include "foundation/Qt3DSVec4.h" +#include "foundation/Qt3DSMat33.h" +#include "foundation/Qt3DSTransform.h" + +#ifndef QT3DS_DOXYGEN +namespace qt3ds { +#endif + +/*! +\brief 4x4 matrix class + +This class is layout-compatible with D3D and OpenGL matrices. More notes on layout are given in the QT3DSMat33 +Graphics matrices always (by which I mean DX and OpenGL) have the rotation basis vectors stored contiguously +in 0-2, 3-5, 6-8 and the the translation stored contiguously in 12-14. However, DX calls this row major and GL calls it column-major. +http://www.mindcontrol.org/~hplus/graphics/matrix-layout.html + +you can blat these directly into GL (or DX) + +--Dilip Sequeira + +@see QT3DSMat33 NVTransform +*/ + +class QT3DSMat44 +{ +public: + //! Default constructor + QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44() {} + + //! Construct from four 4-vectors + QT3DS_CUDA_CALLABLE QT3DSMat44(const QT3DSVec4 &col0, const QT3DSVec4 &col1, const QT3DSVec4 &col2, + const QT3DSVec4 &col3) + : column0(col0) + , column1(col1) + , column2(col2) + , column3(col3) + { + } + + //! Construct from three base vectors and a translation + QT3DS_CUDA_CALLABLE QT3DSMat44(const QT3DSVec3 &column0, const QT3DSVec3 &column1, const QT3DSVec3 &column2, + const QT3DSVec3 &column3) + : column0(column0, 0) + , column1(column1, 0) + , column2(column2, 0) + , column3(column3, 1) + { + } + + //! Construct from float[16] + explicit QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44(NVReal values[]) + : column0(values[0], values[1], values[2], values[3]) + , column1(values[4], values[5], values[6], values[7]) + , column2(values[8], values[9], values[10], values[11]) + , column3(values[12], values[13], values[14], values[15]) + { + } + + //! Construct from a quaternion + explicit QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44(const QT3DSQuat &q) + { + const NVReal x = q.x; + const NVReal y = q.y; + const NVReal z = q.z; + const NVReal w = q.w; + + const NVReal x2 = x + x; + const NVReal y2 = y + y; + const NVReal z2 = z + z; + + const NVReal xx = x2 * x; + const NVReal yy = y2 * y; + const NVReal zz = z2 * z; + + const NVReal xy = x2 * y; + const NVReal xz = x2 * z; + const NVReal xw = x2 * w; + + const NVReal yz = y2 * z; + const NVReal yw = y2 * w; + const NVReal zw = z2 * w; + + column0 = QT3DSVec4(1.0f - yy - zz, xy + zw, xz - yw, 0.0f); + column1 = QT3DSVec4(xy - zw, 1.0f - xx - zz, yz + xw, 0.0f); + column2 = QT3DSVec4(xz + yw, yz - xw, 1.0f - xx - yy, 0.0f); + column3 = QT3DSVec4(0.0f, 0.0f, 0.0f, 1.0f); + } + + //! Construct from a diagonal vector + explicit QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44(const QT3DSVec4 &diagonal) + : column0(diagonal.x, 0.0f, 0.0f, 0.0f) + , column1(0.0f, diagonal.y, 0.0f, 0.0f) + , column2(0.0f, 0.0f, diagonal.z, 0.0f) + , column3(0.0f, 0.0f, 0.0f, diagonal.w) + { + } + + QT3DS_CUDA_CALLABLE QT3DSMat44(const QT3DSMat33 &orientation, const QT3DSVec3 &position) + : column0(orientation.column0, 0.0f) + , column1(orientation.column1, 0.0f) + , column2(orientation.column2, 0.0f) + , column3(position, 1) + { + } + + QT3DS_CUDA_CALLABLE QT3DSMat44(const NVTransform &t) { *this = QT3DSMat44(QT3DSMat33(t.q), t.p); } + + //! Copy constructor + QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44(const QT3DSMat44 &other) + : column0(other.column0) + , column1(other.column1) + , column2(other.column2) + , column3(other.column3) + { + } + + //! Assignment operator + QT3DS_CUDA_CALLABLE QT3DS_INLINE const QT3DSMat44 &operator=(const QT3DSMat44 &other) + { + column0 = other.column0; + column1 = other.column1; + column2 = other.column2; + column3 = other.column3; + return *this; + } + + QT3DS_CUDA_CALLABLE QT3DS_INLINE static QT3DSMat44 createIdentity() + { + return QT3DSMat44(QT3DSVec4(1.0f, 0.0f, 0.0f, 0.0f), QT3DSVec4(0.0f, 1.0f, 0.0f, 0.0f), + QT3DSVec4(0.0f, 0.0f, 1.0f, 0.0f), QT3DSVec4(0.0f, 0.0f, 0.0f, 1.0f)); + } + + QT3DS_CUDA_CALLABLE QT3DS_INLINE static QT3DSMat44 createZero() + { + return QT3DSMat44(QT3DSVec4(0.0f), QT3DSVec4(0.0f), QT3DSVec4(0.0f), QT3DSVec4(0.0f)); + } + + //! Get transposed matrix + QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44 getTranspose() const + { + return QT3DSMat44(QT3DSVec4(column0.x, column1.x, column2.x, column3.x), + QT3DSVec4(column0.y, column1.y, column2.y, column3.y), + QT3DSVec4(column0.z, column1.z, column2.z, column3.z), + QT3DSVec4(column0.w, column1.w, column2.w, column3.w)); + } + + //! Unary minus + QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44 operator-() const + { + return QT3DSMat44(-column0, -column1, -column2, -column3); + } + + //! Add + QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44 operator+(const QT3DSMat44 &other) const + { + return QT3DSMat44(column0 + other.column0, column1 + other.column1, column2 + other.column2, + column3 + other.column3); + } + + //! Subtract + QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44 operator-(const QT3DSMat44 &other) const + { + return QT3DSMat44(column0 - other.column0, column1 - other.column1, column2 - other.column2, + column3 - other.column3); + } + + //! Scalar multiplication + QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44 operator*(NVReal scalar) const + { + return QT3DSMat44(column0 * scalar, column1 * scalar, column2 * scalar, column3 * scalar); + } + + friend QT3DSMat44 operator*(NVReal, const QT3DSMat44 &); + + //! Matrix multiplication + QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44 operator*(const QT3DSMat44 &other) const + { + // Rows from this <dot> columns from other + // column0 = transform(other.column0) etc + return QT3DSMat44(transform(other.column0), transform(other.column1), transform(other.column2), + transform(other.column3)); + } + + // a <op>= b operators + + //! Equals-add + QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44 &operator+=(const QT3DSMat44 &other) + { + column0 += other.column0; + column1 += other.column1; + column2 += other.column2; + column3 += other.column3; + return *this; + } + + //! Equals-sub + QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44 &operator-=(const QT3DSMat44 &other) + { + column0 -= other.column0; + column1 -= other.column1; + column2 -= other.column2; + column3 -= other.column3; + return *this; + } + + //! Equals scalar multiplication + QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44 &operator*=(NVReal scalar) + { + column0 *= scalar; + column1 *= scalar; + column2 *= scalar; + column3 *= scalar; + return *this; + } + + //! Element access, mathematical way! + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVReal operator()(unsigned int row, unsigned int col) const + { + return (*this)[col][row]; + } + + //! Element access, mathematical way! + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVReal &operator()(unsigned int row, unsigned int col) + { + return (*this)[col][row]; + } + + //! Transform vector by matrix, equal to v' = M*v + QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec4 transform(const QT3DSVec4 &other) const + { + return column0 * other.x + column1 * other.y + column2 * other.z + column3 * other.w; + } + + //! Transform vector by matrix, equal to v' = M*v + QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec3 transform(const QT3DSVec3 &other) const + { + return transform(QT3DSVec4(other, 1)).getXYZ(); + } + + //! Rotate vector by matrix, equal to v' = M*v + QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec4 rotate(const QT3DSVec4 &other) const + { + return column0 * other.x + column1 * other.y + column2 * other.z; // + column3*0; + } + + //! Rotate vector by matrix, equal to v' = M*v + QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec3 rotate(const QT3DSVec3 &other) const + { + return rotate(QT3DSVec4(other, 1)).getXYZ(); + } + + /** +* Shamelessly pulled from gl-matrix.js + * Rotates a matrix by the given angle around the specified axis +* +* @param angle Angle (in radians) to rotate +* @param axis vec3 representing the axis to rotate around +*/ + QT3DS_CUDA_CALLABLE QT3DS_INLINE bool rotate(QT3DSF32 angleRadians, QT3DSVec3 axis) + { + QT3DSF32 x = axis[0], y = axis[1], z = axis[2], len = x * x + y * y + z * z, s, c, t, a00, a01, + a02, a03, a10, a11, a12, a13, a20, a21, a22, a23, b00, b01, b02, b10, b11, b12, b20, + b21, b22; + + if (!len) { + return false; + } + if (len != 1.0f) { + len = 1 / (NVSqrt(len)); + x *= len; + y *= len; + z *= len; + } + + s = NVSin(angleRadians); + c = NVCos(angleRadians); + t = 1 - c; + + QT3DSF32 *dataPtr(front()); + +// inverse algorithm was written for row-major matrixes. +#define mat(idx) dataPtr[idx] + + a00 = mat(0); + a01 = mat(1); + a02 = mat(2); + a03 = mat(3); + a10 = mat(4); + a11 = mat(5); + a12 = mat(6); + a13 = mat(7); + a20 = mat(8); + a21 = mat(9); + a22 = mat(10); + a23 = mat(11); +#undef mat + + // Construct the elements of the rotation matrix + b00 = x * x * t + c; + b01 = y * x * t + z * s; + b02 = z * x * t - y * s; + b10 = x * y * t - z * s; + b11 = y * y * t + c; + b12 = z * y * t + x * s; + b20 = x * z * t + y * s; + b21 = y * z * t - x * s; + b22 = z * z * t + c; + +// Perform rotation-specific matrix multiplication + +#define dest(idx) dataPtr[idx] + + dest(0) = a00 * b00 + a10 * b01 + a20 * b02; + dest(1) = a01 * b00 + a11 * b01 + a21 * b02; + dest(2) = a02 * b00 + a12 * b01 + a22 * b02; + dest(3) = a03 * b00 + a13 * b01 + a23 * b02; + + dest(4) = a00 * b10 + a10 * b11 + a20 * b12; + dest(5) = a01 * b10 + a11 * b11 + a21 * b12; + dest(6) = a02 * b10 + a12 * b11 + a22 * b12; + dest(7) = a03 * b10 + a13 * b11 + a23 * b12; + + dest(8) = a00 * b20 + a10 * b21 + a20 * b22; + dest(9) = a01 * b20 + a11 * b21 + a21 * b22; + dest(10) = a02 * b20 + a12 * b21 + a22 * b22; + dest(11) = a03 * b20 + a13 * b21 + a23 * b22; + +#undef dest + + return true; + }; + + QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec3 getBasis(int num) const + { + QT3DS_ASSERT(num >= 0 && num < 3); + return (&column0)[num].getXYZ(); + } + + QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec3 getPosition() const { return column3.getXYZ(); } + + QT3DS_CUDA_CALLABLE QT3DS_INLINE void setPosition(const QT3DSVec3 &position) + { + column3.x = position.x; + column3.y = position.y; + column3.z = position.z; + } + + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVReal *front() { return &column0.x; } + + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE const NVReal *front() const { return &column0.x; } + + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec4 &operator[](int num) { return (&column0)[num]; } + QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE const QT3DSVec4 &operator[](int num) const + { + return (&column0)[num]; + } + + QT3DS_CUDA_CALLABLE QT3DS_INLINE void scale(const QT3DSVec4 &p) + { + column0 *= p.x; + column1 *= p.y; + column2 *= p.z; + column3 *= p.w; + } + + QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44 inverseRT(void) const + { + QT3DSVec3 r0(column0.x, column1.x, column2.x), r1(column0.y, column1.y, column2.y), + r2(column0.z, column1.z, column2.z); + + return QT3DSMat44(r0, r1, r2, -(r0 * column3.x + r1 * column3.y + r2 * column3.z)); + } + + QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44 getInverse(void) const + { + // inverse algorithm was written for row-major matrixes. + const QT3DSF32 *myPtr(front()); +#define mat(idx) myPtr[idx] + + QT3DSF32 a00 = mat(0), a01 = mat(1), a02 = mat(2), a03 = mat(3), a10 = mat(4), a11 = mat(5), + a12 = mat(6), a13 = mat(7), a20 = mat(8), a21 = mat(9), a22 = mat(10), a23 = mat(11), + a30 = mat(12), a31 = mat(13), a32 = mat(14), a33 = mat(15), +#undef mat + + b00 = a00 * a11 - a01 * a10, b01 = a00 * a12 - a02 * a10, b02 = a00 * a13 - a03 * a10, + b03 = a01 * a12 - a02 * a11, b04 = a01 * a13 - a03 * a11, b05 = a02 * a13 - a03 * a12, + b06 = a20 * a31 - a21 * a30, b07 = a20 * a32 - a22 * a30, b08 = a20 * a33 - a23 * a30, + b09 = a21 * a32 - a22 * a31, b10 = a21 * a33 - a23 * a31, b11 = a22 * a33 - a23 * a32, + + d = (b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06), invDet; + + // Calculate the determinant + if (!d) { + QT3DS_ASSERT(false); + return QT3DSMat44::createIdentity(); + } + invDet = 1 / d; + + QT3DSMat44 retval; + QT3DSF32 *destPtr = retval.front(); + +#define dest(idx) destPtr[idx] + dest(0) = (a11 * b11 - a12 * b10 + a13 * b09) * invDet; + dest(1) = (-a01 * b11 + a02 * b10 - a03 * b09) * invDet; + dest(2) = (a31 * b05 - a32 * b04 + a33 * b03) * invDet; + dest(3) = (-a21 * b05 + a22 * b04 - a23 * b03) * invDet; + dest(4) = (-a10 * b11 + a12 * b08 - a13 * b07) * invDet; + dest(5) = (a00 * b11 - a02 * b08 + a03 * b07) * invDet; + dest(6) = (-a30 * b05 + a32 * b02 - a33 * b01) * invDet; + dest(7) = (a20 * b05 - a22 * b02 + a23 * b01) * invDet; + dest(8) = (a10 * b10 - a11 * b08 + a13 * b06) * invDet; + dest(9) = (-a00 * b10 + a01 * b08 - a03 * b06) * invDet; + dest(10) = (a30 * b04 - a31 * b02 + a33 * b00) * invDet; + dest(11) = (-a20 * b04 + a21 * b02 - a23 * b00) * invDet; + dest(12) = (-a10 * b09 + a11 * b07 - a12 * b06) * invDet; + dest(13) = (a00 * b09 - a01 * b07 + a02 * b06) * invDet; + dest(14) = (-a30 * b03 + a31 * b01 - a32 * b00) * invDet; + dest(15) = (a20 * b03 - a21 * b01 + a22 * b00) * invDet; +#undef dest + + return retval; + } + + QT3DS_CUDA_CALLABLE QT3DS_INLINE bool isFinite() const + { + return column0.isFinite() && column1.isFinite() && column2.isFinite() && column3.isFinite(); + } + + QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat33 getUpper3x3() const + { + return QT3DSMat33(column0.getXYZ(), column1.getXYZ(), column2.getXYZ()); + } + + QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat33 getUpper3x3InverseTranspose() const + { + return getUpper3x3().getInverse().getTranspose(); + } + + // Data, see above for format! + + QT3DSVec4 column0, column1, column2, column3; // the four base vectors +}; + +// implementation from Qt3DSTransform.h +QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVTransform::NVTransform(const QT3DSMat44 &m) +{ + QT3DSVec3 column0 = QT3DSVec3(m.column0.x, m.column0.y, m.column0.z); + QT3DSVec3 column1 = QT3DSVec3(m.column1.x, m.column1.y, m.column1.z); + QT3DSVec3 column2 = QT3DSVec3(m.column2.x, m.column2.y, m.column2.z); + + q = QT3DSQuat(QT3DSMat33(column0, column1, column2)); + p = QT3DSVec3(m.column3.x, m.column3.y, m.column3.z); +} + +#ifndef QT3DS_DOXYGEN +} // namespace qt3ds +#endif + +/** @} */ +#endif // QT3DS_FOUNDATION_QT3DS_MAT44_H |