summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
authorKim Motoyoshi Kalland <kim.kalland@nokia.com>2011-08-19 15:00:41 +0200
committerQt by Nokia <qt-info@nokia.com>2011-08-29 10:16:01 +0200
commit13b3545e833f6175f686c9776e1510db3f3f11eb (patch)
tree6244e1d3e9cb47ab2063ec2c7f76e66cf2dec340 /src/gui
parentd7305c10948f501450b6b3358d261217d13c6d6e (diff)
Optimized QMatrix4x4 by improving how 'flagBits' are used.
Change-Id: Ic417336489d334e25b547c719d457faf65307cac Reviewed-on: http://codereview.qt.nokia.com/3670 Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com> Reviewed-by: Gunnar Sletta <gunnar.sletta@nokia.com>
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/math3d/qmatrix4x4.cpp659
-rw-r--r--src/gui/math3d/qmatrix4x4.h321
2 files changed, 572 insertions, 408 deletions
diff --git a/src/gui/math3d/qmatrix4x4.cpp b/src/gui/math3d/qmatrix4x4.cpp
index cef92af66b..1797564a98 100644
--- a/src/gui/math3d/qmatrix4x4.cpp
+++ b/src/gui/math3d/qmatrix4x4.cpp
@@ -209,7 +209,7 @@ QMatrix4x4::QMatrix4x4(const QMatrix& matrix)
m[3][1] = matrix.dy();
m[3][2] = 0.0f;
m[3][3] = 1.0f;
- flagBits = General;
+ flagBits = Translation | Scale | Rotation2D;
}
/*!
@@ -316,6 +316,12 @@ QMatrix4x4::QMatrix4x4(const QTransform& transform)
Fills all elements of this matrx with \a value.
*/
+static inline qreal matrixDet2(const qreal m[4][4], int col0, int col1, int row0, int row1)
+{
+ return m[col0][row0] * m[col1][row1] - m[col0][row1] * m[col1][row0];
+}
+
+
// The 4x4 matrix inverse algorithm is based on that described at:
// http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q24
// Some optimization has been done to avoid making copies of 3x3
@@ -329,15 +335,9 @@ static inline qreal matrixDet3
(const qreal m[4][4], int col0, int col1, int col2,
int row0, int row1, int row2)
{
- return m[col0][row0] *
- (m[col1][row1] * m[col2][row2] -
- m[col1][row2] * m[col2][row1]) -
- m[col1][row0] *
- (m[col0][row1] * m[col2][row2] -
- m[col0][row2] * m[col2][row1]) +
- m[col2][row0] *
- (m[col0][row1] * m[col1][row2] -
- m[col0][row2] * m[col1][row1]);
+ return m[col0][row0] * matrixDet2(m, col1, col2, row1, row2)
+ - m[col1][row0] * matrixDet2(m, col0, col2, row1, row2)
+ + m[col2][row0] * matrixDet2(m, col0, col1, row1, row2);
}
// Calculate the determinant of a 4x4 matrix.
@@ -356,7 +356,13 @@ static inline qreal matrixDet4(const qreal m[4][4])
*/
qreal QMatrix4x4::determinant() const
{
- return qreal(matrixDet4(m));
+ if ((flagBits & ~(Translation | Rotation2D | Rotation)) == Identity)
+ return 1;
+ if (flagBits < Rotation2D)
+ return m[0][0] * m[1][1] * m[2][2]; // Translation | Scale
+ if (flagBits < Perspective)
+ return matrixDet3(m, 0, 1, 2, 0, 1, 2);
+ return matrixDet4(m);
}
/*!
@@ -387,10 +393,61 @@ QMatrix4x4 QMatrix4x4::inverted(bool *invertible) const
if (invertible)
*invertible = true;
return inv;
- } else if (flagBits == Rotation || flagBits == (Rotation | Translation)) {
+ } else if (flagBits < Rotation2D) {
+ // Translation | Scale
+ if (m[0][0] == 0 || m[1][1] == 0 || m[2][2] == 0) {
+ if (invertible)
+ *invertible = false;
+ return QMatrix4x4();
+ }
+ QMatrix4x4 inv;
+ inv.m[0][0] = 1.0f / m[0][0];
+ inv.m[1][1] = 1.0f / m[1][1];
+ inv.m[2][2] = 1.0f / m[2][2];
+ inv.m[3][0] = -m[3][0] * inv.m[0][0];
+ inv.m[3][1] = -m[3][1] * inv.m[1][1];
+ inv.m[3][2] = -m[3][2] * inv.m[2][2];
+ inv.flagBits = flagBits;
+
+ if (invertible)
+ *invertible = true;
+ return inv;
+ } else if ((flagBits & ~(Translation | Rotation2D | Rotation)) == Identity) {
if (invertible)
*invertible = true;
return orthonormalInverse();
+ } else if (flagBits < Perspective) {
+ QMatrix4x4 inv(1); // The "1" says to not load the identity.
+
+ qreal det = matrixDet3(m, 0, 1, 2, 0, 1, 2);
+ if (det == 0.0f) {
+ if (invertible)
+ *invertible = false;
+ return QMatrix4x4();
+ }
+ det = 1.0f / det;
+
+ inv.m[0][0] = matrixDet2(m, 1, 2, 1, 2) * det;
+ inv.m[0][1] = -matrixDet2(m, 0, 2, 1, 2) * det;
+ inv.m[0][2] = matrixDet2(m, 0, 1, 1, 2) * det;
+ inv.m[0][3] = 0;
+ inv.m[1][0] = -matrixDet2(m, 1, 2, 0, 2) * det;
+ inv.m[1][1] = matrixDet2(m, 0, 2, 0, 2) * det;
+ inv.m[1][2] = -matrixDet2(m, 0, 1, 0, 2) * det;
+ inv.m[1][3] = 0;
+ inv.m[2][0] = matrixDet2(m, 1, 2, 0, 1) * det;
+ inv.m[2][1] = -matrixDet2(m, 0, 2, 0, 1) * det;
+ inv.m[2][2] = matrixDet2(m, 0, 1, 0, 1) * det;
+ inv.m[2][3] = 0;
+ inv.m[3][0] = -inv.m[0][0] * m[3][0] - inv.m[1][0] * m[3][1] - inv.m[2][0] * m[3][2];
+ inv.m[3][1] = -inv.m[0][1] * m[3][0] - inv.m[1][1] * m[3][1] - inv.m[2][1] * m[3][2];
+ inv.m[3][2] = -inv.m[0][2] * m[3][0] - inv.m[1][2] * m[3][1] - inv.m[2][2] * m[3][2];
+ inv.m[3][3] = 1;
+ inv.flagBits = flagBits;
+
+ if (invertible)
+ *invertible = true;
+ return inv;
}
QMatrix4x4 inv(1); // The "1" says to not load the identity.
@@ -419,6 +476,7 @@ QMatrix4x4 QMatrix4x4::inverted(bool *invertible) const
inv.m[3][1] = matrixDet3(m, 0, 2, 3, 0, 1, 2) * det;
inv.m[3][2] = -matrixDet3(m, 0, 1, 3, 0, 1, 2) * det;
inv.m[3][3] = matrixDet3(m, 0, 1, 2, 0, 1, 2) * det;
+ inv.flagBits = flagBits;
if (invertible)
*invertible = true;
@@ -438,15 +496,29 @@ QMatrix3x3 QMatrix4x4::normalMatrix() const
QMatrix3x3 inv;
// Handle the simple cases first.
- if (flagBits == Identity || flagBits == Translation) {
+ if (flagBits < Scale) {
+ // Translation
return inv;
- } else if (flagBits == Scale || flagBits == (Translation | Scale)) {
+ } else if (flagBits < Rotation2D) {
+ // Translation | Scale
if (m[0][0] == 0.0f || m[1][1] == 0.0f || m[2][2] == 0.0f)
return inv;
inv.data()[0] = 1.0f / m[0][0];
inv.data()[4] = 1.0f / m[1][1];
inv.data()[8] = 1.0f / m[2][2];
return inv;
+ } else if ((flagBits & ~(Translation | Rotation2D | Rotation)) == Identity) {
+ qreal *invm = inv.data();
+ invm[0 + 0 * 3] = m[0][0];
+ invm[1 + 0 * 3] = m[0][1];
+ invm[2 + 0 * 3] = m[0][2];
+ invm[0 + 1 * 3] = m[1][0];
+ invm[1 + 1 * 3] = m[1][1];
+ invm[2 + 1 * 3] = m[1][2];
+ invm[0 + 2 * 3] = m[2][0];
+ invm[1 + 2 * 3] = m[2][1];
+ invm[2 + 2 * 3] = m[2][2];
+ return inv;
}
qreal det = matrixDet3(m, 0, 1, 2, 0, 1, 2);
@@ -481,6 +553,8 @@ QMatrix4x4 QMatrix4x4::transposed() const
result.m[col][row] = m[row][col];
}
}
+ // When a translation is transposed, it becomes a perspective transformation.
+ result.flagBits = (flagBits & Translation ? General : flagBits);
return result;
}
@@ -689,6 +763,7 @@ QMatrix4x4 operator/(const QMatrix4x4& matrix, qreal divisor)
m.m[3][1] = matrix.m[3][1] / divisor;
m.m[3][2] = matrix.m[3][2] / divisor;
m.m[3][3] = matrix.m[3][3] / divisor;
+ m.flagBits = QMatrix4x4::General;
return m;
}
@@ -713,20 +788,20 @@ void QMatrix4x4::scale(const QVector3D& vector)
qreal vx = vector.x();
qreal vy = vector.y();
qreal vz = vector.z();
- if (flagBits == Identity) {
+ if (flagBits < Scale) {
m[0][0] = vx;
m[1][1] = vy;
m[2][2] = vz;
- flagBits = Scale;
- } else if (flagBits == Scale || flagBits == (Scale | Translation)) {
+ } else if (flagBits < Rotation2D) {
m[0][0] *= vx;
m[1][1] *= vy;
m[2][2] *= vz;
- } else if (flagBits == Translation) {
- m[0][0] = vx;
- m[1][1] = vy;
- m[2][2] = vz;
- flagBits |= Scale;
+ } else if (flagBits < Rotation) {
+ m[0][0] *= vx;
+ m[0][1] *= vx;
+ m[1][0] *= vy;
+ m[1][1] *= vy;
+ m[2][2] *= vz;
} else {
m[0][0] *= vx;
m[0][1] *= vx;
@@ -740,9 +815,10 @@ void QMatrix4x4::scale(const QVector3D& vector)
m[2][1] *= vz;
m[2][2] *= vz;
m[2][3] *= vz;
- flagBits = General;
}
+ flagBits |= Scale;
}
+
#endif
/*!
@@ -755,17 +831,17 @@ void QMatrix4x4::scale(const QVector3D& vector)
*/
void QMatrix4x4::scale(qreal x, qreal y)
{
- if (flagBits == Identity) {
+ if (flagBits < Scale) {
m[0][0] = x;
m[1][1] = y;
- flagBits = Scale;
- } else if (flagBits == Scale || flagBits == (Scale | Translation)) {
+ } else if (flagBits < Rotation2D) {
m[0][0] *= x;
m[1][1] *= y;
- } else if (flagBits == Translation) {
- m[0][0] = x;
- m[1][1] = y;
- flagBits |= Scale;
+ } else if (flagBits < Rotation) {
+ m[0][0] *= x;
+ m[0][1] *= x;
+ m[1][0] *= y;
+ m[1][1] *= y;
} else {
m[0][0] *= x;
m[0][1] *= x;
@@ -775,8 +851,8 @@ void QMatrix4x4::scale(qreal x, qreal y)
m[1][1] *= y;
m[1][2] *= y;
m[1][3] *= y;
- flagBits = General;
}
+ flagBits |= Scale;
}
/*!
@@ -789,20 +865,20 @@ void QMatrix4x4::scale(qreal x, qreal y)
*/
void QMatrix4x4::scale(qreal x, qreal y, qreal z)
{
- if (flagBits == Identity) {
+ if (flagBits < Scale) {
m[0][0] = x;
m[1][1] = y;
m[2][2] = z;
- flagBits = Scale;
- } else if (flagBits == Scale || flagBits == (Scale | Translation)) {
+ } else if (flagBits < Rotation2D) {
m[0][0] *= x;
m[1][1] *= y;
m[2][2] *= z;
- } else if (flagBits == Translation) {
- m[0][0] = x;
- m[1][1] = y;
- m[2][2] = z;
- flagBits |= Scale;
+ } else if (flagBits < Rotation) {
+ m[0][0] *= x;
+ m[0][1] *= x;
+ m[1][0] *= y;
+ m[1][1] *= y;
+ m[2][2] *= z;
} else {
m[0][0] *= x;
m[0][1] *= x;
@@ -816,8 +892,8 @@ void QMatrix4x4::scale(qreal x, qreal y, qreal z)
m[2][1] *= z;
m[2][2] *= z;
m[2][3] *= z;
- flagBits = General;
}
+ flagBits |= Scale;
}
/*!
@@ -830,20 +906,20 @@ void QMatrix4x4::scale(qreal x, qreal y, qreal z)
*/
void QMatrix4x4::scale(qreal factor)
{
- if (flagBits == Identity) {
+ if (flagBits < Scale) {
m[0][0] = factor;
m[1][1] = factor;
m[2][2] = factor;
- flagBits = Scale;
- } else if (flagBits == Scale || flagBits == (Scale | Translation)) {
+ } else if (flagBits < Rotation2D) {
m[0][0] *= factor;
m[1][1] *= factor;
m[2][2] *= factor;
- } else if (flagBits == Translation) {
- m[0][0] = factor;
- m[1][1] = factor;
- m[2][2] = factor;
- flagBits |= Scale;
+ } else if (flagBits < Rotation) {
+ m[0][0] *= factor;
+ m[0][1] *= factor;
+ m[1][0] *= factor;
+ m[1][1] *= factor;
+ m[2][2] *= factor;
} else {
m[0][0] *= factor;
m[0][1] *= factor;
@@ -857,8 +933,8 @@ void QMatrix4x4::scale(qreal factor)
m[2][1] *= factor;
m[2][2] *= factor;
m[2][3] *= factor;
- flagBits = General;
}
+ flagBits |= Scale;
}
#ifndef QT_NO_VECTOR3D
@@ -868,6 +944,7 @@ void QMatrix4x4::scale(qreal factor)
\sa scale(), rotate()
*/
+
void QMatrix4x4::translate(const QVector3D& vector)
{
qreal vx = vector.x();
@@ -877,7 +954,6 @@ void QMatrix4x4::translate(const QVector3D& vector)
m[3][0] = vx;
m[3][1] = vy;
m[3][2] = vz;
- flagBits = Translation;
} else if (flagBits == Translation) {
m[3][0] += vx;
m[3][1] += vy;
@@ -886,23 +962,22 @@ void QMatrix4x4::translate(const QVector3D& vector)
m[3][0] = m[0][0] * vx;
m[3][1] = m[1][1] * vy;
m[3][2] = m[2][2] * vz;
- flagBits |= Translation;
- } else if (flagBits == (Scale | Translation)) {
+ } else if (flagBits == (Translation | Scale)) {
m[3][0] += m[0][0] * vx;
m[3][1] += m[1][1] * vy;
m[3][2] += m[2][2] * vz;
+ } else if (flagBits < Rotation) {
+ m[3][0] += m[0][0] * vx + m[1][0] * vy;
+ m[3][1] += m[0][1] * vx + m[1][1] * vy;
+ m[3][2] += m[2][2] * vz;
} else {
m[3][0] += m[0][0] * vx + m[1][0] * vy + m[2][0] * vz;
m[3][1] += m[0][1] * vx + m[1][1] * vy + m[2][1] * vz;
m[3][2] += m[0][2] * vx + m[1][2] * vy + m[2][2] * vz;
m[3][3] += m[0][3] * vx + m[1][3] * vy + m[2][3] * vz;
- if (flagBits == Rotation)
- flagBits |= Translation;
- else if (flagBits != (Rotation | Translation))
- flagBits = General;
}
+ flagBits |= Translation;
}
-
#endif
/*!
@@ -918,28 +993,25 @@ void QMatrix4x4::translate(qreal x, qreal y)
if (flagBits == Identity) {
m[3][0] = x;
m[3][1] = y;
- flagBits = Translation;
} else if (flagBits == Translation) {
m[3][0] += x;
m[3][1] += y;
} else if (flagBits == Scale) {
m[3][0] = m[0][0] * x;
m[3][1] = m[1][1] * y;
- m[3][2] = 0.;
- flagBits |= Translation;
- } else if (flagBits == (Scale | Translation)) {
+ } else if (flagBits == (Translation | Scale)) {
m[3][0] += m[0][0] * x;
m[3][1] += m[1][1] * y;
+ } else if (flagBits < Rotation) {
+ m[3][0] += m[0][0] * x + m[1][0] * y;
+ m[3][1] += m[0][1] * x + m[1][1] * y;
} else {
m[3][0] += m[0][0] * x + m[1][0] * y;
m[3][1] += m[0][1] * x + m[1][1] * y;
m[3][2] += m[0][2] * x + m[1][2] * y;
m[3][3] += m[0][3] * x + m[1][3] * y;
- if (flagBits == Rotation)
- flagBits |= Translation;
- else if (flagBits != (Rotation | Translation))
- flagBits = General;
}
+ flagBits |= Translation;
}
/*!
@@ -956,7 +1028,6 @@ void QMatrix4x4::translate(qreal x, qreal y, qreal z)
m[3][0] = x;
m[3][1] = y;
m[3][2] = z;
- flagBits = Translation;
} else if (flagBits == Translation) {
m[3][0] += x;
m[3][1] += y;
@@ -965,31 +1036,31 @@ void QMatrix4x4::translate(qreal x, qreal y, qreal z)
m[3][0] = m[0][0] * x;
m[3][1] = m[1][1] * y;
m[3][2] = m[2][2] * z;
- flagBits |= Translation;
- } else if (flagBits == (Scale | Translation)) {
+ } else if (flagBits == (Translation | Scale)) {
m[3][0] += m[0][0] * x;
m[3][1] += m[1][1] * y;
m[3][2] += m[2][2] * z;
+ } else if (flagBits < Rotation) {
+ m[3][0] += m[0][0] * x + m[1][0] * y;
+ m[3][1] += m[0][1] * x + m[1][1] * y;
+ m[3][2] += m[2][2] * z;
} else {
m[3][0] += m[0][0] * x + m[1][0] * y + m[2][0] * z;
m[3][1] += m[0][1] * x + m[1][1] * y + m[2][1] * z;
m[3][2] += m[0][2] * x + m[1][2] * y + m[2][2] * z;
m[3][3] += m[0][3] * x + m[1][3] * y + m[2][3] * z;
- if (flagBits == Rotation)
- flagBits |= Translation;
- else if (flagBits != (Rotation | Translation))
- flagBits = General;
}
+ flagBits |= Translation;
}
#ifndef QT_NO_VECTOR3D
-
/*!
Multiples this matrix by another that rotates coordinates through
\a angle degrees about \a vector.
\sa scale(), translate()
*/
+
void QMatrix4x4::rotate(qreal angle, const QVector3D& vector)
{
rotate(angle, vector.x(), vector.y(), vector.z());
@@ -1009,8 +1080,7 @@ void QMatrix4x4::rotate(qreal angle, qreal x, qreal y, qreal z)
{
if (angle == 0.0f)
return;
- QMatrix4x4 m(1); // The "1" says to not load the identity.
- qreal c, s, ic;
+ qreal c, s;
if (angle == 90.0f || angle == -270.0f) {
s = 1.0f;
c = 0.0f;
@@ -1025,86 +1095,87 @@ void QMatrix4x4::rotate(qreal angle, qreal x, qreal y, qreal z)
c = qCos(a);
s = qSin(a);
}
- bool quick = false;
if (x == 0.0f) {
if (y == 0.0f) {
if (z != 0.0f) {
// Rotate around the Z axis.
- m.setToIdentity();
- m.m[0][0] = c;
- m.m[1][1] = c;
- if (z < 0.0f) {
- m.m[1][0] = s;
- m.m[0][1] = -s;
- } else {
- m.m[1][0] = -s;
- m.m[0][1] = s;
- }
- m.flagBits = General;
- quick = true;
+ if (z < 0)
+ s = -s;
+ qreal tmp;
+ m[0][0] = (tmp = m[0][0]) * c + m[1][0] * s;
+ m[1][0] = m[1][0] * c - tmp * s;
+ m[0][1] = (tmp = m[0][1]) * c + m[1][1] * s;
+ m[1][1] = m[1][1] * c - tmp * s;
+ m[0][2] = (tmp = m[0][2]) * c + m[1][2] * s;
+ m[1][2] = m[1][2] * c - tmp * s;
+ m[0][3] = (tmp = m[0][3]) * c + m[1][3] * s;
+ m[1][3] = m[1][3] * c - tmp * s;
+
+ flagBits |= Rotation2D;
+ return;
}
} else if (z == 0.0f) {
// Rotate around the Y axis.
- m.setToIdentity();
- m.m[0][0] = c;
- m.m[2][2] = c;
- if (y < 0.0f) {
- m.m[2][0] = -s;
- m.m[0][2] = s;
- } else {
- m.m[2][0] = s;
- m.m[0][2] = -s;
- }
- m.flagBits = General;
- quick = true;
+ if (y < 0)
+ s = -s;
+ qreal tmp;
+ m[2][0] = (tmp = m[2][0]) * c + m[0][0] * s;
+ m[0][0] = m[0][0] * c - tmp * s;
+ m[2][1] = (tmp = m[2][1]) * c + m[0][1] * s;
+ m[0][1] = m[0][1] * c - tmp * s;
+ m[2][2] = (tmp = m[2][2]) * c + m[0][2] * s;
+ m[0][2] = m[0][2] * c - tmp * s;
+ m[2][3] = (tmp = m[2][3]) * c + m[0][3] * s;
+ m[0][3] = m[0][3] * c - tmp * s;
+
+ flagBits |= Rotation;
+ return;
}
} else if (y == 0.0f && z == 0.0f) {
// Rotate around the X axis.
- m.setToIdentity();
- m.m[1][1] = c;
- m.m[2][2] = c;
- if (x < 0.0f) {
- m.m[2][1] = s;
- m.m[1][2] = -s;
- } else {
- m.m[2][1] = -s;
- m.m[1][2] = s;
- }
- m.flagBits = General;
- quick = true;
+ if (x < 0)
+ s = -s;
+ qreal tmp;
+ m[1][0] = (tmp = m[1][0]) * c + m[2][0] * s;
+ m[2][0] = m[2][0] * c - tmp * s;
+ m[1][1] = (tmp = m[1][1]) * c + m[2][1] * s;
+ m[2][1] = m[2][1] * c - tmp * s;
+ m[1][2] = (tmp = m[1][2]) * c + m[2][2] * s;
+ m[2][2] = m[2][2] * c - tmp * s;
+ m[1][3] = (tmp = m[1][3]) * c + m[2][3] * s;
+ m[2][3] = m[2][3] * c - tmp * s;
+
+ flagBits |= Rotation;
+ return;
}
- if (!quick) {
- qreal len = x * x + y * y + z * z;
- if (!qFuzzyIsNull(len - 1.0f) && !qFuzzyIsNull(len)) {
- len = qSqrt(len);
- x /= len;
- y /= len;
- z /= len;
- }
- ic = 1.0f - c;
- m.m[0][0] = x * x * ic + c;
- m.m[1][0] = x * y * ic - z * s;
- m.m[2][0] = x * z * ic + y * s;
- m.m[3][0] = 0.0f;
- m.m[0][1] = y * x * ic + z * s;
- m.m[1][1] = y * y * ic + c;
- m.m[2][1] = y * z * ic - x * s;
- m.m[3][1] = 0.0f;
- m.m[0][2] = x * z * ic - y * s;
- m.m[1][2] = y * z * ic + x * s;
- m.m[2][2] = z * z * ic + c;
- m.m[3][2] = 0.0f;
- m.m[0][3] = 0.0f;
- m.m[1][3] = 0.0f;
- m.m[2][3] = 0.0f;
- m.m[3][3] = 1.0f;
+
+ qreal len = x * x + y * y + z * z;
+ if (!qFuzzyCompare(len, qreal(1)) && !qFuzzyIsNull(len)) {
+ len = qSqrt(len);
+ x /= len;
+ y /= len;
+ z /= len;
}
- int flags = flagBits;
- *this *= m;
- if (flags != Identity)
- flagBits = flags | Rotation;
- else
- flagBits = Rotation;
+ qreal ic = 1.0f - c;
+ QMatrix4x4 rot(1); // The "1" says to not load the identity.
+ rot.m[0][0] = x * x * ic + c;
+ rot.m[1][0] = x * y * ic - z * s;
+ rot.m[2][0] = x * z * ic + y * s;
+ rot.m[3][0] = 0.0f;
+ rot.m[0][1] = y * x * ic + z * s;
+ rot.m[1][1] = y * y * ic + c;
+ rot.m[2][1] = y * z * ic - x * s;
+ rot.m[3][1] = 0.0f;
+ rot.m[0][2] = x * z * ic - y * s;
+ rot.m[1][2] = y * z * ic + x * s;
+ rot.m[2][2] = z * z * ic + c;
+ rot.m[3][2] = 0.0f;
+ rot.m[0][3] = 0.0f;
+ rot.m[1][3] = 0.0f;
+ rot.m[2][3] = 0.0f;
+ rot.m[3][3] = 1.0f;
+ rot.flagBits = Rotation;
+ *this *= rot;
}
/*!
@@ -1116,8 +1187,7 @@ void QMatrix4x4::projectedRotate(qreal angle, qreal x, qreal y, qreal z)
// and projection back to 2D in a single step.
if (angle == 0.0f)
return;
- QMatrix4x4 m(1); // The "1" says to not load the identity.
- qreal c, s, ic;
+ qreal c, s;
if (angle == 90.0f || angle == -270.0f) {
s = 1.0f;
c = 0.0f;
@@ -1132,82 +1202,74 @@ void QMatrix4x4::projectedRotate(qreal angle, qreal x, qreal y, qreal z)
c = qCos(a);
s = qSin(a);
}
- bool quick = false;
if (x == 0.0f) {
if (y == 0.0f) {
if (z != 0.0f) {
// Rotate around the Z axis.
- m.setToIdentity();
- m.m[0][0] = c;
- m.m[1][1] = c;
- if (z < 0.0f) {
- m.m[1][0] = s;
- m.m[0][1] = -s;
- } else {
- m.m[1][0] = -s;
- m.m[0][1] = s;
- }
- m.flagBits = General;
- quick = true;
+ if (z < 0)
+ s = -s;
+ qreal tmp;
+ m[0][0] = (tmp = m[0][0]) * c + m[1][0] * s;
+ m[1][0] = m[1][0] * c - tmp * s;
+ m[0][1] = (tmp = m[0][1]) * c + m[1][1] * s;
+ m[1][1] = m[1][1] * c - tmp * s;
+ m[0][2] = (tmp = m[0][2]) * c + m[1][2] * s;
+ m[1][2] = m[1][2] * c - tmp * s;
+ m[0][3] = (tmp = m[0][3]) * c + m[1][3] * s;
+ m[1][3] = m[1][3] * c - tmp * s;
+
+ flagBits |= Rotation2D;
+ return;
}
} else if (z == 0.0f) {
// Rotate around the Y axis.
- m.setToIdentity();
- m.m[0][0] = c;
- m.m[2][2] = 1.0f;
- if (y < 0.0f) {
- m.m[0][3] = -s * inv_dist_to_plane;
- } else {
- m.m[0][3] = s * inv_dist_to_plane;
- }
- m.flagBits = General;
- quick = true;
+ if (y < 0)
+ s = -s;
+ m[0][0] = m[0][0] * c + m[3][0] * s * inv_dist_to_plane;
+ m[0][1] = m[0][1] * c + m[3][1] * s * inv_dist_to_plane;
+ m[0][2] = m[0][2] * c + m[3][2] * s * inv_dist_to_plane;
+ m[0][3] = m[0][3] * c + m[3][3] * s * inv_dist_to_plane;
+ flagBits = General;
+ return;
}
} else if (y == 0.0f && z == 0.0f) {
// Rotate around the X axis.
- m.setToIdentity();
- m.m[1][1] = c;
- m.m[2][2] = 1.0f;
- if (x < 0.0f) {
- m.m[1][3] = s * inv_dist_to_plane;
- } else {
- m.m[1][3] = -s * inv_dist_to_plane;
- }
- m.flagBits = General;
- quick = true;
+ if (x < 0)
+ s = -s;
+ m[1][0] = m[1][0] * c - m[3][0] * s * inv_dist_to_plane;
+ m[1][1] = m[1][1] * c - m[3][1] * s * inv_dist_to_plane;
+ m[1][2] = m[1][2] * c - m[3][2] * s * inv_dist_to_plane;
+ m[1][3] = m[1][3] * c - m[3][3] * s * inv_dist_to_plane;
+ flagBits = General;
+ return;
}
- if (!quick) {
- qreal len = x * x + y * y + z * z;
- if (!qFuzzyIsNull(len - 1.0f) && !qFuzzyIsNull(len)) {
- len = qSqrt(len);
- x /= len;
- y /= len;
- z /= len;
- }
- ic = 1.0f - c;
- m.m[0][0] = x * x * ic + c;
- m.m[1][0] = x * y * ic - z * s;
- m.m[2][0] = 0.0f;
- m.m[3][0] = 0.0f;
- m.m[0][1] = y * x * ic + z * s;
- m.m[1][1] = y * y * ic + c;
- m.m[2][1] = 0.0f;
- m.m[3][1] = 0.0f;
- m.m[0][2] = 0.0f;
- m.m[1][2] = 0.0f;
- m.m[2][2] = 1.0f;
- m.m[3][2] = 0.0f;
- m.m[0][3] = (x * z * ic - y * s) * -inv_dist_to_plane;
- m.m[1][3] = (y * z * ic + x * s) * -inv_dist_to_plane;
- m.m[2][3] = 0.0f;
- m.m[3][3] = 1.0f;
+ qreal len = x * x + y * y + z * z;
+ if (!qFuzzyIsNull(len - 1.0f) && !qFuzzyIsNull(len)) {
+ len = qSqrt(len);
+ x /= len;
+ y /= len;
+ z /= len;
}
- int flags = flagBits;
- *this *= m;
- if (flags != Identity)
- flagBits = flags | Rotation;
- else
- flagBits = Rotation;
+ qreal ic = 1.0f - c;
+ QMatrix4x4 rot(1); // The "1" says to not load the identity.
+ rot.m[0][0] = x * x * ic + c;
+ rot.m[1][0] = x * y * ic - z * s;
+ rot.m[2][0] = 0.0f;
+ rot.m[3][0] = 0.0f;
+ rot.m[0][1] = y * x * ic + z * s;
+ rot.m[1][1] = y * y * ic + c;
+ rot.m[2][1] = 0.0f;
+ rot.m[3][1] = 0.0f;
+ rot.m[0][2] = 0.0f;
+ rot.m[1][2] = 0.0f;
+ rot.m[2][2] = 1.0f;
+ rot.m[3][2] = 0.0f;
+ rot.m[0][3] = (x * z * ic - y * s) * -inv_dist_to_plane;
+ rot.m[1][3] = (y * z * ic + x * s) * -inv_dist_to_plane;
+ rot.m[2][3] = 0.0f;
+ rot.m[3][3] = 1.0f;
+ rot.flagBits = General;
+ *this *= rot;
}
#ifndef QT_NO_QUATERNION
@@ -1249,12 +1311,8 @@ void QMatrix4x4::rotate(const QQuaternion& quaternion)
m.m[1][3] = 0.0f;
m.m[2][3] = 0.0f;
m.m[3][3] = 1.0f;
- int flags = flagBits;
+ m.flagBits = Rotation;
*this *= m;
- if (flags != Identity)
- flagBits = flags | Rotation;
- else
- flagBits = Rotation;
}
#endif
@@ -1309,22 +1367,6 @@ void QMatrix4x4::ortho(qreal left, qreal right, qreal bottom, qreal top, qreal n
qreal width = right - left;
qreal invheight = top - bottom;
qreal clip = farPlane - nearPlane;
-#ifndef QT_NO_VECTOR3D
- if (clip == 2.0f && (nearPlane + farPlane) == 0.0f) {
- // We can express this projection as a translate and scale
- // which will be more efficient to modify with further
- // transformations than producing a "General" matrix.
- translate(QVector3D
- (-(left + right) / width,
- -(top + bottom) / invheight,
- 0.0f));
- scale(QVector3D
- (2.0f / width,
- 2.0f / invheight,
- -1.0f));
- return;
- }
-#endif
QMatrix4x4 m(1);
m.m[0][0] = 2.0f / width;
m.m[1][0] = 0.0f;
@@ -1342,10 +1384,10 @@ void QMatrix4x4::ortho(qreal left, qreal right, qreal bottom, qreal top, qreal n
m.m[1][3] = 0.0f;
m.m[2][3] = 0.0f;
m.m[3][3] = 1.0f;
+ m.flagBits = Translation | Scale;
// Apply the projection.
*this *= m;
- return;
}
/*!
@@ -1383,6 +1425,7 @@ void QMatrix4x4::frustum(qreal left, qreal right, qreal bottom, qreal top, qreal
m.m[1][3] = 0.0f;
m.m[2][3] = -1.0f;
m.m[3][3] = 0.0f;
+ m.flagBits = General;
// Apply the projection.
*this *= m;
@@ -1426,6 +1469,7 @@ void QMatrix4x4::perspective(qreal angle, qreal aspect, qreal nearPlane, qreal f
m.m[1][3] = 0.0f;
m.m[2][3] = -1.0f;
m.m[3][3] = 0.0f;
+ m.flagBits = General;
// Apply the projection.
*this *= m;
@@ -1446,7 +1490,6 @@ void QMatrix4x4::lookAt(const QVector3D& eye, const QVector3D& center, const QVe
QVector3D upVector = QVector3D::crossProduct(side, forward);
QMatrix4x4 m(1);
-
m.m[0][0] = side.x();
m.m[1][0] = side.y();
m.m[2][0] = side.z();
@@ -1463,6 +1506,7 @@ void QMatrix4x4::lookAt(const QVector3D& eye, const QVector3D& center, const QVe
m.m[1][3] = 0.0f;
m.m[2][3] = 0.0f;
m.m[3][3] = 1.0f;
+ m.flagBits = Rotation;
*this *= m;
translate(-eye);
@@ -1471,6 +1515,8 @@ void QMatrix4x4::lookAt(const QVector3D& eye, const QVector3D& center, const QVe
#endif
/*!
+ \deprecated
+
Flips between right-handed and left-handed coordinate systems
by multiplying the y and z co-ordinates by -1. This is normally
used to create a left-handed orthographic view without scaling
@@ -1480,17 +1526,13 @@ void QMatrix4x4::lookAt(const QVector3D& eye, const QVector3D& center, const QVe
*/
void QMatrix4x4::flipCoordinates()
{
- if (flagBits == Scale || flagBits == (Scale | Translation)) {
+ // Multiplying the y and z coordinates with -1 does NOT flip between right-handed and
+ // left-handed coordinate systems, it just rotates 180 degrees around the x axis, so
+ // I'm deprecating this function.
+ if (flagBits < Rotation2D) {
+ // Translation | Scale
m[1][1] = -m[1][1];
m[2][2] = -m[2][2];
- } else if (flagBits == Translation) {
- m[1][1] = -m[1][1];
- m[2][2] = -m[2][2];
- flagBits |= Scale;
- } else if (flagBits == Identity) {
- m[1][1] = -1.0f;
- m[2][2] = -1.0f;
- flagBits = Scale;
} else {
m[1][0] = -m[1][0];
m[1][1] = -m[1][1];
@@ -1500,8 +1542,8 @@ void QMatrix4x4::flipCoordinates()
m[2][1] = -m[2][1];
m[2][2] = -m[2][2];
m[2][3] = -m[2][3];
- flagBits = General;
}
+ flagBits |= Scale;
}
/*!
@@ -1568,12 +1610,9 @@ QTransform QMatrix4x4::toTransform(qreal distanceToPlane) const
{
if (distanceToPlane == 1024.0f) {
// Optimize the common case with constants.
- return QTransform(m[0][0], m[0][1],
- m[0][3] - m[0][2] * inv_dist_to_plane,
- m[1][0], m[1][1],
- m[1][3] - m[1][2] * inv_dist_to_plane,
- m[3][0], m[3][1],
- m[3][3] - m[3][2] * inv_dist_to_plane);
+ return QTransform(m[0][0], m[0][1], m[0][3] - m[0][2] * inv_dist_to_plane,
+ m[1][0], m[1][1], m[1][3] - m[1][2] * inv_dist_to_plane,
+ m[3][0], m[3][1], m[3][3] - m[3][2] * inv_dist_to_plane);
} else if (distanceToPlane != 0.0f) {
// The following projection matrix is pre-multiplied with "matrix":
// | 1 0 0 0 |
@@ -1654,7 +1693,13 @@ QTransform QMatrix4x4::toTransform(qreal distanceToPlane) const
*/
QRect QMatrix4x4::mapRect(const QRect& rect) const
{
- if (flagBits == (Translation | Scale) || flagBits == Scale) {
+ if (flagBits < Scale) {
+ // Translation
+ return QRect(qRound(rect.x() + m[3][0]),
+ qRound(rect.y() + m[3][1]),
+ rect.width(), rect.height());
+ } else if (flagBits < Rotation2D) {
+ // Translation | Scale
qreal x = rect.x() * m[0][0] + m[3][0];
qreal y = rect.y() * m[1][1] + m[3][1];
qreal w = rect.width() * m[0][0];
@@ -1668,10 +1713,6 @@ QRect QMatrix4x4::mapRect(const QRect& rect) const
y -= h;
}
return QRect(qRound(x), qRound(y), qRound(w), qRound(h));
- } else if (flagBits == Translation) {
- return QRect(qRound(rect.x() + m[3][0]),
- qRound(rect.y() + m[3][1]),
- rect.width(), rect.height());
}
QPoint tl = map(rect.topLeft());
@@ -1698,7 +1739,11 @@ QRect QMatrix4x4::mapRect(const QRect& rect) const
*/
QRectF QMatrix4x4::mapRect(const QRectF& rect) const
{
- if (flagBits == (Translation | Scale) || flagBits == Scale) {
+ if (flagBits < Scale) {
+ // Translation
+ return rect.translated(m[3][0], m[3][1]);
+ } else if (flagBits < Rotation2D) {
+ // Translation | Scale
qreal x = rect.x() * m[0][0] + m[3][0];
qreal y = rect.y() * m[1][1] + m[3][1];
qreal w = rect.width() * m[0][0];
@@ -1712,8 +1757,6 @@ QRectF QMatrix4x4::mapRect(const QRectF& rect) const
y -= h;
}
return QRectF(x, y, w, h);
- } else if (flagBits == Translation) {
- return rect.translated(m[3][0], m[3][1]);
}
QPointF tl = map(rect.topLeft()); QPointF tr = map(rect.topRight());
@@ -1780,6 +1823,8 @@ QMatrix4x4 QMatrix4x4::orthonormalInverse() const
result.m[3][2] = -(result.m[0][2] * m[3][0] + result.m[1][2] * m[3][1] + result.m[2][2] * m[3][2]);
result.m[3][3] = 1.0f;
+ result.flagBits = flagBits;
+
return result;
}
@@ -1805,40 +1850,50 @@ QMatrix4x4 QMatrix4x4::orthonormalInverse() const
*/
void QMatrix4x4::optimize()
{
- // If the last element is not 1, then it can never be special.
- if (m[3][3] != 1.0f) {
- flagBits = General;
+ // If the last row is not (0, 0, 0, 1), the matrix is not a special type.
+ flagBits = General;
+ if (m[0][3] != 0 || m[1][3] != 0 || m[2][3] != 0 || m[3][3] != 1)
return;
- }
- // If the upper three elements m12, m13, and m21 are not all zero,
- // or the lower elements below the diagonal are not all zero, then
- // the matrix can never be special.
- if (m[1][0] != 0.0f || m[2][0] != 0.0f || m[2][1] != 0.0f) {
- flagBits = General;
- return;
- }
- if (m[0][1] != 0.0f || m[0][2] != 0.0f || m[0][3] != 0.0f ||
- m[1][2] != 0.0f || m[1][3] != 0.0f || m[2][3] != 0.0f) {
- flagBits = General;
- return;
+ flagBits &= ~Perspective;
+
+ // If the last column is (0, 0, 0, 1), then there is no translation.
+ if (m[3][0] == 0 && m[3][1] == 0 && m[3][2] == 0)
+ flagBits &= ~Translation;
+
+ // If the two first elements of row 3 and column 3 are 0, then any rotation must be about Z.
+ if (!m[0][2] && !m[1][2] && !m[2][0] && !m[2][1]) {
+ flagBits &= ~Rotation;
+ // If the six non-diagonal elements in the top left 3x3 matrix are 0, there is no rotation.
+ if (!m[0][1] && !m[1][0]) {
+ flagBits &= ~Rotation2D;
+ // Check for identity.
+ if (m[0][0] == 1 && m[1][1] == 1 && m[2][2] == 1)
+ flagBits &= ~Scale;
+ } else {
+ // If the columns are orthonormal and form a right-handed system, then there is no scale.
+ qreal det = matrixDet2(m, 0, 1, 0, 1);
+ qreal lenX = m[0][0] * m[0][0] + m[0][1] * m[0][1];
+ qreal lenY = m[1][0] * m[1][0] + m[1][1] * m[1][1];
+ qreal lenZ = m[2][2];
+ if (qFuzzyCompare(det, qreal(1)) && qFuzzyCompare(lenX, qreal(1))
+ && qFuzzyCompare(lenY, qreal(1)) && qFuzzyCompare(lenZ, qreal(1)))
+ {
+ flagBits &= ~Scale;
+ }
+ }
+ } else {
+ // If the columns are orthonormal and form a right-handed system, then there is no scale.
+ qreal det = matrixDet3(m, 0, 1, 2, 0, 1, 2);
+ qreal lenX = m[0][0] * m[0][0] + m[0][1] * m[0][1] + m[0][2] * m[0][2];
+ qreal lenY = m[1][0] * m[1][0] + m[1][1] * m[1][1] + m[1][2] * m[1][2];
+ qreal lenZ = m[2][0] * m[2][0] + m[2][1] * m[2][1] + m[2][2] * m[2][2];
+ if (qFuzzyCompare(det, qreal(1)) && qFuzzyCompare(lenX, qreal(1))
+ && qFuzzyCompare(lenY, qreal(1)) && qFuzzyCompare(lenZ, qreal(1)))
+ {
+ flagBits &= ~Scale;
+ }
}
-
- // Determine what we have in the remaining regions of the matrix.
- bool identityAlongDiagonal
- = (m[0][0] == 1.0f && m[1][1] == 1.0f && m[2][2] == 1.0f);
- bool translationPresent
- = (m[3][0] != 0.0f || m[3][1] != 0.0f || m[3][2] != 0.0f);
-
- // Now determine the special matrix type.
- if (translationPresent && identityAlongDiagonal)
- flagBits = Translation;
- else if (translationPresent)
- flagBits = (Translation | Scale);
- else if (identityAlongDiagonal)
- flagBits = Identity;
- else
- flagBits = Scale;
}
/*!
@@ -1855,18 +1910,24 @@ QDebug operator<<(QDebug dbg, const QMatrix4x4 &m)
{
// Create a string that represents the matrix type.
QByteArray bits;
- if ((m.flagBits & QMatrix4x4::Identity) != 0)
- bits += "Identity,";
- if ((m.flagBits & QMatrix4x4::General) != 0)
- bits += "General,";
- if ((m.flagBits & QMatrix4x4::Translation) != 0)
- bits += "Translation,";
- if ((m.flagBits & QMatrix4x4::Scale) != 0)
- bits += "Scale,";
- if ((m.flagBits & QMatrix4x4::Rotation) != 0)
- bits += "Rotation,";
- if (bits.size() > 0)
- bits = bits.left(bits.size() - 1);
+ if (m.flagBits == QMatrix4x4::Identity) {
+ bits = "Identity";
+ } else if (m.flagBits == QMatrix4x4::General) {
+ bits = "General";
+ } else {
+ if ((m.flagBits & QMatrix4x4::Translation) != 0)
+ bits += "Translation,";
+ if ((m.flagBits & QMatrix4x4::Scale) != 0)
+ bits += "Scale,";
+ if ((m.flagBits & QMatrix4x4::Rotation2D) != 0)
+ bits += "Rotation2D,";
+ if ((m.flagBits & QMatrix4x4::Rotation) != 0)
+ bits += "Rotation,";
+ if ((m.flagBits & QMatrix4x4::Perspective) != 0)
+ bits += "Perspective,";
+ if (bits.size() > 0)
+ bits = bits.left(bits.size() - 1);
+ }
// Output in row-major order because it is more human-readable.
dbg.nospace() << "QMatrix4x4(type:" << bits.constData() << endl
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]);