69 The contents of the array \a values is assumed to be in |
71 The contents of the array \a values is assumed to be in |
70 row-major order. |
72 row-major order. |
71 |
73 |
72 If the matrix has a special type (identity, translate, scale, etc), |
74 If the matrix has a special type (identity, translate, scale, etc), |
73 the programmer should follow this constructor with a call to |
75 the programmer should follow this constructor with a call to |
74 inferSpecialType() if they wish QMatrix4x4 to optimize further |
76 optimize() if they wish QMatrix4x4 to optimize further |
75 calls to translate(), scale(), etc. |
77 calls to translate(), scale(), etc. |
76 |
78 |
77 \sa toValueArray(), inferSpecialType() |
79 \sa copyDataTo(), optimize() |
78 */ |
80 */ |
79 QMatrix4x4::QMatrix4x4(const qreal *values) |
81 QMatrix4x4::QMatrix4x4(const qreal *values) |
80 { |
82 { |
81 for (int row = 0; row < 4; ++row) |
83 for (int row = 0; row < 4; ++row) |
82 for (int col = 0; col < 4; ++col) |
84 for (int col = 0; col < 4; ++col) |
92 \a m41, \a m42, \a m43, and \a m44. The elements are specified in |
94 \a m41, \a m42, \a m43, and \a m44. The elements are specified in |
93 row-major order. |
95 row-major order. |
94 |
96 |
95 If the matrix has a special type (identity, translate, scale, etc), |
97 If the matrix has a special type (identity, translate, scale, etc), |
96 the programmer should follow this constructor with a call to |
98 the programmer should follow this constructor with a call to |
97 inferSpecialType() if they wish QMatrix4x4 to optimize further |
99 optimize() if they wish QMatrix4x4 to optimize further |
98 calls to translate(), scale(), etc. |
100 calls to translate(), scale(), etc. |
99 |
101 |
100 \sa inferSpecialType() |
102 \sa optimize() |
101 */ |
103 */ |
102 |
104 |
103 #if !defined(QT_NO_MEMBER_TEMPLATES) || defined(Q_QDOC) |
105 #if !defined(QT_NO_MEMBER_TEMPLATES) || defined(Q_QDOC) |
104 |
106 |
105 /*! |
107 /*! |
172 Constructs a 4x4 matrix from a conventional Qt 2D affine |
174 Constructs a 4x4 matrix from a conventional Qt 2D affine |
173 transformation \a matrix. |
175 transformation \a matrix. |
174 |
176 |
175 If \a matrix has a special type (identity, translate, scale, etc), |
177 If \a matrix has a special type (identity, translate, scale, etc), |
176 the programmer should follow this constructor with a call to |
178 the programmer should follow this constructor with a call to |
177 inferSpecialType() if they wish QMatrix4x4 to optimize further |
179 optimize() if they wish QMatrix4x4 to optimize further |
178 calls to translate(), scale(), etc. |
180 calls to translate(), scale(), etc. |
179 |
181 |
180 \sa toAffine(), inferSpecialType() |
182 \sa toAffine(), optimize() |
181 */ |
183 */ |
182 QMatrix4x4::QMatrix4x4(const QMatrix& matrix) |
184 QMatrix4x4::QMatrix4x4(const QMatrix& matrix) |
183 { |
185 { |
184 m[0][0] = matrix.m11(); |
186 m[0][0] = matrix.m11(); |
185 m[0][1] = matrix.m12(); |
187 m[0][1] = matrix.m12(); |
204 Constructs a 4x4 matrix from the conventional Qt 2D |
206 Constructs a 4x4 matrix from the conventional Qt 2D |
205 transformation matrix \a transform. |
207 transformation matrix \a transform. |
206 |
208 |
207 If \a transform has a special type (identity, translate, scale, etc), |
209 If \a transform has a special type (identity, translate, scale, etc), |
208 the programmer should follow this constructor with a call to |
210 the programmer should follow this constructor with a call to |
209 inferSpecialType() if they wish QMatrix4x4 to optimize further |
211 optimize() if they wish QMatrix4x4 to optimize further |
210 calls to translate(), scale(), etc. |
212 calls to translate(), scale(), etc. |
211 |
213 |
212 \sa toTransform(), inferSpecialType() |
214 \sa toTransform(), optimize() |
213 */ |
215 */ |
214 QMatrix4x4::QMatrix4x4(const QTransform& transform) |
216 QMatrix4x4::QMatrix4x4(const QTransform& transform) |
215 { |
217 { |
216 m[0][0] = transform.m11(); |
218 m[0][0] = transform.m11(); |
217 m[0][1] = transform.m12(); |
219 m[0][1] = transform.m12(); |
690 |
692 |
691 #ifndef QT_NO_VECTOR3D |
693 #ifndef QT_NO_VECTOR3D |
692 |
694 |
693 /*! |
695 /*! |
694 Multiplies this matrix by another that scales coordinates by |
696 Multiplies this matrix by another that scales coordinates by |
695 the components of \a vector. Returns this matrix. |
697 the components of \a vector. |
696 |
698 |
697 \sa translate(), rotate() |
699 \sa translate(), rotate() |
698 */ |
700 */ |
699 QMatrix4x4& QMatrix4x4::scale(const QVector3D& vector) |
701 void QMatrix4x4::scale(const QVector3D& vector) |
700 { |
702 { |
701 qreal vx = vector.x(); |
703 qreal vx = vector.x(); |
702 qreal vy = vector.y(); |
704 qreal vy = vector.y(); |
703 qreal vz = vector.z(); |
705 qreal vz = vector.z(); |
704 if (flagBits == Identity) { |
706 if (flagBits == Identity) { |
848 m[2][1] *= factor; |
847 m[2][1] *= factor; |
849 m[2][2] *= factor; |
848 m[2][2] *= factor; |
850 m[2][3] *= factor; |
849 m[2][3] *= factor; |
851 flagBits = General; |
850 flagBits = General; |
852 } |
851 } |
853 return *this; |
|
854 } |
852 } |
855 |
853 |
856 #ifndef QT_NO_VECTOR3D |
854 #ifndef QT_NO_VECTOR3D |
857 /*! |
855 /*! |
858 Multiplies this matrix by another that translates coordinates by |
856 Multiplies this matrix by another that translates coordinates by |
859 the components of \a vector. Returns this matrix. |
857 the components of \a vector. |
860 |
858 |
861 \sa scale(), rotate() |
859 \sa scale(), rotate() |
862 */ |
860 */ |
863 QMatrix4x4& QMatrix4x4::translate(const QVector3D& vector) |
861 void QMatrix4x4::translate(const QVector3D& vector) |
864 { |
862 { |
865 qreal vx = vector.x(); |
863 qreal vx = vector.x(); |
866 qreal vy = vector.y(); |
864 qreal vy = vector.y(); |
867 qreal vz = vector.z(); |
865 qreal vz = vector.z(); |
868 if (flagBits == Identity) { |
866 if (flagBits == Identity) { |
891 if (flagBits == Rotation) |
889 if (flagBits == Rotation) |
892 flagBits |= Translation; |
890 flagBits |= Translation; |
893 else if (flagBits != (Rotation | Translation)) |
891 else if (flagBits != (Rotation | Translation)) |
894 flagBits = General; |
892 flagBits = General; |
895 } |
893 } |
896 return *this; |
|
897 } |
894 } |
898 |
895 |
899 #endif |
896 #endif |
900 |
897 |
901 /*! |
898 /*! |
902 \overload |
899 \overload |
903 |
900 |
904 Multiplies this matrix by another that translates coordinates |
901 Multiplies this matrix by another that translates coordinates |
905 by the components \a x, and \a y. Returns this matrix. |
902 by the components \a x, and \a y. |
906 |
903 |
907 \sa scale(), rotate() |
904 \sa scale(), rotate() |
908 */ |
905 */ |
909 QMatrix4x4& QMatrix4x4::translate(qreal x, qreal y) |
906 void QMatrix4x4::translate(qreal x, qreal y) |
910 { |
907 { |
911 if (flagBits == Identity) { |
908 if (flagBits == Identity) { |
912 m[3][0] = x; |
909 m[3][0] = x; |
913 m[3][1] = y; |
910 m[3][1] = y; |
914 flagBits = Translation; |
911 flagBits = Translation; |
931 if (flagBits == Rotation) |
928 if (flagBits == Rotation) |
932 flagBits |= Translation; |
929 flagBits |= Translation; |
933 else if (flagBits != (Rotation | Translation)) |
930 else if (flagBits != (Rotation | Translation)) |
934 flagBits = General; |
931 flagBits = General; |
935 } |
932 } |
936 return *this; |
|
937 } |
933 } |
938 |
934 |
939 /*! |
935 /*! |
940 \overload |
936 \overload |
941 |
937 |
942 Multiplies this matrix by another that translates coordinates |
938 Multiplies this matrix by another that translates coordinates |
943 by the components \a x, \a y, and \a z. Returns this matrix. |
939 by the components \a x, \a y, and \a z. |
944 |
940 |
945 \sa scale(), rotate() |
941 \sa scale(), rotate() |
946 */ |
942 */ |
947 QMatrix4x4& QMatrix4x4::translate(qreal x, qreal y, qreal z) |
943 void QMatrix4x4::translate(qreal x, qreal y, qreal z) |
948 { |
944 { |
949 if (flagBits == Identity) { |
945 if (flagBits == Identity) { |
950 m[3][0] = x; |
946 m[3][0] = x; |
951 m[3][1] = y; |
947 m[3][1] = y; |
952 m[3][2] = z; |
948 m[3][2] = z; |
972 if (flagBits == Rotation) |
968 if (flagBits == Rotation) |
973 flagBits |= Translation; |
969 flagBits |= Translation; |
974 else if (flagBits != (Rotation | Translation)) |
970 else if (flagBits != (Rotation | Translation)) |
975 flagBits = General; |
971 flagBits = General; |
976 } |
972 } |
977 return *this; |
|
978 } |
973 } |
979 |
974 |
980 #ifndef QT_NO_VECTOR3D |
975 #ifndef QT_NO_VECTOR3D |
981 |
976 |
982 /*! |
977 /*! |
983 Multiples this matrix by another that rotates coordinates through |
978 Multiples this matrix by another that rotates coordinates through |
984 \a angle degrees about \a vector. Returns this matrix. |
979 \a angle degrees about \a vector. |
985 |
980 |
986 \sa scale(), translate() |
981 \sa scale(), translate() |
987 */ |
982 */ |
988 QMatrix4x4& QMatrix4x4::rotate(qreal angle, const QVector3D& vector) |
983 void QMatrix4x4::rotate(qreal angle, const QVector3D& vector) |
989 { |
984 { |
990 return rotate(angle, vector.x(), vector.y(), vector.z()); |
985 rotate(angle, vector.x(), vector.y(), vector.z()); |
991 } |
986 } |
992 |
987 |
993 #endif |
988 #endif |
994 |
989 |
995 /*! |
990 /*! |
996 \overload |
991 \overload |
997 |
992 |
998 Multiplies this matrix by another that rotates coordinates through |
993 Multiplies this matrix by another that rotates coordinates through |
999 \a angle degrees about the vector (\a x, \a y, \a z). Returns this matrix. |
994 \a angle degrees about the vector (\a x, \a y, \a z). |
1000 |
995 |
1001 \sa scale(), translate() |
996 \sa scale(), translate() |
1002 */ |
997 */ |
1003 QMatrix4x4& QMatrix4x4::rotate(qreal angle, qreal x, qreal y, qreal z) |
998 void QMatrix4x4::rotate(qreal angle, qreal x, qreal y, qreal z) |
1004 { |
999 { |
1005 if (angle == 0.0f) |
1000 if (angle == 0.0f) |
1006 return *this; |
1001 return; |
1007 QMatrix4x4 m(1); // The "1" says to not load the identity. |
1002 QMatrix4x4 m(1); // The "1" says to not load the identity. |
1008 qreal c, s, ic; |
1003 qreal c, s, ic; |
1009 if (angle == 90.0f || angle == -270.0f) { |
1004 if (angle == 90.0f || angle == -270.0f) { |
1010 s = 1.0f; |
1005 s = 1.0f; |
1011 c = 0.0f; |
1006 c = 0.0f; |
1098 *this *= m; |
1093 *this *= m; |
1099 if (flags != Identity) |
1094 if (flags != Identity) |
1100 flagBits = flags | Rotation; |
1095 flagBits = flags | Rotation; |
1101 else |
1096 else |
1102 flagBits = Rotation; |
1097 flagBits = Rotation; |
1103 return *this; |
1098 } |
1104 } |
1099 |
1105 |
1100 /*! |
1106 #ifndef QT_NO_VECTOR4D |
1101 \internal |
|
1102 */ |
|
1103 void QMatrix4x4::projectedRotate(qreal angle, qreal x, qreal y, qreal z) |
|
1104 { |
|
1105 // Used by QGraphicsRotation::applyTo() to perform a rotation |
|
1106 // and projection back to 2D in a single step. |
|
1107 if (angle == 0.0f) |
|
1108 return; |
|
1109 QMatrix4x4 m(1); // The "1" says to not load the identity. |
|
1110 qreal c, s, ic; |
|
1111 if (angle == 90.0f || angle == -270.0f) { |
|
1112 s = 1.0f; |
|
1113 c = 0.0f; |
|
1114 } else if (angle == -90.0f || angle == 270.0f) { |
|
1115 s = -1.0f; |
|
1116 c = 0.0f; |
|
1117 } else if (angle == 180.0f || angle == -180.0f) { |
|
1118 s = 0.0f; |
|
1119 c = -1.0f; |
|
1120 } else { |
|
1121 qreal a = angle * M_PI / 180.0f; |
|
1122 c = qCos(a); |
|
1123 s = qSin(a); |
|
1124 } |
|
1125 bool quick = false; |
|
1126 if (x == 0.0f) { |
|
1127 if (y == 0.0f) { |
|
1128 if (z != 0.0f) { |
|
1129 // Rotate around the Z axis. |
|
1130 m.setToIdentity(); |
|
1131 m.m[0][0] = c; |
|
1132 m.m[1][1] = c; |
|
1133 if (z < 0.0f) { |
|
1134 m.m[1][0] = s; |
|
1135 m.m[0][1] = -s; |
|
1136 } else { |
|
1137 m.m[1][0] = -s; |
|
1138 m.m[0][1] = s; |
|
1139 } |
|
1140 m.flagBits = General; |
|
1141 quick = true; |
|
1142 } |
|
1143 } else if (z == 0.0f) { |
|
1144 // Rotate around the Y axis. |
|
1145 m.setToIdentity(); |
|
1146 m.m[0][0] = c; |
|
1147 m.m[2][2] = 1.0f; |
|
1148 if (y < 0.0f) { |
|
1149 m.m[0][3] = -s * inv_dist_to_plane; |
|
1150 } else { |
|
1151 m.m[0][3] = s * inv_dist_to_plane; |
|
1152 } |
|
1153 m.flagBits = General; |
|
1154 quick = true; |
|
1155 } |
|
1156 } else if (y == 0.0f && z == 0.0f) { |
|
1157 // Rotate around the X axis. |
|
1158 m.setToIdentity(); |
|
1159 m.m[1][1] = c; |
|
1160 m.m[2][2] = 1.0f; |
|
1161 if (x < 0.0f) { |
|
1162 m.m[1][3] = s * inv_dist_to_plane; |
|
1163 } else { |
|
1164 m.m[1][3] = -s * inv_dist_to_plane; |
|
1165 } |
|
1166 m.flagBits = General; |
|
1167 quick = true; |
|
1168 } |
|
1169 if (!quick) { |
|
1170 qreal len = x * x + y * y + z * z; |
|
1171 if (!qFuzzyIsNull(len - 1.0f) && !qFuzzyIsNull(len)) { |
|
1172 len = qSqrt(len); |
|
1173 x /= len; |
|
1174 y /= len; |
|
1175 z /= len; |
|
1176 } |
|
1177 ic = 1.0f - c; |
|
1178 m.m[0][0] = x * x * ic + c; |
|
1179 m.m[1][0] = x * y * ic - z * s; |
|
1180 m.m[2][0] = 0.0f; |
|
1181 m.m[3][0] = 0.0f; |
|
1182 m.m[0][1] = y * x * ic + z * s; |
|
1183 m.m[1][1] = y * y * ic + c; |
|
1184 m.m[2][1] = 0.0f; |
|
1185 m.m[3][1] = 0.0f; |
|
1186 m.m[0][2] = 0.0f; |
|
1187 m.m[1][2] = 0.0f; |
|
1188 m.m[2][2] = 1.0f; |
|
1189 m.m[3][2] = 0.0f; |
|
1190 m.m[0][3] = (x * z * ic - y * s) * -inv_dist_to_plane; |
|
1191 m.m[1][3] = (y * z * ic + x * s) * -inv_dist_to_plane; |
|
1192 m.m[2][3] = 0.0f; |
|
1193 m.m[3][3] = 1.0f; |
|
1194 } |
|
1195 int flags = flagBits; |
|
1196 *this *= m; |
|
1197 if (flags != Identity) |
|
1198 flagBits = flags | Rotation; |
|
1199 else |
|
1200 flagBits = Rotation; |
|
1201 } |
|
1202 |
|
1203 #ifndef QT_NO_QUATERNION |
1107 |
1204 |
1108 /*! |
1205 /*! |
1109 Multiples this matrix by another that rotates coordinates according |
1206 Multiples this matrix by another that rotates coordinates according |
1110 to a specified \a quaternion. The \a quaternion is assumed to have |
1207 to a specified \a quaternion. The \a quaternion is assumed to have |
1111 been normalized. Returns this matrix. |
1208 been normalized. |
1112 |
1209 |
1113 \sa scale(), translate(), QQuaternion |
1210 \sa scale(), translate(), QQuaternion |
1114 */ |
1211 */ |
1115 QMatrix4x4& QMatrix4x4::rotate(const QQuaternion& quaternion) |
1212 void QMatrix4x4::rotate(const QQuaternion& quaternion) |
1116 { |
1213 { |
1117 // Algorithm from: |
1214 // Algorithm from: |
1118 // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q54 |
1215 // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q54 |
1119 QMatrix4x4 m(1); |
1216 QMatrix4x4 m(1); |
1120 qreal xx = quaternion.x() * quaternion.x(); |
1217 qreal xx = quaternion.x() * quaternion.x(); |
1146 *this *= m; |
1243 *this *= m; |
1147 if (flags != Identity) |
1244 if (flags != Identity) |
1148 flagBits = flags | Rotation; |
1245 flagBits = flags | Rotation; |
1149 else |
1246 else |
1150 flagBits = Rotation; |
1247 flagBits = Rotation; |
1151 return *this; |
|
1152 } |
1248 } |
1153 |
1249 |
1154 #endif |
1250 #endif |
1155 |
1251 |
1156 /*! |
1252 /*! |
1157 \overload |
1253 \overload |
1158 |
1254 |
1159 Multiplies this matrix by another that applies an orthographic |
1255 Multiplies this matrix by another that applies an orthographic |
1160 projection for a window with boundaries specified by \a rect. |
1256 projection for a window with boundaries specified by \a rect. |
1161 The near and far clipping planes will be -1 and 1 respectively. |
1257 The near and far clipping planes will be -1 and 1 respectively. |
1162 Returns this matrix. |
|
1163 |
1258 |
1164 \sa frustum(), perspective() |
1259 \sa frustum(), perspective() |
1165 */ |
1260 */ |
1166 QMatrix4x4& QMatrix4x4::ortho(const QRect& rect) |
1261 void QMatrix4x4::ortho(const QRect& rect) |
1167 { |
1262 { |
1168 // Note: rect.right() and rect.bottom() subtract 1 in QRect, |
1263 // Note: rect.right() and rect.bottom() subtract 1 in QRect, |
1169 // which gives the location of a pixel within the rectangle, |
1264 // which gives the location of a pixel within the rectangle, |
1170 // instead of the extent of the rectangle. We want the extent. |
1265 // instead of the extent of the rectangle. We want the extent. |
1171 // QRectF expresses the extent properly. |
1266 // QRectF expresses the extent properly. |
1172 return ortho(rect.x(), rect.x() + rect.width(), rect.y() + rect.height(), rect.y(), -1.0f, 1.0f); |
1267 ortho(rect.x(), rect.x() + rect.width(), rect.y() + rect.height(), rect.y(), -1.0f, 1.0f); |
1173 } |
1268 } |
1174 |
1269 |
1175 /*! |
1270 /*! |
1176 \overload |
1271 \overload |
1177 |
1272 |
1178 Multiplies this matrix by another that applies an orthographic |
1273 Multiplies this matrix by another that applies an orthographic |
1179 projection for a window with boundaries specified by \a rect. |
1274 projection for a window with boundaries specified by \a rect. |
1180 The near and far clipping planes will be -1 and 1 respectively. |
1275 The near and far clipping planes will be -1 and 1 respectively. |
1181 Returns this matrix. |
|
1182 |
1276 |
1183 \sa frustum(), perspective() |
1277 \sa frustum(), perspective() |
1184 */ |
1278 */ |
1185 QMatrix4x4& QMatrix4x4::ortho(const QRectF& rect) |
1279 void QMatrix4x4::ortho(const QRectF& rect) |
1186 { |
1280 { |
1187 return ortho(rect.left(), rect.right(), rect.bottom(), rect.top(), -1.0f, 1.0f); |
1281 ortho(rect.left(), rect.right(), rect.bottom(), rect.top(), -1.0f, 1.0f); |
1188 } |
1282 } |
1189 |
1283 |
1190 /*! |
1284 /*! |
1191 Multiplies this matrix by another that applies an orthographic |
1285 Multiplies this matrix by another that applies an orthographic |
1192 projection for a window with lower-left corner (\a left, \a bottom), |
1286 projection for a window with lower-left corner (\a left, \a bottom), |
1193 upper-right corner (\a right, \a top), and the specified \a nearPlane |
1287 upper-right corner (\a right, \a top), and the specified \a nearPlane |
1194 and \a farPlane clipping planes. Returns this matrix. |
1288 and \a farPlane clipping planes. |
1195 |
1289 |
1196 \sa frustum(), perspective() |
1290 \sa frustum(), perspective() |
1197 */ |
1291 */ |
1198 QMatrix4x4& QMatrix4x4::ortho(qreal left, qreal right, qreal bottom, qreal top, qreal nearPlane, qreal farPlane) |
1292 void QMatrix4x4::ortho(qreal left, qreal right, qreal bottom, qreal top, qreal nearPlane, qreal farPlane) |
1199 { |
1293 { |
1200 // Bail out if the projection volume is zero-sized. |
1294 // Bail out if the projection volume is zero-sized. |
1201 if (left == right || bottom == top || nearPlane == farPlane) |
1295 if (left == right || bottom == top || nearPlane == farPlane) |
1202 return *this; |
1296 return; |
1203 |
1297 |
1204 // Construct the projection. |
1298 // Construct the projection. |
1205 qreal width = right - left; |
1299 qreal width = right - left; |
1206 qreal invheight = top - bottom; |
1300 qreal invheight = top - bottom; |
1207 qreal clip = farPlane - nearPlane; |
1301 qreal clip = farPlane - nearPlane; |
1239 m.m[2][3] = 0.0f; |
1333 m.m[2][3] = 0.0f; |
1240 m.m[3][3] = 1.0f; |
1334 m.m[3][3] = 1.0f; |
1241 |
1335 |
1242 // Apply the projection. |
1336 // Apply the projection. |
1243 *this *= m; |
1337 *this *= m; |
1244 return *this; |
1338 return; |
1245 } |
1339 } |
1246 |
1340 |
1247 /*! |
1341 /*! |
1248 Multiplies this matrix by another that applies a perspective |
1342 Multiplies this matrix by another that applies a perspective |
1249 frustum projection for a window with lower-left corner (\a left, \a bottom), |
1343 frustum projection for a window with lower-left corner (\a left, \a bottom), |
1250 upper-right corner (\a right, \a top), and the specified \a nearPlane |
1344 upper-right corner (\a right, \a top), and the specified \a nearPlane |
1251 and \a farPlane clipping planes. Returns this matrix. |
1345 and \a farPlane clipping planes. |
1252 |
1346 |
1253 \sa ortho(), perspective() |
1347 \sa ortho(), perspective() |
1254 */ |
1348 */ |
1255 QMatrix4x4& QMatrix4x4::frustum(qreal left, qreal right, qreal bottom, qreal top, qreal nearPlane, qreal farPlane) |
1349 void QMatrix4x4::frustum(qreal left, qreal right, qreal bottom, qreal top, qreal nearPlane, qreal farPlane) |
1256 { |
1350 { |
1257 // Bail out if the projection volume is zero-sized. |
1351 // Bail out if the projection volume is zero-sized. |
1258 if (left == right || bottom == top || nearPlane == farPlane) |
1352 if (left == right || bottom == top || nearPlane == farPlane) |
1259 return *this; |
1353 return; |
1260 |
1354 |
1261 // Construct the projection. |
1355 // Construct the projection. |
1262 QMatrix4x4 m(1); |
1356 QMatrix4x4 m(1); |
1263 qreal width = right - left; |
1357 qreal width = right - left; |
1264 qreal invheight = top - bottom; |
1358 qreal invheight = top - bottom; |
1280 m.m[2][3] = -1.0f; |
1374 m.m[2][3] = -1.0f; |
1281 m.m[3][3] = 0.0f; |
1375 m.m[3][3] = 0.0f; |
1282 |
1376 |
1283 // Apply the projection. |
1377 // Apply the projection. |
1284 *this *= m; |
1378 *this *= m; |
1285 return *this; |
|
1286 } |
1379 } |
1287 |
1380 |
1288 /*! |
1381 /*! |
1289 Multiplies this matrix by another that applies a perspective |
1382 Multiplies this matrix by another that applies a perspective |
1290 projection. The field of view will be \a angle degrees within |
1383 projection. The field of view will be \a angle degrees within |
1291 a window with a given \a aspect ratio. The projection will |
1384 a window with a given \a aspect ratio. The projection will |
1292 have the specified \a nearPlane and \a farPlane clipping planes. |
1385 have the specified \a nearPlane and \a farPlane clipping planes. |
1293 Returns this matrix. |
|
1294 |
1386 |
1295 \sa ortho(), frustum() |
1387 \sa ortho(), frustum() |
1296 */ |
1388 */ |
1297 QMatrix4x4& QMatrix4x4::perspective(qreal angle, qreal aspect, qreal nearPlane, qreal farPlane) |
1389 void QMatrix4x4::perspective(qreal angle, qreal aspect, qreal nearPlane, qreal farPlane) |
1298 { |
1390 { |
1299 // Bail out if the projection volume is zero-sized. |
1391 // Bail out if the projection volume is zero-sized. |
1300 if (nearPlane == farPlane || aspect == 0.0f) |
1392 if (nearPlane == farPlane || aspect == 0.0f) |
1301 return *this; |
1393 return; |
1302 |
1394 |
1303 // Construct the projection. |
1395 // Construct the projection. |
1304 QMatrix4x4 m(1); |
1396 QMatrix4x4 m(1); |
1305 qreal radians = (angle / 2.0f) * M_PI / 180.0f; |
1397 qreal radians = (angle / 2.0f) * M_PI / 180.0f; |
1306 qreal sine = qSin(radians); |
1398 qreal sine = qSin(radians); |
1307 if (sine == 0.0f) |
1399 if (sine == 0.0f) |
1308 return *this; |
1400 return; |
1309 qreal cotan = qCos(radians) / sine; |
1401 qreal cotan = qCos(radians) / sine; |
1310 qreal clip = farPlane - nearPlane; |
1402 qreal clip = farPlane - nearPlane; |
1311 m.m[0][0] = cotan / aspect; |
1403 m.m[0][0] = cotan / aspect; |
1312 m.m[1][0] = 0.0f; |
1404 m.m[1][0] = 0.0f; |
1313 m.m[2][0] = 0.0f; |
1405 m.m[2][0] = 0.0f; |
1325 m.m[2][3] = -1.0f; |
1417 m.m[2][3] = -1.0f; |
1326 m.m[3][3] = 0.0f; |
1418 m.m[3][3] = 0.0f; |
1327 |
1419 |
1328 // Apply the projection. |
1420 // Apply the projection. |
1329 *this *= m; |
1421 *this *= m; |
1330 return *this; |
|
1331 } |
1422 } |
1332 |
1423 |
1333 #ifndef QT_NO_VECTOR3D |
1424 #ifndef QT_NO_VECTOR3D |
1334 |
1425 |
1335 /*! |
1426 /*! |
1336 Multiplies this matrix by another that applies an \a eye position |
1427 Multiplies this matrix by another that applies an \a eye position |
1337 transformation. The \a center value indicates the center of the |
1428 transformation. The \a center value indicates the center of the |
1338 view that the \a eye is looking at. The \a up value indicates |
1429 view that the \a eye is looking at. The \a up value indicates |
1339 which direction should be considered up with respect to the \a eye. |
1430 which direction should be considered up with respect to the \a eye. |
1340 Returns this matrix. |
1431 */ |
1341 */ |
1432 void QMatrix4x4::lookAt(const QVector3D& eye, const QVector3D& center, const QVector3D& up) |
1342 QMatrix4x4& QMatrix4x4::lookAt(const QVector3D& eye, const QVector3D& center, const QVector3D& up) |
|
1343 { |
1433 { |
1344 QVector3D forward = (center - eye).normalized(); |
1434 QVector3D forward = (center - eye).normalized(); |
1345 QVector3D side = QVector3D::crossProduct(forward, up).normalized(); |
1435 QVector3D side = QVector3D::crossProduct(forward, up).normalized(); |
1346 QVector3D upVector = QVector3D::crossProduct(side, forward); |
1436 QVector3D upVector = QVector3D::crossProduct(side, forward); |
1347 |
1437 |
1428 return QMatrix(m[0][0], m[0][1], |
1517 return QMatrix(m[0][0], m[0][1], |
1429 m[1][0], m[1][1], |
1518 m[1][0], m[1][1], |
1430 m[3][0], m[3][1]); |
1519 m[3][0], m[3][1]); |
1431 } |
1520 } |
1432 |
1521 |
1433 static const qreal inv_dist_to_plane = 1. / 1024.; |
|
1434 |
|
1435 /*! |
1522 /*! |
1436 Returns the conventional Qt 2D transformation matrix that |
1523 Returns the conventional Qt 2D transformation matrix that |
1437 corresponds to this matrix. |
1524 corresponds to this matrix. |
1438 |
1525 |
|
1526 The returned QTransform is formed by simply dropping the |
|
1527 third row and third column of the QMatrix4x4. This is suitable |
|
1528 for implementing orthographic projections where the z co-ordinate |
|
1529 should be dropped rather than projected. |
|
1530 |
|
1531 \sa toAffine() |
|
1532 */ |
|
1533 QTransform QMatrix4x4::toTransform() const |
|
1534 { |
|
1535 return QTransform(m[0][0], m[0][1], m[0][3], |
|
1536 m[1][0], m[1][1], m[1][3], |
|
1537 m[3][0], m[3][1], m[3][3]); |
|
1538 } |
|
1539 |
|
1540 /*! |
|
1541 Returns the conventional Qt 2D transformation matrix that |
|
1542 corresponds to this matrix. |
|
1543 |
1439 If \a distanceToPlane is non-zero, it indicates a projection |
1544 If \a distanceToPlane is non-zero, it indicates a projection |
1440 factor to use to adjust for the z co-ordinate. The default |
1545 factor to use to adjust for the z co-ordinate. The value of |
1441 value of 1024 corresponds to the projection factor used |
1546 1024 corresponds to the projection factor used |
1442 by QTransform::rotate() for the x and y axes. |
1547 by QTransform::rotate() for the x and y axes. |
1443 |
1548 |
1444 If \a distanceToPlane is zero, then the returned QTransform |
1549 If \a distanceToPlane is zero, then the returned QTransform |
1445 is formed by simply dropping the third row and third column |
1550 is formed by simply dropping the third row and third column |
1446 of the QMatrix4x4. This is suitable for implementing |
1551 of the QMatrix4x4. This is suitable for implementing |
1664 result.m[3][3] = 1.0f; |
1769 result.m[3][3] = 1.0f; |
1665 |
1770 |
1666 return result; |
1771 return result; |
1667 } |
1772 } |
1668 |
1773 |
1669 #ifndef QT_NO_VECTOR3D |
1774 /*! |
1670 /*! |
1775 Optimize the usage of this matrix from its current elements. |
1671 Decomposes the current rotation matrix into an \a axis of rotation plus |
|
1672 an \a angle. The result can be used to construct an equivalent rotation |
|
1673 matrix using glRotate(). It is assumed that the homogenous coordinate |
|
1674 is 1.0. The returned vector is guaranteed to be normalized. |
|
1675 |
|
1676 \code |
|
1677 qreal angle; |
|
1678 QVector3D axis; |
|
1679 |
|
1680 matrix.extractAxisAngle(angle, axis); |
|
1681 glRotate(angle, axis[0], axis[1], axis[2]); |
|
1682 \endcode |
|
1683 |
|
1684 \sa rotate() |
|
1685 */ |
|
1686 void QMatrix4x4::extractAxisRotation(qreal &angle, QVector3D &axis) const |
|
1687 { |
|
1688 // Orientation is dependent on the upper 3x3 matrix; subtract the |
|
1689 // homogeneous scaling element from the trace of the 4x4 matrix |
|
1690 qreal tr = m[0][0] + m[1][1] + m[2][2]; |
|
1691 qreal cosa = qreal(0.5f * (tr - 1.0f)); |
|
1692 angle = acos(cosa) * 180.0f / M_PI; |
|
1693 |
|
1694 // Any axis will work if r is zero (means no rotation) |
|
1695 if (qFuzzyIsNull(angle)) { |
|
1696 axis.setX(1.0f); |
|
1697 axis.setY(0.0f); |
|
1698 axis.setZ(0.0f); |
|
1699 return; |
|
1700 } |
|
1701 |
|
1702 if (angle < 180.0f) { |
|
1703 axis.setX(m[1][2] - m[2][1]); |
|
1704 axis.setY(m[2][0] - m[0][2]); |
|
1705 axis.setZ(m[0][1] - m[1][0]); |
|
1706 axis.normalize(); |
|
1707 return; |
|
1708 } |
|
1709 |
|
1710 // rads == PI |
|
1711 qreal tmp; |
|
1712 |
|
1713 // r00 is maximum |
|
1714 if ((m[0][0] >= m[2][2]) && (m[0][0] >= m[1][1])) { |
|
1715 axis.setX(0.5f * qSqrt(m[0][0] - m[1][1] - m[2][2] + 1.0f)); |
|
1716 tmp = 0.5f / axis.x(); |
|
1717 axis.setY(m[1][0] * tmp); |
|
1718 axis.setZ(m[2][0] * tmp); |
|
1719 } |
|
1720 |
|
1721 // r11 is maximum |
|
1722 if ((m[1][1] >= m[2][2]) && (m[1][1] >= m[0][0])) { |
|
1723 axis.setY(0.5f * qSqrt(m[1][1] - m[0][0] - m[2][2] + 1.0f)); |
|
1724 tmp = 0.5f / axis.y(); |
|
1725 axis.setX(tmp * m[1][0]); |
|
1726 axis.setZ(tmp * m[2][1]); |
|
1727 } |
|
1728 |
|
1729 // r22 is maximum |
|
1730 if ((m[2][2] >= m[1][1]) && (m[2][2] >= m[0][0])) { |
|
1731 axis.setZ(0.5f * qSqrt(m[2][2] - m[0][0] - m[1][1] + 1.0f)); |
|
1732 tmp = 0.5f / axis.z(); |
|
1733 axis.setX(m[2][0]*tmp); |
|
1734 axis.setY(m[2][1]*tmp); |
|
1735 } |
|
1736 } |
|
1737 |
|
1738 /*! |
|
1739 If this is an orthonormal transformation matrix (e.g. only rotations and |
|
1740 translations have been applied to the matrix, no scaling, or shearing) |
|
1741 then the world translational component can be obtained by calling this function. |
|
1742 |
|
1743 This is most useful for camera matrices, where the negation of this vector |
|
1744 is effectively the camera world coordinates. |
|
1745 */ |
|
1746 QVector3D QMatrix4x4::extractTranslation() const |
|
1747 { |
|
1748 return QVector3D |
|
1749 (m[0][0] * m[3][0] + m[0][1] * m[3][1] + m[0][2] * m[3][2], |
|
1750 m[1][0] * m[3][0] + m[1][1] * m[3][1] + m[1][2] * m[3][2], |
|
1751 m[2][0] * m[3][0] + m[2][1] * m[3][1] + m[2][2] * m[3][2]); |
|
1752 } |
|
1753 #endif |
|
1754 |
|
1755 /*! |
|
1756 Infers the special type of this matrix from its current elements. |
|
1757 |
1776 |
1758 Some operations such as translate(), scale(), and rotate() can be |
1777 Some operations such as translate(), scale(), and rotate() can be |
1759 performed more efficiently if the matrix being modified is already |
1778 performed more efficiently if the matrix being modified is already |
1760 known to be the identity, a previous translate(), a previous |
1779 known to be the identity, a previous translate(), a previous |
1761 scale(), etc. |
1780 scale(), etc. |
1764 as operations are performed. However, if the matrix is modified |
1783 as operations are performed. However, if the matrix is modified |
1765 directly with operator()() or data(), then QMatrix4x4 will lose track of |
1784 directly with operator()() or data(), then QMatrix4x4 will lose track of |
1766 the special type and will revert to the safest but least efficient |
1785 the special type and will revert to the safest but least efficient |
1767 operations thereafter. |
1786 operations thereafter. |
1768 |
1787 |
1769 By calling inferSpecialType() after directly modifying the matrix, |
1788 By calling optimize() after directly modifying the matrix, |
1770 the programmer can force QMatrix4x4 to recover the special type if |
1789 the programmer can force QMatrix4x4 to recover the special type if |
1771 the elements appear to conform to one of the known optimized types. |
1790 the elements appear to conform to one of the known optimized types. |
1772 |
1791 |
1773 \sa operator()(), data(), translate() |
1792 \sa operator()(), data(), translate() |
1774 */ |
1793 */ |
1775 void QMatrix4x4::inferSpecialType() |
1794 void QMatrix4x4::optimize() |
1776 { |
1795 { |
1777 // If the last element is not 1, then it can never be special. |
1796 // If the last element is not 1, then it can never be special. |
1778 if (m[3][3] != 1.0f) { |
1797 if (m[3][3] != 1.0f) { |
1779 flagBits = General; |
1798 flagBits = General; |
1780 return; |
1799 return; |