src/gui/math3d/qmatrix4x4.cpp
changeset 3 41300fa6a67c
parent 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
2:56cd8111b7f7 3:41300fa6a67c
    56     \ingroup painting-3D
    56     \ingroup painting-3D
    57 
    57 
    58     \sa QVector3D, QGenericMatrix
    58     \sa QVector3D, QGenericMatrix
    59 */
    59 */
    60 
    60 
       
    61 static const qreal inv_dist_to_plane = 1. / 1024.;
       
    62 
    61 /*!
    63 /*!
    62     \fn QMatrix4x4::QMatrix4x4()
    64     \fn QMatrix4x4::QMatrix4x4()
    63 
    65 
    64     Constructs an identity matrix.
    66     Constructs an identity matrix.
    65 */
    67 */
    69     The contents of the array \a values is assumed to be in
    71     The contents of the array \a values is assumed to be in
    70     row-major order.
    72     row-major order.
    71 
    73 
    72     If the matrix has a special type (identity, translate, scale, etc),
    74     If the matrix has a special type (identity, translate, scale, etc),
    73     the programmer should follow this constructor with a call to
    75     the programmer should follow this constructor with a call to
    74     inferSpecialType() if they wish QMatrix4x4 to optimize further
    76     optimize() if they wish QMatrix4x4 to optimize further
    75     calls to translate(), scale(), etc.
    77     calls to translate(), scale(), etc.
    76 
    78 
    77     \sa toValueArray(), inferSpecialType()
    79     \sa copyDataTo(), optimize()
    78 */
    80 */
    79 QMatrix4x4::QMatrix4x4(const qreal *values)
    81 QMatrix4x4::QMatrix4x4(const qreal *values)
    80 {
    82 {
    81     for (int row = 0; row < 4; ++row)
    83     for (int row = 0; row < 4; ++row)
    82         for (int col = 0; col < 4; ++col)
    84         for (int col = 0; col < 4; ++col)
    92     \a m41, \a m42, \a m43, and \a m44.  The elements are specified in
    94     \a m41, \a m42, \a m43, and \a m44.  The elements are specified in
    93     row-major order.
    95     row-major order.
    94 
    96 
    95     If the matrix has a special type (identity, translate, scale, etc),
    97     If the matrix has a special type (identity, translate, scale, etc),
    96     the programmer should follow this constructor with a call to
    98     the programmer should follow this constructor with a call to
    97     inferSpecialType() if they wish QMatrix4x4 to optimize further
    99     optimize() if they wish QMatrix4x4 to optimize further
    98     calls to translate(), scale(), etc.
   100     calls to translate(), scale(), etc.
    99 
   101 
   100     \sa inferSpecialType()
   102     \sa optimize()
   101 */
   103 */
   102 
   104 
   103 #if !defined(QT_NO_MEMBER_TEMPLATES) || defined(Q_QDOC)
   105 #if !defined(QT_NO_MEMBER_TEMPLATES) || defined(Q_QDOC)
   104 
   106 
   105 /*!
   107 /*!
   172     Constructs a 4x4 matrix from a conventional Qt 2D affine
   174     Constructs a 4x4 matrix from a conventional Qt 2D affine
   173     transformation \a matrix.
   175     transformation \a matrix.
   174 
   176 
   175     If \a matrix has a special type (identity, translate, scale, etc),
   177     If \a matrix has a special type (identity, translate, scale, etc),
   176     the programmer should follow this constructor with a call to
   178     the programmer should follow this constructor with a call to
   177     inferSpecialType() if they wish QMatrix4x4 to optimize further
   179     optimize() if they wish QMatrix4x4 to optimize further
   178     calls to translate(), scale(), etc.
   180     calls to translate(), scale(), etc.
   179 
   181 
   180     \sa toAffine(), inferSpecialType()
   182     \sa toAffine(), optimize()
   181 */
   183 */
   182 QMatrix4x4::QMatrix4x4(const QMatrix& matrix)
   184 QMatrix4x4::QMatrix4x4(const QMatrix& matrix)
   183 {
   185 {
   184     m[0][0] = matrix.m11();
   186     m[0][0] = matrix.m11();
   185     m[0][1] = matrix.m12();
   187     m[0][1] = matrix.m12();
   204     Constructs a 4x4 matrix from the conventional Qt 2D
   206     Constructs a 4x4 matrix from the conventional Qt 2D
   205     transformation matrix \a transform.
   207     transformation matrix \a transform.
   206 
   208 
   207     If \a transform has a special type (identity, translate, scale, etc),
   209     If \a transform has a special type (identity, translate, scale, etc),
   208     the programmer should follow this constructor with a call to
   210     the programmer should follow this constructor with a call to
   209     inferSpecialType() if they wish QMatrix4x4 to optimize further
   211     optimize() if they wish QMatrix4x4 to optimize further
   210     calls to translate(), scale(), etc.
   212     calls to translate(), scale(), etc.
   211 
   213 
   212     \sa toTransform(), inferSpecialType()
   214     \sa toTransform(), optimize()
   213 */
   215 */
   214 QMatrix4x4::QMatrix4x4(const QTransform& transform)
   216 QMatrix4x4::QMatrix4x4(const QTransform& transform)
   215 {
   217 {
   216     m[0][0] = transform.m11();
   218     m[0][0] = transform.m11();
   217     m[0][1] = transform.m12();
   219     m[0][1] = transform.m12();
   245     \fn qreal& QMatrix4x4::operator()(int row, int column)
   247     \fn qreal& QMatrix4x4::operator()(int row, int column)
   246 
   248 
   247     Returns a reference to the element at position (\a row, \a column)
   249     Returns a reference to the element at position (\a row, \a column)
   248     in this matrix so that the element can be assigned to.
   250     in this matrix so that the element can be assigned to.
   249 
   251 
   250     \sa inferSpecialType(), setColumn(), setRow()
   252     \sa optimize(), setColumn(), setRow()
   251 */
   253 */
   252 
   254 
   253 /*!
   255 /*!
   254     \fn QVector4D QMatrix4x4::column(int index) const
   256     \fn QVector4D QMatrix4x4::column(int index) const
   255 
   257 
   285 /*!
   287 /*!
   286     \fn bool QMatrix4x4::isIdentity() const
   288     \fn bool QMatrix4x4::isIdentity() const
   287 
   289 
   288     Returns true if this matrix is the identity; false otherwise.
   290     Returns true if this matrix is the identity; false otherwise.
   289 
   291 
   290     \sa setIdentity()
   292     \sa setToIdentity()
   291 */
   293 */
   292 
   294 
   293 /*!
   295 /*!
   294     \fn void QMatrix4x4::setIdentity()
   296     \fn void QMatrix4x4::setToIdentity()
   295 
   297 
   296     Sets this matrix to the identity.
   298     Sets this matrix to the identity.
   297 
   299 
   298     \sa isIdentity()
   300     \sa isIdentity()
   299 */
   301 */
   690 
   692 
   691 #ifndef QT_NO_VECTOR3D
   693 #ifndef QT_NO_VECTOR3D
   692 
   694 
   693 /*!
   695 /*!
   694     Multiplies this matrix by another that scales coordinates by
   696     Multiplies this matrix by another that scales coordinates by
   695     the components of \a vector.  Returns this matrix.
   697     the components of \a vector.
   696 
   698 
   697     \sa translate(), rotate()
   699     \sa translate(), rotate()
   698 */
   700 */
   699 QMatrix4x4& QMatrix4x4::scale(const QVector3D& vector)
   701 void QMatrix4x4::scale(const QVector3D& vector)
   700 {
   702 {
   701     qreal vx = vector.x();
   703     qreal vx = vector.x();
   702     qreal vy = vector.y();
   704     qreal vy = vector.y();
   703     qreal vz = vector.z();
   705     qreal vz = vector.z();
   704     if (flagBits == Identity) {
   706     if (flagBits == Identity) {
   728         m[2][1] *= vz;
   730         m[2][1] *= vz;
   729         m[2][2] *= vz;
   731         m[2][2] *= vz;
   730         m[2][3] *= vz;
   732         m[2][3] *= vz;
   731         flagBits = General;
   733         flagBits = General;
   732     }
   734     }
   733     return *this;
       
   734 }
   735 }
   735 #endif
   736 #endif
   736 
   737 
   737 /*!
   738 /*!
   738     \overload
   739     \overload
   739 
   740 
   740     Multiplies this matrix by another that scales coordinates by the
   741     Multiplies this matrix by another that scales coordinates by the
   741     components \a x, and \a y.  Returns this matrix.
   742     components \a x, and \a y.
   742 
   743 
   743     \sa translate(), rotate()
   744     \sa translate(), rotate()
   744 */
   745 */
   745 QMatrix4x4& QMatrix4x4::scale(qreal x, qreal y)
   746 void QMatrix4x4::scale(qreal x, qreal y)
   746 {
   747 {
   747     if (flagBits == Identity) {
   748     if (flagBits == Identity) {
   748         m[0][0] = x;
   749         m[0][0] = x;
   749         m[1][1] = y;
   750         m[1][1] = y;
   750         flagBits = Scale;
   751         flagBits = Scale;
   764         m[1][1] *= y;
   765         m[1][1] *= y;
   765         m[1][2] *= y;
   766         m[1][2] *= y;
   766         m[1][3] *= y;
   767         m[1][3] *= y;
   767         flagBits = General;
   768         flagBits = General;
   768     }
   769     }
   769     return *this;
       
   770 }
   770 }
   771 
   771 
   772 /*!
   772 /*!
   773     \overload
   773     \overload
   774 
   774 
   775     Multiplies this matrix by another that scales coordinates by the
   775     Multiplies this matrix by another that scales coordinates by the
   776     components \a x, \a y, and \a z.  Returns this matrix.
   776     components \a x, \a y, and \a z.
   777 
   777 
   778     \sa translate(), rotate()
   778     \sa translate(), rotate()
   779 */
   779 */
   780 QMatrix4x4& QMatrix4x4::scale(qreal x, qreal y, qreal z)
   780 void QMatrix4x4::scale(qreal x, qreal y, qreal z)
   781 {
   781 {
   782     if (flagBits == Identity) {
   782     if (flagBits == Identity) {
   783         m[0][0] = x;
   783         m[0][0] = x;
   784         m[1][1] = y;
   784         m[1][1] = y;
   785         m[2][2] = z;
   785         m[2][2] = z;
   806         m[2][1] *= z;
   806         m[2][1] *= z;
   807         m[2][2] *= z;
   807         m[2][2] *= z;
   808         m[2][3] *= z;
   808         m[2][3] *= z;
   809         flagBits = General;
   809         flagBits = General;
   810     }
   810     }
   811     return *this;
       
   812 }
   811 }
   813 
   812 
   814 /*!
   813 /*!
   815     \overload
   814     \overload
   816 
   815 
   817     Multiplies this matrix by another that scales coordinates by the
   816     Multiplies this matrix by another that scales coordinates by the
   818     given \a factor.  Returns this matrix.
   817     given \a factor.
   819 
   818 
   820     \sa translate(), rotate()
   819     \sa translate(), rotate()
   821 */
   820 */
   822 QMatrix4x4& QMatrix4x4::scale(qreal factor)
   821 void QMatrix4x4::scale(qreal factor)
   823 {
   822 {
   824     if (flagBits == Identity) {
   823     if (flagBits == Identity) {
   825         m[0][0] = factor;
   824         m[0][0] = factor;
   826         m[1][1] = factor;
   825         m[1][1] = factor;
   827         m[2][2] = factor;
   826         m[2][2] = factor;
   848         m[2][1] *= factor;
   847         m[2][1] *= factor;
   849         m[2][2] *= factor;
   848         m[2][2] *= factor;
   850         m[2][3] *= factor;
   849         m[2][3] *= factor;
   851         flagBits = General;
   850         flagBits = General;
   852     }
   851     }
   853     return *this;
       
   854 }
   852 }
   855 
   853 
   856 #ifndef QT_NO_VECTOR3D
   854 #ifndef QT_NO_VECTOR3D
   857 /*!
   855 /*!
   858     Multiplies this matrix by another that translates coordinates by
   856     Multiplies this matrix by another that translates coordinates by
   859     the components of \a vector.  Returns this matrix.
   857     the components of \a vector.
   860 
   858 
   861     \sa scale(), rotate()
   859     \sa scale(), rotate()
   862 */
   860 */
   863 QMatrix4x4& QMatrix4x4::translate(const QVector3D& vector)
   861 void QMatrix4x4::translate(const QVector3D& vector)
   864 {
   862 {
   865     qreal vx = vector.x();
   863     qreal vx = vector.x();
   866     qreal vy = vector.y();
   864     qreal vy = vector.y();
   867     qreal vz = vector.z();
   865     qreal vz = vector.z();
   868     if (flagBits == Identity) {
   866     if (flagBits == Identity) {
   891         if (flagBits == Rotation)
   889         if (flagBits == Rotation)
   892             flagBits |= Translation;
   890             flagBits |= Translation;
   893         else if (flagBits != (Rotation | Translation))
   891         else if (flagBits != (Rotation | Translation))
   894             flagBits = General;
   892             flagBits = General;
   895     }
   893     }
   896     return *this;
       
   897 }
   894 }
   898 
   895 
   899 #endif
   896 #endif
   900 
   897 
   901 /*!
   898 /*!
   902     \overload
   899     \overload
   903 
   900 
   904     Multiplies this matrix by another that translates coordinates
   901     Multiplies this matrix by another that translates coordinates
   905     by the components \a x, and \a y.  Returns this matrix.
   902     by the components \a x, and \a y.
   906 
   903 
   907     \sa scale(), rotate()
   904     \sa scale(), rotate()
   908 */
   905 */
   909 QMatrix4x4& QMatrix4x4::translate(qreal x, qreal y)
   906 void QMatrix4x4::translate(qreal x, qreal y)
   910 {
   907 {
   911     if (flagBits == Identity) {
   908     if (flagBits == Identity) {
   912         m[3][0] = x;
   909         m[3][0] = x;
   913         m[3][1] = y;
   910         m[3][1] = y;
   914         flagBits = Translation;
   911         flagBits = Translation;
   931         if (flagBits == Rotation)
   928         if (flagBits == Rotation)
   932             flagBits |= Translation;
   929             flagBits |= Translation;
   933         else if (flagBits != (Rotation | Translation))
   930         else if (flagBits != (Rotation | Translation))
   934             flagBits = General;
   931             flagBits = General;
   935     }
   932     }
   936     return *this;
       
   937 }
   933 }
   938 
   934 
   939 /*!
   935 /*!
   940     \overload
   936     \overload
   941 
   937 
   942     Multiplies this matrix by another that translates coordinates
   938     Multiplies this matrix by another that translates coordinates
   943     by the components \a x, \a y, and \a z.  Returns this matrix.
   939     by the components \a x, \a y, and \a z.
   944 
   940 
   945     \sa scale(), rotate()
   941     \sa scale(), rotate()
   946 */
   942 */
   947 QMatrix4x4& QMatrix4x4::translate(qreal x, qreal y, qreal z)
   943 void QMatrix4x4::translate(qreal x, qreal y, qreal z)
   948 {
   944 {
   949     if (flagBits == Identity) {
   945     if (flagBits == Identity) {
   950         m[3][0] = x;
   946         m[3][0] = x;
   951         m[3][1] = y;
   947         m[3][1] = y;
   952         m[3][2] = z;
   948         m[3][2] = z;
   972         if (flagBits == Rotation)
   968         if (flagBits == Rotation)
   973             flagBits |= Translation;
   969             flagBits |= Translation;
   974         else if (flagBits != (Rotation | Translation))
   970         else if (flagBits != (Rotation | Translation))
   975             flagBits = General;
   971             flagBits = General;
   976     }
   972     }
   977     return *this;
       
   978 }
   973 }
   979 
   974 
   980 #ifndef QT_NO_VECTOR3D
   975 #ifndef QT_NO_VECTOR3D
   981 
   976 
   982 /*!
   977 /*!
   983     Multiples this matrix by another that rotates coordinates through
   978     Multiples this matrix by another that rotates coordinates through
   984     \a angle degrees about \a vector.  Returns this matrix.
   979     \a angle degrees about \a vector.
   985 
   980 
   986     \sa scale(), translate()
   981     \sa scale(), translate()
   987 */
   982 */
   988 QMatrix4x4& QMatrix4x4::rotate(qreal angle, const QVector3D& vector)
   983 void QMatrix4x4::rotate(qreal angle, const QVector3D& vector)
   989 {
   984 {
   990     return rotate(angle, vector.x(), vector.y(), vector.z());
   985     rotate(angle, vector.x(), vector.y(), vector.z());
   991 }
   986 }
   992 
   987 
   993 #endif
   988 #endif
   994 
   989 
   995 /*!
   990 /*!
   996     \overload
   991     \overload
   997 
   992 
   998     Multiplies this matrix by another that rotates coordinates through
   993     Multiplies this matrix by another that rotates coordinates through
   999     \a angle degrees about the vector (\a x, \a y, \a z).  Returns this matrix.
   994     \a angle degrees about the vector (\a x, \a y, \a z).
  1000 
   995 
  1001     \sa scale(), translate()
   996     \sa scale(), translate()
  1002 */
   997 */
  1003 QMatrix4x4& QMatrix4x4::rotate(qreal angle, qreal x, qreal y, qreal z)
   998 void QMatrix4x4::rotate(qreal angle, qreal x, qreal y, qreal z)
  1004 {
   999 {
  1005     if (angle == 0.0f)
  1000     if (angle == 0.0f)
  1006         return *this;
  1001         return;
  1007     QMatrix4x4 m(1); // The "1" says to not load the identity.
  1002     QMatrix4x4 m(1); // The "1" says to not load the identity.
  1008     qreal c, s, ic;
  1003     qreal c, s, ic;
  1009     if (angle == 90.0f || angle == -270.0f) {
  1004     if (angle == 90.0f || angle == -270.0f) {
  1010         s = 1.0f;
  1005         s = 1.0f;
  1011         c = 0.0f;
  1006         c = 0.0f;
  1023     bool quick = false;
  1018     bool quick = false;
  1024     if (x == 0.0f) {
  1019     if (x == 0.0f) {
  1025         if (y == 0.0f) {
  1020         if (y == 0.0f) {
  1026             if (z != 0.0f) {
  1021             if (z != 0.0f) {
  1027                 // Rotate around the Z axis.
  1022                 // Rotate around the Z axis.
  1028                 m.setIdentity();
  1023                 m.setToIdentity();
  1029                 m.m[0][0] = c;
  1024                 m.m[0][0] = c;
  1030                 m.m[1][1] = c;
  1025                 m.m[1][1] = c;
  1031                 if (z < 0.0f) {
  1026                 if (z < 0.0f) {
  1032                     m.m[1][0] = s;
  1027                     m.m[1][0] = s;
  1033                     m.m[0][1] = -s;
  1028                     m.m[0][1] = -s;
  1038                 m.flagBits = General;
  1033                 m.flagBits = General;
  1039                 quick = true;
  1034                 quick = true;
  1040             }
  1035             }
  1041         } else if (z == 0.0f) {
  1036         } else if (z == 0.0f) {
  1042             // Rotate around the Y axis.
  1037             // Rotate around the Y axis.
  1043             m.setIdentity();
  1038             m.setToIdentity();
  1044             m.m[0][0] = c;
  1039             m.m[0][0] = c;
  1045             m.m[2][2] = c;
  1040             m.m[2][2] = c;
  1046             if (y < 0.0f) {
  1041             if (y < 0.0f) {
  1047                 m.m[2][0] = -s;
  1042                 m.m[2][0] = -s;
  1048                 m.m[0][2] = s;
  1043                 m.m[0][2] = s;
  1053             m.flagBits = General;
  1048             m.flagBits = General;
  1054             quick = true;
  1049             quick = true;
  1055         }
  1050         }
  1056     } else if (y == 0.0f && z == 0.0f) {
  1051     } else if (y == 0.0f && z == 0.0f) {
  1057         // Rotate around the X axis.
  1052         // Rotate around the X axis.
  1058         m.setIdentity();
  1053         m.setToIdentity();
  1059         m.m[1][1] = c;
  1054         m.m[1][1] = c;
  1060         m.m[2][2] = c;
  1055         m.m[2][2] = c;
  1061         if (x < 0.0f) {
  1056         if (x < 0.0f) {
  1062             m.m[2][1] = s;
  1057             m.m[2][1] = s;
  1063             m.m[1][2] = -s;
  1058             m.m[1][2] = -s;
  1098     *this *= m;
  1093     *this *= m;
  1099     if (flags != Identity)
  1094     if (flags != Identity)
  1100         flagBits = flags | Rotation;
  1095         flagBits = flags | Rotation;
  1101     else
  1096     else
  1102         flagBits = Rotation;
  1097         flagBits = Rotation;
  1103     return *this;
  1098 }
  1104 }
  1099 
  1105 
  1100 /*!
  1106 #ifndef QT_NO_VECTOR4D
  1101     \internal
       
  1102 */
       
  1103 void QMatrix4x4::projectedRotate(qreal angle, qreal x, qreal y, qreal z)
       
  1104 {
       
  1105     // Used by QGraphicsRotation::applyTo() to perform a rotation
       
  1106     // and projection back to 2D in a single step.
       
  1107     if (angle == 0.0f)
       
  1108         return;
       
  1109     QMatrix4x4 m(1); // The "1" says to not load the identity.
       
  1110     qreal c, s, ic;
       
  1111     if (angle == 90.0f || angle == -270.0f) {
       
  1112         s = 1.0f;
       
  1113         c = 0.0f;
       
  1114     } else if (angle == -90.0f || angle == 270.0f) {
       
  1115         s = -1.0f;
       
  1116         c = 0.0f;
       
  1117     } else if (angle == 180.0f || angle == -180.0f) {
       
  1118         s = 0.0f;
       
  1119         c = -1.0f;
       
  1120     } else {
       
  1121         qreal a = angle * M_PI / 180.0f;
       
  1122         c = qCos(a);
       
  1123         s = qSin(a);
       
  1124     }
       
  1125     bool quick = false;
       
  1126     if (x == 0.0f) {
       
  1127         if (y == 0.0f) {
       
  1128             if (z != 0.0f) {
       
  1129                 // Rotate around the Z axis.
       
  1130                 m.setToIdentity();
       
  1131                 m.m[0][0] = c;
       
  1132                 m.m[1][1] = c;
       
  1133                 if (z < 0.0f) {
       
  1134                     m.m[1][0] = s;
       
  1135                     m.m[0][1] = -s;
       
  1136                 } else {
       
  1137                     m.m[1][0] = -s;
       
  1138                     m.m[0][1] = s;
       
  1139                 }
       
  1140                 m.flagBits = General;
       
  1141                 quick = true;
       
  1142             }
       
  1143         } else if (z == 0.0f) {
       
  1144             // Rotate around the Y axis.
       
  1145             m.setToIdentity();
       
  1146             m.m[0][0] = c;
       
  1147             m.m[2][2] = 1.0f;
       
  1148             if (y < 0.0f) {
       
  1149                 m.m[0][3] = -s * inv_dist_to_plane;
       
  1150             } else {
       
  1151                 m.m[0][3] = s * inv_dist_to_plane;
       
  1152             }
       
  1153             m.flagBits = General;
       
  1154             quick = true;
       
  1155         }
       
  1156     } else if (y == 0.0f && z == 0.0f) {
       
  1157         // Rotate around the X axis.
       
  1158         m.setToIdentity();
       
  1159         m.m[1][1] = c;
       
  1160         m.m[2][2] = 1.0f;
       
  1161         if (x < 0.0f) {
       
  1162             m.m[1][3] = s * inv_dist_to_plane;
       
  1163         } else {
       
  1164             m.m[1][3] = -s * inv_dist_to_plane;
       
  1165         }
       
  1166         m.flagBits = General;
       
  1167         quick = true;
       
  1168     }
       
  1169     if (!quick) {
       
  1170         qreal len = x * x + y * y + z * z;
       
  1171         if (!qFuzzyIsNull(len - 1.0f) && !qFuzzyIsNull(len)) {
       
  1172             len = qSqrt(len);
       
  1173             x /= len;
       
  1174             y /= len;
       
  1175             z /= len;
       
  1176         }
       
  1177         ic = 1.0f - c;
       
  1178         m.m[0][0] = x * x * ic + c;
       
  1179         m.m[1][0] = x * y * ic - z * s;
       
  1180         m.m[2][0] = 0.0f;
       
  1181         m.m[3][0] = 0.0f;
       
  1182         m.m[0][1] = y * x * ic + z * s;
       
  1183         m.m[1][1] = y * y * ic + c;
       
  1184         m.m[2][1] = 0.0f;
       
  1185         m.m[3][1] = 0.0f;
       
  1186         m.m[0][2] = 0.0f;
       
  1187         m.m[1][2] = 0.0f;
       
  1188         m.m[2][2] = 1.0f;
       
  1189         m.m[3][2] = 0.0f;
       
  1190         m.m[0][3] = (x * z * ic - y * s) * -inv_dist_to_plane;
       
  1191         m.m[1][3] = (y * z * ic + x * s) * -inv_dist_to_plane;
       
  1192         m.m[2][3] = 0.0f;
       
  1193         m.m[3][3] = 1.0f;
       
  1194     }
       
  1195     int flags = flagBits;
       
  1196     *this *= m;
       
  1197     if (flags != Identity)
       
  1198         flagBits = flags | Rotation;
       
  1199     else
       
  1200         flagBits = Rotation;
       
  1201 }
       
  1202 
       
  1203 #ifndef QT_NO_QUATERNION
  1107 
  1204 
  1108 /*!
  1205 /*!
  1109     Multiples this matrix by another that rotates coordinates according
  1206     Multiples this matrix by another that rotates coordinates according
  1110     to a specified \a quaternion.  The \a quaternion is assumed to have
  1207     to a specified \a quaternion.  The \a quaternion is assumed to have
  1111     been normalized.  Returns this matrix.
  1208     been normalized.
  1112 
  1209 
  1113     \sa scale(), translate(), QQuaternion
  1210     \sa scale(), translate(), QQuaternion
  1114 */
  1211 */
  1115 QMatrix4x4& QMatrix4x4::rotate(const QQuaternion& quaternion)
  1212 void QMatrix4x4::rotate(const QQuaternion& quaternion)
  1116 {
  1213 {
  1117     // Algorithm from:
  1214     // Algorithm from:
  1118     // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q54
  1215     // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q54
  1119     QMatrix4x4 m(1);
  1216     QMatrix4x4 m(1);
  1120     qreal xx = quaternion.x() * quaternion.x();
  1217     qreal xx = quaternion.x() * quaternion.x();
  1146     *this *= m;
  1243     *this *= m;
  1147     if (flags != Identity)
  1244     if (flags != Identity)
  1148         flagBits = flags | Rotation;
  1245         flagBits = flags | Rotation;
  1149     else
  1246     else
  1150         flagBits = Rotation;
  1247         flagBits = Rotation;
  1151     return *this;
       
  1152 }
  1248 }
  1153 
  1249 
  1154 #endif
  1250 #endif
  1155 
  1251 
  1156 /*!
  1252 /*!
  1157     \overload
  1253     \overload
  1158 
  1254 
  1159     Multiplies this matrix by another that applies an orthographic
  1255     Multiplies this matrix by another that applies an orthographic
  1160     projection for a window with boundaries specified by \a rect.
  1256     projection for a window with boundaries specified by \a rect.
  1161     The near and far clipping planes will be -1 and 1 respectively.
  1257     The near and far clipping planes will be -1 and 1 respectively.
  1162     Returns this matrix.
       
  1163 
  1258 
  1164     \sa frustum(), perspective()
  1259     \sa frustum(), perspective()
  1165 */
  1260 */
  1166 QMatrix4x4& QMatrix4x4::ortho(const QRect& rect)
  1261 void QMatrix4x4::ortho(const QRect& rect)
  1167 {
  1262 {
  1168     // Note: rect.right() and rect.bottom() subtract 1 in QRect,
  1263     // Note: rect.right() and rect.bottom() subtract 1 in QRect,
  1169     // which gives the location of a pixel within the rectangle,
  1264     // which gives the location of a pixel within the rectangle,
  1170     // instead of the extent of the rectangle.  We want the extent.
  1265     // instead of the extent of the rectangle.  We want the extent.
  1171     // QRectF expresses the extent properly.
  1266     // QRectF expresses the extent properly.
  1172     return ortho(rect.x(), rect.x() + rect.width(), rect.y() + rect.height(), rect.y(), -1.0f, 1.0f);
  1267     ortho(rect.x(), rect.x() + rect.width(), rect.y() + rect.height(), rect.y(), -1.0f, 1.0f);
  1173 }
  1268 }
  1174 
  1269 
  1175 /*!
  1270 /*!
  1176     \overload
  1271     \overload
  1177 
  1272 
  1178     Multiplies this matrix by another that applies an orthographic
  1273     Multiplies this matrix by another that applies an orthographic
  1179     projection for a window with boundaries specified by \a rect.
  1274     projection for a window with boundaries specified by \a rect.
  1180     The near and far clipping planes will be -1 and 1 respectively.
  1275     The near and far clipping planes will be -1 and 1 respectively.
  1181     Returns this matrix.
       
  1182 
  1276 
  1183     \sa frustum(), perspective()
  1277     \sa frustum(), perspective()
  1184 */
  1278 */
  1185 QMatrix4x4& QMatrix4x4::ortho(const QRectF& rect)
  1279 void QMatrix4x4::ortho(const QRectF& rect)
  1186 {
  1280 {
  1187     return ortho(rect.left(), rect.right(), rect.bottom(), rect.top(), -1.0f, 1.0f);
  1281     ortho(rect.left(), rect.right(), rect.bottom(), rect.top(), -1.0f, 1.0f);
  1188 }
  1282 }
  1189 
  1283 
  1190 /*!
  1284 /*!
  1191     Multiplies this matrix by another that applies an orthographic
  1285     Multiplies this matrix by another that applies an orthographic
  1192     projection for a window with lower-left corner (\a left, \a bottom),
  1286     projection for a window with lower-left corner (\a left, \a bottom),
  1193     upper-right corner (\a right, \a top), and the specified \a nearPlane
  1287     upper-right corner (\a right, \a top), and the specified \a nearPlane
  1194     and \a farPlane clipping planes.  Returns this matrix.
  1288     and \a farPlane clipping planes.
  1195 
  1289 
  1196     \sa frustum(), perspective()
  1290     \sa frustum(), perspective()
  1197 */
  1291 */
  1198 QMatrix4x4& QMatrix4x4::ortho(qreal left, qreal right, qreal bottom, qreal top, qreal nearPlane, qreal farPlane)
  1292 void QMatrix4x4::ortho(qreal left, qreal right, qreal bottom, qreal top, qreal nearPlane, qreal farPlane)
  1199 {
  1293 {
  1200     // Bail out if the projection volume is zero-sized.
  1294     // Bail out if the projection volume is zero-sized.
  1201     if (left == right || bottom == top || nearPlane == farPlane)
  1295     if (left == right || bottom == top || nearPlane == farPlane)
  1202         return *this;
  1296         return;
  1203 
  1297 
  1204     // Construct the projection.
  1298     // Construct the projection.
  1205     qreal width = right - left;
  1299     qreal width = right - left;
  1206     qreal invheight = top - bottom;
  1300     qreal invheight = top - bottom;
  1207     qreal clip = farPlane - nearPlane;
  1301     qreal clip = farPlane - nearPlane;
  1216              0.0f));
  1310              0.0f));
  1217         scale(QVector3D
  1311         scale(QVector3D
  1218             (2.0f / width,
  1312             (2.0f / width,
  1219              2.0f / invheight,
  1313              2.0f / invheight,
  1220              -1.0f));
  1314              -1.0f));
  1221         return *this;
  1315         return;
  1222     }
  1316     }
  1223 #endif
  1317 #endif
  1224     QMatrix4x4 m(1);
  1318     QMatrix4x4 m(1);
  1225     m.m[0][0] = 2.0f / width;
  1319     m.m[0][0] = 2.0f / width;
  1226     m.m[1][0] = 0.0f;
  1320     m.m[1][0] = 0.0f;
  1239     m.m[2][3] = 0.0f;
  1333     m.m[2][3] = 0.0f;
  1240     m.m[3][3] = 1.0f;
  1334     m.m[3][3] = 1.0f;
  1241 
  1335 
  1242     // Apply the projection.
  1336     // Apply the projection.
  1243     *this *= m;
  1337     *this *= m;
  1244     return *this;
  1338     return;
  1245 }
  1339 }
  1246 
  1340 
  1247 /*!
  1341 /*!
  1248     Multiplies this matrix by another that applies a perspective
  1342     Multiplies this matrix by another that applies a perspective
  1249     frustum projection for a window with lower-left corner (\a left, \a bottom),
  1343     frustum projection for a window with lower-left corner (\a left, \a bottom),
  1250     upper-right corner (\a right, \a top), and the specified \a nearPlane
  1344     upper-right corner (\a right, \a top), and the specified \a nearPlane
  1251     and \a farPlane clipping planes.  Returns this matrix.
  1345     and \a farPlane clipping planes.
  1252 
  1346 
  1253     \sa ortho(), perspective()
  1347     \sa ortho(), perspective()
  1254 */
  1348 */
  1255 QMatrix4x4& QMatrix4x4::frustum(qreal left, qreal right, qreal bottom, qreal top, qreal nearPlane, qreal farPlane)
  1349 void QMatrix4x4::frustum(qreal left, qreal right, qreal bottom, qreal top, qreal nearPlane, qreal farPlane)
  1256 {
  1350 {
  1257     // Bail out if the projection volume is zero-sized.
  1351     // Bail out if the projection volume is zero-sized.
  1258     if (left == right || bottom == top || nearPlane == farPlane)
  1352     if (left == right || bottom == top || nearPlane == farPlane)
  1259         return *this;
  1353         return;
  1260 
  1354 
  1261     // Construct the projection.
  1355     // Construct the projection.
  1262     QMatrix4x4 m(1);
  1356     QMatrix4x4 m(1);
  1263     qreal width = right - left;
  1357     qreal width = right - left;
  1264     qreal invheight = top - bottom;
  1358     qreal invheight = top - bottom;
  1280     m.m[2][3] = -1.0f;
  1374     m.m[2][3] = -1.0f;
  1281     m.m[3][3] = 0.0f;
  1375     m.m[3][3] = 0.0f;
  1282 
  1376 
  1283     // Apply the projection.
  1377     // Apply the projection.
  1284     *this *= m;
  1378     *this *= m;
  1285     return *this;
       
  1286 }
  1379 }
  1287 
  1380 
  1288 /*!
  1381 /*!
  1289     Multiplies this matrix by another that applies a perspective
  1382     Multiplies this matrix by another that applies a perspective
  1290     projection.  The field of view will be \a angle degrees within
  1383     projection.  The field of view will be \a angle degrees within
  1291     a window with a given \a aspect ratio.  The projection will
  1384     a window with a given \a aspect ratio.  The projection will
  1292     have the specified \a nearPlane and \a farPlane clipping planes.
  1385     have the specified \a nearPlane and \a farPlane clipping planes.
  1293     Returns this matrix.
       
  1294 
  1386 
  1295     \sa ortho(), frustum()
  1387     \sa ortho(), frustum()
  1296 */
  1388 */
  1297 QMatrix4x4& QMatrix4x4::perspective(qreal angle, qreal aspect, qreal nearPlane, qreal farPlane)
  1389 void QMatrix4x4::perspective(qreal angle, qreal aspect, qreal nearPlane, qreal farPlane)
  1298 {
  1390 {
  1299     // Bail out if the projection volume is zero-sized.
  1391     // Bail out if the projection volume is zero-sized.
  1300     if (nearPlane == farPlane || aspect == 0.0f)
  1392     if (nearPlane == farPlane || aspect == 0.0f)
  1301         return *this;
  1393         return;
  1302 
  1394 
  1303     // Construct the projection.
  1395     // Construct the projection.
  1304     QMatrix4x4 m(1);
  1396     QMatrix4x4 m(1);
  1305     qreal radians = (angle / 2.0f) * M_PI / 180.0f;
  1397     qreal radians = (angle / 2.0f) * M_PI / 180.0f;
  1306     qreal sine = qSin(radians);
  1398     qreal sine = qSin(radians);
  1307     if (sine == 0.0f)
  1399     if (sine == 0.0f)
  1308         return *this;
  1400         return;
  1309     qreal cotan = qCos(radians) / sine;
  1401     qreal cotan = qCos(radians) / sine;
  1310     qreal clip = farPlane - nearPlane;
  1402     qreal clip = farPlane - nearPlane;
  1311     m.m[0][0] = cotan / aspect;
  1403     m.m[0][0] = cotan / aspect;
  1312     m.m[1][0] = 0.0f;
  1404     m.m[1][0] = 0.0f;
  1313     m.m[2][0] = 0.0f;
  1405     m.m[2][0] = 0.0f;
  1325     m.m[2][3] = -1.0f;
  1417     m.m[2][3] = -1.0f;
  1326     m.m[3][3] = 0.0f;
  1418     m.m[3][3] = 0.0f;
  1327 
  1419 
  1328     // Apply the projection.
  1420     // Apply the projection.
  1329     *this *= m;
  1421     *this *= m;
  1330     return *this;
       
  1331 }
  1422 }
  1332 
  1423 
  1333 #ifndef QT_NO_VECTOR3D
  1424 #ifndef QT_NO_VECTOR3D
  1334 
  1425 
  1335 /*!
  1426 /*!
  1336     Multiplies this matrix by another that applies an \a eye position
  1427     Multiplies this matrix by another that applies an \a eye position
  1337     transformation.  The \a center value indicates the center of the
  1428     transformation.  The \a center value indicates the center of the
  1338     view that the \a eye is looking at.  The \a up value indicates
  1429     view that the \a eye is looking at.  The \a up value indicates
  1339     which direction should be considered up with respect to the \a eye.
  1430     which direction should be considered up with respect to the \a eye.
  1340     Returns this matrix.
  1431 */
  1341 */
  1432 void QMatrix4x4::lookAt(const QVector3D& eye, const QVector3D& center, const QVector3D& up)
  1342 QMatrix4x4& QMatrix4x4::lookAt(const QVector3D& eye, const QVector3D& center, const QVector3D& up)
       
  1343 {
  1433 {
  1344     QVector3D forward = (center - eye).normalized();
  1434     QVector3D forward = (center - eye).normalized();
  1345     QVector3D side = QVector3D::crossProduct(forward, up).normalized();
  1435     QVector3D side = QVector3D::crossProduct(forward, up).normalized();
  1346     QVector3D upVector = QVector3D::crossProduct(side, forward);
  1436     QVector3D upVector = QVector3D::crossProduct(side, forward);
  1347 
  1437 
  1363     m.m[1][3] = 0.0f;
  1453     m.m[1][3] = 0.0f;
  1364     m.m[2][3] = 0.0f;
  1454     m.m[2][3] = 0.0f;
  1365     m.m[3][3] = 1.0f;
  1455     m.m[3][3] = 1.0f;
  1366 
  1456 
  1367     *this *= m;
  1457     *this *= m;
  1368     return translate(-eye);
  1458     translate(-eye);
  1369 }
  1459 }
  1370 
  1460 
  1371 #endif
  1461 #endif
  1372 
  1462 
  1373 /*!
  1463 /*!
  1374     Flips between right-handed and left-handed coordinate systems
  1464     Flips between right-handed and left-handed coordinate systems
  1375     by multiplying the y and z co-ordinates by -1.  This is normally
  1465     by multiplying the y and z co-ordinates by -1.  This is normally
  1376     used to create a left-handed orthographic view without scaling
  1466     used to create a left-handed orthographic view without scaling
  1377     the viewport as ortho() does.  Returns this matrix.
  1467     the viewport as ortho() does.
  1378 
  1468 
  1379     \sa ortho()
  1469     \sa ortho()
  1380 */
  1470 */
  1381 QMatrix4x4& QMatrix4x4::flipCoordinates()
  1471 void QMatrix4x4::flipCoordinates()
  1382 {
  1472 {
  1383     if (flagBits == Scale || flagBits == (Scale | Translation)) {
  1473     if (flagBits == Scale || flagBits == (Scale | Translation)) {
  1384         m[1][1] = -m[1][1];
  1474         m[1][1] = -m[1][1];
  1385         m[2][2] = -m[2][2];
  1475         m[2][2] = -m[2][2];
  1386     } else if (flagBits == Translation) {
  1476     } else if (flagBits == Translation) {
  1400         m[2][1] = -m[2][1];
  1490         m[2][1] = -m[2][1];
  1401         m[2][2] = -m[2][2];
  1491         m[2][2] = -m[2][2];
  1402         m[2][3] = -m[2][3];
  1492         m[2][3] = -m[2][3];
  1403         flagBits = General;
  1493         flagBits = General;
  1404     }
  1494     }
  1405     return *this;
  1495 }
  1406 }
  1496 
  1407 
  1497 /*!
  1408 /*!
  1498     Retrieves the 16 items in this matrix and copies them to \a values
  1409     Retrieves the 16 items in this matrix and writes them to \a values
       
  1410     in row-major order.
  1499     in row-major order.
  1411 */
  1500 */
  1412 void QMatrix4x4::toValueArray(qreal *values) const
  1501 void QMatrix4x4::copyDataTo(qreal *values) const
  1413 {
  1502 {
  1414     for (int row = 0; row < 4; ++row)
  1503     for (int row = 0; row < 4; ++row)
  1415         for (int col = 0; col < 4; ++col)
  1504         for (int col = 0; col < 4; ++col)
  1416             values[row * 4 + col] = qreal(m[col][row]);
  1505             values[row * 4 + col] = qreal(m[col][row]);
  1417 }
  1506 }
  1428     return QMatrix(m[0][0], m[0][1],
  1517     return QMatrix(m[0][0], m[0][1],
  1429                    m[1][0], m[1][1],
  1518                    m[1][0], m[1][1],
  1430                    m[3][0], m[3][1]);
  1519                    m[3][0], m[3][1]);
  1431 }
  1520 }
  1432 
  1521 
  1433 static const qreal inv_dist_to_plane = 1. / 1024.;
       
  1434 
       
  1435 /*!
  1522 /*!
  1436     Returns the conventional Qt 2D transformation matrix that
  1523     Returns the conventional Qt 2D transformation matrix that
  1437     corresponds to this matrix.
  1524     corresponds to this matrix.
  1438 
  1525 
       
  1526     The returned QTransform is formed by simply dropping the
       
  1527     third row and third column of the QMatrix4x4.  This is suitable
       
  1528     for implementing orthographic projections where the z co-ordinate
       
  1529     should be dropped rather than projected.
       
  1530 
       
  1531     \sa toAffine()
       
  1532 */
       
  1533 QTransform QMatrix4x4::toTransform() const
       
  1534 {
       
  1535     return QTransform(m[0][0], m[0][1], m[0][3],
       
  1536                       m[1][0], m[1][1], m[1][3],
       
  1537                       m[3][0], m[3][1], m[3][3]);
       
  1538 }
       
  1539 
       
  1540 /*!
       
  1541     Returns the conventional Qt 2D transformation matrix that
       
  1542     corresponds to this matrix.
       
  1543 
  1439     If \a distanceToPlane is non-zero, it indicates a projection
  1544     If \a distanceToPlane is non-zero, it indicates a projection
  1440     factor to use to adjust for the z co-ordinate.  The default
  1545     factor to use to adjust for the z co-ordinate.  The value of
  1441     value of 1024 corresponds to the projection factor used
  1546     1024 corresponds to the projection factor used
  1442     by QTransform::rotate() for the x and y axes.
  1547     by QTransform::rotate() for the x and y axes.
  1443 
  1548 
  1444     If \a distanceToPlane is zero, then the returned QTransform
  1549     If \a distanceToPlane is zero, then the returned QTransform
  1445     is formed by simply dropping the third row and third column
  1550     is formed by simply dropping the third row and third column
  1446     of the QMatrix4x4.  This is suitable for implementing
  1551     of the QMatrix4x4.  This is suitable for implementing
  1615 /*!
  1720 /*!
  1616     \fn qreal *QMatrix4x4::data()
  1721     \fn qreal *QMatrix4x4::data()
  1617 
  1722 
  1618     Returns a pointer to the raw data of this matrix.
  1723     Returns a pointer to the raw data of this matrix.
  1619 
  1724 
  1620     \sa constData(), inferSpecialType()
  1725     \sa constData(), optimize()
  1621 */
  1726 */
  1622 
  1727 
  1623 /*!
  1728 /*!
  1624     \fn const qreal *QMatrix4x4::data() const
  1729     \fn const qreal *QMatrix4x4::data() const
  1625 
  1730 
  1664     result.m[3][3] = 1.0f;
  1769     result.m[3][3] = 1.0f;
  1665 
  1770 
  1666     return result;
  1771     return result;
  1667 }
  1772 }
  1668 
  1773 
  1669 #ifndef QT_NO_VECTOR3D
  1774 /*!
  1670 /*!
  1775     Optimize the usage of this matrix from its current elements.
  1671     Decomposes the current rotation matrix into an \a axis of rotation plus
       
  1672     an \a angle.  The result can be used to construct an equivalent rotation
       
  1673     matrix using glRotate().  It is assumed that the homogenous coordinate
       
  1674     is 1.0.  The returned vector is guaranteed to be normalized.
       
  1675 
       
  1676     \code
       
  1677         qreal angle;
       
  1678         QVector3D axis;
       
  1679 
       
  1680         matrix.extractAxisAngle(angle, axis);
       
  1681         glRotate(angle, axis[0], axis[1], axis[2]);
       
  1682     \endcode
       
  1683 
       
  1684     \sa rotate()
       
  1685 */
       
  1686 void QMatrix4x4::extractAxisRotation(qreal &angle, QVector3D &axis) const
       
  1687 {
       
  1688     // Orientation is dependent on the upper 3x3 matrix; subtract the
       
  1689     // homogeneous scaling element from the trace of the 4x4 matrix
       
  1690     qreal tr = m[0][0] + m[1][1] + m[2][2];
       
  1691     qreal cosa = qreal(0.5f * (tr - 1.0f));
       
  1692     angle = acos(cosa) * 180.0f / M_PI;
       
  1693 
       
  1694     // Any axis will work if r is zero (means no rotation)
       
  1695     if (qFuzzyIsNull(angle)) {
       
  1696         axis.setX(1.0f);
       
  1697         axis.setY(0.0f);
       
  1698         axis.setZ(0.0f);
       
  1699         return;
       
  1700     }
       
  1701 
       
  1702     if (angle < 180.0f) {
       
  1703         axis.setX(m[1][2] - m[2][1]);
       
  1704         axis.setY(m[2][0] - m[0][2]);
       
  1705         axis.setZ(m[0][1] - m[1][0]);
       
  1706         axis.normalize();
       
  1707         return;
       
  1708     }
       
  1709 
       
  1710     // rads == PI
       
  1711     qreal tmp;
       
  1712 
       
  1713     // r00 is maximum
       
  1714     if ((m[0][0] >= m[2][2]) && (m[0][0] >= m[1][1])) {
       
  1715         axis.setX(0.5f * qSqrt(m[0][0] - m[1][1] - m[2][2] + 1.0f));
       
  1716         tmp = 0.5f / axis.x();
       
  1717         axis.setY(m[1][0] * tmp);
       
  1718         axis.setZ(m[2][0] * tmp);
       
  1719     }
       
  1720 
       
  1721     // r11 is maximum
       
  1722     if ((m[1][1] >= m[2][2]) && (m[1][1] >= m[0][0])) {
       
  1723         axis.setY(0.5f * qSqrt(m[1][1] - m[0][0] - m[2][2] + 1.0f));
       
  1724         tmp = 0.5f / axis.y();
       
  1725         axis.setX(tmp * m[1][0]);
       
  1726         axis.setZ(tmp * m[2][1]);
       
  1727     }
       
  1728 
       
  1729     // r22 is maximum
       
  1730     if ((m[2][2] >= m[1][1]) && (m[2][2] >= m[0][0])) {
       
  1731         axis.setZ(0.5f * qSqrt(m[2][2] - m[0][0] - m[1][1] + 1.0f));
       
  1732         tmp = 0.5f / axis.z();
       
  1733         axis.setX(m[2][0]*tmp);
       
  1734         axis.setY(m[2][1]*tmp);
       
  1735     }
       
  1736 }
       
  1737 
       
  1738 /*!
       
  1739     If this is an orthonormal transformation matrix (e.g. only rotations and
       
  1740     translations have been applied to the matrix, no scaling, or shearing)
       
  1741     then the world translational component can be obtained by calling this function.
       
  1742 
       
  1743     This is most useful for camera matrices, where the negation of this vector
       
  1744     is effectively the camera world coordinates.
       
  1745 */
       
  1746 QVector3D QMatrix4x4::extractTranslation() const
       
  1747 {
       
  1748     return QVector3D
       
  1749         (m[0][0] * m[3][0] + m[0][1] * m[3][1] + m[0][2] * m[3][2],
       
  1750          m[1][0] * m[3][0] + m[1][1] * m[3][1] + m[1][2] * m[3][2],
       
  1751          m[2][0] * m[3][0] + m[2][1] * m[3][1] + m[2][2] * m[3][2]);
       
  1752 }
       
  1753 #endif
       
  1754 
       
  1755 /*!
       
  1756     Infers the special type of this matrix from its current elements.
       
  1757 
  1776 
  1758     Some operations such as translate(), scale(), and rotate() can be
  1777     Some operations such as translate(), scale(), and rotate() can be
  1759     performed more efficiently if the matrix being modified is already
  1778     performed more efficiently if the matrix being modified is already
  1760     known to be the identity, a previous translate(), a previous
  1779     known to be the identity, a previous translate(), a previous
  1761     scale(), etc.
  1780     scale(), etc.
  1764     as operations are performed.  However, if the matrix is modified
  1783     as operations are performed.  However, if the matrix is modified
  1765     directly with operator()() or data(), then QMatrix4x4 will lose track of
  1784     directly with operator()() or data(), then QMatrix4x4 will lose track of
  1766     the special type and will revert to the safest but least efficient
  1785     the special type and will revert to the safest but least efficient
  1767     operations thereafter.
  1786     operations thereafter.
  1768 
  1787 
  1769     By calling inferSpecialType() after directly modifying the matrix,
  1788     By calling optimize() after directly modifying the matrix,
  1770     the programmer can force QMatrix4x4 to recover the special type if
  1789     the programmer can force QMatrix4x4 to recover the special type if
  1771     the elements appear to conform to one of the known optimized types.
  1790     the elements appear to conform to one of the known optimized types.
  1772 
  1791 
  1773     \sa operator()(), data(), translate()
  1792     \sa operator()(), data(), translate()
  1774 */
  1793 */
  1775 void QMatrix4x4::inferSpecialType()
  1794 void QMatrix4x4::optimize()
  1776 {
  1795 {
  1777     // If the last element is not 1, then it can never be special.
  1796     // If the last element is not 1, then it can never be special.
  1778     if (m[3][3] != 1.0f) {
  1797     if (m[3][3] != 1.0f) {
  1779         flagBits = General;
  1798         flagBits = General;
  1780         return;
  1799         return;
  1887         for (int col = 0; col < 4; ++col) {
  1906         for (int col = 0; col < 4; ++col) {
  1888             stream >> x;
  1907             stream >> x;
  1889             matrix(row, col) = qreal(x);
  1908             matrix(row, col) = qreal(x);
  1890         }
  1909         }
  1891     }
  1910     }
  1892     matrix.inferSpecialType();
  1911     matrix.optimize();
  1893     return stream;
  1912     return stream;
  1894 }
  1913 }
  1895 
  1914 
  1896 #endif // QT_NO_DATASTREAM
  1915 #endif // QT_NO_DATASTREAM
  1897 
  1916