From 13b3545e833f6175f686c9776e1510db3f3f11eb Mon Sep 17 00:00:00 2001 From: Kim Motoyoshi Kalland Date: Fri, 19 Aug 2011 15:00:41 +0200 Subject: Optimized QMatrix4x4 by improving how 'flagBits' are used. Change-Id: Ic417336489d334e25b547c719d457faf65307cac Reviewed-on: http://codereview.qt.nokia.com/3670 Reviewed-by: Qt Sanity Bot Reviewed-by: Gunnar Sletta --- src/gui/math3d/qmatrix4x4.h | 321 +++++++++++++++++++++++++++++--------------- 1 file changed, 212 insertions(+), 109 deletions(-) (limited to 'src/gui/math3d/qmatrix4x4.h') diff --git a/src/gui/math3d/qmatrix4x4.h b/src/gui/math3d/qmatrix4x4.h index bfbe4b9793..2c98dd03e3 100644 --- a/src/gui/math3d/qmatrix4x4.h +++ b/src/gui/math3d/qmatrix4x4.h @@ -80,11 +80,13 @@ public: inline const qreal& operator()(int row, int column) const; inline qreal& operator()(int row, int column); +#ifndef QT_NO_VECTOR4D inline QVector4D column(int index) const; inline void setColumn(int index, const QVector4D& value); inline QVector4D row(int index) const; inline void setRow(int index, const QVector4D& value); +#endif inline bool isIdentity() const; inline void setToIdentity(); @@ -188,16 +190,19 @@ private: qreal m[4][4]; // Column-major order to match OpenGL. int flagBits; // Flag bits from the enum below. + // When matrices are multiplied, the flag bits are or-ed together. enum { - Identity = 0x0001, // Identity matrix - General = 0x0002, // General matrix, unknown contents - Translation = 0x0004, // Contains a simple translation - Scale = 0x0008, // Contains a simple scale - Rotation = 0x0010 // Contains a simple rotation + Identity = 0x0000, // Identity matrix + Translation = 0x0001, // Contains a translation + Scale = 0x0002, // Contains a scale + Rotation2D = 0x0004, // Contains a rotation about the Z axis + Rotation = 0x0008, // Contains an arbitrary rotation + Perspective = 0x0010, // Last row is different from (0, 0, 0, 1) + General = 0x001f // General matrix, unknown contents }; // Construct without initializing identity matrix. - QMatrix4x4(int) { flagBits = General; } + QMatrix4x4(int) { } QMatrix4x4 orthonormalInverse() const; @@ -270,6 +275,7 @@ inline qreal& QMatrix4x4::operator()(int aRow, int aColumn) return m[aColumn][aRow]; } +#ifndef QT_NO_VECTOR4D inline QVector4D QMatrix4x4::column(int index) const { Q_ASSERT(index >= 0 && index < 4); @@ -301,6 +307,7 @@ inline void QMatrix4x4::setRow(int index, const QVector4D& value) m[3][index] = value.w(); flagBits = General; } +#endif Q_GUI_EXPORT QMatrix4x4 operator/(const QMatrix4x4& matrix, qreal divisor); @@ -409,15 +416,100 @@ inline QMatrix4x4& QMatrix4x4::operator-=(const QMatrix4x4& other) inline QMatrix4x4& QMatrix4x4::operator*=(const QMatrix4x4& other) { - if (flagBits == Identity) { - *this = other; - return *this; - } else if (other.flagBits == Identity) { - return *this; - } else { - *this = *this * other; + flagBits |= other.flagBits; + + if (flagBits < Rotation2D) { + m[3][0] += m[0][0] * other.m[3][0]; + m[3][1] += m[1][1] * other.m[3][1]; + m[3][2] += m[2][2] * other.m[3][2]; + + m[0][0] *= other.m[0][0]; + m[1][1] *= other.m[1][1]; + m[2][2] *= other.m[2][2]; return *this; } + + qreal m0, m1, m2; + m0 = m[0][0] * other.m[0][0] + + m[1][0] * other.m[0][1] + + m[2][0] * other.m[0][2] + + m[3][0] * other.m[0][3]; + m1 = m[0][0] * other.m[1][0] + + m[1][0] * other.m[1][1] + + m[2][0] * other.m[1][2] + + m[3][0] * other.m[1][3]; + m2 = m[0][0] * other.m[2][0] + + m[1][0] * other.m[2][1] + + m[2][0] * other.m[2][2] + + m[3][0] * other.m[2][3]; + m[3][0] = m[0][0] * other.m[3][0] + + m[1][0] * other.m[3][1] + + m[2][0] * other.m[3][2] + + m[3][0] * other.m[3][3]; + m[0][0] = m0; + m[1][0] = m1; + m[2][0] = m2; + + m0 = m[0][1] * other.m[0][0] + + m[1][1] * other.m[0][1] + + m[2][1] * other.m[0][2] + + m[3][1] * other.m[0][3]; + m1 = m[0][1] * other.m[1][0] + + m[1][1] * other.m[1][1] + + m[2][1] * other.m[1][2] + + m[3][1] * other.m[1][3]; + m2 = m[0][1] * other.m[2][0] + + m[1][1] * other.m[2][1] + + m[2][1] * other.m[2][2] + + m[3][1] * other.m[2][3]; + m[3][1] = m[0][1] * other.m[3][0] + + m[1][1] * other.m[3][1] + + m[2][1] * other.m[3][2] + + m[3][1] * other.m[3][3]; + m[0][1] = m0; + m[1][1] = m1; + m[2][1] = m2; + + m0 = m[0][2] * other.m[0][0] + + m[1][2] * other.m[0][1] + + m[2][2] * other.m[0][2] + + m[3][2] * other.m[0][3]; + m1 = m[0][2] * other.m[1][0] + + m[1][2] * other.m[1][1] + + m[2][2] * other.m[1][2] + + m[3][2] * other.m[1][3]; + m2 = m[0][2] * other.m[2][0] + + m[1][2] * other.m[2][1] + + m[2][2] * other.m[2][2] + + m[3][2] * other.m[2][3]; + m[3][2] = m[0][2] * other.m[3][0] + + m[1][2] * other.m[3][1] + + m[2][2] * other.m[3][2] + + m[3][2] * other.m[3][3]; + m[0][2] = m0; + m[1][2] = m1; + m[2][2] = m2; + + m0 = m[0][3] * other.m[0][0] + + m[1][3] * other.m[0][1] + + m[2][3] * other.m[0][2] + + m[3][3] * other.m[0][3]; + m1 = m[0][3] * other.m[1][0] + + m[1][3] * other.m[1][1] + + m[2][3] * other.m[1][2] + + m[3][3] * other.m[1][3]; + m2 = m[0][3] * other.m[2][0] + + m[1][3] * other.m[2][1] + + m[2][3] * other.m[2][2] + + m[3][3] * other.m[2][3]; + m[3][3] = m[0][3] * other.m[3][0] + + m[1][3] * other.m[3][1] + + m[2][3] * other.m[3][2] + + m[3][3] * other.m[3][3]; + m[0][3] = m0; + m[1][3] = m1; + m[2][3] = m2; + return *this; } inline QMatrix4x4& QMatrix4x4::operator*=(qreal factor) @@ -501,6 +593,7 @@ inline QMatrix4x4 operator+(const QMatrix4x4& m1, const QMatrix4x4& m2) m.m[3][1] = m1.m[3][1] + m2.m[3][1]; m.m[3][2] = m1.m[3][2] + m2.m[3][2]; m.m[3][3] = m1.m[3][3] + m2.m[3][3]; + m.flagBits = QMatrix4x4::General; return m; } @@ -523,81 +616,95 @@ inline QMatrix4x4 operator-(const QMatrix4x4& m1, const QMatrix4x4& m2) m.m[3][1] = m1.m[3][1] - m2.m[3][1]; m.m[3][2] = m1.m[3][2] - m2.m[3][2]; m.m[3][3] = m1.m[3][3] - m2.m[3][3]; + m.flagBits = QMatrix4x4::General; return m; } inline QMatrix4x4 operator*(const QMatrix4x4& m1, const QMatrix4x4& m2) { - if (m1.flagBits == QMatrix4x4::Identity) - return m2; - else if (m2.flagBits == QMatrix4x4::Identity) - return m1; + int flagBits = m1.flagBits | m2.flagBits; + if (flagBits < QMatrix4x4::Rotation2D) { + QMatrix4x4 m = m1; + m.m[3][0] += m.m[0][0] * m2.m[3][0]; + m.m[3][1] += m.m[1][1] * m2.m[3][1]; + m.m[3][2] += m.m[2][2] * m2.m[3][2]; + + m.m[0][0] *= m2.m[0][0]; + m.m[1][1] *= m2.m[1][1]; + m.m[2][2] *= m2.m[2][2]; + m.flagBits = flagBits; + return m; + } QMatrix4x4 m(1); - m.m[0][0] = m1.m[0][0] * m2.m[0][0] + - m1.m[1][0] * m2.m[0][1] + - m1.m[2][0] * m2.m[0][2] + - m1.m[3][0] * m2.m[0][3]; - m.m[0][1] = m1.m[0][1] * m2.m[0][0] + - m1.m[1][1] * m2.m[0][1] + - m1.m[2][1] * m2.m[0][2] + - m1.m[3][1] * m2.m[0][3]; - m.m[0][2] = m1.m[0][2] * m2.m[0][0] + - m1.m[1][2] * m2.m[0][1] + - m1.m[2][2] * m2.m[0][2] + - m1.m[3][2] * m2.m[0][3]; - m.m[0][3] = m1.m[0][3] * m2.m[0][0] + - m1.m[1][3] * m2.m[0][1] + - m1.m[2][3] * m2.m[0][2] + - m1.m[3][3] * m2.m[0][3]; - m.m[1][0] = m1.m[0][0] * m2.m[1][0] + - m1.m[1][0] * m2.m[1][1] + - m1.m[2][0] * m2.m[1][2] + - m1.m[3][0] * m2.m[1][3]; - m.m[1][1] = m1.m[0][1] * m2.m[1][0] + - m1.m[1][1] * m2.m[1][1] + - m1.m[2][1] * m2.m[1][2] + - m1.m[3][1] * m2.m[1][3]; - m.m[1][2] = m1.m[0][2] * m2.m[1][0] + - m1.m[1][2] * m2.m[1][1] + - m1.m[2][2] * m2.m[1][2] + - m1.m[3][2] * m2.m[1][3]; - m.m[1][3] = m1.m[0][3] * m2.m[1][0] + - m1.m[1][3] * m2.m[1][1] + - m1.m[2][3] * m2.m[1][2] + - m1.m[3][3] * m2.m[1][3]; - m.m[2][0] = m1.m[0][0] * m2.m[2][0] + - m1.m[1][0] * m2.m[2][1] + - m1.m[2][0] * m2.m[2][2] + - m1.m[3][0] * m2.m[2][3]; - m.m[2][1] = m1.m[0][1] * m2.m[2][0] + - m1.m[1][1] * m2.m[2][1] + - m1.m[2][1] * m2.m[2][2] + - m1.m[3][1] * m2.m[2][3]; - m.m[2][2] = m1.m[0][2] * m2.m[2][0] + - m1.m[1][2] * m2.m[2][1] + - m1.m[2][2] * m2.m[2][2] + - m1.m[3][2] * m2.m[2][3]; - m.m[2][3] = m1.m[0][3] * m2.m[2][0] + - m1.m[1][3] * m2.m[2][1] + - m1.m[2][3] * m2.m[2][2] + - m1.m[3][3] * m2.m[2][3]; - m.m[3][0] = m1.m[0][0] * m2.m[3][0] + - m1.m[1][0] * m2.m[3][1] + - m1.m[2][0] * m2.m[3][2] + - m1.m[3][0] * m2.m[3][3]; - m.m[3][1] = m1.m[0][1] * m2.m[3][0] + - m1.m[1][1] * m2.m[3][1] + - m1.m[2][1] * m2.m[3][2] + - m1.m[3][1] * m2.m[3][3]; - m.m[3][2] = m1.m[0][2] * m2.m[3][0] + - m1.m[1][2] * m2.m[3][1] + - m1.m[2][2] * m2.m[3][2] + - m1.m[3][2] * m2.m[3][3]; - m.m[3][3] = m1.m[0][3] * m2.m[3][0] + - m1.m[1][3] * m2.m[3][1] + - m1.m[2][3] * m2.m[3][2] + - m1.m[3][3] * m2.m[3][3]; + m.m[0][0] = m1.m[0][0] * m2.m[0][0] + + m1.m[1][0] * m2.m[0][1] + + m1.m[2][0] * m2.m[0][2] + + m1.m[3][0] * m2.m[0][3]; + m.m[0][1] = m1.m[0][1] * m2.m[0][0] + + m1.m[1][1] * m2.m[0][1] + + m1.m[2][1] * m2.m[0][2] + + m1.m[3][1] * m2.m[0][3]; + m.m[0][2] = m1.m[0][2] * m2.m[0][0] + + m1.m[1][2] * m2.m[0][1] + + m1.m[2][2] * m2.m[0][2] + + m1.m[3][2] * m2.m[0][3]; + m.m[0][3] = m1.m[0][3] * m2.m[0][0] + + m1.m[1][3] * m2.m[0][1] + + m1.m[2][3] * m2.m[0][2] + + m1.m[3][3] * m2.m[0][3]; + + m.m[1][0] = m1.m[0][0] * m2.m[1][0] + + m1.m[1][0] * m2.m[1][1] + + m1.m[2][0] * m2.m[1][2] + + m1.m[3][0] * m2.m[1][3]; + m.m[1][1] = m1.m[0][1] * m2.m[1][0] + + m1.m[1][1] * m2.m[1][1] + + m1.m[2][1] * m2.m[1][2] + + m1.m[3][1] * m2.m[1][3]; + m.m[1][2] = m1.m[0][2] * m2.m[1][0] + + m1.m[1][2] * m2.m[1][1] + + m1.m[2][2] * m2.m[1][2] + + m1.m[3][2] * m2.m[1][3]; + m.m[1][3] = m1.m[0][3] * m2.m[1][0] + + m1.m[1][3] * m2.m[1][1] + + m1.m[2][3] * m2.m[1][2] + + m1.m[3][3] * m2.m[1][3]; + + m.m[2][0] = m1.m[0][0] * m2.m[2][0] + + m1.m[1][0] * m2.m[2][1] + + m1.m[2][0] * m2.m[2][2] + + m1.m[3][0] * m2.m[2][3]; + m.m[2][1] = m1.m[0][1] * m2.m[2][0] + + m1.m[1][1] * m2.m[2][1] + + m1.m[2][1] * m2.m[2][2] + + m1.m[3][1] * m2.m[2][3]; + m.m[2][2] = m1.m[0][2] * m2.m[2][0] + + m1.m[1][2] * m2.m[2][1] + + m1.m[2][2] * m2.m[2][2] + + m1.m[3][2] * m2.m[2][3]; + m.m[2][3] = m1.m[0][3] * m2.m[2][0] + + m1.m[1][3] * m2.m[2][1] + + m1.m[2][3] * m2.m[2][2] + + m1.m[3][3] * m2.m[2][3]; + + m.m[3][0] = m1.m[0][0] * m2.m[3][0] + + m1.m[1][0] * m2.m[3][1] + + m1.m[2][0] * m2.m[3][2] + + m1.m[3][0] * m2.m[3][3]; + m.m[3][1] = m1.m[0][1] * m2.m[3][0] + + m1.m[1][1] * m2.m[3][1] + + m1.m[2][1] * m2.m[3][2] + + m1.m[3][1] * m2.m[3][3]; + m.m[3][2] = m1.m[0][2] * m2.m[3][0] + + m1.m[1][2] * m2.m[3][1] + + m1.m[2][2] * m2.m[3][2] + + m1.m[3][2] * m2.m[3][3]; + m.m[3][3] = m1.m[0][3] * m2.m[3][0] + + m1.m[1][3] * m2.m[3][1] + + m1.m[2][3] * m2.m[3][2] + + m1.m[3][3] * m2.m[3][3]; + m.flagBits = flagBits; return m; } @@ -633,19 +740,16 @@ inline QVector3D operator*(const QMatrix4x4& matrix, const QVector3D& vector) qreal x, y, z, w; if (matrix.flagBits == QMatrix4x4::Identity) { return vector; - } else if (matrix.flagBits == QMatrix4x4::Translation) { - return QVector3D(vector.x() + matrix.m[3][0], - vector.y() + matrix.m[3][1], - vector.z() + matrix.m[3][2]); - } else if (matrix.flagBits == - (QMatrix4x4::Translation | QMatrix4x4::Scale)) { + } else if (matrix.flagBits < QMatrix4x4::Rotation2D) { + // Translation | Scale return QVector3D(vector.x() * matrix.m[0][0] + matrix.m[3][0], vector.y() * matrix.m[1][1] + matrix.m[3][1], vector.z() * matrix.m[2][2] + matrix.m[3][2]); - } else if (matrix.flagBits == QMatrix4x4::Scale) { - return QVector3D(vector.x() * matrix.m[0][0], - vector.y() * matrix.m[1][1], - vector.z() * matrix.m[2][2]); + } else if (matrix.flagBits < QMatrix4x4::Rotation) { + // Translation | Scale | Rotation2D + return QVector3D(vector.x() * matrix.m[0][0] + vector.y() * matrix.m[1][0] + matrix.m[3][0], + vector.x() * matrix.m[0][1] + vector.y() * matrix.m[1][1] + matrix.m[3][1], + vector.z() * matrix.m[2][2] + matrix.m[3][2]); } else { x = vector.x() * matrix.m[0][0] + vector.y() * matrix.m[1][0] + @@ -771,16 +875,13 @@ inline QPoint operator*(const QMatrix4x4& matrix, const QPoint& point) yin = point.y(); if (matrix.flagBits == QMatrix4x4::Identity) { return point; - } else if (matrix.flagBits == QMatrix4x4::Translation) { - return QPoint(qRound(xin + matrix.m[3][0]), - qRound(yin + matrix.m[3][1])); - } else if (matrix.flagBits == - (QMatrix4x4::Translation | QMatrix4x4::Scale)) { + } else if (matrix.flagBits < QMatrix4x4::Rotation2D) { + // Translation | Scale return QPoint(qRound(xin * matrix.m[0][0] + matrix.m[3][0]), qRound(yin * matrix.m[1][1] + matrix.m[3][1])); - } else if (matrix.flagBits == QMatrix4x4::Scale) { - return QPoint(qRound(xin * matrix.m[0][0]), - qRound(yin * matrix.m[1][1])); + } else if (matrix.flagBits < QMatrix4x4::Perspective) { + return QPoint(qRound(xin * matrix.m[0][0] + yin * matrix.m[1][0] + matrix.m[3][0]), + qRound(xin * matrix.m[0][1] + yin * matrix.m[1][1] + matrix.m[3][1])); } else { x = xin * matrix.m[0][0] + yin * matrix.m[1][0] + @@ -806,16 +907,13 @@ inline QPointF operator*(const QMatrix4x4& matrix, const QPointF& point) yin = point.y(); if (matrix.flagBits == QMatrix4x4::Identity) { return point; - } else if (matrix.flagBits == QMatrix4x4::Translation) { - return QPointF(xin + matrix.m[3][0], - yin + matrix.m[3][1]); - } else if (matrix.flagBits == - (QMatrix4x4::Translation | QMatrix4x4::Scale)) { + } else if (matrix.flagBits < QMatrix4x4::Rotation2D) { + // Translation | Scale return QPointF(xin * matrix.m[0][0] + matrix.m[3][0], yin * matrix.m[1][1] + matrix.m[3][1]); - } else if (matrix.flagBits == QMatrix4x4::Scale) { - return QPointF(xin * matrix.m[0][0], - yin * matrix.m[1][1]); + } else if (matrix.flagBits < QMatrix4x4::Perspective) { + return QPointF(xin * matrix.m[0][0] + yin * matrix.m[1][0] + matrix.m[3][0], + xin * matrix.m[0][1] + yin * matrix.m[1][1] + matrix.m[3][1]); } else { x = xin * matrix.m[0][0] + yin * matrix.m[1][0] + @@ -853,6 +951,7 @@ inline QMatrix4x4 operator-(const QMatrix4x4& matrix) m.m[3][1] = -matrix.m[3][1]; m.m[3][2] = -matrix.m[3][2]; m.m[3][3] = -matrix.m[3][3]; + m.flagBits = QMatrix4x4::General; return m; } @@ -875,6 +974,7 @@ inline QMatrix4x4 operator*(qreal factor, const QMatrix4x4& matrix) m.m[3][1] = matrix.m[3][1] * factor; m.m[3][2] = matrix.m[3][2] * factor; m.m[3][3] = matrix.m[3][3] * factor; + m.flagBits = QMatrix4x4::General; return m; } @@ -897,6 +997,7 @@ inline QMatrix4x4 operator*(const QMatrix4x4& matrix, qreal factor) m.m[3][1] = matrix.m[3][1] * factor; m.m[3][2] = matrix.m[3][2] * factor; m.m[3][3] = matrix.m[3][3] * factor; + m.flagBits = QMatrix4x4::General; return m; } @@ -939,9 +1040,11 @@ inline QVector3D QMatrix4x4::map(const QVector3D& point) const inline QVector3D QMatrix4x4::mapVector(const QVector3D& vector) const { - if (flagBits == Identity || flagBits == Translation) { + if (flagBits < Scale) { + // Translation return vector; - } else if (flagBits == Scale || flagBits == (Translation | Scale)) { + } else if (flagBits < Rotation2D) { + // Translation | Scale return QVector3D(vector.x() * m[0][0], vector.y() * m[1][1], vector.z() * m[2][2]); -- cgit v1.2.3