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

source code of qtbase/src/gui/math3d/qmatrix4x4.h