1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QMATRIX4X4_H
41#define QMATRIX4X4_H
42
43#include <QtGui/qtguiglobal.h>
44#include <QtGui/qvector3d.h>
45#include <QtGui/qvector4d.h>
46#include <QtGui/qquaternion.h>
47#include <QtGui/qgenericmatrix.h>
48#include <QtCore/qrect.h>
49
50QT_BEGIN_NAMESPACE
51
52
53#ifndef QT_NO_MATRIX4X4
54
55class QMatrix;
56class QTransform;
57class QVariant;
58
59class Q_GUI_EXPORT QMatrix4x4
60{
61public:
62 inline QMatrix4x4() { setToIdentity(); }
63 explicit QMatrix4x4(Qt::Initialization) : flagBits(General) {}
64 explicit QMatrix4x4(const float *values);
65 inline QMatrix4x4(float m11, float m12, float m13, float m14,
66 float m21, float m22, float m23, float m24,
67 float m31, float m32, float m33, float m34,
68 float m41, float m42, float m43, float m44);
69
70 template <int N, int M>
71 explicit QMatrix4x4(const QGenericMatrix<N, M, float>& matrix);
72
73 QMatrix4x4(const float *values, int cols, int rows);
74 QMatrix4x4(const QTransform& transform);
75 QMatrix4x4(const QMatrix& matrix);
76
77 inline const float& operator()(int row, int column) const;
78 inline float& operator()(int row, int column);
79
80#ifndef QT_NO_VECTOR4D
81 inline QVector4D column(int index) const;
82 inline void setColumn(int index, const QVector4D& value);
83
84 inline QVector4D row(int index) const;
85 inline void setRow(int index, const QVector4D& value);
86#endif
87
88 inline bool isAffine() const;
89
90 inline bool isIdentity() const;
91 inline void setToIdentity();
92
93 inline void fill(float value);
94
95 double determinant() const;
96 QMatrix4x4 inverted(bool *invertible = nullptr) const;
97 QMatrix4x4 transposed() const;
98 QMatrix3x3 normalMatrix() const;
99
100 inline QMatrix4x4& operator+=(const QMatrix4x4& other);
101 inline QMatrix4x4& operator-=(const QMatrix4x4& other);
102 inline QMatrix4x4& operator*=(const QMatrix4x4& other);
103 inline QMatrix4x4& operator*=(float factor);
104 QMatrix4x4& operator/=(float divisor);
105 inline bool operator==(const QMatrix4x4& other) const;
106 inline bool operator!=(const QMatrix4x4& other) const;
107
108 friend QMatrix4x4 operator+(const QMatrix4x4& m1, const QMatrix4x4& m2);
109 friend QMatrix4x4 operator-(const QMatrix4x4& m1, const QMatrix4x4& m2);
110 friend QMatrix4x4 operator*(const QMatrix4x4& m1, const QMatrix4x4& m2);
111#ifndef QT_NO_VECTOR3D
112 friend QVector3D operator*(const QMatrix4x4& matrix, const QVector3D& vector);
113 friend QVector3D operator*(const QVector3D& vector, const QMatrix4x4& matrix);
114#endif
115#ifndef QT_NO_VECTOR4D
116 friend QVector4D operator*(const QVector4D& vector, const QMatrix4x4& matrix);
117 friend QVector4D operator*(const QMatrix4x4& matrix, const QVector4D& vector);
118#endif
119 friend QPoint operator*(const QPoint& point, const QMatrix4x4& matrix);
120 friend QPointF operator*(const QPointF& point, const QMatrix4x4& matrix);
121 friend QMatrix4x4 operator-(const QMatrix4x4& matrix);
122 friend QPoint operator*(const QMatrix4x4& matrix, const QPoint& point);
123 friend QPointF operator*(const QMatrix4x4& matrix, const QPointF& point);
124 friend QMatrix4x4 operator*(float factor, const QMatrix4x4& matrix);
125 friend QMatrix4x4 operator*(const QMatrix4x4& matrix, float factor);
126 friend Q_GUI_EXPORT QMatrix4x4 operator/(const QMatrix4x4& matrix, float divisor);
127
128 friend inline bool qFuzzyCompare(const QMatrix4x4& m1, const QMatrix4x4& m2);
129
130#ifndef QT_NO_VECTOR3D
131 void scale(const QVector3D& vector);
132 void translate(const QVector3D& vector);
133 void rotate(float angle, const QVector3D& vector);
134#endif
135 void scale(float x, float y);
136 void scale(float x, float y, float z);
137 void scale(float factor);
138 void translate(float x, float y);
139 void translate(float x, float y, float z);
140 void rotate(float angle, float x, float y, float z = 0.0f);
141#ifndef QT_NO_QUATERNION
142 void rotate(const QQuaternion& quaternion);
143#endif
144
145 void ortho(const QRect& rect);
146 void ortho(const QRectF& rect);
147 void ortho(float left, float right, float bottom, float top, float nearPlane, float farPlane);
148 void frustum(float left, float right, float bottom, float top, float nearPlane, float farPlane);
149 void perspective(float verticalAngle, float aspectRatio, float nearPlane, float farPlane);
150#ifndef QT_NO_VECTOR3D
151 void lookAt(const QVector3D& eye, const QVector3D& center, const QVector3D& up);
152#endif
153 void viewport(const QRectF &rect);
154 void viewport(float left, float bottom, float width, float height, float nearPlane = 0.0f, float farPlane = 1.0f);
155 void flipCoordinates();
156
157 void copyDataTo(float *values) const;
158
159 QMatrix toAffine() const;
160 QTransform toTransform() const;
161 QTransform toTransform(float distanceToPlane) const;
162
163 QPoint map(const QPoint& point) const;
164 QPointF map(const QPointF& point) const;
165#ifndef QT_NO_VECTOR3D
166 QVector3D map(const QVector3D& point) const;
167 QVector3D mapVector(const QVector3D& vector) const;
168#endif
169#ifndef QT_NO_VECTOR4D
170 QVector4D map(const QVector4D& point) const;
171#endif
172 QRect mapRect(const QRect& rect) const;
173 QRectF mapRect(const QRectF& rect) const;
174
175 template <int N, int M>
176 QGenericMatrix<N, M, float> toGenericMatrix() const;
177
178 inline float *data();
179 inline const float *data() const { return *m; }
180 inline const float *constData() const { return *m; }
181
182 void optimize();
183
184 operator QVariant() const;
185
186#ifndef QT_NO_DEBUG_STREAM
187 friend Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QMatrix4x4 &m);
188#endif
189
190private:
191 float m[4][4]; // Column-major order to match OpenGL.
192 int flagBits; // Flag bits from the enum below.
193
194 // When matrices are multiplied, the flag bits are or-ed together.
195 enum {
196 Identity = 0x0000, // Identity matrix
197 Translation = 0x0001, // Contains a translation
198 Scale = 0x0002, // Contains a scale
199 Rotation2D = 0x0004, // Contains a rotation about the Z axis
200 Rotation = 0x0008, // Contains an arbitrary rotation
201 Perspective = 0x0010, // Last row is different from (0, 0, 0, 1)
202 General = 0x001f // General matrix, unknown contents
203 };
204
205 // Construct without initializing identity matrix.
206 explicit QMatrix4x4(int) { }
207
208 QMatrix4x4 orthonormalInverse() const;
209
210 void projectedRotate(float angle, float x, float y, float z);
211
212 friend class QGraphicsRotation;
213};
214
215QT_WARNING_PUSH
216QT_WARNING_DISABLE_CLANG("-Wfloat-equal")
217QT_WARNING_DISABLE_GCC("-Wfloat-equal")
218Q_DECLARE_TYPEINFO(QMatrix4x4, Q_MOVABLE_TYPE);
219
220inline QMatrix4x4::QMatrix4x4
221 (float m11, float m12, float m13, float m14,
222 float m21, float m22, float m23, float m24,
223 float m31, float m32, float m33, float m34,
224 float m41, float m42, float m43, float m44)
225{
226 m[0][0] = m11; m[0][1] = m21; m[0][2] = m31; m[0][3] = m41;
227 m[1][0] = m12; m[1][1] = m22; m[1][2] = m32; m[1][3] = m42;
228 m[2][0] = m13; m[2][1] = m23; m[2][2] = m33; m[2][3] = m43;
229 m[3][0] = m14; m[3][1] = m24; m[3][2] = m34; m[3][3] = m44;
230 flagBits = General;
231}
232
233template <int N, int M>
234Q_INLINE_TEMPLATE QMatrix4x4::QMatrix4x4
235 (const QGenericMatrix<N, M, float>& matrix)
236{
237 const float *values = matrix.constData();
238 for (int matrixCol = 0; matrixCol < 4; ++matrixCol) {
239 for (int matrixRow = 0; matrixRow < 4; ++matrixRow) {
240 if (matrixCol < N && matrixRow < M)
241 m[matrixCol][matrixRow] = values[matrixCol * M + matrixRow];
242 else if (matrixCol == matrixRow)
243 m[matrixCol][matrixRow] = 1.0f;
244 else
245 m[matrixCol][matrixRow] = 0.0f;
246 }
247 }
248 flagBits = General;
249}
250
251template <int N, int M>
252QGenericMatrix<N, M, float> QMatrix4x4::toGenericMatrix() const
253{
254 QGenericMatrix<N, M, float> result;
255 float *values = result.data();
256 for (int matrixCol = 0; matrixCol < N; ++matrixCol) {
257 for (int matrixRow = 0; matrixRow < M; ++matrixRow) {
258 if (matrixCol < 4 && matrixRow < 4)
259 values[matrixCol * M + matrixRow] = m[matrixCol][matrixRow];
260 else if (matrixCol == matrixRow)
261 values[matrixCol * M + matrixRow] = 1.0f;
262 else
263 values[matrixCol * M + matrixRow] = 0.0f;
264 }
265 }
266 return result;
267}
268
269inline const float& QMatrix4x4::operator()(int aRow, int aColumn) const
270{
271 Q_ASSERT(aRow >= 0 && aRow < 4 && aColumn >= 0 && aColumn < 4);
272 return m[aColumn][aRow];
273}
274
275inline float& QMatrix4x4::operator()(int aRow, int aColumn)
276{
277 Q_ASSERT(aRow >= 0 && aRow < 4 && aColumn >= 0 && aColumn < 4);
278 flagBits = General;
279 return m[aColumn][aRow];
280}
281
282#ifndef QT_NO_VECTOR4D
283inline QVector4D QMatrix4x4::column(int index) const
284{
285 Q_ASSERT(index >= 0 && index < 4);
286 return QVector4D(m[index][0], m[index][1], m[index][2], m[index][3]);
287}
288
289inline void QMatrix4x4::setColumn(int index, const QVector4D& value)
290{
291 Q_ASSERT(index >= 0 && index < 4);
292 m[index][0] = value.x();
293 m[index][1] = value.y();
294 m[index][2] = value.z();
295 m[index][3] = value.w();
296 flagBits = General;
297}
298
299inline QVector4D QMatrix4x4::row(int index) const
300{
301 Q_ASSERT(index >= 0 && index < 4);
302 return QVector4D(m[0][index], m[1][index], m[2][index], m[3][index]);
303}
304
305inline void QMatrix4x4::setRow(int index, const QVector4D& value)
306{
307 Q_ASSERT(index >= 0 && index < 4);
308 m[0][index] = value.x();
309 m[1][index] = value.y();
310 m[2][index] = value.z();
311 m[3][index] = value.w();
312 flagBits = General;
313}
314#endif
315
316Q_GUI_EXPORT QMatrix4x4 operator/(const QMatrix4x4& matrix, float divisor);
317
318inline bool QMatrix4x4::isAffine() const
319{
320 return m[0][3] == 0.0f && m[1][3] == 0.0f && m[2][3] == 0.0f && m[3][3] == 1.0f;
321}
322
323inline bool QMatrix4x4::isIdentity() const
324{
325 if (flagBits == Identity)
326 return true;
327 if (m[0][0] != 1.0f || m[0][1] != 0.0f || m[0][2] != 0.0f)
328 return false;
329 if (m[0][3] != 0.0f || m[1][0] != 0.0f || m[1][1] != 1.0f)
330 return false;
331 if (m[1][2] != 0.0f || m[1][3] != 0.0f || m[2][0] != 0.0f)
332 return false;
333 if (m[2][1] != 0.0f || m[2][2] != 1.0f || m[2][3] != 0.0f)
334 return false;
335 if (m[3][0] != 0.0f || m[3][1] != 0.0f || m[3][2] != 0.0f)
336 return false;
337 return (m[3][3] == 1.0f);
338}
339
340inline void QMatrix4x4::setToIdentity()
341{
342 m[0][0] = 1.0f;
343 m[0][1] = 0.0f;
344 m[0][2] = 0.0f;
345 m[0][3] = 0.0f;
346 m[1][0] = 0.0f;
347 m[1][1] = 1.0f;
348 m[1][2] = 0.0f;
349 m[1][3] = 0.0f;
350 m[2][0] = 0.0f;
351 m[2][1] = 0.0f;
352 m[2][2] = 1.0f;
353 m[2][3] = 0.0f;
354 m[3][0] = 0.0f;
355 m[3][1] = 0.0f;
356 m[3][2] = 0.0f;
357 m[3][3] = 1.0f;
358 flagBits = Identity;
359}
360
361inline void QMatrix4x4::fill(float value)
362{
363 m[0][0] = value;
364 m[0][1] = value;
365 m[0][2] = value;
366 m[0][3] = value;
367 m[1][0] = value;
368 m[1][1] = value;
369 m[1][2] = value;
370 m[1][3] = value;
371 m[2][0] = value;
372 m[2][1] = value;
373 m[2][2] = value;
374 m[2][3] = value;
375 m[3][0] = value;
376 m[3][1] = value;
377 m[3][2] = value;
378 m[3][3] = value;
379 flagBits = General;
380}
381
382inline QMatrix4x4& QMatrix4x4::operator+=(const QMatrix4x4& other)
383{
384 m[0][0] += other.m[0][0];
385 m[0][1] += other.m[0][1];
386 m[0][2] += other.m[0][2];
387 m[0][3] += other.m[0][3];
388 m[1][0] += other.m[1][0];
389 m[1][1] += other.m[1][1];
390 m[1][2] += other.m[1][2];
391 m[1][3] += other.m[1][3];
392 m[2][0] += other.m[2][0];
393 m[2][1] += other.m[2][1];
394 m[2][2] += other.m[2][2];
395 m[2][3] += other.m[2][3];
396 m[3][0] += other.m[3][0];
397 m[3][1] += other.m[3][1];
398 m[3][2] += other.m[3][2];
399 m[3][3] += other.m[3][3];
400 flagBits = General;
401 return *this;
402}
403
404inline QMatrix4x4& QMatrix4x4::operator-=(const QMatrix4x4& other)
405{
406 m[0][0] -= other.m[0][0];
407 m[0][1] -= other.m[0][1];
408 m[0][2] -= other.m[0][2];
409 m[0][3] -= other.m[0][3];
410 m[1][0] -= other.m[1][0];
411 m[1][1] -= other.m[1][1];
412 m[1][2] -= other.m[1][2];
413 m[1][3] -= other.m[1][3];
414 m[2][0] -= other.m[2][0];
415 m[2][1] -= other.m[2][1];
416 m[2][2] -= other.m[2][2];
417 m[2][3] -= other.m[2][3];
418 m[3][0] -= other.m[3][0];
419 m[3][1] -= other.m[3][1];
420 m[3][2] -= other.m[3][2];
421 m[3][3] -= other.m[3][3];
422 flagBits = General;
423 return *this;
424}
425
426inline QMatrix4x4& QMatrix4x4::operator*=(const QMatrix4x4& o)
427{
428 const QMatrix4x4 other = o; // prevent aliasing when &o == this ### Qt 6: take o by value
429 flagBits |= other.flagBits;
430
431 if (flagBits < Rotation2D) {
432 m[3][0] += m[0][0] * other.m[3][0];
433 m[3][1] += m[1][1] * other.m[3][1];
434 m[3][2] += m[2][2] * other.m[3][2];
435
436 m[0][0] *= other.m[0][0];
437 m[1][1] *= other.m[1][1];
438 m[2][2] *= other.m[2][2];
439 return *this;
440 }
441
442 float m0, m1, m2;
443 m0 = m[0][0] * other.m[0][0]
444 + m[1][0] * other.m[0][1]
445 + m[2][0] * other.m[0][2]
446 + m[3][0] * other.m[0][3];
447 m1 = m[0][0] * other.m[1][0]
448 + m[1][0] * other.m[1][1]
449 + m[2][0] * other.m[1][2]
450 + m[3][0] * other.m[1][3];
451 m2 = m[0][0] * other.m[2][0]
452 + m[1][0] * other.m[2][1]
453 + m[2][0] * other.m[2][2]
454 + m[3][0] * other.m[2][3];
455 m[3][0] = m[0][0] * other.m[3][0]
456 + m[1][0] * other.m[3][1]
457 + m[2][0] * other.m[3][2]
458 + m[3][0] * other.m[3][3];
459 m[0][0] = m0;
460 m[1][0] = m1;
461 m[2][0] = m2;
462
463 m0 = m[0][1] * other.m[0][0]
464 + m[1][1] * other.m[0][1]
465 + m[2][1] * other.m[0][2]
466 + m[3][1] * other.m[0][3];
467 m1 = m[0][1] * other.m[1][0]
468 + m[1][1] * other.m[1][1]
469 + m[2][1] * other.m[1][2]
470 + m[3][1] * other.m[1][3];
471 m2 = m[0][1] * other.m[2][0]
472 + m[1][1] * other.m[2][1]
473 + m[2][1] * other.m[2][2]
474 + m[3][1] * other.m[2][3];
475 m[3][1] = m[0][1] * other.m[3][0]
476 + m[1][1] * other.m[3][1]
477 + m[2][1] * other.m[3][2]
478 + m[3][1] * other.m[3][3];
479 m[0][1] = m0;
480 m[1][1] = m1;
481 m[2][1] = m2;
482
483 m0 = m[0][2] * other.m[0][0]
484 + m[1][2] * other.m[0][1]
485 + m[2][2] * other.m[0][2]
486 + m[3][2] * other.m[0][3];
487 m1 = m[0][2] * other.m[1][0]
488 + m[1][2] * other.m[1][1]
489 + m[2][2] * other.m[1][2]
490 + m[3][2] * other.m[1][3];
491 m2 = m[0][2] * other.m[2][0]
492 + m[1][2] * other.m[2][1]
493 + m[2][2] * other.m[2][2]
494 + m[3][2] * other.m[2][3];
495 m[3][2] = m[0][2] * other.m[3][0]
496 + m[1][2] * other.m[3][1]
497 + m[2][2] * other.m[3][2]
498 + m[3][2] * other.m[3][3];
499 m[0][2] = m0;
500 m[1][2] = m1;
501 m[2][2] = m2;
502
503 m0 = m[0][3] * other.m[0][0]
504 + m[1][3] * other.m[0][1]
505 + m[2][3] * other.m[0][2]
506 + m[3][3] * other.m[0][3];
507 m1 = m[0][3] * other.m[1][0]
508 + m[1][3] * other.m[1][1]
509 + m[2][3] * other.m[1][2]
510 + m[3][3] * other.m[1][3];
511 m2 = m[0][3] * other.m[2][0]
512 + m[1][3] * other.m[2][1]
513 + m[2][3] * other.m[2][2]
514 + m[3][3] * other.m[2][3];
515 m[3][3] = m[0][3] * other.m[3][0]
516 + m[1][3] * other.m[3][1]
517 + m[2][3] * other.m[3][2]
518 + m[3][3] * other.m[3][3];
519 m[0][3] = m0;
520 m[1][3] = m1;
521 m[2][3] = m2;
522 return *this;
523}
524
525inline QMatrix4x4& QMatrix4x4::operator*=(float factor)
526{
527 m[0][0] *= factor;
528 m[0][1] *= factor;
529 m[0][2] *= factor;
530 m[0][3] *= factor;
531 m[1][0] *= factor;
532 m[1][1] *= factor;
533 m[1][2] *= factor;
534 m[1][3] *= factor;
535 m[2][0] *= factor;
536 m[2][1] *= factor;
537 m[2][2] *= factor;
538 m[2][3] *= factor;
539 m[3][0] *= factor;
540 m[3][1] *= factor;
541 m[3][2] *= factor;
542 m[3][3] *= factor;
543 flagBits = General;
544 return *this;
545}
546
547inline bool QMatrix4x4::operator==(const QMatrix4x4& other) const
548{
549 return m[0][0] == other.m[0][0] &&
550 m[0][1] == other.m[0][1] &&
551 m[0][2] == other.m[0][2] &&
552 m[0][3] == other.m[0][3] &&
553 m[1][0] == other.m[1][0] &&
554 m[1][1] == other.m[1][1] &&
555 m[1][2] == other.m[1][2] &&
556 m[1][3] == other.m[1][3] &&
557 m[2][0] == other.m[2][0] &&
558 m[2][1] == other.m[2][1] &&
559 m[2][2] == other.m[2][2] &&
560 m[2][3] == other.m[2][3] &&
561 m[3][0] == other.m[3][0] &&
562 m[3][1] == other.m[3][1] &&
563 m[3][2] == other.m[3][2] &&
564 m[3][3] == other.m[3][3];
565}
566
567inline bool QMatrix4x4::operator!=(const QMatrix4x4& other) const
568{
569 return m[0][0] != other.m[0][0] ||
570 m[0][1] != other.m[0][1] ||
571 m[0][2] != other.m[0][2] ||
572 m[0][3] != other.m[0][3] ||
573 m[1][0] != other.m[1][0] ||
574 m[1][1] != other.m[1][1] ||
575 m[1][2] != other.m[1][2] ||
576 m[1][3] != other.m[1][3] ||
577 m[2][0] != other.m[2][0] ||
578 m[2][1] != other.m[2][1] ||
579 m[2][2] != other.m[2][2] ||
580 m[2][3] != other.m[2][3] ||
581 m[3][0] != other.m[3][0] ||
582 m[3][1] != other.m[3][1] ||
583 m[3][2] != other.m[3][2] ||
584 m[3][3] != other.m[3][3];
585}
586
587inline QMatrix4x4 operator+(const QMatrix4x4& m1, const QMatrix4x4& m2)
588{
589 QMatrix4x4 m(1);
590 m.m[0][0] = m1.m[0][0] + m2.m[0][0];
591 m.m[0][1] = m1.m[0][1] + m2.m[0][1];
592 m.m[0][2] = m1.m[0][2] + m2.m[0][2];
593 m.m[0][3] = m1.m[0][3] + m2.m[0][3];
594 m.m[1][0] = m1.m[1][0] + m2.m[1][0];
595 m.m[1][1] = m1.m[1][1] + m2.m[1][1];
596 m.m[1][2] = m1.m[1][2] + m2.m[1][2];
597 m.m[1][3] = m1.m[1][3] + m2.m[1][3];
598 m.m[2][0] = m1.m[2][0] + m2.m[2][0];
599 m.m[2][1] = m1.m[2][1] + m2.m[2][1];
600 m.m[2][2] = m1.m[2][2] + m2.m[2][2];
601 m.m[2][3] = m1.m[2][3] + m2.m[2][3];
602 m.m[3][0] = m1.m[3][0] + m2.m[3][0];
603 m.m[3][1] = m1.m[3][1] + m2.m[3][1];
604 m.m[3][2] = m1.m[3][2] + m2.m[3][2];
605 m.m[3][3] = m1.m[3][3] + m2.m[3][3];
606 m.flagBits = QMatrix4x4::General;
607 return m;
608}
609
610inline QMatrix4x4 operator-(const QMatrix4x4& m1, const QMatrix4x4& m2)
611{
612 QMatrix4x4 m(1);
613 m.m[0][0] = m1.m[0][0] - m2.m[0][0];
614 m.m[0][1] = m1.m[0][1] - m2.m[0][1];
615 m.m[0][2] = m1.m[0][2] - m2.m[0][2];
616 m.m[0][3] = m1.m[0][3] - m2.m[0][3];
617 m.m[1][0] = m1.m[1][0] - m2.m[1][0];
618 m.m[1][1] = m1.m[1][1] - m2.m[1][1];
619 m.m[1][2] = m1.m[1][2] - m2.m[1][2];
620 m.m[1][3] = m1.m[1][3] - m2.m[1][3];
621 m.m[2][0] = m1.m[2][0] - m2.m[2][0];
622 m.m[2][1] = m1.m[2][1] - m2.m[2][1];
623 m.m[2][2] = m1.m[2][2] - m2.m[2][2];
624 m.m[2][3] = m1.m[2][3] - m2.m[2][3];
625 m.m[3][0] = m1.m[3][0] - m2.m[3][0];
626 m.m[3][1] = m1.m[3][1] - m2.m[3][1];
627 m.m[3][2] = m1.m[3][2] - m2.m[3][2];
628 m.m[3][3] = m1.m[3][3] - m2.m[3][3];
629 m.flagBits = QMatrix4x4::General;
630 return m;
631}
632
633inline QMatrix4x4 operator*(const QMatrix4x4& m1, const QMatrix4x4& m2)
634{
635 int flagBits = m1.flagBits | m2.flagBits;
636 if (flagBits < QMatrix4x4::Rotation2D) {
637 QMatrix4x4 m = m1;
638 m.m[3][0] += m.m[0][0] * m2.m[3][0];
639 m.m[3][1] += m.m[1][1] * m2.m[3][1];
640 m.m[3][2] += m.m[2][2] * m2.m[3][2];
641
642 m.m[0][0] *= m2.m[0][0];
643 m.m[1][1] *= m2.m[1][1];
644 m.m[2][2] *= m2.m[2][2];
645 m.flagBits = flagBits;
646 return m;
647 }
648
649 QMatrix4x4 m(1);
650 m.m[0][0] = m1.m[0][0] * m2.m[0][0]
651 + m1.m[1][0] * m2.m[0][1]
652 + m1.m[2][0] * m2.m[0][2]
653 + m1.m[3][0] * m2.m[0][3];
654 m.m[0][1] = m1.m[0][1] * m2.m[0][0]
655 + m1.m[1][1] * m2.m[0][1]
656 + m1.m[2][1] * m2.m[0][2]
657 + m1.m[3][1] * m2.m[0][3];
658 m.m[0][2] = m1.m[0][2] * m2.m[0][0]
659 + m1.m[1][2] * m2.m[0][1]
660 + m1.m[2][2] * m2.m[0][2]
661 + m1.m[3][2] * m2.m[0][3];
662 m.m[0][3] = m1.m[0][3] * m2.m[0][0]
663 + m1.m[1][3] * m2.m[0][1]
664 + m1.m[2][3] * m2.m[0][2]
665 + m1.m[3][3] * m2.m[0][3];
666
667 m.m[1][0] = m1.m[0][0] * m2.m[1][0]
668 + m1.m[1][0] * m2.m[1][1]
669 + m1.m[2][0] * m2.m[1][2]
670 + m1.m[3][0] * m2.m[1][3];
671 m.m[1][1] = m1.m[0][1] * m2.m[1][0]
672 + m1.m[1][1] * m2.m[1][1]
673 + m1.m[2][1] * m2.m[1][2]
674 + m1.m[3][1] * m2.m[1][3];
675 m.m[1][2] = m1.m[0][2] * m2.m[1][0]
676 + m1.m[1][2] * m2.m[1][1]
677 + m1.m[2][2] * m2.m[1][2]
678 + m1.m[3][2] * m2.m[1][3];
679 m.m[1][3] = m1.m[0][3] * m2.m[1][0]
680 + m1.m[1][3] * m2.m[1][1]
681 + m1.m[2][3] * m2.m[1][2]
682 + m1.m[3][3] * m2.m[1][3];
683
684 m.m[2][0] = m1.m[0][0] * m2.m[2][0]
685 + m1.m[1][0] * m2.m[2][1]
686 + m1.m[2][0] * m2.m[2][2]
687 + m1.m[3][0] * m2.m[2][3];
688 m.m[2][1] = m1.m[0][1] * m2.m[2][0]
689 + m1.m[1][1] * m2.m[2][1]
690 + m1.m[2][1] * m2.m[2][2]
691 + m1.m[3][1] * m2.m[2][3];
692 m.m[2][2] = m1.m[0][2] * m2.m[2][0]
693 + m1.m[1][2] * m2.m[2][1]
694 + m1.m[2][2] * m2.m[2][2]
695 + m1.m[3][2] * m2.m[2][3];
696 m.m[2][3] = m1.m[0][3] * m2.m[2][0]
697 + m1.m[1][3] * m2.m[2][1]
698 + m1.m[2][3] * m2.m[2][2]
699 + m1.m[3][3] * m2.m[2][3];
700
701 m.m[3][0] = m1.m[0][0] * m2.m[3][0]
702 + m1.m[1][0] * m2.m[3][1]
703 + m1.m[2][0] * m2.m[3][2]
704 + m1.m[3][0] * m2.m[3][3];
705 m.m[3][1] = m1.m[0][1] * m2.m[3][0]
706 + m1.m[1][1] * m2.m[3][1]
707 + m1.m[2][1] * m2.m[3][2]
708 + m1.m[3][1] * m2.m[3][3];
709 m.m[3][2] = m1.m[0][2] * m2.m[3][0]
710 + m1.m[1][2] * m2.m[3][1]
711 + m1.m[2][2] * m2.m[3][2]
712 + m1.m[3][2] * m2.m[3][3];
713 m.m[3][3] = m1.m[0][3] * m2.m[3][0]
714 + m1.m[1][3] * m2.m[3][1]
715 + m1.m[2][3] * m2.m[3][2]
716 + m1.m[3][3] * m2.m[3][3];
717 m.flagBits = flagBits;
718 return m;
719}
720
721#ifndef QT_NO_VECTOR3D
722
723inline QVector3D operator*(const QVector3D& vector, const QMatrix4x4& matrix)
724{
725 float x, y, z, w;
726 x = vector.x() * matrix.m[0][0] +
727 vector.y() * matrix.m[0][1] +
728 vector.z() * matrix.m[0][2] +
729 matrix.m[0][3];
730 y = vector.x() * matrix.m[1][0] +
731 vector.y() * matrix.m[1][1] +
732 vector.z() * matrix.m[1][2] +
733 matrix.m[1][3];
734 z = vector.x() * matrix.m[2][0] +
735 vector.y() * matrix.m[2][1] +
736 vector.z() * matrix.m[2][2] +
737 matrix.m[2][3];
738 w = vector.x() * matrix.m[3][0] +
739 vector.y() * matrix.m[3][1] +
740 vector.z() * matrix.m[3][2] +
741 matrix.m[3][3];
742 if (w == 1.0f)
743 return QVector3D(x, y, z);
744 else
745 return QVector3D(x / w, y / w, z / w);
746}
747
748inline QVector3D operator*(const QMatrix4x4& matrix, const QVector3D& vector)
749{
750 float x, y, z, w;
751 if (matrix.flagBits == QMatrix4x4::Identity) {
752 return vector;
753 } else if (matrix.flagBits < QMatrix4x4::Rotation2D) {
754 // Translation | Scale
755 return QVector3D(vector.x() * matrix.m[0][0] + matrix.m[3][0],
756 vector.y() * matrix.m[1][1] + matrix.m[3][1],
757 vector.z() * matrix.m[2][2] + matrix.m[3][2]);
758 } else if (matrix.flagBits < QMatrix4x4::Rotation) {
759 // Translation | Scale | Rotation2D
760 return QVector3D(vector.x() * matrix.m[0][0] + vector.y() * matrix.m[1][0] + matrix.m[3][0],
761 vector.x() * matrix.m[0][1] + vector.y() * matrix.m[1][1] + matrix.m[3][1],
762 vector.z() * matrix.m[2][2] + matrix.m[3][2]);
763 } else {
764 x = vector.x() * matrix.m[0][0] +
765 vector.y() * matrix.m[1][0] +
766 vector.z() * matrix.m[2][0] +
767 matrix.m[3][0];
768 y = vector.x() * matrix.m[0][1] +
769 vector.y() * matrix.m[1][1] +
770 vector.z() * matrix.m[2][1] +
771 matrix.m[3][1];
772 z = vector.x() * matrix.m[0][2] +
773 vector.y() * matrix.m[1][2] +
774 vector.z() * matrix.m[2][2] +
775 matrix.m[3][2];
776 w = vector.x() * matrix.m[0][3] +
777 vector.y() * matrix.m[1][3] +
778 vector.z() * matrix.m[2][3] +
779 matrix.m[3][3];
780 if (w == 1.0f)
781 return QVector3D(x, y, z);
782 else
783 return QVector3D(x / w, y / w, z / w);
784 }
785}
786
787#endif
788
789#ifndef QT_NO_VECTOR4D
790
791inline QVector4D operator*(const QVector4D& vector, const QMatrix4x4& matrix)
792{
793 float x, y, z, w;
794 x = vector.x() * matrix.m[0][0] +
795 vector.y() * matrix.m[0][1] +
796 vector.z() * matrix.m[0][2] +
797 vector.w() * matrix.m[0][3];
798 y = vector.x() * matrix.m[1][0] +
799 vector.y() * matrix.m[1][1] +
800 vector.z() * matrix.m[1][2] +
801 vector.w() * matrix.m[1][3];
802 z = vector.x() * matrix.m[2][0] +
803 vector.y() * matrix.m[2][1] +
804 vector.z() * matrix.m[2][2] +
805 vector.w() * matrix.m[2][3];
806 w = vector.x() * matrix.m[3][0] +
807 vector.y() * matrix.m[3][1] +
808 vector.z() * matrix.m[3][2] +
809 vector.w() * matrix.m[3][3];
810 return QVector4D(x, y, z, w);
811}
812
813inline QVector4D operator*(const QMatrix4x4& matrix, const QVector4D& vector)
814{
815 float x, y, z, w;
816 x = vector.x() * matrix.m[0][0] +
817 vector.y() * matrix.m[1][0] +
818 vector.z() * matrix.m[2][0] +
819 vector.w() * matrix.m[3][0];
820 y = vector.x() * matrix.m[0][1] +
821 vector.y() * matrix.m[1][1] +
822 vector.z() * matrix.m[2][1] +
823 vector.w() * matrix.m[3][1];
824 z = vector.x() * matrix.m[0][2] +
825 vector.y() * matrix.m[1][2] +
826 vector.z() * matrix.m[2][2] +
827 vector.w() * matrix.m[3][2];
828 w = vector.x() * matrix.m[0][3] +
829 vector.y() * matrix.m[1][3] +
830 vector.z() * matrix.m[2][3] +
831 vector.w() * matrix.m[3][3];
832 return QVector4D(x, y, z, w);
833}
834
835#endif
836
837inline QPoint operator*(const QPoint& point, const QMatrix4x4& matrix)
838{
839 float xin, yin;
840 float x, y, w;
841 xin = point.x();
842 yin = point.y();
843 x = xin * matrix.m[0][0] +
844 yin * matrix.m[0][1] +
845 matrix.m[0][3];
846 y = xin * matrix.m[1][0] +
847 yin * matrix.m[1][1] +
848 matrix.m[1][3];
849 w = xin * matrix.m[3][0] +
850 yin * matrix.m[3][1] +
851 matrix.m[3][3];
852 if (w == 1.0f)
853 return QPoint(qRound(x), qRound(y));
854 else
855 return QPoint(qRound(x / w), qRound(y / w));
856}
857
858inline QPointF operator*(const QPointF& point, const QMatrix4x4& matrix)
859{
860 float xin, yin;
861 float x, y, w;
862 xin = float(point.x());
863 yin = float(point.y());
864 x = xin * matrix.m[0][0] +
865 yin * matrix.m[0][1] +
866 matrix.m[0][3];
867 y = xin * matrix.m[1][0] +
868 yin * matrix.m[1][1] +
869 matrix.m[1][3];
870 w = xin * matrix.m[3][0] +
871 yin * matrix.m[3][1] +
872 matrix.m[3][3];
873 if (w == 1.0f) {
874 return QPointF(qreal(x), qreal(y));
875 } else {
876 return QPointF(qreal(x / w), qreal(y / w));
877 }
878}
879
880inline QPoint operator*(const QMatrix4x4& matrix, const QPoint& point)
881{
882 float xin, yin;
883 float x, y, w;
884 xin = point.x();
885 yin = point.y();
886 if (matrix.flagBits == QMatrix4x4::Identity) {
887 return point;
888 } else if (matrix.flagBits < QMatrix4x4::Rotation2D) {
889 // Translation | Scale
890 return QPoint(qRound(xin * matrix.m[0][0] + matrix.m[3][0]),
891 qRound(yin * matrix.m[1][1] + matrix.m[3][1]));
892 } else if (matrix.flagBits < QMatrix4x4::Perspective) {
893 return QPoint(qRound(xin * matrix.m[0][0] + yin * matrix.m[1][0] + matrix.m[3][0]),
894 qRound(xin * matrix.m[0][1] + yin * matrix.m[1][1] + matrix.m[3][1]));
895 } else {
896 x = xin * matrix.m[0][0] +
897 yin * matrix.m[1][0] +
898 matrix.m[3][0];
899 y = xin * matrix.m[0][1] +
900 yin * matrix.m[1][1] +
901 matrix.m[3][1];
902 w = xin * matrix.m[0][3] +
903 yin * matrix.m[1][3] +
904 matrix.m[3][3];
905 if (w == 1.0f)
906 return QPoint(qRound(x), qRound(y));
907 else
908 return QPoint(qRound(x / w), qRound(y / w));
909 }
910}
911
912inline QPointF operator*(const QMatrix4x4& matrix, const QPointF& point)
913{
914 qreal xin, yin;
915 qreal x, y, w;
916 xin = point.x();
917 yin = point.y();
918 if (matrix.flagBits == QMatrix4x4::Identity) {
919 return point;
920 } else if (matrix.flagBits < QMatrix4x4::Rotation2D) {
921 // Translation | Scale
922 return QPointF(xin * qreal(matrix.m[0][0]) + qreal(matrix.m[3][0]),
923 yin * qreal(matrix.m[1][1]) + qreal(matrix.m[3][1]));
924 } else if (matrix.flagBits < QMatrix4x4::Perspective) {
925 return QPointF(xin * qreal(matrix.m[0][0]) + yin * qreal(matrix.m[1][0]) +
926 qreal(matrix.m[3][0]),
927 xin * qreal(matrix.m[0][1]) + yin * qreal(matrix.m[1][1]) +
928 qreal(matrix.m[3][1]));
929 } else {
930 x = xin * qreal(matrix.m[0][0]) +
931 yin * qreal(matrix.m[1][0]) +
932 qreal(matrix.m[3][0]);
933 y = xin * qreal(matrix.m[0][1]) +
934 yin * qreal(matrix.m[1][1]) +
935 qreal(matrix.m[3][1]);
936 w = xin * qreal(matrix.m[0][3]) +
937 yin * qreal(matrix.m[1][3]) +
938 qreal(matrix.m[3][3]);
939 if (w == 1.0) {
940 return QPointF(qreal(x), qreal(y));
941 } else {
942 return QPointF(qreal(x / w), qreal(y / w));
943 }
944 }
945}
946
947inline QMatrix4x4 operator-(const QMatrix4x4& matrix)
948{
949 QMatrix4x4 m(1);
950 m.m[0][0] = -matrix.m[0][0];
951 m.m[0][1] = -matrix.m[0][1];
952 m.m[0][2] = -matrix.m[0][2];
953 m.m[0][3] = -matrix.m[0][3];
954 m.m[1][0] = -matrix.m[1][0];
955 m.m[1][1] = -matrix.m[1][1];
956 m.m[1][2] = -matrix.m[1][2];
957 m.m[1][3] = -matrix.m[1][3];
958 m.m[2][0] = -matrix.m[2][0];
959 m.m[2][1] = -matrix.m[2][1];
960 m.m[2][2] = -matrix.m[2][2];
961 m.m[2][3] = -matrix.m[2][3];
962 m.m[3][0] = -matrix.m[3][0];
963 m.m[3][1] = -matrix.m[3][1];
964 m.m[3][2] = -matrix.m[3][2];
965 m.m[3][3] = -matrix.m[3][3];
966 m.flagBits = QMatrix4x4::General;
967 return m;
968}
969
970inline QMatrix4x4 operator*(float factor, const QMatrix4x4& matrix)
971{
972 QMatrix4x4 m(1);
973 m.m[0][0] = matrix.m[0][0] * factor;
974 m.m[0][1] = matrix.m[0][1] * factor;
975 m.m[0][2] = matrix.m[0][2] * factor;
976 m.m[0][3] = matrix.m[0][3] * factor;
977 m.m[1][0] = matrix.m[1][0] * factor;
978 m.m[1][1] = matrix.m[1][1] * factor;
979 m.m[1][2] = matrix.m[1][2] * factor;
980 m.m[1][3] = matrix.m[1][3] * factor;
981 m.m[2][0] = matrix.m[2][0] * factor;
982 m.m[2][1] = matrix.m[2][1] * factor;
983 m.m[2][2] = matrix.m[2][2] * factor;
984 m.m[2][3] = matrix.m[2][3] * factor;
985 m.m[3][0] = matrix.m[3][0] * factor;
986 m.m[3][1] = matrix.m[3][1] * factor;
987 m.m[3][2] = matrix.m[3][2] * factor;
988 m.m[3][3] = matrix.m[3][3] * factor;
989 m.flagBits = QMatrix4x4::General;
990 return m;
991}
992
993inline QMatrix4x4 operator*(const QMatrix4x4& matrix, float factor)
994{
995 QMatrix4x4 m(1);
996 m.m[0][0] = matrix.m[0][0] * factor;
997 m.m[0][1] = matrix.m[0][1] * factor;
998 m.m[0][2] = matrix.m[0][2] * factor;
999 m.m[0][3] = matrix.m[0][3] * factor;
1000 m.m[1][0] = matrix.m[1][0] * factor;
1001 m.m[1][1] = matrix.m[1][1] * factor;
1002 m.m[1][2] = matrix.m[1][2] * factor;
1003 m.m[1][3] = matrix.m[1][3] * factor;
1004 m.m[2][0] = matrix.m[2][0] * factor;
1005 m.m[2][1] = matrix.m[2][1] * factor;
1006 m.m[2][2] = matrix.m[2][2] * factor;
1007 m.m[2][3] = matrix.m[2][3] * factor;
1008 m.m[3][0] = matrix.m[3][0] * factor;
1009 m.m[3][1] = matrix.m[3][1] * factor;
1010 m.m[3][2] = matrix.m[3][2] * factor;
1011 m.m[3][3] = matrix.m[3][3] * factor;
1012 m.flagBits = QMatrix4x4::General;
1013 return m;
1014}
1015
1016inline bool qFuzzyCompare(const QMatrix4x4& m1, const QMatrix4x4& m2)
1017{
1018 return qFuzzyCompare(m1.m[0][0], m2.m[0][0]) &&
1019 qFuzzyCompare(m1.m[0][1], m2.m[0][1]) &&
1020 qFuzzyCompare(m1.m[0][2], m2.m[0][2]) &&
1021 qFuzzyCompare(m1.m[0][3], m2.m[0][3]) &&
1022 qFuzzyCompare(m1.m[1][0], m2.m[1][0]) &&
1023 qFuzzyCompare(m1.m[1][1], m2.m[1][1]) &&
1024 qFuzzyCompare(m1.m[1][2], m2.m[1][2]) &&
1025 qFuzzyCompare(m1.m[1][3], m2.m[1][3]) &&
1026 qFuzzyCompare(m1.m[2][0], m2.m[2][0]) &&
1027 qFuzzyCompare(m1.m[2][1], m2.m[2][1]) &&
1028 qFuzzyCompare(m1.m[2][2], m2.m[2][2]) &&
1029 qFuzzyCompare(m1.m[2][3], m2.m[2][3]) &&
1030 qFuzzyCompare(m1.m[3][0], m2.m[3][0]) &&
1031 qFuzzyCompare(m1.m[3][1], m2.m[3][1]) &&
1032 qFuzzyCompare(m1.m[3][2], m2.m[3][2]) &&
1033 qFuzzyCompare(m1.m[3][3], m2.m[3][3]);
1034}
1035
1036inline QPoint QMatrix4x4::map(const QPoint& point) const
1037{
1038 return *this * point;
1039}
1040
1041inline QPointF QMatrix4x4::map(const QPointF& point) const
1042{
1043 return *this * point;
1044}
1045
1046#ifndef QT_NO_VECTOR3D
1047
1048inline QVector3D QMatrix4x4::map(const QVector3D& point) const
1049{
1050 return *this * point;
1051}
1052
1053inline QVector3D QMatrix4x4::mapVector(const QVector3D& vector) const
1054{
1055 if (flagBits < Scale) {
1056 // Translation
1057 return vector;
1058 } else if (flagBits < Rotation2D) {
1059 // Translation | Scale
1060 return QVector3D(vector.x() * m[0][0],
1061 vector.y() * m[1][1],
1062 vector.z() * m[2][2]);
1063 } else {
1064 return QVector3D(vector.x() * m[0][0] +
1065 vector.y() * m[1][0] +
1066 vector.z() * m[2][0],
1067 vector.x() * m[0][1] +
1068 vector.y() * m[1][1] +
1069 vector.z() * m[2][1],
1070 vector.x() * m[0][2] +
1071 vector.y() * m[1][2] +
1072 vector.z() * m[2][2]);
1073 }
1074}
1075
1076#endif
1077
1078#ifndef QT_NO_VECTOR4D
1079
1080inline QVector4D QMatrix4x4::map(const QVector4D& point) const
1081{
1082 return *this * point;
1083}
1084
1085#endif
1086
1087inline float *QMatrix4x4::data()
1088{
1089 // We have to assume that the caller will modify the matrix elements,
1090 // so we flip it over to "General" mode.
1091 flagBits = General;
1092 return *m;
1093}
1094
1095inline void QMatrix4x4::viewport(const QRectF &rect)
1096{
1097 viewport(float(rect.x()), float(rect.y()), float(rect.width()), float(rect.height()));
1098}
1099
1100QT_WARNING_POP
1101
1102#ifndef QT_NO_DEBUG_STREAM
1103Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QMatrix4x4 &m);
1104#endif
1105
1106#ifndef QT_NO_DATASTREAM
1107Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QMatrix4x4 &);
1108Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QMatrix4x4 &);
1109#endif
1110
1111#if QT_DEPRECATED_SINCE(5, 0)
1112template <int N, int M>
1113QT_DEPRECATED QMatrix4x4 qGenericMatrixToMatrix4x4(const QGenericMatrix<N, M, float>& matrix)
1114{
1115 return QMatrix4x4(matrix.constData(), N, M);
1116}
1117
1118template <int N, int M>
1119QT_DEPRECATED QGenericMatrix<N, M, float> qGenericMatrixFromMatrix4x4(const QMatrix4x4& matrix)
1120{
1121 QGenericMatrix<N, M, float> result;
1122 const float *m = matrix.constData();
1123 float *values = result.data();
1124 for (int col = 0; col < N; ++col) {
1125 for (int row = 0; row < M; ++row) {
1126 if (col < 4 && row < 4)
1127 values[col * M + row] = m[col * 4 + row];
1128 else if (col == row)
1129 values[col * M + row] = 1.0f;
1130 else
1131 values[col * M + row] = 0.0f;
1132 }
1133 }
1134 return result;
1135}
1136#endif
1137
1138#endif
1139
1140QT_END_NAMESPACE
1141
1142#endif
1143