Revert "Remove flagBits from QMatrix4x4"

This reverts commit 5ebb03c476.

Reason for revert: Removing flagBits breaks the batchrenderer in declarative, which accesses them via QMatrix4x4_Accessor. If flagBits are still going to be removed, we need to first find a solution for the renderer.

Change-Id: Ib0a3fc7a327926f2245058c0e2ed30e8789aa75d
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
This commit is contained in:
Fabian Kosmale 2020-03-04 10:06:08 +00:00
parent 09f3272814
commit aa6c560a74
3 changed files with 656 additions and 184 deletions

View File

@ -105,6 +105,7 @@ QMatrix4x4::QMatrix4x4(const float *values)
for (int row = 0; row < 4; ++row) for (int row = 0; row < 4; ++row)
for (int col = 0; col < 4; ++col) for (int col = 0; col < 4; ++col)
m[col][row] = values[row * 4 + col]; m[col][row] = values[row * 4 + col];
flagBits = General;
} }
/*! /*!
@ -182,6 +183,7 @@ QMatrix4x4::QMatrix4x4(const float *values, int cols, int rows)
m[col][row] = 0.0f; m[col][row] = 0.0f;
} }
} }
flagBits = General;
} }
/*! /*!
@ -213,6 +215,7 @@ QMatrix4x4::QMatrix4x4(const QTransform& transform)
m[3][1] = transform.dy(); m[3][1] = transform.dy();
m[3][2] = 0.0f; m[3][2] = 0.0f;
m[3][3] = transform.m33(); m[3][3] = transform.m33();
flagBits = General;
} }
/*! /*!
@ -346,11 +349,15 @@ static inline void copyToDoubles(const float m[4][4], double mm[4][4])
*/ */
double QMatrix4x4::determinant() const double QMatrix4x4::determinant() const
{ {
if (isIdentity()) if ((flagBits & ~(Translation | Rotation2D | Rotation)) == Identity)
return 1.0; return 1.0;
double mm[4][4]; double mm[4][4];
copyToDoubles(m, mm); copyToDoubles(m, mm);
if (flagBits < Rotation2D)
return mm[0][0] * mm[1][1] * mm[2][2]; // Translation | Scale
if (flagBits < Perspective)
return matrixDet3(mm, 0, 1, 2, 0, 1, 2);
return matrixDet4(mm); return matrixDet4(mm);
} }
@ -369,10 +376,77 @@ double QMatrix4x4::determinant() const
QMatrix4x4 QMatrix4x4::inverted(bool *invertible) const QMatrix4x4 QMatrix4x4::inverted(bool *invertible) const
{ {
// Handle some of the easy cases first. // Handle some of the easy cases first.
if (isIdentity()) { if (flagBits == Identity) {
if (invertible) if (invertible)
*invertible = true; *invertible = true;
return QMatrix4x4(); return QMatrix4x4();
} else if (flagBits == Translation) {
QMatrix4x4 inv;
inv.m[3][0] = -m[3][0];
inv.m[3][1] = -m[3][1];
inv.m[3][2] = -m[3][2];
inv.flagBits = Translation;
if (invertible)
*invertible = true;
return inv;
} 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.
double mm[4][4];
copyToDoubles(m, mm);
double det = matrixDet3(mm, 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(mm, 1, 2, 1, 2) * det;
inv.m[0][1] = -matrixDet2(mm, 0, 2, 1, 2) * det;
inv.m[0][2] = matrixDet2(mm, 0, 1, 1, 2) * det;
inv.m[0][3] = 0;
inv.m[1][0] = -matrixDet2(mm, 1, 2, 0, 2) * det;
inv.m[1][1] = matrixDet2(mm, 0, 2, 0, 2) * det;
inv.m[1][2] = -matrixDet2(mm, 0, 1, 0, 2) * det;
inv.m[1][3] = 0;
inv.m[2][0] = matrixDet2(mm, 1, 2, 0, 1) * det;
inv.m[2][1] = -matrixDet2(mm, 0, 2, 0, 1) * det;
inv.m[2][2] = matrixDet2(mm, 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. QMatrix4x4 inv(1); // The "1" says to not load the identity.
@ -404,6 +478,7 @@ QMatrix4x4 QMatrix4x4::inverted(bool *invertible) const
inv.m[3][1] = matrixDet3(mm, 0, 2, 3, 0, 1, 2) * det; inv.m[3][1] = matrixDet3(mm, 0, 2, 3, 0, 1, 2) * det;
inv.m[3][2] = -matrixDet3(mm, 0, 1, 3, 0, 1, 2) * det; inv.m[3][2] = -matrixDet3(mm, 0, 1, 3, 0, 1, 2) * det;
inv.m[3][3] = matrixDet3(mm, 0, 1, 2, 0, 1, 2) * det; inv.m[3][3] = matrixDet3(mm, 0, 1, 2, 0, 1, 2) * det;
inv.flagBits = flagBits;
if (invertible) if (invertible)
*invertible = true; *invertible = true;
@ -422,6 +497,32 @@ QMatrix3x3 QMatrix4x4::normalMatrix() const
{ {
QMatrix3x3 inv; QMatrix3x3 inv;
// Handle the simple cases first.
if (flagBits < Scale) {
// Translation
return inv;
} 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) {
float *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;
}
double mm[4][4]; double mm[4][4];
copyToDoubles(m, mm); copyToDoubles(m, mm);
double det = matrixDet3(mm, 0, 1, 2, 0, 1, 2); double det = matrixDet3(mm, 0, 1, 2, 0, 1, 2);
@ -456,6 +557,8 @@ QMatrix4x4 QMatrix4x4::transposed() const
result.m[col][row] = m[row][col]; 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; return result;
} }
@ -507,6 +610,7 @@ QMatrix4x4& QMatrix4x4::operator/=(float divisor)
m[3][1] /= divisor; m[3][1] /= divisor;
m[3][2] /= divisor; m[3][2] /= divisor;
m[3][3] /= divisor; m[3][3] /= divisor;
flagBits = General;
return *this; return *this;
} }
@ -663,6 +767,7 @@ QMatrix4x4 operator/(const QMatrix4x4& matrix, float divisor)
m.m[3][1] = matrix.m[3][1] / divisor; m.m[3][1] = matrix.m[3][1] / divisor;
m.m[3][2] = matrix.m[3][2] / divisor; m.m[3][2] = matrix.m[3][2] / divisor;
m.m[3][3] = matrix.m[3][3] / divisor; m.m[3][3] = matrix.m[3][3] / divisor;
m.flagBits = QMatrix4x4::General;
return m; return m;
} }
@ -684,9 +789,24 @@ QMatrix4x4 operator/(const QMatrix4x4& matrix, float divisor)
*/ */
void QMatrix4x4::scale(const QVector3D& vector) void QMatrix4x4::scale(const QVector3D& vector)
{ {
const float vx = vector.x(); float vx = vector.x();
const float vy = vector.y(); float vy = vector.y();
const float vz = vector.z(); float vz = vector.z();
if (flagBits < Scale) {
m[0][0] = vx;
m[1][1] = vy;
m[2][2] = vz;
} else if (flagBits < Rotation2D) {
m[0][0] *= vx;
m[1][1] *= vy;
m[2][2] *= vz;
} 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][0] *= vx;
m[0][1] *= vx; m[0][1] *= vx;
m[0][2] *= vx; m[0][2] *= vx;
@ -699,6 +819,8 @@ void QMatrix4x4::scale(const QVector3D& vector)
m[2][1] *= vz; m[2][1] *= vz;
m[2][2] *= vz; m[2][2] *= vz;
m[2][3] *= vz; m[2][3] *= vz;
}
flagBits |= Scale;
} }
#endif #endif
@ -713,6 +835,18 @@ void QMatrix4x4::scale(const QVector3D& vector)
*/ */
void QMatrix4x4::scale(float x, float y) void QMatrix4x4::scale(float x, float y)
{ {
if (flagBits < Scale) {
m[0][0] = x;
m[1][1] = y;
} else if (flagBits < Rotation2D) {
m[0][0] *= x;
m[1][1] *= y;
} 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][0] *= x;
m[0][1] *= x; m[0][1] *= x;
m[0][2] *= x; m[0][2] *= x;
@ -721,6 +855,8 @@ void QMatrix4x4::scale(float x, float y)
m[1][1] *= y; m[1][1] *= y;
m[1][2] *= y; m[1][2] *= y;
m[1][3] *= y; m[1][3] *= y;
}
flagBits |= Scale;
} }
/*! /*!
@ -733,6 +869,21 @@ void QMatrix4x4::scale(float x, float y)
*/ */
void QMatrix4x4::scale(float x, float y, float z) void QMatrix4x4::scale(float x, float y, float z)
{ {
if (flagBits < Scale) {
m[0][0] = x;
m[1][1] = y;
m[2][2] = z;
} else if (flagBits < Rotation2D) {
m[0][0] *= x;
m[1][1] *= y;
m[2][2] *= z;
} 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][0] *= x;
m[0][1] *= x; m[0][1] *= x;
m[0][2] *= x; m[0][2] *= x;
@ -745,6 +896,8 @@ void QMatrix4x4::scale(float x, float y, float z)
m[2][1] *= z; m[2][1] *= z;
m[2][2] *= z; m[2][2] *= z;
m[2][3] *= z; m[2][3] *= z;
}
flagBits |= Scale;
} }
/*! /*!
@ -757,6 +910,21 @@ void QMatrix4x4::scale(float x, float y, float z)
*/ */
void QMatrix4x4::scale(float factor) void QMatrix4x4::scale(float factor)
{ {
if (flagBits < Scale) {
m[0][0] = factor;
m[1][1] = factor;
m[2][2] = factor;
} else if (flagBits < Rotation2D) {
m[0][0] *= factor;
m[1][1] *= factor;
m[2][2] *= factor;
} 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][0] *= factor;
m[0][1] *= factor; m[0][1] *= factor;
m[0][2] *= factor; m[0][2] *= factor;
@ -769,6 +937,8 @@ void QMatrix4x4::scale(float factor)
m[2][1] *= factor; m[2][1] *= factor;
m[2][2] *= factor; m[2][2] *= factor;
m[2][3] *= factor; m[2][3] *= factor;
}
flagBits |= Scale;
} }
#ifndef QT_NO_VECTOR3D #ifndef QT_NO_VECTOR3D
@ -781,13 +951,36 @@ void QMatrix4x4::scale(float factor)
void QMatrix4x4::translate(const QVector3D& vector) void QMatrix4x4::translate(const QVector3D& vector)
{ {
const float vx = vector.x(); float vx = vector.x();
const float vy = vector.y(); float vy = vector.y();
const float vz = vector.z(); float vz = vector.z();
if (flagBits == Identity) {
m[3][0] = vx;
m[3][1] = vy;
m[3][2] = vz;
} else if (flagBits == Translation) {
m[3][0] += vx;
m[3][1] += vy;
m[3][2] += vz;
} else if (flagBits == 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 == (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][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][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][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; m[3][3] += m[0][3] * vx + m[1][3] * vy + m[2][3] * vz;
}
flagBits |= Translation;
} }
#endif #endif
@ -801,10 +994,28 @@ void QMatrix4x4::translate(const QVector3D& vector)
*/ */
void QMatrix4x4::translate(float x, float y) void QMatrix4x4::translate(float x, float y)
{ {
if (flagBits == Identity) {
m[3][0] = x;
m[3][1] = y;
} 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;
} 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][0] += m[0][0] * x + m[1][0] * y;
m[3][1] += m[0][1] * x + m[1][1] * 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][2] += m[0][2] * x + m[1][2] * y;
m[3][3] += m[0][3] * x + m[1][3] * y; m[3][3] += m[0][3] * x + m[1][3] * y;
}
flagBits |= Translation;
} }
/*! /*!
@ -817,10 +1028,33 @@ void QMatrix4x4::translate(float x, float y)
*/ */
void QMatrix4x4::translate(float x, float y, float z) void QMatrix4x4::translate(float x, float y, float z)
{ {
if (flagBits == Identity) {
m[3][0] = x;
m[3][1] = y;
m[3][2] = z;
} else if (flagBits == Translation) {
m[3][0] += x;
m[3][1] += y;
m[3][2] += z;
} else if (flagBits == 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 == (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][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][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][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; m[3][3] += m[0][3] * x + m[1][3] * y + m[2][3] * z;
}
flagBits |= Translation;
} }
#ifndef QT_NO_VECTOR3D #ifndef QT_NO_VECTOR3D
@ -881,6 +1115,7 @@ void QMatrix4x4::rotate(float angle, float x, float y, float z)
m[0][3] = (tmp = m[0][3]) * c + m[1][3] * s; m[0][3] = (tmp = m[0][3]) * c + m[1][3] * s;
m[1][3] = m[1][3] * c - tmp * s; m[1][3] = m[1][3] * c - tmp * s;
flagBits |= Rotation2D;
return; return;
} }
} else if (z == 0.0f) { } else if (z == 0.0f) {
@ -897,6 +1132,7 @@ void QMatrix4x4::rotate(float angle, float x, float y, float z)
m[2][3] = (tmp = m[2][3]) * c + m[0][3] * s; m[2][3] = (tmp = m[2][3]) * c + m[0][3] * s;
m[0][3] = m[0][3] * c - tmp * s; m[0][3] = m[0][3] * c - tmp * s;
flagBits |= Rotation;
return; return;
} }
} else if (y == 0.0f && z == 0.0f) { } else if (y == 0.0f && z == 0.0f) {
@ -913,6 +1149,7 @@ void QMatrix4x4::rotate(float angle, float x, float y, float z)
m[1][3] = (tmp = m[1][3]) * c + m[2][3] * s; m[1][3] = (tmp = m[1][3]) * c + m[2][3] * s;
m[2][3] = m[2][3] * c - tmp * s; m[2][3] = m[2][3] * c - tmp * s;
flagBits |= Rotation;
return; return;
} }
@ -943,6 +1180,7 @@ void QMatrix4x4::rotate(float angle, float x, float y, float z)
rot.m[1][3] = 0.0f; rot.m[1][3] = 0.0f;
rot.m[2][3] = 0.0f; rot.m[2][3] = 0.0f;
rot.m[3][3] = 1.0f; rot.m[3][3] = 1.0f;
rot.flagBits = Rotation;
*this *= rot; *this *= rot;
} }
@ -966,7 +1204,7 @@ void QMatrix4x4::projectedRotate(float angle, float x, float y, float z)
s = 0.0f; s = 0.0f;
c = -1.0f; c = -1.0f;
} else { } else {
const float a = qDegreesToRadians(angle); float a = qDegreesToRadians(angle);
c = std::cos(a); c = std::cos(a);
s = std::sin(a); s = std::sin(a);
} }
@ -986,6 +1224,7 @@ void QMatrix4x4::projectedRotate(float angle, float x, float y, float z)
m[0][3] = (tmp = m[0][3]) * c + m[1][3] * s; m[0][3] = (tmp = m[0][3]) * c + m[1][3] * s;
m[1][3] = m[1][3] * c - tmp * s; m[1][3] = m[1][3] * c - tmp * s;
flagBits |= Rotation2D;
return; return;
} }
} else if (z == 0.0f) { } else if (z == 0.0f) {
@ -996,6 +1235,7 @@ void QMatrix4x4::projectedRotate(float angle, float x, float y, float z)
m[0][1] = m[0][1] * c + m[3][1] * 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][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; m[0][3] = m[0][3] * c + m[3][3] * s * inv_dist_to_plane;
flagBits = General;
return; return;
} }
} else if (y == 0.0f && z == 0.0f) { } else if (y == 0.0f && z == 0.0f) {
@ -1006,6 +1246,7 @@ void QMatrix4x4::projectedRotate(float angle, float x, float y, float z)
m[1][1] = m[1][1] * c - m[3][1] * 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][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; m[1][3] = m[1][3] * c - m[3][3] * s * inv_dist_to_plane;
flagBits = General;
return; return;
} }
double len = double(x) * double(x) + double len = double(x) * double(x) +
@ -1017,7 +1258,7 @@ void QMatrix4x4::projectedRotate(float angle, float x, float y, float z)
y = float(double(y) / len); y = float(double(y) / len);
z = float(double(z) / len); z = float(double(z) / len);
} }
const float ic = 1.0f - c; float ic = 1.0f - c;
QMatrix4x4 rot(1); // The "1" says to not load the identity. QMatrix4x4 rot(1); // The "1" says to not load the identity.
rot.m[0][0] = x * x * ic + c; rot.m[0][0] = x * x * ic + c;
rot.m[1][0] = x * y * ic - z * s; rot.m[1][0] = x * y * ic - z * s;
@ -1035,6 +1276,7 @@ void QMatrix4x4::projectedRotate(float angle, float x, float y, float z)
rot.m[1][3] = (y * z * ic + x * 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[2][3] = 0.0f;
rot.m[3][3] = 1.0f; rot.m[3][3] = 1.0f;
rot.flagBits = General;
*this *= rot; *this *= rot;
} }
@ -1083,6 +1325,7 @@ void QMatrix4x4::rotate(const QQuaternion& quaternion)
m.m[1][3] = 0.0f; m.m[1][3] = 0.0f;
m.m[2][3] = 0.0f; m.m[2][3] = 0.0f;
m.m[3][3] = 1.0f; m.m[3][3] = 1.0f;
m.flagBits = Rotation;
*this *= m; *this *= m;
} }
@ -1135,9 +1378,9 @@ void QMatrix4x4::ortho(float left, float right, float bottom, float top, float n
return; return;
// Construct the projection. // Construct the projection.
const float width = right - left; float width = right - left;
const float invheight = top - bottom; float invheight = top - bottom;
const float clip = farPlane - nearPlane; float clip = farPlane - nearPlane;
QMatrix4x4 m(1); QMatrix4x4 m(1);
m.m[0][0] = 2.0f / width; m.m[0][0] = 2.0f / width;
m.m[1][0] = 0.0f; m.m[1][0] = 0.0f;
@ -1155,6 +1398,7 @@ void QMatrix4x4::ortho(float left, float right, float bottom, float top, float n
m.m[1][3] = 0.0f; m.m[1][3] = 0.0f;
m.m[2][3] = 0.0f; m.m[2][3] = 0.0f;
m.m[3][3] = 1.0f; m.m[3][3] = 1.0f;
m.flagBits = Translation | Scale;
// Apply the projection. // Apply the projection.
*this *= m; *this *= m;
@ -1176,9 +1420,9 @@ void QMatrix4x4::frustum(float left, float right, float bottom, float top, float
// Construct the projection. // Construct the projection.
QMatrix4x4 m(1); QMatrix4x4 m(1);
const float width = right - left; float width = right - left;
const float invheight = top - bottom; float invheight = top - bottom;
const float clip = farPlane - nearPlane; float clip = farPlane - nearPlane;
m.m[0][0] = 2.0f * nearPlane / width; m.m[0][0] = 2.0f * nearPlane / width;
m.m[1][0] = 0.0f; m.m[1][0] = 0.0f;
m.m[2][0] = (left + right) / width; m.m[2][0] = (left + right) / width;
@ -1195,6 +1439,7 @@ void QMatrix4x4::frustum(float left, float right, float bottom, float top, float
m.m[1][3] = 0.0f; m.m[1][3] = 0.0f;
m.m[2][3] = -1.0f; m.m[2][3] = -1.0f;
m.m[3][3] = 0.0f; m.m[3][3] = 0.0f;
m.flagBits = General;
// Apply the projection. // Apply the projection.
*this *= m; *this *= m;
@ -1218,12 +1463,12 @@ void QMatrix4x4::perspective(float verticalAngle, float aspectRatio, float nearP
// Construct the projection. // Construct the projection.
QMatrix4x4 m(1); QMatrix4x4 m(1);
const float radians = qDegreesToRadians(verticalAngle / 2.0f); float radians = qDegreesToRadians(verticalAngle / 2.0f);
const float sine = std::sin(radians); float sine = std::sin(radians);
if (sine == 0.0f) if (sine == 0.0f)
return; return;
const float cotan = std::cos(radians) / sine; float cotan = std::cos(radians) / sine;
const float clip = farPlane - nearPlane; float clip = farPlane - nearPlane;
m.m[0][0] = cotan / aspectRatio; m.m[0][0] = cotan / aspectRatio;
m.m[1][0] = 0.0f; m.m[1][0] = 0.0f;
m.m[2][0] = 0.0f; m.m[2][0] = 0.0f;
@ -1240,6 +1485,7 @@ void QMatrix4x4::perspective(float verticalAngle, float aspectRatio, float nearP
m.m[1][3] = 0.0f; m.m[1][3] = 0.0f;
m.m[2][3] = -1.0f; m.m[2][3] = -1.0f;
m.m[3][3] = 0.0f; m.m[3][3] = 0.0f;
m.flagBits = General;
// Apply the projection. // Apply the projection.
*this *= m; *this *= m;
@ -1283,6 +1529,7 @@ void QMatrix4x4::lookAt(const QVector3D& eye, const QVector3D& center, const QVe
m.m[1][3] = 0.0f; m.m[1][3] = 0.0f;
m.m[2][3] = 0.0f; m.m[2][3] = 0.0f;
m.m[3][3] = 1.0f; m.m[3][3] = 1.0f;
m.flagBits = Rotation;
*this *= m; *this *= m;
translate(-eye); translate(-eye);
@ -1331,6 +1578,7 @@ void QMatrix4x4::viewport(float left, float bottom, float width, float height, f
m.m[1][3] = 0.0f; m.m[1][3] = 0.0f;
m.m[2][3] = 0.0f; m.m[2][3] = 0.0f;
m.m[3][3] = 1.0f; m.m[3][3] = 1.0f;
m.flagBits = General;
*this *= m; *this *= m;
} }
@ -1350,6 +1598,11 @@ void QMatrix4x4::flipCoordinates()
// Multiplying the y and z coordinates with -1 does NOT flip between right-handed and // 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 // left-handed coordinate systems, it just rotates 180 degrees around the x axis, so
// I'm deprecating this function. // I'm deprecating this function.
if (flagBits < Rotation2D) {
// Translation | Scale
m[1][1] = -m[1][1];
m[2][2] = -m[2][2];
} else {
m[1][0] = -m[1][0]; m[1][0] = -m[1][0];
m[1][1] = -m[1][1]; m[1][1] = -m[1][1];
m[1][2] = -m[1][2]; m[1][2] = -m[1][2];
@ -1358,6 +1611,8 @@ void QMatrix4x4::flipCoordinates()
m[2][1] = -m[2][1]; m[2][1] = -m[2][1];
m[2][2] = -m[2][2]; m[2][2] = -m[2][2];
m[2][3] = -m[2][3]; m[2][3] = -m[2][3];
}
flagBits |= Scale;
} }
/*! /*!
@ -1421,7 +1676,7 @@ QTransform QMatrix4x4::toTransform(float distanceToPlane) const
// | 0 0 d 1 | // | 0 0 d 1 |
// where d = -1 / distanceToPlane. After projection, row 3 and // where d = -1 / distanceToPlane. After projection, row 3 and
// column 3 are dropped to form the final QTransform. // column 3 are dropped to form the final QTransform.
const float d = 1.0f / distanceToPlane; float d = 1.0f / distanceToPlane;
return QTransform(m[0][0], m[0][1], m[0][3] - m[0][2] * d, return QTransform(m[0][0], m[0][1], m[0][3] - m[0][2] * d,
m[1][0], m[1][1], m[1][3] - m[1][2] * d, m[1][0], m[1][1], m[1][3] - m[1][2] * d,
m[3][0], m[3][1], m[3][3] - m[3][2] * d); m[3][0], m[3][1], m[3][3] - m[3][2] * d);
@ -1493,16 +1748,38 @@ QTransform QMatrix4x4::toTransform(float distanceToPlane) const
*/ */
QRect QMatrix4x4::mapRect(const QRect& rect) const QRect QMatrix4x4::mapRect(const QRect& rect) const
{ {
const QPoint tl = map(rect.topLeft()); if (flagBits < Scale) {
const QPoint tr = map(QPoint(rect.x() + rect.width(), rect.y())); // Translation
const QPoint bl = map(QPoint(rect.x(), rect.y() + rect.height())); return QRect(qRound(rect.x() + m[3][0]),
const QPoint br = map(QPoint(rect.x() + rect.width(), qRound(rect.y() + m[3][1]),
rect.width(), rect.height());
} else if (flagBits < Rotation2D) {
// Translation | Scale
float x = rect.x() * m[0][0] + m[3][0];
float y = rect.y() * m[1][1] + m[3][1];
float w = rect.width() * m[0][0];
float h = rect.height() * m[1][1];
if (w < 0) {
w = -w;
x -= w;
}
if (h < 0) {
h = -h;
y -= h;
}
return QRect(qRound(x), qRound(y), qRound(w), qRound(h));
}
QPoint tl = map(rect.topLeft());
QPoint tr = map(QPoint(rect.x() + rect.width(), rect.y()));
QPoint bl = map(QPoint(rect.x(), rect.y() + rect.height()));
QPoint br = map(QPoint(rect.x() + rect.width(),
rect.y() + rect.height())); rect.y() + rect.height()));
const int xmin = qMin(qMin(tl.x(), tr.x()), qMin(bl.x(), br.x())); int xmin = qMin(qMin(tl.x(), tr.x()), qMin(bl.x(), br.x()));
const int xmax = qMax(qMax(tl.x(), tr.x()), qMax(bl.x(), br.x())); int xmax = qMax(qMax(tl.x(), tr.x()), qMax(bl.x(), br.x()));
const int ymin = qMin(qMin(tl.y(), tr.y()), qMin(bl.y(), br.y())); int ymin = qMin(qMin(tl.y(), tr.y()), qMin(bl.y(), br.y()));
const int ymax = qMax(qMax(tl.y(), tr.y()), qMax(bl.y(), br.y())); int ymax = qMax(qMax(tl.y(), tr.y()), qMax(bl.y(), br.y()));
return QRect(xmin, ymin, xmax - xmin, ymax - ymin); return QRect(xmin, ymin, xmax - xmin, ymax - ymin);
} }
@ -1517,13 +1794,33 @@ QRect QMatrix4x4::mapRect(const QRect& rect) const
*/ */
QRectF QMatrix4x4::mapRect(const QRectF& rect) const QRectF QMatrix4x4::mapRect(const QRectF& rect) const
{ {
const QPointF tl = map(rect.topLeft()); QPointF tr = map(rect.topRight()); if (flagBits < Scale) {
const QPointF bl = map(rect.bottomLeft()); QPointF br = map(rect.bottomRight()); // Translation
return rect.translated(m[3][0], m[3][1]);
} else if (flagBits < Rotation2D) {
// Translation | Scale
float x = rect.x() * m[0][0] + m[3][0];
float y = rect.y() * m[1][1] + m[3][1];
float w = rect.width() * m[0][0];
float h = rect.height() * m[1][1];
if (w < 0) {
w = -w;
x -= w;
}
if (h < 0) {
h = -h;
y -= h;
}
return QRectF(x, y, w, h);
}
const float xmin = qMin(qMin(tl.x(), tr.x()), qMin(bl.x(), br.x())); QPointF tl = map(rect.topLeft()); QPointF tr = map(rect.topRight());
const float xmax = qMax(qMax(tl.x(), tr.x()), qMax(bl.x(), br.x())); QPointF bl = map(rect.bottomLeft()); QPointF br = map(rect.bottomRight());
const float ymin = qMin(qMin(tl.y(), tr.y()), qMin(bl.y(), br.y()));
const float ymax = qMax(qMax(tl.y(), tr.y()), qMax(bl.y(), br.y())); float xmin = qMin(qMin(tl.x(), tr.x()), qMin(bl.x(), br.x()));
float xmax = qMax(qMax(tl.x(), tr.x()), qMax(bl.x(), br.x()));
float ymin = qMin(qMin(tl.y(), tr.y()), qMin(bl.y(), br.y()));
float ymax = qMax(qMax(tl.y(), tr.y()), qMax(bl.y(), br.y()));
return QRectF(QPointF(xmin, ymin), QPointF(xmax, ymax)); return QRectF(QPointF(xmin, ymin), QPointF(xmax, ymax));
} }
@ -1581,6 +1878,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][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.m[3][3] = 1.0f;
result.flagBits = flagBits;
return result; return result;
} }
@ -1606,6 +1905,54 @@ QMatrix4x4 QMatrix4x4::orthonormalInverse() const
*/ */
void QMatrix4x4::optimize() void QMatrix4x4::optimize()
{ {
// 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;
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.
double mm[4][4];
copyToDoubles(m, mm);
double det = matrixDet2(mm, 0, 1, 0, 1);
double lenX = mm[0][0] * mm[0][0] + mm[0][1] * mm[0][1];
double lenY = mm[1][0] * mm[1][0] + mm[1][1] * mm[1][1];
double lenZ = mm[2][2];
if (qFuzzyCompare(det, 1.0) && qFuzzyCompare(lenX, 1.0)
&& qFuzzyCompare(lenY, 1.0) && qFuzzyCompare(lenZ, 1.0))
{
flagBits &= ~Scale;
}
}
} else {
// If the columns are orthonormal and form a right-handed system, then there is no scale.
double mm[4][4];
copyToDoubles(m, mm);
double det = matrixDet3(mm, 0, 1, 2, 0, 1, 2);
double lenX = mm[0][0] * mm[0][0] + mm[0][1] * mm[0][1] + mm[0][2] * mm[0][2];
double lenY = mm[1][0] * mm[1][0] + mm[1][1] * mm[1][1] + mm[1][2] * mm[1][2];
double lenZ = mm[2][0] * mm[2][0] + mm[2][1] * mm[2][1] + mm[2][2] * mm[2][2];
if (qFuzzyCompare(det, 1.0) && qFuzzyCompare(lenX, 1.0)
&& qFuzzyCompare(lenY, 1.0) && qFuzzyCompare(lenZ, 1.0))
{
flagBits &= ~Scale;
}
}
} }
/*! /*!
@ -1623,10 +1970,23 @@ QDebug operator<<(QDebug dbg, const QMatrix4x4 &m)
QDebugStateSaver saver(dbg); QDebugStateSaver saver(dbg);
// Create a string that represents the matrix type. // Create a string that represents the matrix type.
QByteArray bits; QByteArray bits;
if (m.isIdentity()) { if (m.flagBits == QMatrix4x4::Identity) {
bits = "Identity"; bits = "Identity";
} else { } else if (m.flagBits == QMatrix4x4::General) {
bits = "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. // Output in row-major order because it is more human-readable.

View File

@ -59,7 +59,7 @@ class Q_GUI_EXPORT QMatrix4x4
{ {
public: public:
inline QMatrix4x4() { setToIdentity(); } inline QMatrix4x4() { setToIdentity(); }
explicit QMatrix4x4(Qt::Initialization) {} explicit QMatrix4x4(Qt::Initialization) : flagBits(General) {}
explicit QMatrix4x4(const float *values); explicit QMatrix4x4(const float *values);
inline QMatrix4x4(float m11, float m12, float m13, float m14, inline QMatrix4x4(float m11, float m12, float m13, float m14,
float m21, float m22, float m23, float m24, float m21, float m22, float m23, float m24,
@ -186,9 +186,19 @@ public:
void projectedRotate(float angle, float x, float y, float z); void projectedRotate(float angle, float x, float y, float z);
private: private:
// No other members are allowed in order to ensure a size of 16 * sizeof(float)
float m[4][4]; // Column-major order to match OpenGL. float 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 = 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. // Construct without initializing identity matrix.
explicit QMatrix4x4(int) { } explicit QMatrix4x4(int) { }
@ -212,6 +222,7 @@ inline QMatrix4x4::QMatrix4x4
m[1][0] = m12; m[1][1] = m22; m[1][2] = m32; m[1][3] = m42; m[1][0] = m12; m[1][1] = m22; m[1][2] = m32; m[1][3] = m42;
m[2][0] = m13; m[2][1] = m23; m[2][2] = m33; m[2][3] = m43; m[2][0] = m13; m[2][1] = m23; m[2][2] = m33; m[2][3] = m43;
m[3][0] = m14; m[3][1] = m24; m[3][2] = m34; m[3][3] = m44; m[3][0] = m14; m[3][1] = m24; m[3][2] = m34; m[3][3] = m44;
flagBits = General;
} }
template <int N, int M> template <int N, int M>
@ -229,6 +240,7 @@ Q_INLINE_TEMPLATE QMatrix4x4::QMatrix4x4
m[matrixCol][matrixRow] = 0.0f; m[matrixCol][matrixRow] = 0.0f;
} }
} }
flagBits = General;
} }
template <int N, int M> template <int N, int M>
@ -258,6 +270,7 @@ inline const float& QMatrix4x4::operator()(int aRow, int aColumn) const
inline float& QMatrix4x4::operator()(int aRow, int aColumn) inline float& QMatrix4x4::operator()(int aRow, int aColumn)
{ {
Q_ASSERT(aRow >= 0 && aRow < 4 && aColumn >= 0 && aColumn < 4); Q_ASSERT(aRow >= 0 && aRow < 4 && aColumn >= 0 && aColumn < 4);
flagBits = General;
return m[aColumn][aRow]; return m[aColumn][aRow];
} }
@ -275,6 +288,7 @@ inline void QMatrix4x4::setColumn(int index, const QVector4D& value)
m[index][1] = value.y(); m[index][1] = value.y();
m[index][2] = value.z(); m[index][2] = value.z();
m[index][3] = value.w(); m[index][3] = value.w();
flagBits = General;
} }
inline QVector4D QMatrix4x4::row(int index) const inline QVector4D QMatrix4x4::row(int index) const
@ -290,6 +304,7 @@ inline void QMatrix4x4::setRow(int index, const QVector4D& value)
m[1][index] = value.y(); m[1][index] = value.y();
m[2][index] = value.z(); m[2][index] = value.z();
m[3][index] = value.w(); m[3][index] = value.w();
flagBits = General;
} }
#endif #endif
@ -302,6 +317,8 @@ inline bool QMatrix4x4::isAffine() const
inline bool QMatrix4x4::isIdentity() const inline bool QMatrix4x4::isIdentity() const
{ {
if (flagBits == Identity)
return true;
if (m[0][0] != 1.0f || m[0][1] != 0.0f || m[0][2] != 0.0f) if (m[0][0] != 1.0f || m[0][1] != 0.0f || m[0][2] != 0.0f)
return false; return false;
if (m[0][3] != 0.0f || m[1][0] != 0.0f || m[1][1] != 1.0f) if (m[0][3] != 0.0f || m[1][0] != 0.0f || m[1][1] != 1.0f)
@ -333,6 +350,7 @@ inline void QMatrix4x4::setToIdentity()
m[3][1] = 0.0f; m[3][1] = 0.0f;
m[3][2] = 0.0f; m[3][2] = 0.0f;
m[3][3] = 1.0f; m[3][3] = 1.0f;
flagBits = Identity;
} }
inline void QMatrix4x4::fill(float value) inline void QMatrix4x4::fill(float value)
@ -353,6 +371,7 @@ inline void QMatrix4x4::fill(float value)
m[3][1] = value; m[3][1] = value;
m[3][2] = value; m[3][2] = value;
m[3][3] = value; m[3][3] = value;
flagBits = General;
} }
inline QMatrix4x4& QMatrix4x4::operator+=(const QMatrix4x4& other) inline QMatrix4x4& QMatrix4x4::operator+=(const QMatrix4x4& other)
@ -373,6 +392,7 @@ inline QMatrix4x4& QMatrix4x4::operator+=(const QMatrix4x4& other)
m[3][1] += other.m[3][1]; m[3][1] += other.m[3][1];
m[3][2] += other.m[3][2]; m[3][2] += other.m[3][2];
m[3][3] += other.m[3][3]; m[3][3] += other.m[3][3];
flagBits = General;
return *this; return *this;
} }
@ -394,12 +414,25 @@ inline QMatrix4x4& QMatrix4x4::operator-=(const QMatrix4x4& other)
m[3][1] -= other.m[3][1]; m[3][1] -= other.m[3][1];
m[3][2] -= other.m[3][2]; m[3][2] -= other.m[3][2];
m[3][3] -= other.m[3][3]; m[3][3] -= other.m[3][3];
flagBits = General;
return *this; return *this;
} }
inline QMatrix4x4& QMatrix4x4::operator*=(const QMatrix4x4& o) inline QMatrix4x4& QMatrix4x4::operator*=(const QMatrix4x4& o)
{ {
const QMatrix4x4 other = o; // prevent aliasing when &o == this ### Qt 6: take o by value const QMatrix4x4 other = o; // prevent aliasing when &o == this ### Qt 6: take o by value
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;
}
float m0, m1, m2; float m0, m1, m2;
m0 = m[0][0] * other.m[0][0] m0 = m[0][0] * other.m[0][0]
@ -502,6 +535,7 @@ inline QMatrix4x4& QMatrix4x4::operator*=(float factor)
m[3][1] *= factor; m[3][1] *= factor;
m[3][2] *= factor; m[3][2] *= factor;
m[3][3] *= factor; m[3][3] *= factor;
flagBits = General;
return *this; return *this;
} }
@ -564,6 +598,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][1] = m1.m[3][1] + m2.m[3][1];
m.m[3][2] = m1.m[3][2] + m2.m[3][2]; 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.m[3][3] = m1.m[3][3] + m2.m[3][3];
m.flagBits = QMatrix4x4::General;
return m; return m;
} }
@ -586,11 +621,26 @@ inline QMatrix4x4 operator-(const QMatrix4x4& m1, const QMatrix4x4& m2)
m.m[3][1] = m1.m[3][1] - m2.m[3][1]; 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][2] = m1.m[3][2] - m2.m[3][2];
m.m[3][3] = m1.m[3][3] - m2.m[3][3]; m.m[3][3] = m1.m[3][3] - m2.m[3][3];
m.flagBits = QMatrix4x4::General;
return m; return m;
} }
inline QMatrix4x4 operator*(const QMatrix4x4& m1, const QMatrix4x4& m2) inline QMatrix4x4 operator*(const QMatrix4x4& m1, const QMatrix4x4& m2)
{ {
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); QMatrix4x4 m(1);
m.m[0][0] = m1.m[0][0] * m2.m[0][0] m.m[0][0] = m1.m[0][0] * m2.m[0][0]
+ m1.m[1][0] * m2.m[0][1] + m1.m[1][0] * m2.m[0][1]
@ -659,6 +709,7 @@ inline QMatrix4x4 operator*(const QMatrix4x4& m1, const QMatrix4x4& m2)
+ m1.m[1][3] * m2.m[3][1] + m1.m[1][3] * m2.m[3][1]
+ m1.m[2][3] * m2.m[3][2] + m1.m[2][3] * m2.m[3][2]
+ m1.m[3][3] * m2.m[3][3]; + m1.m[3][3] * m2.m[3][3];
m.flagBits = flagBits;
return m; return m;
} }
@ -666,19 +717,20 @@ inline QMatrix4x4 operator*(const QMatrix4x4& m1, const QMatrix4x4& m2)
inline QVector3D operator*(const QVector3D& vector, const QMatrix4x4& matrix) inline QVector3D operator*(const QVector3D& vector, const QMatrix4x4& matrix)
{ {
const float x = vector.x() * matrix.m[0][0] + float x, y, z, w;
x = vector.x() * matrix.m[0][0] +
vector.y() * matrix.m[0][1] + vector.y() * matrix.m[0][1] +
vector.z() * matrix.m[0][2] + vector.z() * matrix.m[0][2] +
matrix.m[0][3]; matrix.m[0][3];
const float y = vector.x() * matrix.m[1][0] + y = vector.x() * matrix.m[1][0] +
vector.y() * matrix.m[1][1] + vector.y() * matrix.m[1][1] +
vector.z() * matrix.m[1][2] + vector.z() * matrix.m[1][2] +
matrix.m[1][3]; matrix.m[1][3];
const float z = vector.x() * matrix.m[2][0] + z = vector.x() * matrix.m[2][0] +
vector.y() * matrix.m[2][1] + vector.y() * matrix.m[2][1] +
vector.z() * matrix.m[2][2] + vector.z() * matrix.m[2][2] +
matrix.m[2][3]; matrix.m[2][3];
const float w = vector.x() * matrix.m[3][0] + w = vector.x() * matrix.m[3][0] +
vector.y() * matrix.m[3][1] + vector.y() * matrix.m[3][1] +
vector.z() * matrix.m[3][2] + vector.z() * matrix.m[3][2] +
matrix.m[3][3]; matrix.m[3][3];
@ -690,22 +742,33 @@ inline QVector3D operator*(const QVector3D& vector, const QMatrix4x4& matrix)
inline QVector3D operator*(const QMatrix4x4& matrix, const QVector3D& vector) inline QVector3D operator*(const QMatrix4x4& matrix, const QVector3D& vector)
{ {
if (matrix.isIdentity()) float x, y, z, w;
if (matrix.flagBits == QMatrix4x4::Identity) {
return vector; return vector;
} else if (matrix.flagBits < QMatrix4x4::Rotation2D) {
const float x = vector.x() * matrix.m[0][0] + // 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::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] + vector.y() * matrix.m[1][0] +
vector.z() * matrix.m[2][0] + vector.z() * matrix.m[2][0] +
matrix.m[3][0]; matrix.m[3][0];
const float y = vector.x() * matrix.m[0][1] + y = vector.x() * matrix.m[0][1] +
vector.y() * matrix.m[1][1] + vector.y() * matrix.m[1][1] +
vector.z() * matrix.m[2][1] + vector.z() * matrix.m[2][1] +
matrix.m[3][1]; matrix.m[3][1];
const float z = vector.x() * matrix.m[0][2] + z = vector.x() * matrix.m[0][2] +
vector.y() * matrix.m[1][2] + vector.y() * matrix.m[1][2] +
vector.z() * matrix.m[2][2] + vector.z() * matrix.m[2][2] +
matrix.m[3][2]; matrix.m[3][2];
const float w = vector.x() * matrix.m[0][3] + w = vector.x() * matrix.m[0][3] +
vector.y() * matrix.m[1][3] + vector.y() * matrix.m[1][3] +
vector.z() * matrix.m[2][3] + vector.z() * matrix.m[2][3] +
matrix.m[3][3]; matrix.m[3][3];
@ -713,6 +776,7 @@ inline QVector3D operator*(const QMatrix4x4& matrix, const QVector3D& vector)
return QVector3D(x, y, z); return QVector3D(x, y, z);
else else
return QVector3D(x / w, y / w, z / w); return QVector3D(x / w, y / w, z / w);
}
} }
#endif #endif
@ -721,19 +785,20 @@ inline QVector3D operator*(const QMatrix4x4& matrix, const QVector3D& vector)
inline QVector4D operator*(const QVector4D& vector, const QMatrix4x4& matrix) inline QVector4D operator*(const QVector4D& vector, const QMatrix4x4& matrix)
{ {
const float x = vector.x() * matrix.m[0][0] + float x, y, z, w;
x = vector.x() * matrix.m[0][0] +
vector.y() * matrix.m[0][1] + vector.y() * matrix.m[0][1] +
vector.z() * matrix.m[0][2] + vector.z() * matrix.m[0][2] +
vector.w() * matrix.m[0][3]; vector.w() * matrix.m[0][3];
const float y = vector.x() * matrix.m[1][0] + y = vector.x() * matrix.m[1][0] +
vector.y() * matrix.m[1][1] + vector.y() * matrix.m[1][1] +
vector.z() * matrix.m[1][2] + vector.z() * matrix.m[1][2] +
vector.w() * matrix.m[1][3]; vector.w() * matrix.m[1][3];
const float z = vector.x() * matrix.m[2][0] + z = vector.x() * matrix.m[2][0] +
vector.y() * matrix.m[2][1] + vector.y() * matrix.m[2][1] +
vector.z() * matrix.m[2][2] + vector.z() * matrix.m[2][2] +
vector.w() * matrix.m[2][3]; vector.w() * matrix.m[2][3];
const float w = vector.x() * matrix.m[3][0] + w = vector.x() * matrix.m[3][0] +
vector.y() * matrix.m[3][1] + vector.y() * matrix.m[3][1] +
vector.z() * matrix.m[3][2] + vector.z() * matrix.m[3][2] +
vector.w() * matrix.m[3][3]; vector.w() * matrix.m[3][3];
@ -742,19 +807,20 @@ inline QVector4D operator*(const QVector4D& vector, const QMatrix4x4& matrix)
inline QVector4D operator*(const QMatrix4x4& matrix, const QVector4D& vector) inline QVector4D operator*(const QMatrix4x4& matrix, const QVector4D& vector)
{ {
const float x = vector.x() * matrix.m[0][0] + float x, y, z, w;
x = vector.x() * matrix.m[0][0] +
vector.y() * matrix.m[1][0] + vector.y() * matrix.m[1][0] +
vector.z() * matrix.m[2][0] + vector.z() * matrix.m[2][0] +
vector.w() * matrix.m[3][0]; vector.w() * matrix.m[3][0];
const float y = vector.x() * matrix.m[0][1] + y = vector.x() * matrix.m[0][1] +
vector.y() * matrix.m[1][1] + vector.y() * matrix.m[1][1] +
vector.z() * matrix.m[2][1] + vector.z() * matrix.m[2][1] +
vector.w() * matrix.m[3][1]; vector.w() * matrix.m[3][1];
const float z = vector.x() * matrix.m[0][2] + z = vector.x() * matrix.m[0][2] +
vector.y() * matrix.m[1][2] + vector.y() * matrix.m[1][2] +
vector.z() * matrix.m[2][2] + vector.z() * matrix.m[2][2] +
vector.w() * matrix.m[3][2]; vector.w() * matrix.m[3][2];
const float w = vector.x() * matrix.m[0][3] + w = vector.x() * matrix.m[0][3] +
vector.y() * matrix.m[1][3] + vector.y() * matrix.m[1][3] +
vector.z() * matrix.m[2][3] + vector.z() * matrix.m[2][3] +
vector.w() * matrix.m[3][3]; vector.w() * matrix.m[3][3];
@ -765,15 +831,17 @@ inline QVector4D operator*(const QMatrix4x4& matrix, const QVector4D& vector)
inline QPoint operator*(const QPoint& point, const QMatrix4x4& matrix) inline QPoint operator*(const QPoint& point, const QMatrix4x4& matrix)
{ {
const float xin = point.x(); float xin, yin;
const float yin = point.y(); float x, y, w;
const float x = xin * matrix.m[0][0] + xin = point.x();
yin = point.y();
x = xin * matrix.m[0][0] +
yin * matrix.m[0][1] + yin * matrix.m[0][1] +
matrix.m[0][3]; matrix.m[0][3];
const float y = xin * matrix.m[1][0] + y = xin * matrix.m[1][0] +
yin * matrix.m[1][1] + yin * matrix.m[1][1] +
matrix.m[1][3]; matrix.m[1][3];
const float w = xin * matrix.m[3][0] + w = xin * matrix.m[3][0] +
yin * matrix.m[3][1] + yin * matrix.m[3][1] +
matrix.m[3][3]; matrix.m[3][3];
if (w == 1.0f) if (w == 1.0f)
@ -784,15 +852,17 @@ inline QPoint operator*(const QPoint& point, const QMatrix4x4& matrix)
inline QPointF operator*(const QPointF& point, const QMatrix4x4& matrix) inline QPointF operator*(const QPointF& point, const QMatrix4x4& matrix)
{ {
const float xin = float(point.x()); float xin, yin;
const float yin = float(point.y()); float x, y, w;
const float x = xin * matrix.m[0][0] + xin = float(point.x());
yin = float(point.y());
x = xin * matrix.m[0][0] +
yin * matrix.m[0][1] + yin * matrix.m[0][1] +
matrix.m[0][3]; matrix.m[0][3];
const float y = xin * matrix.m[1][0] + y = xin * matrix.m[1][0] +
yin * matrix.m[1][1] + yin * matrix.m[1][1] +
matrix.m[1][3]; matrix.m[1][3];
const float w = xin * matrix.m[3][0] + w = xin * matrix.m[3][0] +
yin * matrix.m[3][1] + yin * matrix.m[3][1] +
matrix.m[3][3]; matrix.m[3][3];
if (w == 1.0f) { if (w == 1.0f) {
@ -804,46 +874,69 @@ inline QPointF operator*(const QPointF& point, const QMatrix4x4& matrix)
inline QPoint operator*(const QMatrix4x4& matrix, const QPoint& point) inline QPoint operator*(const QMatrix4x4& matrix, const QPoint& point)
{ {
if (matrix.isIdentity()) float xin, yin;
float x, y, w;
xin = point.x();
yin = point.y();
if (matrix.flagBits == QMatrix4x4::Identity) {
return point; return point;
} else if (matrix.flagBits < QMatrix4x4::Rotation2D) {
const float xin = point.x(); // Translation | Scale
const float yin = point.y(); return QPoint(qRound(xin * matrix.m[0][0] + matrix.m[3][0]),
const float x = xin * matrix.m[0][0] + qRound(yin * matrix.m[1][1] + matrix.m[3][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] + yin * matrix.m[1][0] +
matrix.m[3][0]; matrix.m[3][0];
const float y = xin * matrix.m[0][1] + y = xin * matrix.m[0][1] +
yin * matrix.m[1][1] + yin * matrix.m[1][1] +
matrix.m[3][1]; matrix.m[3][1];
const float w = xin * matrix.m[0][3] + w = xin * matrix.m[0][3] +
yin * matrix.m[1][3] + yin * matrix.m[1][3] +
matrix.m[3][3]; matrix.m[3][3];
if (w == 1.0f) if (w == 1.0f)
return QPoint(qRound(x), qRound(y)); return QPoint(qRound(x), qRound(y));
else
return QPoint(qRound(x / w), qRound(y / w)); return QPoint(qRound(x / w), qRound(y / w));
}
} }
inline QPointF operator*(const QMatrix4x4& matrix, const QPointF& point) inline QPointF operator*(const QMatrix4x4& matrix, const QPointF& point)
{ {
if (matrix.isIdentity()) qreal xin, yin;
qreal x, y, w;
xin = point.x();
yin = point.y();
if (matrix.flagBits == QMatrix4x4::Identity) {
return point; return point;
} else if (matrix.flagBits < QMatrix4x4::Rotation2D) {
const qreal xin = point.x(); // Translation | Scale
const qreal yin = point.y(); return QPointF(xin * qreal(matrix.m[0][0]) + qreal(matrix.m[3][0]),
const qreal x = xin * qreal(matrix.m[0][0]) + yin * qreal(matrix.m[1][1]) + qreal(matrix.m[3][1]));
} else if (matrix.flagBits < QMatrix4x4::Perspective) {
return QPointF(xin * qreal(matrix.m[0][0]) + yin * qreal(matrix.m[1][0]) +
qreal(matrix.m[3][0]),
xin * qreal(matrix.m[0][1]) + yin * qreal(matrix.m[1][1]) +
qreal(matrix.m[3][1]));
} else {
x = xin * qreal(matrix.m[0][0]) +
yin * qreal(matrix.m[1][0]) + yin * qreal(matrix.m[1][0]) +
qreal(matrix.m[3][0]); qreal(matrix.m[3][0]);
const qreal y = xin * qreal(matrix.m[0][1]) + y = xin * qreal(matrix.m[0][1]) +
yin * qreal(matrix.m[1][1]) + yin * qreal(matrix.m[1][1]) +
qreal(matrix.m[3][1]); qreal(matrix.m[3][1]);
const qreal w = xin * qreal(matrix.m[0][3]) + w = xin * qreal(matrix.m[0][3]) +
yin * qreal(matrix.m[1][3]) + yin * qreal(matrix.m[1][3]) +
qreal(matrix.m[3][3]); qreal(matrix.m[3][3]);
if (w == 1.0) if (w == 1.0) {
return QPointF(qreal(x), qreal(y)); return QPointF(qreal(x), qreal(y));
} else {
return QPointF(qreal(x / w), qreal(y / w)); return QPointF(qreal(x / w), qreal(y / w));
}
}
} }
inline QMatrix4x4 operator-(const QMatrix4x4& matrix) inline QMatrix4x4 operator-(const QMatrix4x4& matrix)
@ -865,6 +958,7 @@ inline QMatrix4x4 operator-(const QMatrix4x4& matrix)
m.m[3][1] = -matrix.m[3][1]; m.m[3][1] = -matrix.m[3][1];
m.m[3][2] = -matrix.m[3][2]; m.m[3][2] = -matrix.m[3][2];
m.m[3][3] = -matrix.m[3][3]; m.m[3][3] = -matrix.m[3][3];
m.flagBits = QMatrix4x4::General;
return m; return m;
} }
@ -887,6 +981,7 @@ inline QMatrix4x4 operator*(float factor, const QMatrix4x4& matrix)
m.m[3][1] = matrix.m[3][1] * factor; m.m[3][1] = matrix.m[3][1] * factor;
m.m[3][2] = matrix.m[3][2] * factor; m.m[3][2] = matrix.m[3][2] * factor;
m.m[3][3] = matrix.m[3][3] * factor; m.m[3][3] = matrix.m[3][3] * factor;
m.flagBits = QMatrix4x4::General;
return m; return m;
} }
@ -909,6 +1004,7 @@ inline QMatrix4x4 operator*(const QMatrix4x4& matrix, float factor)
m.m[3][1] = matrix.m[3][1] * factor; m.m[3][1] = matrix.m[3][1] * factor;
m.m[3][2] = matrix.m[3][2] * factor; m.m[3][2] = matrix.m[3][2] * factor;
m.m[3][3] = matrix.m[3][3] * factor; m.m[3][3] = matrix.m[3][3] * factor;
m.flagBits = QMatrix4x4::General;
return m; return m;
} }
@ -951,9 +1047,25 @@ inline QVector3D QMatrix4x4::map(const QVector3D& point) const
inline QVector3D QMatrix4x4::mapVector(const QVector3D& vector) const inline QVector3D QMatrix4x4::mapVector(const QVector3D& vector) const
{ {
return QVector3D(vector.x() * m[0][0] + vector.y() * m[1][0] + vector.z() * m[2][0], if (flagBits < Scale) {
vector.x() * m[0][1] + vector.y() * m[1][1] + vector.z() * m[2][1], // Translation
vector.x() * m[0][2] + vector.y() * m[1][2] + vector.z() * m[2][2]); return vector;
} else if (flagBits < Rotation2D) {
// Translation | Scale
return QVector3D(vector.x() * m[0][0],
vector.y() * m[1][1],
vector.z() * m[2][2]);
} else {
return QVector3D(vector.x() * m[0][0] +
vector.y() * m[1][0] +
vector.z() * m[2][0],
vector.x() * m[0][1] +
vector.y() * m[1][1] +
vector.z() * m[2][1],
vector.x() * m[0][2] +
vector.y() * m[1][2] +
vector.z() * m[2][2]);
}
} }
#endif #endif
@ -971,6 +1083,7 @@ inline float *QMatrix4x4::data()
{ {
// We have to assume that the caller will modify the matrix elements, // We have to assume that the caller will modify the matrix elements,
// so we flip it over to "General" mode. // so we flip it over to "General" mode.
flagBits = General;
return *m; return *m;
} }

View File

@ -139,8 +139,8 @@ private slots:
void convertGeneric(); void convertGeneric();
// void optimize_data(); void optimize_data();
// void optimize(); void optimize();
void columnsAndRows(); void columnsAndRows();
@ -2881,7 +2881,6 @@ void tst_QMatrixNxN::convertGeneric()
#endif #endif
} }
/*
// Copy of "flagBits" in qmatrix4x4.h. // Copy of "flagBits" in qmatrix4x4.h.
enum { enum {
Identity = 0x0000, // Identity matrix Identity = 0x0000, // Identity matrix
@ -3015,7 +3014,7 @@ void tst_QMatrixNxN::optimize()
QCOMPARE(reinterpret_cast<Matrix4x4 *>(&m)->flagBits, flagBits); QCOMPARE(reinterpret_cast<Matrix4x4 *>(&m)->flagBits, flagBits);
} }
*/
void tst_QMatrixNxN::columnsAndRows() void tst_QMatrixNxN::columnsAndRows()
{ {
QMatrix4x4 m1(uniqueValues4); QMatrix4x4 m1(uniqueValues4);