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