tests/auto/qmatrixnxn/tst_qmatrixnxn.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the test suite of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include <QtTest/QtTest>
       
    43 #include <QtCore/qmath.h>
       
    44 #include <QtGui/qmatrix4x4.h>
       
    45 
       
    46 class tst_QMatrixNxN : public QObject
       
    47 {
       
    48     Q_OBJECT
       
    49 public:
       
    50     tst_QMatrixNxN() {}
       
    51     ~tst_QMatrixNxN() {}
       
    52 
       
    53 private slots:
       
    54     void create2x2();
       
    55     void create3x3();
       
    56     void create4x4();
       
    57     void create4x3();
       
    58 
       
    59     void isIdentity2x2();
       
    60     void isIdentity3x3();
       
    61     void isIdentity4x4();
       
    62     void isIdentity4x3();
       
    63 
       
    64     void compare2x2();
       
    65     void compare3x3();
       
    66     void compare4x4();
       
    67     void compare4x3();
       
    68 
       
    69     void transposed2x2();
       
    70     void transposed3x3();
       
    71     void transposed4x4();
       
    72     void transposed4x3();
       
    73 
       
    74     void add2x2_data();
       
    75     void add2x2();
       
    76     void add3x3_data();
       
    77     void add3x3();
       
    78     void add4x4_data();
       
    79     void add4x4();
       
    80     void add4x3_data();
       
    81     void add4x3();
       
    82 
       
    83     void subtract2x2_data();
       
    84     void subtract2x2();
       
    85     void subtract3x3_data();
       
    86     void subtract3x3();
       
    87     void subtract4x4_data();
       
    88     void subtract4x4();
       
    89     void subtract4x3_data();
       
    90     void subtract4x3();
       
    91 
       
    92     void multiply2x2_data();
       
    93     void multiply2x2();
       
    94     void multiply3x3_data();
       
    95     void multiply3x3();
       
    96     void multiply4x4_data();
       
    97     void multiply4x4();
       
    98     void multiply4x3_data();
       
    99     void multiply4x3();
       
   100 
       
   101     void multiplyFactor2x2_data();
       
   102     void multiplyFactor2x2();
       
   103     void multiplyFactor3x3_data();
       
   104     void multiplyFactor3x3();
       
   105     void multiplyFactor4x4_data();
       
   106     void multiplyFactor4x4();
       
   107     void multiplyFactor4x3_data();
       
   108     void multiplyFactor4x3();
       
   109 
       
   110     void divideFactor2x2_data();
       
   111     void divideFactor2x2();
       
   112     void divideFactor3x3_data();
       
   113     void divideFactor3x3();
       
   114     void divideFactor4x4_data();
       
   115     void divideFactor4x4();
       
   116     void divideFactor4x3_data();
       
   117     void divideFactor4x3();
       
   118 
       
   119     void negate2x2_data();
       
   120     void negate2x2();
       
   121     void negate3x3_data();
       
   122     void negate3x3();
       
   123     void negate4x4_data();
       
   124     void negate4x4();
       
   125     void negate4x3_data();
       
   126     void negate4x3();
       
   127 
       
   128     void inverted4x4_data();
       
   129     void inverted4x4();
       
   130 
       
   131     void orthonormalInverse4x4();
       
   132 
       
   133     void scale4x4_data();
       
   134     void scale4x4();
       
   135 
       
   136     void translate4x4_data();
       
   137     void translate4x4();
       
   138 
       
   139     void rotate4x4_data();
       
   140     void rotate4x4();
       
   141 
       
   142     void normalMatrix_data();
       
   143     void normalMatrix();
       
   144 
       
   145     void optimizedTransforms();
       
   146 
       
   147     void ortho();
       
   148     void frustum();
       
   149     void perspective();
       
   150     void flipCoordinates();
       
   151 
       
   152     void convertGeneric();
       
   153 
       
   154     void extractAxisRotation_data();
       
   155     void extractAxisRotation();
       
   156 
       
   157     void extractTranslation_data();
       
   158     void extractTranslation();
       
   159 
       
   160     void inferSpecialType_data();
       
   161     void inferSpecialType();
       
   162 
       
   163     void columnsAndRows();
       
   164 
       
   165     void convertQMatrix();
       
   166     void convertQTransform();
       
   167 
       
   168     void fill();
       
   169 
       
   170     void mapRect_data();
       
   171     void mapRect();
       
   172 
       
   173     void mapVector_data();
       
   174     void mapVector();
       
   175 
       
   176     void properties();
       
   177     void metaTypes();
       
   178 
       
   179 private:
       
   180     static void setMatrix(QMatrix2x2& m, const qreal *values);
       
   181     static void setMatrixDirect(QMatrix2x2& m, const qreal *values);
       
   182     static bool isSame(const QMatrix2x2& m, const qreal *values);
       
   183     static bool isIdentity(const QMatrix2x2& m);
       
   184 
       
   185     static void setMatrix(QMatrix3x3& m, const qreal *values);
       
   186     static void setMatrixDirect(QMatrix3x3& m, const qreal *values);
       
   187     static bool isSame(const QMatrix3x3& m, const qreal *values);
       
   188     static bool isIdentity(const QMatrix3x3& m);
       
   189 
       
   190     static void setMatrix(QMatrix4x4& m, const qreal *values);
       
   191     static void setMatrixDirect(QMatrix4x4& m, const qreal *values);
       
   192     static bool isSame(const QMatrix4x4& m, const qreal *values);
       
   193     static bool isIdentity(const QMatrix4x4& m);
       
   194 
       
   195     static void setMatrix(QMatrix4x3& m, const qreal *values);
       
   196     static void setMatrixDirect(QMatrix4x3& m, const qreal *values);
       
   197     static bool isSame(const QMatrix4x3& m, const qreal *values);
       
   198     static bool isIdentity(const QMatrix4x3& m);
       
   199 };
       
   200 
       
   201 static const qreal nullValues2[] =
       
   202     {0.0f, 0.0f,
       
   203      0.0f, 0.0f};
       
   204 
       
   205 static qreal const identityValues2[16] =
       
   206     {1.0f, 0.0f,
       
   207      0.0f, 1.0f};
       
   208 
       
   209 static const qreal doubleIdentity2[] =
       
   210     {2.0f, 0.0f,
       
   211      0.0f, 2.0f};
       
   212 
       
   213 static qreal const uniqueValues2[16] =
       
   214     {1.0f, 2.0f,
       
   215      5.0f, 6.0f};
       
   216 
       
   217 static qreal const transposedValues2[16] =
       
   218     {1.0f, 5.0f,
       
   219      2.0f, 6.0f};
       
   220 
       
   221 static const qreal nullValues3[] =
       
   222     {0.0f, 0.0f, 0.0f,
       
   223      0.0f, 0.0f, 0.0f,
       
   224      0.0f, 0.0f, 0.0f};
       
   225 
       
   226 static qreal const identityValues3[16] =
       
   227     {1.0f, 0.0f, 0.0f,
       
   228      0.0f, 1.0f, 0.0f,
       
   229      0.0f, 0.0f, 1.0f};
       
   230 
       
   231 static const qreal doubleIdentity3[] =
       
   232     {2.0f, 0.0f, 0.0f,
       
   233      0.0f, 2.0f, 0.0f,
       
   234      0.0f, 0.0f, 2.0f};
       
   235 
       
   236 static qreal const uniqueValues3[16] =
       
   237     {1.0f, 2.0f, 3.0f,
       
   238      5.0f, 6.0f, 7.0f,
       
   239      9.0f, 10.0f, 11.0f};
       
   240 
       
   241 static qreal const transposedValues3[16] =
       
   242     {1.0f, 5.0f, 9.0f,
       
   243      2.0f, 6.0f, 10.0f,
       
   244      3.0f, 7.0f, 11.0f};
       
   245 
       
   246 static const qreal nullValues4[] =
       
   247     {0.0f, 0.0f, 0.0f, 0.0f,
       
   248      0.0f, 0.0f, 0.0f, 0.0f,
       
   249      0.0f, 0.0f, 0.0f, 0.0f,
       
   250      0.0f, 0.0f, 0.0f, 0.0f};
       
   251 
       
   252 static qreal const identityValues4[16] =
       
   253     {1.0f, 0.0f, 0.0f, 0.0f,
       
   254      0.0f, 1.0f, 0.0f, 0.0f,
       
   255      0.0f, 0.0f, 1.0f, 0.0f,
       
   256      0.0f, 0.0f, 0.0f, 1.0f};
       
   257 
       
   258 static const qreal doubleIdentity4[] =
       
   259     {2.0f, 0.0f, 0.0f, 0.0f,
       
   260      0.0f, 2.0f, 0.0f, 0.0f,
       
   261      0.0f, 0.0f, 2.0f, 0.0f,
       
   262      0.0f, 0.0f, 0.0f, 2.0f};
       
   263 
       
   264 static qreal const uniqueValues4[16] =
       
   265     {1.0f, 2.0f, 3.0f, 4.0f,
       
   266      5.0f, 6.0f, 7.0f, 8.0f,
       
   267      9.0f, 10.0f, 11.0f, 12.0f,
       
   268      13.0f, 14.0f, 15.0f, 16.0f};
       
   269 
       
   270 static qreal const transposedValues4[16] =
       
   271     {1.0f, 5.0f, 9.0f, 13.0f,
       
   272      2.0f, 6.0f, 10.0f, 14.0f,
       
   273      3.0f, 7.0f, 11.0f, 15.0f,
       
   274      4.0f, 8.0f, 12.0f, 16.0f};
       
   275 
       
   276 static const qreal nullValues4x3[] =
       
   277     {0.0f, 0.0f, 0.0f, 0.0f,
       
   278      0.0f, 0.0f, 0.0f, 0.0f,
       
   279      0.0f, 0.0f, 0.0f, 0.0f};
       
   280 
       
   281 static qreal const identityValues4x3[12] =
       
   282     {1.0f, 0.0f, 0.0f, 0.0f,
       
   283      0.0f, 1.0f, 0.0f, 0.0f,
       
   284      0.0f, 0.0f, 1.0f, 0.0f};
       
   285 
       
   286 static qreal const doubleIdentity4x3[12] =
       
   287     {2.0f, 0.0f, 0.0f, 0.0f,
       
   288      0.0f, 2.0f, 0.0f, 0.0f,
       
   289      0.0f, 0.0f, 2.0f, 0.0f};
       
   290 
       
   291 static qreal const uniqueValues4x3[12] =
       
   292     {1.0f, 2.0f, 3.0f, 4.0f,
       
   293      5.0f, 6.0f, 7.0f, 8.0f,
       
   294      9.0f, 10.0f, 11.0f, 12.0f};
       
   295 
       
   296 static qreal const transposedValues3x4[12] =
       
   297     {1.0f, 5.0f, 9.0f,
       
   298      2.0f, 6.0f, 10.0f,
       
   299      3.0f, 7.0f, 11.0f,
       
   300      4.0f, 8.0f, 12.0f};
       
   301 
       
   302 // Set a matrix to a specified array of values, which are assumed
       
   303 // to be in row-major order.  This sets the values using floating-point.
       
   304 void tst_QMatrixNxN::setMatrix(QMatrix2x2& m, const qreal *values)
       
   305 {
       
   306     for (int row = 0; row < 2; ++row)
       
   307         for (int col = 0; col < 2; ++col)
       
   308             m(row, col) = values[row * 2 + col];
       
   309 }
       
   310 void tst_QMatrixNxN::setMatrix(QMatrix3x3& m, const qreal *values)
       
   311 {
       
   312     for (int row = 0; row < 3; ++row)
       
   313         for (int col = 0; col < 3; ++col)
       
   314             m(row, col) = values[row * 3 + col];
       
   315 }
       
   316 void tst_QMatrixNxN::setMatrix(QMatrix4x4& m, const qreal *values)
       
   317 {
       
   318     for (int row = 0; row < 4; ++row)
       
   319         for (int col = 0; col < 4; ++col)
       
   320             m(row, col) = values[row * 4 + col];
       
   321 }
       
   322 void tst_QMatrixNxN::setMatrix(QMatrix4x3& m, const qreal *values)
       
   323 {
       
   324     for (int row = 0; row < 3; ++row)
       
   325         for (int col = 0; col < 4; ++col)
       
   326             m(row, col) = values[row * 4 + col];
       
   327 }
       
   328 
       
   329 // Set a matrix to a specified array of values, which are assumed
       
   330 // to be in row-major order.  This sets the values directly into
       
   331 // the internal data() array.
       
   332 void tst_QMatrixNxN::setMatrixDirect(QMatrix2x2& m, const qreal *values)
       
   333 {
       
   334     qreal *data = m.data();
       
   335     for (int row = 0; row < 2; ++row) {
       
   336         for (int col = 0; col < 2; ++col) {
       
   337             data[row + col * 2] = values[row * 2 + col];
       
   338         }
       
   339     }
       
   340 }
       
   341 void tst_QMatrixNxN::setMatrixDirect(QMatrix3x3& m, const qreal *values)
       
   342 {
       
   343     qreal *data = m.data();
       
   344     for (int row = 0; row < 3; ++row) {
       
   345         for (int col = 0; col < 3; ++col) {
       
   346             data[row + col * 3] = values[row * 3 + col];
       
   347         }
       
   348     }
       
   349 }
       
   350 void tst_QMatrixNxN::setMatrixDirect(QMatrix4x4& m, const qreal *values)
       
   351 {
       
   352     qreal *data = m.data();
       
   353     for (int row = 0; row < 4; ++row) {
       
   354         for (int col = 0; col < 4; ++col) {
       
   355             data[row + col * 4] = values[row * 4 + col];
       
   356         }
       
   357     }
       
   358 }
       
   359 void tst_QMatrixNxN::setMatrixDirect(QMatrix4x3& m, const qreal *values)
       
   360 {
       
   361     qreal *data = m.data();
       
   362     for (int row = 0; row < 3; ++row) {
       
   363         for (int col = 0; col < 4; ++col) {
       
   364             data[row + col * 3] = values[row * 4 + col];
       
   365         }
       
   366     }
       
   367 }
       
   368 
       
   369 // QVector2/3/4D use float internally, which can sometimes lead
       
   370 // to precision issues when converting to and from qreal during
       
   371 // operations involving QMatrix4x4.  This fuzzy compare is slightly
       
   372 // "fuzzier" than the default qFuzzyCompare for qreal to compensate.
       
   373 static bool fuzzyCompare(qreal x, qreal y)
       
   374 {
       
   375     return qFuzzyIsNull((float)(x - y));
       
   376 }
       
   377 
       
   378 static bool fuzzyCompare(const QVector3D &v1, const QVector3D &v2)
       
   379 {
       
   380     if (!fuzzyCompare(v1.x(), v2.x()))
       
   381         return false;
       
   382     if (!fuzzyCompare(v1.y(), v2.y()))
       
   383         return false;
       
   384     if (!fuzzyCompare(v1.z(), v2.z()))
       
   385         return false;
       
   386     return true;
       
   387 }
       
   388 
       
   389 // Determine if a matrix is the same as a specified array of values.
       
   390 // The values are assumed to be specified in row-major order.
       
   391 bool tst_QMatrixNxN::isSame(const QMatrix2x2& m, const qreal *values)
       
   392 {
       
   393     const qreal *mv = m.constData();
       
   394     for (int row = 0; row < 2; ++row) {
       
   395         for (int col = 0; col < 2; ++col) {
       
   396             // Check the values using the operator() function.
       
   397             if (!fuzzyCompare(m(row, col), values[row * 2 + col])) {
       
   398                 qDebug() << "floating-point failure at" << row << col << "actual =" << m(row, col) << "expected =" << values[row * 2 + col];
       
   399                 return false;
       
   400             }
       
   401 
       
   402             // Check the values using direct access, which verifies that the values
       
   403             // are stored internally in column-major order.
       
   404             if (!fuzzyCompare(mv[col * 2 + row], values[row * 2 + col])) {
       
   405                 qDebug() << "column floating-point failure at" << row << col << "actual =" << mv[col * 2 + row] << "expected =" << values[row * 2 + col];
       
   406                 return false;
       
   407             }
       
   408         }
       
   409     }
       
   410     return true;
       
   411 }
       
   412 bool tst_QMatrixNxN::isSame(const QMatrix3x3& m, const qreal *values)
       
   413 {
       
   414     const qreal *mv = m.constData();
       
   415     for (int row = 0; row < 3; ++row) {
       
   416         for (int col = 0; col < 3; ++col) {
       
   417             // Check the values using the operator() access function.
       
   418             if (!fuzzyCompare(m(row, col), values[row * 3 + col])) {
       
   419                 qDebug() << "floating-point failure at" << row << col << "actual =" << m(row, col) << "expected =" << values[row * 3 + col];
       
   420                 return false;
       
   421             }
       
   422 
       
   423             // Check the values using direct access, which verifies that the values
       
   424             // are stored internally in column-major order.
       
   425             if (!fuzzyCompare(mv[col * 3 + row], values[row * 3 + col])) {
       
   426                 qDebug() << "column floating-point failure at" << row << col << "actual =" << mv[col * 3 + row] << "expected =" << values[row * 3 + col];
       
   427                 return false;
       
   428             }
       
   429         }
       
   430     }
       
   431     return true;
       
   432 }
       
   433 bool tst_QMatrixNxN::isSame(const QMatrix4x4& m, const qreal *values)
       
   434 {
       
   435     const qreal *mv = m.constData();
       
   436     for (int row = 0; row < 4; ++row) {
       
   437         for (int col = 0; col < 4; ++col) {
       
   438             // Check the values using the operator() access function.
       
   439             if (!fuzzyCompare(m(row, col), values[row * 4 + col])) {
       
   440                 qDebug() << "floating-point failure at" << row << col << "actual =" << m(row, col) << "expected =" << values[row * 4 + col];
       
   441                 return false;
       
   442             }
       
   443 
       
   444             // Check the values using direct access, which verifies that the values
       
   445             // are stored internally in column-major order.
       
   446             if (!fuzzyCompare(mv[col * 4 + row], values[row * 4 + col])) {
       
   447                 qDebug() << "column floating-point failure at" << row << col << "actual =" << mv[col * 4 + row] << "expected =" << values[row * 4 + col];
       
   448                 return false;
       
   449             }
       
   450         }
       
   451     }
       
   452     return true;
       
   453 }
       
   454 bool tst_QMatrixNxN::isSame(const QMatrix4x3& m, const qreal *values)
       
   455 {
       
   456     const qreal *mv = m.constData();
       
   457     for (int row = 0; row < 3; ++row) {
       
   458         for (int col = 0; col < 4; ++col) {
       
   459             // Check the values using the operator() access function.
       
   460             if (!fuzzyCompare(m(row, col), values[row * 4 + col])) {
       
   461                 qDebug() << "floating-point failure at" << row << col << "actual =" << m(row, col) << "expected =" << values[row * 4 + col];
       
   462                 return false;
       
   463             }
       
   464 
       
   465             // Check the values using direct access, which verifies that the values
       
   466             // are stored internally in column-major order.
       
   467             if (!fuzzyCompare(mv[col * 3 + row], values[row * 4 + col])) {
       
   468                 qDebug() << "column floating-point failure at" << row << col << "actual =" << mv[col * 3 + row] << "expected =" << values[row * 4 + col];
       
   469                 return false;
       
   470             }
       
   471         }
       
   472     }
       
   473     return true;
       
   474 }
       
   475 
       
   476 // Determine if a matrix is the identity.
       
   477 bool tst_QMatrixNxN::isIdentity(const QMatrix2x2& m)
       
   478 {
       
   479     return isSame(m, identityValues2);
       
   480 }
       
   481 bool tst_QMatrixNxN::isIdentity(const QMatrix3x3& m)
       
   482 {
       
   483     return isSame(m, identityValues3);
       
   484 }
       
   485 bool tst_QMatrixNxN::isIdentity(const QMatrix4x4& m)
       
   486 {
       
   487     return isSame(m, identityValues4);
       
   488 }
       
   489 bool tst_QMatrixNxN::isIdentity(const QMatrix4x3& m)
       
   490 {
       
   491     return isSame(m, identityValues4x3);
       
   492 }
       
   493 
       
   494 // Test the creation of QMatrix2x2 objects in various ways:
       
   495 // construct, copy, and modify.
       
   496 void tst_QMatrixNxN::create2x2()
       
   497 {
       
   498     QMatrix2x2 m1;
       
   499     QVERIFY(isIdentity(m1));
       
   500     QVERIFY(m1.isIdentity());
       
   501 
       
   502     QMatrix2x2 m2;
       
   503     setMatrix(m2, uniqueValues2);
       
   504     QVERIFY(isSame(m2, uniqueValues2));
       
   505     QVERIFY(!m2.isIdentity());
       
   506 
       
   507     QMatrix2x2 m3;
       
   508     setMatrixDirect(m3, uniqueValues2);
       
   509     QVERIFY(isSame(m3, uniqueValues2));
       
   510 
       
   511     QMatrix2x2 m4(m3);
       
   512     QVERIFY(isSame(m4, uniqueValues2));
       
   513 
       
   514     QMatrix2x2 m5;
       
   515     m5 = m3;
       
   516     QVERIFY(isSame(m5, uniqueValues2));
       
   517 
       
   518     m5.setIdentity();
       
   519     QVERIFY(isIdentity(m5));
       
   520 
       
   521     QMatrix2x2 m6(uniqueValues2);
       
   522     QVERIFY(isSame(m6, uniqueValues2));
       
   523     qreal vals[4];
       
   524     m6.toValueArray(vals);
       
   525     for (int index = 0; index < 4; ++index)
       
   526         QCOMPARE(vals[index], uniqueValues2[index]);
       
   527 }
       
   528 
       
   529 // Test the creation of QMatrix3x3 objects in various ways:
       
   530 // construct, copy, and modify.
       
   531 void tst_QMatrixNxN::create3x3()
       
   532 {
       
   533     QMatrix3x3 m1;
       
   534     QVERIFY(isIdentity(m1));
       
   535     QVERIFY(m1.isIdentity());
       
   536 
       
   537     QMatrix3x3 m2;
       
   538     setMatrix(m2, uniqueValues3);
       
   539     QVERIFY(isSame(m2, uniqueValues3));
       
   540     QVERIFY(!m2.isIdentity());
       
   541 
       
   542     QMatrix3x3 m3;
       
   543     setMatrixDirect(m3, uniqueValues3);
       
   544     QVERIFY(isSame(m3, uniqueValues3));
       
   545 
       
   546     QMatrix3x3 m4(m3);
       
   547     QVERIFY(isSame(m4, uniqueValues3));
       
   548 
       
   549     QMatrix3x3 m5;
       
   550     m5 = m3;
       
   551     QVERIFY(isSame(m5, uniqueValues3));
       
   552 
       
   553     m5.setIdentity();
       
   554     QVERIFY(isIdentity(m5));
       
   555 
       
   556     QMatrix3x3 m6(uniqueValues3);
       
   557     QVERIFY(isSame(m6, uniqueValues3));
       
   558     qreal vals[9];
       
   559     m6.toValueArray(vals);
       
   560     for (int index = 0; index < 9; ++index)
       
   561         QCOMPARE(vals[index], uniqueValues3[index]);
       
   562 }
       
   563 
       
   564 // Test the creation of QMatrix4x4 objects in various ways:
       
   565 // construct, copy, and modify.
       
   566 void tst_QMatrixNxN::create4x4()
       
   567 {
       
   568     QMatrix4x4 m1;
       
   569     QVERIFY(isIdentity(m1));
       
   570     QVERIFY(m1.isIdentity());
       
   571 
       
   572     QMatrix4x4 m2;
       
   573     setMatrix(m2, uniqueValues4);
       
   574     QVERIFY(isSame(m2, uniqueValues4));
       
   575     QVERIFY(!m2.isIdentity());
       
   576 
       
   577     QMatrix4x4 m3;
       
   578     setMatrixDirect(m3, uniqueValues4);
       
   579     QVERIFY(isSame(m3, uniqueValues4));
       
   580 
       
   581     QMatrix4x4 m4(m3);
       
   582     QVERIFY(isSame(m4, uniqueValues4));
       
   583 
       
   584     QMatrix4x4 m5;
       
   585     m5 = m3;
       
   586     QVERIFY(isSame(m5, uniqueValues4));
       
   587 
       
   588     m5.setIdentity();
       
   589     QVERIFY(isIdentity(m5));
       
   590 
       
   591     QMatrix4x4 m6(uniqueValues4);
       
   592     QVERIFY(isSame(m6, uniqueValues4));
       
   593     qreal vals[16];
       
   594     m6.toValueArray(vals);
       
   595     for (int index = 0; index < 16; ++index)
       
   596         QCOMPARE(vals[index], uniqueValues4[index]);
       
   597 
       
   598     QMatrix4x4 m8
       
   599         (uniqueValues4[0], uniqueValues4[1], uniqueValues4[2], uniqueValues4[3],
       
   600          uniqueValues4[4], uniqueValues4[5], uniqueValues4[6], uniqueValues4[7],
       
   601          uniqueValues4[8], uniqueValues4[9], uniqueValues4[10], uniqueValues4[11],
       
   602          uniqueValues4[12], uniqueValues4[13], uniqueValues4[14], uniqueValues4[15]);
       
   603     QVERIFY(isSame(m8, uniqueValues4));
       
   604 }
       
   605 
       
   606 // Test the creation of QMatrix4x3 objects in various ways:
       
   607 // construct, copy, and modify.
       
   608 void tst_QMatrixNxN::create4x3()
       
   609 {
       
   610     QMatrix4x3 m1;
       
   611     QVERIFY(isIdentity(m1));
       
   612     QVERIFY(m1.isIdentity());
       
   613 
       
   614     QMatrix4x3 m2;
       
   615     setMatrix(m2, uniqueValues4x3);
       
   616     QVERIFY(isSame(m2, uniqueValues4x3));
       
   617     QVERIFY(!m2.isIdentity());
       
   618 
       
   619     QMatrix4x3 m3;
       
   620     setMatrixDirect(m3, uniqueValues4x3);
       
   621     QVERIFY(isSame(m3, uniqueValues4x3));
       
   622 
       
   623     QMatrix4x3 m4(m3);
       
   624     QVERIFY(isSame(m4, uniqueValues4x3));
       
   625 
       
   626     QMatrix4x3 m5;
       
   627     m5 = m3;
       
   628     QVERIFY(isSame(m5, uniqueValues4x3));
       
   629 
       
   630     m5.setIdentity();
       
   631     QVERIFY(isIdentity(m5));
       
   632 
       
   633     QMatrix4x3 m6(uniqueValues4x3);
       
   634     QVERIFY(isSame(m6, uniqueValues4x3));
       
   635     qreal vals[12];
       
   636     m6.toValueArray(vals);
       
   637     for (int index = 0; index < 12; ++index)
       
   638         QCOMPARE(vals[index], uniqueValues4x3[index]);
       
   639 }
       
   640 
       
   641 // Test isIdentity() for 2x2 matrices.
       
   642 void tst_QMatrixNxN::isIdentity2x2()
       
   643 {
       
   644     for (int i = 0; i < 2 * 2; ++i) {
       
   645         QMatrix2x2 m;
       
   646         QVERIFY(m.isIdentity());
       
   647         m.data()[i] = 42.0f;
       
   648         QVERIFY(!m.isIdentity());
       
   649     }
       
   650 }
       
   651 
       
   652 // Test isIdentity() for 3x3 matrices.
       
   653 void tst_QMatrixNxN::isIdentity3x3()
       
   654 {
       
   655     for (int i = 0; i < 3 * 3; ++i) {
       
   656         QMatrix3x3 m;
       
   657         QVERIFY(m.isIdentity());
       
   658         m.data()[i] = 42.0f;
       
   659         QVERIFY(!m.isIdentity());
       
   660     }
       
   661 }
       
   662 
       
   663 // Test isIdentity() for 4x4 matrices.
       
   664 void tst_QMatrixNxN::isIdentity4x4()
       
   665 {
       
   666     for (int i = 0; i < 4 * 4; ++i) {
       
   667         QMatrix4x4 m;
       
   668         QVERIFY(m.isIdentity());
       
   669         m.data()[i] = 42.0f;
       
   670         QVERIFY(!m.isIdentity());
       
   671     }
       
   672 
       
   673     // Force the "Identity" flag bit to be lost and check again.
       
   674     QMatrix4x4 m2;
       
   675     m2.data()[0] = 1.0f;
       
   676     QVERIFY(m2.isIdentity());
       
   677 }
       
   678 
       
   679 // Test isIdentity() for 4x3 matrices.
       
   680 void tst_QMatrixNxN::isIdentity4x3()
       
   681 {
       
   682     for (int i = 0; i < 4 * 3; ++i) {
       
   683         QMatrix4x3 m;
       
   684         QVERIFY(m.isIdentity());
       
   685         m.data()[i] = 42.0f;
       
   686         QVERIFY(!m.isIdentity());
       
   687     }
       
   688 }
       
   689 
       
   690 // Test 2x2 matrix comparisons.
       
   691 void tst_QMatrixNxN::compare2x2()
       
   692 {
       
   693     QMatrix2x2 m1(uniqueValues2);
       
   694     QMatrix2x2 m2(uniqueValues2);
       
   695     QMatrix2x2 m3(transposedValues2);
       
   696 
       
   697     QVERIFY(m1 == m2);
       
   698     QVERIFY(!(m1 != m2));
       
   699     QVERIFY(m1 != m3);
       
   700     QVERIFY(!(m1 == m3));
       
   701 }
       
   702 
       
   703 // Test 3x3 matrix comparisons.
       
   704 void tst_QMatrixNxN::compare3x3()
       
   705 {
       
   706     QMatrix3x3 m1(uniqueValues3);
       
   707     QMatrix3x3 m2(uniqueValues3);
       
   708     QMatrix3x3 m3(transposedValues3);
       
   709 
       
   710     QVERIFY(m1 == m2);
       
   711     QVERIFY(!(m1 != m2));
       
   712     QVERIFY(m1 != m3);
       
   713     QVERIFY(!(m1 == m3));
       
   714 }
       
   715 
       
   716 // Test 4x4 matrix comparisons.
       
   717 void tst_QMatrixNxN::compare4x4()
       
   718 {
       
   719     QMatrix4x4 m1(uniqueValues4);
       
   720     QMatrix4x4 m2(uniqueValues4);
       
   721     QMatrix4x4 m3(transposedValues4);
       
   722 
       
   723     QVERIFY(m1 == m2);
       
   724     QVERIFY(!(m1 != m2));
       
   725     QVERIFY(m1 != m3);
       
   726     QVERIFY(!(m1 == m3));
       
   727 }
       
   728 
       
   729 // Test 4x3 matrix comparisons.
       
   730 void tst_QMatrixNxN::compare4x3()
       
   731 {
       
   732     QMatrix4x3 m1(uniqueValues4x3);
       
   733     QMatrix4x3 m2(uniqueValues4x3);
       
   734     QMatrix4x3 m3(transposedValues3x4);
       
   735 
       
   736     QVERIFY(m1 == m2);
       
   737     QVERIFY(!(m1 != m2));
       
   738     QVERIFY(m1 != m3);
       
   739     QVERIFY(!(m1 == m3));
       
   740 }
       
   741 
       
   742 // Test matrix 2x2 transpose operations.
       
   743 void tst_QMatrixNxN::transposed2x2()
       
   744 {
       
   745     // Transposing the identity should result in the identity.
       
   746     QMatrix2x2 m1;
       
   747     QMatrix2x2 m2 = m1.transposed();
       
   748     QVERIFY(isIdentity(m2));
       
   749 
       
   750     // Transpose a more interesting matrix that allows us to track
       
   751     // exactly where each source element ends up.
       
   752     QMatrix2x2 m3(uniqueValues2);
       
   753     QMatrix2x2 m4 = m3.transposed();
       
   754     QVERIFY(isSame(m4, transposedValues2));
       
   755 
       
   756     // Transpose in-place, just to check that the compiler is sane.
       
   757     m3 = m3.transposed();
       
   758     QVERIFY(isSame(m3, transposedValues2));
       
   759 }
       
   760 
       
   761 // Test matrix 3x3 transpose operations.
       
   762 void tst_QMatrixNxN::transposed3x3()
       
   763 {
       
   764     // Transposing the identity should result in the identity.
       
   765     QMatrix3x3 m1;
       
   766     QMatrix3x3 m2 = m1.transposed();
       
   767     QVERIFY(isIdentity(m2));
       
   768 
       
   769     // Transpose a more interesting matrix that allows us to track
       
   770     // exactly where each source element ends up.
       
   771     QMatrix3x3 m3(uniqueValues3);
       
   772     QMatrix3x3 m4 = m3.transposed();
       
   773     QVERIFY(isSame(m4, transposedValues3));
       
   774 
       
   775     // Transpose in-place, just to check that the compiler is sane.
       
   776     m3 = m3.transposed();
       
   777     QVERIFY(isSame(m3, transposedValues3));
       
   778 }
       
   779 
       
   780 // Test matrix 4x4 transpose operations.
       
   781 void tst_QMatrixNxN::transposed4x4()
       
   782 {
       
   783     // Transposing the identity should result in the identity.
       
   784     QMatrix4x4 m1;
       
   785     QMatrix4x4 m2 = m1.transposed();
       
   786     QVERIFY(isIdentity(m2));
       
   787 
       
   788     // Transpose a more interesting matrix that allows us to track
       
   789     // exactly where each source element ends up.
       
   790     QMatrix4x4 m3(uniqueValues4);
       
   791     QMatrix4x4 m4 = m3.transposed();
       
   792     QVERIFY(isSame(m4, transposedValues4));
       
   793 
       
   794     // Transpose in-place, just to check that the compiler is sane.
       
   795     m3 = m3.transposed();
       
   796     QVERIFY(isSame(m3, transposedValues4));
       
   797 }
       
   798 
       
   799 // Test matrix 4x3 transpose operations.
       
   800 void tst_QMatrixNxN::transposed4x3()
       
   801 {
       
   802     QMatrix4x3 m3(uniqueValues4x3);
       
   803     QMatrix3x4 m4 = m3.transposed();
       
   804     qreal values[12];
       
   805     m4.toValueArray(values);
       
   806     for (int index = 0; index < 12; ++index)
       
   807         QCOMPARE(values[index], transposedValues3x4[index]);
       
   808 }
       
   809 
       
   810 // Test matrix addition for 2x2 matrices.
       
   811 void tst_QMatrixNxN::add2x2_data()
       
   812 {
       
   813     QTest::addColumn<void *>("m1Values");
       
   814     QTest::addColumn<void *>("m2Values");
       
   815     QTest::addColumn<void *>("m3Values");
       
   816 
       
   817     QTest::newRow("null")
       
   818         << (void *)nullValues2 << (void *)nullValues2 << (void *)nullValues2;
       
   819 
       
   820     QTest::newRow("identity/null")
       
   821         << (void *)identityValues2 << (void *)nullValues2 << (void *)identityValues2;
       
   822 
       
   823     QTest::newRow("identity/identity")
       
   824         << (void *)identityValues2 << (void *)identityValues2 << (void *)doubleIdentity2;
       
   825 
       
   826     static qreal const sumValues[16] =
       
   827         {2.0f, 7.0f,
       
   828          7.0f, 12.0f};
       
   829     QTest::newRow("unique")
       
   830         << (void *)uniqueValues2 << (void *)transposedValues2 << (void *)sumValues;
       
   831 }
       
   832 void tst_QMatrixNxN::add2x2()
       
   833 {
       
   834     QFETCH(void *, m1Values);
       
   835     QFETCH(void *, m2Values);
       
   836     QFETCH(void *, m3Values);
       
   837 
       
   838     QMatrix2x2 m1((const qreal *)m1Values);
       
   839     QMatrix2x2 m2((const qreal *)m2Values);
       
   840 
       
   841     QMatrix2x2 m4(m1);
       
   842     m4 += m2;
       
   843     QVERIFY(isSame(m4, (const qreal *)m3Values));
       
   844 
       
   845     QMatrix2x2 m5;
       
   846     m5 = m1 + m2;
       
   847     QVERIFY(isSame(m5, (const qreal *)m3Values));
       
   848 }
       
   849 
       
   850 // Test matrix addition for 3x3 matrices.
       
   851 void tst_QMatrixNxN::add3x3_data()
       
   852 {
       
   853     QTest::addColumn<void *>("m1Values");
       
   854     QTest::addColumn<void *>("m2Values");
       
   855     QTest::addColumn<void *>("m3Values");
       
   856 
       
   857     QTest::newRow("null")
       
   858         << (void *)nullValues3 << (void *)nullValues3 << (void *)nullValues3;
       
   859 
       
   860     QTest::newRow("identity/null")
       
   861         << (void *)identityValues3 << (void *)nullValues3 << (void *)identityValues3;
       
   862 
       
   863     QTest::newRow("identity/identity")
       
   864         << (void *)identityValues3 << (void *)identityValues3 << (void *)doubleIdentity3;
       
   865 
       
   866     static qreal const sumValues[16] =
       
   867         {2.0f, 7.0f, 12.0f,
       
   868          7.0f, 12.0f, 17.0f,
       
   869          12.0f, 17.0f, 22.0f};
       
   870     QTest::newRow("unique")
       
   871         << (void *)uniqueValues3 << (void *)transposedValues3 << (void *)sumValues;
       
   872 }
       
   873 void tst_QMatrixNxN::add3x3()
       
   874 {
       
   875     QFETCH(void *, m1Values);
       
   876     QFETCH(void *, m2Values);
       
   877     QFETCH(void *, m3Values);
       
   878 
       
   879     QMatrix3x3 m1((const qreal *)m1Values);
       
   880     QMatrix3x3 m2((const qreal *)m2Values);
       
   881 
       
   882     QMatrix3x3 m4(m1);
       
   883     m4 += m2;
       
   884     QVERIFY(isSame(m4, (const qreal *)m3Values));
       
   885 
       
   886     QMatrix3x3 m5;
       
   887     m5 = m1 + m2;
       
   888     QVERIFY(isSame(m5, (const qreal *)m3Values));
       
   889 }
       
   890 
       
   891 // Test matrix addition for 4x4 matrices.
       
   892 void tst_QMatrixNxN::add4x4_data()
       
   893 {
       
   894     QTest::addColumn<void *>("m1Values");
       
   895     QTest::addColumn<void *>("m2Values");
       
   896     QTest::addColumn<void *>("m3Values");
       
   897 
       
   898     QTest::newRow("null")
       
   899         << (void *)nullValues4 << (void *)nullValues4 << (void *)nullValues4;
       
   900 
       
   901     QTest::newRow("identity/null")
       
   902         << (void *)identityValues4 << (void *)nullValues4 << (void *)identityValues4;
       
   903 
       
   904     QTest::newRow("identity/identity")
       
   905         << (void *)identityValues4 << (void *)identityValues4 << (void *)doubleIdentity4;
       
   906 
       
   907     static qreal const sumValues[16] =
       
   908         {2.0f, 7.0f, 12.0f, 17.0f,
       
   909          7.0f, 12.0f, 17.0f, 22.0f,
       
   910          12.0f, 17.0f, 22.0f, 27.0f,
       
   911          17.0f, 22.0f, 27.0f, 32.0f};
       
   912     QTest::newRow("unique")
       
   913         << (void *)uniqueValues4 << (void *)transposedValues4 << (void *)sumValues;
       
   914 }
       
   915 void tst_QMatrixNxN::add4x4()
       
   916 {
       
   917     QFETCH(void *, m1Values);
       
   918     QFETCH(void *, m2Values);
       
   919     QFETCH(void *, m3Values);
       
   920 
       
   921     QMatrix4x4 m1((const qreal *)m1Values);
       
   922     QMatrix4x4 m2((const qreal *)m2Values);
       
   923 
       
   924     QMatrix4x4 m4(m1);
       
   925     m4 += m2;
       
   926     QVERIFY(isSame(m4, (const qreal *)m3Values));
       
   927 
       
   928     QMatrix4x4 m5;
       
   929     m5 = m1 + m2;
       
   930     QVERIFY(isSame(m5, (const qreal *)m3Values));
       
   931 }
       
   932 
       
   933 // Test matrix addition for 4x3 matrices.
       
   934 void tst_QMatrixNxN::add4x3_data()
       
   935 {
       
   936     QTest::addColumn<void *>("m1Values");
       
   937     QTest::addColumn<void *>("m2Values");
       
   938     QTest::addColumn<void *>("m3Values");
       
   939 
       
   940     QTest::newRow("null")
       
   941         << (void *)nullValues4x3 << (void *)nullValues4x3 << (void *)nullValues4x3;
       
   942 
       
   943     QTest::newRow("identity/null")
       
   944         << (void *)identityValues4x3 << (void *)nullValues4x3 << (void *)identityValues4x3;
       
   945 
       
   946     QTest::newRow("identity/identity")
       
   947         << (void *)identityValues4x3 << (void *)identityValues4x3 << (void *)doubleIdentity4x3;
       
   948 
       
   949     static qreal const sumValues[16] =
       
   950         {2.0f, 7.0f, 12.0f, 6.0f,
       
   951          11.0f, 16.0f, 10.0f, 15.0f,
       
   952          20.0f, 14.0f, 19.0f, 24.0f};
       
   953     QTest::newRow("unique")
       
   954         << (void *)uniqueValues4x3 << (void *)transposedValues3x4 << (void *)sumValues;
       
   955 }
       
   956 void tst_QMatrixNxN::add4x3()
       
   957 {
       
   958     QFETCH(void *, m1Values);
       
   959     QFETCH(void *, m2Values);
       
   960     QFETCH(void *, m3Values);
       
   961 
       
   962     QMatrix4x3 m1((const qreal *)m1Values);
       
   963     QMatrix4x3 m2((const qreal *)m2Values);
       
   964 
       
   965     QMatrix4x3 m4(m1);
       
   966     m4 += m2;
       
   967     QVERIFY(isSame(m4, (const qreal *)m3Values));
       
   968 
       
   969     QMatrix4x3 m5;
       
   970     m5 = m1 + m2;
       
   971     QVERIFY(isSame(m5, (const qreal *)m3Values));
       
   972 }
       
   973 
       
   974 // Test matrix subtraction for 2x2 matrices.
       
   975 void tst_QMatrixNxN::subtract2x2_data()
       
   976 {
       
   977     // Use the same test cases as the add test.
       
   978     add2x2_data();
       
   979 }
       
   980 void tst_QMatrixNxN::subtract2x2()
       
   981 {
       
   982     QFETCH(void *, m1Values);
       
   983     QFETCH(void *, m2Values);
       
   984     QFETCH(void *, m3Values);
       
   985 
       
   986     QMatrix2x2 m1((const qreal *)m1Values);
       
   987     QMatrix2x2 m2((const qreal *)m2Values);
       
   988     QMatrix2x2 m3((const qreal *)m3Values);
       
   989 
       
   990     QMatrix2x2 m4(m3);
       
   991     m4 -= m1;
       
   992     QVERIFY(isSame(m4, (const qreal *)m2Values));
       
   993 
       
   994     QMatrix2x2 m5;
       
   995     m5 = m3 - m1;
       
   996     QVERIFY(isSame(m5, (const qreal *)m2Values));
       
   997 
       
   998     QMatrix2x2 m6(m3);
       
   999     m6 -= m2;
       
  1000     QVERIFY(isSame(m6, (const qreal *)m1Values));
       
  1001 
       
  1002     QMatrix2x2 m7;
       
  1003     m7 = m3 - m2;
       
  1004     QVERIFY(isSame(m7, (const qreal *)m1Values));
       
  1005 }
       
  1006 
       
  1007 // Test matrix subtraction for 3x3 matrices.
       
  1008 void tst_QMatrixNxN::subtract3x3_data()
       
  1009 {
       
  1010     // Use the same test cases as the add test.
       
  1011     add3x3_data();
       
  1012 }
       
  1013 void tst_QMatrixNxN::subtract3x3()
       
  1014 {
       
  1015     QFETCH(void *, m1Values);
       
  1016     QFETCH(void *, m2Values);
       
  1017     QFETCH(void *, m3Values);
       
  1018 
       
  1019     QMatrix3x3 m1((const qreal *)m1Values);
       
  1020     QMatrix3x3 m2((const qreal *)m2Values);
       
  1021     QMatrix3x3 m3((const qreal *)m3Values);
       
  1022 
       
  1023     QMatrix3x3 m4(m3);
       
  1024     m4 -= m1;
       
  1025     QVERIFY(isSame(m4, (const qreal *)m2Values));
       
  1026 
       
  1027     QMatrix3x3 m5;
       
  1028     m5 = m3 - m1;
       
  1029     QVERIFY(isSame(m5, (const qreal *)m2Values));
       
  1030 
       
  1031     QMatrix3x3 m6(m3);
       
  1032     m6 -= m2;
       
  1033     QVERIFY(isSame(m6, (const qreal *)m1Values));
       
  1034 
       
  1035     QMatrix3x3 m7;
       
  1036     m7 = m3 - m2;
       
  1037     QVERIFY(isSame(m7, (const qreal *)m1Values));
       
  1038 }
       
  1039 
       
  1040 // Test matrix subtraction for 4x4 matrices.
       
  1041 void tst_QMatrixNxN::subtract4x4_data()
       
  1042 {
       
  1043     // Use the same test cases as the add test.
       
  1044     add4x4_data();
       
  1045 }
       
  1046 void tst_QMatrixNxN::subtract4x4()
       
  1047 {
       
  1048     QFETCH(void *, m1Values);
       
  1049     QFETCH(void *, m2Values);
       
  1050     QFETCH(void *, m3Values);
       
  1051 
       
  1052     QMatrix4x4 m1((const qreal *)m1Values);
       
  1053     QMatrix4x4 m2((const qreal *)m2Values);
       
  1054     QMatrix4x4 m3((const qreal *)m3Values);
       
  1055 
       
  1056     QMatrix4x4 m4(m3);
       
  1057     m4 -= m1;
       
  1058     QVERIFY(isSame(m4, (const qreal *)m2Values));
       
  1059 
       
  1060     QMatrix4x4 m5;
       
  1061     m5 = m3 - m1;
       
  1062     QVERIFY(isSame(m5, (const qreal *)m2Values));
       
  1063 
       
  1064     QMatrix4x4 m6(m3);
       
  1065     m6 -= m2;
       
  1066     QVERIFY(isSame(m6, (const qreal *)m1Values));
       
  1067 
       
  1068     QMatrix4x4 m7;
       
  1069     m7 = m3 - m2;
       
  1070     QVERIFY(isSame(m7, (const qreal *)m1Values));
       
  1071 }
       
  1072 
       
  1073 // Test matrix subtraction for 4x3 matrices.
       
  1074 void tst_QMatrixNxN::subtract4x3_data()
       
  1075 {
       
  1076     // Use the same test cases as the add test.
       
  1077     add4x3_data();
       
  1078 }
       
  1079 void tst_QMatrixNxN::subtract4x3()
       
  1080 {
       
  1081     QFETCH(void *, m1Values);
       
  1082     QFETCH(void *, m2Values);
       
  1083     QFETCH(void *, m3Values);
       
  1084 
       
  1085     QMatrix4x3 m1((const qreal *)m1Values);
       
  1086     QMatrix4x3 m2((const qreal *)m2Values);
       
  1087     QMatrix4x3 m3((const qreal *)m3Values);
       
  1088 
       
  1089     QMatrix4x3 m4(m3);
       
  1090     m4 -= m1;
       
  1091     QVERIFY(isSame(m4, (const qreal *)m2Values));
       
  1092 
       
  1093     QMatrix4x3 m5;
       
  1094     m5 = m3 - m1;
       
  1095     QVERIFY(isSame(m5, (const qreal *)m2Values));
       
  1096 
       
  1097     QMatrix4x3 m6(m3);
       
  1098     m6 -= m2;
       
  1099     QVERIFY(isSame(m6, (const qreal *)m1Values));
       
  1100 
       
  1101     QMatrix4x3 m7;
       
  1102     m7 = m3 - m2;
       
  1103     QVERIFY(isSame(m7, (const qreal *)m1Values));
       
  1104 }
       
  1105 
       
  1106 // Test matrix multiplication for 2x2 matrices.
       
  1107 void tst_QMatrixNxN::multiply2x2_data()
       
  1108 {
       
  1109     QTest::addColumn<void *>("m1Values");
       
  1110     QTest::addColumn<void *>("m2Values");
       
  1111     QTest::addColumn<void *>("m3Values");
       
  1112 
       
  1113     QTest::newRow("null")
       
  1114         << (void *)nullValues2 << (void *)nullValues2 << (void *)nullValues2;
       
  1115 
       
  1116     QTest::newRow("null/unique")
       
  1117         << (void *)nullValues2 << (void *)uniqueValues2 << (void *)nullValues2;
       
  1118 
       
  1119     QTest::newRow("unique/null")
       
  1120         << (void *)uniqueValues2 << (void *)nullValues2 << (void *)nullValues2;
       
  1121 
       
  1122     QTest::newRow("unique/identity")
       
  1123         << (void *)uniqueValues2 << (void *)identityValues2 << (void *)uniqueValues2;
       
  1124 
       
  1125     QTest::newRow("identity/unique")
       
  1126         << (void *)identityValues2 << (void *)uniqueValues2 << (void *)uniqueValues2;
       
  1127 
       
  1128     static qreal uniqueResult[4];
       
  1129     for (int row = 0; row < 2; ++row) {
       
  1130         for (int col = 0; col < 2; ++col) {
       
  1131             qreal sum = 0.0f;
       
  1132             for (int j = 0; j < 2; ++j)
       
  1133                 sum += uniqueValues2[row * 2 + j] * transposedValues2[j * 2 + col];
       
  1134             uniqueResult[row * 2 + col] = sum;
       
  1135         }
       
  1136     }
       
  1137 
       
  1138     QTest::newRow("unique/transposed")
       
  1139         << (void *)uniqueValues2 << (void *)transposedValues2 << (void *)uniqueResult;
       
  1140 }
       
  1141 void tst_QMatrixNxN::multiply2x2()
       
  1142 {
       
  1143     QFETCH(void *, m1Values);
       
  1144     QFETCH(void *, m2Values);
       
  1145     QFETCH(void *, m3Values);
       
  1146 
       
  1147     QMatrix2x2 m1((const qreal *)m1Values);
       
  1148     QMatrix2x2 m2((const qreal *)m2Values);
       
  1149 
       
  1150     QMatrix2x2 m5;
       
  1151     m5 = m1 * m2;
       
  1152     QVERIFY(isSame(m5, (const qreal *)m3Values));
       
  1153 }
       
  1154 
       
  1155 // Test matrix multiplication for 3x3 matrices.
       
  1156 void tst_QMatrixNxN::multiply3x3_data()
       
  1157 {
       
  1158     QTest::addColumn<void *>("m1Values");
       
  1159     QTest::addColumn<void *>("m2Values");
       
  1160     QTest::addColumn<void *>("m3Values");
       
  1161 
       
  1162     QTest::newRow("null")
       
  1163         << (void *)nullValues3 << (void *)nullValues3 << (void *)nullValues3;
       
  1164 
       
  1165     QTest::newRow("null/unique")
       
  1166         << (void *)nullValues3 << (void *)uniqueValues3 << (void *)nullValues3;
       
  1167 
       
  1168     QTest::newRow("unique/null")
       
  1169         << (void *)uniqueValues3 << (void *)nullValues3 << (void *)nullValues3;
       
  1170 
       
  1171     QTest::newRow("unique/identity")
       
  1172         << (void *)uniqueValues3 << (void *)identityValues3 << (void *)uniqueValues3;
       
  1173 
       
  1174     QTest::newRow("identity/unique")
       
  1175         << (void *)identityValues3 << (void *)uniqueValues3 << (void *)uniqueValues3;
       
  1176 
       
  1177     static qreal uniqueResult[9];
       
  1178     for (int row = 0; row < 3; ++row) {
       
  1179         for (int col = 0; col < 3; ++col) {
       
  1180             qreal sum = 0.0f;
       
  1181             for (int j = 0; j < 3; ++j)
       
  1182                 sum += uniqueValues3[row * 3 + j] * transposedValues3[j * 3 + col];
       
  1183             uniqueResult[row * 3 + col] = sum;
       
  1184         }
       
  1185     }
       
  1186 
       
  1187     QTest::newRow("unique/transposed")
       
  1188         << (void *)uniqueValues3 << (void *)transposedValues3 << (void *)uniqueResult;
       
  1189 }
       
  1190 void tst_QMatrixNxN::multiply3x3()
       
  1191 {
       
  1192     QFETCH(void *, m1Values);
       
  1193     QFETCH(void *, m2Values);
       
  1194     QFETCH(void *, m3Values);
       
  1195 
       
  1196     QMatrix3x3 m1((const qreal *)m1Values);
       
  1197     QMatrix3x3 m2((const qreal *)m2Values);
       
  1198 
       
  1199     QMatrix3x3 m5;
       
  1200     m5 = m1 * m2;
       
  1201     QVERIFY(isSame(m5, (const qreal *)m3Values));
       
  1202 }
       
  1203 
       
  1204 // Test matrix multiplication for 4x4 matrices.
       
  1205 void tst_QMatrixNxN::multiply4x4_data()
       
  1206 {
       
  1207     QTest::addColumn<void *>("m1Values");
       
  1208     QTest::addColumn<void *>("m2Values");
       
  1209     QTest::addColumn<void *>("m3Values");
       
  1210 
       
  1211     QTest::newRow("null")
       
  1212         << (void *)nullValues4 << (void *)nullValues4 << (void *)nullValues4;
       
  1213 
       
  1214     QTest::newRow("null/unique")
       
  1215         << (void *)nullValues4 << (void *)uniqueValues4 << (void *)nullValues4;
       
  1216 
       
  1217     QTest::newRow("unique/null")
       
  1218         << (void *)uniqueValues4 << (void *)nullValues4 << (void *)nullValues4;
       
  1219 
       
  1220     QTest::newRow("unique/identity")
       
  1221         << (void *)uniqueValues4 << (void *)identityValues4 << (void *)uniqueValues4;
       
  1222 
       
  1223     QTest::newRow("identity/unique")
       
  1224         << (void *)identityValues4 << (void *)uniqueValues4 << (void *)uniqueValues4;
       
  1225 
       
  1226     static qreal uniqueResult[16];
       
  1227     for (int row = 0; row < 4; ++row) {
       
  1228         for (int col = 0; col < 4; ++col) {
       
  1229             qreal sum = 0.0f;
       
  1230             for (int j = 0; j < 4; ++j)
       
  1231                 sum += uniqueValues4[row * 4 + j] * transposedValues4[j * 4 + col];
       
  1232             uniqueResult[row * 4 + col] = sum;
       
  1233         }
       
  1234     }
       
  1235 
       
  1236     QTest::newRow("unique/transposed")
       
  1237         << (void *)uniqueValues4 << (void *)transposedValues4 << (void *)uniqueResult;
       
  1238 }
       
  1239 void tst_QMatrixNxN::multiply4x4()
       
  1240 {
       
  1241     QFETCH(void *, m1Values);
       
  1242     QFETCH(void *, m2Values);
       
  1243     QFETCH(void *, m3Values);
       
  1244 
       
  1245     QMatrix4x4 m1((const qreal *)m1Values);
       
  1246     QMatrix4x4 m2((const qreal *)m2Values);
       
  1247 
       
  1248     QMatrix4x4 m4;
       
  1249     m4 = m1;
       
  1250     m4 *= m2;
       
  1251     QVERIFY(isSame(m4, (const qreal *)m3Values));
       
  1252 
       
  1253     QMatrix4x4 m5;
       
  1254     m5 = m1 * m2;
       
  1255     QVERIFY(isSame(m5, (const qreal *)m3Values));
       
  1256 }
       
  1257 
       
  1258 // Test matrix multiplication for 4x3 matrices.
       
  1259 void tst_QMatrixNxN::multiply4x3_data()
       
  1260 {
       
  1261     QTest::addColumn<void *>("m1Values");
       
  1262     QTest::addColumn<void *>("m2Values");
       
  1263     QTest::addColumn<void *>("m3Values");
       
  1264 
       
  1265     QTest::newRow("null")
       
  1266         << (void *)nullValues4x3 << (void *)nullValues4x3 << (void *)nullValues3;
       
  1267 
       
  1268     QTest::newRow("null/unique")
       
  1269         << (void *)nullValues4x3 << (void *)uniqueValues4x3 << (void *)nullValues3;
       
  1270 
       
  1271     QTest::newRow("unique/null")
       
  1272         << (void *)uniqueValues4x3 << (void *)nullValues4x3 << (void *)nullValues3;
       
  1273 
       
  1274     static qreal uniqueResult[9];
       
  1275     for (int row = 0; row < 3; ++row) {
       
  1276         for (int col = 0; col < 3; ++col) {
       
  1277             qreal sum = 0.0f;
       
  1278             for (int j = 0; j < 4; ++j)
       
  1279                 sum += uniqueValues4x3[row * 4 + j] * transposedValues3x4[j * 3 + col];
       
  1280             uniqueResult[row * 3 + col] = sum;
       
  1281         }
       
  1282     }
       
  1283 
       
  1284     QTest::newRow("unique/transposed")
       
  1285         << (void *)uniqueValues4x3 << (void *)transposedValues3x4 << (void *)uniqueResult;
       
  1286 }
       
  1287 void tst_QMatrixNxN::multiply4x3()
       
  1288 {
       
  1289     QFETCH(void *, m1Values);
       
  1290     QFETCH(void *, m2Values);
       
  1291     QFETCH(void *, m3Values);
       
  1292 
       
  1293     QMatrix4x3 m1((const qreal *)m1Values);
       
  1294     QMatrix3x4 m2((const qreal *)m2Values);
       
  1295 
       
  1296     QGenericMatrix<3, 3, qreal> m4;
       
  1297     m4 = m1 * m2;
       
  1298     qreal values[9];
       
  1299     m4.toValueArray(values);
       
  1300     for (int index = 0; index < 9; ++index)
       
  1301         QCOMPARE(values[index], ((const qreal *)m3Values)[index]);
       
  1302 }
       
  1303 
       
  1304 // Test matrix multiplication by a factor for 2x2 matrices.
       
  1305 void tst_QMatrixNxN::multiplyFactor2x2_data()
       
  1306 {
       
  1307     QTest::addColumn<void *>("m1Values");
       
  1308     QTest::addColumn<qreal>("factor");
       
  1309     QTest::addColumn<void *>("m2Values");
       
  1310 
       
  1311     QTest::newRow("null")
       
  1312         << (void *)nullValues2 << (qreal)1.0f << (void *)nullValues2;
       
  1313 
       
  1314     QTest::newRow("double identity")
       
  1315         << (void *)identityValues2 << (qreal)2.0f << (void *)doubleIdentity2;
       
  1316 
       
  1317     static qreal const values[16] =
       
  1318         {1.0f, 2.0f,
       
  1319          5.0f, 6.0f};
       
  1320     static qreal const doubleValues[16] =
       
  1321         {2.0f, 4.0f,
       
  1322          10.0f, 12.0f};
       
  1323     static qreal const negDoubleValues[16] =
       
  1324         {-2.0f, -4.0f,
       
  1325          -10.0f, -12.0f};
       
  1326 
       
  1327     QTest::newRow("unique")
       
  1328         << (void *)values << (qreal)2.0f << (void *)doubleValues;
       
  1329 
       
  1330     QTest::newRow("neg")
       
  1331         << (void *)values << (qreal)-2.0f << (void *)negDoubleValues;
       
  1332 
       
  1333     QTest::newRow("zero")
       
  1334         << (void *)values << (qreal)0.0f << (void *)nullValues4;
       
  1335 }
       
  1336 void tst_QMatrixNxN::multiplyFactor2x2()
       
  1337 {
       
  1338     QFETCH(void *, m1Values);
       
  1339     QFETCH(qreal, factor);
       
  1340     QFETCH(void *, m2Values);
       
  1341 
       
  1342     QMatrix2x2 m1((const qreal *)m1Values);
       
  1343 
       
  1344     QMatrix2x2 m3;
       
  1345     m3 = m1;
       
  1346     m3 *= factor;
       
  1347     QVERIFY(isSame(m3, (const qreal *)m2Values));
       
  1348 
       
  1349     QMatrix2x2 m4;
       
  1350     m4 = m1 * factor;
       
  1351     QVERIFY(isSame(m4, (const qreal *)m2Values));
       
  1352 
       
  1353     QMatrix2x2 m5;
       
  1354     m5 = factor * m1;
       
  1355     QVERIFY(isSame(m5, (const qreal *)m2Values));
       
  1356 }
       
  1357 
       
  1358 // Test matrix multiplication by a factor for 3x3 matrices.
       
  1359 void tst_QMatrixNxN::multiplyFactor3x3_data()
       
  1360 {
       
  1361     QTest::addColumn<void *>("m1Values");
       
  1362     QTest::addColumn<qreal>("factor");
       
  1363     QTest::addColumn<void *>("m2Values");
       
  1364 
       
  1365     QTest::newRow("null")
       
  1366         << (void *)nullValues3 << (qreal)1.0f << (void *)nullValues3;
       
  1367 
       
  1368     QTest::newRow("double identity")
       
  1369         << (void *)identityValues3 << (qreal)2.0f << (void *)doubleIdentity3;
       
  1370 
       
  1371     static qreal const values[16] =
       
  1372         {1.0f, 2.0f, 3.0f,
       
  1373          5.0f, 6.0f, 7.0f,
       
  1374          9.0f, 10.0f, 11.0f};
       
  1375     static qreal const doubleValues[16] =
       
  1376         {2.0f, 4.0f, 6.0f,
       
  1377          10.0f, 12.0f, 14.0f,
       
  1378          18.0f, 20.0f, 22.0f};
       
  1379     static qreal const negDoubleValues[16] =
       
  1380         {-2.0f, -4.0f, -6.0f,
       
  1381          -10.0f, -12.0f, -14.0f,
       
  1382          -18.0f, -20.0f, -22.0f};
       
  1383 
       
  1384     QTest::newRow("unique")
       
  1385         << (void *)values << (qreal)2.0f << (void *)doubleValues;
       
  1386 
       
  1387     QTest::newRow("neg")
       
  1388         << (void *)values << (qreal)-2.0f << (void *)negDoubleValues;
       
  1389 
       
  1390     QTest::newRow("zero")
       
  1391         << (void *)values << (qreal)0.0f << (void *)nullValues4;
       
  1392 }
       
  1393 void tst_QMatrixNxN::multiplyFactor3x3()
       
  1394 {
       
  1395     QFETCH(void *, m1Values);
       
  1396     QFETCH(qreal, factor);
       
  1397     QFETCH(void *, m2Values);
       
  1398 
       
  1399     QMatrix3x3 m1((const qreal *)m1Values);
       
  1400 
       
  1401     QMatrix3x3 m3;
       
  1402     m3 = m1;
       
  1403     m3 *= factor;
       
  1404     QVERIFY(isSame(m3, (const qreal *)m2Values));
       
  1405 
       
  1406     QMatrix3x3 m4;
       
  1407     m4 = m1 * factor;
       
  1408     QVERIFY(isSame(m4, (const qreal *)m2Values));
       
  1409 
       
  1410     QMatrix3x3 m5;
       
  1411     m5 = factor * m1;
       
  1412     QVERIFY(isSame(m5, (const qreal *)m2Values));
       
  1413 }
       
  1414 
       
  1415 // Test matrix multiplication by a factor for 4x4 matrices.
       
  1416 void tst_QMatrixNxN::multiplyFactor4x4_data()
       
  1417 {
       
  1418     QTest::addColumn<void *>("m1Values");
       
  1419     QTest::addColumn<qreal>("factor");
       
  1420     QTest::addColumn<void *>("m2Values");
       
  1421 
       
  1422     QTest::newRow("null")
       
  1423         << (void *)nullValues4 << (qreal)1.0f << (void *)nullValues4;
       
  1424 
       
  1425     QTest::newRow("double identity")
       
  1426         << (void *)identityValues4 << (qreal)2.0f << (void *)doubleIdentity4;
       
  1427 
       
  1428     static qreal const values[16] =
       
  1429         {1.0f, 2.0f, 3.0f, 4.0f,
       
  1430          5.0f, 6.0f, 7.0f, 8.0f,
       
  1431          9.0f, 10.0f, 11.0f, 12.0f,
       
  1432          13.0f, 14.0f, 15.0f, 16.0f};
       
  1433     static qreal const doubleValues[16] =
       
  1434         {2.0f, 4.0f, 6.0f, 8.0f,
       
  1435          10.0f, 12.0f, 14.0f, 16.0f,
       
  1436          18.0f, 20.0f, 22.0f, 24.0f,
       
  1437          26.0f, 28.0f, 30.0f, 32.0f};
       
  1438     static qreal const negDoubleValues[16] =
       
  1439         {-2.0f, -4.0f, -6.0f, -8.0f,
       
  1440          -10.0f, -12.0f, -14.0f, -16.0f,
       
  1441          -18.0f, -20.0f, -22.0f, -24.0f,
       
  1442          -26.0f, -28.0f, -30.0f, -32.0f};
       
  1443 
       
  1444     QTest::newRow("unique")
       
  1445         << (void *)values << (qreal)2.0f << (void *)doubleValues;
       
  1446 
       
  1447     QTest::newRow("neg")
       
  1448         << (void *)values << (qreal)-2.0f << (void *)negDoubleValues;
       
  1449 
       
  1450     QTest::newRow("zero")
       
  1451         << (void *)values << (qreal)0.0f << (void *)nullValues4;
       
  1452 }
       
  1453 void tst_QMatrixNxN::multiplyFactor4x4()
       
  1454 {
       
  1455     QFETCH(void *, m1Values);
       
  1456     QFETCH(qreal, factor);
       
  1457     QFETCH(void *, m2Values);
       
  1458 
       
  1459     QMatrix4x4 m1((const qreal *)m1Values);
       
  1460 
       
  1461     QMatrix4x4 m3;
       
  1462     m3 = m1;
       
  1463     m3 *= factor;
       
  1464     QVERIFY(isSame(m3, (const qreal *)m2Values));
       
  1465 
       
  1466     QMatrix4x4 m4;
       
  1467     m4 = m1 * factor;
       
  1468     QVERIFY(isSame(m4, (const qreal *)m2Values));
       
  1469 
       
  1470     QMatrix4x4 m5;
       
  1471     m5 = factor * m1;
       
  1472     QVERIFY(isSame(m5, (const qreal *)m2Values));
       
  1473 }
       
  1474 
       
  1475 // Test matrix multiplication by a factor for 4x3 matrices.
       
  1476 void tst_QMatrixNxN::multiplyFactor4x3_data()
       
  1477 {
       
  1478     QTest::addColumn<void *>("m1Values");
       
  1479     QTest::addColumn<qreal>("factor");
       
  1480     QTest::addColumn<void *>("m2Values");
       
  1481 
       
  1482     QTest::newRow("null")
       
  1483         << (void *)nullValues4x3 << (qreal)1.0f << (void *)nullValues4x3;
       
  1484 
       
  1485     QTest::newRow("double identity")
       
  1486         << (void *)identityValues4x3 << (qreal)2.0f << (void *)doubleIdentity4x3;
       
  1487 
       
  1488     static qreal const values[12] =
       
  1489         {1.0f, 2.0f, 3.0f, 4.0f,
       
  1490          5.0f, 6.0f, 7.0f, 8.0f,
       
  1491          9.0f, 10.0f, 11.0f, 12.0f};
       
  1492     static qreal const doubleValues[12] =
       
  1493         {2.0f, 4.0f, 6.0f, 8.0f,
       
  1494          10.0f, 12.0f, 14.0f, 16.0f,
       
  1495          18.0f, 20.0f, 22.0f, 24.0f};
       
  1496     static qreal const negDoubleValues[12] =
       
  1497         {-2.0f, -4.0f, -6.0f, -8.0f,
       
  1498          -10.0f, -12.0f, -14.0f, -16.0f,
       
  1499          -18.0f, -20.0f, -22.0f, -24.0f};
       
  1500 
       
  1501     QTest::newRow("unique")
       
  1502         << (void *)values << (qreal)2.0f << (void *)doubleValues;
       
  1503 
       
  1504     QTest::newRow("neg")
       
  1505         << (void *)values << (qreal)-2.0f << (void *)negDoubleValues;
       
  1506 
       
  1507     QTest::newRow("zero")
       
  1508         << (void *)values << (qreal)0.0f << (void *)nullValues4x3;
       
  1509 }
       
  1510 void tst_QMatrixNxN::multiplyFactor4x3()
       
  1511 {
       
  1512     QFETCH(void *, m1Values);
       
  1513     QFETCH(qreal, factor);
       
  1514     QFETCH(void *, m2Values);
       
  1515 
       
  1516     QMatrix4x3 m1((const qreal *)m1Values);
       
  1517 
       
  1518     QMatrix4x3 m3;
       
  1519     m3 = m1;
       
  1520     m3 *= factor;
       
  1521     QVERIFY(isSame(m3, (const qreal *)m2Values));
       
  1522 
       
  1523     QMatrix4x3 m4;
       
  1524     m4 = m1 * factor;
       
  1525     QVERIFY(isSame(m4, (const qreal *)m2Values));
       
  1526 
       
  1527     QMatrix4x3 m5;
       
  1528     m5 = factor * m1;
       
  1529     QVERIFY(isSame(m5, (const qreal *)m2Values));
       
  1530 }
       
  1531 
       
  1532 // Test matrix division by a factor for 2x2 matrices.
       
  1533 void tst_QMatrixNxN::divideFactor2x2_data()
       
  1534 {
       
  1535     // Use the same test cases as the multiplyFactor test.
       
  1536     multiplyFactor2x2_data();
       
  1537 }
       
  1538 void tst_QMatrixNxN::divideFactor2x2()
       
  1539 {
       
  1540     QFETCH(void *, m1Values);
       
  1541     QFETCH(qreal, factor);
       
  1542     QFETCH(void *, m2Values);
       
  1543 
       
  1544     if (factor == 0.0f)
       
  1545         return;
       
  1546 
       
  1547     QMatrix2x2 m2((const qreal *)m2Values);
       
  1548 
       
  1549     QMatrix2x2 m3;
       
  1550     m3 = m2;
       
  1551     m3 /= factor;
       
  1552     QVERIFY(isSame(m3, (const qreal *)m1Values));
       
  1553 
       
  1554     QMatrix2x2 m4;
       
  1555     m4 = m2 / factor;
       
  1556     QVERIFY(isSame(m4, (const qreal *)m1Values));
       
  1557 }
       
  1558 
       
  1559 // Test matrix division by a factor for 3x3 matrices.
       
  1560 void tst_QMatrixNxN::divideFactor3x3_data()
       
  1561 {
       
  1562     // Use the same test cases as the multiplyFactor test.
       
  1563     multiplyFactor3x3_data();
       
  1564 }
       
  1565 void tst_QMatrixNxN::divideFactor3x3()
       
  1566 {
       
  1567     QFETCH(void *, m1Values);
       
  1568     QFETCH(qreal, factor);
       
  1569     QFETCH(void *, m2Values);
       
  1570 
       
  1571     if (factor == 0.0f)
       
  1572         return;
       
  1573 
       
  1574     QMatrix3x3 m2((const qreal *)m2Values);
       
  1575 
       
  1576     QMatrix3x3 m3;
       
  1577     m3 = m2;
       
  1578     m3 /= factor;
       
  1579     QVERIFY(isSame(m3, (const qreal *)m1Values));
       
  1580 
       
  1581     QMatrix3x3 m4;
       
  1582     m4 = m2 / factor;
       
  1583     QVERIFY(isSame(m4, (const qreal *)m1Values));
       
  1584 }
       
  1585 
       
  1586 // Test matrix division by a factor for 4x4 matrices.
       
  1587 void tst_QMatrixNxN::divideFactor4x4_data()
       
  1588 {
       
  1589     // Use the same test cases as the multiplyFactor test.
       
  1590     multiplyFactor4x4_data();
       
  1591 }
       
  1592 void tst_QMatrixNxN::divideFactor4x4()
       
  1593 {
       
  1594     QFETCH(void *, m1Values);
       
  1595     QFETCH(qreal, factor);
       
  1596     QFETCH(void *, m2Values);
       
  1597 
       
  1598     if (factor == 0.0f)
       
  1599         return;
       
  1600 
       
  1601     QMatrix4x4 m2((const qreal *)m2Values);
       
  1602 
       
  1603     QMatrix4x4 m3;
       
  1604     m3 = m2;
       
  1605     m3 /= factor;
       
  1606     QVERIFY(isSame(m3, (const qreal *)m1Values));
       
  1607 
       
  1608     QMatrix4x4 m4;
       
  1609     m4 = m2 / factor;
       
  1610     QVERIFY(isSame(m4, (const qreal *)m1Values));
       
  1611 }
       
  1612 
       
  1613 // Test matrix division by a factor for 4x3 matrices.
       
  1614 void tst_QMatrixNxN::divideFactor4x3_data()
       
  1615 {
       
  1616     // Use the same test cases as the multiplyFactor test.
       
  1617     multiplyFactor4x3_data();
       
  1618 }
       
  1619 void tst_QMatrixNxN::divideFactor4x3()
       
  1620 {
       
  1621     QFETCH(void *, m1Values);
       
  1622     QFETCH(qreal, factor);
       
  1623     QFETCH(void *, m2Values);
       
  1624 
       
  1625     if (factor == 0.0f)
       
  1626         return;
       
  1627 
       
  1628     QMatrix4x3 m2((const qreal *)m2Values);
       
  1629 
       
  1630     QMatrix4x3 m3;
       
  1631     m3 = m2;
       
  1632     m3 /= factor;
       
  1633     QVERIFY(isSame(m3, (const qreal *)m1Values));
       
  1634 
       
  1635     QMatrix4x3 m4;
       
  1636     m4 = m2 / factor;
       
  1637     QVERIFY(isSame(m4, (const qreal *)m1Values));
       
  1638 }
       
  1639 
       
  1640 // Test matrix negation for 2x2 matrices.
       
  1641 void tst_QMatrixNxN::negate2x2_data()
       
  1642 {
       
  1643     // Use the same test cases as the multiplyFactor test.
       
  1644     multiplyFactor2x2_data();
       
  1645 }
       
  1646 void tst_QMatrixNxN::negate2x2()
       
  1647 {
       
  1648     QFETCH(void *, m1Values);
       
  1649 
       
  1650     const qreal *values = (const qreal *)m1Values;
       
  1651 
       
  1652     QMatrix2x2 m1(values);
       
  1653 
       
  1654     qreal negated[4];
       
  1655     for (int index = 0; index < 4; ++index)
       
  1656         negated[index] = -values[index];
       
  1657 
       
  1658     QMatrix2x2 m2;
       
  1659     m2 = -m1;
       
  1660     QVERIFY(isSame(m2, negated));
       
  1661 }
       
  1662 
       
  1663 // Test matrix negation for 3x3 matrices.
       
  1664 void tst_QMatrixNxN::negate3x3_data()
       
  1665 {
       
  1666     // Use the same test cases as the multiplyFactor test.
       
  1667     multiplyFactor3x3_data();
       
  1668 }
       
  1669 void tst_QMatrixNxN::negate3x3()
       
  1670 {
       
  1671     QFETCH(void *, m1Values);
       
  1672 
       
  1673     const qreal *values = (const qreal *)m1Values;
       
  1674 
       
  1675     QMatrix3x3 m1(values);
       
  1676 
       
  1677     qreal negated[9];
       
  1678     for (int index = 0; index < 9; ++index)
       
  1679         negated[index] = -values[index];
       
  1680 
       
  1681     QMatrix3x3 m2;
       
  1682     m2 = -m1;
       
  1683     QVERIFY(isSame(m2, negated));
       
  1684 }
       
  1685 
       
  1686 // Test matrix negation for 4x4 matrices.
       
  1687 void tst_QMatrixNxN::negate4x4_data()
       
  1688 {
       
  1689     // Use the same test cases as the multiplyFactor test.
       
  1690     multiplyFactor4x4_data();
       
  1691 }
       
  1692 void tst_QMatrixNxN::negate4x4()
       
  1693 {
       
  1694     QFETCH(void *, m1Values);
       
  1695 
       
  1696     const qreal *values = (const qreal *)m1Values;
       
  1697 
       
  1698     QMatrix4x4 m1(values);
       
  1699 
       
  1700     qreal negated[16];
       
  1701     for (int index = 0; index < 16; ++index)
       
  1702         negated[index] = -values[index];
       
  1703 
       
  1704     QMatrix4x4 m2;
       
  1705     m2 = -m1;
       
  1706     QVERIFY(isSame(m2, negated));
       
  1707 }
       
  1708 
       
  1709 // Test matrix negation for 4x3 matrices.
       
  1710 void tst_QMatrixNxN::negate4x3_data()
       
  1711 {
       
  1712     // Use the same test cases as the multiplyFactor test.
       
  1713     multiplyFactor4x3_data();
       
  1714 }
       
  1715 void tst_QMatrixNxN::negate4x3()
       
  1716 {
       
  1717     QFETCH(void *, m1Values);
       
  1718 
       
  1719     const qreal *values = (const qreal *)m1Values;
       
  1720 
       
  1721     QMatrix4x3 m1(values);
       
  1722 
       
  1723     qreal negated[12];
       
  1724     for (int index = 0; index < 12; ++index)
       
  1725         negated[index] = -values[index];
       
  1726 
       
  1727     QMatrix4x3 m2;
       
  1728     m2 = -m1;
       
  1729     QVERIFY(isSame(m2, negated));
       
  1730 }
       
  1731 
       
  1732 // Matrix inverted.  This is a more straight-forward implementation
       
  1733 // of the algorithm at http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q24
       
  1734 // than the optimized version in the QMatrix4x4 code.  Hopefully it is
       
  1735 // easier to verify that this version is the same as the reference.
       
  1736 
       
  1737 struct Matrix3
       
  1738 {
       
  1739     qreal v[9];
       
  1740 };
       
  1741 struct Matrix4
       
  1742 {
       
  1743     qreal v[16];
       
  1744 };
       
  1745 
       
  1746 static qreal m3Determinant(const Matrix3& m)
       
  1747 {
       
  1748     return m.v[0] * (m.v[4] * m.v[8] - m.v[7] * m.v[5]) -
       
  1749            m.v[1] * (m.v[3] * m.v[8] - m.v[6] * m.v[5]) +
       
  1750            m.v[2] * (m.v[3] * m.v[7] - m.v[6] * m.v[4]);
       
  1751 }
       
  1752 
       
  1753 static bool m3Inverse(const Matrix3& min, Matrix3& mout)
       
  1754 {
       
  1755     qreal det = m3Determinant(min);
       
  1756     if (det == 0.0f)
       
  1757         return false;
       
  1758     mout.v[0] =  (min.v[4] * min.v[8] - min.v[5] * min.v[7]) / det;
       
  1759     mout.v[1] = -(min.v[1] * min.v[8] - min.v[2] * min.v[7]) / det;
       
  1760     mout.v[2] =  (min.v[1] * min.v[5] - min.v[4] * min.v[2]) / det;
       
  1761     mout.v[3] = -(min.v[3] * min.v[8] - min.v[5] * min.v[6]) / det;
       
  1762     mout.v[4] =  (min.v[0] * min.v[8] - min.v[6] * min.v[2]) / det;
       
  1763     mout.v[5] = -(min.v[0] * min.v[5] - min.v[3] * min.v[2]) / det;
       
  1764     mout.v[6] =  (min.v[3] * min.v[7] - min.v[6] * min.v[4]) / det;
       
  1765     mout.v[7] = -(min.v[0] * min.v[7] - min.v[6] * min.v[1]) / det;
       
  1766     mout.v[8] =  (min.v[0] * min.v[4] - min.v[1] * min.v[3]) / det;
       
  1767     return true;
       
  1768 }
       
  1769 
       
  1770 static void m3Transpose(Matrix3& m)
       
  1771 {
       
  1772     qSwap(m.v[1], m.v[3]);
       
  1773     qSwap(m.v[2], m.v[6]);
       
  1774     qSwap(m.v[5], m.v[7]);
       
  1775 }
       
  1776 
       
  1777 static void m4Submatrix(const Matrix4& min, Matrix3& mout, int i, int j)
       
  1778 {
       
  1779     for (int di = 0; di < 3; ++di) {
       
  1780         for (int dj = 0; dj < 3; ++dj) {
       
  1781             int si = di + ((di >= i) ? 1 : 0);
       
  1782             int sj = dj + ((dj >= j) ? 1 : 0);
       
  1783             mout.v[di * 3 + dj] = min.v[si * 4 + sj];
       
  1784         }
       
  1785     }
       
  1786 }
       
  1787 
       
  1788 static qreal m4Determinant(const Matrix4& m)
       
  1789 {
       
  1790     qreal det;
       
  1791     qreal result = 0.0f;
       
  1792     qreal i = 1.0f;
       
  1793     Matrix3 msub;
       
  1794     for (int n = 0; n < 4; ++n, i *= -1.0f) {
       
  1795         m4Submatrix(m, msub, 0, n);
       
  1796         det = m3Determinant(msub);
       
  1797         result += m.v[n] * det * i;
       
  1798     }
       
  1799     return result;
       
  1800 }
       
  1801 
       
  1802 static void m4Inverse(const Matrix4& min, Matrix4& mout)
       
  1803 {
       
  1804     qreal det = m4Determinant(min);
       
  1805     Matrix3 msub;
       
  1806     for (int i = 0; i < 4; ++i) {
       
  1807         for (int j = 0; j < 4; ++j) {
       
  1808             qreal sign = 1.0f - ((i + j) % 2) * 2.0f;
       
  1809             m4Submatrix(min, msub, i, j);
       
  1810             mout.v[i + j * 4] = (m3Determinant(msub) * sign) / det;
       
  1811         }
       
  1812     }
       
  1813 }
       
  1814 
       
  1815 // Test matrix inverted for 4x4 matrices.
       
  1816 void tst_QMatrixNxN::inverted4x4_data()
       
  1817 {
       
  1818     QTest::addColumn<void *>("m1Values");
       
  1819     QTest::addColumn<void *>("m2Values");
       
  1820     QTest::addColumn<bool>("invertible");
       
  1821 
       
  1822     QTest::newRow("null")
       
  1823         << (void *)nullValues4 << (void *)identityValues4 << false;
       
  1824 
       
  1825     QTest::newRow("identity")
       
  1826         << (void *)identityValues4 << (void *)identityValues4 << true;
       
  1827 
       
  1828     QTest::newRow("unique")
       
  1829         << (void *)uniqueValues4 << (void *)identityValues4 << false;
       
  1830 
       
  1831     static Matrix4 const invertible = {
       
  1832         {5.0f, 0.0f, 0.0f, 2.0f,
       
  1833          0.0f, 6.0f, 0.0f, 3.0f,
       
  1834          0.0f, 0.0f, 7.0f, 4.0f,
       
  1835          0.0f, 0.0f, 0.0f, 1.0f}
       
  1836     };
       
  1837     static Matrix4 inverted;
       
  1838     m4Inverse(invertible, inverted);
       
  1839 
       
  1840     QTest::newRow("invertible")
       
  1841         << (void *)invertible.v << (void *)inverted.v << true;
       
  1842 
       
  1843     static Matrix4 const translate = {
       
  1844         {1.0f, 0.0f, 0.0f, 2.0f,
       
  1845          0.0f, 1.0f, 0.0f, 3.0f,
       
  1846          0.0f, 0.0f, 1.0f, 4.0f,
       
  1847          0.0f, 0.0f, 0.0f, 1.0f}
       
  1848     };
       
  1849     static Matrix4 const inverseTranslate = {
       
  1850         {1.0f, 0.0f, 0.0f, -2.0f,
       
  1851          0.0f, 1.0f, 0.0f, -3.0f,
       
  1852          0.0f, 0.0f, 1.0f, -4.0f,
       
  1853          0.0f, 0.0f, 0.0f, 1.0f}
       
  1854     };
       
  1855 
       
  1856     QTest::newRow("translate")
       
  1857         << (void *)translate.v << (void *)inverseTranslate.v << true;
       
  1858 }
       
  1859 void tst_QMatrixNxN::inverted4x4()
       
  1860 {
       
  1861     QFETCH(void *, m1Values);
       
  1862     QFETCH(void *, m2Values);
       
  1863     QFETCH(bool, invertible);
       
  1864 
       
  1865     QMatrix4x4 m1((const qreal *)m1Values);
       
  1866 
       
  1867     if (invertible)
       
  1868         QVERIFY(m1.determinant() != 0.0f);
       
  1869     else
       
  1870         QVERIFY(m1.determinant() == 0.0f);
       
  1871 
       
  1872     Matrix4 m1alt;
       
  1873     memcpy(m1alt.v, (const qreal *)m1Values, sizeof(m1alt.v));
       
  1874 
       
  1875     QCOMPARE(m1.determinant(), m4Determinant(m1alt));
       
  1876 
       
  1877     QMatrix4x4 m2;
       
  1878     bool inv;
       
  1879     m2 = m1.inverted(&inv);
       
  1880     QVERIFY(isSame(m2, (const qreal *)m2Values));
       
  1881 
       
  1882     if (invertible) {
       
  1883         QVERIFY(inv);
       
  1884 
       
  1885         Matrix4 m2alt;
       
  1886         m4Inverse(m1alt, m2alt);
       
  1887         QVERIFY(isSame(m2, m2alt.v));
       
  1888 
       
  1889         QMatrix4x4 m3;
       
  1890         m3 = m1 * m2;
       
  1891         QVERIFY(isIdentity(m3));
       
  1892 
       
  1893         QMatrix4x4 m4;
       
  1894         m4 = m2 * m1;
       
  1895         QVERIFY(isIdentity(m4));
       
  1896     } else {
       
  1897         QVERIFY(!inv);
       
  1898     }
       
  1899 
       
  1900     // Test again, after inferring the special matrix type.
       
  1901     m1.inferSpecialType();
       
  1902     m2 = m1.inverted(&inv);
       
  1903     QVERIFY(isSame(m2, (const qreal *)m2Values));
       
  1904     QCOMPARE(inv, invertible);
       
  1905 }
       
  1906 
       
  1907 void tst_QMatrixNxN::orthonormalInverse4x4()
       
  1908 {
       
  1909     QMatrix4x4 m1;
       
  1910     QVERIFY(qFuzzyCompare(m1.inverted(), m1));
       
  1911 
       
  1912     QMatrix4x4 m2;
       
  1913     m2.rotate(45.0, 1.0, 0.0, 0.0);
       
  1914     m2.translate(10.0, 0.0, 0.0);
       
  1915 
       
  1916     // Use inferSpecialType() to drop the internal flags that
       
  1917     // mark the matrix as orthonormal.  This will force inverted()
       
  1918     // to compute m3.inverted() the long way.  We can then compare
       
  1919     // the result to what the faster algorithm produces on m2.
       
  1920     QMatrix4x4 m3 = m2;
       
  1921     m3.inferSpecialType();
       
  1922     bool invertible;
       
  1923     QVERIFY(qFuzzyCompare(m2.inverted(&invertible), m3.inverted()));
       
  1924     QVERIFY(invertible);
       
  1925 
       
  1926     QMatrix4x4 m4;
       
  1927     m4.rotate(45.0, 0.0, 1.0, 0.0);
       
  1928     QMatrix4x4 m5 = m4;
       
  1929     m5.inferSpecialType();
       
  1930     QVERIFY(qFuzzyCompare(m4.inverted(), m5.inverted()));
       
  1931 
       
  1932     QMatrix4x4 m6;
       
  1933     m1.rotate(88, 0.0, 0.0, 1.0);
       
  1934     m1.translate(-20.0, 20.0, 15.0);
       
  1935     m1.rotate(25, 1.0, 0.0, 0.0);
       
  1936     QMatrix4x4 m7 = m6;
       
  1937     m7.inferSpecialType();
       
  1938     QVERIFY(qFuzzyCompare(m6.inverted(), m7.inverted()));
       
  1939 }
       
  1940 
       
  1941 // Test the generation and use of 4x4 scale matrices.
       
  1942 void tst_QMatrixNxN::scale4x4_data()
       
  1943 {
       
  1944     QTest::addColumn<qreal>("x");
       
  1945     QTest::addColumn<qreal>("y");
       
  1946     QTest::addColumn<qreal>("z");
       
  1947     QTest::addColumn<void *>("resultValues");
       
  1948 
       
  1949     static const qreal nullScale[] =
       
  1950         {0.0f, 0.0f, 0.0f, 0.0f,
       
  1951          0.0f, 0.0f, 0.0f, 0.0f,
       
  1952          0.0f, 0.0f, 0.0f, 0.0f,
       
  1953          0.0f, 0.0f, 0.0f, 1.0f};
       
  1954     QTest::newRow("null")
       
  1955         << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (void *)nullScale;
       
  1956 
       
  1957     QTest::newRow("identity")
       
  1958         << (qreal)1.0f << (qreal)1.0f << (qreal)1.0f << (void *)identityValues4;
       
  1959 
       
  1960     static const qreal doubleScale[] =
       
  1961         {2.0f, 0.0f, 0.0f, 0.0f,
       
  1962          0.0f, 2.0f, 0.0f, 0.0f,
       
  1963          0.0f, 0.0f, 2.0f, 0.0f,
       
  1964          0.0f, 0.0f, 0.0f, 1.0f};
       
  1965     QTest::newRow("double")
       
  1966         << (qreal)2.0f << (qreal)2.0f << (qreal)2.0f << (void *)doubleScale;
       
  1967 
       
  1968     static const qreal complexScale[] =
       
  1969         {2.0f, 0.0f, 0.0f, 0.0f,
       
  1970          0.0f, 11.0f, 0.0f, 0.0f,
       
  1971          0.0f, 0.0f, -6.5f, 0.0f,
       
  1972          0.0f, 0.0f, 0.0f, 1.0f};
       
  1973     QTest::newRow("complex")
       
  1974         << (qreal)2.0f << (qreal)11.0f << (qreal)-6.5f << (void *)complexScale;
       
  1975 
       
  1976     static const qreal complexScale2D[] =
       
  1977         {2.0f, 0.0f, 0.0f, 0.0f,
       
  1978          0.0f, -11.0f, 0.0f, 0.0f,
       
  1979          0.0f, 0.0f, 1.0f, 0.0f,
       
  1980          0.0f, 0.0f, 0.0f, 1.0f};
       
  1981     QTest::newRow("complex2D")
       
  1982         << (qreal)2.0f << (qreal)-11.0f << (qreal)1.0f << (void *)complexScale2D;
       
  1983 }
       
  1984 void tst_QMatrixNxN::scale4x4()
       
  1985 {
       
  1986     QFETCH(qreal, x);
       
  1987     QFETCH(qreal, y);
       
  1988     QFETCH(qreal, z);
       
  1989     QFETCH(void *, resultValues);
       
  1990 
       
  1991     QMatrix4x4 result((const qreal *)resultValues);
       
  1992 
       
  1993     QMatrix4x4 m1;
       
  1994     m1.scale(QVector3D(x, y, z));
       
  1995     QVERIFY(isSame(m1, (const qreal *)resultValues));
       
  1996 
       
  1997     QMatrix4x4 m2;
       
  1998     m2.scale(x, y, z);
       
  1999     QVERIFY(isSame(m2, (const qreal *)resultValues));
       
  2000 
       
  2001     if (z == 1.0f) {
       
  2002         QMatrix4x4 m2b;
       
  2003         m2b.scale(x, y);
       
  2004         QVERIFY(m2b == m2);
       
  2005     }
       
  2006 
       
  2007     QVector3D v1(2.0f, 3.0f, -4.0f);
       
  2008     QVector3D v2 = m1 * v1;
       
  2009     QCOMPARE(v2.x(), (qreal)(2.0f * x));
       
  2010     QCOMPARE(v2.y(), (qreal)(3.0f * y));
       
  2011     QCOMPARE(v2.z(), (qreal)(-4.0f * z));
       
  2012 
       
  2013     v2 = v1 * m1;
       
  2014     QCOMPARE(v2.x(), (qreal)(2.0f * x));
       
  2015     QCOMPARE(v2.y(), (qreal)(3.0f * y));
       
  2016     QCOMPARE(v2.z(), (qreal)(-4.0f * z));
       
  2017 
       
  2018     QVector4D v3(2.0f, 3.0f, -4.0f, 34.0f);
       
  2019     QVector4D v4 = m1 * v3;
       
  2020     QCOMPARE(v4.x(), (qreal)(2.0f * x));
       
  2021     QCOMPARE(v4.y(), (qreal)(3.0f * y));
       
  2022     QCOMPARE(v4.z(), (qreal)(-4.0f * z));
       
  2023     QCOMPARE(v4.w(), (qreal)34.0f);
       
  2024 
       
  2025     v4 = v3 * m1;
       
  2026     QCOMPARE(v4.x(), (qreal)(2.0f * x));
       
  2027     QCOMPARE(v4.y(), (qreal)(3.0f * y));
       
  2028     QCOMPARE(v4.z(), (qreal)(-4.0f * z));
       
  2029     QCOMPARE(v4.w(), (qreal)34.0f);
       
  2030 
       
  2031     QPoint p1(2, 3);
       
  2032     QPoint p2 = m1 * p1;
       
  2033     QCOMPARE(p2.x(), (int)(2.0f * x));
       
  2034     QCOMPARE(p2.y(), (int)(3.0f * y));
       
  2035 
       
  2036     p2 = p1 * m1;
       
  2037     QCOMPARE(p2.x(), (int)(2.0f * x));
       
  2038     QCOMPARE(p2.y(), (int)(3.0f * y));
       
  2039 
       
  2040     QPointF p3(2.0f, 3.0f);
       
  2041     QPointF p4 = m1 * p3;
       
  2042     QCOMPARE(p4.x(), (qreal)(2.0f * x));
       
  2043     QCOMPARE(p4.y(), (qreal)(3.0f * y));
       
  2044 
       
  2045     p4 = p3 * m1;
       
  2046     QCOMPARE(p4.x(), (qreal)(2.0f * x));
       
  2047     QCOMPARE(p4.y(), (qreal)(3.0f * y));
       
  2048 
       
  2049     QMatrix4x4 m3(uniqueValues4);
       
  2050     QMatrix4x4 m4(m3);
       
  2051     m4.scale(x, y, z);
       
  2052     QVERIFY(m4 == m3 * m1);
       
  2053 
       
  2054     if (x == y && y == z) {
       
  2055         QMatrix4x4 m5;
       
  2056         m5.scale(x);
       
  2057         QVERIFY(isSame(m5, (const qreal *)resultValues));
       
  2058     }
       
  2059 
       
  2060     if (z == 1.0f) {
       
  2061         QMatrix4x4 m4b(m3);
       
  2062         m4b.scale(x, y);
       
  2063         QVERIFY(m4b == m4);
       
  2064     }
       
  2065 
       
  2066     // Test coverage when the special matrix type is unknown.
       
  2067 
       
  2068     QMatrix4x4 m6;
       
  2069     m6(0, 0) = 1.0f;
       
  2070     m6.scale(QVector3D(x, y, z));
       
  2071     QVERIFY(isSame(m6, (const qreal *)resultValues));
       
  2072 
       
  2073     QMatrix4x4 m7;
       
  2074     m7(0, 0) = 1.0f;
       
  2075     m7.scale(x, y, z);
       
  2076     QVERIFY(isSame(m7, (const qreal *)resultValues));
       
  2077 
       
  2078     if (x == y && y == z) {
       
  2079         QMatrix4x4 m8;
       
  2080         m8(0, 0) = 1.0f;
       
  2081         m8.scale(x);
       
  2082         QVERIFY(isSame(m8, (const qreal *)resultValues));
       
  2083 
       
  2084         m8.inferSpecialType();
       
  2085         m8.scale(1.0f);
       
  2086         QVERIFY(isSame(m8, (const qreal *)resultValues));
       
  2087 
       
  2088         QMatrix4x4 m9;
       
  2089         m9.translate(0.0f, 0.0f, 0.0f);
       
  2090         m9.scale(x);
       
  2091         QVERIFY(isSame(m9, (const qreal *)resultValues));
       
  2092     }
       
  2093 }
       
  2094 
       
  2095 // Test the generation and use of 4x4 translation matrices.
       
  2096 void tst_QMatrixNxN::translate4x4_data()
       
  2097 {
       
  2098     QTest::addColumn<qreal>("x");
       
  2099     QTest::addColumn<qreal>("y");
       
  2100     QTest::addColumn<qreal>("z");
       
  2101     QTest::addColumn<void *>("resultValues");
       
  2102 
       
  2103     QTest::newRow("null")
       
  2104         << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (void *)identityValues4;
       
  2105 
       
  2106     static const qreal identityTranslate[] =
       
  2107         {1.0f, 0.0f, 0.0f, 1.0f,
       
  2108          0.0f, 1.0f, 0.0f, 1.0f,
       
  2109          0.0f, 0.0f, 1.0f, 1.0f,
       
  2110          0.0f, 0.0f, 0.0f, 1.0f};
       
  2111     QTest::newRow("identity")
       
  2112         << (qreal)1.0f << (qreal)1.0f << (qreal)1.0f << (void *)identityTranslate;
       
  2113 
       
  2114     static const qreal complexTranslate[] =
       
  2115         {1.0f, 0.0f, 0.0f, 2.0f,
       
  2116          0.0f, 1.0f, 0.0f, 11.0f,
       
  2117          0.0f, 0.0f, 1.0f, -6.5f,
       
  2118          0.0f, 0.0f, 0.0f, 1.0f};
       
  2119     QTest::newRow("complex")
       
  2120         << (qreal)2.0f << (qreal)11.0f << (qreal)-6.5f << (void *)complexTranslate;
       
  2121 
       
  2122     static const qreal complexTranslate2D[] =
       
  2123         {1.0f, 0.0f, 0.0f, 2.0f,
       
  2124          0.0f, 1.0f, 0.0f, -11.0f,
       
  2125          0.0f, 0.0f, 1.0f, 0.0f,
       
  2126          0.0f, 0.0f, 0.0f, 1.0f};
       
  2127     QTest::newRow("complex2D")
       
  2128         << (qreal)2.0f << (qreal)-11.0f << (qreal)0.0f << (void *)complexTranslate2D;
       
  2129 }
       
  2130 void tst_QMatrixNxN::translate4x4()
       
  2131 {
       
  2132     QFETCH(qreal, x);
       
  2133     QFETCH(qreal, y);
       
  2134     QFETCH(qreal, z);
       
  2135     QFETCH(void *, resultValues);
       
  2136 
       
  2137     QMatrix4x4 result((const qreal *)resultValues);
       
  2138 
       
  2139     QMatrix4x4 m1;
       
  2140     m1.translate(QVector3D(x, y, z));
       
  2141     QVERIFY(isSame(m1, (const qreal *)resultValues));
       
  2142 
       
  2143     QMatrix4x4 m2;
       
  2144     m2.translate(x, y, z);
       
  2145     QVERIFY(isSame(m2, (const qreal *)resultValues));
       
  2146 
       
  2147     if (z == 0.0f) {
       
  2148         QMatrix4x4 m2b;
       
  2149         m2b.translate(x, y);
       
  2150         QVERIFY(m2b == m2);
       
  2151     }
       
  2152 
       
  2153     QVector3D v1(2.0f, 3.0f, -4.0f);
       
  2154     QVector3D v2 = m1 * v1;
       
  2155     QCOMPARE(v2.x(), (qreal)(2.0f + x));
       
  2156     QCOMPARE(v2.y(), (qreal)(3.0f + y));
       
  2157     QCOMPARE(v2.z(), (qreal)(-4.0f + z));
       
  2158 
       
  2159     QVector4D v3(2.0f, 3.0f, -4.0f, 1.0f);
       
  2160     QVector4D v4 = m1 * v3;
       
  2161     QCOMPARE(v4.x(), (qreal)(2.0f + x));
       
  2162     QCOMPARE(v4.y(), (qreal)(3.0f + y));
       
  2163     QCOMPARE(v4.z(), (qreal)(-4.0f + z));
       
  2164     QCOMPARE(v4.w(), (qreal)1.0f);
       
  2165 
       
  2166     QVector4D v5(2.0f, 3.0f, -4.0f, 34.0f);
       
  2167     QVector4D v6 = m1 * v5;
       
  2168     QCOMPARE(v6.x(), (qreal)(2.0f + x * 34.0f));
       
  2169     QCOMPARE(v6.y(), (qreal)(3.0f + y * 34.0f));
       
  2170     QCOMPARE(v6.z(), (qreal)(-4.0f + z * 34.0f));
       
  2171     QCOMPARE(v6.w(), (qreal)34.0f);
       
  2172 
       
  2173     QPoint p1(2, 3);
       
  2174     QPoint p2 = m1 * p1;
       
  2175     QCOMPARE(p2.x(), (int)(2.0f + x));
       
  2176     QCOMPARE(p2.y(), (int)(3.0f + y));
       
  2177 
       
  2178     QPointF p3(2.0f, 3.0f);
       
  2179     QPointF p4 = m1 * p3;
       
  2180     QCOMPARE(p4.x(), (qreal)(2.0f + x));
       
  2181     QCOMPARE(p4.y(), (qreal)(3.0f + y));
       
  2182 
       
  2183     QMatrix4x4 m3(uniqueValues4);
       
  2184     QMatrix4x4 m4(m3);
       
  2185     m4.translate(x, y, z);
       
  2186     QVERIFY(m4 == m3 * m1);
       
  2187 
       
  2188     if (z == 0.0f) {
       
  2189         QMatrix4x4 m4b(m3);
       
  2190         m4b.translate(x, y);
       
  2191         QVERIFY(m4b == m4);
       
  2192     }
       
  2193 }
       
  2194 
       
  2195 // Test the generation and use of 4x4 rotation matrices.
       
  2196 void tst_QMatrixNxN::rotate4x4_data()
       
  2197 {
       
  2198     QTest::addColumn<qreal>("angle");
       
  2199     QTest::addColumn<qreal>("x");
       
  2200     QTest::addColumn<qreal>("y");
       
  2201     QTest::addColumn<qreal>("z");
       
  2202     QTest::addColumn<void *>("resultValues");
       
  2203 
       
  2204     static const qreal nullRotate[] =
       
  2205         {0.0f, 0.0f, 0.0f, 0.0f,
       
  2206          0.0f, 0.0f, 0.0f, 0.0f,
       
  2207          0.0f, 0.0f, 0.0f, 0.0f,
       
  2208          0.0f, 0.0f, 0.0f, 1.0f};
       
  2209     QTest::newRow("null")
       
  2210         << (qreal)90.0f
       
  2211         << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f
       
  2212         << (void *)nullRotate;
       
  2213 
       
  2214     static const qreal noRotate[] =
       
  2215         {1.0f, 0.0f, 0.0f, 0.0f,
       
  2216          0.0f, 1.0f, 0.0f, 0.0f,
       
  2217          0.0f, 0.0f, 1.0f, 0.0f,
       
  2218          0.0f, 0.0f, 0.0f, 1.0f};
       
  2219     QTest::newRow("zerodegrees")
       
  2220         << (qreal)0.0f
       
  2221         << (qreal)2.0f << (qreal)3.0f << (qreal)-4.0f
       
  2222         << (void *)noRotate;
       
  2223 
       
  2224     static const qreal xRotate[] =
       
  2225         {1.0f, 0.0f, 0.0f, 0.0f,
       
  2226          0.0f, 0.0f, -1.0f, 0.0f,
       
  2227          0.0f, 1.0f, 0.0f, 0.0f,
       
  2228          0.0f, 0.0f, 0.0f, 1.0f};
       
  2229     QTest::newRow("xrotate")
       
  2230         << (qreal)90.0f
       
  2231         << (qreal)1.0f << (qreal)0.0f << (qreal)0.0f
       
  2232         << (void *)xRotate;
       
  2233 
       
  2234     static const qreal xRotateNeg[] =
       
  2235         {1.0f, 0.0f, 0.0f, 0.0f,
       
  2236          0.0f, 0.0f, 1.0f, 0.0f,
       
  2237          0.0f, -1.0f, 0.0f, 0.0f,
       
  2238          0.0f, 0.0f, 0.0f, 1.0f};
       
  2239     QTest::newRow("-xrotate")
       
  2240         << (qreal)90.0f
       
  2241         << (qreal)-1.0f << (qreal)0.0f << (qreal)0.0f
       
  2242         << (void *)xRotateNeg;
       
  2243 
       
  2244     static const qreal yRotate[] =
       
  2245         {0.0f, 0.0f, 1.0f, 0.0f,
       
  2246          0.0f, 1.0f, 0.0f, 0.0f,
       
  2247          -1.0f, 0.0f, 0.0f, 0.0f,
       
  2248          0.0f, 0.0f, 0.0f, 1.0f};
       
  2249     QTest::newRow("yrotate")
       
  2250         << (qreal)90.0f
       
  2251         << (qreal)0.0f << (qreal)1.0f << (qreal)0.0f
       
  2252         << (void *)yRotate;
       
  2253 
       
  2254     static const qreal yRotateNeg[] =
       
  2255         {0.0f, 0.0f, -1.0f, 0.0f,
       
  2256          0.0f, 1.0f, 0.0f, 0.0f,
       
  2257          1.0f, 0.0f, 0.0f, 0.0f,
       
  2258          0.0f, 0.0f, 0.0f, 1.0f};
       
  2259     QTest::newRow("-yrotate")
       
  2260         << (qreal)90.0f
       
  2261         << (qreal)0.0f << (qreal)-1.0f << (qreal)0.0f
       
  2262         << (void *)yRotateNeg;
       
  2263 
       
  2264     static const qreal zRotate[] =
       
  2265         {0.0f, -1.0f, 0.0f, 0.0f,
       
  2266          1.0f, 0.0f, 0.0f, 0.0f,
       
  2267          0.0f, 0.0f, 1.0f, 0.0f,
       
  2268          0.0f, 0.0f, 0.0f, 1.0f};
       
  2269     QTest::newRow("zrotate")
       
  2270         << (qreal)90.0f
       
  2271         << (qreal)0.0f << (qreal)0.0f << (qreal)1.0f
       
  2272         << (void *)zRotate;
       
  2273 
       
  2274     static const qreal zRotateNeg[] =
       
  2275         {0.0f, 1.0f, 0.0f, 0.0f,
       
  2276          -1.0f, 0.0f, 0.0f, 0.0f,
       
  2277          0.0f, 0.0f, 1.0f, 0.0f,
       
  2278          0.0f, 0.0f, 0.0f, 1.0f};
       
  2279     QTest::newRow("-zrotate")
       
  2280         << (qreal)90.0f
       
  2281         << (qreal)0.0f << (qreal)0.0f << (qreal)-1.0f
       
  2282         << (void *)zRotateNeg;
       
  2283 
       
  2284     // Algorithm from http://en.wikipedia.org/wiki/Rotation_matrix.
       
  2285     // Deliberately different from the one in the code for cross-checking.
       
  2286     static qreal complexRotate[16];
       
  2287     qreal x = 1.0f;
       
  2288     qreal y = 2.0f;
       
  2289     qreal z = -6.0f;
       
  2290     qreal angle = -45.0f;
       
  2291     qreal c = qCos(angle * M_PI / 180.0f);
       
  2292     qreal s = qSin(angle * M_PI / 180.0f);
       
  2293     qreal len = qSqrt(x * x + y * y + z * z);
       
  2294     qreal xu = x / len;
       
  2295     qreal yu = y / len;
       
  2296     qreal zu = z / len;
       
  2297     complexRotate[0] = (qreal)((1 - xu * xu) * c + xu * xu);
       
  2298     complexRotate[1] = (qreal)(-zu * s - xu * yu * c + xu * yu);
       
  2299     complexRotate[2] = (qreal)(yu * s - xu * zu * c + xu * zu);
       
  2300     complexRotate[3] = 0;
       
  2301     complexRotate[4] = (qreal)(zu * s - xu * yu * c + xu * yu);
       
  2302     complexRotate[5] = (qreal)((1 - yu * yu) * c + yu * yu);
       
  2303     complexRotate[6] = (qreal)(-xu * s - yu * zu * c + yu * zu);
       
  2304     complexRotate[7] = 0;
       
  2305     complexRotate[8] = (qreal)(-yu * s - xu * zu * c + xu * zu);
       
  2306     complexRotate[9] = (qreal)(xu * s - yu * zu * c + yu * zu);
       
  2307     complexRotate[10] = (qreal)((1 - zu * zu) * c + zu * zu);
       
  2308     complexRotate[11] = 0;
       
  2309     complexRotate[12] = 0;
       
  2310     complexRotate[13] = 0;
       
  2311     complexRotate[14] = 0;
       
  2312     complexRotate[15] = 1;
       
  2313 
       
  2314     QTest::newRow("complex")
       
  2315         << (qreal)angle
       
  2316         << (qreal)x << (qreal)y << (qreal)z
       
  2317         << (void *)complexRotate;
       
  2318 }
       
  2319 void tst_QMatrixNxN::rotate4x4()
       
  2320 {
       
  2321     QFETCH(qreal, angle);
       
  2322     QFETCH(qreal, x);
       
  2323     QFETCH(qreal, y);
       
  2324     QFETCH(qreal, z);
       
  2325     QFETCH(void *, resultValues);
       
  2326 
       
  2327     QMatrix4x4 m1;
       
  2328     m1.rotate(angle, QVector3D(x, y, z));
       
  2329     QVERIFY(isSame(m1, (const qreal *)resultValues));
       
  2330 
       
  2331     QMatrix4x4 m2;
       
  2332     m2.rotate(angle, x, y, z);
       
  2333     QVERIFY(isSame(m2, (const qreal *)resultValues));
       
  2334 
       
  2335     QMatrix4x4 m3(uniqueValues4);
       
  2336     QMatrix4x4 m4(m3);
       
  2337     m4.rotate(angle, x, y, z);
       
  2338     QVERIFY(qFuzzyCompare(m4, m3 * m1));
       
  2339 
       
  2340     // Null vectors don't make sense for quaternion rotations.
       
  2341     if (x != 0 || y != 0 || z != 0) {
       
  2342         QMatrix4x4 m5;
       
  2343         m5.rotate(QQuaternion::fromAxisAndAngle(QVector3D(x, y, z), angle));
       
  2344         QVERIFY(isSame(m5, (const qreal *)resultValues));
       
  2345     }
       
  2346 
       
  2347 #define ROTATE4(xin,yin,zin,win,xout,yout,zout,wout) \
       
  2348     do { \
       
  2349         xout = ((const qreal *)resultValues)[0] * xin + \
       
  2350                ((const qreal *)resultValues)[1] * yin + \
       
  2351                ((const qreal *)resultValues)[2] * zin + \
       
  2352                ((const qreal *)resultValues)[3] * win; \
       
  2353         yout = ((const qreal *)resultValues)[4] * xin + \
       
  2354                ((const qreal *)resultValues)[5] * yin + \
       
  2355                ((const qreal *)resultValues)[6] * zin + \
       
  2356                ((const qreal *)resultValues)[7] * win; \
       
  2357         zout = ((const qreal *)resultValues)[8] * xin + \
       
  2358                ((const qreal *)resultValues)[9] * yin + \
       
  2359                ((const qreal *)resultValues)[10] * zin + \
       
  2360                ((const qreal *)resultValues)[11] * win; \
       
  2361         wout = ((const qreal *)resultValues)[12] * xin + \
       
  2362                ((const qreal *)resultValues)[13] * yin + \
       
  2363                ((const qreal *)resultValues)[14] * zin + \
       
  2364                ((const qreal *)resultValues)[15] * win; \
       
  2365     } while (0)
       
  2366 
       
  2367     // Rotate various test vectors using the straight-forward approach.
       
  2368     qreal v1x, v1y, v1z, v1w;
       
  2369     ROTATE4(2.0f, 3.0f, -4.0f, 1.0f, v1x, v1y, v1z, v1w);
       
  2370     v1x /= v1w;
       
  2371     v1y /= v1w;
       
  2372     v1z /= v1w;
       
  2373     qreal v3x, v3y, v3z, v3w;
       
  2374     ROTATE4(2.0f, 3.0f, -4.0f, 1.0f, v3x, v3y, v3z, v3w);
       
  2375     qreal v5x, v5y, v5z, v5w;
       
  2376     ROTATE4(2.0f, 3.0f, -4.0f, 34.0f, v5x, v5y, v5z, v5w);
       
  2377     qreal p1x, p1y, p1z, p1w;
       
  2378     ROTATE4(2.0f, 3.0f, 0.0f, 1.0f, p1x, p1y, p1z, p1w);
       
  2379     p1x /= p1w;
       
  2380     p1y /= p1w;
       
  2381     p1z /= p1w;
       
  2382 
       
  2383     QVector3D v1(2.0f, 3.0f, -4.0f);
       
  2384     QVector3D v2 = m1 * v1;
       
  2385     QVERIFY(fuzzyCompare(v2.x(), v1x));
       
  2386     QVERIFY(fuzzyCompare(v2.y(), v1y));
       
  2387     QVERIFY(fuzzyCompare(v2.z(), v1z));
       
  2388 
       
  2389     QVector4D v3(2.0f, 3.0f, -4.0f, 1.0f);
       
  2390     QVector4D v4 = m1 * v3;
       
  2391     QVERIFY(fuzzyCompare(v4.x(), v3x));
       
  2392     QVERIFY(fuzzyCompare(v4.y(), v3y));
       
  2393     QVERIFY(fuzzyCompare(v4.z(), v3z));
       
  2394     QVERIFY(fuzzyCompare(v4.w(), v3w));
       
  2395 
       
  2396     QVector4D v5(2.0f, 3.0f, -4.0f, 34.0f);
       
  2397     QVector4D v6 = m1 * v5;
       
  2398     QVERIFY(fuzzyCompare(v6.x(), v5x));
       
  2399     QVERIFY(fuzzyCompare(v6.y(), v5y));
       
  2400     QVERIFY(fuzzyCompare(v6.z(), v5z));
       
  2401     QVERIFY(fuzzyCompare(v6.w(), v5w));
       
  2402 
       
  2403     QPoint p1(2, 3);
       
  2404     QPoint p2 = m1 * p1;
       
  2405     QCOMPARE(p2.x(), qRound(p1x));
       
  2406     QCOMPARE(p2.y(), qRound(p1y));
       
  2407 
       
  2408     QPointF p3(2.0f, 3.0f);
       
  2409     QPointF p4 = m1 * p3;
       
  2410     QVERIFY(fuzzyCompare(p4.x(), p1x));
       
  2411     QVERIFY(fuzzyCompare(p4.y(), p1y));
       
  2412 
       
  2413     if (x != 0 || y != 0 || z != 0) {
       
  2414         QQuaternion q = QQuaternion::fromAxisAndAngle(QVector3D(x, y, z), angle);
       
  2415         QVector3D vq = q.rotateVector(v1);
       
  2416         QVERIFY(fuzzyCompare(vq.x(), v1x));
       
  2417         QVERIFY(fuzzyCompare(vq.y(), v1y));
       
  2418         QVERIFY(fuzzyCompare(vq.z(), v1z));
       
  2419     }
       
  2420 }
       
  2421 
       
  2422 static bool isSame(const QMatrix3x3& m1, const Matrix3& m2)
       
  2423 {
       
  2424     for (int row = 0; row < 3; ++row) {
       
  2425         for (int col = 0; col < 3; ++col) {
       
  2426             if (!fuzzyCompare(m1(row, col), m2.v[row * 3 + col]))
       
  2427                 return false;
       
  2428         }
       
  2429     }
       
  2430     return true;
       
  2431 }
       
  2432 
       
  2433 // Test the computation of normal matrices from 4x4 transformation matrices.
       
  2434 void tst_QMatrixNxN::normalMatrix_data()
       
  2435 {
       
  2436     QTest::addColumn<void *>("mValues");
       
  2437 
       
  2438     QTest::newRow("identity")
       
  2439         << (void *)identityValues4;
       
  2440     QTest::newRow("unique")
       
  2441         << (void *)uniqueValues4;   // Not invertible because determinant == 0.
       
  2442 
       
  2443     static qreal const translateValues[16] =
       
  2444         {1.0f, 0.0f, 0.0f, 4.0f,
       
  2445          0.0f, 1.0f, 0.0f, 5.0f,
       
  2446          0.0f, 0.0f, 1.0f, -3.0f,
       
  2447          0.0f, 0.0f, 0.0f, 1.0f};
       
  2448     static qreal const scaleValues[16] =
       
  2449         {2.0f, 0.0f, 0.0f, 0.0f,
       
  2450          0.0f, 7.0f, 0.0f, 0.0f,
       
  2451          0.0f, 0.0f, 9.0f, 0.0f,
       
  2452          0.0f, 0.0f, 0.0f, 1.0f};
       
  2453     static qreal const bothValues[16] =
       
  2454         {2.0f, 0.0f, 0.0f, 4.0f,
       
  2455          0.0f, 7.0f, 0.0f, 5.0f,
       
  2456          0.0f, 0.0f, 9.0f, -3.0f,
       
  2457          0.0f, 0.0f, 0.0f, 1.0f};
       
  2458     static qreal const nullScaleValues1[16] =
       
  2459         {0.0f, 0.0f, 0.0f, 4.0f,
       
  2460          0.0f, 7.0f, 0.0f, 5.0f,
       
  2461          0.0f, 0.0f, 9.0f, -3.0f,
       
  2462          0.0f, 0.0f, 0.0f, 1.0f};
       
  2463     static qreal const nullScaleValues2[16] =
       
  2464         {2.0f, 0.0f, 0.0f, 4.0f,
       
  2465          0.0f, 0.0f, 0.0f, 5.0f,
       
  2466          0.0f, 0.0f, 9.0f, -3.0f,
       
  2467          0.0f, 0.0f, 0.0f, 1.0f};
       
  2468     static qreal const nullScaleValues3[16] =
       
  2469         {2.0f, 0.0f, 0.0f, 4.0f,
       
  2470          0.0f, 7.0f, 0.0f, 5.0f,
       
  2471          0.0f, 0.0f, 0.0f, -3.0f,
       
  2472          0.0f, 0.0f, 0.0f, 1.0f};
       
  2473 
       
  2474     QTest::newRow("translate") << (void *)translateValues;
       
  2475     QTest::newRow("scale") << (void *)scaleValues;
       
  2476     QTest::newRow("both") << (void *)bothValues;
       
  2477     QTest::newRow("null scale 1") << (void *)nullScaleValues1;
       
  2478     QTest::newRow("null scale 2") << (void *)nullScaleValues2;
       
  2479     QTest::newRow("null scale 3") << (void *)nullScaleValues3;
       
  2480 }
       
  2481 void tst_QMatrixNxN::normalMatrix()
       
  2482 {
       
  2483     QFETCH(void *, mValues);
       
  2484     const qreal *values = (const qreal *)mValues;
       
  2485 
       
  2486     // Compute the expected answer the long way.
       
  2487     Matrix3 min;
       
  2488     Matrix3 answer;
       
  2489     min.v[0] = values[0];
       
  2490     min.v[1] = values[1];
       
  2491     min.v[2] = values[2];
       
  2492     min.v[3] = values[4];
       
  2493     min.v[4] = values[5];
       
  2494     min.v[5] = values[6];
       
  2495     min.v[6] = values[8];
       
  2496     min.v[7] = values[9];
       
  2497     min.v[8] = values[10];
       
  2498     bool invertible = m3Inverse(min, answer);
       
  2499     m3Transpose(answer);
       
  2500 
       
  2501     // Perform the test.
       
  2502     QMatrix4x4 m1(values);
       
  2503     QMatrix3x3 n1 = m1.normalMatrix();
       
  2504 
       
  2505     if (invertible)
       
  2506         QVERIFY(::isSame(n1, answer));
       
  2507     else
       
  2508         QVERIFY(isIdentity(n1));
       
  2509 
       
  2510     // Perform the test again, after inferring special matrix types.
       
  2511     // This tests the optimized paths in the normalMatrix() function.
       
  2512     m1.inferSpecialType();
       
  2513     n1 = m1.normalMatrix();
       
  2514 
       
  2515     if (invertible)
       
  2516         QVERIFY(::isSame(n1, answer));
       
  2517     else
       
  2518         QVERIFY(isIdentity(n1));
       
  2519 }
       
  2520 
       
  2521 // Test optimized transformations on 4x4 matrices.
       
  2522 void tst_QMatrixNxN::optimizedTransforms()
       
  2523 {
       
  2524     static qreal const translateValues[16] =
       
  2525         {1.0f, 0.0f, 0.0f, 4.0f,
       
  2526          0.0f, 1.0f, 0.0f, 5.0f,
       
  2527          0.0f, 0.0f, 1.0f, -3.0f,
       
  2528          0.0f, 0.0f, 0.0f, 1.0f};
       
  2529     static qreal const translateDoubleValues[16] =
       
  2530         {1.0f, 0.0f, 0.0f, 8.0f,
       
  2531          0.0f, 1.0f, 0.0f, 10.0f,
       
  2532          0.0f, 0.0f, 1.0f, -6.0f,
       
  2533          0.0f, 0.0f, 0.0f, 1.0f};
       
  2534     static qreal const scaleValues[16] =
       
  2535         {2.0f, 0.0f, 0.0f, 0.0f,
       
  2536          0.0f, 7.0f, 0.0f, 0.0f,
       
  2537          0.0f, 0.0f, 9.0f, 0.0f,
       
  2538          0.0f, 0.0f, 0.0f, 1.0f};
       
  2539     static qreal const scaleDoubleValues[16] =
       
  2540         {4.0f, 0.0f, 0.0f, 0.0f,
       
  2541          0.0f, 49.0f, 0.0f, 0.0f,
       
  2542          0.0f, 0.0f, 81.0f, 0.0f,
       
  2543          0.0f, 0.0f, 0.0f, 1.0f};
       
  2544     static qreal const bothValues[16] =
       
  2545         {2.0f, 0.0f, 0.0f, 4.0f,
       
  2546          0.0f, 7.0f, 0.0f, 5.0f,
       
  2547          0.0f, 0.0f, 9.0f, -3.0f,
       
  2548          0.0f, 0.0f, 0.0f, 1.0f};
       
  2549     static qreal const bothReverseValues[16] =
       
  2550         {2.0f, 0.0f, 0.0f, 4.0f * 2.0f,
       
  2551          0.0f, 7.0f, 0.0f, 5.0f * 7.0f,
       
  2552          0.0f, 0.0f, 9.0f, -3.0f * 9.0f,
       
  2553          0.0f, 0.0f, 0.0f, 1.0f};
       
  2554     static qreal const bothThenTranslateValues[16] =
       
  2555         {2.0f, 0.0f, 0.0f, 4.0f + 2.0f * 4.0f,
       
  2556          0.0f, 7.0f, 0.0f, 5.0f + 7.0f * 5.0f,
       
  2557          0.0f, 0.0f, 9.0f, -3.0f + 9.0f * -3.0f,
       
  2558          0.0f, 0.0f, 0.0f, 1.0f};
       
  2559     static qreal const bothThenScaleValues[16] =
       
  2560         {4.0f, 0.0f, 0.0f, 4.0f,
       
  2561          0.0f, 49.0f, 0.0f, 5.0f,
       
  2562          0.0f, 0.0f, 81.0f, -3.0f,
       
  2563          0.0f, 0.0f, 0.0f, 1.0f};
       
  2564 
       
  2565     QMatrix4x4 translate(translateValues);
       
  2566     QMatrix4x4 scale(scaleValues);
       
  2567     QMatrix4x4 both(bothValues);
       
  2568 
       
  2569     QMatrix4x4 m1;
       
  2570     m1.translate(4.0f, 5.0f, -3.0f);
       
  2571     QVERIFY(isSame(m1, translateValues));
       
  2572     m1.translate(4.0f, 5.0f, -3.0f);
       
  2573     QVERIFY(isSame(m1, translateDoubleValues));
       
  2574 
       
  2575     QMatrix4x4 m2;
       
  2576     m2.translate(QVector3D(4.0f, 5.0f, -3.0f));
       
  2577     QVERIFY(isSame(m2, translateValues));
       
  2578     m2.translate(QVector3D(4.0f, 5.0f, -3.0f));
       
  2579     QVERIFY(isSame(m2, translateDoubleValues));
       
  2580 
       
  2581     QMatrix4x4 m3;
       
  2582     m3.scale(2.0f, 7.0f, 9.0f);
       
  2583     QVERIFY(isSame(m3, scaleValues));
       
  2584     m3.scale(2.0f, 7.0f, 9.0f);
       
  2585     QVERIFY(isSame(m3, scaleDoubleValues));
       
  2586 
       
  2587     QMatrix4x4 m4;
       
  2588     m4.scale(QVector3D(2.0f, 7.0f, 9.0f));
       
  2589     QVERIFY(isSame(m4, scaleValues));
       
  2590     m4.scale(QVector3D(2.0f, 7.0f, 9.0f));
       
  2591     QVERIFY(isSame(m4, scaleDoubleValues));
       
  2592 
       
  2593     QMatrix4x4 m5;
       
  2594     m5.translate(4.0f, 5.0f, -3.0f);
       
  2595     m5.scale(2.0f, 7.0f, 9.0f);
       
  2596     QVERIFY(isSame(m5, bothValues));
       
  2597     m5.translate(4.0f, 5.0f, -3.0f);
       
  2598     QVERIFY(isSame(m5, bothThenTranslateValues));
       
  2599 
       
  2600     QMatrix4x4 m6;
       
  2601     m6.translate(QVector3D(4.0f, 5.0f, -3.0f));
       
  2602     m6.scale(QVector3D(2.0f, 7.0f, 9.0f));
       
  2603     QVERIFY(isSame(m6, bothValues));
       
  2604     m6.translate(QVector3D(4.0f, 5.0f, -3.0f));
       
  2605     QVERIFY(isSame(m6, bothThenTranslateValues));
       
  2606 
       
  2607     QMatrix4x4 m7;
       
  2608     m7.scale(2.0f, 7.0f, 9.0f);
       
  2609     m7.translate(4.0f, 5.0f, -3.0f);
       
  2610     QVERIFY(isSame(m7, bothReverseValues));
       
  2611 
       
  2612     QMatrix4x4 m8;
       
  2613     m8.scale(QVector3D(2.0f, 7.0f, 9.0f));
       
  2614     m8.translate(QVector3D(4.0f, 5.0f, -3.0f));
       
  2615     QVERIFY(isSame(m8, bothReverseValues));
       
  2616 
       
  2617     QMatrix4x4 m9;
       
  2618     m9.translate(4.0f, 5.0f, -3.0f);
       
  2619     m9.scale(2.0f, 7.0f, 9.0f);
       
  2620     QVERIFY(isSame(m9, bothValues));
       
  2621     m9.scale(2.0f, 7.0f, 9.0f);
       
  2622     QVERIFY(isSame(m9, bothThenScaleValues));
       
  2623 
       
  2624     QMatrix4x4 m10;
       
  2625     m10.translate(QVector3D(4.0f, 5.0f, -3.0f));
       
  2626     m10.scale(QVector3D(2.0f, 7.0f, 9.0f));
       
  2627     QVERIFY(isSame(m10, bothValues));
       
  2628     m10.scale(QVector3D(2.0f, 7.0f, 9.0f));
       
  2629     QVERIFY(isSame(m10, bothThenScaleValues));
       
  2630 }
       
  2631 
       
  2632 // Test orthographic projections.
       
  2633 void tst_QMatrixNxN::ortho()
       
  2634 {
       
  2635     QMatrix4x4 m1;
       
  2636     m1.ortho(QRect(0, 0, 300, 150));
       
  2637     QPointF p1 = m1 * QPointF(0, 0);
       
  2638     QPointF p2 = m1 * QPointF(300, 0);
       
  2639     QPointF p3 = m1 * QPointF(0, 150);
       
  2640     QPointF p4 = m1 * QPointF(300, 150);
       
  2641     QVector3D p5 = m1 * QVector3D(300, 150, 1);
       
  2642     QVERIFY(fuzzyCompare(p1.x(), -1.0));
       
  2643     QVERIFY(fuzzyCompare(p1.y(), 1.0));
       
  2644     QVERIFY(fuzzyCompare(p2.x(), 1.0));
       
  2645     QVERIFY(fuzzyCompare(p2.y(), 1.0));
       
  2646     QVERIFY(fuzzyCompare(p3.x(), -1.0));
       
  2647     QVERIFY(fuzzyCompare(p3.y(), -1.0));
       
  2648     QVERIFY(fuzzyCompare(p4.x(), 1.0));
       
  2649     QVERIFY(fuzzyCompare(p4.y(), -1.0));
       
  2650     QVERIFY(fuzzyCompare(p5.x(), (qreal)1.0));
       
  2651     QVERIFY(fuzzyCompare(p5.y(), (qreal)-1.0));
       
  2652     QVERIFY(fuzzyCompare(p5.z(), (qreal)-1.0));
       
  2653 
       
  2654     QMatrix4x4 m2;
       
  2655     m2.ortho(QRectF(0, 0, 300, 150));
       
  2656     p1 = m2 * QPointF(0, 0);
       
  2657     p2 = m2 * QPointF(300, 0);
       
  2658     p3 = m2 * QPointF(0, 150);
       
  2659     p4 = m2 * QPointF(300, 150);
       
  2660     p5 = m2 * QVector3D(300, 150, 1);
       
  2661     QVERIFY(fuzzyCompare(p1.x(), -1.0));
       
  2662     QVERIFY(fuzzyCompare(p1.y(), 1.0));
       
  2663     QVERIFY(fuzzyCompare(p2.x(), 1.0));
       
  2664     QVERIFY(fuzzyCompare(p2.y(), 1.0));
       
  2665     QVERIFY(fuzzyCompare(p3.x(), -1.0));
       
  2666     QVERIFY(fuzzyCompare(p3.y(), -1.0));
       
  2667     QVERIFY(fuzzyCompare(p4.x(), 1.0));
       
  2668     QVERIFY(fuzzyCompare(p4.y(), -1.0));
       
  2669     QVERIFY(fuzzyCompare(p5.x(), (qreal)1.0));
       
  2670     QVERIFY(fuzzyCompare(p5.y(), (qreal)-1.0));
       
  2671     QVERIFY(fuzzyCompare(p5.z(), (qreal)-1.0));
       
  2672 
       
  2673     QMatrix4x4 m3;
       
  2674     m3.ortho(0, 300, 150, 0, -1, 1);
       
  2675     p1 = m3 * QPointF(0, 0);
       
  2676     p2 = m3 * QPointF(300, 0);
       
  2677     p3 = m3 * QPointF(0, 150);
       
  2678     p4 = m3 * QPointF(300, 150);
       
  2679     p5 = m3 * QVector3D(300, 150, 1);
       
  2680     QVERIFY(fuzzyCompare(p1.x(), -1.0));
       
  2681     QVERIFY(fuzzyCompare(p1.y(), 1.0));
       
  2682     QVERIFY(fuzzyCompare(p2.x(), 1.0));
       
  2683     QVERIFY(fuzzyCompare(p2.y(), 1.0));
       
  2684     QVERIFY(fuzzyCompare(p3.x(), -1.0));
       
  2685     QVERIFY(fuzzyCompare(p3.y(), -1.0));
       
  2686     QVERIFY(fuzzyCompare(p4.x(), 1.0));
       
  2687     QVERIFY(fuzzyCompare(p4.y(), -1.0));
       
  2688     QVERIFY(fuzzyCompare(p5.x(), (qreal)1.0));
       
  2689     QVERIFY(fuzzyCompare(p5.y(), (qreal)-1.0));
       
  2690     QVERIFY(fuzzyCompare(p5.z(), (qreal)-1.0));
       
  2691 
       
  2692     QMatrix4x4 m4;
       
  2693     m4.ortho(0, 300, 150, 0, -2, 3);
       
  2694     p1 = m4 * QPointF(0, 0);
       
  2695     p2 = m4 * QPointF(300, 0);
       
  2696     p3 = m4 * QPointF(0, 150);
       
  2697     p4 = m4 * QPointF(300, 150);
       
  2698     p5 = m4 * QVector3D(300, 150, 1);
       
  2699     QVERIFY(fuzzyCompare(p1.x(), -1.0));
       
  2700     QVERIFY(fuzzyCompare(p1.y(), 1.0));
       
  2701     QVERIFY(fuzzyCompare(p2.x(), 1.0));
       
  2702     QVERIFY(fuzzyCompare(p2.y(), 1.0));
       
  2703     QVERIFY(fuzzyCompare(p3.x(), -1.0));
       
  2704     QVERIFY(fuzzyCompare(p3.y(), -1.0));
       
  2705     QVERIFY(fuzzyCompare(p4.x(), 1.0));
       
  2706     QVERIFY(fuzzyCompare(p4.y(), -1.0));
       
  2707     QVERIFY(fuzzyCompare(p5.x(), (qreal)1.0));
       
  2708     QVERIFY(fuzzyCompare(p5.y(), (qreal)-1.0));
       
  2709     QVERIFY(fuzzyCompare(p5.z(), (qreal)-0.6));
       
  2710 
       
  2711     // An empty view volume should leave the matrix alone.
       
  2712     QMatrix4x4 m5;
       
  2713     m5.ortho(0, 0, 150, 0, -2, 3);
       
  2714     QVERIFY(m5.isIdentity());
       
  2715     m5.ortho(0, 300, 150, 150, -2, 3);
       
  2716     QVERIFY(m5.isIdentity());
       
  2717     m5.ortho(0, 300, 150, 0, 2, 2);
       
  2718     QVERIFY(m5.isIdentity());
       
  2719 }
       
  2720 
       
  2721 // Test perspective frustum projections.
       
  2722 void tst_QMatrixNxN::frustum()
       
  2723 {
       
  2724     QMatrix4x4 m1;
       
  2725     m1.frustum(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
       
  2726     QVector3D p1 = m1 * QVector3D(-1.0f, -1.0f, 1.0f);
       
  2727     QVector3D p2 = m1 * QVector3D(1.0f, -1.0f, 1.0f);
       
  2728     QVector3D p3 = m1 * QVector3D(-1.0f, 1.0f, 1.0f);
       
  2729     QVector3D p4 = m1 * QVector3D(1.0f, 1.0f, 1.0f);
       
  2730     QVector3D p5 = m1 * QVector3D(0.0f, 0.0f, 2.0f);
       
  2731     QVERIFY(fuzzyCompare(p1.x(), -1.0f));
       
  2732     QVERIFY(fuzzyCompare(p1.y(), -1.0f));
       
  2733     QVERIFY(fuzzyCompare(p1.z(), -1.0f));
       
  2734     QVERIFY(fuzzyCompare(p2.x(), 1.0f));
       
  2735     QVERIFY(fuzzyCompare(p2.y(), -1.0f));
       
  2736     QVERIFY(fuzzyCompare(p2.z(), -1.0f));
       
  2737     QVERIFY(fuzzyCompare(p3.x(), -1.0f));
       
  2738     QVERIFY(fuzzyCompare(p3.y(), 1.0f));
       
  2739     QVERIFY(fuzzyCompare(p3.z(), -1.0f));
       
  2740     QVERIFY(fuzzyCompare(p4.x(), 1.0f));
       
  2741     QVERIFY(fuzzyCompare(p4.y(), 1.0f));
       
  2742     QVERIFY(fuzzyCompare(p4.z(), -1.0f));
       
  2743     QVERIFY(fuzzyCompare(p5.x(), 0.0f));
       
  2744     QVERIFY(fuzzyCompare(p5.y(), 0.0f));
       
  2745     QVERIFY(fuzzyCompare(p5.z(), -0.5f));
       
  2746 
       
  2747     // An empty view volume should leave the matrix alone.
       
  2748     QMatrix4x4 m5;
       
  2749     m5.frustum(0, 0, 150, 0, -2, 3);
       
  2750     QVERIFY(m5.isIdentity());
       
  2751     m5.frustum(0, 300, 150, 150, -2, 3);
       
  2752     QVERIFY(m5.isIdentity());
       
  2753     m5.frustum(0, 300, 150, 0, 2, 2);
       
  2754     QVERIFY(m5.isIdentity());
       
  2755 }
       
  2756 
       
  2757 // Test perspective field-of-view projections.
       
  2758 void tst_QMatrixNxN::perspective()
       
  2759 {
       
  2760     QMatrix4x4 m1;
       
  2761     m1.perspective(45.0f, 1.0f, -1.0f, 1.0f);
       
  2762     QVector3D p1 = m1 * QVector3D(-1.0f, -1.0f, 1.0f);
       
  2763     QVector3D p2 = m1 * QVector3D(1.0f, -1.0f, 1.0f);
       
  2764     QVector3D p3 = m1 * QVector3D(-1.0f, 1.0f, 1.0f);
       
  2765     QVector3D p4 = m1 * QVector3D(1.0f, 1.0f, 1.0f);
       
  2766     QVector3D p5 = m1 * QVector3D(0.0f, 0.0f, 2.0f);
       
  2767     QVERIFY(fuzzyCompare(p1.x(), 2.41421));
       
  2768     QVERIFY(fuzzyCompare(p1.y(), 2.41421));
       
  2769     QVERIFY(fuzzyCompare(p1.z(), -1));
       
  2770     QVERIFY(fuzzyCompare(p2.x(), -2.41421));
       
  2771     QVERIFY(fuzzyCompare(p2.y(), 2.41421));
       
  2772     QVERIFY(fuzzyCompare(p2.z(), -1.0f));
       
  2773     QVERIFY(fuzzyCompare(p3.x(), 2.41421));
       
  2774     QVERIFY(fuzzyCompare(p3.y(), -2.41421));
       
  2775     QVERIFY(fuzzyCompare(p3.z(), -1.0f));
       
  2776     QVERIFY(fuzzyCompare(p4.x(), -2.41421));
       
  2777     QVERIFY(fuzzyCompare(p4.y(), -2.41421));
       
  2778     QVERIFY(fuzzyCompare(p4.z(), -1.0f));
       
  2779     QVERIFY(fuzzyCompare(p5.x(), 0.0f));
       
  2780     QVERIFY(fuzzyCompare(p5.y(), 0.0f));
       
  2781     QVERIFY(fuzzyCompare(p5.z(), -0.5f));
       
  2782 
       
  2783     // An empty view volume should leave the matrix alone.
       
  2784     QMatrix4x4 m5;
       
  2785     m5.perspective(45.0f, 1.0f, 0.0f, 0.0f);
       
  2786     QVERIFY(m5.isIdentity());
       
  2787     m5.perspective(45.0f, 0.0f, -1.0f, 1.0f);
       
  2788     QVERIFY(m5.isIdentity());
       
  2789     m5.perspective(0.0f, 1.0f, -1.0f, 1.0f);
       
  2790     QVERIFY(m5.isIdentity());
       
  2791 }
       
  2792 
       
  2793 // Test left-handed vs right-handed coordinate flipping.
       
  2794 void tst_QMatrixNxN::flipCoordinates()
       
  2795 {
       
  2796     QMatrix4x4 m1;
       
  2797     m1.flipCoordinates();
       
  2798     QVector3D p1 = m1 * QVector3D(2, 3, 4);
       
  2799     QVERIFY(p1 == QVector3D(2, -3, -4));
       
  2800 
       
  2801     QMatrix4x4 m2;
       
  2802     m2.scale(2.0f, 3.0f, 1.0f);
       
  2803     m2.flipCoordinates();
       
  2804     QVector3D p2 = m2 * QVector3D(2, 3, 4);
       
  2805     QVERIFY(p2 == QVector3D(4, -9, -4));
       
  2806 
       
  2807     QMatrix4x4 m3;
       
  2808     m3.translate(2.0f, 3.0f, 1.0f);
       
  2809     m3.flipCoordinates();
       
  2810     QVector3D p3 = m3 * QVector3D(2, 3, 4);
       
  2811     QVERIFY(p3 == QVector3D(4, 0, -3));
       
  2812 
       
  2813     QMatrix4x4 m4;
       
  2814     m4.rotate(90.0f, 0.0f, 0.0f, 1.0f);
       
  2815     m4.flipCoordinates();
       
  2816     QVector3D p4 = m4 * QVector3D(2, 3, 4);
       
  2817     QVERIFY(p4 == QVector3D(3, 2, -4));
       
  2818 }
       
  2819 
       
  2820 // Test conversion of generic matrices to and from the non-generic types.
       
  2821 void tst_QMatrixNxN::convertGeneric()
       
  2822 {
       
  2823     QMatrix4x3 m1(uniqueValues4x3);
       
  2824 
       
  2825     static qreal const unique4x4[16] = {
       
  2826         1.0f, 2.0f, 3.0f, 4.0f,
       
  2827         5.0f, 6.0f, 7.0f, 8.0f,
       
  2828         9.0f, 10.0f, 11.0f, 12.0f,
       
  2829         0.0f, 0.0f, 0.0f, 1.0f
       
  2830     };
       
  2831 #if !defined(QT_NO_MEMBER_TEMPLATES)
       
  2832     QMatrix4x4 m4(m1);
       
  2833     QVERIFY(isSame(m4, unique4x4));
       
  2834 #endif
       
  2835     QMatrix4x4 m5 = qGenericMatrixToMatrix4x4(m1);
       
  2836     QVERIFY(isSame(m5, unique4x4));
       
  2837 
       
  2838     static qreal const conv4x4[12] = {
       
  2839         1.0f, 2.0f, 3.0f, 4.0f,
       
  2840         5.0f, 6.0f, 7.0f, 8.0f,
       
  2841         9.0f, 10.0f, 11.0f, 12.0f
       
  2842     };
       
  2843     QMatrix4x4 m9(uniqueValues4);
       
  2844 #if !defined(QT_NO_MEMBER_TEMPLATES)
       
  2845     QMatrix4x3 m10 = m9.toGenericMatrix<4, 3>();
       
  2846     QVERIFY(isSame(m10, conv4x4));
       
  2847 #endif
       
  2848 
       
  2849     QMatrix4x3 m11 = qGenericMatrixFromMatrix4x4<4, 3>(m9);
       
  2850     QVERIFY(isSame(m11, conv4x4));
       
  2851 }
       
  2852 
       
  2853 void tst_QMatrixNxN::extractAxisRotation_data()
       
  2854 {
       
  2855     QTest::addColumn<float>("x");
       
  2856     QTest::addColumn<float>("y");
       
  2857     QTest::addColumn<float>("z");
       
  2858     QTest::addColumn<float>("angle");
       
  2859     
       
  2860     QTest::newRow("1, 0, 0, 0 deg") << 1.0f << 0.0f << 0.0f << 0.0f;
       
  2861     QTest::newRow("1, 0, 0, 90 deg") << 1.0f << 0.0f << 0.0f << 90.0f;
       
  2862     QTest::newRow("1, 0, 0, 270 deg") << 1.0f << 0.0f << 0.0f << 270.0f;
       
  2863     QTest::newRow("1, 0, 0, 45 deg") << 1.0f << 0.0f << 0.0f << 45.0f;
       
  2864     QTest::newRow("1, 0, 0, 120 deg") << 1.0f << 0.0f << 0.0f << 120.0f;
       
  2865     QTest::newRow("1, 0, 0, 300 deg") << 1.0f << 0.0f << 0.0f << 300.0f;
       
  2866 
       
  2867     QTest::newRow("0, 1, 0, 90 deg") << 0.0f << 1.0f << 0.0f << 90.0f;
       
  2868     QTest::newRow("0, 1, 0, 270 deg") << 0.0f << 1.0f << 0.0f << 270.0f;
       
  2869     QTest::newRow("0, 1, 0, 45 deg") << 0.0f << 1.0f << 0.0f << 45.0f;
       
  2870     QTest::newRow("0, 1, 0, 120 deg") << 0.0f << 1.0f << 0.0f << 120.0f;
       
  2871     QTest::newRow("0, 1, 0, 300 deg") << 0.0f << 1.0f << 0.0f << 300.0f;
       
  2872     
       
  2873     QTest::newRow("0, 0, 1, 90 deg") << 0.0f << 0.0f << 1.0f << 90.0f;
       
  2874     QTest::newRow("0, 0, 1, 270 deg") << 0.0f << 0.0f << 1.0f << 270.0f;
       
  2875     QTest::newRow("0, 0, 1, 45 deg") << 0.0f << 0.0f << 1.0f << 45.0f;
       
  2876     QTest::newRow("0, 0, 1, 120 deg") << 0.0f << 0.0f << 1.0f << 120.0f;
       
  2877     QTest::newRow("0, 0, 1, 300 deg") << 0.0f << 0.0f << 1.0f << 300.0f;
       
  2878 
       
  2879     QTest::newRow("1, 1, 1, 90 deg") << 1.0f << 1.0f << 1.0f << 90.0f;
       
  2880     QTest::newRow("1, 1, 1, 270 deg") << 1.0f << 1.0f << 1.0f << 270.0f;
       
  2881     QTest::newRow("1, 1, 1, 45 deg") << 1.0f << 1.0f << 1.0f << 45.0f;
       
  2882     QTest::newRow("1, 1, 1, 120 deg") << 1.0f << 1.0f << 1.0f << 120.0f;
       
  2883     QTest::newRow("1, 1, 1, 300 deg") << 1.0f << 1.0f << 1.0f << 300.0f;
       
  2884 }
       
  2885 
       
  2886 void tst_QMatrixNxN::extractAxisRotation()
       
  2887 {
       
  2888     QFETCH(float, x);
       
  2889     QFETCH(float, y);
       
  2890     QFETCH(float, z);
       
  2891     QFETCH(float, angle);
       
  2892 
       
  2893     QMatrix4x4 m;
       
  2894     QVector3D origAxis(x, y, z);
       
  2895 
       
  2896     m.rotate(angle, x, y, z);
       
  2897 
       
  2898     origAxis.normalize();
       
  2899     QVector3D extractedAxis;
       
  2900     qreal extractedAngle;
       
  2901 
       
  2902     m.extractAxisRotation(extractedAngle, extractedAxis);
       
  2903  
       
  2904     if (angle > 180) {
       
  2905         QVERIFY(fuzzyCompare(360.0f - angle, extractedAngle));
       
  2906         QVERIFY(fuzzyCompare(extractedAxis, -origAxis));
       
  2907     } else {
       
  2908         QVERIFY(fuzzyCompare(angle, extractedAngle));
       
  2909         QVERIFY(fuzzyCompare(extractedAxis, origAxis));
       
  2910     }
       
  2911 }
       
  2912 
       
  2913 void tst_QMatrixNxN::extractTranslation_data()
       
  2914 {
       
  2915     QTest::addColumn<QMatrix4x4>("rotation");
       
  2916     QTest::addColumn<float>("x");
       
  2917     QTest::addColumn<float>("y");
       
  2918     QTest::addColumn<float>("z");
       
  2919 
       
  2920     static QMatrix4x4 m1;
       
  2921 
       
  2922     QTest::newRow("identity, 100, 50, 25")
       
  2923         << m1 << 100.0f << 50.0f << 250.0f;
       
  2924 
       
  2925     m1.rotate(45.0, 1.0, 0.0, 0.0);
       
  2926     QTest::newRow("rotX 45 + 100, 50, 25") << m1 << 100.0f << 50.0f << 25.0f;
       
  2927 
       
  2928     m1.setIdentity();
       
  2929     m1.rotate(45.0, 0.0, 1.0, 0.0);
       
  2930     QTest::newRow("rotY 45 + 100, 50, 25") << m1 << 100.0f << 50.0f << 25.0f;
       
  2931 
       
  2932     m1.setIdentity();
       
  2933     m1.rotate(75, 0.0, 0.0, 1.0);
       
  2934     m1.rotate(25, 1.0, 0.0, 0.0);
       
  2935     m1.rotate(45, 0.0, 1.0, 0.0);
       
  2936     QTest::newRow("rotZ 75, rotX 25, rotY 45, 100, 50, 25") << m1 << 100.0f << 50.0f << 25.0f;
       
  2937 }
       
  2938 
       
  2939 void tst_QMatrixNxN::extractTranslation()
       
  2940 {
       
  2941     QFETCH(QMatrix4x4, rotation);
       
  2942     QFETCH(float, x);
       
  2943     QFETCH(float, y);
       
  2944     QFETCH(float, z);
       
  2945 
       
  2946     rotation.translate(x, y, z);
       
  2947 
       
  2948     QVector3D vec = rotation.extractTranslation();
       
  2949 
       
  2950     QVERIFY(fuzzyCompare(vec.x(), x));
       
  2951     QVERIFY(fuzzyCompare(vec.y(), y));
       
  2952     QVERIFY(fuzzyCompare(vec.z(), z));
       
  2953 
       
  2954     QMatrix4x4 lookAt;
       
  2955     QVector3D eye(1.5f, -2.5f, 2.5f);
       
  2956     lookAt.lookAt(eye,
       
  2957                   QVector3D(10.0f, 10.0f, 10.0f), 
       
  2958                   QVector3D(0.0f, 1.0f, 0.0f));
       
  2959 
       
  2960    QVector3D extEye = lookAt.extractTranslation();
       
  2961 
       
  2962    QVERIFY(fuzzyCompare(eye.x(), -extEye.x()));
       
  2963    QVERIFY(fuzzyCompare(eye.y(), -extEye.y()));
       
  2964    QVERIFY(fuzzyCompare(eye.z(), -extEye.z()));
       
  2965 }
       
  2966 
       
  2967 // Copy of "flagBits" in qmatrix4x4.h.
       
  2968 enum {
       
  2969     Identity        = 0x0001,   // Identity matrix
       
  2970     General         = 0x0002,   // General matrix, unknown contents
       
  2971     Translation     = 0x0004,   // Contains a simple translation
       
  2972     Scale           = 0x0008,   // Contains a simple scale
       
  2973     Rotation        = 0x0010    // Contains a simple rotation
       
  2974 };
       
  2975 
       
  2976 // Structure that allows direct access to "flagBits" for testing.
       
  2977 struct Matrix4x4
       
  2978 {
       
  2979     qreal m[4][4];
       
  2980     int flagBits;
       
  2981 };
       
  2982 
       
  2983 // Test the inferring of special matrix types.
       
  2984 void tst_QMatrixNxN::inferSpecialType_data()
       
  2985 {
       
  2986     QTest::addColumn<void *>("mValues");
       
  2987     QTest::addColumn<int>("flagBits");
       
  2988 
       
  2989     QTest::newRow("null")
       
  2990         << (void *)nullValues4 << (int)General;
       
  2991     QTest::newRow("identity")
       
  2992         << (void *)identityValues4 << (int)Identity;
       
  2993     QTest::newRow("unique")
       
  2994         << (void *)uniqueValues4 << (int)General;
       
  2995 
       
  2996     static qreal scaleValues[16] = {
       
  2997         2.0f, 0.0f, 0.0f, 0.0f,
       
  2998         0.0f, 3.0f, 0.0f, 0.0f,
       
  2999         0.0f, 0.0f, 4.0f, 0.0f,
       
  3000         0.0f, 0.0f, 0.0f, 1.0f
       
  3001     };
       
  3002     QTest::newRow("scale")
       
  3003         << (void *)scaleValues << (int)Scale;
       
  3004 
       
  3005     static qreal translateValues[16] = {
       
  3006         1.0f, 0.0f, 0.0f, 2.0f,
       
  3007         0.0f, 1.0f, 0.0f, 3.0f,
       
  3008         0.0f, 0.0f, 1.0f, 4.0f,
       
  3009         0.0f, 0.0f, 0.0f, 1.0f
       
  3010     };
       
  3011     QTest::newRow("scale")
       
  3012         << (void *)translateValues << (int)Translation;
       
  3013 
       
  3014     static qreal bothValues[16] = {
       
  3015         1.0f, 0.0f, 0.0f, 2.0f,
       
  3016         0.0f, 2.0f, 0.0f, 0.0f,
       
  3017         0.0f, 0.0f, 1.0f, 4.0f,
       
  3018         0.0f, 0.0f, 0.0f, 1.0f
       
  3019     };
       
  3020     QTest::newRow("both")
       
  3021         << (void *)bothValues << (int)(Scale | Translation);
       
  3022 
       
  3023     static qreal belowValues[16] = {
       
  3024         1.0f, 0.0f, 0.0f, 0.0f,
       
  3025         0.0f, 1.0f, 0.0f, 0.0f,
       
  3026         0.0f, 0.0f, 1.0f, 0.0f,
       
  3027         4.0f, 0.0f, 0.0f, 1.0f
       
  3028     };
       
  3029     QTest::newRow("below")
       
  3030         << (void *)belowValues << (int)General;
       
  3031 }
       
  3032 void tst_QMatrixNxN::inferSpecialType()
       
  3033 {
       
  3034     QFETCH(void *, mValues);
       
  3035     QFETCH(int, flagBits);
       
  3036 
       
  3037     QMatrix4x4 m((const qreal *)mValues);
       
  3038     m.inferSpecialType();
       
  3039 
       
  3040     QCOMPARE(reinterpret_cast<Matrix4x4 *>(&m)->flagBits, flagBits);
       
  3041 }
       
  3042 
       
  3043 void tst_QMatrixNxN::columnsAndRows()
       
  3044 {
       
  3045     QMatrix4x4 m1(uniqueValues4);
       
  3046 
       
  3047     QVERIFY(m1.column(0) == QVector4D(1, 5, 9, 13));
       
  3048     QVERIFY(m1.column(1) == QVector4D(2, 6, 10, 14));
       
  3049     QVERIFY(m1.column(2) == QVector4D(3, 7, 11, 15));
       
  3050     QVERIFY(m1.column(3) == QVector4D(4, 8, 12, 16));
       
  3051 
       
  3052     QVERIFY(m1.row(0) == QVector4D(1, 2, 3, 4));
       
  3053     QVERIFY(m1.row(1) == QVector4D(5, 6, 7, 8));
       
  3054     QVERIFY(m1.row(2) == QVector4D(9, 10, 11, 12));
       
  3055     QVERIFY(m1.row(3) == QVector4D(13, 14, 15, 16));
       
  3056 
       
  3057     m1.setColumn(0, QVector4D(-1, -5, -9, -13));
       
  3058     m1.setColumn(1, QVector4D(-2, -6, -10, -14));
       
  3059     m1.setColumn(2, QVector4D(-3, -7, -11, -15));
       
  3060     m1.setColumn(3, QVector4D(-4, -8, -12, -16));
       
  3061 
       
  3062     QVERIFY(m1.column(0) == QVector4D(-1, -5, -9, -13));
       
  3063     QVERIFY(m1.column(1) == QVector4D(-2, -6, -10, -14));
       
  3064     QVERIFY(m1.column(2) == QVector4D(-3, -7, -11, -15));
       
  3065     QVERIFY(m1.column(3) == QVector4D(-4, -8, -12, -16));
       
  3066 
       
  3067     QVERIFY(m1.row(0) == QVector4D(-1, -2, -3, -4));
       
  3068     QVERIFY(m1.row(1) == QVector4D(-5, -6, -7, -8));
       
  3069     QVERIFY(m1.row(2) == QVector4D(-9, -10, -11, -12));
       
  3070     QVERIFY(m1.row(3) == QVector4D(-13, -14, -15, -16));
       
  3071 
       
  3072     m1.setRow(0, QVector4D(1, 5, 9, 13));
       
  3073     m1.setRow(1, QVector4D(2, 6, 10, 14));
       
  3074     m1.setRow(2, QVector4D(3, 7, 11, 15));
       
  3075     m1.setRow(3, QVector4D(4, 8, 12, 16));
       
  3076 
       
  3077     QVERIFY(m1.column(0) == QVector4D(1, 2, 3, 4));
       
  3078     QVERIFY(m1.column(1) == QVector4D(5, 6, 7, 8));
       
  3079     QVERIFY(m1.column(2) == QVector4D(9, 10, 11, 12));
       
  3080     QVERIFY(m1.column(3) == QVector4D(13, 14, 15, 16));
       
  3081 
       
  3082     QVERIFY(m1.row(0) == QVector4D(1, 5, 9, 13));
       
  3083     QVERIFY(m1.row(1) == QVector4D(2, 6, 10, 14));
       
  3084     QVERIFY(m1.row(2) == QVector4D(3, 7, 11, 15));
       
  3085     QVERIFY(m1.row(3) == QVector4D(4, 8, 12, 16));
       
  3086 }
       
  3087 
       
  3088 // Test converting QMatrix objects into QMatrix4x4 and then
       
  3089 // checking that transformations in the original perform the
       
  3090 // equivalent transformations in the new matrix.
       
  3091 void tst_QMatrixNxN::convertQMatrix()
       
  3092 {
       
  3093     QMatrix m1;
       
  3094     m1.translate(-3.5, 2.0);
       
  3095     QPointF p1 = m1.map(QPointF(100.0, 150.0));
       
  3096     QCOMPARE(p1.x(), 100.0 - 3.5);
       
  3097     QCOMPARE(p1.y(), 150.0 + 2.0);
       
  3098 
       
  3099     QMatrix4x4 m2(m1);
       
  3100     QPointF p2 = m2 * QPointF(100.0, 150.0);
       
  3101     QCOMPARE((double)p2.x(), 100.0 - 3.5);
       
  3102     QCOMPARE((double)p2.y(), 150.0 + 2.0);
       
  3103     QVERIFY(m1 == m2.toAffine());
       
  3104 
       
  3105     QMatrix m3;
       
  3106     m3.scale(1.5, -2.0);
       
  3107     QPointF p3 = m3.map(QPointF(100.0, 150.0));
       
  3108     QCOMPARE(p3.x(), 1.5 * 100.0);
       
  3109     QCOMPARE(p3.y(), -2.0 * 150.0);
       
  3110 
       
  3111     QMatrix4x4 m4(m3);
       
  3112     QPointF p4 = m4 * QPointF(100.0, 150.0);
       
  3113     QCOMPARE((double)p4.x(), 1.5 * 100.0);
       
  3114     QCOMPARE((double)p4.y(), -2.0 * 150.0);
       
  3115     QVERIFY(m3 == m4.toAffine());
       
  3116 
       
  3117     QMatrix m5;
       
  3118     m5.rotate(45.0);
       
  3119     QPointF p5 = m5.map(QPointF(100.0, 150.0));
       
  3120 
       
  3121     QMatrix4x4 m6(m5);
       
  3122     QPointF p6 = m6 * QPointF(100.0, 150.0);
       
  3123     QVERIFY(fuzzyCompare(p5.x(), p6.x()));
       
  3124     QVERIFY(fuzzyCompare(p5.y(), p6.y()));
       
  3125 
       
  3126     QMatrix m7 = m6.toAffine();
       
  3127     QVERIFY(fuzzyCompare(m5.m11(), m7.m11()));
       
  3128     QVERIFY(fuzzyCompare(m5.m12(), m7.m12()));
       
  3129     QVERIFY(fuzzyCompare(m5.m21(), m7.m21()));
       
  3130     QVERIFY(fuzzyCompare(m5.m22(), m7.m22()));
       
  3131     QVERIFY(fuzzyCompare(m5.dx(), m7.dx()));
       
  3132     QVERIFY(fuzzyCompare(m5.dy(), m7.dy()));
       
  3133 }
       
  3134 
       
  3135 // Test converting QTransform objects into QMatrix4x4 and then
       
  3136 // checking that transformations in the original perform the
       
  3137 // equivalent transformations in the new matrix.
       
  3138 void tst_QMatrixNxN::convertQTransform()
       
  3139 {
       
  3140     QTransform m1;
       
  3141     m1.translate(-3.5, 2.0);
       
  3142     QPointF p1 = m1.map(QPointF(100.0, 150.0));
       
  3143     QCOMPARE(p1.x(), 100.0 - 3.5);
       
  3144     QCOMPARE(p1.y(), 150.0 + 2.0);
       
  3145 
       
  3146     QMatrix4x4 m2(m1);
       
  3147     QPointF p2 = m2 * QPointF(100.0, 150.0);
       
  3148     QCOMPARE((double)p2.x(), 100.0 - 3.5);
       
  3149     QCOMPARE((double)p2.y(), 150.0 + 2.0);
       
  3150     QVERIFY(m1 == m2.toTransform());
       
  3151 
       
  3152     QTransform m3;
       
  3153     m3.scale(1.5, -2.0);
       
  3154     QPointF p3 = m3.map(QPointF(100.0, 150.0));
       
  3155     QCOMPARE(p3.x(), 1.5 * 100.0);
       
  3156     QCOMPARE(p3.y(), -2.0 * 150.0);
       
  3157 
       
  3158     QMatrix4x4 m4(m3);
       
  3159     QPointF p4 = m4 * QPointF(100.0, 150.0);
       
  3160     QCOMPARE((double)p4.x(), 1.5 * 100.0);
       
  3161     QCOMPARE((double)p4.y(), -2.0 * 150.0);
       
  3162     QVERIFY(m3 == m4.toTransform());
       
  3163 
       
  3164     QTransform m5;
       
  3165     m5.rotate(45.0);
       
  3166     QPointF p5 = m5.map(QPointF(100.0, 150.0));
       
  3167 
       
  3168     QMatrix4x4 m6(m5);
       
  3169     QPointF p6 = m6 * QPointF(100.0, 150.0);
       
  3170     QVERIFY(fuzzyCompare(p5.x(), p6.x()));
       
  3171     QVERIFY(fuzzyCompare(p5.y(), p6.y()));
       
  3172 
       
  3173     QTransform m7 = m6.toTransform();
       
  3174     QVERIFY(fuzzyCompare(m5.m11(), m7.m11()));
       
  3175     QVERIFY(fuzzyCompare(m5.m12(), m7.m12()));
       
  3176     QVERIFY(fuzzyCompare(m5.m21(), m7.m21()));
       
  3177     QVERIFY(fuzzyCompare(m5.m22(), m7.m22()));
       
  3178     QVERIFY(fuzzyCompare(m5.dx(), m7.dx()));
       
  3179     QVERIFY(fuzzyCompare(m5.dy(), m7.dy()));
       
  3180     QVERIFY(fuzzyCompare(m5.m13(), m7.m13()));
       
  3181     QVERIFY(fuzzyCompare(m5.m23(), m7.m23()));
       
  3182     QVERIFY(fuzzyCompare(m5.m33(), m7.m33()));
       
  3183 }
       
  3184 
       
  3185 // Test filling matrices with specific values.
       
  3186 void tst_QMatrixNxN::fill()
       
  3187 {
       
  3188     QMatrix4x4 m1;
       
  3189     m1.fill(0.0f);
       
  3190     QVERIFY(isSame(m1, nullValues4));
       
  3191 
       
  3192     static const qreal fillValues4[] =
       
  3193         {2.5f, 2.5f, 2.5f, 2.5f,
       
  3194          2.5f, 2.5f, 2.5f, 2.5f,
       
  3195          2.5f, 2.5f, 2.5f, 2.5f,
       
  3196          2.5f, 2.5f, 2.5f, 2.5f};
       
  3197     m1.fill(2.5f);
       
  3198     QVERIFY(isSame(m1, fillValues4));
       
  3199 
       
  3200     QMatrix4x3 m2;
       
  3201     m2.fill(0.0f);
       
  3202     QVERIFY(isSame(m2, nullValues4x3));
       
  3203 
       
  3204     static const qreal fillValues4x3[] =
       
  3205         {2.5f, 2.5f, 2.5f, 2.5f,
       
  3206          2.5f, 2.5f, 2.5f, 2.5f,
       
  3207          2.5f, 2.5f, 2.5f, 2.5f};
       
  3208     m2.fill(2.5f);
       
  3209     QVERIFY(isSame(m2, fillValues4x3));
       
  3210 }
       
  3211 
       
  3212 // Test the mapRect() function for QRect and QRectF.
       
  3213 void tst_QMatrixNxN::mapRect_data()
       
  3214 {
       
  3215     QTest::addColumn<qreal>("x");
       
  3216     QTest::addColumn<qreal>("y");
       
  3217     QTest::addColumn<qreal>("width");
       
  3218     QTest::addColumn<qreal>("height");
       
  3219 
       
  3220     QTest::newRow("null")
       
  3221         << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f << (qreal)0.0f;
       
  3222     QTest::newRow("rect")
       
  3223         << (qreal)1.0f << (qreal)-20.5f << (qreal)100.0f << (qreal)63.75f;
       
  3224 }
       
  3225 void tst_QMatrixNxN::mapRect()
       
  3226 {
       
  3227     QFETCH(qreal, x);
       
  3228     QFETCH(qreal, y);
       
  3229     QFETCH(qreal, width);
       
  3230     QFETCH(qreal, height);
       
  3231 
       
  3232     QRectF rect(x, y, width, height);
       
  3233     QRect recti(qRound(x), qRound(y), qRound(width), qRound(height));
       
  3234 
       
  3235     QMatrix4x4 m1;
       
  3236     QVERIFY(m1.mapRect(rect) == rect);
       
  3237     QVERIFY(m1.mapRect(recti) == recti);
       
  3238 
       
  3239     QMatrix4x4 m2;
       
  3240     m2.translate(-100.5f, 64.0f);
       
  3241     QRectF translated = rect.translated(-100.5f, 64.0f);
       
  3242     QRect translatedi = QRect(qRound(recti.x() - 100.5f), recti.y() + 64,
       
  3243                               recti.width(), recti.height());
       
  3244     QVERIFY(m2.mapRect(rect) == translated);
       
  3245     QVERIFY(m2.mapRect(recti) == translatedi);
       
  3246 
       
  3247     QMatrix4x4 m3;
       
  3248     m3.scale(-100.5f, 64.0f);
       
  3249     qreal scalex = x * -100.5f;
       
  3250     qreal scaley = y * 64.0f;
       
  3251     qreal scalewid = width * -100.5f;
       
  3252     qreal scaleht = height * 64.0f;
       
  3253     if (scalewid < 0.0f) {
       
  3254         scalewid = -scalewid;
       
  3255         scalex -= scalewid;
       
  3256     }
       
  3257     if (scaleht < 0.0f) {
       
  3258         scaleht = -scaleht;
       
  3259         scaley -= scaleht;
       
  3260     }
       
  3261     QRectF scaled(scalex, scaley, scalewid, scaleht);
       
  3262     QVERIFY(m3.mapRect(rect) == scaled);
       
  3263     scalex = recti.x() * -100.5f;
       
  3264     scaley = recti.y() * 64.0f;
       
  3265     scalewid = recti.width() * -100.5f;
       
  3266     scaleht = recti.height() * 64.0f;
       
  3267     if (scalewid < 0.0f) {
       
  3268         scalewid = -scalewid;
       
  3269         scalex -= scalewid;
       
  3270     }
       
  3271     if (scaleht < 0.0f) {
       
  3272         scaleht = -scaleht;
       
  3273         scaley -= scaleht;
       
  3274     }
       
  3275     QRect scaledi(qRound(scalex), qRound(scaley),
       
  3276                   qRound(scalewid), qRound(scaleht));
       
  3277     QVERIFY(m3.mapRect(recti) == scaledi);
       
  3278 
       
  3279     QMatrix4x4 m4;
       
  3280     m4.translate(-100.5f, 64.0f);
       
  3281     m4.scale(-2.5f, 4.0f);
       
  3282     qreal transx1 = x * -2.5f - 100.5f;
       
  3283     qreal transy1 = y * 4.0f + 64.0f;
       
  3284     qreal transx2 = (x + width) * -2.5f - 100.5f;
       
  3285     qreal transy2 = (y + height) * 4.0f + 64.0f;
       
  3286     if (transx1 > transx2)
       
  3287         qSwap(transx1, transx2);
       
  3288     if (transy1 > transy2)
       
  3289         qSwap(transy1, transy2);
       
  3290     QRectF trans(transx1, transy1, transx2 - transx1, transy2 - transy1);
       
  3291     QVERIFY(m4.mapRect(rect) == trans);
       
  3292     transx1 = recti.x() * -2.5f - 100.5f;
       
  3293     transy1 = recti.y() * 4.0f + 64.0f;
       
  3294     transx2 = (recti.x() + recti.width()) * -2.5f - 100.5f;
       
  3295     transy2 = (recti.y() + recti.height()) * 4.0f + 64.0f;
       
  3296     if (transx1 > transx2)
       
  3297         qSwap(transx1, transx2);
       
  3298     if (transy1 > transy2)
       
  3299         qSwap(transy1, transy2);
       
  3300     QRect transi(qRound(transx1), qRound(transy1),
       
  3301                  qRound(transx2) - qRound(transx1),
       
  3302                  qRound(transy2) - qRound(transy1));
       
  3303     QVERIFY(m4.mapRect(recti) == transi);
       
  3304 
       
  3305     m4.rotate(45.0f, 0.0f, 0.0f, 1.0f);
       
  3306 
       
  3307     QTransform t4;
       
  3308     t4.translate(-100.5f, 64.0f);
       
  3309     t4.scale(-2.5f, 4.0f);
       
  3310     t4.rotate(45.0f);
       
  3311     QRectF mr = m4.mapRect(rect);
       
  3312     QRectF tr = t4.mapRect(rect);
       
  3313     QVERIFY(fuzzyCompare(mr.x(), tr.x()));
       
  3314     QVERIFY(fuzzyCompare(mr.y(), tr.y()));
       
  3315     QVERIFY(fuzzyCompare(mr.width(), tr.width()));
       
  3316     QVERIFY(fuzzyCompare(mr.height(), tr.height()));
       
  3317 
       
  3318     QRect mri = m4.mapRect(recti);
       
  3319     QRect tri = t4.mapRect(recti);
       
  3320     QVERIFY(mri == tri);
       
  3321 }
       
  3322 
       
  3323 void tst_QMatrixNxN::mapVector_data()
       
  3324 {
       
  3325     QTest::addColumn<void *>("mValues");
       
  3326 
       
  3327     QTest::newRow("null")
       
  3328         << (void *)nullValues4;
       
  3329 
       
  3330     QTest::newRow("identity")
       
  3331         << (void *)identityValues4;
       
  3332 
       
  3333     QTest::newRow("unique")
       
  3334         << (void *)uniqueValues4;
       
  3335 
       
  3336     static const qreal scale[] =
       
  3337         {2.0f, 0.0f, 0.0f, 0.0f,
       
  3338          0.0f, 11.0f, 0.0f, 0.0f,
       
  3339          0.0f, 0.0f, -6.5f, 0.0f,
       
  3340          0.0f, 0.0f, 0.0f, 1.0f};
       
  3341     QTest::newRow("scale")
       
  3342         << (void *)scale;
       
  3343 
       
  3344     static const qreal scaleTranslate[] =
       
  3345         {2.0f, 0.0f, 0.0f, 1.0f,
       
  3346          0.0f, 11.0f, 0.0f, 2.0f,
       
  3347          0.0f, 0.0f, -6.5f, 3.0f,
       
  3348          0.0f, 0.0f, 0.0f, 1.0f};
       
  3349     QTest::newRow("scaleTranslate")
       
  3350         << (void *)scaleTranslate;
       
  3351 
       
  3352     static const qreal translate[] =
       
  3353         {1.0f, 0.0f, 0.0f, 1.0f,
       
  3354          0.0f, 1.0f, 0.0f, 2.0f,
       
  3355          0.0f, 0.0f, 1.0f, 3.0f,
       
  3356          0.0f, 0.0f, 0.0f, 1.0f};
       
  3357     QTest::newRow("translate")
       
  3358         << (void *)translate;
       
  3359 }
       
  3360 void tst_QMatrixNxN::mapVector()
       
  3361 {
       
  3362     QFETCH(void *, mValues);
       
  3363 
       
  3364     QMatrix4x4 m1((const qreal *)mValues);
       
  3365     m1.inferSpecialType();
       
  3366 
       
  3367     QVector3D v(3.5f, -1.0f, 2.5f);
       
  3368 
       
  3369     QVector3D expected
       
  3370         (v.x() * m1(0, 0) + v.y() * m1(0, 1) + v.z() * m1(0, 2),
       
  3371          v.x() * m1(1, 0) + v.y() * m1(1, 1) + v.z() * m1(1, 2),
       
  3372          v.x() * m1(2, 0) + v.y() * m1(2, 1) + v.z() * m1(2, 2));
       
  3373 
       
  3374     QVector3D actual = m1.mapVector(v);
       
  3375 
       
  3376     QVERIFY(fuzzyCompare(actual.x(), expected.x()));
       
  3377     QVERIFY(fuzzyCompare(actual.y(), expected.y()));
       
  3378     QVERIFY(fuzzyCompare(actual.z(), expected.z()));
       
  3379 }
       
  3380 
       
  3381 class tst_QMatrixNxN4x4Properties : public QObject
       
  3382 {
       
  3383     Q_OBJECT
       
  3384     Q_PROPERTY(QMatrix4x4 matrix READ matrix WRITE setMatrix)
       
  3385 public:
       
  3386     tst_QMatrixNxN4x4Properties(QObject *parent = 0) : QObject(parent) {}
       
  3387 
       
  3388     QMatrix4x4 matrix() const { return m; }
       
  3389     void setMatrix(const QMatrix4x4& value) { m = value; }
       
  3390 
       
  3391 private:
       
  3392     QMatrix4x4 m;
       
  3393 };
       
  3394 
       
  3395 // Test getting and setting matrix properties via the metaobject system.
       
  3396 void tst_QMatrixNxN::properties()
       
  3397 {
       
  3398     tst_QMatrixNxN4x4Properties obj;
       
  3399 
       
  3400     QMatrix4x4 m1(uniqueValues4);
       
  3401     obj.setMatrix(m1);
       
  3402 
       
  3403     QMatrix4x4 m2 = qVariantValue<QMatrix4x4>(obj.property("matrix"));
       
  3404     QVERIFY(isSame(m2, uniqueValues4));
       
  3405 
       
  3406     QMatrix4x4 m3(transposedValues4);
       
  3407     obj.setProperty("matrix", qVariantFromValue(m3));
       
  3408 
       
  3409     m2 = qVariantValue<QMatrix4x4>(obj.property("matrix"));
       
  3410     QVERIFY(isSame(m2, transposedValues4));
       
  3411 }
       
  3412 
       
  3413 void tst_QMatrixNxN::metaTypes()
       
  3414 {
       
  3415     QVERIFY(QMetaType::type("QMatrix4x4") == QMetaType::QMatrix4x4);
       
  3416 
       
  3417     QCOMPARE(QByteArray(QMetaType::typeName(QMetaType::QMatrix4x4)),
       
  3418              QByteArray("QMatrix4x4"));
       
  3419 
       
  3420     QVERIFY(QMetaType::isRegistered(QMetaType::QMatrix4x4));
       
  3421 
       
  3422     QVERIFY(qMetaTypeId<QMatrix4x4>() == QMetaType::QMatrix4x4);
       
  3423 }
       
  3424 
       
  3425 QTEST_APPLESS_MAIN(tst_QMatrixNxN)
       
  3426 
       
  3427 #include "tst_qmatrixnxn.moc"